Thu Sep 7 01:03:03 2017

Asterisk developer's documentation


res_agi.c

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

Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1