Wed Mar 3 22:37:06 2010

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

Generated on 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1