Thu Sep 7 01:03:35 2017

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
struct  agimaskvars

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 941 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 940 of file res_agi.c.

00944 {

static void __reg_module ( void   )  [static]

Definition at line 4034 of file res_agi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4034 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 1157 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().

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

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

Definition at line 1028 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().

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

static int add_to_agi ( struct ast_channel chan  )  [static]

Definition at line 1061 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().

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

static void agi_destroy_commands_cb ( void *  data  )  [static]

Definition at line 987 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().

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

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

Definition at line 3919 of file res_agi.c.

References agi_exec_full(), and ast_check_hangup().

Referenced by deadagi_exec(), and load_module().

03920 {
03921    if (!ast_check_hangup(chan))
03922       return agi_exec_full(chan, data, 0, 0);
03923    else
03924       return agi_exec_full(chan, data, 0, 1);
03925 }

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

Definition at line 3852 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().

03853 {
03854    enum agi_result res;
03855    char *buf;
03856    int fds[2], efd = -1, pid = -1;
03857    AST_DECLARE_APP_ARGS(args,
03858       AST_APP_ARG(arg)[MAX_ARGS];
03859    );
03860    AGI agi;
03861 
03862    if (ast_strlen_zero(data)) {
03863       ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03864       return -1;
03865    }
03866    if (dead)
03867       ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03868    memset(&agi, 0, sizeof(agi));
03869    buf = ast_strdupa(data);
03870    AST_STANDARD_APP_ARGS(args, buf);
03871    args.argv[args.argc] = NULL;
03872 #if 0
03873     /* Answer if need be */
03874    if (chan->_state != AST_STATE_UP) {
03875       if (ast_answer(chan))
03876          return -1;
03877    }
03878 #endif
03879    res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03880    /* Async AGI do not require run_agi(), so just proceed if normal AGI
03881       or Fast AGI are setup with success. */
03882    if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03883       int status = 0;
03884       agi.fd = fds[1];
03885       agi.ctrl = fds[0];
03886       agi.audio = efd;
03887       agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03888       res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03889       /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
03890       if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03891          res = AGI_RESULT_FAILURE;
03892       if (fds[1] != fds[0])
03893          close(fds[1]);
03894       if (efd > -1)
03895          close(efd);
03896    }
03897    ast_safe_fork_cleanup();
03898 
03899    switch (res) {
03900    case AGI_RESULT_SUCCESS:
03901    case AGI_RESULT_SUCCESS_FAST:
03902    case AGI_RESULT_SUCCESS_ASYNC:
03903       pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03904       break;
03905    case AGI_RESULT_FAILURE:
03906       pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03907       break;
03908    case AGI_RESULT_NOTFOUND:
03909       pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03910       break;
03911    case AGI_RESULT_HANGUP:
03912       pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03913       return -1;
03914    }
03915 
03916    return 0;
03917 }

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

Definition at line 3370 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().

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

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

Definition at line 3138 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().

03139 {
03140    char fullcmd[MAX_CMD_LEN];
03141 
03142    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03143 
03144    if (!find_command(cmd->cmda, 1)) {
03145       *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
03146       if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
03147 #ifdef AST_XML_DOCS
03148          *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
03149          *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
03150          *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
03151          *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
03152          *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
03153 #endif
03154 #ifndef HAVE_NULLSAFE_PRINTF
03155          if (!cmd->summary) {
03156             *((char **) &cmd->summary) = ast_strdup("");
03157          }
03158          if (!cmd->usage) {
03159             *((char **) &cmd->usage) = ast_strdup("");
03160          }
03161          if (!cmd->syntax) {
03162             *((char **) &cmd->syntax) = ast_strdup("");
03163          }
03164          if (!cmd->seealso) {
03165             *((char **) &cmd->seealso) = ast_strdup("");
03166          }
03167 #endif
03168       }
03169 
03170       cmd->mod = mod;
03171       AST_RWLIST_WRLOCK(&agi_commands);
03172       AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
03173       AST_RWLIST_UNLOCK(&agi_commands);
03174       if (mod != ast_module_info->self)
03175          ast_module_ref(ast_module_info->self);
03176       ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
03177       return 1;
03178    } else {
03179       ast_log(LOG_WARNING, "Command already registered!\n");
03180       return 0;
03181    }
03182 }

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

