Wed Apr 6 11:29:46 2011

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

Generated on Wed Apr 6 11:29:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7