Mon Oct 8 12:39:27 2012

Asterisk developer's documentation


res_agi.c File Reference

AGI - the Asterisk Gateway Interface. More...

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

Go to the source code of this file.

Data Structures

struct  agi_cmd
struct  agi_commands

Defines

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

Enumerations

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

Functions

static void __init_agi_buf (void)
static void __reg_module (void)
static void __unreg_module (void)
static int action_add_agi_cmd (struct mansession *s, const struct message *m)
 Add a new command to execute by the Async AGI application.
static int add_agi_cmd (struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
static int add_to_agi (struct ast_channel *chan)
static void agi_destroy_commands_cb (void *data)
static int agi_exec (struct ast_channel *chan, const char *data)
static int agi_exec_full (struct ast_channel *chan, const char *data, int enhanced, int dead)
static enum agi_result agi_handle_command (struct ast_channel *chan, AGI *agi, char *buf, int dead)
int AST_OPTIONAL_API_NAME() ast_agi_register (struct ast_module *mod, agi_command *cmd)
 Registers an AGI command.
int AST_OPTIONAL_API_NAME() ast_agi_register_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
 Registers a group of AGI commands, provided as an array of struct agi_command entries.
int AST_OPTIONAL_API_NAME() ast_agi_send (int fd, struct ast_channel *chan, char *fmt,...)
 Sends a string of text to an application connected via AGI.
int AST_OPTIONAL_API_NAME() ast_agi_unregister (struct ast_module *mod, agi_command *cmd)
 Unregisters an AGI command.
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
 Unregisters a group of AGI commands, provided as an array of struct agi_command entries.
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 937 of file res_agi.c.

Referenced by ast_agi_send().

#define AGI_BUF_LEN   2048

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

Referenced by run_agi().

#define AGI_PORT   4573

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

Referenced by agi_handle_command(), and handle_asyncagi_break().

#define MAX_AGI_CONNECT   2000

Definition at line 918 of file res_agi.c.

Referenced by launch_netscript().

#define MAX_ARGS   128

Definition at line 901 of file res_agi.c.

#define MAX_CMD_LEN   80

Definition at line 902 of file res_agi.c.

Referenced by ast_agi_register(), ast_agi_unregister(), handle_cli_agi_show(), help_workhorse(), and write_htmldump().

#define SRV_PREFIX   "_agi._tcp."

Definition at line 905 of file res_agi.c.

Referenced by launch_ha_netscript().

#define TONE_BLOCK_SIZE   200

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


Function Documentation

static void __init_agi_buf ( void   )  [static]

Definition at line 936 of file res_agi.c.

00940 {

static void __reg_module ( void   )  [static]

Definition at line 4008 of file res_agi.c.

static void __unreg_module ( void   )  [static]

Definition at line 4008 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 1153 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(), astman_send_error(), and ast_channel::name.

Referenced by load_module().

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

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

Definition at line 1024 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, ast_datastore::data, agi_cmd::entry, LOG_WARNING, and ast_channel::name.

Referenced by action_add_agi_cmd(), and handle_cli_agi_add_cmd().

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

static int add_to_agi ( struct ast_channel chan  )  [static]

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

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

static void agi_destroy_commands_cb ( void *  data  )  [static]

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

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

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

Definition at line 3893 of file res_agi.c.

References agi_exec_full(), and ast_check_hangup().

Referenced by deadagi_exec(), and load_module().

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

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

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

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

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

Definition at line 3350 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, ast_channel::name, parse_args(), RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_command::usage.

Referenced by launch_asyncagi(), and run_agi().

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

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

Registers an AGI command.

Parameters:
mod Pointer to the module_info structure for the module that is registering the command
cmd Pointer to the descriptor for the command
Return values:
1 on success
0 the command is already registered
AST_OPTIONAL_API_UNAVAILABLE the module is not loaded.

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

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

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

Registers a group of AGI commands, provided as an array of struct agi_command entries.

Parameters:
mod Pointer to the module_info structure for the module that is registering the commands
cmd Pointer to the first entry in the array of command descriptors
len Length of the array (use the ARRAY_LEN macro to determine this easily)
Returns:
0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
Note:
If any command fails to register, all commands previously registered during the operation will be unregistered. In other words, this function registers all the provided commands, or none of them.

Definition at line 3203 of file res_agi.c.

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

Referenced by load_module().

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

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

Sends a string of text to an application connected via AGI.

Parameters:
fd The file descriptor for the AGI session (from struct agi_state)
chan Pointer to an associated Asterisk channel, if any
fmt printf-style format string
Returns:
0 for success, -1 for failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded

Definition at line 939 of file res_agi.c.

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

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

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

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

Unregisters an AGI command.

Parameters:
mod Pointer to the module_info structure for the module that is unregistering the command
cmd Pointer to the descriptor for the command
Returns:
1 on success, 0 if the command was not already registered

Definition at line 3164 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, LOG_WARNING, and MAX_CMD_LEN.

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

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

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

Unregisters a group of AGI commands, provided as an array of struct agi_command entries.

Parameters:
mod Pointer to the module_info structure for the module that is unregistering the commands
cmd Pointer to the first entry in the array of command descriptors
len Length of the array (use the ARRAY_LEN macro to determine this easily)
Returns:
0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
Note:
If any command fails to unregister, this function will continue to unregister the remaining commands in the array; it will not reregister the already-unregistered commands.

Definition at line 3233 of file res_agi.c.

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

Referenced by unload_module().

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

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

Definition at line 1203 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, and ast_channel::name.

Referenced by launch_asyncagi().

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

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

Definition at line 3923 of file res_agi.c.

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

Referenced by load_module().

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

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

Definition at line 3901 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, ast_channel::name, and ast_channel::readformat.

Referenced by load_module().

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

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

Definition at line 3249 of file res_agi.c.

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

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

static void free_agi_cmd ( struct agi_cmd cmd  )  [static]

Definition at line 975 of file res_agi.c.

References ast_free.

Referenced by agi_destroy_commands_cb(), and launch_asyncagi().

00976 {
00977    ast_free(cmd->cmd_buffer);
00978    ast_free(cmd->cmd_id);
00979    ast_free(cmd);
00980 }

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

Definition at line 1002 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, LOG_ERROR, and ast_channel::name.

Referenced by launch_asyncagi().

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

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

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

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

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

Definition at line 1775 of file res_agi.c.

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

01776 {
01777    ast_agi_send(agi->fd, chan, "200 result=0\n");
01778    return ASYNC_AGI_BREAK;
01779 }

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

Definition at line 2416 of file res_agi.c.

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

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

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

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

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

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 1101 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_channel::name, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 2679 of file res_agi.c.

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

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

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

Definition at line 2690 of file res_agi.c.

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

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

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

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

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

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

Definition at line 2668 of file res_agi.c.

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

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

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

Definition at line 2464 of file res_agi.c.

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

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

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

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

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

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 1980 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, ast_channel::language, LOG_WARNING, ast_channel::pbx, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_filestream::vfs.

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

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

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

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

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

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

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

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

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

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

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

Definition at line 2734 of file res_agi.c.

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

02735 {
02736    ast_agi_send(agi->fd, chan, "200 result=0\n");
02737    return RESULT_SUCCESS;
02738 }

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

Definition at line 2237 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_channel::language, LOG_WARNING, ast_channel::name, ast_channel::readformat, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, THRESHOLD_SILENCE, and ast_dsp::totalsilence.

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

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

Definition at line 1813 of file res_agi.c.

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

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

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

Definition at line 1833 of file res_agi.c.

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

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

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

Definition at line 2080 of file res_agi.c.

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

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

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

Definition at line 2094 of file res_agi.c.

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

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

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

Definition at line 2124 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, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

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

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

Definition at line 2064 of file res_agi.c.

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

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

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

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

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

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

Definition at line 2158 of file res_agi.c.

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

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

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

Definition at line 2109 of file res_agi.c.

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

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

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

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

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

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

Definition at line 1794 of file res_agi.c.

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

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

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

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

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

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

Definition at line 2199 of file res_agi.c.

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

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

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

Definition at line 2209 of file res_agi.c.

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

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

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

Definition at line 2740 of file res_agi.c.

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

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

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

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

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

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

Definition at line 2552 of file res_agi.c.

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

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

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

Definition at line 2836 of file res_agi.c.

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

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

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

Definition at line 2753 of file res_agi.c.

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

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

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

Definition at line 2854 of file res_agi.c.

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

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

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

Definition at line 2787 of file res_agi.c.

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

02788 {
02789    if (agi->speech) {
02790       ast_speech_destroy(agi->speech);
02791       agi->speech = NULL;
02792       ast_agi_send(agi->fd, chan, "200 result=1\n");
02793    } else {
02794       ast_agi_send(agi->fd, chan, "200 result=0\n");
02795    }
02796 
02797    return RESULT_SUCCESS;
02798 }

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

Definition at line 2800 of file res_agi.c.

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

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

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

Definition at line 2891 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_channel::language, ast_speech::lock, 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.

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

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

Definition at line 2769 of file res_agi.c.

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

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

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

Definition at line 2818 of file res_agi.c.

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

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

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

Definition at line 1930 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, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_filestream::vfs.

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

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

Definition at line 1850 of file res_agi.c.

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

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

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

Definition at line 2618 of file res_agi.c.

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

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

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

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

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

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

Definition at line 3092 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, agi_command::list, MAX_CMD_LEN, S_OR, and agi_command::summary.

Referenced by handle_cli_agi_show().

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

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

Definition at line 1231 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, ast_channel::name, setup_env(), and agi_state::speech.

Referenced by launch_script().

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

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

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

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

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

Definition at line 1443 of file res_agi.c.

References AGI_PORT, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS_FAST, ahp, 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().

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

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

Definition at line 1598 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(), LOG_WARNING, and setenv().

Referenced by agi_exec_full().

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

static int load_module ( void   )  [static]

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

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

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

Definition at line 3287 of file res_agi.c.

References ast_log(), LOG_WARNING, and MAX_ARGS.

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

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

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

Referenced by agi_exec_full().

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

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

Definition at line 1717 of file res_agi.c.

References ast_channel::accountcode, 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_channel::language, ast_party_id::name, ast_channel::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_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

Referenced by launch_asyncagi(), and run_agi().

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

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

Definition at line 2872 of file res_agi.c.

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

02873 {
02874    struct ast_filestream *fs = NULL;
02875 
02876    if (!(fs = ast_openstream(chan, filename, preflang)))
02877       return -1;
02878 
02879    if (offset)
02880       ast_seekstream(fs, offset, SEEK_SET);
02881 
02882    if (ast_applystream(chan, fs))
02883       return -1;
02884 
02885    if (ast_playstream(fs))
02886       return -1;
02887 
02888    return 0;
02889 }

static int unload_module ( void   )  [static]

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

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

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

Referenced by write_htmldump().

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

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

Definition at line 3743 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, agi_command::list, MAX_CMD_LEN, strsep(), agi_command::summary, agi_command::usage, and write_html_escaped().

Referenced by handle_cli_agi_dump_html().

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


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

Referenced by ast_agi_send().

struct ast_datastore_info agi_commands_datastore_info [static]

Initial value:

 {
   .type = "AsyncAGI",
   .destroy = agi_destroy_commands_cb
}

Definition at line 997 of file res_agi.c.

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

int agidebug = 0 [static]

Definition at line 913 of file res_agi.c.

char* app = "AGI" [static]

Definition at line 907 of file res_agi.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4008 of file res_agi.c.

struct ast_cli_entry cli_agi[] [static]

Definition at line 3929 of file res_agi.c.

Referenced by load_module(), and unload_module().

struct agi_command commands[] [static]

AGI commands list.

Definition at line 3041 of file res_agi.c.

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

char* deadapp = "DeadAGI" [static]

Definition at line 911 of file res_agi.c.

char* eapp = "EAGI" [static]

Definition at line 909 of file res_agi.c.


Generated on Mon Oct 8 12:39:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7