Definition at line 3223 of file res_agi.c.

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

Referenced by load_module().

03224 {
03225    unsigned int i, x = 0;
03226 
03227    for (i = 0; i < len; i++) {
03228       if (ast_agi_register(mod, cmd + i) == 1) {
03229          x++;
03230          continue;
03231       }
03232 
03233       /* registration failed, unregister everything
03234          that had been registered up to that point
03235       */
03236       for (; x > 0; x--) {
03237          /* we are intentionally ignoring the
03238             result of ast_agi_unregister() here,
03239             but it should be safe to do so since
03240             we just registered these commands and
03241             the only possible way for unregistration
03242             to fail is if the command is not
03243             registered
03244          */
03245          (void) ast_agi_unregister(mod, cmd + x - 1);
03246       }
03247       return -1;
03248    }
03249 
03250    return 0;
03251 }

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

Definition at line 943 of file res_agi.c.

References 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().

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

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

Definition at line 3184 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().

03185 {
03186    struct agi_command *e;
03187    int unregistered = 0;
03188    char fullcmd[MAX_CMD_LEN];
03189 
03190    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03191 
03192    AST_RWLIST_WRLOCK(&agi_commands);
03193    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
03194       if (cmd == e) {
03195          AST_RWLIST_REMOVE_CURRENT(list);
03196          if (mod != ast_module_info->self)
03197             ast_module_unref(ast_module_info->self);
03198 #ifdef AST_XML_DOCS
03199          if (e->docsrc == AST_XML_DOC) {
03200             ast_free((char *) e->summary);
03201             ast_free((char *) e->usage);
03202             ast_free((char *) e->syntax);
03203             ast_free((char *) e->seealso);
03204             *((char **) &e->summary) = NULL;
03205             *((char **) &e->usage) = NULL;
03206             *((char **) &e->syntax) = NULL;
03207             *((char **) &e->seealso) = NULL;
03208          }
03209 #endif
03210          unregistered=1;
03211          break;
03212       }
03213    }
03214    AST_RWLIST_TRAVERSE_SAFE_END;
03215    AST_RWLIST_UNLOCK(&agi_commands);
03216    if (unregistered)
03217       ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
03218    else
03219       ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
03220    return unregistered;
03221 }

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

Definition at line 3253 of file res_agi.c.

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

Referenced by unload_module().

03254 {
03255    unsigned int i;
03256    int res = 0;
03257 
03258    for (i = 0; i < len; i++) {
03259       /* remember whether any of the unregistration
03260          attempts failed... there is no recourse if
03261          any of them do
03262       */
03263       res |= ast_agi_unregister(mod, cmd + i);
03264    }
03265 
03266    return res;
03267 }

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

Definition at line 1207 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().

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

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

Definition at line 3949 of file res_agi.c.

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

Referenced by load_module().

03950 {
03951    ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03952    return agi_exec(chan, data);
03953 }

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

Definition at line 3927 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().

03928 {
03929    int readformat, res;
03930 
03931    if (ast_check_hangup(chan)) {
03932       ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03933       return 0;
03934    }
03935    readformat = chan->readformat;
03936    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03937       ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03938       return -1;
03939    }
03940    res = agi_exec_full(chan, data, 1, 0);
03941    if (!res) {
03942       if (ast_set_read_format(chan, readformat)) {
03943          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03944       }
03945    }
03946    return res;
03947 }

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

Definition at line 3269 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().

