Sun Oct 16 2011 08:41:44

Asterisk developer's documentation


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