Wed Aug 7 17:16:10 2019

Asterisk developer's documentation


res_agi.c File Reference

AGI - the Asterisk Gateway Interface. More...

#include "asterisk.h"
#include <math.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pthread.h>
#include "asterisk/paths.h"
#include "asterisk/network.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/astdb.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/image.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/strings.h"
#include "asterisk/manager.h"
#include "asterisk/ast_version.h"
#include "asterisk/speech.h"
#include "asterisk/term.h"
#include "asterisk/xmldoc.h"
#include "asterisk/srv.h"
#include "asterisk/test.h"
#include "asterisk/agi.h"

Go to the source code of this file.

Data Structures

struct  agi_cmd
struct  agi_commands

Defines

#define AGI_BUF_INITSIZE   256
#define AGI_BUF_LEN   2048
#define AGI_BUF_SIZE   1024
#define AGI_NANDFS_RETRY   3
#define AGI_PORT   4573
#define AMI_BUF_SIZE   2048
#define AST_API_MODULE
#define ASYNC_AGI_BREAK   3
#define MAX_AGI_CONNECT   2000
#define MAX_ARGS   128
#define MAX_CMD_LEN   80
#define SRV_PREFIX   "_agi._tcp."
#define TONE_BLOCK_SIZE   200

Enumerations

enum  agi_result {
  AGI_RESULT_FAILURE = -1, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_FAST, AGI_RESULT_SUCCESS_ASYNC,
  AGI_RESULT_NOTFOUND, AGI_RESULT_HANGUP
}

Functions

static void __init_agi_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static int action_add_agi_cmd (struct mansession *s, const struct message *m)
 Add a new command to execute by the Async AGI application.