03270 {
03271    int y, match;
03272    struct agi_command *e;
03273 
03274    AST_RWLIST_RDLOCK(&agi_commands);
03275    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03276       if (!e->cmda[0])
03277          break;
03278       /* start optimistic */
03279       match = 1;
03280       for (y = 0; match && cmds[y]; y++) {
03281          /* If there are no more words in the command (and we're looking for
03282             an exact match) or there is a difference between the two words,
03283             then this is not a match */
03284          if (!e->cmda[y] && !exact)
03285             break;
03286          /* don't segfault if the next part of a command doesn't exist */
03287          if (!e->cmda[y]) {
03288             AST_RWLIST_UNLOCK(&agi_commands);
03289             return NULL;
03290          }
03291          if (strcasecmp(e->cmda[y], cmds[y]))
03292             match = 0;
03293       }
03294       /* If more words are needed to complete the command then this is not
03295          a candidate (unless we're looking for a really inexact answer  */
03296       if ((exact > -1) && e->cmda[y])
03297          match = 0;
03298       if (match) {
03299          AST_RWLIST_UNLOCK(&agi_commands);
03300          return e;
03301       }
03302    }
03303    AST_RWLIST_UNLOCK(&agi_commands);
03304    return NULL;
03305 }

static void free_agi_cmd ( struct agi_cmd cmd  )  [static]

Definition at line 979 of file res_agi.c.

References ast_free.

Referenced by agi_destroy_commands_cb(), and launch_asyncagi().

00980 {
00981    ast_free(cmd->cmd_buffer);
00982    ast_free(cmd->cmd_id);
00983    ast_free(cmd);
00984 }

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

Definition at line 1006 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().

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

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

Definition at line 1768 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.

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

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

Definition at line 1780 of file res_agi.c.

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

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

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

Definition at line 2421 of file res_agi.c.

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

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

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

Definition at line 2535 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.

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

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 1105 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.

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

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

Definition at line 2725 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.

02726 {
02727    switch (cmd) {
02728    case CLI_INIT:
02729       e->command = "agi set debug [on|off]";
02730       e->usage =
02731          "Usage: agi set debug [on|off]\n"
02732          "       Enables/disables dumping of AGI transactions for\n"
02733          "       debugging purposes.\n";
02734       return NULL;
02735 
02736    case CLI_GENERATE:
02737       return NULL;
02738    }
02739 
02740    if (a->argc != e->args)
02741       return CLI_SHOWUSAGE;
02742 
02743    if (strncasecmp(a->argv[3], "off", 3) == 0) {
02744       agidebug = 0;
02745    } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
02746       agidebug = 1;
02747    } else {
02748       return CLI_SHOWUSAGE;
02749    }
02750    ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
02751    return CLI_SUCCESS;
02752 }

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

Definition at line 3828 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().

03829 {
03830    switch (cmd) {
03831    case CLI_INIT:
03832       e->command = "agi dump html";
03833       e->usage =
03834          "Usage: agi dump html <filename>\n"
03835          "       Dumps the AGI command list in HTML format to the given\n"
03836          "       file.\n";
03837       return NULL;
03838    case CLI_GENERATE:
03839       return NULL;
03840    }
03841    if (a->argc != e->args + 1)
03842       return CLI_SHOWUSAGE;
03843 
03844    if (write_htmldump(a->argv[e->args]) < 0) {
03845       ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03846       return CLI_SHOWUSAGE;
03847    }
03848    ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03849    return CLI_SUCCESS;
03850 }

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

Definition at line 3641 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.

