Thu Apr 28 2011 17:13:35

Asterisk developer's documentation


res_agi.c

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