Sat Mar 10 01:54:23 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: 345431 $")
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", chan->name, 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          chan->name);
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", chan->name);
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", chan->name);
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", chan->name);
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", chan->name);
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", chan->name);
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", chan->name);
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", chan->name);
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          chan->name);
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, 1);
01311    manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01312       "SubEvent: Start\r\n"
01313       "Channel: %s\r\n"
01314       "Env: %s\r\n", chan->name, 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                chan->name);
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, 1);
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", chan->name, 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", chan->name, 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", chan->name);
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", chan->name);
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", chan->name);
01725    ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
01726    ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
01727    ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
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", chan->accountcode ? chan->accountcode : "");
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    if (argv[3])
01941       edigits = argv[3];
01942 
01943    if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01944       return RESULT_SHOWUSAGE;
01945 
01946    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01947       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01948       return RESULT_SUCCESS;
01949    }
01950 
01951    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01952       ast_debug(1, "Ooh, found a video stream, too\n");
01953 
01954    ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01955 
01956    ast_seekstream(fs, 0, SEEK_END);
01957    max_length = ast_tellstream(fs);
01958    ast_seekstream(fs, sample_offset, SEEK_SET);
01959    res = ast_applystream(chan, fs);
01960    if (vfs)
01961       ast_applystream(chan, vfs);
01962    ast_playstream(fs);
01963    if (vfs)
01964       ast_playstream(vfs);
01965 
01966    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01967    /* this is to check for if ast_waitstream closed the stream, we probably are at
01968     * the end of the stream, return that amount, else check for the amount */
01969    sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01970    ast_stopstream(chan);
01971    if (res == 1) {
01972       /* Stop this command, don't print a result line, as there is a new command */
01973       return RESULT_SUCCESS;
01974    }
01975    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01976    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01977 }
01978 
01979 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
01980 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01981 {
01982    int res;
01983    struct ast_filestream *fs, *vfs;
01984    long sample_offset = 0, max_length;
01985    int timeout = 0;
01986    const char *edigits = "";
01987 
01988    if ( argc < 4 || argc > 5 )
01989       return RESULT_SHOWUSAGE;
01990 
01991    if ( argv[3] )
01992       edigits = argv[3];
01993 
01994    if ( argc == 5 )
01995       timeout = atoi(argv[4]);
01996    else if (chan->pbx->dtimeoutms) {
01997       /* by default dtimeout is set to 5sec */
01998       timeout = chan->pbx->dtimeoutms; /* in msec */
01999    }
02000 
02001    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
02002       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
02003       ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
02004       return RESULT_SUCCESS;
02005    }
02006 
02007    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
02008       ast_debug(1, "Ooh, found a video stream, too\n");
02009 
02010    ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
02011 
02012    ast_seekstream(fs, 0, SEEK_END);
02013    max_length = ast_tellstream(fs);
02014    ast_seekstream(fs, sample_offset, SEEK_SET);
02015    res = ast_applystream(chan, fs);
02016    if (vfs)
02017       ast_applystream(chan, vfs);
02018    ast_playstream(fs);
02019    if (vfs)
02020       ast_playstream(vfs);
02021 
02022    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
02023    /* this is to check for if ast_waitstream closed the stream, we probably are at
02024     * the end of the stream, return that amount, else check for the amount */
02025    sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
02026    ast_stopstream(chan);
02027    if (res == 1) {
02028       /* Stop this command, don't print a result line, as there is a new command */
02029       return RESULT_SUCCESS;
02030    }
02031 
02032    /* If the user didnt press a key, wait for digitTimeout*/
02033    if (res == 0 ) {
02034       res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
02035       /* Make sure the new result is in the escape digits of the GET OPTION */
02036       if ( !strchr(edigits,res) )
02037          res=0;
02038    }
02039 
02040    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
02041    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02042 }
02043 
02044 
02045 
02046 
02047 /*! \brief Say number in various language syntaxes */
02048 /* While waiting, we're sending a NULL.  */
02049 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02050 {
02051    int res, num;
02052 
02053    if (argc < 4 || argc > 5)
02054       return RESULT_SHOWUSAGE;
02055    if (sscanf(argv[2], "%30d", &num) != 1)
02056       return RESULT_SHOWUSAGE;
02057    res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
02058    if (res == 1)
02059       return RESULT_SUCCESS;
02060    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02061    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02062 }
02063 
02064 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02065 {
02066    int res, num;
02067 
02068    if (argc != 4)
02069       return RESULT_SHOWUSAGE;
02070    if (sscanf(argv[2], "%30d", &num) != 1)
02071       return RESULT_SHOWUSAGE;
02072 
02073    res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02074    if (res == 1) /* New command */
02075       return RESULT_SUCCESS;
02076    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02077    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02078 }
02079 
02080 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02081 {
02082    int res;
02083 
02084    if (argc != 4)
02085       return RESULT_SHOWUSAGE;
02086 
02087    res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02088    if (res == 1) /* New command */
02089       return RESULT_SUCCESS;
02090    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02091    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02092 }
02093 
02094 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02095 {
02096    int res, num;
02097 
02098    if (argc != 4)
02099       return RESULT_SHOWUSAGE;
02100    if (sscanf(argv[2], "%30d", &num) != 1)
02101       return RESULT_SHOWUSAGE;
02102    res = ast_say_date(chan, num, argv[3], chan->language);
02103    if (res == 1)
02104       return RESULT_SUCCESS;
02105    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02106    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02107 }
02108 
02109 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02110 {
02111    int res, num;
02112 
02113    if (argc != 4)
02114       return RESULT_SHOWUSAGE;
02115    if (sscanf(argv[2], "%30d", &num) != 1)
02116       return RESULT_SHOWUSAGE;
02117    res = ast_say_time(chan, num, argv[3], chan->language);
02118    if (res == 1)
02119       return RESULT_SUCCESS;
02120    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02121    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02122 }
02123 
02124 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02125 {
02126    int res = 0;
02127    time_t unixtime;
02128    const char *format, *zone = NULL;
02129 
02130    if (argc < 4)
02131       return RESULT_SHOWUSAGE;
02132 
02133    if (argc > 4) {
02134       format = argv[4];
02135    } else {
02136       /* XXX this doesn't belong here, but in the 'say' module */
02137       if (!strcasecmp(chan->language, "de")) {
02138          format = "A dBY HMS";
02139       } else {
02140          format = "ABdY 'digits/at' IMp";
02141       }
02142    }
02143 
02144    if (argc > 5 && !ast_strlen_zero(argv[5]))
02145       zone = argv[5];
02146 
02147    if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
02148       return RESULT_SHOWUSAGE;
02149 
02150    res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
02151    if (res == 1)
02152       return RESULT_SUCCESS;
02153 
02154    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02155    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02156 }
02157 
02158 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02159 {
02160    int res;
02161 
02162    if (argc != 4)
02163       return RESULT_SHOWUSAGE;
02164 
02165    res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02166    if (res == 1) /* New command */
02167       return RESULT_SUCCESS;
02168    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02169    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02170 }
02171 
02172 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02173 {
02174    int res, max, timeout;
02175    char data[1024];
02176 
02177    if (argc < 3)
02178       return RESULT_SHOWUSAGE;
02179    if (argc >= 4)
02180       timeout = atoi(argv[3]);
02181    else
02182       timeout = 0;
02183    if (argc >= 5)
02184       max = atoi(argv[4]);
02185    else
02186       max = 1024;
02187    res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
02188    if (res == 2)        /* New command */
02189       return RESULT_SUCCESS;
02190    else if (res == 1)
02191       ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
02192    else if (res < 0 )
02193       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02194    else
02195       ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
02196    return RESULT_SUCCESS;
02197 }
02198 
02199 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02200 {
02201 
02202    if (argc != 3)
02203       return RESULT_SHOWUSAGE;
02204    ast_copy_string(chan->context, argv[2], sizeof(chan->context));
02205    ast_agi_send(agi->fd, chan, "200 result=0\n");
02206    return RESULT_SUCCESS;
02207 }
02208 
02209 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02210 {
02211    if (argc != 3)
02212       return RESULT_SHOWUSAGE;
02213    ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
02214    ast_agi_send(agi->fd, chan, "200 result=0\n");
02215    return RESULT_SUCCESS;
02216 }
02217 
02218 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02219 {
02220    int pri;
02221 
02222    if (argc != 3)
02223       return RESULT_SHOWUSAGE;
02224 
02225    if (sscanf(argv[2], "%30d", &pri) != 1) {
02226       pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2],
02227          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
02228       if (pri < 1)
02229          return RESULT_SHOWUSAGE;
02230    }
02231 
02232    ast_explicit_goto(chan, NULL, NULL, pri);
02233    ast_agi_send(agi->fd, chan, "200 result=0\n");
02234    return RESULT_SUCCESS;
02235 }
02236 
02237 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02238 {
02239    struct ast_filestream *fs;
02240    struct ast_frame *f;
02241    struct timeval start;
02242    long sample_offset = 0;
02243    int res = 0;
02244    int ms;
02245 
02246    struct ast_dsp *sildet=NULL;         /* silence detector dsp */
02247    int totalsilence = 0;
02248    int dspsilence = 0;
02249    int silence = 0;                /* amount of silence to allow */
02250    int gotsilence = 0;             /* did we timeout for silence? */
02251    char *silencestr = NULL;
02252    int rfmt = 0;
02253 
02254    /* XXX EAGI FIXME XXX */
02255 
02256    if (argc < 6)
02257       return RESULT_SHOWUSAGE;
02258    if (sscanf(argv[5], "%30d", &ms) != 1)
02259       return RESULT_SHOWUSAGE;
02260 
02261    if (argc > 6)
02262       silencestr = strchr(argv[6],'s');
02263    if ((argc > 7) && (!silencestr))
02264       silencestr = strchr(argv[7],'s');
02265    if ((argc > 8) && (!silencestr))
02266       silencestr = strchr(argv[8],'s');
02267 
02268    if (silencestr) {
02269       if (strlen(silencestr) > 2) {
02270          if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
02271             silencestr++;
02272             silencestr++;
02273             if (silencestr)
02274                silence = atoi(silencestr);
02275             if (silence > 0)
02276                silence *= 1000;
02277          }
02278       }
02279    }
02280 
02281    if (silence > 0) {
02282       rfmt = chan->readformat;
02283       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
02284       if (res < 0) {
02285          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
02286          ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02287          return RESULT_FAILURE;
02288       }
02289       sildet = ast_dsp_new();
02290       if (!sildet) {
02291          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
02292          ast_agi_send(agi->fd, chan, "200 result=-1\n");
02293          return RESULT_FAILURE;
02294       }
02295       ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
02296    }
02297    
02298    /* backward compatibility, if no offset given, arg[6] would have been
02299     * caught below and taken to be a beep, else if it is a digit then it is a
02300     * offset */
02301    if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
02302       res = ast_streamfile(chan, "beep", chan->language);
02303 
02304    if ((argc > 7) && (!strchr(argv[7], '=')))
02305       res = ast_streamfile(chan, "beep", chan->language);
02306 
02307    if (!res)
02308       res = ast_waitstream(chan, argv[4]);
02309    if (res) {
02310       ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
02311    } else {
02312       fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
02313       if (!fs) {
02314          res = -1;
02315          ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
02316          if (sildet)
02317             ast_dsp_free(sildet);
02318          return RESULT_FAILURE;
02319       }
02320 
02321       /* Request a video update */
02322       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
02323 
02324       chan->stream = fs;
02325       ast_applystream(chan,fs);
02326       /* really should have checks */
02327       ast_seekstream(fs, sample_offset, SEEK_SET);
02328       ast_truncstream(fs);
02329 
02330       start = ast_tvnow();
02331       while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
02332          res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
02333          if (res < 0) {
02334             ast_closestream(fs);
02335             ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
02336             if (sildet)
02337                ast_dsp_free(sildet);
02338             return RESULT_FAILURE;
02339          }
02340          f = ast_read(chan);
02341          if (!f) {
02342             ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
02343             ast_closestream(fs);
02344             if (sildet)
02345                ast_dsp_free(sildet);
02346             return RESULT_FAILURE;
02347          }
02348          switch(f->frametype) {
02349          case AST_FRAME_DTMF:
02350             if (strchr(argv[4], f->subclass.integer)) {
02351                /* This is an interrupting chracter, so rewind to chop off any small
02352                   amount of DTMF that may have been recorded
02353                */
02354                ast_stream_rewind(fs, 200);
02355                ast_truncstream(fs);
02356                sample_offset = ast_tellstream(fs);
02357                ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
02358                ast_closestream(fs);
02359                ast_frfree(f);
02360                if (sildet)
02361                   ast_dsp_free(sildet);
02362                return RESULT_SUCCESS;
02363             }
02364             break;
02365          case AST_FRAME_VOICE:
02366             ast_writestream(fs, f);
02367             /* this is a safe place to check progress since we know that fs
02368              * is valid after a write, and it will then have our current
02369              * location */
02370             sample_offset = ast_tellstream(fs);
02371             if (silence > 0) {
02372                dspsilence = 0;
02373                ast_dsp_silence(sildet, f, &dspsilence);
02374                if (dspsilence) {
02375                   totalsilence = dspsilence;
02376                } else {
02377                   totalsilence = 0;
02378                }
02379                if (totalsilence > silence) {
02380                   /* Ended happily with silence */
02381                   gotsilence = 1;
02382                   break;
02383                }
02384             }
02385             break;
02386          case AST_FRAME_VIDEO:
02387             ast_writestream(fs, f);
02388          default:
02389             /* Ignore all other frames */
02390             break;
02391          }
02392          ast_frfree(f);
02393          if (gotsilence)
02394             break;
02395       }
02396 
02397       if (gotsilence) {
02398          ast_stream_rewind(fs, silence-1000);
02399          ast_truncstream(fs);
02400          sample_offset = ast_tellstream(fs);
02401       }
02402       ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
02403       ast_closestream(fs);
02404    }
02405 
02406    if (silence > 0) {
02407       res = ast_set_read_format(chan, rfmt);
02408       if (res)
02409          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
02410       ast_dsp_free(sildet);
02411    }
02412 
02413    return RESULT_SUCCESS;
02414 }
02415 
02416 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02417 {
02418    double timeout;
02419    struct timeval whentohangup = { 0, 0 };
02420 
02421    if (argc != 3)
02422       return RESULT_SHOWUSAGE;
02423    if (sscanf(argv[2], "%30lf", &timeout) != 1)
02424       return RESULT_SHOWUSAGE;
02425    if (timeout < 0)
02426       timeout = 0;
02427    if (timeout) {
02428       whentohangup.tv_sec = timeout;
02429       whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
02430    }
02431    ast_channel_setwhentohangup_tv(chan, whentohangup);
02432    ast_agi_send(agi->fd, chan, "200 result=0\n");
02433    return RESULT_SUCCESS;
02434 }
02435 
02436 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02437 {
02438    struct ast_channel *c;
02439 
02440    if (argc == 1) {
02441       /* no argument: hangup the current channel */
02442       ast_set_hangupsource(chan, "dialplan/agi", 0);
02443       ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
02444       ast_agi_send(agi->fd, chan, "200 result=1\n");
02445       return RESULT_SUCCESS;
02446    } else if (argc == 2) {
02447       /* one argument: look for info on the specified channel */
02448       if ((c = ast_channel_get_by_name(argv[1]))) {
02449          /* we have a matching channel */
02450          ast_set_hangupsource(c, "dialplan/agi", 0);
02451          ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
02452          c = ast_channel_unref(c);
02453          ast_agi_send(agi->fd, chan, "200 result=1\n");
02454          return RESULT_SUCCESS;
02455       }
02456       /* if we get this far no channel name matched the argument given */
02457       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02458       return RESULT_SUCCESS;
02459    } else {
02460       return RESULT_SHOWUSAGE;
02461    }
02462 }
02463 
02464 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02465 {
02466    int res, workaround;
02467    struct ast_app *app_to_exec;
02468 
02469    if (argc < 2)
02470       return RESULT_SHOWUSAGE;
02471 
02472    ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
02473 
02474    if ((app_to_exec = pbx_findapp(argv[1]))) {
02475       if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
02476          ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02477       }
02478       if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
02479          char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr;
02480          const char *vptr;
02481          for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
02482             if (*vptr == ',') {
02483                *cptr++ = '\\';
02484                *cptr++ = ',';
02485             } else if (*vptr == '|') {
02486                *cptr++ = ',';
02487             } else {
02488                *cptr++ = *vptr;
02489             }
02490          }
02491          *cptr = '\0';
02492          res = pbx_exec(chan, app_to_exec, compat);
02493       } else {
02494          res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
02495       }
02496       if (!workaround) {
02497          ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02498       }
02499    } else {
02500       ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
02501       res = -2;
02502    }
02503    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02504 
02505    /* Even though this is wrong, users are depending upon this result. */
02506    return res;
02507 }
02508 
02509 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02510 {
02511    char tmp[256]="";
02512    char *l = NULL, *n = NULL;
02513 
02514    if (argv[2]) {
02515       ast_copy_string(tmp, argv[2], sizeof(tmp));
02516       ast_callerid_parse(tmp, &n, &l);
02517       if (l)
02518          ast_shrink_phone_number(l);
02519       else
02520          l = "";
02521       if (!n)
02522          n = "";
02523       ast_set_callerid(chan, l, n, NULL);
02524    }
02525 
02526    ast_agi_send(agi->fd, chan, "200 result=1\n");
02527    return RESULT_SUCCESS;
02528 }
02529 
02530 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02531 {
02532    struct ast_channel *c;
02533    if (argc == 2) {
02534       /* no argument: supply info on the current channel */
02535       ast_agi_send(agi->fd, chan, "200 result=%d\n", chan->_state);
02536       return RESULT_SUCCESS;
02537    } else if (argc == 3) {
02538       /* one argument: look for info on the specified channel */
02539       if ((c = ast_channel_get_by_name(argv[2]))) {
02540          ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state);
02541          c = ast_channel_unref(c);
02542          return RESULT_SUCCESS;
02543       }
02544       /* if we get this far no channel name matched the argument given */
02545       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02546       return RESULT_SUCCESS;
02547    } else {
02548       return RESULT_SHOWUSAGE;
02549    }
02550 }
02551 
02552 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02553 {
02554    if (argv[3])
02555       pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
02556 
02557    ast_agi_send(agi->fd, chan, "200 result=1\n");
02558    return RESULT_SUCCESS;
02559 }
02560 
02561 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02562 {
02563    char *ret;
02564    char tempstr[1024] = "";
02565 
02566    if (argc != 3)
02567       return RESULT_SHOWUSAGE;
02568 
02569    /* check if we want to execute an ast_custom_function */
02570    if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
02571       ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
02572    } else {
02573       pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
02574    }
02575 
02576    if (ret)
02577       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
02578    else
02579       ast_agi_send(agi->fd, chan, "200 result=0\n");
02580 
02581    return RESULT_SUCCESS;
02582 }
02583 
02584 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02585 {
02586    struct ast_channel *chan2 = NULL;
02587 
02588    if (argc != 4 && argc != 5) {
02589       return RESULT_SHOWUSAGE;
02590    }
02591 
02592    if (argc == 5) {
02593       chan2 = ast_channel_get_by_name(argv[4]);
02594    } else {
02595       chan2 = ast_channel_ref(chan);
02596    }
02597 
02598    if (chan2) {
02599       struct ast_str *str = ast_str_create(16);
02600       if (!str) {
02601          ast_agi_send(agi->fd, chan, "200 result=0\n");
02602          return RESULT_SUCCESS;
02603       }
02604       ast_str_substitute_variables(&str, 0, chan2, argv[3]);
02605       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
02606       ast_free(str);
02607    } else {
02608       ast_agi_send(agi->fd, chan, "200 result=0\n");
02609    }
02610 
02611    if (chan2) {
02612       chan2 = ast_channel_unref(chan2);
02613    }
02614 
02615    return RESULT_SUCCESS;
02616 }
02617 
02618 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02619 {
02620    int level = 0;
02621 
02622    if (argc < 2)
02623       return RESULT_SHOWUSAGE;
02624 
02625    if (argv[2])
02626       sscanf(argv[2], "%30d", &level);
02627 
02628    ast_verb(level, "%s: %s\n", chan->data, argv[1]);
02629 
02630    ast_agi_send(agi->fd, chan, "200 result=1\n");
02631 
02632    return RESULT_SUCCESS;
02633 }
02634 
02635 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02636 {
02637    int res;
02638    struct ast_str *buf;
02639 
02640    if (argc != 4)
02641       return RESULT_SHOWUSAGE;
02642 
02643    if (!(buf = ast_str_create(16))) {
02644       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02645       return RESULT_SUCCESS;
02646    }
02647 
02648    do {
02649       res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
02650       ast_str_update(buf);
02651       if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
02652          break;
02653       }
02654       if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
02655          break;
02656       }
02657    } while (1);
02658    
02659    if (res)
02660       ast_agi_send(agi->fd, chan, "200 result=0\n");
02661    else
02662       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
02663 
02664    ast_free(buf);
02665    return RESULT_SUCCESS;
02666 }
02667 
02668 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02669 {
02670    int res;
02671 
02672    if (argc != 5)
02673       return RESULT_SHOWUSAGE;
02674    res = ast_db_put(argv[2], argv[3], argv[4]);
02675    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02676    return RESULT_SUCCESS;
02677 }
02678 
02679 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02680 {
02681    int res;
02682 
02683    if (argc != 4)
02684       return RESULT_SHOWUSAGE;
02685    res = ast_db_del(argv[2], argv[3]);
02686    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02687    return RESULT_SUCCESS;
02688 }
02689 
02690 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02691 {
02692    int res;
02693 
02694    if ((argc < 3) || (argc > 4))
02695       return RESULT_SHOWUSAGE;
02696    if (argc == 4)
02697       res = ast_db_deltree(argv[2], argv[3]);
02698    else
02699       res = ast_db_deltree(argv[2], NULL);
02700 
02701    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02702    return RESULT_SUCCESS;
02703 }
02704 
02705 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02706 {
02707    switch (cmd) {
02708    case CLI_INIT:
02709       e->command = "agi set debug [on|off]";
02710       e->usage =
02711          "Usage: agi set debug [on|off]\n"
02712          "       Enables/disables dumping of AGI transactions for\n"
02713          "       debugging purposes.\n";
02714       return NULL;
02715 
02716    case CLI_GENERATE:
02717       return NULL;
02718    }
02719 
02720    if (a->argc != e->args)
02721       return CLI_SHOWUSAGE;
02722 
02723    if (strncasecmp(a->argv[3], "off", 3) == 0) {
02724       agidebug = 0;
02725    } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
02726       agidebug = 1;
02727    } else {
02728       return CLI_SHOWUSAGE;
02729    }
02730    ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
02731    return CLI_SUCCESS;
02732 }
02733 
02734 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
02735 {
02736    ast_agi_send(agi->fd, chan, "200 result=0\n");
02737    return RESULT_SUCCESS;
02738 }
02739 
02740 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02741 {
02742    if (argc < 3) {
02743       return RESULT_SHOWUSAGE;
02744    }
02745    if (!strncasecmp(argv[2], "on", 2))
02746       ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
02747    else if (!strncasecmp(argv[2], "off", 3))
02748       ast_moh_stop(chan);
02749    ast_agi_send(agi->fd, chan, "200 result=0\n");
02750    return RESULT_SUCCESS;
02751 }
02752 
02753 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02754 {
02755    /* If a structure already exists, return an error */
02756         if (agi->speech) {
02757       ast_agi_send(agi->fd, chan, "200 result=0\n");
02758       return RESULT_SUCCESS;
02759    }
02760 
02761    if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02762       ast_agi_send(agi->fd, chan, "200 result=1\n");
02763    else
02764       ast_agi_send(agi->fd, chan, "200 result=0\n");
02765 
02766    return RESULT_SUCCESS;
02767 }
02768 
02769 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02770 {
02771    /* Check for minimum arguments */
02772    if (argc != 4)
02773       return RESULT_SHOWUSAGE;
02774 
02775    /* Check to make sure speech structure exists */
02776    if (!agi->speech) {
02777       ast_agi_send(agi->fd, chan, "200 result=0\n");
02778       return RESULT_SUCCESS;
02779    }
02780 
02781    ast_speech_change(agi->speech, argv[2], argv[3]);
02782    ast_agi_send(agi->fd, chan, "200 result=1\n");
02783 
02784    return RESULT_SUCCESS;
02785 }
02786 
02787 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02788 {
02789    if (agi->speech) {
02790       ast_speech_destroy(agi->speech);
02791       agi->speech = NULL;
02792       ast_agi_send(agi->fd, chan, "200 result=1\n");
02793    } else {
02794       ast_agi_send(agi->fd, chan, "200 result=0\n");
02795    }
02796 
02797    return RESULT_SUCCESS;
02798 }
02799 
02800 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02801 {
02802    if (argc != 5)
02803       return RESULT_SHOWUSAGE;
02804 
02805    if (!agi->speech) {
02806       ast_agi_send(agi->fd, chan, "200 result=0\n");
02807       return RESULT_SUCCESS;
02808    }
02809 
02810    if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02811       ast_agi_send(agi->fd, chan, "200 result=0\n");
02812    else
02813       ast_agi_send(agi->fd, chan, "200 result=1\n");
02814 
02815    return RESULT_SUCCESS;
02816 }
02817 
02818 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02819 {
02820    if (argc != 4)
02821       return RESULT_SHOWUSAGE;
02822 
02823    if (!agi->speech) {
02824       ast_agi_send(agi->fd, chan, "200 result=0\n");
02825       return RESULT_SUCCESS;
02826    }
02827 
02828    if (ast_speech_grammar_unload(agi->speech, argv[3]))
02829       ast_agi_send(agi->fd, chan, "200 result=0\n");
02830    else
02831       ast_agi_send(agi->fd, chan, "200 result=1\n");
02832 
02833    return RESULT_SUCCESS;
02834 }
02835 
02836 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02837 {
02838    if (argc != 4)
02839       return RESULT_SHOWUSAGE;
02840 
02841    if (!agi->speech) {
02842       ast_agi_send(agi->fd, chan, "200 result=0\n");
02843       return RESULT_SUCCESS;
02844    }
02845 
02846    if (ast_speech_grammar_activate(agi->speech, argv[3]))
02847       ast_agi_send(agi->fd, chan, "200 result=0\n");
02848    else
02849       ast_agi_send(agi->fd, chan, "200 result=1\n");
02850 
02851    return RESULT_SUCCESS;
02852 }
02853 
02854 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02855 {
02856    if (argc != 4)
02857       return RESULT_SHOWUSAGE;
02858 
02859    if (!agi->speech) {
02860       ast_agi_send(agi->fd, chan, "200 result=0\n");
02861       return RESULT_SUCCESS;
02862    }
02863 
02864    if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02865       ast_agi_send(agi->fd, chan, "200 result=0\n");
02866    else
02867       ast_agi_send(agi->fd, chan, "200 result=1\n");
02868 
02869    return RESULT_SUCCESS;
02870 }
02871 
02872 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
02873 {
02874    struct ast_filestream *fs = NULL;
02875 
02876    if (!(fs = ast_openstream(chan, filename, preflang)))
02877       return -1;
02878 
02879    if (offset)
02880       ast_seekstream(fs, offset, SEEK_SET);
02881 
02882    if (ast_applystream(chan, fs))
02883       return -1;
02884 
02885    if (ast_playstream(fs))
02886       return -1;
02887 
02888    return 0;
02889 }
02890 
02891 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02892 {
02893    struct ast_speech *speech = agi->speech;
02894    const char *prompt;
02895    char dtmf = 0, tmp[4096] = "", *buf = tmp;
02896    int timeout = 0, offset = 0, res = 0, i = 0;
02897    long current_offset = 0;
02898    const char *reason = NULL;
02899    struct ast_frame *fr = NULL;
02900    struct ast_speech_result *result = NULL;
02901    size_t left = sizeof(tmp);
02902    time_t start = 0, current;
02903 
02904    if (argc < 4)
02905       return RESULT_SHOWUSAGE;
02906 
02907    if (!speech) {
02908       ast_agi_send(agi->fd, chan, "200 result=0\n");
02909       return RESULT_SUCCESS;
02910    }
02911 
02912    prompt = argv[2];
02913    timeout = atoi(argv[3]);
02914 
02915    /* If offset is specified then convert from text to integer */
02916    if (argc == 5)
02917       offset = atoi(argv[4]);
02918 
02919    /* We want frames coming in signed linear */
02920    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02921       ast_agi_send(agi->fd, chan, "200 result=0\n");
02922       return RESULT_SUCCESS;
02923    }
02924 
02925    /* Setup speech structure */
02926    if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02927       ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02928       ast_speech_start(speech);
02929    }
02930 
02931    /* Start playing prompt */
02932    speech_streamfile(chan, prompt, chan->language, offset);
02933 
02934    /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
02935    while (ast_strlen_zero(reason)) {
02936       /* Run scheduled items */
02937                 ast_sched_runq(chan->sched);
02938 
02939       /* See maximum time of waiting */
02940       if ((res = ast_sched_wait(chan->sched)) < 0)
02941          res = 1000;
02942 
02943       /* Wait for frame */
02944       if (ast_waitfor(chan, res) > 0) {
02945          if (!(fr = ast_read(chan))) {
02946             reason = "hangup";
02947             break;
02948          }
02949       }
02950 
02951       /* Perform timeout check */
02952       if ((timeout > 0) && (start > 0)) {
02953          time(&current);
02954          if ((current - start) >= timeout) {
02955             reason = "timeout";
02956             if (fr)
02957                ast_frfree(fr);
02958             break;
02959          }
02960       }
02961 
02962       /* Check the speech structure for any changes */
02963       ast_mutex_lock(&speech->lock);
02964 
02965       /* See if we need to quiet the audio stream playback */
02966       if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02967          current_offset = ast_tellstream(chan->stream);
02968          ast_stopstream(chan);
02969          ast_clear_flag(speech, AST_SPEECH_QUIET);
02970       }
02971 
02972       /* Check each state */
02973       switch (speech->state) {
02974       case AST_SPEECH_STATE_READY:
02975          /* If the stream is done, start timeout calculation */
02976          if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02977             ast_stopstream(chan);
02978             time(&start);
02979          }
02980          /* Write audio frame data into speech engine if possible */
02981          if (fr && fr->frametype == AST_FRAME_VOICE)
02982             ast_speech_write(speech, fr->data.ptr, fr->datalen);
02983          break;
02984       case AST_SPEECH_STATE_WAIT:
02985          /* Cue waiting sound if not already playing */
02986          if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
02987             ast_stopstream(chan);
02988             /* If a processing sound exists, or is not none - play it */
02989             if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
02990                speech_streamfile(chan, speech->processing_sound, chan->language, 0);
02991          }
02992          break;
02993       case AST_SPEECH_STATE_DONE:
02994          /* Get the results */
02995          speech->results = ast_speech_results_get(speech);
02996          /* Change state to not ready */
02997          ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02998          reason = "speech";
02999          break;
03000       default:
03001          break;
03002       }
03003       ast_mutex_unlock(&speech->lock);
03004 
03005       /* Check frame for DTMF or hangup */
03006       if (fr) {
03007          if (fr->frametype == AST_FRAME_DTMF) {
03008             reason = "dtmf";
03009             dtmf = fr->subclass.integer;
03010          } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
03011             reason = "hangup";
03012          }
03013          ast_frfree(fr);
03014       }
03015    }
03016 
03017    if (!strcasecmp(reason, "speech")) {
03018       /* Build string containing speech results */
03019                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
03020          /* Build result string */
03021          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);
03022                         /* Increment result count */
03023          i++;
03024       }
03025                 /* Print out */
03026       ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
03027    } else if (!strcasecmp(reason, "dtmf")) {
03028       ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
03029    } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
03030       ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
03031    } else {
03032       ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
03033    }
03034 
03035    return RESULT_SUCCESS;
03036 }
03037 
03038 /*!
03039  * \brief AGI commands list
03040  */
03041 static struct agi_command commands[] = {
03042    { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
03043    { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
03044    { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
03045    { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
03046    { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
03047    { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
03048    { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
03049    { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
03050    { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
03051    { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
03052    { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
03053    { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
03054    { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
03055    { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
03056    { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
03057    { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
03058    { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 }, 
03059    { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
03060    { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
03061    { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
03062    { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0}, 
03063    { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0}, 
03064    { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0}, 
03065    { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
03066    { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0}, 
03067    { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
03068    { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
03069    { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
03070    { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
03071    { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
03072    { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
03073    { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
03074    { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
03075    { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
03076    { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
03077    { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
03078    { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
03079    { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
03080    { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
03081    { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
03082    { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
03083    { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
03084    { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
03085    { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
03086    { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
03087    { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
03088 };
03089 
03090 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
03091 
03092 static char *help_workhorse(int fd, const char * const match[])
03093 {
03094    char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
03095    struct agi_command *e;
03096 
03097    if (match)
03098       ast_join(matchstr, sizeof(matchstr), match);
03099 
03100    ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
03101    AST_RWLIST_RDLOCK(&agi_commands);
03102    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03103       if (!e->cmda[0])
03104          break;
03105       /* Hide commands that start with '_' */
03106       if ((e->cmda[0])[0] == '_')
03107          continue;
03108       ast_join(fullcmd, sizeof(fullcmd), e->cmda);
03109       if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
03110          continue;
03111       ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
03112    }
03113    AST_RWLIST_UNLOCK(&agi_commands);
03114 
03115    return CLI_SUCCESS;
03116 }
03117 
03118 int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command *cmd)
03119 {
03120    char fullcmd[MAX_CMD_LEN];
03121 
03122    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03123 
03124    if (!find_command(cmd->cmda, 1)) {
03125       *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
03126       if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
03127 #ifdef AST_XML_DOCS
03128          *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
03129          *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
03130          *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
03131          *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
03132          *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
03133 #endif
03134 #ifndef HAVE_NULLSAFE_PRINTF
03135          if (!cmd->summary) {
03136             *((char **) &cmd->summary) = ast_strdup("");
03137          }
03138          if (!cmd->usage) {
03139             *((char **) &cmd->usage) = ast_strdup("");
03140          }
03141          if (!cmd->syntax) {
03142             *((char **) &cmd->syntax) = ast_strdup("");
03143          }
03144          if (!cmd->seealso) {
03145             *((char **) &cmd->seealso) = ast_strdup("");
03146          }
03147 #endif
03148       }
03149 
03150       cmd->mod = mod;
03151       AST_RWLIST_WRLOCK(&agi_commands);
03152       AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
03153       AST_RWLIST_UNLOCK(&agi_commands);
03154       if (mod != ast_module_info->self)
03155          ast_module_ref(ast_module_info->self);
03156       ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
03157       return 1;
03158    } else {
03159       ast_log(LOG_WARNING, "Command already registered!\n");
03160       return 0;
03161    }
03162 }
03163 
03164 int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_command *cmd)
03165 {
03166    struct agi_command *e;
03167    int unregistered = 0;
03168    char fullcmd[MAX_CMD_LEN];
03169 
03170    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03171 
03172    AST_RWLIST_WRLOCK(&agi_commands);
03173    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
03174       if (cmd == e) {
03175          AST_RWLIST_REMOVE_CURRENT(list);
03176          if (mod != ast_module_info->self)
03177             ast_module_unref(ast_module_info->self);
03178 #ifdef AST_XML_DOCS
03179          if (e->docsrc == AST_XML_DOC) {
03180             ast_free((char *) e->summary);
03181             ast_free((char *) e->usage);
03182             ast_free((char *) e->syntax);
03183             ast_free((char *) e->seealso);
03184             *((char **) &e->summary) = NULL;
03185             *((char **) &e->usage) = NULL;
03186             *((char **) &e->syntax) = NULL;
03187             *((char **) &e->seealso) = NULL;
03188          }
03189 #endif
03190          unregistered=1;
03191          break;
03192       }
03193    }
03194    AST_RWLIST_TRAVERSE_SAFE_END;
03195    AST_RWLIST_UNLOCK(&agi_commands);
03196    if (unregistered)
03197       ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
03198    else
03199       ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
03200    return unregistered;
03201 }
03202 
03203 int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
03204 {
03205    unsigned int i, x = 0;
03206 
03207    for (i = 0; i < len; i++) {
03208       if (ast_agi_register(mod, cmd + i) == 1) {
03209          x++;
03210          continue;
03211       }
03212 
03213       /* registration failed, unregister everything
03214          that had been registered up to that point
03215       */
03216       for (; x > 0; x--) {
03217          /* we are intentionally ignoring the
03218             result of ast_agi_unregister() here,
03219             but it should be safe to do so since
03220             we just registered these commands and
03221             the only possible way for unregistration
03222             to fail is if the command is not
03223             registered
03224          */
03225          (void) ast_agi_unregister(mod, cmd + x - 1);
03226       }
03227       return -1;
03228    }
03229 
03230    return 0;
03231 }
03232 
03233 int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
03234 {
03235    unsigned int i;
03236    int res = 0;
03237 
03238    for (i = 0; i < len; i++) {
03239       /* remember whether any of the unregistration
03240          attempts failed... there is no recourse if
03241          any of them do
03242       */
03243       res |= ast_agi_unregister(mod, cmd + i);
03244    }
03245 
03246    return res;
03247 }
03248 
03249 static agi_command *find_command(const char * const cmds[], int exact)
03250 {
03251    int y, match;
03252    struct agi_command *e;
03253 
03254    AST_RWLIST_RDLOCK(&agi_commands);
03255    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03256       if (!e->cmda[0])
03257          break;
03258       /* start optimistic */
03259       match = 1;
03260       for (y = 0; match && cmds[y]; y++) {
03261          /* If there are no more words in the command (and we're looking for
03262             an exact match) or there is a difference between the two words,
03263             then this is not a match */
03264          if (!e->cmda[y] && !exact)
03265             break;
03266          /* don't segfault if the next part of a command doesn't exist */
03267          if (!e->cmda[y]) {
03268             AST_RWLIST_UNLOCK(&agi_commands);
03269             return NULL;
03270          }
03271          if (strcasecmp(e->cmda[y], cmds[y]))
03272             match = 0;
03273       }
03274       /* If more words are needed to complete the command then this is not
03275          a candidate (unless we're looking for a really inexact answer  */
03276       if ((exact > -1) && e->cmda[y])
03277          match = 0;
03278       if (match) {
03279          AST_RWLIST_UNLOCK(&agi_commands);
03280          return e;
03281       }
03282    }
03283    AST_RWLIST_UNLOCK(&agi_commands);
03284    return NULL;
03285 }
03286 
03287 static int parse_args(char *s, int *max, const char *argv[])
03288 {
03289    int x = 0, quoted = 0, escaped = 0, whitespace = 1;
03290    char *cur;
03291 
03292    cur = s;
03293    while(*s) {
03294       switch(*s) {
03295       case '"':
03296          /* If it's escaped, put a literal quote */
03297          if (escaped)
03298             goto normal;
03299          else
03300             quoted = !quoted;
03301          if (quoted && whitespace) {
03302             /* If we're starting a quote, coming off white space start a new word, too */
03303             argv[x++] = cur;
03304             whitespace=0;
03305          }
03306          escaped = 0;
03307       break;
03308       case ' ':
03309       case '\t':
03310          if (!quoted && !escaped) {
03311             /* If we're not quoted, mark this as whitespace, and
03312                end the previous argument */
03313             whitespace = 1;
03314             *(cur++) = '\0';
03315          } else
03316             /* Otherwise, just treat it as anything else */
03317             goto normal;
03318          break;
03319       case '\\':
03320          /* If we're escaped, print a literal, otherwise enable escaping */
03321          if (escaped) {
03322             goto normal;
03323          } else {
03324             escaped=1;
03325          }
03326          break;
03327       default:
03328 normal:
03329          if (whitespace) {
03330             if (x >= MAX_ARGS -1) {
03331                ast_log(LOG_WARNING, "Too many arguments, truncating\n");
03332                break;
03333             }
03334             /* Coming off of whitespace, start the next argument */
03335             argv[x++] = cur;
03336             whitespace=0;
03337          }
03338          *(cur++) = *s;
03339          escaped=0;
03340       }
03341       s++;
03342    }
03343    /* Null terminate */
03344    *(cur++) = '\0';
03345    argv[x] = NULL;
03346    *max = x;
03347    return 0;
03348 }
03349 
03350 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
03351 {
03352    const char *argv[MAX_ARGS];
03353    int argc = MAX_ARGS;
03354    int res;
03355    agi_command *c;
03356    const char *ami_res;
03357    char *ami_cmd = ast_strdupa(buf);
03358    int command_id = ast_random();
03359    int resultcode;
03360 
03361    manager_event(EVENT_FLAG_AGI, "AGIExec",
03362          "SubEvent: Start\r\n"
03363          "Channel: %s\r\n"
03364          "CommandId: %d\r\n"
03365          "Command: %s\r\n", chan->name, command_id, ami_cmd);
03366    parse_args(buf, &argc, argv);
03367    c = find_command(argv, 0);
03368    if (c && (!dead || (dead && c->dead))) {
03369       /* if this command wasn't registered by res_agi, be sure to usecount
03370       the module we are using */
03371       if (c->mod != ast_module_info->self)
03372          ast_module_ref(c->mod);
03373       /* If the AGI command being executed is an actual application (using agi exec)
03374       the app field will be updated in pbx_exec via handle_exec */
03375       if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
03376          ast_cdr_setapp(chan->cdr, "AGI", buf);
03377 
03378       res = c->handler(chan, agi, argc, argv);
03379       if (c->mod != ast_module_info->self)
03380          ast_module_unref(c->mod);
03381       switch (res) {
03382       case RESULT_SHOWUSAGE:
03383          ami_res = "Usage";
03384          resultcode = 520;
03385          break;
03386       case RESULT_FAILURE:
03387          ami_res = "Failure";
03388          resultcode = -1;
03389          break;
03390       case ASYNC_AGI_BREAK:
03391       case RESULT_SUCCESS:
03392          ami_res = "Success";
03393          resultcode = 200;
03394          break;
03395       default:
03396          ami_res = "Unknown Result";
03397          resultcode = 200;
03398          break;
03399       }
03400       manager_event(EVENT_FLAG_AGI, "AGIExec",
03401             "SubEvent: End\r\n"
03402             "Channel: %s\r\n"
03403             "CommandId: %d\r\n"
03404             "Command: %s\r\n"
03405             "ResultCode: %d\r\n"
03406             "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
03407       switch (res) {
03408       case RESULT_SHOWUSAGE:
03409          if (ast_strlen_zero(c->usage)) {
03410             ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
03411          } else {
03412             ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
03413             ast_agi_send(agi->fd, chan, "%s", c->usage);
03414             ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
03415          }
03416          break;
03417       case ASYNC_AGI_BREAK:
03418          return AGI_RESULT_SUCCESS_ASYNC;
03419       case RESULT_FAILURE:
03420          /* The RESULT_FAILURE code is usually because the channel hungup. */
03421          return AGI_RESULT_FAILURE;
03422       default:
03423          break;
03424       }
03425    } else if (c) {
03426       ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
03427       manager_event(EVENT_FLAG_AGI, "AGIExec",
03428             "SubEvent: End\r\n"
03429             "Channel: %s\r\n"
03430             "CommandId: %d\r\n"
03431             "Command: %s\r\n"
03432             "ResultCode: 511\r\n"
03433             "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
03434    } else {
03435       ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
03436       manager_event(EVENT_FLAG_AGI, "AGIExec",
03437             "SubEvent: End\r\n"
03438             "Channel: %s\r\n"
03439             "CommandId: %d\r\n"
03440             "Command: %s\r\n"
03441             "ResultCode: 510\r\n"
03442             "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
03443    }
03444    return AGI_RESULT_SUCCESS;
03445 }
03446 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
03447 {
03448    struct ast_channel *c;
03449    int outfd;
03450    int ms;
03451    int needhup = 0;
03452    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
03453    struct ast_frame *f;
03454    char buf[AGI_BUF_LEN];
03455    char *res = NULL;
03456    FILE *readf;
03457    /* how many times we'll retry if ast_waitfor_nandfs will return without either
03458      channel or file descriptor in case select is interrupted by a system call (EINTR) */
03459    int retry = AGI_NANDFS_RETRY;
03460    int send_sighup;
03461    const char *sighup_str;
03462    
03463    ast_channel_lock(chan);
03464    sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
03465    send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
03466    ast_channel_unlock(chan);
03467 
03468    if (!(readf = fdopen(agi->ctrl, "r"))) {
03469       ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
03470       if (send_sighup && pid > -1)
03471          kill(pid, SIGHUP);
03472       close(agi->ctrl);
03473       return AGI_RESULT_FAILURE;
03474    }
03475    
03476    setlinebuf(readf);
03477    setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
03478    for (;;) {
03479       if (needhup) {
03480          needhup = 0;
03481          dead = 1;
03482          if (send_sighup) {
03483             if (pid > -1) {
03484                kill(pid, SIGHUP);
03485             } else if (agi->fast) {
03486                ast_agi_send(agi->fd, chan, "HANGUP\n");
03487             }
03488          }
03489       }
03490       ms = -1;
03491       if (dead) {
03492          c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
03493       } else if (!ast_check_hangup(chan)) {
03494          c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
03495       } else {
03496          /*
03497           * Read the channel control queue until it is dry so we can
03498           * switch to dead mode.
03499           */
03500          c = chan;
03501       }
03502       if (c) {
03503          retry = AGI_NANDFS_RETRY;
03504          /* Idle the channel until we get a command */
03505          f = ast_read(c);
03506          if (!f) {
03507             ast_debug(1, "%s hungup\n", chan->name);
03508             needhup = 1;
03509             if (!returnstatus) {
03510                returnstatus = AGI_RESULT_HANGUP;
03511             }
03512          } else {
03513             /* If it's voice, write it to the audio pipe */
03514             if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
03515                /* Write, ignoring errors */
03516                if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
03517                }
03518             }
03519             ast_frfree(f);
03520          }
03521       } else if (outfd > -1) {
03522          size_t len = sizeof(buf);
03523          size_t buflen = 0;
03524          enum agi_result cmd_status;
03525 
03526          retry = AGI_NANDFS_RETRY;
03527          buf[0] = '\0';
03528 
03529          while (len > 1) {
03530             res = fgets(buf + buflen, len, readf);
03531             if (feof(readf))
03532                break;
03533             if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
03534                break;
03535             if (res != NULL && !agi->fast)
03536                break;
03537             buflen = strlen(buf);
03538             if (buflen && buf[buflen - 1] == '\n')
03539                break;
03540             len = sizeof(buf) - buflen;
03541             if (agidebug)
03542                ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
03543          }
03544 
03545          if (!buf[0]) {
03546             /* Program terminated */
03547             ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
03548             if (pid > 0)
03549                waitpid(pid, status, 0);
03550             /* No need to kill the pid anymore, since they closed us */
03551             pid = -1;
03552             break;
03553          }
03554 
03555          /* Special case for inability to execute child process */
03556          if (*buf && strncasecmp(buf, "failure", 7) == 0) {
03557             returnstatus = AGI_RESULT_FAILURE;
03558             break;
03559          }
03560 
03561          /* get rid of trailing newline, if any */
03562          buflen = strlen(buf);
03563          if (buflen && buf[buflen - 1] == '\n') {
03564             buf[buflen - 1] = '\0';
03565          }
03566 
03567          if (agidebug)
03568             ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
03569          cmd_status = agi_handle_command(chan, agi, buf, dead);
03570          switch (cmd_status) {
03571          case AGI_RESULT_FAILURE:
03572             if (dead || !ast_check_hangup(chan)) {
03573                /* The failure was not because of a hangup. */
03574                returnstatus = AGI_RESULT_FAILURE;
03575             }
03576             break;
03577          default:
03578             break;
03579          }
03580       } else {
03581          if (--retry <= 0) {
03582             ast_log(LOG_WARNING, "No channel, no fd?\n");
03583             returnstatus = AGI_RESULT_FAILURE;
03584             break;
03585          }
03586       }
03587    }
03588    if (agi->speech) {
03589       ast_speech_destroy(agi->speech);
03590    }
03591    /* Notify process */
03592    if (send_sighup) {
03593       if (pid > -1) {
03594          if (kill(pid, SIGHUP)) {
03595             ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
03596          } else { /* Give the process a chance to die */
03597             usleep(1);
03598          }
03599          waitpid(pid, status, WNOHANG);
03600       } else if (agi->fast) {
03601          ast_agi_send(agi->fd, chan, "HANGUP\n");
03602       }
03603    }
03604    fclose(readf);
03605    return returnstatus;
03606 }
03607 
03608 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03609 {
03610    struct agi_command *command;
03611    char fullcmd[MAX_CMD_LEN];
03612    int error = 0;
03613 
03614    switch (cmd) {
03615    case CLI_INIT:
03616       e->command = "agi show commands [topic]";
03617       e->usage =
03618          "Usage: agi show commands [topic] <topic>\n"
03619          "       When called with a topic as an argument, displays usage\n"
03620          "       information on the given command.  If called without a\n"
03621          "       topic, it provides a list of AGI commands.\n";
03622    case CLI_GENERATE:
03623       return NULL;
03624    }
03625    if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03626       return CLI_SHOWUSAGE;
03627    if (a->argc > e->args - 1) {
03628       command = find_command(a->argv + e->args, 1);
03629       if (command) {
03630          char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03631          char info[30 + MAX_CMD_LEN];              /* '-= Info about...' */
03632          char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];  /* '-= Info about...' with colors */
03633          char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03634          char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Description]\n with colors */
03635          char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Runs Dead]\n with colors */
03636          char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];      /* 'Yes' or 'No' with colors */
03637          char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];    /* [See Also]\n with colors */
03638          char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03639          size_t synlen, desclen, seealsolen, stxlen;
03640 
03641          term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03642          term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03643          term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03644          term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03645          term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03646          term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03647 
03648          ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03649          snprintf(info, sizeof(info), "\n  -= Info about agi '%s' =- ", fullcmd);
03650          term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03651 #ifdef AST_XML_DOCS
03652          if (command->docsrc == AST_XML_DOC) {
03653             synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03654             description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03655             seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03656             if (!seealso || !description || !synopsis) {
03657                error = 1;
03658                goto return_cleanup;
03659             }
03660          } else
03661 #endif
03662          {
03663             synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03664             synopsis = ast_malloc(synlen);
03665 
03666             desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03667             description = ast_malloc(desclen);
03668 
03669             seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03670             seealso = ast_malloc(seealsolen);
03671 
03672             if (!synopsis || !description || !seealso) {
03673                error = 1;
03674                goto return_cleanup;
03675             }
03676             term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03677             term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03678             term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03679          }
03680 
03681          stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03682          syntax = ast_malloc(stxlen);
03683          if (!syntax) {
03684             error = 1;
03685             goto return_cleanup;
03686          }
03687          term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03688 
03689          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,
03690                desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03691                seealsotitle, seealso);
03692 return_cleanup:
03693          ast_free(synopsis);
03694          ast_free(description);
03695          ast_free(syntax);
03696          ast_free(seealso);
03697       } else {
03698          if (find_command(a->argv + e->args, -1)) {
03699             return help_workhorse(a->fd, a->argv + e->args);
03700          } else {
03701             ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03702             ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03703          }
03704       }
03705    } else {
03706       return help_workhorse(a->fd, NULL);
03707    }
03708    return (error ? CLI_FAILURE : CLI_SUCCESS);
03709 }
03710 
03711 /*! \brief Convert string to use HTML escaped characters
03712    \note Maybe this should be a generic function?
03713 */
03714 static void write_html_escaped(FILE *htmlfile, char *str)
03715 {
03716    char *cur = str;
03717 
03718    while(*cur) {
03719       switch (*cur) {
03720       case '<':
03721          fprintf(htmlfile, "%s", "&lt;");
03722          break;
03723       case '>':
03724          fprintf(htmlfile, "%s", "&gt;");
03725          break;
03726       case '&':
03727          fprintf(htmlfile, "%s", "&amp;");
03728          break;
03729       case '"':
03730          fprintf(htmlfile, "%s", "&quot;");
03731          break;
03732       default:
03733          fprintf(htmlfile, "%c", *cur);
03734          break;
03735       }
03736       cur++;
03737    }
03738 
03739    return;
03740 }
03741 
03742 static int write_htmldump(const char *filename)
03743 {
03744    struct agi_command *command;
03745    char fullcmd[MAX_CMD_LEN];
03746    FILE *htmlfile;
03747 
03748    if (!(htmlfile = fopen(filename, "wt")))
03749       return -1;
03750 
03751    fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03752    fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03753    fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03754 
03755    AST_RWLIST_RDLOCK(&agi_commands);
03756    AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03757 #ifdef AST_XML_DOCS
03758       char *stringptmp;
03759 #endif
03760       char *tempstr, *stringp;
03761 
03762       if (!command->cmda[0])  /* end ? */
03763          break;
03764       /* Hide commands that start with '_' */
03765       if ((command->cmda[0])[0] == '_')
03766          continue;
03767       ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03768 
03769       fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03770       fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03771 #ifdef AST_XML_DOCS
03772       stringptmp = ast_xmldoc_printable(command->usage, 0);
03773       stringp = ast_strdup(stringptmp);
03774 #else
03775       stringp = ast_strdup(command->usage);
03776 #endif
03777       tempstr = strsep(&stringp, "\n");
03778 
03779       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03780       write_html_escaped(htmlfile, tempstr);
03781       fprintf(htmlfile, "</TD></TR>\n");
03782       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03783 
03784       while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03785          write_html_escaped(htmlfile, tempstr);
03786          fprintf(htmlfile, "<BR>\n");
03787       }
03788       fprintf(htmlfile, "</TD></TR>\n");
03789       fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03790       ast_free(stringp);
03791 #ifdef AST_XML_DOCS
03792       ast_free(stringptmp);
03793 #endif
03794    }
03795    AST_RWLIST_UNLOCK(&agi_commands);
03796    fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03797    fclose(htmlfile);
03798    return 0;
03799 }
03800 
03801 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03802 {
03803    switch (cmd) {
03804    case CLI_INIT:
03805       e->command = "agi dump html";
03806       e->usage =
03807          "Usage: agi dump html <filename>\n"
03808          "       Dumps the AGI command list in HTML format to the given\n"
03809          "       file.\n";
03810       return NULL;
03811    case CLI_GENERATE:
03812       return NULL;
03813    }
03814    if (a->argc != e->args + 1)
03815       return CLI_SHOWUSAGE;
03816 
03817    if (write_htmldump(a->argv[e->args]) < 0) {
03818       ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03819       return CLI_SHOWUSAGE;
03820    }
03821    ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03822    return CLI_SUCCESS;
03823 }
03824 
03825 static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
03826 {
03827    enum agi_result res;
03828    char *buf;
03829    int fds[2], efd = -1, pid = -1;
03830    AST_DECLARE_APP_ARGS(args,
03831       AST_APP_ARG(arg)[MAX_ARGS];
03832    );
03833    AGI agi;
03834 
03835    if (ast_strlen_zero(data)) {
03836       ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03837       return -1;
03838    }
03839    if (dead)
03840       ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03841    memset(&agi, 0, sizeof(agi));
03842    buf = ast_strdupa(data);
03843    AST_STANDARD_APP_ARGS(args, buf);
03844    args.argv[args.argc] = NULL;
03845 #if 0
03846     /* Answer if need be */
03847    if (chan->_state != AST_STATE_UP) {
03848       if (ast_answer(chan))
03849          return -1;
03850    }
03851 #endif
03852    res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03853    /* Async AGI do not require run_agi(), so just proceed if normal AGI
03854       or Fast AGI are setup with success. */
03855    if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03856       int status = 0;
03857       agi.fd = fds[1];
03858       agi.ctrl = fds[0];
03859       agi.audio = efd;
03860       agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03861       res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03862       /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
03863       if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03864          res = AGI_RESULT_FAILURE;
03865       if (fds[1] != fds[0])
03866          close(fds[1]);
03867       if (efd > -1)
03868          close(efd);
03869    }
03870    ast_safe_fork_cleanup();
03871 
03872    switch (res) {
03873    case AGI_RESULT_SUCCESS:
03874    case AGI_RESULT_SUCCESS_FAST:
03875    case AGI_RESULT_SUCCESS_ASYNC:
03876       pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03877       break;
03878    case AGI_RESULT_FAILURE:
03879       pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03880       break;
03881    case AGI_RESULT_NOTFOUND:
03882       pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03883       break;
03884    case AGI_RESULT_HANGUP:
03885       pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03886       return -1;
03887    }
03888 
03889    return 0;
03890 }
03891 
03892 static int agi_exec(struct ast_channel *chan, const char *data)
03893 {
03894    if (!ast_check_hangup(chan))
03895       return agi_exec_full(chan, data, 0, 0);
03896    else
03897       return agi_exec_full(chan, data, 0, 1);
03898 }
03899 
03900 static int eagi_exec(struct ast_channel *chan, const char *data)
03901 {
03902    int readformat, res;
03903 
03904    if (ast_check_hangup(chan)) {
03905       ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03906       return 0;
03907    }
03908    readformat = chan->readformat;
03909    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03910       ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03911       return -1;
03912    }
03913    res = agi_exec_full(chan, data, 1, 0);
03914    if (!res) {
03915       if (ast_set_read_format(chan, readformat)) {
03916          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03917       }
03918    }
03919    return res;
03920 }
03921 
03922 static int deadagi_exec(struct ast_channel *chan, const char *data)
03923 {
03924    ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03925    return agi_exec(chan, data);
03926 }
03927 
03928 static struct ast_cli_entry cli_agi[] = {
03929    AST_CLI_DEFINE(handle_cli_agi_add_cmd,   "Add AGI command to a channel in Async AGI"),
03930    AST_CLI_DEFINE(handle_cli_agi_debug,     "Enable/Disable AGI debugging"),
03931    AST_CLI_DEFINE(handle_cli_agi_show,      "List AGI commands or specific help"),
03932    AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
03933 };
03934 
03935 #ifdef TEST_FRAMEWORK
03936 AST_TEST_DEFINE(test_agi_null_docs)
03937 {
03938    int res = AST_TEST_PASS;
03939    struct agi_command noop_command =
03940       { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
03941 
03942    switch (cmd) {
03943    case TEST_INIT:
03944       info->name = "null_agi_docs";
03945       info->category = "/res/agi/";
03946       info->summary = "AGI command with no documentation";
03947       info->description = "Test whether an AGI command with no documentation will crash Asterisk";
03948       return AST_TEST_NOT_RUN;
03949    case TEST_EXECUTE:
03950       break;
03951    }
03952 
03953    if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
03954       ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
03955       return AST_TEST_NOT_RUN;
03956    }
03957 
03958 #ifndef HAVE_NULLSAFE_PRINTF
03959    /* Test for condition without actually crashing Asterisk */
03960    if (noop_command.usage == NULL) {
03961       ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
03962       res = AST_TEST_FAIL;
03963    }
03964    if (noop_command.syntax == NULL) {
03965       ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
03966       res = AST_TEST_FAIL;
03967    }
03968 #endif
03969 
03970    ast_agi_unregister(ast_module_info->self, &noop_command);
03971    return res;
03972 }
03973 #endif
03974 
03975 static int unload_module(void)
03976 {
03977    ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
03978    /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
03979       we know that these commands were registered by this module and are still registered
03980    */
03981    (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03982    ast_unregister_application(eapp);
03983    ast_unregister_application(deadapp);
03984    ast_manager_unregister("AGI");
03985    AST_TEST_UNREGISTER(test_agi_null_docs);
03986    return ast_unregister_application(app);
03987 }
03988 
03989 static int load_module(void)
03990 {
03991    ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
03992    /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
03993       no other commands have been registered yet
03994    */
03995    (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03996    ast_register_application_xml(deadapp, deadagi_exec);
03997    ast_register_application_xml(eapp, eagi_exec);
03998    ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
03999    AST_TEST_REGISTER(test_agi_null_docs);
04000    return ast_register_application_xml(app, agi_exec);
04001 }
04002 
04003 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Gateway Interface (AGI)",
04004       .load = load_module,
04005       .unload = unload_module,
04006       .load_pri = AST_MODPRI_APP_DEPEND,
04007       );

Generated on Sat Mar 10 01:54:23 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7