03642 {
03643    struct agi_command *command;
03644    char fullcmd[MAX_CMD_LEN];
03645    int error = 0;
03646 
03647    switch (cmd) {
03648    case CLI_INIT:
03649       e->command = "agi show commands [topic]";
03650       e->usage =
03651          "Usage: agi show commands [topic] <topic>\n"
03652          "       When called with a topic as an argument, displays usage\n"
03653          "       information on the given command.  If called without a\n"
03654          "       topic, it provides a list of AGI commands.\n";
03655       return NULL;
03656    case CLI_GENERATE:
03657       return NULL;
03658    }
03659    if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03660       return CLI_SHOWUSAGE;
03661    if (a->argc > e->args - 1) {
03662       command = find_command(a->argv + e->args, 1);
03663       if (command) {
03664          char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03665          char info[30 + MAX_CMD_LEN];              /* '-= Info about...' */
03666          char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];  /* '-= Info about...' with colors */
03667          char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03668          char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Description]\n with colors */
03669          char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Runs Dead]\n with colors */
03670          char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];      /* 'Yes' or 'No' with colors */
03671          char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];    /* [See Also]\n with colors */
03672          char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03673          size_t synlen, desclen, seealsolen, stxlen;
03674 
03675          term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03676          term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03677          term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03678          term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03679          term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03680          term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03681 
03682          ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03683          snprintf(info, sizeof(info), "\n  -= Info about agi '%s' =- ", fullcmd);
03684          term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03685 #ifdef AST_XML_DOCS
03686          if (command->docsrc == AST_XML_DOC) {
03687             synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03688             description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03689             seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03690             if (!seealso || !description || !synopsis) {
03691                error = 1;
03692                goto return_cleanup;
03693             }
03694          } else
03695 #endif
03696          {
03697             synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03698             synopsis = ast_malloc(synlen);
03699 
03700             desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03701             description = ast_malloc(desclen);
03702 
03703             seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03704             seealso = ast_malloc(seealsolen);
03705 
03706             if (!synopsis || !description || !seealso) {
03707                error = 1;
03708                goto return_cleanup;
03709             }
03710             term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03711             term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03712             term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03713          }
03714 
03715          stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03716          syntax = ast_malloc(stxlen);
03717          if (!syntax) {
03718             error = 1;
03719             goto return_cleanup;
03720          }
03721          term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03722 
03723          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,
03724                desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03725                seealsotitle, seealso);
03726 return_cleanup:
03727          ast_free(synopsis);
03728          ast_free(description);
03729          ast_free(syntax);
03730          ast_free(seealso);
03731       } else {
03732          if (find_command(a->argv + e->args, -1)) {
03733             return help_workhorse(a->fd, a->argv + e->args);
03734          } else {
03735             ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03736             ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03737          }
03738       }
03739    } else {
03740       return help_workhorse(a->fd, NULL);
03741    }
03742    return (error ? CLI_FAILURE : CLI_SUCCESS);
03743 }

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

Definition at line 1899 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().

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

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

Definition at line 2697 of file res_agi.c.

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

02698 {
02699    int res;
02700 
02701    if (argc != 4)
02702       return RESULT_SHOWUSAGE;
02703    res = ast_db_del(argv[2], argv[3]);
02704    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02705    return RESULT_SUCCESS;
02706 }

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

Definition at line 2708 of file res_agi.c.

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

02709 {
02710    int num_deleted;
02711 
02712    if ((argc < 3) || (argc > 4)) {
02713       return RESULT_SHOWUSAGE;
02714    }
02715    if (argc == 4) {
02716       num_deleted = ast_db_deltree(argv[2], argv[3]);
02717    } else {
02718       num_deleted = ast_db_deltree(argv[2], NULL);
02719    }
02720 
02721    ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
02722    return RESULT_SUCCESS;
02723 }

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

Definition at line 2653 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.

02654 {
02655    int res;
02656    struct ast_str *buf;
02657 
02658    if (argc != 4)
02659       return RESULT_SHOWUSAGE;
02660 
02661    if (!(buf = ast_str_create(16))) {
02662       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02663       return RESULT_SUCCESS;
02664    }
02665 
02666    do {
02667       res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
02668       ast_str_update(buf);
02669       if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
02670          break;
02671       }
02672       if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
02673          break;
02674       }
02675    } while (1);
02676    
02677    if (res)
02678       ast_agi_send(agi->fd, chan, "200 result=0\n");
02679    else
02680       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
02681 
02682    ast_free(buf);
02683    return RESULT_SUCCESS;
02684 }

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