static int add_agi_cmd (struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
static int add_to_agi (struct ast_channel *chan)
static void agi_destroy_commands_cb (void *data)
static int agi_exec (struct ast_channel *chan, const char *data)
static int agi_exec_full (struct ast_channel *chan, const char *data, int enhanced, int dead)
static enum agi_result agi_handle_command (struct ast_channel *chan, AGI *agi, char *buf, int dead)
int AST_OPTIONAL_API_NAME() ast_agi_register (struct ast_module *mod, agi_command *cmd)
int AST_OPTIONAL_API_NAME() ast_agi_register_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
int AST_OPTIONAL_API_NAME() ast_agi_send (int fd, struct ast_channel *chan, char *fmt,...)
int AST_OPTIONAL_API_NAME() ast_agi_unregister (struct ast_module *mod, agi_command *cmd)
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
static enum agi_result async_agi_read_frame (struct ast_channel *chan)
static int deadagi_exec (struct ast_channel *chan, const char *data)
static int eagi_exec (struct ast_channel *chan, const char *data)
static agi_commandfind_command (const char *const cmds[], int exact)
static void free_agi_cmd (struct agi_cmd *cmd)
static struct agi_cmdget_agi_cmd (struct ast_channel *chan)
static int handle_answer (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_asyncagi_break (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_autohangup (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_channelstatus (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static char * handle_cli_agi_add_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to add applications to execute in Async AGI.
static char * handle_cli_agi_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_agi_dump_html (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_agi_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int handle_controlstreamfile (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_dbdel (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_dbdeltree (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_dbget (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_dbput (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_exec (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_getdata (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_getoption (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 get option - really similar to the handle_streamfile, but with a timeout
static int handle_getvariable (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_getvariablefull (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_hangup (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_noop (struct ast_channel *chan, AGI *agi, int arg, const char *const argv[])
static int handle_recordfile (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_recvchar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_recvtext (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_sayalpha (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_saydate (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_saydatetime (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_saydigits (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_saynumber (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 Say number in various language syntaxes.
static int handle_sayphonetic (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_saytime (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_sendimage (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_sendtext (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_setcallerid (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_setcontext (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_setextension (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_setmusic (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_setpriority (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_setvariable (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechactivategrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechcreate (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechdeactivategrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechdestroy (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechloadgrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechrecognize (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechset (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_speechunloadgrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_streamfile (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_tddmode (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_verbose (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static int handle_waitfordigit (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
static char * help_workhorse (int fd, const char *const match[])
static enum agi_result launch_asyncagi (struct ast_channel *chan, char *argv[], int *efd)
static enum agi_result launch_ha_netscript (char *agiurl, char *argv[], int *fds)
static enum agi_result launch_netscript (char *agiurl, char *argv[], int *fds)
static enum agi_result launch_script (struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
static int load_module (void)
static int parse_args (char *s, int *max, const char *argv[])
static enum agi_result run_agi (struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
static void setup_env (struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
static int speech_streamfile (struct ast_channel *chan, const char *filename, const char *preflang, int offset)
static int unload_module (void)
static void write_html_escaped (FILE *htmlfile, char *str)
 Convert string to use HTML escaped characters.
static int write_htmldump (const char *filename)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk Gateway Interface (AGI)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, }
static struct ast_threadstorage agi_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_agi_buf , .custom_init = NULL , }
static struct ast_datastore_info agi_commands_datastore_info
static int agidebug = 0
static char * app = "AGI"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_agi []
static struct agi_command commands []
 AGI commands list.
static char * deadapp = "DeadAGI"
static char * eapp = "EAGI"

Detailed Description

AGI - the Asterisk Gateway Interface.

Author:
Mark Spencer <markster@digium.com>
Todo:
Convert the rest of the AGI commands over to XML documentation

Definition in file res_agi.c.


Define Documentation

#define AGI_BUF_INITSIZE   256

Definition at line 939 of file res_agi.c.

Referenced by ast_agi_send().

#define AGI_BUF_LEN   2048

Definition at line 906 of file res_agi.c.

Referenced by run_agi().

#define AGI_BUF_SIZE   1024

Referenced by launch_asyncagi().

#define AGI_NANDFS_RETRY   3

Definition at line 905 of file res_agi.c.

Referenced by run_agi().

#define AGI_PORT   4573

Definition at line 922 of file res_agi.c.

Referenced by launch_netscript().

#define AMI_BUF_SIZE   2048

Referenced by launch_asyncagi().

#define AST_API_MODULE

Definition at line 69 of file res_agi.c.

#define ASYNC_AGI_BREAK   3

Special return code for "asyncagi break" command.

Definition at line 925 of file res_agi.c.

Referenced by agi_handle_command(), and handle_asyncagi_break().

#define MAX_AGI_CONNECT   2000

Definition at line 920 of file res_agi.c.

Referenced by launch_netscript().

#define MAX_ARGS   128

Definition at line 903 of file res_agi.c.

#define MAX_CMD_LEN   80
#define SRV_PREFIX   "_agi._tcp."

Definition at line 907 of file res_agi.c.

Referenced by launch_ha_netscript().

#define TONE_BLOCK_SIZE   200

Definition at line 917 of file res_agi.c.


Enumeration Type Documentation

enum agi_result
Enumerator:
AGI_RESULT_FAILURE 
AGI_RESULT_SUCCESS 
AGI_RESULT_SUCCESS_FAST 
AGI_RESULT_SUCCESS_ASYNC 
AGI_RESULT_NOTFOUND 
AGI_RESULT_HANGUP 

Definition at line 927 of file res_agi.c.


Function Documentation

static void __init_agi_buf ( void   )  [static]

Definition at line 938 of file res_agi.c.

00942 {

static void __reg_module ( void   )  [static]

Definition at line 4006 of file res_agi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4006 of file res_agi.c.

static int action_add_agi_cmd ( struct mansession s,
const struct message m 
) [static]

Add a new command to execute by the Async AGI application.

Parameters:
s 
m It will append the application to the specified channel's queue if the channel is not inside Async AGI application it will return an error
Return values:
0 on success or incorrect use
1 on failure to add the command ( most likely because the channel is not in Async AGI loop )

Definition at line 1155 of file res_agi.c.

References add_agi_cmd(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_strlen_zero(), astman_get_header(), astman_send_ack(), and astman_send_error().

Referenced by load_module().

01156 {
01157    const char *channel = astman_get_header(m, "Channel");
01158    const char *cmdbuff = astman_get_header(m, "Command");
01159    const char *cmdid   = astman_get_header(m, "CommandID");
01160    struct ast_channel *chan;
01161    char buf[256];
01162 
01163    if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
01164       astman_send_error(s, m, "Both, Channel and Command are *required*");
01165       return 0;
01166    }
01167 
01168    if (!(chan = ast_channel_get_by_name(channel))) {
01169       snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
01170       astman_send_error(s, m, buf);
01171       return 0;
01172    }
01173 
01174    ast_channel_lock(chan);
01175 
01176    if (add_agi_cmd(chan, cmdbuff, cmdid)) {
01177       snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
01178       astman_send_error(s, m, buf);
01179       ast_channel_unlock(chan);
01180       chan = ast_channel_unref(chan);
01181       return 0;
01182    }
01183 
01184    ast_channel_unlock(chan);
01185    chan = ast_channel_unref(chan);
01186 
01187    astman_send_ack(s, m, "Added AGI command to queue");
01188 
01189    return 0;
01190 }

static int add_agi_cmd ( struct ast_channel chan,
const char *  cmd_buff,
const char *  cmd_id 
) [static]

Definition at line 1026 of file res_agi.c.

References agi_commands_datastore_info, ast_calloc, ast_channel_datastore_find(), ast_free, AST_LIST_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strdup, agi_cmd::cmd_buffer, agi_cmd::cmd_id, ast_datastore::data, agi_cmd::entry, and LOG_WARNING.

Referenced by action_add_agi_cmd(), and handle_cli_agi_add_cmd().

01027 {
01028    struct ast_datastore *store;
01029    struct agi_cmd *cmd;
01030    AST_LIST_HEAD(, agi_cmd) *agi_commands;
01031 
01032    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01033    if (!store) {
01034       ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", chan->name);
01035       return -1;
01036    }
01037    agi_commands = store->data;
01038    cmd = ast_calloc(1, sizeof(*cmd));
01039    if (!cmd) {
01040       return -1;
01041    }
01042    cmd->cmd_buffer = ast_strdup(cmd_buff);
01043    if (!cmd->cmd_buffer) {
01044       ast_free(cmd);
01045       return -1;
01046    }
01047    cmd->cmd_id = ast_strdup(cmd_id);
01048    if (!cmd->cmd_id) {
01049       ast_free(cmd->cmd_buffer);
01050       ast_free(cmd);
01051       return -1;
01052    }
01053    AST_LIST_LOCK(agi_commands);
01054    AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
01055    AST_LIST_UNLOCK(agi_commands);
01056    return 0;
01057 }

static int add_to_agi ( struct ast_channel chan  )  [static]

Definition at line 1059 of file res_agi.c.

References agi_commands_datastore_info, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, ast_log(), ast_datastore::data, and LOG_ERROR.

Referenced by launch_asyncagi().

01060 {
01061    struct ast_datastore *datastore;
01062    AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
01063 
01064    /* check if already on AGI */
01065    ast_channel_lock(chan);
01066    datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01067    ast_channel_unlock(chan);
01068    if (datastore) {
01069       /* we already have an AGI datastore, let's just
01070          return success */
01071       return 0;
01072    }
01073 
01074    /* the channel has never been on Async AGI,
01075       let's allocate it's datastore */
01076    datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
01077    if (!datastore) {
01078       return -1;
01079    }
01080    agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
01081    if (!agi_cmds_list) {
01082       ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
01083       ast_datastore_free(datastore);
01084       return -1;
01085    }
01086    datastore->data = agi_cmds_list;
01087    AST_LIST_HEAD_INIT(agi_cmds_list);
01088    ast_channel_lock(chan);
01089    ast_channel_datastore_add(chan, datastore);
01090    ast_channel_unlock(chan);
01091    return 0;
01092 }

static void agi_destroy_commands_cb ( void *  data  )  [static]

Definition at line 985 of file res_agi.c.

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, agi_cmd::entry, and free_agi_cmd().

00986 {
00987    struct agi_cmd *cmd;
00988    AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
00989    AST_LIST_LOCK(chan_cmds);
00990    while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
00991       free_agi_cmd(cmd);
00992    }
00993    AST_LIST_UNLOCK(chan_cmds);
00994    AST_LIST_HEAD_DESTROY(chan_cmds);
00995    ast_free(chan_cmds);
00996 }

static int agi_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 3891 of file res_agi.c.

References agi_exec_full(), and ast_check_hangup().

Referenced by deadagi_exec(), and load_module().

03892 {
03893    if (!ast_check_hangup(chan))
03894       return agi_exec_full(chan, data, 0, 0);
03895    else
03896       return agi_exec_full(chan, data, 0, 1);
03897 }

static int agi_exec_full ( struct ast_channel chan,
const char *  data,
int  enhanced,
int  dead 
) [static]

Definition at line 3824 of file res_agi.c.

References ast_channel::_state, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_NOTFOUND, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, AGI_RESULT_SUCCESS_FAST, args, ast_answer(), AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_safe_fork_cleanup(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), launch_script(), LOG_WARNING, MAX_ARGS, pbx_builtin_setvar_helper(), run_agi(), and status.

Referenced by agi_exec(), and eagi_exec().

03825 {
03826    enum agi_result res;
03827    char *buf;
03828    int fds[2], efd = -1, pid = -1;
03829    AST_DECLARE_APP_ARGS(args,
03830       AST_APP_ARG(arg)[MAX_ARGS];
03831    );
03832    AGI agi;
03833 
03834    if (ast_strlen_zero(data)) {
03835       ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03836       return -1;
03837    }
03838    if (dead)
03839       ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03840    memset(&agi, 0, sizeof(agi));
03841    buf = ast_strdupa(data);
03842    AST_STANDARD_APP_ARGS(args, buf);
03843    args.argv[args.argc] = NULL;
03844 #if 0
03845     /* Answer if need be */
03846    if (chan->_state != AST_STATE_UP) {
03847       if (ast_answer(chan))
03848          return -1;
03849    }
03850 #endif
03851    res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03852    /* Async AGI do not require run_agi(), so just proceed if normal AGI
03853       or Fast AGI are setup with success. */
03854    if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03855       int status = 0;
03856       agi.fd = fds[1];
03857       agi.ctrl = fds[0];
03858       agi.audio = efd;
03859       agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03860       res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03861       /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
03862       if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03863          res = AGI_RESULT_FAILURE;
03864       if (fds[1] != fds[0])
03865          close(fds[1]);
03866       if (efd > -1)
03867          close(efd);
03868    }
03869    ast_safe_fork_cleanup();
03870 
03871    switch (res) {
03872    case AGI_RESULT_SUCCESS:
03873    case AGI_RESULT_SUCCESS_FAST:
03874    case AGI_RESULT_SUCCESS_ASYNC:
03875       pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03876       break;
03877    case AGI_RESULT_FAILURE:
03878       pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03879       break;
03880    case AGI_RESULT_NOTFOUND:
03881       pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03882       break;
03883    case AGI_RESULT_HANGUP:
03884       pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03885       return -1;
03886    }
03887 
03888    return 0;
03889 }

static enum agi_result agi_handle_command ( struct ast_channel chan,
AGI agi,
char *  buf,
int  dead 
) [static]

Definition at line 3355 of file res_agi.c.

References AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, ast_agi_send(), ast_cdr_setapp(), ast_check_hangup(), ast_module_ref(), ast_module_unref(), ast_random(), ast_strdupa, ast_strlen_zero(), ASYNC_AGI_BREAK, ast_channel::cdr, agi_command::dead, EVENT_FLAG_AGI, agi_state::fd, find_command(), agi_command::handler, manager_event, MAX_ARGS, agi_command::mod, parse_args(), RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_command::usage.

Referenced by launch_asyncagi(), and run_agi().

03356 {
03357    const char *argv[MAX_ARGS];
03358    int argc = MAX_ARGS;
03359    int res;
03360    agi_command *c;
03361    const char *ami_res;
03362    char *ami_cmd = ast_strdupa(buf);
03363    int command_id = ast_random();
03364    int resultcode;
03365 
03366    manager_event(EVENT_FLAG_AGI, "AGIExec",
03367          "SubEvent: Start\r\n"
03368          "Channel: %s\r\n"
03369          "CommandId: %d\r\n"
03370          "Command: %s\r\n", chan->name, command_id, ami_cmd);
03371    parse_args(buf, &argc, argv);
03372    c = find_command(argv, 0);
03373    if (c && (!dead || (dead && c->dead))) {
03374       /* if this command wasn't registered by res_agi, be sure to usecount
03375       the module we are using */
03376       if (c->mod != ast_module_info->self)
03377          ast_module_ref(c->mod);
03378       /* If the AGI command being executed is an actual application (using agi exec)
03379       the app field will be updated in pbx_exec via handle_exec */
03380       if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
03381          ast_cdr_setapp(chan->cdr, "AGI", buf);
03382 
03383       res = c->handler(chan, agi, argc, argv);
03384       if (c->mod != ast_module_info->self)
03385          ast_module_unref(c->mod);
03386       switch (res) {
03387       case RESULT_SHOWUSAGE:
03388          ami_res = "Usage";
03389          resultcode = 520;
03390          break;
03391       case RESULT_FAILURE:
03392          ami_res = "Failure";
03393          resultcode = -1;
03394          break;
03395       case ASYNC_AGI_BREAK:
03396       case RESULT_SUCCESS:
03397          ami_res = "Success";
03398          resultcode = 200;
03399          break;
03400       default:
03401          ami_res = "Unknown Result";
03402          resultcode = 200;
03403          break;
03404       }
03405       manager_event(EVENT_FLAG_AGI, "AGIExec",
03406             "SubEvent: End\r\n"
03407             "Channel: %s\r\n"
03408             "CommandId: %d\r\n"
03409             "Command: %s\r\n"
03410             "ResultCode: %d\r\n"
03411             "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
03412       switch (res) {
03413       case RESULT_SHOWUSAGE:
03414          if (ast_strlen_zero(c->usage)) {
03415             ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
03416          } else {
03417             ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
03418             ast_agi_send(agi->fd, chan, "%s", c->usage);
03419             ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
03420          }
03421          break;
03422       case ASYNC_AGI_BREAK:
03423          return AGI_RESULT_SUCCESS_ASYNC;
03424       case RESULT_FAILURE:
03425          /* The RESULT_FAILURE code is usually because the channel hungup. */
03426          return AGI_RESULT_FAILURE;
03427       default:
03428          break;
03429       }
03430    } else if (c) {
03431       ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
03432       manager_event(EVENT_FLAG_AGI, "AGIExec",
03433             "SubEvent: End\r\n"
03434             "Channel: %s\r\n"
03435             "CommandId: %d\r\n"
03436             "Command: %s\r\n"
03437             "ResultCode: 511\r\n"
03438             "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
03439    } else {
03440       ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
03441       manager_event(EVENT_FLAG_AGI, "AGIExec",
03442             "SubEvent: End\r\n"
03443             "Channel: %s\r\n"
03444             "CommandId: %d\r\n"
03445             "Command: %s\r\n"
03446             "ResultCode: 510\r\n"
03447             "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
03448    }
03449    return AGI_RESULT_SUCCESS;
03450 }

int AST_OPTIONAL_API_NAME() ast_agi_register ( struct ast_module mod,
agi_command cmd 
)

Definition at line 3123 of file res_agi.c.

References ast_join(), AST_LIST_INSERT_TAIL, ast_log(), ast_module_ref(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_strdup, ast_strlen_zero(), ast_verb, AST_XML_DOC, ast_xmldoc_build_description(), ast_xmldoc_build_seealso(), ast_xmldoc_build_synopsis(), ast_xmldoc_build_syntax(), find_command(), LOG_WARNING, and MAX_CMD_LEN.

Referenced by ast_agi_register_multiple(), and load_module().

03124 {
03125    char fullcmd[MAX_CMD_LEN];
03126 
03127    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03128 
03129    if (!find_command(cmd->cmda, 1)) {
03130       *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
03131       if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
03132 #ifdef AST_XML_DOCS
03133          *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
03134          *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
03135          *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
03136          *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
03137          *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
03138 #endif
03139 #ifndef HAVE_NULLSAFE_PRINTF
03140          if (!cmd->summary) {
03141             *((char **) &cmd->summary) = ast_strdup("");
03142          }
03143          if (!cmd->usage) {
03144             *((char **) &cmd->usage) = ast_strdup("");
03145          }
03146          if (!cmd->syntax) {
03147             *((char **) &cmd->syntax) = ast_strdup("");
03148          }
03149          if (!cmd->seealso) {
03150             *((char **) &cmd->seealso) = ast_strdup("");
03151          }
03152 #endif
03153       }
03154 
03155       cmd->mod = mod;
03156       AST_RWLIST_WRLOCK(&agi_commands);
03157       AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
03158       AST_RWLIST_UNLOCK(&agi_commands);
03159       if (mod != ast_module_info->self)
03160          ast_module_ref(ast_module_info->self);
03161       ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
03162       return 1;
03163    } else {
03164       ast_log(LOG_WARNING, "Command already registered!\n");
03165       return 0;
03166    }
03167 }

int AST_OPTIONAL_API_NAME() ast_agi_register_multiple ( struct ast_module mod,
struct agi_command cmd,
unsigned int  len 
)

Definition at line 3208 of file res_agi.c.

References ast_agi_register(), ast_agi_unregister(), len(), and agi_command::mod.

Referenced by load_module().

03209 {
03210    unsigned int i, x = 0;
03211 
03212    for (i = 0; i < len; i++) {
03213       if (ast_agi_register(mod, cmd + i) == 1) {
03214          x++;
03215          continue;
03216       }
03217 
03218       /* registration failed, unregister everything
03219          that had been registered up to that point
03220       */
03221       for (; x > 0; x--) {
03222          /* we are intentionally ignoring the
03223             result of ast_agi_unregister() here,
03224             but it should be safe to do so since
03225             we just registered these commands and
03226             the only possible way for unregistration
03227             to fail is if the command is not
03228             registered
03229          */
03230          (void) ast_agi_unregister(mod, cmd + x - 1);
03231       }
03232       return -1;
03233    }
03234 
03235    return 0;
03236 }

int AST_OPTIONAL_API_NAME() ast_agi_send ( int  fd,
struct ast_channel chan,
char *  fmt,
  ... 
)

Definition at line 941 of file res_agi.c.

References agi_buf, AGI_BUF_INITSIZE, ast_carefulwrite(), ast_log(), ast_str_buffer(), ast_str_set_va(), ast_str_strlen(), ast_str_thread_get(), ast_verbose, and LOG_ERROR.

Referenced by agi_handle_command(), handle_answer(), handle_asyncagi_break(), handle_autohangup(), handle_channelstatus(), handle_controlstreamfile(), handle_dbdel(), handle_dbdeltree(), handle_dbget(), handle_dbput(), handle_exec(), handle_getdata(), handle_getoption(), handle_getvariable(), handle_getvariablefull(), handle_gosub(), handle_hangup(), handle_noop(), handle_recordfile(), handle_recvchar(), handle_recvtext(), handle_sayalpha(), handle_saydate(), handle_saydatetime(), handle_saydigits(), handle_saynumber(), handle_sayphonetic(), handle_saytime(), handle_sendimage(), handle_sendtext(), handle_setcallerid(), handle_setcontext(), handle_setextension(), handle_setmusic(), handle_setpriority(), handle_setvariable(), handle_speechactivategrammar(), handle_speechcreate(), handle_speechdeactivategrammar(), handle_speechdestroy(), handle_speechloadgrammar(), handle_speechrecognize(), handle_speechset(), handle_speechunloadgrammar(), handle_streamfile(), handle_tddmode(), handle_verbose(), handle_waitfordigit(), launch_netscript(), run_agi(), and setup_env().

00942 {
00943    int res = 0;
00944    va_list ap;
00945    struct ast_str *buf;
00946 
00947    if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
00948       return -1;
00949 
00950    va_start(ap, fmt);
00951    res = ast_str_set_va(&buf, 0, fmt, ap);
00952    va_end(ap);
00953 
00954    if (res == -1) {
00955       ast_log(LOG_ERROR, "Out of memory\n");
00956       return -1;
00957    }
00958 
00959    if (agidebug) {
00960       if (chan) {
00961          ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
00962       } else {
00963          ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
00964       }
00965    }
00966 
00967    return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
00968 }

int AST_OPTIONAL_API_NAME() ast_agi_unregister ( struct ast_module mod,
agi_command cmd 
)

Definition at line 3169 of file res_agi.c.

References ast_free, ast_join(), ast_log(), ast_module_unref(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, AST_XML_DOC, agi_command::docsrc, LOG_WARNING, MAX_CMD_LEN, agi_command::mod, agi_command::seealso, agi_command::summary, agi_command::syntax, and agi_command::usage.

Referenced by ast_agi_register_multiple(), ast_agi_unregister_multiple(), and unload_module().

03170 {
03171    struct agi_command *e;
03172    int unregistered = 0;
03173    char fullcmd[MAX_CMD_LEN];
03174 
03175    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03176 
03177    AST_RWLIST_WRLOCK(&agi_commands);
03178    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
03179       if (cmd == e) {
03180          AST_RWLIST_REMOVE_CURRENT(list);
03181          if (mod != ast_module_info->self)
03182             ast_module_unref(ast_module_info->self);
03183 #ifdef AST_XML_DOCS
03184          if (e->docsrc == AST_XML_DOC) {
03185             ast_free((char *) e->summary);
03186             ast_free((char *) e->usage);
03187             ast_free((char *) e->syntax);
03188             ast_free((char *) e->seealso);
03189             *((char **) &e->summary) = NULL;
03190             *((char **) &e->usage) = NULL;
03191             *((char **) &e->syntax) = NULL;
03192             *((char **) &e->seealso) = NULL;
03193          }
03194 #endif
03195          unregistered=1;
03196          break;
03197       }
03198    }
03199    AST_RWLIST_TRAVERSE_SAFE_END;
03200    AST_RWLIST_UNLOCK(&agi_commands);
03201    if (unregistered)
03202       ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
03203    else
03204       ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
03205    return unregistered;
03206 }

int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple ( struct ast_module mod,
struct agi_command cmd,
unsigned int  len 
)

Definition at line 3238 of file res_agi.c.

References ast_agi_unregister(), len(), and agi_command::mod.

Referenced by unload_module().

03239 {
03240    unsigned int i;
03241    int res = 0;
03242 
03243    for (i = 0; i < len; i++) {
03244       /* remember whether any of the unregistration
03245          attempts failed... there is no recourse if
03246          any of them do
03247       */
03248       res |= ast_agi_unregister(mod, cmd + i);
03249    }
03250 
03251    return res;
03252 }

static enum agi_result async_agi_read_frame ( struct ast_channel chan  )  [static]

Definition at line 1205 of file res_agi.c.

References AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, AST_CONTROL_HANGUP, ast_debug, AST_FRAME_CONTROL, ast_frfree, ast_read(), f, ast_frame::frametype, ast_frame_subclass::integer, and ast_frame::subclass.

Referenced by launch_asyncagi().

01206 {
01207    struct ast_frame *f;
01208 
01209    f = ast_read(chan);
01210    if (!f) {
01211       ast_debug(3, "No frame read on channel %s, going out ...\n", chan->name);
01212       return AGI_RESULT_HANGUP;
01213    }
01214    if (f->frametype == AST_FRAME_CONTROL) {
01215       /*
01216        * Is there any other frame we should care about besides
01217        * AST_CONTROL_HANGUP?
01218        */
01219       switch (f->subclass.integer) {
01220       case AST_CONTROL_HANGUP:
01221          ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
01222          ast_frfree(f);
01223          return AGI_RESULT_HANGUP;
01224       default:
01225          break;
01226       }
01227    }
01228    ast_frfree(f);
01229 
01230    return AGI_RESULT_SUCCESS;
01231 }

static int deadagi_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 3921 of file res_agi.c.

References agi_exec(), ast_log(), and LOG_WARNING.

Referenced by load_module().

03922 {
03923    ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03924    return agi_exec(chan, data);
03925 }

static int eagi_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 3899 of file res_agi.c.

References agi_exec_full(), ast_check_hangup(), AST_FORMAT_SLINEAR, ast_getformatname(), ast_log(), ast_set_read_format(), LOG_ERROR, LOG_WARNING, and ast_channel::readformat.

Referenced by load_module().

03900 {
03901    int readformat, res;
03902 
03903    if (ast_check_hangup(chan)) {
03904       ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03905       return 0;
03906    }
03907    readformat = chan->readformat;
03908    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03909       ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03910       return -1;
03911    }
03912    res = agi_exec_full(chan, data, 1, 0);
03913    if (!res) {
03914       if (ast_set_read_format(chan, readformat)) {
03915          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03916       }
03917    }
03918    return res;
03919 }

static agi_command * find_command ( const char *const   cmds[],
int  exact 
) [static]

Definition at line 3254 of file res_agi.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, agi_command::cmda, and match().

Referenced by agi_handle_command(), ast_agi_register(), and handle_cli_agi_show().

03255 {
03256    int y, match;
03257    struct agi_command *e;
03258 
03259    AST_RWLIST_RDLOCK(&agi_commands);
03260    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03261       if (!e->cmda[0])
03262          break;
03263       /* start optimistic */
03264       match = 1;
03265       for (y = 0; match && cmds[y]; y++) {
03266          /* If there are no more words in the command (and we're looking for
03267             an exact match) or there is a difference between the two words,
03268             then this is not a match */
03269          if (!e->cmda[y] && !exact)
03270             break;
03271          /* don't segfault if the next part of a command doesn't exist */
03272          if (!e->cmda[y]) {
03273             AST_RWLIST_UNLOCK(&agi_commands);
03274             return NULL;
03275          }
03276          if (strcasecmp(e->cmda[y], cmds[y]))
03277             match = 0;
03278       }
03279       /* If more words are needed to complete the command then this is not
03280          a candidate (unless we're looking for a really inexact answer  */
03281       if ((exact > -1) && e->cmda[y])
03282          match = 0;
03283       if (match) {
03284          AST_RWLIST_UNLOCK(&agi_commands);
03285          return e;
03286       }
03287    }
03288    AST_RWLIST_UNLOCK(&agi_commands);
03289    return NULL;
03290 }

static void free_agi_cmd ( struct agi_cmd cmd  )  [static]

Definition at line 977 of file res_agi.c.

References ast_free.

Referenced by agi_destroy_commands_cb(), and launch_asyncagi().

00978 {
00979    ast_free(cmd->cmd_buffer);
00980    ast_free(cmd->cmd_id);
00981    ast_free(cmd);
00982 }

static struct agi_cmd* get_agi_cmd ( struct ast_channel chan  )  [static, read]

Definition at line 1004 of file res_agi.c.

References agi_commands_datastore_info, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, agi_cmd::entry, and LOG_ERROR.

Referenced by launch_asyncagi().

01005 {
01006    struct ast_datastore *store;
01007    struct agi_cmd *cmd;
01008    AST_LIST_HEAD(, agi_cmd) *agi_commands;
01009 
01010    ast_channel_lock(chan);
01011    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01012    ast_channel_unlock(chan);
01013    if (!store) {
01014       ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
01015          chan->name);
01016       return NULL;
01017    }
01018    agi_commands = store->data;
01019    AST_LIST_LOCK(agi_commands);
01020    cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
01021    AST_LIST_UNLOCK(agi_commands);
01022    return cmd;
01023 }

static int handle_answer ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1766 of file res_agi.c.

References ast_channel::_state, ast_agi_send(), ast_answer(), AST_STATE_UP, agi_state::fd, RESULT_FAILURE, and RESULT_SUCCESS.

01767 {
01768    int res = 0;
01769 
01770    /* Answer the channel */
01771    if (chan->_state != AST_STATE_UP)
01772       res = ast_answer(chan);
01773 
01774    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01775    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01776 }

static int handle_asyncagi_break ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1778 of file res_agi.c.

References ast_agi_send(), ASYNC_AGI_BREAK, and agi_state::fd.

01779 {
01780    ast_agi_send(agi->fd, chan, "200 result=0\n");
01781    return ASYNC_AGI_BREAK;
01782 }

static int handle_autohangup ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2419 of file res_agi.c.

References ast_agi_send(), ast_channel_setwhentohangup_tv(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02420 {
02421    double timeout;
02422    struct timeval whentohangup = { 0, 0 };
02423 
02424    if (argc != 3)
02425       return RESULT_SHOWUSAGE;
02426    if (sscanf(argv[2], "%30lf", &timeout) != 1)
02427       return RESULT_SHOWUSAGE;
02428    if (timeout < 0)
02429       timeout = 0;
02430    if (timeout) {
02431       whentohangup.tv_sec = timeout;
02432       whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
02433    }
02434    ast_channel_setwhentohangup_tv(chan, whentohangup);
02435    ast_agi_send(agi->fd, chan, "200 result=0\n");
02436    return RESULT_SUCCESS;
02437 }

static int handle_channelstatus ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2533 of file res_agi.c.

References ast_channel::_state, ast_agi_send(), ast_channel_get_by_name(), ast_channel_unref, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02534 {
02535    struct ast_channel *c;
02536    if (argc == 2) {
02537       /* no argument: supply info on the current channel */
02538       ast_agi_send(agi->fd, chan, "200 result=%u\n", chan->_state);
02539       return RESULT_SUCCESS;
02540    } else if (argc == 3) {
02541       /* one argument: look for info on the specified channel */
02542       if ((c = ast_channel_get_by_name(argv[2]))) {
02543          ast_agi_send(agi->fd, chan, "200 result=%u\n", c->_state);
02544          c = ast_channel_unref(c);
02545          return RESULT_SUCCESS;
02546       }
02547       /* if we get this far no channel name matched the argument given */
02548       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02549       return RESULT_SUCCESS;
02550    } else {
02551       return RESULT_SHOWUSAGE;
02552    }
02553 }

static char* handle_cli_agi_add_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to add applications to execute in Async AGI.

Parameters:
e 
cmd 
a 
Return values:
CLI_SUCCESS on success
NULL when init or tab completion is used

Definition at line 1103 of file res_agi.c.

References add_agi_cmd(), ast_cli_args::argc, ast_cli_args::argv, ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), ast_debug, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01104 {
01105    struct ast_channel *chan;
01106    switch (cmd) {
01107    case CLI_INIT:
01108       e->command = "agi exec";
01109       e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
01110             "       Add AGI command to the execute queue of the specified channel in Async AGI\n";
01111       return NULL;
01112    case CLI_GENERATE:
01113       if (a->pos == 2)
01114          return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
01115       return NULL;
01116    }
01117 
01118    if (a->argc < 4) {
01119       return CLI_SHOWUSAGE;
01120    }
01121 
01122    if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
01123       ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
01124       return CLI_FAILURE;
01125    }
01126 
01127    ast_channel_lock(chan);
01128 
01129    if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
01130       ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", chan->name);
01131       ast_channel_unlock(chan);
01132       chan = ast_channel_unref(chan);
01133       return CLI_FAILURE;
01134    }
01135 
01136    ast_debug(1, "Added AGI command to channel %s queue\n", chan->name);
01137 
01138    ast_channel_unlock(chan);
01139    chan = ast_channel_unref(chan);
01140 
01141    return CLI_SUCCESS;
01142 }

static char* handle_cli_agi_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2710 of file res_agi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

02711 {
02712    switch (cmd) {
02713    case CLI_INIT:
02714       e->command = "agi set debug [on|off]";
02715       e->usage =
02716          "Usage: agi set debug [on|off]\n"
02717          "       Enables/disables dumping of AGI transactions for\n"
02718          "       debugging purposes.\n";
02719       return NULL;
02720 
02721    case CLI_GENERATE:
02722       return NULL;
02723    }
02724 
02725    if (a->argc != e->args)
02726       return CLI_SHOWUSAGE;
02727 
02728    if (strncasecmp(a->argv[3], "off", 3) == 0) {
02729       agidebug = 0;
02730    } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
02731       agidebug = 1;
02732    } else {
02733       return CLI_SHOWUSAGE;
02734    }
02735    ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
02736    return CLI_SUCCESS;
02737 }

static char* handle_cli_agi_dump_html ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3800 of file res_agi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_entry::usage, and write_htmldump().

03801 {
03802    switch (cmd) {
03803    case CLI_INIT:
03804       e->command = "agi dump html";
03805       e->usage =
03806          "Usage: agi dump html <filename>\n"
03807          "       Dumps the AGI command list in HTML format to the given\n"
03808          "       file.\n";
03809       return NULL;
03810    case CLI_GENERATE:
03811       return NULL;
03812    }
03813    if (a->argc != e->args + 1)
03814       return CLI_SHOWUSAGE;
03815 
03816    if (write_htmldump(a->argv[e->args]) < 0) {
03817       ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03818       return CLI_SHOWUSAGE;
03819    }
03820    ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03821    return CLI_SUCCESS;
03822 }

static char* handle_cli_agi_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3613 of file res_agi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_free, ast_join(), ast_malloc, AST_TERM_MAX_ESCAPE_CHARS, AST_XML_DOC, ast_xmldoc_printable(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_CYAN, COLOR_MAGENTA, ast_cli_entry::command, agi_command::dead, agi_command::docsrc, ast_cli_args::fd, find_command(), help_workhorse(), MAX_CMD_LEN, S_OR, agi_command::seealso, agi_command::summary, synopsis, agi_command::syntax, term_color(), agi_command::usage, and ast_cli_entry::usage.

03614 {
03615    struct agi_command *command;
03616    char fullcmd[MAX_CMD_LEN];
03617    int error = 0;
03618 
03619    switch (cmd) {
03620    case CLI_INIT:
03621       e->command = "agi show commands [topic]";
03622       e->usage =
03623          "Usage: agi show commands [topic] <topic>\n"
03624          "       When called with a topic as an argument, displays usage\n"
03625          "       information on the given command.  If called without a\n"
03626          "       topic, it provides a list of AGI commands.\n";
03627       return NULL;
03628    case CLI_GENERATE:
03629       return NULL;
03630    }
03631    if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03632       return CLI_SHOWUSAGE;
03633    if (a->argc > e->args - 1) {
03634       command = find_command(a->argv + e->args, 1);
03635       if (command) {
03636          char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03637          char info[30 + MAX_CMD_LEN];              /* '-= Info about...' */
03638          char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];  /* '-= Info about...' with colors */
03639          char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03640          char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Description]\n with colors */
03641          char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Runs Dead]\n with colors */
03642          char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];      /* 'Yes' or 'No' with colors */
03643          char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];    /* [See Also]\n with colors */
03644          char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03645          size_t synlen, desclen, seealsolen, stxlen;
03646 
03647          term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03648          term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03649          term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03650          term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03651          term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03652          term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03653 
03654          ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03655          snprintf(info, sizeof(info), "\n  -= Info about agi '%s' =- ", fullcmd);
03656          term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03657 #ifdef AST_XML_DOCS
03658          if (command->docsrc == AST_XML_DOC) {
03659             synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03660             description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03661             seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03662             if (!seealso || !description || !synopsis) {
03663                error = 1;
03664                goto return_cleanup;
03665             }
03666          } else
03667 #endif
03668          {
03669             synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03670             synopsis = ast_malloc(synlen);
03671 
03672             desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03673             description = ast_malloc(desclen);
03674 
03675             seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03676             seealso = ast_malloc(seealsolen);
03677 
03678             if (!synopsis || !description || !seealso) {
03679                error = 1;
03680                goto return_cleanup;
03681             }
03682             term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03683             term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03684             term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03685          }
03686 
03687          stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03688          syntax = ast_malloc(stxlen);
03689          if (!syntax) {
03690             error = 1;
03691             goto return_cleanup;
03692          }
03693          term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03694 
03695          ast_cli(a->fd, "%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n", infotitle, stxtitle, syntax,
03696                desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03697                seealsotitle, seealso);
03698 return_cleanup:
03699          ast_free(synopsis);
03700          ast_free(description);
03701          ast_free(syntax);
03702          ast_free(seealso);
03703       } else {
03704          if (find_command(a->argv + e->args, -1)) {
03705             return help_workhorse(a->fd, a->argv + e->args);
03706          } else {
03707             ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03708             ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03709          }
03710       }
03711    } else {
03712       return help_workhorse(a->fd, NULL);
03713    }
03714    return (error ? CLI_FAILURE : CLI_SUCCESS);
03715 }

static int handle_controlstreamfile ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1897 of file res_agi.c.

References ast_agi_send(), ast_control_streamfile(), ast_strlen_zero(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, skipms, stop, and suspend().

01898 {
01899    int res = 0, skipms = 3000;
01900    const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
01901 
01902    if (argc < 5 || argc > 9) {
01903       return RESULT_SHOWUSAGE;
01904    }
01905 
01906    if (!ast_strlen_zero(argv[4])) {
01907       stop = argv[4];
01908    }
01909 
01910    if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
01911       return RESULT_SHOWUSAGE;
01912    }
01913 
01914    if (argc > 6 && !ast_strlen_zero(argv[6])) {
01915       fwd = argv[6];
01916    }
01917 
01918    if (argc > 7 && !ast_strlen_zero(argv[7])) {
01919       rev = argv[7];
01920    }
01921 
01922    if (argc > 8 && !ast_strlen_zero(argv[8])) {
01923       suspend = argv[8];
01924    }
01925 
01926    res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
01927 
01928    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01929 
01930    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01931 }

static int handle_dbdel ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2682 of file res_agi.c.

References ast_agi_send(), ast_db_del(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02683 {
02684    int res;
02685 
02686    if (argc != 4)
02687       return RESULT_SHOWUSAGE;
02688    res = ast_db_del(argv[2], argv[3]);
02689    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02690    return RESULT_SUCCESS;
02691 }

static int handle_dbdeltree ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2693 of file res_agi.c.

References ast_agi_send(), ast_db_deltree(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02694 {
02695    int num_deleted;
02696 
02697    if ((argc < 3) || (argc > 4)) {
02698       return RESULT_SHOWUSAGE;
02699    }
02700    if (argc == 4) {
02701       num_deleted = ast_db_deltree(argv[2], argv[3]);
02702    } else {
02703       num_deleted = ast_db_deltree(argv[2], NULL);
02704    }
02705 
02706    ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
02707    return RESULT_SUCCESS;
02708 }

static int handle_dbget ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2638 of file res_agi.c.

References ast_agi_send(), ast_db_get(), ast_free, ast_str_buffer(), ast_str_create(), ast_str_make_space(), ast_str_size(), ast_str_strlen(), ast_str_update(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02639 {
02640    int res;
02641    struct ast_str *buf;
02642 
02643    if (argc != 4)
02644       return RESULT_SHOWUSAGE;
02645 
02646    if (!(buf = ast_str_create(16))) {
02647       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02648       return RESULT_SUCCESS;
02649    }
02650 
02651    do {
02652       res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
02653       ast_str_update(buf);
02654       if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
02655          break;
02656       }
02657       if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
02658          break;
02659       }
02660    } while (1);
02661    
02662    if (res)
02663       ast_agi_send(agi->fd, chan, "200 result=0\n");
02664    else
02665       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
02666 
02667    ast_free(buf);
02668    return RESULT_SUCCESS;
02669 }

static int handle_dbput ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2671 of file res_agi.c.

References ast_agi_send(), ast_db_put(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02672 {
02673    int res;
02674 
02675    if (argc != 5)
02676       return RESULT_SHOWUSAGE;
02677    res = ast_db_put(argv[2], argv[3], argv[4]);
02678    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02679    return RESULT_SUCCESS;
02680 }

static int handle_exec ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2467 of file res_agi.c.

References ast_agi_send(), ast_alloca, ast_clear_flag, ast_compat_res_agi, AST_FLAG_DISABLE_WORKAROUNDS, ast_log(), ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_verb, agi_state::fd, LOG_WARNING, pbx_exec(), pbx_findapp(), and RESULT_SHOWUSAGE.

02468 {
02469    int res, workaround;
02470    struct ast_app *app_to_exec;
02471 
02472    if (argc < 2)
02473       return RESULT_SHOWUSAGE;
02474 
02475    ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
02476 
02477    if ((app_to_exec = pbx_findapp(argv[1]))) {
02478       if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
02479          ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02480       }
02481       if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
02482          char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr;
02483          const char *vptr;
02484          for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
02485             if (*vptr == ',') {
02486                *cptr++ = '\\';
02487                *cptr++ = ',';
02488             } else if (*vptr == '|') {
02489                *cptr++ = ',';
02490             } else {
02491                *cptr++ = *vptr;
02492             }
02493          }
02494          *cptr = '\0';
02495          res = pbx_exec(chan, app_to_exec, compat);
02496       } else {
02497          res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
02498       }
02499       if (!workaround) {
02500          ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02501       }
02502    } else {
02503       ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
02504       res = -2;
02505    }
02506    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02507 
02508    /* Even though this is wrong, users are depending upon this result. */
02509    return res;
02510 }

static int handle_getdata ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2175 of file res_agi.c.

References ast_agi_send(), ast_app_getdata_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02176 {
02177    int res, max, timeout;
02178    char data[1024];
02179 
02180    if (argc < 3)
02181       return RESULT_SHOWUSAGE;
02182    if (argc >= 4)
02183       timeout = atoi(argv[3]);
02184    else
02185       timeout = 0;
02186    if (argc >= 5)
02187       max = atoi(argv[4]);
02188    else
02189       max = 1024;
02190    res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
02191    if (res == 2)        /* New command */
02192       return RESULT_SUCCESS;
02193    else if (res == 1)
02194       ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
02195    else if (res < 0 )
02196       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02197    else
02198       ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
02199    return RESULT_SUCCESS;
02200 }

static int handle_getoption ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

get option - really similar to the handle_streamfile, but with a timeout

Definition at line 1983 of file res_agi.c.

References ast_agi_send(), ast_applystream(), ast_debug, ast_log(), ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verb, ast_waitfordigit_full(), ast_waitstream_full(), agi_state::audio, agi_state::ctrl, ast_pbx::dtimeoutms, agi_state::fd, LOG_WARNING, ast_channel::pbx, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, and ast_filestream::vfs.

01984 {
01985    int res;
01986    struct ast_filestream *fs, *vfs;
01987    long sample_offset = 0, max_length;
01988    int timeout = 0;
01989    const char *edigits = "";
01990 
01991    if ( argc < 4 || argc > 5 )
01992       return RESULT_SHOWUSAGE;
01993 
01994    if ( argv[3] )
01995       edigits = argv[3];
01996 
01997    if ( argc == 5 )
01998       timeout = atoi(argv[4]);
01999    else if (chan->pbx->dtimeoutms) {
02000       /* by default dtimeout is set to 5sec */
02001       timeout = chan->pbx->dtimeoutms; /* in msec */
02002    }
02003 
02004    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
02005       ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
02006       ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
02007       return RESULT_FAILURE;
02008    }
02009 
02010    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
02011       ast_debug(1, "Ooh, found a video stream, too\n");
02012 
02013    ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
02014 
02015    ast_seekstream(fs, 0, SEEK_END);
02016    max_length = ast_tellstream(fs);
02017    ast_seekstream(fs, sample_offset, SEEK_SET);
02018    res = ast_applystream(chan, fs);
02019    if (vfs)
02020       ast_applystream(chan, vfs);
02021    ast_playstream(fs);
02022    if (vfs)
02023       ast_playstream(vfs);
02024 
02025    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
02026    /* this is to check for if ast_waitstream closed the stream, we probably are at
02027     * the end of the stream, return that amount, else check for the amount */
02028    sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
02029    ast_stopstream(chan);
02030    if (res == 1) {
02031       /* Stop this command, don't print a result line, as there is a new command */
02032       return RESULT_SUCCESS;
02033    }
02034 
02035    /* If the user didnt press a key, wait for digitTimeout*/
02036    if (res == 0 ) {
02037       res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
02038       /* Make sure the new result is in the escape digits of the GET OPTION */
02039       if ( !strchr(edigits,res) )
02040          res=0;
02041    }
02042 
02043    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
02044    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02045 }

static int handle_getvariable ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2564 of file res_agi.c.

References ast_agi_send(), ast_func_read(), ast_strlen_zero(), agi_state::fd, pbx_retrieve_variable(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02565 {
02566    char *ret;
02567    char tempstr[1024] = "";
02568 
02569    if (argc != 3)
02570       return RESULT_SHOWUSAGE;
02571 
02572    /* check if we want to execute an ast_custom_function */
02573    if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
02574       ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
02575    } else {
02576       pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
02577    }
02578 
02579    if (ret)
02580       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
02581    else
02582       ast_agi_send(agi->fd, chan, "200 result=0\n");
02583 
02584    return RESULT_SUCCESS;
02585 }

static int handle_getvariablefull ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2587 of file res_agi.c.

References ast_agi_send(), ast_channel_get_by_name(), ast_channel_ref, ast_channel_unref, ast_free, ast_str_buffer(), ast_str_create(), ast_str_substitute_variables(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and str.

02588 {
02589    struct ast_channel *chan2 = NULL;
02590 
02591    if (argc != 4 && argc != 5) {
02592       return RESULT_SHOWUSAGE;
02593    }
02594 
02595    if (argc == 5) {
02596       chan2 = ast_channel_get_by_name(argv[4]);
02597    } else {
02598       chan2 = ast_channel_ref(chan);
02599    }
02600 
02601    if (chan2) {
02602       struct ast_str *str = ast_str_create(16);
02603       if (!str) {
02604          ast_agi_send(agi->fd, chan, "200 result=0\n");
02605          return RESULT_SUCCESS;
02606       }
02607       ast_str_substitute_variables(&str, 0, chan2, argv[3]);
02608       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
02609       ast_free(str);
02610    } else {
02611       ast_agi_send(agi->fd, chan, "200 result=0\n");
02612    }
02613 
02614    if (chan2) {
02615       chan2 = ast_channel_unref(chan2);
02616    }
02617 
02618    return RESULT_SUCCESS;
02619 }

static int handle_hangup ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2439 of file res_agi.c.

References ast_agi_send(), ast_channel_get_by_name(), ast_channel_unref, ast_set_hangupsource(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02440 {
02441    struct ast_channel *c;
02442 
02443    if (argc == 1) {
02444       /* no argument: hangup the current channel */
02445       ast_set_hangupsource(chan, "dialplan/agi", 0);
02446       ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
02447       ast_agi_send(agi->fd, chan, "200 result=1\n");
02448       return RESULT_SUCCESS;
02449    } else if (argc == 2) {
02450       /* one argument: look for info on the specified channel */
02451       if ((c = ast_channel_get_by_name(argv[1]))) {
02452          /* we have a matching channel */
02453          ast_set_hangupsource(c, "dialplan/agi", 0);
02454          ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
02455          c = ast_channel_unref(c);
02456          ast_agi_send(agi->fd, chan, "200 result=1\n");
02457          return RESULT_SUCCESS;
02458       }
02459       /* if we get this far no channel name matched the argument given */
02460       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02461       return RESULT_SUCCESS;
02462    } else {
02463       return RESULT_SHOWUSAGE;
02464    }
02465 }

static int handle_noop ( struct ast_channel chan,
AGI agi,
int  arg,
const char *const   argv[] 
) [static]

Definition at line 2739 of file res_agi.c.

References ast_agi_send(), agi_state::fd, and RESULT_SUCCESS.

02740 {
02741    ast_agi_send(agi->fd, chan, "200 result=0\n");
02742    return RESULT_SUCCESS;
02743 }

static int handle_recordfile ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2240 of file res_agi.c.

References ast_agi_send(), ast_applystream(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FILE_MODE, AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log(), ast_read(), ast_seekstream(), ast_set_read_format(), ast_stream_rewind(), ast_streamfile(), ast_tellstream(), ast_truncstream(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), f, agi_state::fd, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, ast_channel::readformat, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, ast_frame::subclass, THRESHOLD_SILENCE, and ast_dsp::totalsilence.

02241 {
02242    struct ast_filestream *fs;
02243    struct ast_frame *f;
02244    struct timeval start;
02245    long sample_offset = 0;
02246    int res = 0;
02247    int ms;
02248 
02249    struct ast_dsp *sildet=NULL;         /* silence detector dsp */
02250    int totalsilence = 0;
02251    int dspsilence = 0;
02252    int silence = 0;                /* amount of silence to allow */
02253    int gotsilence = 0;             /* did we timeout for silence? */
02254    char *silencestr = NULL;
02255    int rfmt = 0;
02256 
02257    /* XXX EAGI FIXME XXX */
02258 
02259    if (argc < 6)
02260       return RESULT_SHOWUSAGE;
02261    if (sscanf(argv[5], "%30d", &ms) != 1)
02262       return RESULT_SHOWUSAGE;
02263 
02264    if (argc > 6)
02265       silencestr = strchr(argv[6],'s');
02266    if ((argc > 7) && (!silencestr))
02267       silencestr = strchr(argv[7],'s');
02268    if ((argc > 8) && (!silencestr))
02269       silencestr = strchr(argv[8],'s');
02270 
02271    if (silencestr) {
02272       if (strlen(silencestr) > 2) {
02273          if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
02274             silencestr++;
02275             silencestr++;
02276             if (silencestr)
02277                silence = atoi(silencestr);
02278             if (silence > 0)
02279                silence *= 1000;
02280          }
02281       }
02282    }
02283 
02284    if (silence > 0) {
02285       rfmt = chan->readformat;
02286       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
02287       if (res < 0) {
02288          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
02289          ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02290          return RESULT_FAILURE;
02291       }
02292       sildet = ast_dsp_new();
02293       if (!sildet) {
02294          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
02295          ast_agi_send(agi->fd, chan, "200 result=-1\n");
02296          return RESULT_FAILURE;
02297       }
02298       ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
02299    }
02300    
02301    /* backward compatibility, if no offset given, arg[6] would have been
02302     * caught below and taken to be a beep, else if it is a digit then it is a
02303     * offset */
02304    if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
02305       res = ast_streamfile(chan, "beep", chan->language);
02306 
02307    if ((argc > 7) && (!strchr(argv[7], '=')))
02308       res = ast_streamfile(chan, "beep", chan->language);
02309 
02310    if (!res)
02311       res = ast_waitstream(chan, argv[4]);
02312    if (res) {
02313       ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
02314    } else {
02315       fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
02316       if (!fs) {
02317          res = -1;
02318          ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
02319          if (sildet)
02320             ast_dsp_free(sildet);
02321          return RESULT_FAILURE;
02322       }
02323 
02324       /* Request a video update */
02325       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
02326 
02327       chan->stream = fs;
02328       ast_applystream(chan,fs);
02329       /* really should have checks */
02330       ast_seekstream(fs, sample_offset, SEEK_SET);
02331       ast_truncstream(fs);
02332 
02333       start = ast_tvnow();
02334       while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
02335          res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
02336          if (res < 0) {
02337             ast_closestream(fs);
02338             ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
02339             if (sildet)
02340                ast_dsp_free(sildet);
02341             return RESULT_FAILURE;
02342          }
02343          f = ast_read(chan);
02344          if (!f) {
02345             ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
02346             ast_closestream(fs);
02347             if (sildet)
02348                ast_dsp_free(sildet);
02349             return RESULT_FAILURE;
02350          }
02351          switch(f->frametype) {
02352          case AST_FRAME_DTMF:
02353             if (strchr(argv[4], f->subclass.integer)) {
02354                /* This is an interrupting chracter, so rewind to chop off any small
02355                   amount of DTMF that may have been recorded
02356                */
02357                ast_stream_rewind(fs, 200);
02358                ast_truncstream(fs);
02359                sample_offset = ast_tellstream(fs);
02360                ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
02361                ast_closestream(fs);
02362                ast_frfree(f);
02363                if (sildet)
02364                   ast_dsp_free(sildet);
02365                return RESULT_SUCCESS;
02366             }
02367             break;
02368          case AST_FRAME_VOICE:
02369             ast_writestream(fs, f);
02370             /* this is a safe place to check progress since we know that fs
02371              * is valid after a write, and it will then have our current
02372              * location */
02373             sample_offset = ast_tellstream(fs);
02374             if (silence > 0) {
02375                dspsilence = 0;
02376                ast_dsp_silence(sildet, f, &dspsilence);
02377                if (dspsilence) {
02378                   totalsilence = dspsilence;
02379                } else {
02380                   totalsilence = 0;
02381                }
02382                if (totalsilence > silence) {
02383                   /* Ended happily with silence */
02384                   gotsilence = 1;
02385                   break;
02386                }
02387             }
02388             break;
02389          case AST_FRAME_VIDEO:
02390             ast_writestream(fs, f);
02391          default:
02392             /* Ignore all other frames */
02393             break;
02394          }
02395          ast_frfree(f);
02396          if (gotsilence)
02397             break;
02398       }
02399 
02400       if (gotsilence) {
02401          ast_stream_rewind(fs, silence-1000);
02402          ast_truncstream(fs);
02403          sample_offset = ast_tellstream(fs);
02404       }
02405       ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
02406       ast_closestream(fs);
02407    }
02408 
02409    if (silence > 0) {
02410       res = ast_set_read_format(chan, rfmt);
02411       if (res)
02412          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
02413       ast_dsp_free(sildet);
02414    }
02415 
02416    return RESULT_SUCCESS;
02417 }

static int handle_recvchar ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1816 of file res_agi.c.

References ast_agi_send(), ast_recvchar(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01817 {
01818    int res;
01819 
01820    if (argc != 3)
01821       return RESULT_SHOWUSAGE;
01822 
01823    res = ast_recvchar(chan,atoi(argv[2]));
01824    if (res == 0) {
01825       ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
01826       return RESULT_SUCCESS;
01827    }
01828    if (res > 0) {
01829       ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01830       return RESULT_SUCCESS;
01831    }
01832    ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
01833    return RESULT_FAILURE;
01834 }

static int handle_recvtext ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1836 of file res_agi.c.

References ast_agi_send(), ast_free, ast_recvtext(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01837 {
01838    char *buf;
01839 
01840    if (argc != 3)
01841       return RESULT_SHOWUSAGE;
01842 
01843    buf = ast_recvtext(chan, atoi(argv[2]));
01844    if (buf) {
01845       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
01846       ast_free(buf);
01847    } else {
01848       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01849    }
01850    return RESULT_SUCCESS;
01851 }

static int handle_sayalpha ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2083 of file res_agi.c.

References ast_agi_send(), ast_say_character_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02084 {
02085    int res;
02086 
02087    if (argc != 4)
02088       return RESULT_SHOWUSAGE;
02089 
02090    res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02091    if (res == 1) /* New command */
02092       return RESULT_SUCCESS;
02093    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02094    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02095 }

static int handle_saydate ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2097 of file res_agi.c.

References ast_agi_send(), ast_say_date, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02098 {
02099    int res, num;
02100 
02101    if (argc != 4)
02102       return RESULT_SHOWUSAGE;
02103    if (sscanf(argv[2], "%30d", &num) != 1)
02104       return RESULT_SHOWUSAGE;
02105    res = ast_say_date(chan, num, argv[3], chan->language);
02106    if (res == 1)
02107       return RESULT_SUCCESS;
02108    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02109    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02110 }

static int handle_saydatetime ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2127 of file res_agi.c.

References ast_agi_send(), ast_get_time_t(), ast_say_date_with_format, ast_strlen_zero(), agi_state::fd, format, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02128 {
02129    int res = 0;
02130    time_t unixtime;
02131    const char *format, *zone = NULL;
02132 
02133    if (argc < 4)
02134       return RESULT_SHOWUSAGE;
02135 
02136    if (argc > 4) {
02137       format = argv[4];
02138    } else {
02139       /* XXX this doesn't belong here, but in the 'say' module */
02140       if (!strcasecmp(chan->language, "de")) {
02141          format = "A dBY HMS";
02142       } else {
02143          format = "ABdY 'digits/at' IMp";
02144       }
02145    }
02146 
02147    if (argc > 5 && !ast_strlen_zero(argv[5]))
02148       zone = argv[5];
02149 
02150    if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
02151       return RESULT_SHOWUSAGE;
02152 
02153    res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
02154    if (res == 1)
02155       return RESULT_SUCCESS;
02156 
02157    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02158    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02159 }

static int handle_saydigits ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2067 of file res_agi.c.

References ast_agi_send(), ast_say_digit_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02068 {
02069    int res, num;
02070 
02071    if (argc != 4)
02072       return RESULT_SHOWUSAGE;
02073    if (sscanf(argv[2], "%30d", &num) != 1)
02074       return RESULT_SHOWUSAGE;
02075 
02076    res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02077    if (res == 1) /* New command */
02078       return RESULT_SUCCESS;
02079    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02080    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02081 }

static int handle_saynumber ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Say number in various language syntaxes.

Definition at line 2052 of file res_agi.c.

References ast_agi_send(), ast_say_number_full, agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02053 {
02054    int res, num;
02055 
02056    if (argc < 4 || argc > 5)
02057       return RESULT_SHOWUSAGE;
02058    if (sscanf(argv[2], "%30d", &num) != 1)
02059       return RESULT_SHOWUSAGE;
02060    res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
02061    if (res == 1)
02062       return RESULT_SUCCESS;
02063    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02064    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02065 }

static int handle_sayphonetic ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2161 of file res_agi.c.

References ast_agi_send(), ast_say_phonetic_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02162 {
02163    int res;
02164 
02165    if (argc != 4)
02166       return RESULT_SHOWUSAGE;
02167 
02168    res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02169    if (res == 1) /* New command */
02170       return RESULT_SUCCESS;
02171    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02172    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02173 }

static int handle_saytime ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2112 of file res_agi.c.

References ast_agi_send(), ast_say_time, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02113 {
02114    int res, num;
02115 
02116    if (argc != 4)
02117       return RESULT_SHOWUSAGE;
02118    if (sscanf(argv[2], "%30d", &num) != 1)
02119       return RESULT_SHOWUSAGE;
02120    res = ast_say_time(chan, num, argv[3], chan->language);
02121    if (res == 1)
02122       return RESULT_SUCCESS;
02123    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02124    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02125 }

static int handle_sendimage ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1881 of file res_agi.c.

References ast_agi_send(), ast_check_hangup(), ast_send_image(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01882 {
01883    int res;
01884 
01885    if (argc != 3) {
01886       return RESULT_SHOWUSAGE;
01887    }
01888 
01889    res = ast_send_image(chan, argv[2]);
01890    if (!ast_check_hangup(chan)) {
01891       res = 0;
01892    }
01893    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01894    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01895 }

static int handle_sendtext ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1797 of file res_agi.c.

References ast_agi_send(), ast_sendtext(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01798 {
01799    int res;
01800 
01801    if (argc != 3)
01802       return RESULT_SHOWUSAGE;
01803 
01804    /* At the moment, the parser (perhaps broken) returns with
01805       the last argument PLUS the newline at the end of the input
01806       buffer. This probably needs to be fixed, but I wont do that
01807       because other stuff may break as a result. The right way
01808       would probably be to strip off the trailing newline before
01809       parsing, then here, add a newline at the end of the string
01810       before sending it to ast_sendtext --DUDE */
01811    res = ast_sendtext(chan, argv[2]);
01812    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01813    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01814 }

static int handle_setcallerid ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2512 of file res_agi.c.

References ast_agi_send(), ast_callerid_parse(), ast_copy_string(), ast_set_callerid(), ast_shrink_phone_number(), agi_state::fd, and RESULT_SUCCESS.

02513 {
02514    char tmp[256]="";
02515    char *l = NULL, *n = NULL;
02516 
02517    if (argv[2]) {
02518       ast_copy_string(tmp, argv[2], sizeof(tmp));
02519       ast_callerid_parse(tmp, &n, &l);
02520       if (l)
02521          ast_shrink_phone_number(l);
02522       else
02523          l = "";
02524       if (!n)
02525          n = "";
02526       ast_set_callerid(chan, l, n, NULL);
02527    }
02528 
02529    ast_agi_send(agi->fd, chan, "200 result=1\n");
02530    return RESULT_SUCCESS;
02531 }

static int handle_setcontext ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2202 of file res_agi.c.

References ast_agi_send(), ast_copy_string(), ast_channel::context, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02203 {
02204 
02205    if (argc != 3)
02206       return RESULT_SHOWUSAGE;
02207    ast_copy_string(chan->context, argv[2], sizeof(chan->context));
02208    ast_agi_send(agi->fd, chan, "200 result=0\n");
02209    return RESULT_SUCCESS;
02210 }

static int handle_setextension ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2212 of file res_agi.c.

References ast_agi_send(), ast_copy_string(), ast_channel::exten, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02213 {
02214    if (argc != 3)
02215       return RESULT_SHOWUSAGE;
02216    ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
02217    ast_agi_send(agi->fd, chan, "200 result=0\n");
02218    return RESULT_SUCCESS;
02219 }

static int handle_setmusic ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2745 of file res_agi.c.

References ast_agi_send(), ast_moh_start(), ast_moh_stop(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02746 {
02747    if (argc < 3) {
02748       return RESULT_SHOWUSAGE;
02749    }
02750    if (!strncasecmp(argv[2], "on", 2))
02751       ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
02752    else if (!strncasecmp(argv[2], "off", 3))
02753       ast_moh_stop(chan);
02754    ast_agi_send(agi->fd, chan, "200 result=0\n");
02755    return RESULT_SUCCESS;
02756 }

static int handle_setpriority ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2221 of file res_agi.c.

References ast_agi_send(), ast_explicit_goto(), ast_findlabel_extension(), ast_channel::caller, ast_channel::context, ast_channel::exten, agi_state::fd, ast_party_caller::id, ast_party_id::number, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, ast_party_number::str, and ast_party_number::valid.

02222 {
02223    int pri;
02224 
02225    if (argc != 3)
02226       return RESULT_SHOWUSAGE;
02227 
02228    if (sscanf(argv[2], "%30d", &pri) != 1) {
02229       pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2],
02230          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
02231       if (pri < 1)
02232          return RESULT_SHOWUSAGE;
02233    }
02234 
02235    ast_explicit_goto(chan, NULL, NULL, pri);
02236    ast_agi_send(agi->fd, chan, "200 result=0\n");
02237    return RESULT_SUCCESS;
02238 }

static int handle_setvariable ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2555 of file res_agi.c.

References ast_agi_send(), agi_state::fd, pbx_builtin_setvar_helper(), and RESULT_SUCCESS.

02556 {
02557    if (argv[3])
02558       pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
02559 
02560    ast_agi_send(agi->fd, chan, "200 result=1\n");
02561    return RESULT_SUCCESS;
02562 }

static int handle_speechactivategrammar ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2841 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_activate(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02842 {
02843    if (argc != 4)
02844       return RESULT_SHOWUSAGE;
02845 
02846    if (!agi->speech) {
02847       ast_agi_send(agi->fd, chan, "200 result=0\n");
02848       return RESULT_SUCCESS;
02849    }
02850 
02851    if (ast_speech_grammar_activate(agi->speech, argv[3]))
02852       ast_agi_send(agi->fd, chan, "200 result=0\n");
02853    else
02854       ast_agi_send(agi->fd, chan, "200 result=1\n");
02855 
02856    return RESULT_SUCCESS;
02857 }

static int handle_speechcreate ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2758 of file res_agi.c.

References ast_agi_send(), AST_FORMAT_SLINEAR, ast_speech_new(), agi_state::fd, RESULT_SUCCESS, and agi_state::speech.

02759 {
02760    /* If a structure already exists, return an error */
02761         if (agi->speech) {
02762       ast_agi_send(agi->fd, chan, "200 result=0\n");
02763       return RESULT_SUCCESS;
02764    }
02765 
02766    if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02767       ast_agi_send(agi->fd, chan, "200 result=1\n");
02768    else
02769       ast_agi_send(agi->fd, chan, "200 result=0\n");
02770 
02771    return RESULT_SUCCESS;
02772 }

static int handle_speechdeactivategrammar ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2859 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_deactivate(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02860 {
02861    if (argc != 4)
02862       return RESULT_SHOWUSAGE;
02863 
02864    if (!agi->speech) {
02865       ast_agi_send(agi->fd, chan, "200 result=0\n");
02866       return RESULT_SUCCESS;
02867    }
02868 
02869    if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02870       ast_agi_send(agi->fd, chan, "200 result=0\n");
02871    else
02872       ast_agi_send(agi->fd, chan, "200 result=1\n");
02873 
02874    return RESULT_SUCCESS;
02875 }

static int handle_speechdestroy ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2792 of file res_agi.c.

References ast_agi_send(), ast_speech_destroy(), agi_state::fd, RESULT_SUCCESS, and agi_state::speech.

02793 {
02794    if (agi->speech) {
02795       ast_speech_destroy(agi->speech);
02796       agi->speech = NULL;
02797       ast_agi_send(agi->fd, chan, "200 result=1\n");
02798    } else {
02799       ast_agi_send(agi->fd, chan, "200 result=0\n");
02800    }
02801 
02802    return RESULT_SUCCESS;
02803 }

static int handle_speechloadgrammar ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2805 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_load(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02806 {
02807    if (argc != 5)
02808       return RESULT_SHOWUSAGE;
02809 
02810    if (!agi->speech) {
02811       ast_agi_send(agi->fd, chan, "200 result=0\n");
02812       return RESULT_SUCCESS;
02813    }
02814 
02815    if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02816       ast_agi_send(agi->fd, chan, "200 result=0\n");
02817    else
02818       ast_agi_send(agi->fd, chan, "200 result=1\n");
02819 
02820    return RESULT_SUCCESS;
02821 }

static int handle_speechrecognize ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2896 of file res_agi.c.

References ast_agi_send(), ast_build_string(), ast_clear_flag, AST_CONTROL_HANGUP, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_sched_runq(), ast_sched_wait(), ast_set_read_format(), ast_speech_change_state(), AST_SPEECH_QUIET, ast_speech_results_get(), ast_speech_start(), AST_SPEECH_STATE_DONE, AST_SPEECH_STATE_NOT_READY, AST_SPEECH_STATE_READY, AST_SPEECH_STATE_WAIT, ast_speech_write(), ast_stopstream(), ast_strlen_zero(), ast_tellstream(), ast_test_flag, ast_waitfor(), ast_frame::data, ast_frame::datalen, agi_state::fd, ast_frame::frametype, ast_speech_result::grammar, ast_frame_subclass::integer, ast_speech_result::list, ast_speech::lock, ast_speech::processing_sound, prompt, ast_frame::ptr, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_speech::results, ast_channel::sched, ast_speech_result::score, agi_state::speech, speech_streamfile(), ast_speech::state, ast_channel::stream, ast_channel::streamid, ast_frame::subclass, ast_speech_result::text, and ast_channel::timingfunc.

02897 {
02898    struct ast_speech *speech = agi->speech;
02899    const char *prompt;
02900    char dtmf = 0, tmp[4096] = "", *buf = tmp;
02901    int timeout = 0, offset = 0, res = 0, i = 0;
02902    long current_offset = 0;
02903    const char *reason = NULL;
02904    struct ast_frame *fr = NULL;
02905    struct ast_speech_result *result = NULL;
02906    size_t left = sizeof(tmp);
02907    time_t start = 0, current;
02908 
02909    if (argc < 4)
02910       return RESULT_SHOWUSAGE;
02911 
02912    if (!speech) {
02913       ast_agi_send(agi->fd, chan, "200 result=0\n");
02914       return RESULT_SUCCESS;
02915    }
02916 
02917    prompt = argv[2];
02918    timeout = atoi(argv[3]);
02919 
02920    /* If offset is specified then convert from text to integer */
02921    if (argc == 5)
02922       offset = atoi(argv[4]);
02923 
02924    /* We want frames coming in signed linear */
02925    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02926       ast_agi_send(agi->fd, chan, "200 result=0\n");
02927       return RESULT_SUCCESS;
02928    }
02929 
02930    /* Setup speech structure */
02931    if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02932       ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02933       ast_speech_start(speech);
02934    }
02935 
02936    /* Start playing prompt */
02937    speech_streamfile(chan, prompt, chan->language, offset);
02938 
02939    /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
02940    while (ast_strlen_zero(reason)) {
02941       /* Run scheduled items */
02942                 ast_sched_runq(chan->sched);
02943 
02944       /* See maximum time of waiting */
02945       if ((res = ast_sched_wait(chan->sched)) < 0)
02946          res = 1000;
02947 
02948       /* Wait for frame */
02949       if (ast_waitfor(chan, res) > 0) {
02950          if (!(fr = ast_read(chan))) {
02951             reason = "hangup";
02952             break;
02953          }
02954       }
02955 
02956       /* Perform timeout check */
02957       if ((timeout > 0) && (start > 0)) {
02958          time(&current);
02959          if ((current - start) >= timeout) {
02960             reason = "timeout";
02961             if (fr)
02962                ast_frfree(fr);
02963             break;
02964          }
02965       }
02966 
02967       /* Check the speech structure for any changes */
02968       ast_mutex_lock(&speech->lock);
02969 
02970       /* See if we need to quiet the audio stream playback */
02971       if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02972          current_offset = ast_tellstream(chan->stream);
02973          ast_stopstream(chan);
02974          ast_clear_flag(speech, AST_SPEECH_QUIET);
02975       }
02976 
02977       /* Check each state */
02978       switch (speech->state) {
02979       case AST_SPEECH_STATE_READY:
02980          /* If the stream is done, start timeout calculation */
02981          if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02982             ast_stopstream(chan);
02983             time(&start);
02984          }
02985          /* Write audio frame data into speech engine if possible */
02986          if (fr && fr->frametype == AST_FRAME_VOICE)
02987             ast_speech_write(speech, fr->data.ptr, fr->datalen);
02988          break;
02989       case AST_SPEECH_STATE_WAIT:
02990          /* Cue waiting sound if not already playing */
02991          if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
02992             ast_stopstream(chan);
02993             /* If a processing sound exists, or is not none - play it */
02994             if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
02995                speech_streamfile(chan, speech->processing_sound, chan->language, 0);
02996          }
02997          break;
02998       case AST_SPEECH_STATE_DONE:
02999          /* Get the results */
03000          speech->results = ast_speech_results_get(speech);
03001          /* Change state to not ready */
03002          ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
03003          reason = "speech";
03004          break;
03005       default:
03006          break;
03007       }
03008       ast_mutex_unlock(&speech->lock);
03009 
03010       /* Check frame for DTMF or hangup */
03011       if (fr) {
03012          if (fr->frametype == AST_FRAME_DTMF) {
03013             reason = "dtmf";
03014             dtmf = fr->subclass.integer;
03015          } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
03016             reason = "hangup";
03017          }
03018          ast_frfree(fr);
03019       }
03020    }
03021 
03022    if (!strcasecmp(reason, "speech")) {
03023       /* Build string containing speech results */
03024                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
03025          /* Build result string */
03026          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);
03027                         /* Increment result count */
03028          i++;
03029       }
03030                 /* Print out */
03031       ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
03032    } else if (!strcasecmp(reason, "dtmf")) {
03033       ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
03034    } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
03035       ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
03036    } else {
03037       ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
03038    }
03039 
03040    return RESULT_SUCCESS;
03041 }

static int handle_speechset ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2774 of file res_agi.c.

References ast_agi_send(), ast_speech_change(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02775 {
02776    /* Check for minimum arguments */
02777    if (argc != 4)
02778       return RESULT_SHOWUSAGE;
02779 
02780    /* Check to make sure speech structure exists */
02781    if (!agi->speech) {
02782       ast_agi_send(agi->fd, chan, "200 result=0\n");
02783       return RESULT_SUCCESS;
02784    }
02785 
02786    ast_speech_change(agi->speech, argv[2], argv[3]);
02787    ast_agi_send(agi->fd, chan, "200 result=1\n");
02788 
02789    return RESULT_SUCCESS;
02790 }

static int handle_speechunloadgrammar ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2823 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_unload(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02824 {
02825    if (argc != 4)
02826       return RESULT_SHOWUSAGE;
02827 
02828    if (!agi->speech) {
02829       ast_agi_send(agi->fd, chan, "200 result=0\n");
02830       return RESULT_SUCCESS;
02831    }
02832 
02833    if (ast_speech_grammar_unload(agi->speech, argv[3]))
02834       ast_agi_send(agi->fd, chan, "200 result=0\n");
02835    else
02836       ast_agi_send(agi->fd, chan, "200 result=1\n");
02837 
02838    return RESULT_SUCCESS;
02839 }

static int handle_streamfile ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1933 of file res_agi.c.

References ast_agi_send(), ast_applystream(), ast_debug, ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verb, ast_waitstream_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, and ast_filestream::vfs.

01934 {
01935    int res;
01936    struct ast_filestream *fs, *vfs;
01937    long sample_offset = 0, max_length;
01938    const char *edigits = "";
01939 
01940    if (argc < 4 || argc > 5)
01941       return RESULT_SHOWUSAGE;
01942 
01943    if (argv[3])
01944       edigits = argv[3];
01945 
01946    if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01947       return RESULT_SHOWUSAGE;
01948 
01949    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01950       ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
01951       return RESULT_FAILURE;
01952    }
01953 
01954    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01955       ast_debug(1, "Ooh, found a video stream, too\n");
01956 
01957    ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01958 
01959    ast_seekstream(fs, 0, SEEK_END);
01960    max_length = ast_tellstream(fs);
01961    ast_seekstream(fs, sample_offset, SEEK_SET);
01962    res = ast_applystream(chan, fs);
01963    if (vfs)
01964       ast_applystream(chan, vfs);
01965    ast_playstream(fs);
01966    if (vfs)
01967       ast_playstream(vfs);
01968 
01969    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01970    /* this is to check for if ast_waitstream closed the stream, we probably are at
01971     * the end of the stream, return that amount, else check for the amount */
01972    sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01973    ast_stopstream(chan);
01974    if (res == 1) {
01975       /* Stop this command, don't print a result line, as there is a new command */
01976       return RESULT_SUCCESS;
01977    }
01978    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01979    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01980 }

static int handle_tddmode ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1853 of file res_agi.c.

References ast_agi_send(), ast_channel_setoption(), AST_OPTION_TDD, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01854 {
01855    int res, x;
01856 
01857    if (argc != 3)
01858       return RESULT_SHOWUSAGE;
01859 
01860    if (!strncasecmp(argv[2],"on",2)) {
01861       x = 1;
01862    } else  {
01863       x = 0;
01864    }
01865    if (!strncasecmp(argv[2],"mate",4))  {
01866       x = 2;
01867    }
01868    if (!strncasecmp(argv[2],"tdd",3)) {
01869       x = 1;
01870    }
01871    res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
01872    if (res) {
01873       /* Set channel option failed */
01874       ast_agi_send(agi->fd, chan, "200 result=0\n");
01875    } else {
01876       ast_agi_send(agi->fd, chan, "200 result=1\n");
01877    }
01878    return RESULT_SUCCESS;
01879 }

static int handle_verbose ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 2621 of file res_agi.c.

References ast_agi_send(), ast_verb, ast_channel::data, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

02622 {
02623    int level = 0;
02624 
02625    if (argc < 2)
02626       return RESULT_SHOWUSAGE;
02627 
02628    if (argv[2])
02629       sscanf(argv[2], "%30d", &level);
02630 
02631    ast_verb(level, "%s: %s\n", chan->data, argv[1]);
02632 
02633    ast_agi_send(agi->fd, chan, "200 result=1\n");
02634 
02635    return RESULT_SUCCESS;
02636 }

static int handle_waitfordigit ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const   argv[] 
) [static]

Definition at line 1784 of file res_agi.c.

References ast_agi_send(), ast_waitfordigit_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01785 {
01786    int res, to;
01787 
01788    if (argc != 4)
01789       return RESULT_SHOWUSAGE;
01790    if (sscanf(argv[3], "%30d", &to) != 1)
01791       return RESULT_SHOWUSAGE;
01792    res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
01793    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01794    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01795 }

static char* help_workhorse ( int  fd,
const char *const   match[] 
) [static]

Definition at line 3097 of file res_agi.c.

References ast_cli(), ast_join(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_SUCCESS, agi_command::cmda, agi_command::dead, MAX_CMD_LEN, S_OR, and agi_command::summary.

Referenced by handle_cli_agi_show().

03098 {
03099    char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
03100    struct agi_command *e;
03101 
03102    if (match)
03103       ast_join(matchstr, sizeof(matchstr), match);
03104 
03105    ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
03106    AST_RWLIST_RDLOCK(&agi_commands);
03107    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03108       if (!e->cmda[0])
03109          break;
03110       /* Hide commands that start with '_' */
03111       if ((e->cmda[0])[0] == '_')
03112          continue;
03113       ast_join(fullcmd, sizeof(fullcmd), e->cmda);
03114       if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
03115          continue;
03116       ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
03117    }
03118    AST_RWLIST_UNLOCK(&agi_commands);
03119 
03120    return CLI_SUCCESS;
03121 }

static enum agi_result launch_asyncagi ( struct ast_channel chan,
char *  argv[],
int *  efd 
) [static]

Definition at line 1233 of file res_agi.c.

References add_to_agi(), AGI_BUF_SIZE, agi_handle_command(), AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, AMI_BUF_SIZE, ast_check_hangup(), ast_debug, ast_log(), ast_speech_destroy(), ast_strlen_zero(), ast_uri_encode(), ast_waitfor(), async_agi_read_frame(), agi_state::audio, agi_cmd::cmd_buffer, agi_cmd::cmd_id, agi_state::ctrl, errno, EVENT_FLAG_AGI, agi_state::fast, agi_state::fd, free_agi_cmd(), get_agi_cmd(), LOG_ERROR, LOG_WARNING, manager_event, setup_env(), and agi_state::speech.

Referenced by launch_script().

01234 {
01235 /* This buffer sizes might cause truncation if the AGI command writes more data
01236    than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
01237    that writes a response larger than 1024 bytes?, I don't think so, most of
01238    them are just result=blah stuff. However probably if GET VARIABLE is called
01239    and the variable has large amount of data, that could be a problem. We could
01240    make this buffers dynamic, but let's leave that as a second step.
01241 
01242    AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
01243    number. Some characters of AGI buf will be url encoded to be sent to manager
01244    clients.  An URL encoded character will take 3 bytes, but again, to cause
01245    truncation more than about 70% of the AGI buffer should be URL encoded for
01246    that to happen.  Not likely at all.
01247 
01248    On the other hand. I wonder if read() could eventually return less data than
01249    the amount already available in the pipe? If so, how to deal with that?
01250    So far, my tests on Linux have not had any problems.
01251  */
01252 #define AGI_BUF_SIZE 1024
01253 #define AMI_BUF_SIZE 2048
01254    enum agi_result cmd_status;
01255    struct agi_cmd *cmd;
01256    int res;
01257    int fds[2];
01258    int hungup;
01259    int timeout = 100;
01260    char agi_buffer[AGI_BUF_SIZE + 1];
01261    char ami_buffer[AMI_BUF_SIZE];
01262    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
01263    AGI async_agi;
01264 
01265    if (efd) {
01266       ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
01267       return AGI_RESULT_FAILURE;
01268    }
01269 
01270    /* add AsyncAGI datastore to the channel */
01271    if (add_to_agi(chan)) {
01272       ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", chan->name);
01273       return AGI_RESULT_FAILURE;
01274    }
01275 
01276    /* this pipe allows us to create a "fake" AGI struct to use
01277       the AGI commands */
01278    res = pipe(fds);
01279    if (res) {
01280       ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
01281       /*
01282        * Intentionally do not remove the datastore added with
01283        * add_to_agi() the from channel.  It will be removed when the
01284        * channel is hung up anyway.
01285        */
01286       return AGI_RESULT_FAILURE;
01287    }
01288 
01289    /* handlers will get the pipe write fd and we read the AGI responses
01290       from the pipe read fd */
01291    async_agi.fd = fds[1];
01292    async_agi.ctrl = fds[1];
01293    async_agi.audio = -1; /* no audio support */
01294    async_agi.fast = 0;
01295    async_agi.speech = NULL;
01296 
01297    /* notify possible manager users of a new channel ready to
01298       receive commands */
01299    setup_env(chan, "async", fds[1], 0, 0, NULL);
01300    /* read the environment */
01301    res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01302    if (res <= 0) {
01303       ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
01304          chan->name, res < 0 ? strerror(errno) : "EOF");
01305       returnstatus = AGI_RESULT_FAILURE;
01306       goto async_agi_abort;
01307    }
01308    agi_buffer[res] = '\0';
01309    /* encode it and send it thru the manager so whoever is going to take
01310       care of AGI commands on this channel can decide which AGI commands
01311       to execute based on the setup info */
01312    ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01313    manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01314       "SubEvent: Start\r\n"
01315       "Channel: %s\r\n"
01316       "Env: %s\r\n", chan->name, ami_buffer);
01317    hungup = ast_check_hangup(chan);
01318    for (;;) {
01319       /*
01320        * Process as many commands as we can.  Commands are added via
01321        * the manager or the cli threads.
01322        */
01323       while (!hungup && (cmd = get_agi_cmd(chan))) {
01324          /* OK, we have a command, let's call the command handler. */
01325          cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
01326 
01327          /*
01328           * The command handler must have written to our fake AGI struct
01329           * fd (the pipe), let's read the response.
01330           */
01331          res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01332          if (res <= 0) {
01333             ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
01334                chan->name, res < 0 ? strerror(errno) : "EOF");
01335             free_agi_cmd(cmd);
01336             returnstatus = AGI_RESULT_FAILURE;
01337             goto async_agi_done;
01338          }
01339          /*
01340           * We have a response, let's send the response thru the manager.
01341           * Include the CommandID if it was specified when the command
01342           * was added.
01343           */
01344          agi_buffer[res] = '\0';
01345          ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01346          if (ast_strlen_zero(cmd->cmd_id)) {
01347             manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01348                "SubEvent: Exec\r\n"
01349                "Channel: %s\r\n"
01350                "Result: %s\r\n", chan->name, ami_buffer);
01351          } else {
01352             manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01353                "SubEvent: Exec\r\n"
01354                "Channel: %s\r\n"
01355                "CommandID: %s\r\n"
01356                "Result: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
01357          }
01358          free_agi_cmd(cmd);
01359 
01360          /*
01361           * Check the command status to determine if we should continue
01362           * executing more commands.
01363           */
01364          hungup = ast_check_hangup(chan);
01365          switch (cmd_status) {
01366          case AGI_RESULT_FAILURE:
01367             if (!hungup) {
01368                /* The failure was not because of a hangup. */
01369                returnstatus = AGI_RESULT_FAILURE;
01370                goto async_agi_done;
01371             }
01372             break;
01373          case AGI_RESULT_SUCCESS_ASYNC:
01374             /* Only the "asyncagi break" command does this. */
01375             returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01376             goto async_agi_done;
01377          default:
01378             break;
01379          }
01380       }
01381 
01382       if (!hungup) {
01383          /* Wait a bit for a frame to read or to poll for a new command. */
01384          res = ast_waitfor(chan, timeout);
01385          if (res < 0) {
01386             ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
01387             returnstatus = AGI_RESULT_FAILURE;
01388             break;
01389          }
01390       } else {
01391          /*
01392           * Read the channel control queue until it is dry so we can
01393           * quit.
01394           */
01395          res = 1;
01396       }
01397       if (0 < res) {
01398          do {
01399             cmd_status = async_agi_read_frame(chan);
01400             if (cmd_status != AGI_RESULT_SUCCESS) {
01401                returnstatus = cmd_status;
01402                goto async_agi_done;
01403             }
01404             hungup = ast_check_hangup(chan);
01405          } while (hungup);
01406       } else {
01407          hungup = ast_check_hangup(chan);
01408       }
01409    }
01410 async_agi_done:
01411 
01412    if (async_agi.speech) {
01413       ast_speech_destroy(async_agi.speech);
01414    }
01415    /* notify manager users this channel cannot be
01416       controlled anymore by Async AGI */
01417    manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01418       "SubEvent: End\r\n"
01419       "Channel: %s\r\n", chan->name);
01420 
01421 async_agi_abort:
01422    /* close the pipe */
01423    close(fds[0]);
01424    close(fds[1]);
01425 
01426    /*
01427     * Intentionally do not remove the datastore added with
01428     * add_to_agi() the from channel.  There might be commands still
01429     * in the queue or in-flight to us and AsyncAGI may get called
01430     * again.  The datastore destructor will be called on channel
01431     * destruction anyway.
01432     */
01433 
01434    if (returnstatus == AGI_RESULT_SUCCESS) {
01435       returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01436    }
01437    return returnstatus;
01438 
01439 #undef AGI_BUF_SIZE
01440 #undef AMI_BUF_SIZE
01441 }

static enum agi_result launch_ha_netscript ( char *  agiurl,
char *  argv[],
int *  fds 
) [static]

Definition at line 1547 of file res_agi.c.

References AGI_RESULT_FAILURE, AGI_RESULT_NOTFOUND, ast_log(), ast_srv_cleanup(), ast_srv_lookup(), ast_strdupa, context, launch_netscript(), LOG_WARNING, service, and SRV_PREFIX.

Referenced by launch_script().

01548 {
01549    char *host, *script;
01550    enum agi_result result;
01551    struct srv_context *context = NULL;
01552    int srv_ret;
01553    char service[256];
01554    char resolved_uri[1024];
01555    const char *srvhost;
01556    unsigned short srvport;
01557 
01558    /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
01559    if (strlen(agiurl) < 7) { /* Remove hagi:// */
01560       ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
01561       return AGI_RESULT_FAILURE;
01562    }
01563    host = ast_strdupa(agiurl + 7);
01564 
01565    /* Strip off any script name */
01566    if ((script = strchr(host, '/'))) {
01567       *script++ = '\0';
01568    } else {
01569       script = "";
01570    }
01571 
01572    if (strchr(host, ':')) {
01573       ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
01574       return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
01575    }
01576 
01577    snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
01578 
01579    while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
01580       snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
01581       result = launch_netscript(resolved_uri, argv, fds);
01582       if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
01583          ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
01584       } else {
01585          /* The script launched so we must cleanup the context. */
01586          ast_srv_cleanup(&context);
01587          return result;
01588       }
01589    }
01590    /*
01591     * The DNS SRV lookup failed or we ran out of servers to check.
01592     * ast_srv_lookup() has already cleaned up the context for us.
01593     */
01594    if (srv_ret < 0) {
01595       ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
01596    }
01597 
01598    return AGI_RESULT_FAILURE;
01599 }

static enum agi_result launch_netscript ( char *  agiurl,
char *  argv[],
int *  fds 
) [static]

Definition at line 1445 of file res_agi.c.

References AGI_PORT, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS_FAST, ast_agi_send(), ast_debug, ast_gethostbyname(), ast_log(), ast_poll, ast_strdupa, ast_strlen_zero(), errno, hp, LOG_WARNING, and MAX_AGI_CONNECT.

Referenced by launch_ha_netscript(), and launch_script().

01446 {
01447    int s, flags, res, port = AGI_PORT;
01448    struct pollfd pfds[1];
01449    char *host, *c, *script;
01450    struct sockaddr_in addr_in;
01451    struct hostent *hp;
01452    struct ast_hostent ahp;
01453 
01454    /* agiurl is "agi://host.domain[:port][/script/name]" */
01455    host = ast_strdupa(agiurl + 6);  /* Remove agi:// */
01456    /* Strip off any script name */
01457    if ((script = strchr(host, '/'))) {
01458       *script++ = '\0';
01459    } else {
01460       script = "";
01461    }
01462 
01463    if ((c = strchr(host, ':'))) {
01464       *c++ = '\0';
01465       port = atoi(c);
01466    }
01467    if (!(hp = ast_gethostbyname(host, &ahp))) {
01468       ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
01469       return AGI_RESULT_FAILURE;
01470    }
01471    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
01472       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01473       return AGI_RESULT_FAILURE;
01474    }
01475    if ((flags = fcntl(s, F_GETFL)) < 0) {
01476       ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
01477       close(s);
01478       return AGI_RESULT_FAILURE;
01479    }
01480    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
01481       ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
01482       close(s);
01483       return AGI_RESULT_FAILURE;
01484    }
01485    memset(&addr_in, 0, sizeof(addr_in));
01486    addr_in.sin_family = AF_INET;
01487    addr_in.sin_port = htons(port);
01488    memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
01489    if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
01490       ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
01491       close(s);
01492       return AGI_RESULT_FAILURE;
01493    }
01494 
01495    pfds[0].fd = s;
01496    pfds[0].events = POLLOUT;
01497    while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
01498       if (errno != EINTR) {
01499          if (!res) {
01500             ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
01501                agiurl, MAX_AGI_CONNECT);
01502          } else
01503             ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01504          close(s);
01505          return AGI_RESULT_FAILURE;
01506       }
01507    }
01508 
01509    if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
01510       if (errno != EINTR) {
01511          ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01512          close(s);
01513          return AGI_RESULT_FAILURE;
01514       }
01515    }
01516 
01517    /* If we have a script parameter, relay it to the fastagi server */
01518    /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
01519    if (!ast_strlen_zero(script))
01520       ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
01521 
01522    ast_debug(4, "Wow, connected!\n");
01523    fds[0] = s;
01524    fds[1] = s;
01525    return AGI_RESULT_SUCCESS_FAST;
01526 }

static enum agi_result launch_script ( struct ast_channel chan,
char *  script,
char *  argv[],
int *  fds,
int *  efd,
int *  opid 
) [static]

Definition at line 1601 of file res_agi.c.

References AGI_RESULT_FAILURE, AGI_RESULT_NOTFOUND, AGI_RESULT_SUCCESS, ast_child_verbose(), ast_close_fds_above_n(), ast_config_AST_AGI_DIR, ast_config_AST_CONFIG_DIR, ast_config_AST_CONFIG_FILE, ast_config_AST_DATA_DIR, ast_config_AST_KEY_DIR, ast_config_AST_LOG_DIR, ast_config_AST_MODULE_DIR, ast_config_AST_MONITOR_DIR, ast_config_AST_RUN_DIR, ast_config_AST_SPOOL_DIR, ast_config_AST_VAR_DIR, ast_log(), ast_safe_fork(), ast_set_priority(), ast_verb, errno, launch_asyncagi(), launch_ha_netscript(), launch_netscript(), and LOG_WARNING.

Referenced by agi_exec_full().

01602 {
01603    char tmp[256];
01604    int pid, toast[2], fromast[2], audio[2], res;
01605    struct stat st;
01606 
01607    if (!strncasecmp(script, "agi://", 6)) {
01608       return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01609    }
01610    if (!strncasecmp(script, "hagi://", 7)) {
01611       return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01612    }
01613    if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
01614       return launch_asyncagi(chan, argv, efd);
01615    }
01616 
01617    if (script[0] != '/') {
01618       snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
01619       script = tmp;
01620    }
01621 
01622    /* Before even trying let's see if the file actually exists */
01623    if (stat(script, &st)) {
01624       ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
01625       return AGI_RESULT_NOTFOUND;
01626    }
01627 
01628    if (pipe(toast)) {
01629       ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
01630       return AGI_RESULT_FAILURE;
01631    }
01632    if (pipe(fromast)) {
01633       ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
01634       close(toast[0]);
01635       close(toast[1]);
01636       return AGI_RESULT_FAILURE;
01637    }
01638    if (efd) {
01639       if (pipe(audio)) {
01640          ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
01641          close(fromast[0]);
01642          close(fromast[1]);
01643          close(toast[0]);
01644          close(toast[1]);
01645          return AGI_RESULT_FAILURE;
01646       }
01647       res = fcntl(audio[1], F_GETFL);
01648       if (res > -1)
01649          res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
01650       if (res < 0) {
01651          ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
01652          close(fromast[0]);
01653          close(fromast[1]);
01654          close(toast[0]);
01655          close(toast[1]);
01656          close(audio[0]);
01657          close(audio[1]);
01658          return AGI_RESULT_FAILURE;
01659       }
01660    }
01661 
01662    if ((pid = ast_safe_fork(1)) < 0) {
01663       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
01664       return AGI_RESULT_FAILURE;
01665    }
01666    if (!pid) {
01667       /* Pass paths to AGI via environmental variables */
01668       setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
01669       setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
01670       setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
01671       setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
01672       setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
01673       setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
01674       setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
01675       setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
01676       setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
01677       setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
01678       setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
01679 
01680       /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
01681       ast_set_priority(0);
01682 
01683       /* Redirect stdin and out, provide enhanced audio channel if desired */
01684       dup2(fromast[0], STDIN_FILENO);
01685       dup2(toast[1], STDOUT_FILENO);
01686       if (efd)
01687          dup2(audio[0], STDERR_FILENO + 1);
01688       else
01689          close(STDERR_FILENO + 1);
01690 
01691       /* Close everything but stdin/out/error */
01692       ast_close_fds_above_n(STDERR_FILENO + 1);
01693 
01694       /* Execute script */
01695       /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
01696       execv(script, argv);
01697       /* Can't use ast_log since FD's are closed */
01698       ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
01699       /* Special case to set status of AGI to failure */
01700       fprintf(stdout, "failure\n");
01701       fflush(stdout);
01702       _exit(1);
01703    }
01704    ast_verb(3, "Launched AGI Script %s\n", script);
01705    fds[0] = toast[0];
01706    fds[1] = fromast[1];
01707    if (efd)
01708       *efd = audio[1];
01709    /* close what we're not using in the parent */
01710    close(toast[1]);
01711    close(fromast[0]);
01712 
01713    if (efd)
01714       close(audio[0]);
01715 
01716    *opid = pid;
01717    return AGI_RESULT_SUCCESS;
01718 }

static int load_module ( void   )  [static]

Definition at line 3988 of file res_agi.c.

References action_add_agi_cmd(), agi_exec(), ARRAY_LEN, ast_agi_register_multiple(), ast_cli_register_multiple(), ast_manager_register_xml, ast_register_application_xml, AST_TEST_REGISTER, cli_agi, commands, deadagi_exec(), eagi_exec(), and EVENT_FLAG_AGI.

03989 {
03990    ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
03991    /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
03992       no other commands have been registered yet
03993    */
03994    (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03995    ast_register_application_xml(deadapp, deadagi_exec);
03996    ast_register_application_xml(eapp, eagi_exec);
03997    ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
03998    AST_TEST_REGISTER(test_agi_null_docs);
03999    return ast_register_application_xml(app, agi_exec);
04000 }

static int parse_args ( char *  s,
int *  max,
const char *  argv[] 
) [static]

Definition at line 3292 of file res_agi.c.

References ast_log(), LOG_WARNING, and MAX_ARGS.

Referenced by agi_handle_command().

03293 {
03294    int x = 0, quoted = 0, escaped = 0, whitespace = 1;
03295    char *cur;
03296 
03297    cur = s;
03298    while(*s) {
03299       switch(*s) {
03300       case '"':
03301          /* If it's escaped, put a literal quote */
03302          if (escaped)
03303             goto normal;
03304          else
03305             quoted = !quoted;
03306          if (quoted && whitespace) {
03307             /* If we're starting a quote, coming off white space start a new word, too */
03308             argv[x++] = cur;
03309             whitespace=0;
03310          }
03311          escaped = 0;
03312       break;
03313       case ' ':
03314       case '\t':
03315          if (!quoted && !escaped) {
03316             /* If we're not quoted, mark this as whitespace, and
03317                end the previous argument */
03318             whitespace = 1;
03319             *(cur++) = '\0';
03320          } else
03321             /* Otherwise, just treat it as anything else */
03322             goto normal;
03323          break;
03324       case '\\':
03325          /* If we're escaped, print a literal, otherwise enable escaping */
03326          if (escaped) {
03327             goto normal;
03328          } else {
03329             escaped=1;
03330          }
03331          break;
03332       default:
03333 normal:
03334          if (whitespace) {
03335             if (x >= MAX_ARGS -1) {
03336                ast_log(LOG_WARNING, "Too many arguments, truncating\n");
03337                break;
03338             }
03339             /* Coming off of whitespace, start the next argument */
03340             argv[x++] = cur;
03341             whitespace=0;
03342          }
03343          *(cur++) = *s;
03344          escaped=0;
03345       }
03346       s++;
03347    }
03348    /* Null terminate */
03349    *(cur++) = '\0';
03350    argv[x] = NULL;
03351    *max = x;
03352    return 0;
03353 }

static enum agi_result run_agi ( struct ast_channel chan,
char *  request,
AGI agi,
int  pid,
int *  status,
int  dead,
int  argc,
char *  argv[] 
) [static]

Definition at line 3451 of file res_agi.c.

References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, ast_agi_send(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_debug, ast_false(), AST_FRAME_VOICE, ast_frfree, ast_log(), ast_read(), ast_speech_destroy(), ast_strlen_zero(), ast_verb, ast_verbose, ast_waitfor_nandfds(), agi_state::audio, agi_state::ctrl, ast_frame::data, ast_frame::datalen, errno, f, agi_state::fast, agi_state::fd, ast_frame::frametype, len(), LOG_WARNING, pbx_builtin_getvar_helper(), ast_frame::ptr, setup_env(), and agi_state::speech.

Referenced by agi_exec_full().

03452 {
03453    struct ast_channel *c;
03454    int outfd;
03455    int ms;
03456    int needhup = 0;
03457    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
03458    struct ast_frame *f;
03459    char buf[AGI_BUF_LEN];
03460    char *res = NULL;
03461    FILE *readf;
03462    /* how many times we'll retry if ast_waitfor_nandfs will return without either
03463      channel or file descriptor in case select is interrupted by a system call (EINTR) */
03464    int retry = AGI_NANDFS_RETRY;
03465    int send_sighup;
03466    const char *sighup_str;
03467    
03468    ast_channel_lock(chan);
03469    sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
03470    send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
03471    ast_channel_unlock(chan);
03472 
03473    if (!(readf = fdopen(agi->ctrl, "r"))) {
03474       ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
03475       if (send_sighup && pid > -1)
03476          kill(pid, SIGHUP);
03477       close(agi->ctrl);
03478       return AGI_RESULT_FAILURE;
03479    }
03480    
03481    setlinebuf(readf);
03482    setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
03483    for (;;) {
03484       if (needhup) {
03485          needhup = 0;
03486          dead = 1;
03487          if (send_sighup) {
03488             if (pid > -1) {
03489                kill(pid, SIGHUP);
03490             } else if (agi->fast) {
03491                ast_agi_send(agi->fd, chan, "HANGUP\n");
03492             }
03493          }
03494       }
03495       ms = -1;
03496       if (dead) {
03497          c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
03498       } else if (!ast_check_hangup(chan)) {
03499          c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
03500       } else {
03501          /*
03502           * Read the channel control queue until it is dry so we can
03503           * switch to dead mode.
03504           */
03505          c = chan;
03506       }
03507       if (c) {
03508          retry = AGI_NANDFS_RETRY;
03509          /* Idle the channel until we get a command */
03510          f = ast_read(c);
03511          if (!f) {
03512             ast_debug(1, "%s hungup\n", chan->name);
03513             needhup = 1;
03514             if (!returnstatus) {
03515                returnstatus = AGI_RESULT_HANGUP;
03516             }
03517          } else {
03518             /* If it's voice, write it to the audio pipe */
03519             if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
03520                /* Write, ignoring errors */
03521                if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
03522                }
03523             }
03524             ast_frfree(f);
03525          }
03526       } else if (outfd > -1) {
03527          size_t len = sizeof(buf);
03528          size_t buflen = 0;
03529          enum agi_result cmd_status;
03530 
03531          retry = AGI_NANDFS_RETRY;
03532          buf[0] = '\0';
03533 
03534          while (len > 1) {
03535             res = fgets(buf + buflen, len, readf);
03536             if (feof(readf))
03537                break;
03538             if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
03539                break;
03540             if (res != NULL && !agi->fast)
03541                break;
03542             buflen = strlen(buf);
03543             if (buflen && buf[buflen - 1] == '\n')
03544                break;
03545             len = sizeof(buf) - buflen;
03546             if (agidebug)
03547                ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
03548          }
03549 
03550          if (!buf[0]) {
03551             /* Program terminated */
03552             ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
03553             if (pid > 0)
03554                waitpid(pid, status, 0);
03555             /* No need to kill the pid anymore, since they closed us */
03556             pid = -1;
03557             break;
03558          }
03559 
03560          /* Special case for inability to execute child process */
03561          if (*buf && strncasecmp(buf, "failure", 7) == 0) {
03562             returnstatus = AGI_RESULT_FAILURE;
03563             break;
03564          }
03565 
03566          /* get rid of trailing newline, if any */
03567          buflen = strlen(buf);
03568          if (buflen && buf[buflen - 1] == '\n') {
03569             buf[buflen - 1] = '\0';
03570          }
03571 
03572          if (agidebug)
03573             ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
03574          cmd_status = agi_handle_command(chan, agi, buf, dead);
03575          switch (cmd_status) {
03576          case AGI_RESULT_FAILURE:
03577             if (dead || !ast_check_hangup(chan)) {
03578                /* The failure was not because of a hangup. */
03579                returnstatus = AGI_RESULT_FAILURE;
03580             }
03581             break;
03582          default:
03583             break;
03584          }
03585       } else {
03586          if (--retry <= 0) {
03587             ast_log(LOG_WARNING, "No channel, no fd?\n");
03588             returnstatus = AGI_RESULT_FAILURE;
03589             break;
03590          }
03591       }
03592    }
03593    if (agi->speech) {
03594       ast_speech_destroy(agi->speech);
03595    }
03596    /* Notify process */
03597    if (send_sighup) {
03598       if (pid > -1) {
03599          if (kill(pid, SIGHUP)) {
03600             ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
03601          } else { /* Give the process a chance to die */
03602             usleep(1);
03603          }
03604          waitpid(pid, status, WNOHANG);
03605       } else if (agi->fast) {
03606          ast_agi_send(agi->fd, chan, "HANGUP\n");
03607       }
03608    }
03609    fclose(readf);
03610    return returnstatus;
03611 }

static void setup_env ( struct ast_channel chan,
char *  request,
int  fd,
int  enhanced,
int  argc,
char *  argv[] 
) [static]

Definition at line 1720 of file res_agi.c.

References ast_party_caller::ani2, ast_agi_send(), ast_get_version(), ast_party_id_presentation(), ast_channel::caller, ast_channel::context, ast_channel::dialed, ast_channel::exten, ast_party_redirecting::from, ast_party_caller::id, ast_party_id::name, ast_party_dialed::number, ast_party_id::number, ast_party_number::plan, ast_channel::priority, ast_channel::redirecting, S_COR, S_OR, ast_party_dialed::str, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_party_dialed::transit_network_select, ast_channel_tech::type, ast_party_name::valid, and ast_party_number::valid.

Referenced by launch_asyncagi(), and run_agi().

01721 {
01722    int count;
01723 
01724    /* Print initial environment, with agi_request always being the first
01725       thing */
01726    ast_agi_send(fd, chan, "agi_request: %s\n", request);
01727    ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
01728    ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
01729    ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
01730    ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
01731    ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
01732 
01733    /* ANI/DNIS */
01734    ast_agi_send(fd, chan, "agi_callerid: %s\n",
01735       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "unknown"));
01736    ast_agi_send(fd, chan, "agi_calleridname: %s\n",
01737       S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "unknown"));
01738    ast_agi_send(fd, chan, "agi_callingpres: %d\n",
01739       ast_party_id_presentation(&chan->caller.id));
01740    ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->caller.ani2);
01741    ast_agi_send(fd, chan, "agi_callington: %d\n", chan->caller.id.number.plan);
01742    ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->dialed.transit_network_select);
01743    ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->dialed.number.str, "unknown"));
01744    ast_agi_send(fd, chan, "agi_rdnis: %s\n",
01745       S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "unknown"));
01746 
01747    /* Context information */
01748    ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
01749    ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
01750    ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
01751    ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
01752 
01753    /* User information */
01754    ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
01755    ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
01756 
01757    /* Send any parameters to the fastagi server that have been passed via the agi application */
01758    /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
01759    for(count = 1; count < argc; count++)
01760       ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
01761 
01762    /* End with empty return */
01763    ast_agi_send(fd, chan, "\n");
01764 }

static int speech_streamfile ( struct ast_channel chan,
const char *  filename,
const char *  preflang,
int  offset 
) [static]

Definition at line 2877 of file res_agi.c.

References ast_applystream(), ast_openstream(), ast_playstream(), and ast_seekstream().

Referenced by handle_speechrecognize().

02878 {
02879    struct ast_filestream *fs = NULL;
02880 
02881    if (!(fs = ast_openstream(chan, filename, preflang)))
02882       return -1;
02883 
02884    if (offset)
02885       ast_seekstream(fs, offset, SEEK_SET);
02886 
02887    if (ast_applystream(chan, fs))
02888       return -1;
02889 
02890    if (ast_playstream(fs))
02891       return -1;
02892 
02893    return 0;
02894 }

static int unload_module ( void   )  [static]

Definition at line 3974 of file res_agi.c.

References ARRAY_LEN, ast_agi_unregister_multiple(), ast_cli_unregister_multiple(), ast_manager_unregister(), AST_TEST_UNREGISTER, ast_unregister_application(), cli_agi, and commands.

03975 {
03976    ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
03977    /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
03978       we know that these commands were registered by this module and are still registered
03979    */
03980    (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03981    ast_unregister_application(eapp);
03982    ast_unregister_application(deadapp);
03983    ast_manager_unregister("AGI");
03984    AST_TEST_UNREGISTER(test_agi_null_docs);
03985    return ast_unregister_application(app);
03986 }

static void write_html_escaped ( FILE *  htmlfile,
char *  str 
) [static]

Convert string to use HTML escaped characters.

Note:
Maybe this should be a generic function?

Definition at line 3720 of file res_agi.c.

Referenced by write_htmldump().

03721 {
03722    char *cur = str;
03723 
03724    while(*cur) {
03725       switch (*cur) {
03726       case '<':
03727          fprintf(htmlfile, "%s", "&lt;");
03728          break;
03729       case '>':
03730          fprintf(htmlfile, "%s", "&gt;");
03731          break;
03732       case '&':
03733          fprintf(htmlfile, "%s", "&amp;");
03734          break;
03735       case '"':
03736          fprintf(htmlfile, "%s", "&quot;");
03737          break;
03738       default:
03739          fprintf(htmlfile, "%c", *cur);
03740          break;
03741       }
03742       cur++;
03743    }
03744 
03745    return;
03746 }

static int write_htmldump ( const char *  filename  )  [static]

Definition at line 3748 of file res_agi.c.

References ast_free, ast_join(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_xmldoc_printable(), agi_command::cmda, MAX_CMD_LEN, agi_command::summary, agi_command::usage, and write_html_escaped().

Referenced by handle_cli_agi_dump_html().

03749 {
03750    struct agi_command *command;
03751    char fullcmd[MAX_CMD_LEN];
03752    FILE *htmlfile;
03753 
03754    if (!(htmlfile = fopen(filename, "wt")))
03755       return -1;
03756 
03757    fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03758    fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03759    fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03760 
03761    AST_RWLIST_RDLOCK(&agi_commands);
03762    AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03763       char *tempstr, *stringp;
03764 
03765       if (!command->cmda[0])  /* end ? */
03766          break;
03767       /* Hide commands that start with '_' */
03768       if ((command->cmda[0])[0] == '_')
03769          continue;
03770       ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03771 
03772       fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03773       fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03774 #ifdef AST_XML_DOCS
03775       stringp = ast_xmldoc_printable(command->usage, 0);
03776 #else
03777       stringp = ast_strdup(command->usage);
03778 #endif
03779       tempstr = strsep(&stringp, "\n");
03780 
03781       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03782       write_html_escaped(htmlfile, tempstr);
03783       fprintf(htmlfile, "</TD></TR>\n");
03784       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03785 
03786       while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03787          write_html_escaped(htmlfile, tempstr);
03788          fprintf(htmlfile, "<BR>\n");
03789       }
03790       fprintf(htmlfile, "</TD></TR>\n");
03791       fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03792       ast_free(stringp);
03793    }
03794    AST_RWLIST_UNLOCK(&agi_commands);
03795    fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03796    fclose(htmlfile);
03797    return 0;
03798 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk Gateway Interface (AGI)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, } [static]

Definition at line 4006 of file res_agi.c.

struct ast_threadstorage agi_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_agi_buf , .custom_init = NULL , } [static]

Definition at line 938 of file res_agi.c.

Referenced by ast_agi_send().

Initial value:
 {
   .type = "AsyncAGI",
   .destroy = agi_destroy_commands_cb
}

Definition at line 999 of file res_agi.c.

Referenced by add_agi_cmd(), add_to_agi(), and get_agi_cmd().

int agidebug = 0 [static]

Definition at line 915 of file res_agi.c.

char* app = "AGI" [static]

Definition at line 909 of file res_agi.c.

Definition at line 4006 of file res_agi.c.

struct ast_cli_entry cli_agi[] [static]

Definition at line 3927 of file res_agi.c.

Referenced by load_module(), and unload_module().

struct agi_command commands[] [static]

AGI commands list.

Definition at line 3046 of file res_agi.c.

Referenced by aji_dinfo_handler(), dundi_showframe(), load_module(), and unload_module().

char* deadapp = "DeadAGI" [static]

Definition at line 913 of file res_agi.c.

char* eapp = "EAGI" [static]

Definition at line 911 of file res_agi.c.


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1