Definition at line 2686 of file res_agi.c.

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

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

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

Definition at line 2469 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.

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

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

Definition at line 2177 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.

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

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 1985 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.

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

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

Definition at line 2566 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.

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

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

Definition at line 2589 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.

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

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

Definition at line 2441 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.

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

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

Definition at line 2754 of file res_agi.c.

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

02755 {
02756    ast_agi_send(agi->fd, chan, "200 result=0\n");
02757    return RESULT_SUCCESS;
02758 }

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

Definition at line 2242 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.

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

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

Definition at line 1818 of file res_agi.c.

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

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

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

Definition at line 1838 of file res_agi.c.

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

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

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

Definition at line 2085 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.

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

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

Definition at line 2099 of file res_agi.c.

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

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

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

Definition at line 2129 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.

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

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

Definition at line 2069 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.

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

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 2054 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.

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

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

Definition at line 2163 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.

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

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

Definition at line 2114 of file res_agi.c.

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

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

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

Definition at line 1883 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.

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

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

Definition at line 1799 of file res_agi.c.

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

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

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

Definition at line 2514 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.

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

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

Definition at line 2204 of file res_agi.c.

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

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

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

Definition at line 2214 of file res_agi.c.

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

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

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

Definition at line 2760 of file res_agi.c.

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

02761 {
02762    if (argc < 3) {
02763       return RESULT_SHOWUSAGE;
02764    }
02765    if (!strncasecmp(argv[2], "on", 2))
02766       ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
02767    else if (!strncasecmp(argv[2], "off", 3))
02768       ast_moh_stop(chan);
02769    ast_agi_send(agi->fd, chan, "200 result=0\n");
02770    return RESULT_SUCCESS;
02771 }

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

Definition at line 2223 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.

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

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

Definition at line 2557 of file res_agi.c.

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

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

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

Definition at line 2856 of file res_agi.c.

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

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

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

Definition at line 2773 of file res_agi.c.

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

02774 {
02775    /* If a structure already exists, return an error */
02776         if (agi->speech) {
02777       ast_agi_send(agi->fd, chan, "200 result=0\n");
02778       return RESULT_SUCCESS;
02779    }
02780 
02781    if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02782       ast_agi_send(agi->fd, chan, "200 result=1\n");
02783    else
02784       ast_agi_send(agi->fd, chan, "200 result=0\n");
02785 
02786    return RESULT_SUCCESS;
02787 }

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

Definition at line 2874 of file res_agi.c.

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

02875 {
02876    if (argc != 4)
02877       return RESULT_SHOWUSAGE;
02878 
02879    if (!agi->speech) {
02880       ast_agi_send(agi->fd, chan, "200 result=0\n");
02881       return RESULT_SUCCESS;
02882    }
02883 
02884    if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02885       ast_agi_send(agi->fd, chan, "200 result=0\n");
02886    else
02887       ast_agi_send(agi->fd, chan, "200 result=1\n");
02888 
02889    return RESULT_SUCCESS;
02890 }

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

Definition at line 2807 of file res_agi.c.

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

02808 {
02809    if (agi->speech) {
02810       ast_speech_destroy(agi->speech);
02811       agi->speech = NULL;
02812       ast_agi_send(agi->fd, chan, "200 result=1\n");
02813    } else {
02814       ast_agi_send(agi->fd, chan, "200 result=0\n");
02815    }
02816 
02817    return RESULT_SUCCESS;
02818 }

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

Definition at line 2820 of file res_agi.c.

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

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

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

Definition at line 2911 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.

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

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

Definition at line 2789 of file res_agi.c.

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

02790 {
02791    /* Check for minimum arguments */
02792    if (argc != 4)
02793       return RESULT_SHOWUSAGE;
02794 
02795    /* Check to make sure speech structure exists */
02796    if (!agi->speech) {
02797       ast_agi_send(agi->fd, chan, "200 result=0\n");
02798       return RESULT_SUCCESS;
02799    }
02800 
02801    ast_speech_change(agi->speech, argv[2], argv[3]);
02802    ast_agi_send(agi->fd, chan, "200 result=1\n");
02803 
02804    return RESULT_SUCCESS;
02805 }

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

Definition at line 2838 of file res_agi.c.

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

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

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

Definition at line 1935 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.

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

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

Definition at line 1855 of file res_agi.c.

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

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

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

Definition at line 2623 of file res_agi.c.

References agimaskvarend, agimaskvarini, ast_agi_send(), ast_copy_string(), AST_LIST_TRAVERSE, ast_strdupa, ast_verb, ast_channel::data, agi_state::fd, ast_variable_list::list, mask_string(), RESULT_SHOWUSAGE, RESULT_SUCCESS, var, ast_variable_list::variable, and VERBOSITY_ATLEAST.

02624 {
02625    int level = 0;
02626    char *tmpdata, *var;
02627    struct ast_variable_list *cur;
02628 
02629    if (argc < 2)
02630       return RESULT_SHOWUSAGE;
02631 
02632    if (argv[2])
02633       sscanf(argv[2], "%30d", &level);
02634 
02635    if (VERBOSITY_ATLEAST(level)) {
02636       tmpdata = ast_strdupa(chan->data);  /* do not modify string */
02637       char findstr[128];
02638       AST_LIST_TRAVERSE(&agimaskvars, cur, list) {
02639          ast_copy_string(findstr, cur->variable, sizeof(findstr));
02640          strncat(findstr, "=", sizeof(findstr));
02641          var = strstr(tmpdata, findstr);
02642          if (var)
02643             mask_string(var, agimaskvarini, agimaskvarend, 1);
02644       }
02645       ast_verb(level, "%s: %s\n", tmpdata, argv[1]);
02646    }
02647 
02648    ast_agi_send(agi->fd, chan, "200 result=1\n");
02649 
02650    return RESULT_SUCCESS;
02651 }

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

Definition at line 1786 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.

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

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

Definition at line 3112 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().

03113 {
03114    char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
03115    struct agi_command *e;
03116 
03117    if (match)
03118       ast_join(matchstr, sizeof(matchstr), match);
03119 
03120    ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
03121    AST_RWLIST_RDLOCK(&agi_commands);
03122    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03123       if (!e->cmda[0])
03124          break;
03125       /* Hide commands that start with '_' */
03126       if ((e->cmda[0])[0] == '_')
03127          continue;
03128       ast_join(fullcmd, sizeof(fullcmd), e->cmda);
03129       if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
03130          continue;
03131       ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
03132    }
03133    AST_RWLIST_UNLOCK(&agi_commands);
03134 
03135    return CLI_SUCCESS;
03136 }

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

Definition at line 1235 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().

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

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

Definition at line 1549 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().

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

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

Definition at line 1447 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().

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

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

Definition at line 1603 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().

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

static int load_module ( void   )  [static]

Definition at line 4016 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.

04017 {
04018    ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
04019    /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
04020       no other commands have been registered yet
04021    */
04022    (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
04023    ast_register_application_xml(deadapp, deadagi_exec);
04024    ast_register_application_xml(eapp, eagi_exec);
04025    ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
04026    AST_TEST_REGISTER(test_agi_null_docs);
04027    return ast_register_application_xml(app, agi_exec);
04028 }

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

Definition at line 3307 of file res_agi.c.

References ast_log(), LOG_WARNING, and MAX_ARGS.

Referenced by agi_handle_command().

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

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 3466 of file res_agi.c.

References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, agimaskvarend, agimaskvarini, ast_agi_send(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_copy_string(), ast_debug, ast_false(), AST_FRAME_VOICE, ast_frfree, AST_LIST_TRAVERSE, ast_log(), ast_read(), ast_speech_destroy(), ast_strdupa, 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(), ast_variable_list::list, LOG_WARNING, mask_string(), pbx_builtin_getvar_helper(), ast_frame::ptr, setup_env(), agi_state::speech, var, ast_variable_list::variable, and VERBOSITY_ATLEAST.

Referenced by agi_exec_full().

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

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

Definition at line 1722 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().

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

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

Definition at line 2892 of file res_agi.c.

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

Referenced by handle_speechrecognize().

02893 {
02894    struct ast_filestream *fs = NULL;
02895 
02896    if (!(fs = ast_openstream(chan, filename, preflang)))
02897       return -1;
02898 
02899    if (offset)
02900       ast_seekstream(fs, offset, SEEK_SET);
02901 
02902    if (ast_applystream(chan, fs))
02903       return -1;
02904 
02905    if (ast_playstream(fs))
02906       return -1;
02907 
02908    return 0;
02909 }

static int unload_module ( void   )  [static]

Definition at line 4002 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.

04003 {
04004    ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
04005    /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
04006       we know that these commands were registered by this module and are still registered
04007    */
04008    (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
04009    ast_unregister_application(eapp);
04010    ast_unregister_application(deadapp);
04011    ast_manager_unregister("AGI");
04012    AST_TEST_UNREGISTER(test_agi_null_docs);
04013    return ast_unregister_application(app);
04014 }

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 3748 of file res_agi.c.

Referenced by write_htmldump().

03749 {
03750    char *cur = str;
03751 
03752    while(*cur) {
03753       switch (*cur) {
03754       case '<':
03755          fprintf(htmlfile, "%s", "&lt;");
03756          break;
03757       case '>':
03758          fprintf(htmlfile, "%s", "&gt;");
03759          break;
03760       case '&':
03761          fprintf(htmlfile, "%s", "&amp;");
03762          break;
03763       case '"':
03764          fprintf(htmlfile, "%s", "&quot;");
03765          break;
03766       default:
03767          fprintf(htmlfile, "%c", *cur);
03768          break;
03769       }
03770       cur++;
03771    }
03772 
03773    return;
03774 }

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

Definition at line 3776 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().

03777 {
03778    struct agi_command *command;
03779    char fullcmd[MAX_CMD_LEN];
03780    FILE *htmlfile;
03781 
03782    if (!(htmlfile = fopen(filename, "wt")))
03783       return -1;
03784 
03785    fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03786    fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03787    fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03788 
03789    AST_RWLIST_RDLOCK(&agi_commands);
03790    AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03791       char *tempstr, *stringp;
03792 
03793       if (!command->cmda[0])  /* end ? */
03794          break;
03795       /* Hide commands that start with '_' */
03796       if ((command->cmda[0])[0] == '_')
03797          continue;
03798       ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03799 
03800       fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03801       fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03802 #ifdef AST_XML_DOCS
03803       stringp = ast_xmldoc_printable(command->usage, 0);
03804 #else
03805       stringp = ast_strdup(command->usage);
03806 #endif
03807       tempstr = strsep(&stringp, "\n");
03808 
03809       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03810       write_html_escaped(htmlfile, tempstr);
03811       fprintf(htmlfile, "</TD></TR>\n");
03812       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03813 
03814       while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03815          write_html_escaped(htmlfile, tempstr);
03816          fprintf(htmlfile, "<BR>\n");
03817       }
03818       fprintf(htmlfile, "</TD></TR>\n");
03819       fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03820       ast_free(stringp);
03821    }
03822    AST_RWLIST_UNLOCK(&agi_commands);
03823    fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03824    fclose(htmlfile);
03825    return 0;
03826 }


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 4034 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 940 of file res_agi.c.

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

Definition at line 1001 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 4034 of file res_agi.c.

struct ast_cli_entry cli_agi[] [static]

Definition at line 3955 of file res_agi.c.

Referenced by load_module(), and unload_module().

struct agi_command commands[] [static]

AGI commands list.

Definition at line 3061 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 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1