Wed Apr 6 11:30:08 2011

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/features.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 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 int 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 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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 931 of file res_agi.c.

Referenced by ast_agi_send().

#define AGI_BUF_LEN   2048

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

Referenced by run_agi().

#define AGI_PORT   4573

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

#define MAX_AGI_CONNECT   2000

Definition at line 915 of file res_agi.c.

Referenced by launch_netscript().

#define MAX_ARGS   128

Definition at line 898 of file res_agi.c.

#define MAX_CMD_LEN   80

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

Referenced by launch_ha_netscript().

#define TONE_BLOCK_SIZE   200

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


Function Documentation

static void __init_agi_buf ( void   )  [static]

Definition at line 930 of file res_agi.c.

00934 {

static void __reg_module ( void   )  [static]

Definition at line 3867 of file res_agi.c.

static void __unreg_module ( void   )  [static]

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

01145 {
01146    const char *channel = astman_get_header(m, "Channel");
01147    const char *cmdbuff = astman_get_header(m, "Command");
01148    const char *cmdid   = astman_get_header(m, "CommandID");
01149    struct ast_channel *chan;
01150    char buf[256];
01151 
01152    if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
01153       astman_send_error(s, m, "Both, Channel and Command are *required*");
01154       return 0;
01155    }
01156 
01157    if (!(chan = ast_channel_get_by_name(channel))) {
01158       snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
01159       astman_send_error(s, m, buf);
01160       return 0;
01161    }
01162 
01163    ast_channel_lock(chan);
01164 
01165    if (add_agi_cmd(chan, cmdbuff, cmdid)) {
01166       snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
01167       astman_send_error(s, m, buf);
01168       ast_channel_unlock(chan);
01169       chan = ast_channel_unref(chan);
01170       return 0;
01171    }
01172 
01173    ast_channel_unlock(chan);
01174    chan = ast_channel_unref(chan);
01175 
01176    astman_send_ack(s, m, "Added AGI command to queue");
01177 
01178    return 0;
01179 }

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

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

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

static int add_to_agi ( struct ast_channel chan  )  [static]

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

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

static void agi_destroy_commands_cb ( void *  data  )  [static]

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

00978 {
00979    struct agi_cmd *cmd;
00980    AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
00981    AST_LIST_LOCK(chan_cmds);
00982    while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
00983       free_agi_cmd(cmd);
00984    }
00985    AST_LIST_UNLOCK(chan_cmds);
00986    AST_LIST_HEAD_DESTROY(chan_cmds);
00987    ast_free(chan_cmds);
00988 }

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

Definition at line 3752 of file res_agi.c.

References agi_exec_full(), and ast_check_hangup().

Referenced by deadagi_exec(), and load_module().

03753 {
03754    if (!ast_check_hangup(chan))
03755       return agi_exec_full(chan, data, 0, 0);
03756    else
03757       return agi_exec_full(chan, data, 0, 1);
03758 }

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

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

03686 {
03687    enum agi_result res;
03688    char *buf;
03689    int fds[2], efd = -1, pid = -1;
03690    AST_DECLARE_APP_ARGS(args,
03691       AST_APP_ARG(arg)[MAX_ARGS];
03692    );
03693    AGI agi;
03694 
03695    if (ast_strlen_zero(data)) {
03696       ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03697       return -1;
03698    }
03699    if (dead)
03700       ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03701    memset(&agi, 0, sizeof(agi));
03702    buf = ast_strdupa(data);
03703    AST_STANDARD_APP_ARGS(args, buf);
03704    args.argv[args.argc] = NULL;
03705 #if 0
03706     /* Answer if need be */
03707    if (chan->_state != AST_STATE_UP) {
03708       if (ast_answer(chan))
03709          return -1;
03710    }
03711 #endif
03712    res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03713    /* Async AGI do not require run_agi(), so just proceed if normal AGI
03714       or Fast AGI are setup with success. */
03715    if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03716       int status = 0;
03717       agi.fd = fds[1];
03718       agi.ctrl = fds[0];
03719       agi.audio = efd;
03720       agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03721       res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03722       /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
03723       if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03724          res = AGI_RESULT_FAILURE;
03725       if (fds[1] != fds[0])
03726          close(fds[1]);
03727       if (efd > -1)
03728          close(efd);
03729    }
03730    ast_safe_fork_cleanup();
03731 
03732    switch (res) {
03733    case AGI_RESULT_SUCCESS:
03734    case AGI_RESULT_SUCCESS_FAST:
03735    case AGI_RESULT_SUCCESS_ASYNC:
03736       pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03737       break;
03738    case AGI_RESULT_FAILURE:
03739       pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03740       break;
03741    case AGI_RESULT_NOTFOUND:
03742       pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03743       break;
03744    case AGI_RESULT_HANGUP:
03745       pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03746       return -1;
03747    }
03748 
03749    return 0;
03750 }

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

Definition at line 3249 of file res_agi.c.

References ast_agi_send(), ast_cdr_setapp(), ast_check_hangup(), ast_module_ref(), ast_module_unref(), ast_random(), ast_strdupa, ast_strlen_zero(), 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().

03250 {
03251    const char *argv[MAX_ARGS];
03252    int argc = MAX_ARGS, res;
03253    agi_command *c;
03254    const char *ami_res = "Unknown Result";
03255    char *ami_cmd = ast_strdupa(buf);
03256    int command_id = ast_random(), resultcode = 200;
03257 
03258    manager_event(EVENT_FLAG_AGI, "AGIExec",
03259          "SubEvent: Start\r\n"
03260          "Channel: %s\r\n"
03261          "CommandId: %d\r\n"
03262          "Command: %s\r\n", chan->name, command_id, ami_cmd);
03263    parse_args(buf, &argc, argv);
03264    if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
03265       /* if this command wasnt registered by res_agi, be sure to usecount
03266       the module we are using */
03267       if (c->mod != ast_module_info->self)
03268          ast_module_ref(c->mod);
03269       /* If the AGI command being executed is an actual application (using agi exec)
03270       the app field will be updated in pbx_exec via handle_exec */
03271       if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
03272          ast_cdr_setapp(chan->cdr, "AGI", buf);
03273 
03274       res = c->handler(chan, agi, argc, argv);
03275       if (c->mod != ast_module_info->self)
03276          ast_module_unref(c->mod);
03277       switch (res) {
03278       case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
03279       case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
03280       case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
03281       }
03282       manager_event(EVENT_FLAG_AGI, "AGIExec",
03283             "SubEvent: End\r\n"
03284             "Channel: %s\r\n"
03285             "CommandId: %d\r\n"
03286             "Command: %s\r\n"
03287             "ResultCode: %d\r\n"
03288             "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
03289       switch(res) {
03290       case RESULT_SHOWUSAGE:
03291          if (ast_strlen_zero(c->usage)) {
03292             ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
03293          } else {
03294             ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
03295             ast_agi_send(agi->fd, chan, "%s", c->usage);
03296             ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
03297          }
03298          break;
03299       case RESULT_FAILURE:
03300          /* They've already given the failure.  We've been hung up on so handle this
03301             appropriately */
03302          return -1;
03303       }
03304    } else if ((c = find_command(argv, 0))) {
03305       ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
03306       manager_event(EVENT_FLAG_AGI, "AGIExec",
03307             "SubEvent: End\r\n"
03308             "Channel: %s\r\n"
03309             "CommandId: %d\r\n"
03310             "Command: %s\r\n"
03311             "ResultCode: 511\r\n"
03312             "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
03313    } else {
03314       ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
03315       manager_event(EVENT_FLAG_AGI, "AGIExec",
03316             "SubEvent: End\r\n"
03317             "Channel: %s\r\n"
03318             "CommandId: %d\r\n"
03319             "Command: %s\r\n"
03320             "ResultCode: 510\r\n"
03321             "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
03322    }
03323    return 0;
03324 }

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

03018 {
03019    char fullcmd[MAX_CMD_LEN];
03020 
03021    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03022 
03023    if (!find_command(cmd->cmda, 1)) {
03024       *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
03025       if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
03026 #ifdef AST_XML_DOCS
03027          *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd);
03028          *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd);
03029          *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd);
03030          *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd);
03031          *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
03032 #endif
03033 #ifndef HAVE_NULLSAFE_PRINTF
03034          if (!cmd->summary) {
03035             *((char **) &cmd->summary) = ast_strdup("");
03036          }
03037          if (!cmd->usage) {
03038             *((char **) &cmd->usage) = ast_strdup("");
03039          }
03040          if (!cmd->syntax) {
03041             *((char **) &cmd->syntax) = ast_strdup("");
03042          }
03043          if (!cmd->seealso) {
03044             *((char **) &cmd->seealso) = ast_strdup("");
03045          }
03046 #endif
03047       }
03048 
03049       cmd->mod = mod;
03050       AST_RWLIST_WRLOCK(&agi_commands);
03051       AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
03052       AST_RWLIST_UNLOCK(&agi_commands);
03053       if (mod != ast_module_info->self)
03054          ast_module_ref(ast_module_info->self);
03055       ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
03056       return 1;
03057    } else {
03058       ast_log(LOG_WARNING, "Command already registered!\n");
03059       return 0;
03060    }
03061 }

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

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

Referenced by load_module().

03103 {
03104    unsigned int i, x = 0;
03105 
03106    for (i = 0; i < len; i++) {
03107       if (ast_agi_register(mod, cmd + i) == 1) {
03108          x++;
03109          continue;
03110       }
03111 
03112       /* registration failed, unregister everything
03113          that had been registered up to that point
03114       */
03115       for (; x > 0; x--) {
03116          /* we are intentionally ignoring the
03117             result of ast_agi_unregister() here,
03118             but it should be safe to do so since
03119             we just registered these commands and
03120             the only possible way for unregistration
03121             to fail is if the command is not
03122             registered
03123          */
03124          (void) ast_agi_unregister(mod, cmd + x - 1);
03125       }
03126       return -1;
03127    }
03128 
03129    return 0;
03130 }

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 933 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(), and setup_env().

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

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

03064 {
03065    struct agi_command *e;
03066    int unregistered = 0;
03067    char fullcmd[MAX_CMD_LEN];
03068 
03069    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03070 
03071    AST_RWLIST_WRLOCK(&agi_commands);
03072    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
03073       if (cmd == e) {
03074          AST_RWLIST_REMOVE_CURRENT(list);
03075          if (mod != ast_module_info->self)
03076             ast_module_unref(ast_module_info->self);
03077 #ifdef AST_XML_DOCS
03078          if (e->docsrc == AST_XML_DOC) {
03079             ast_free((char *) e->summary);
03080             ast_free((char *) e->usage);
03081             ast_free((char *) e->syntax);
03082             ast_free((char *) e->seealso);
03083             *((char **) &e->summary) = NULL;
03084             *((char **) &e->usage) = NULL;
03085             *((char **) &e->syntax) = NULL;
03086             *((char **) &e->seealso) = NULL;
03087          }
03088 #endif
03089          unregistered=1;
03090          break;
03091       }
03092    }
03093    AST_RWLIST_TRAVERSE_SAFE_END;
03094    AST_RWLIST_UNLOCK(&agi_commands);
03095    if (unregistered)
03096       ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
03097    else
03098       ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
03099    return unregistered;
03100 }

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

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

Referenced by unload_module().

03133 {
03134    unsigned int i;
03135    int res = 0;
03136 
03137    for (i = 0; i < len; i++) {
03138       /* remember whether any of the unregistration
03139          attempts failed... there is no recourse if
03140          any of them do
03141       */
03142       res |= ast_agi_unregister(mod, cmd + i);
03143    }
03144 
03145    return res;
03146 }

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

Definition at line 3782 of file res_agi.c.

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

Referenced by load_module().

03783 {
03784    ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03785    return agi_exec(chan, data);
03786 }

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

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

03761 {
03762    int readformat, res;
03763 
03764    if (ast_check_hangup(chan)) {
03765       ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03766       return 0;
03767    }
03768    readformat = chan->readformat;
03769    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03770       ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03771       return -1;
03772    }
03773    res = agi_exec_full(chan, data, 1, 0);
03774    if (!res) {
03775       if (ast_set_read_format(chan, readformat)) {
03776          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03777       }
03778    }
03779    return res;
03780 }

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

Definition at line 3148 of file res_agi.c.

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

03149 {
03150    int y, match;
03151    struct agi_command *e;
03152 
03153    AST_RWLIST_RDLOCK(&agi_commands);
03154    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03155       if (!e->cmda[0])
03156          break;
03157       /* start optimistic */
03158       match = 1;
03159       for (y = 0; match && cmds[y]; y++) {
03160          /* If there are no more words in the command (and we're looking for
03161             an exact match) or there is a difference between the two words,
03162             then this is not a match */
03163          if (!e->cmda[y] && !exact)
03164             break;
03165          /* don't segfault if the next part of a command doesn't exist */
03166          if (!e->cmda[y]) {
03167             AST_RWLIST_UNLOCK(&agi_commands);
03168             return NULL;
03169          }
03170          if (strcasecmp(e->cmda[y], cmds[y]))
03171             match = 0;
03172       }
03173       /* If more words are needed to complete the command then this is not
03174          a candidate (unless we're looking for a really inexact answer  */
03175       if ((exact > -1) && e->cmda[y])
03176          match = 0;
03177       if (match) {
03178          AST_RWLIST_UNLOCK(&agi_commands);
03179          return e;
03180       }
03181    }
03182    AST_RWLIST_UNLOCK(&agi_commands);
03183    return NULL;
03184 }

static void free_agi_cmd ( struct agi_cmd cmd  )  [static]

Definition at line 969 of file res_agi.c.

References ast_free.

Referenced by agi_destroy_commands_cb(), and launch_asyncagi().

00970 {
00971    ast_free(cmd->cmd_buffer);
00972    ast_free(cmd->cmd_id);
00973    ast_free(cmd);
00974 }

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

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

00997 {
00998    struct ast_datastore *store;
00999    struct agi_cmd *cmd;
01000    AST_LIST_HEAD(, agi_cmd) *agi_commands;
01001 
01002    ast_channel_lock(chan);
01003    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01004    ast_channel_unlock(chan);
01005    if (!store) {
01006       ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
01007       return NULL;
01008    }
01009    agi_commands = store->data;
01010    AST_LIST_LOCK(agi_commands);
01011    cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
01012    AST_LIST_UNLOCK(agi_commands);
01013    return cmd;
01014 }

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

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

01662 {
01663    int res = 0;
01664 
01665    /* Answer the channel */
01666    if (chan->_state != AST_STATE_UP)
01667       res = ast_answer(chan);
01668 
01669    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01670    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01671 }

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

Definition at line 1673 of file res_agi.c.

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

01674 {
01675    ast_agi_send(agi->fd, chan, "200 result=0\n");
01676    return RESULT_FAILURE;
01677 }

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

Definition at line 2311 of file res_agi.c.

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

02312 {
02313    double timeout;
02314    struct timeval whentohangup = { 0, 0 };
02315 
02316    if (argc != 3)
02317       return RESULT_SHOWUSAGE;
02318    if (sscanf(argv[2], "%30lf", &timeout) != 1)
02319       return RESULT_SHOWUSAGE;
02320    if (timeout < 0)
02321       timeout = 0;
02322    if (timeout) {
02323       whentohangup.tv_sec = timeout;
02324       whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
02325    }
02326    ast_channel_setwhentohangup_tv(chan, whentohangup);
02327    ast_agi_send(agi->fd, chan, "200 result=0\n");
02328    return RESULT_SUCCESS;
02329 }

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

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

02429 {
02430    struct ast_channel *c;
02431    if (argc == 2) {
02432       /* no argument: supply info on the current channel */
02433       ast_agi_send(agi->fd, chan, "200 result=%d\n", chan->_state);
02434       return RESULT_SUCCESS;
02435    } else if (argc == 3) {
02436       /* one argument: look for info on the specified channel */
02437       if ((c = ast_channel_get_by_name(argv[2]))) {
02438          ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state);
02439          c = ast_channel_unref(c);
02440          return RESULT_SUCCESS;
02441       }
02442       /* if we get this far no channel name matched the argument given */
02443       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02444       return RESULT_SUCCESS;
02445    } else {
02446       return RESULT_SHOWUSAGE;
02447    }
02448 }

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

References add_agi_cmd(), ast_cli_args::argc, ast_cli_args::argv, ast_channel_get_by_name(), ast_channel_unlock, ast_channel_unref, ast_complete_channels(), ast_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::line, LOG_DEBUG, LOG_WARNING, ast_cli_args::n, ast_channel::name, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01095 {
01096    struct ast_channel *chan;
01097    switch (cmd) {
01098    case CLI_INIT:
01099       e->command = "agi exec";
01100       e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
01101             "       Add AGI command to the execute queue of the specified channel in Async AGI\n";
01102       return NULL;
01103    case CLI_GENERATE:
01104       if (a->pos == 2)
01105          return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
01106       return NULL;
01107    }
01108 
01109    if (a->argc < 4) {
01110       return CLI_SHOWUSAGE;
01111    }
01112 
01113    if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
01114       ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
01115       return CLI_FAILURE;
01116    }
01117 
01118    if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
01119       ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
01120       ast_channel_unlock(chan);
01121       chan = ast_channel_unref(chan);
01122       return CLI_FAILURE;
01123    }
01124 
01125    ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
01126 
01127    ast_channel_unlock(chan);
01128    chan = ast_channel_unref(chan);
01129 
01130    return CLI_SUCCESS;
01131 }

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

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

02604 {
02605    switch (cmd) {
02606    case CLI_INIT:
02607       e->command = "agi set debug [on|off]";
02608       e->usage =
02609          "Usage: agi set debug [on|off]\n"
02610          "       Enables/disables dumping of AGI transactions for\n"
02611          "       debugging purposes.\n";
02612       return NULL;
02613 
02614    case CLI_GENERATE:
02615       return NULL;
02616    }
02617 
02618    if (a->argc != e->args)
02619       return CLI_SHOWUSAGE;
02620 
02621    if (strncasecmp(a->argv[3], "off", 3) == 0) {
02622       agidebug = 0;
02623    } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
02624       agidebug = 1;
02625    } else {
02626       return CLI_SHOWUSAGE;
02627    }
02628    ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
02629    return CLI_SUCCESS;
02630 }

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

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

03662 {
03663    switch (cmd) {
03664    case CLI_INIT:
03665       e->command = "agi dump html";
03666       e->usage =
03667          "Usage: agi dump html <filename>\n"
03668          "       Dumps the AGI command list in HTML format to the given\n"
03669          "       file.\n";
03670       return NULL;
03671    case CLI_GENERATE:
03672       return NULL;
03673    }
03674    if (a->argc != e->args + 1)
03675       return CLI_SHOWUSAGE;
03676 
03677    if (write_htmldump(a->argv[e->args]) < 0) {
03678       ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03679       return CLI_SHOWUSAGE;
03680    }
03681    ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03682    return CLI_SUCCESS;
03683 }

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

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

03469 {
03470    struct agi_command *command;
03471    char fullcmd[MAX_CMD_LEN];
03472    int error = 0;
03473 
03474    switch (cmd) {
03475    case CLI_INIT:
03476       e->command = "agi show commands [topic]";
03477       e->usage =
03478          "Usage: agi show commands [topic] <topic>\n"
03479          "       When called with a topic as an argument, displays usage\n"
03480          "       information on the given command.  If called without a\n"
03481          "       topic, it provides a list of AGI commands.\n";
03482    case CLI_GENERATE:
03483       return NULL;
03484    }
03485    if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03486       return CLI_SHOWUSAGE;
03487    if (a->argc > e->args - 1) {
03488       command = find_command(a->argv + e->args, 1);
03489       if (command) {
03490          char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03491          char info[30 + MAX_CMD_LEN];              /* '-= Info about...' */
03492          char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];  /* '-= Info about...' with colors */
03493          char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03494          char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Description]\n with colors */
03495          char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Runs Dead]\n with colors */
03496          char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];      /* 'Yes' or 'No' with colors */
03497          char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];    /* [See Also]\n with colors */
03498          char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03499          size_t synlen, desclen, seealsolen, stxlen;
03500 
03501          term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03502          term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03503          term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03504          term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03505          term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03506          term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03507 
03508          ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03509          snprintf(info, sizeof(info), "\n  -= Info about agi '%s' =- ", fullcmd);
03510          term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03511 #ifdef AST_XML_DOCS
03512          if (command->docsrc == AST_XML_DOC) {
03513             synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03514             description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03515             seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03516             if (!seealso || !description || !synopsis) {
03517                error = 1;
03518                goto return_cleanup;
03519             }
03520          } else
03521 #endif
03522          {
03523             synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03524             synopsis = ast_malloc(synlen);
03525 
03526             desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03527             description = ast_malloc(desclen);
03528 
03529             seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03530             seealso = ast_malloc(seealsolen);
03531 
03532             if (!synopsis || !description || !seealso) {
03533                error = 1;
03534                goto return_cleanup;
03535             }
03536             term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03537             term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03538             term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03539          }
03540 
03541          stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03542          syntax = ast_malloc(stxlen);
03543          if (!syntax) {
03544             error = 1;
03545             goto return_cleanup;
03546          }
03547          term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03548 
03549          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,
03550                desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03551                seealsotitle, seealso);
03552 return_cleanup:
03553          ast_free(synopsis);
03554          ast_free(description);
03555          ast_free(syntax);
03556          ast_free(seealso);
03557       } else {
03558          if (find_command(a->argv + e->args, -1)) {
03559             return help_workhorse(a->fd, a->argv + e->args);
03560          } else {
03561             ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03562             ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03563          }
03564       }
03565    } else {
03566       return help_workhorse(a->fd, NULL);
03567    }
03568    return (error ? CLI_FAILURE : CLI_SUCCESS);
03569 }

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

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

01792 {
01793    int res = 0, skipms = 3000;
01794    const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
01795 
01796    if (argc < 5 || argc > 9) {
01797       return RESULT_SHOWUSAGE;
01798    }
01799 
01800    if (!ast_strlen_zero(argv[4])) {
01801       stop = argv[4];
01802    }
01803 
01804    if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
01805       return RESULT_SHOWUSAGE;
01806    }
01807 
01808    if (argc > 6 && !ast_strlen_zero(argv[6])) {
01809       fwd = argv[6];
01810    }
01811 
01812    if (argc > 7 && !ast_strlen_zero(argv[7])) {
01813       rev = argv[7];
01814    }
01815 
01816    if (argc > 8 && !ast_strlen_zero(argv[8])) {
01817       suspend = argv[8];
01818    }
01819 
01820    res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
01821 
01822    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01823 
01824    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01825 }

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

Definition at line 2577 of file res_agi.c.

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

02578 {
02579    int res;
02580 
02581    if (argc != 4)
02582       return RESULT_SHOWUSAGE;
02583    res = ast_db_del(argv[2], argv[3]);
02584    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02585    return RESULT_SUCCESS;
02586 }

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

Definition at line 2588 of file res_agi.c.

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

02589 {
02590    int res;
02591 
02592    if ((argc < 3) || (argc > 4))
02593       return RESULT_SHOWUSAGE;
02594    if (argc == 4)
02595       res = ast_db_deltree(argv[2], argv[3]);
02596    else
02597       res = ast_db_deltree(argv[2], NULL);
02598 
02599    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02600    return RESULT_SUCCESS;
02601 }

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

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

02534 {
02535    int res;
02536    struct ast_str *buf;
02537 
02538    if (argc != 4)
02539       return RESULT_SHOWUSAGE;
02540 
02541    if (!(buf = ast_str_create(16))) {
02542       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02543       return RESULT_SUCCESS;
02544    }
02545 
02546    do {
02547       res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
02548       ast_str_update(buf);
02549       if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
02550          break;
02551       }
02552       if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
02553          break;
02554       }
02555    } while (1);
02556    
02557    if (res)
02558       ast_agi_send(agi->fd, chan, "200 result=0\n");
02559    else
02560       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
02561 
02562    ast_free(buf);
02563    return RESULT_SUCCESS;
02564 }

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

Definition at line 2566 of file res_agi.c.

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

02567 {
02568    int res;
02569 
02570    if (argc != 5)
02571       return RESULT_SHOWUSAGE;
02572    res = ast_db_put(argv[2], argv[3], argv[4]);
02573    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02574    return RESULT_SUCCESS;
02575 }

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

Definition at line 2359 of file res_agi.c.

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

02360 {
02361    int res, workaround;
02362    struct ast_app *app_to_exec;
02363 
02364    if (argc < 2)
02365       return RESULT_SHOWUSAGE;
02366 
02367    ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
02368 
02369    if ((app_to_exec = pbx_findapp(argv[1]))) {
02370       if(!strcasecmp(argv[1], PARK_APP_NAME)) {
02371          ast_masq_park_call(chan, NULL, 0, NULL);
02372       }
02373       if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
02374          ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02375       }
02376       if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
02377          char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr;
02378          const char *vptr;
02379          for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
02380             if (*vptr == ',') {
02381                *cptr++ = '\\';
02382                *cptr++ = ',';
02383             } else if (*vptr == '|') {
02384                *cptr++ = ',';
02385             } else {
02386                *cptr++ = *vptr;
02387             }
02388          }
02389          *cptr = '\0';
02390          res = pbx_exec(chan, app_to_exec, compat);
02391       } else {
02392          res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
02393       }
02394       if (!workaround) {
02395          ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02396       }
02397    } else {
02398       ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
02399       res = -2;
02400    }
02401    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02402 
02403    /* Even though this is wrong, users are depending upon this result. */
02404    return res;
02405 }

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

Definition at line 2069 of file res_agi.c.

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

02070 {
02071    int res, max, timeout;
02072    char data[1024];
02073 
02074    if (argc < 3)
02075       return RESULT_SHOWUSAGE;
02076    if (argc >= 4)
02077       timeout = atoi(argv[3]);
02078    else
02079       timeout = 0;
02080    if (argc >= 5)
02081       max = atoi(argv[4]);
02082    else
02083       max = 1024;
02084    res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
02085    if (res == 2)        /* New command */
02086       return RESULT_SUCCESS;
02087    else if (res == 1)
02088       ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
02089    else if (res < 0 )
02090       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02091    else
02092       ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
02093    return RESULT_SUCCESS;
02094 }

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 1877 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, ast_channel::stream, and ast_filestream::vfs.

01878 {
01879    int res, vres;
01880    struct ast_filestream *fs, *vfs;
01881    long sample_offset = 0, max_length;
01882    int timeout = 0;
01883    const char *edigits = "";
01884 
01885    if ( argc < 4 || argc > 5 )
01886       return RESULT_SHOWUSAGE;
01887 
01888    if ( argv[3] )
01889       edigits = argv[3];
01890 
01891    if ( argc == 5 )
01892       timeout = atoi(argv[4]);
01893    else if (chan->pbx->dtimeoutms) {
01894       /* by default dtimeout is set to 5sec */
01895       timeout = chan->pbx->dtimeoutms; /* in msec */
01896    }
01897 
01898    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01899       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01900       ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
01901       return RESULT_SUCCESS;
01902    }
01903 
01904    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01905       ast_debug(1, "Ooh, found a video stream, too\n");
01906 
01907    ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
01908 
01909    ast_seekstream(fs, 0, SEEK_END);
01910    max_length = ast_tellstream(fs);
01911    ast_seekstream(fs, sample_offset, SEEK_SET);
01912    res = ast_applystream(chan, fs);
01913    if (vfs)
01914       vres = ast_applystream(chan, vfs);
01915    ast_playstream(fs);
01916    if (vfs)
01917       ast_playstream(vfs);
01918 
01919    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01920    /* this is to check for if ast_waitstream closed the stream, we probably are at
01921     * the end of the stream, return that amount, else check for the amount */
01922    sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
01923    ast_stopstream(chan);
01924    if (res == 1) {
01925       /* Stop this command, don't print a result line, as there is a new command */
01926       return RESULT_SUCCESS;
01927    }
01928 
01929    /* If the user didnt press a key, wait for digitTimeout*/
01930    if (res == 0 ) {
01931       res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
01932       /* Make sure the new result is in the escape digits of the GET OPTION */
01933       if ( !strchr(edigits,res) )
01934          res=0;
01935    }
01936 
01937    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01938    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01939 }

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

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

02460 {
02461    char *ret;
02462    char tempstr[1024];
02463 
02464    if (argc != 3)
02465       return RESULT_SHOWUSAGE;
02466 
02467    /* check if we want to execute an ast_custom_function */
02468    if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
02469       ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
02470    } else {
02471       pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
02472    }
02473 
02474    if (ret)
02475       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
02476    else
02477       ast_agi_send(agi->fd, chan, "200 result=0\n");
02478 
02479    return RESULT_SUCCESS;
02480 }

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

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

02483 {
02484    struct ast_channel *chan2 = NULL;
02485 
02486    if (argc != 4 && argc != 5) {
02487       return RESULT_SHOWUSAGE;
02488    }
02489 
02490    if (argc == 5) {
02491       chan2 = ast_channel_get_by_name(argv[4]);
02492    } else {
02493       chan2 = ast_channel_ref(chan);
02494    }
02495 
02496    if (chan2) {
02497       struct ast_str *str = ast_str_create(16);
02498       if (!str) {
02499          ast_agi_send(agi->fd, chan, "200 result=0\n");
02500          return RESULT_SUCCESS;
02501       }
02502       ast_str_substitute_variables(&str, 0, chan2, argv[3]);
02503       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
02504       ast_free(str);
02505    } else {
02506       ast_agi_send(agi->fd, chan, "200 result=0\n");
02507    }
02508 
02509    if (chan2) {
02510       chan2 = ast_channel_unref(chan2);
02511    }
02512 
02513    return RESULT_SUCCESS;
02514 }

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

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

02332 {
02333    struct ast_channel *c;
02334 
02335    if (argc == 1) {
02336       /* no argument: hangup the current channel */
02337       ast_set_hangupsource(chan, "dialplan/agi", 0);
02338       ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
02339       ast_agi_send(agi->fd, chan, "200 result=1\n");
02340       return RESULT_SUCCESS;
02341    } else if (argc == 2) {
02342       /* one argument: look for info on the specified channel */
02343       if ((c = ast_channel_get_by_name(argv[1]))) {
02344          /* we have a matching channel */
02345          ast_set_hangupsource(c, "dialplan/agi", 0);
02346          ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
02347          c = ast_channel_unref(c);
02348          ast_agi_send(agi->fd, chan, "200 result=1\n");
02349          return RESULT_SUCCESS;
02350       }
02351       /* if we get this far no channel name matched the argument given */
02352       ast_agi_send(agi->fd, chan, "200 result=-1\n");
02353       return RESULT_SUCCESS;
02354    } else {
02355       return RESULT_SHOWUSAGE;
02356    }
02357 }

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

Definition at line 2632 of file res_agi.c.

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

02633 {
02634    ast_agi_send(agi->fd, chan, "200 result=0\n");
02635    return RESULT_SUCCESS;
02636 }

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

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

02135 {
02136    struct ast_filestream *fs;
02137    struct ast_frame *f;
02138    struct timeval start;
02139    long sample_offset = 0;
02140    int res = 0;
02141    int ms;
02142 
02143    struct ast_dsp *sildet=NULL;         /* silence detector dsp */
02144    int totalsilence = 0;
02145    int dspsilence = 0;
02146    int silence = 0;                /* amount of silence to allow */
02147    int gotsilence = 0;             /* did we timeout for silence? */
02148    char *silencestr = NULL;
02149    int rfmt = 0;
02150 
02151    /* XXX EAGI FIXME XXX */
02152 
02153    if (argc < 6)
02154       return RESULT_SHOWUSAGE;
02155    if (sscanf(argv[5], "%30d", &ms) != 1)
02156       return RESULT_SHOWUSAGE;
02157 
02158    if (argc > 6)
02159       silencestr = strchr(argv[6],'s');
02160    if ((argc > 7) && (!silencestr))
02161       silencestr = strchr(argv[7],'s');
02162    if ((argc > 8) && (!silencestr))
02163       silencestr = strchr(argv[8],'s');
02164 
02165    if (silencestr) {
02166       if (strlen(silencestr) > 2) {
02167          if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
02168             silencestr++;
02169             silencestr++;
02170             if (silencestr)
02171                silence = atoi(silencestr);
02172             if (silence > 0)
02173                silence *= 1000;
02174          }
02175       }
02176    }
02177 
02178    if (silence > 0) {
02179       rfmt = chan->readformat;
02180       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
02181       if (res < 0) {
02182          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
02183          return -1;
02184       }
02185       sildet = ast_dsp_new();
02186       if (!sildet) {
02187          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
02188          return -1;
02189       }
02190       ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
02191    }
02192    
02193    /* backward compatibility, if no offset given, arg[6] would have been
02194     * caught below and taken to be a beep, else if it is a digit then it is a
02195     * offset */
02196    if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
02197       res = ast_streamfile(chan, "beep", chan->language);
02198 
02199    if ((argc > 7) && (!strchr(argv[7], '=')))
02200       res = ast_streamfile(chan, "beep", chan->language);
02201 
02202    if (!res)
02203       res = ast_waitstream(chan, argv[4]);
02204    if (res) {
02205       ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
02206    } else {
02207       fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
02208       if (!fs) {
02209          res = -1;
02210          ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
02211          if (sildet)
02212             ast_dsp_free(sildet);
02213          return RESULT_FAILURE;
02214       }
02215 
02216       /* Request a video update */
02217       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
02218 
02219       chan->stream = fs;
02220       ast_applystream(chan,fs);
02221       /* really should have checks */
02222       ast_seekstream(fs, sample_offset, SEEK_SET);
02223       ast_truncstream(fs);
02224 
02225       start = ast_tvnow();
02226       while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
02227          res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
02228          if (res < 0) {
02229             ast_closestream(fs);
02230             ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
02231             if (sildet)
02232                ast_dsp_free(sildet);
02233             return RESULT_FAILURE;
02234          }
02235          f = ast_read(chan);
02236          if (!f) {
02237             ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
02238             ast_closestream(fs);
02239             if (sildet)
02240                ast_dsp_free(sildet);
02241             return RESULT_FAILURE;
02242          }
02243          switch(f->frametype) {
02244          case AST_FRAME_DTMF:
02245             if (strchr(argv[4], f->subclass.integer)) {
02246                /* This is an interrupting chracter, so rewind to chop off any small
02247                   amount of DTMF that may have been recorded
02248                */
02249                ast_stream_rewind(fs, 200);
02250                ast_truncstream(fs);
02251                sample_offset = ast_tellstream(fs);
02252                ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
02253                ast_closestream(fs);
02254                ast_frfree(f);
02255                if (sildet)
02256                   ast_dsp_free(sildet);
02257                return RESULT_SUCCESS;
02258             }
02259             break;
02260          case AST_FRAME_VOICE:
02261             ast_writestream(fs, f);
02262             /* this is a safe place to check progress since we know that fs
02263              * is valid after a write, and it will then have our current
02264              * location */
02265             sample_offset = ast_tellstream(fs);
02266             if (silence > 0) {
02267                dspsilence = 0;
02268                ast_dsp_silence(sildet, f, &dspsilence);
02269                if (dspsilence) {
02270                   totalsilence = dspsilence;
02271                } else {
02272                   totalsilence = 0;
02273                }
02274                if (totalsilence > silence) {
02275                   /* Ended happily with silence */
02276                   gotsilence = 1;
02277                   break;
02278                }
02279             }
02280             break;
02281          case AST_FRAME_VIDEO:
02282             ast_writestream(fs, f);
02283          default:
02284             /* Ignore all other frames */
02285             break;
02286          }
02287          ast_frfree(f);
02288          if (gotsilence)
02289             break;
02290       }
02291 
02292       if (gotsilence) {
02293          ast_stream_rewind(fs, silence-1000);
02294          ast_truncstream(fs);
02295          sample_offset = ast_tellstream(fs);
02296       }
02297       ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
02298       ast_closestream(fs);
02299    }
02300 
02301    if (silence > 0) {
02302       res = ast_set_read_format(chan, rfmt);
02303       if (res)
02304          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
02305       ast_dsp_free(sildet);
02306    }
02307 
02308    return RESULT_SUCCESS;
02309 }

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

Definition at line 1711 of file res_agi.c.

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

01712 {
01713    int res;
01714 
01715    if (argc != 3)
01716       return RESULT_SHOWUSAGE;
01717 
01718    res = ast_recvchar(chan,atoi(argv[2]));
01719    if (res == 0) {
01720       ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
01721       return RESULT_SUCCESS;
01722    }
01723    if (res > 0) {
01724       ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01725       return RESULT_SUCCESS;
01726    }
01727    ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
01728    return RESULT_FAILURE;
01729 }

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

Definition at line 1731 of file res_agi.c.

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

01732 {
01733    char *buf;
01734 
01735    if (argc != 3)
01736       return RESULT_SHOWUSAGE;
01737 
01738    buf = ast_recvtext(chan, atoi(argv[2]));
01739    if (buf) {
01740       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
01741       ast_free(buf);
01742    } else {
01743       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01744    }
01745    return RESULT_SUCCESS;
01746 }

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

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

01978 {
01979    int res;
01980 
01981    if (argc != 4)
01982       return RESULT_SHOWUSAGE;
01983 
01984    res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01985    if (res == 1) /* New command */
01986       return RESULT_SUCCESS;
01987    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01988    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01989 }

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

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

01992 {
01993    int res, num;
01994 
01995    if (argc != 4)
01996       return RESULT_SHOWUSAGE;
01997    if (sscanf(argv[2], "%30d", &num) != 1)
01998       return RESULT_SHOWUSAGE;
01999    res = ast_say_date(chan, num, argv[3], chan->language);
02000    if (res == 1)
02001       return RESULT_SUCCESS;
02002    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02003    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02004 }

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

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

02022 {
02023    int res = 0;
02024    time_t unixtime;
02025    const char *format, *zone = NULL;
02026 
02027    if (argc < 4)
02028       return RESULT_SHOWUSAGE;
02029 
02030    if (argc > 4) {
02031       format = argv[4];
02032    } else {
02033       /* XXX this doesn't belong here, but in the 'say' module */
02034       if (!strcasecmp(chan->language, "de")) {
02035          format = "A dBY HMS";
02036       } else {
02037          format = "ABdY 'digits/at' IMp";
02038       }
02039    }
02040 
02041    if (argc > 5 && !ast_strlen_zero(argv[5]))
02042       zone = argv[5];
02043 
02044    if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
02045       return RESULT_SHOWUSAGE;
02046 
02047    res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
02048    if (res == 1)
02049       return RESULT_SUCCESS;
02050 
02051    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02052    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02053 }

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

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

01962 {
01963    int res, num;
01964 
01965    if (argc != 4)
01966       return RESULT_SHOWUSAGE;
01967    if (sscanf(argv[2], "%30d", &num) != 1)
01968       return RESULT_SHOWUSAGE;
01969 
01970    res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01971    if (res == 1) /* New command */
01972       return RESULT_SUCCESS;
01973    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01974    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01975 }

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

01947 {
01948    int res, num;
01949 
01950    if (argc < 4 || argc > 5)
01951       return RESULT_SHOWUSAGE;
01952    if (sscanf(argv[2], "%30d", &num) != 1)
01953       return RESULT_SHOWUSAGE;
01954    res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
01955    if (res == 1)
01956       return RESULT_SUCCESS;
01957    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01958    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01959 }

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

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

02056 {
02057    int res;
02058 
02059    if (argc != 4)
02060       return RESULT_SHOWUSAGE;
02061 
02062    res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02063    if (res == 1) /* New command */
02064       return RESULT_SUCCESS;
02065    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02066    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02067 }

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

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

02007 {
02008    int res, num;
02009 
02010    if (argc != 4)
02011       return RESULT_SHOWUSAGE;
02012    if (sscanf(argv[2], "%30d", &num) != 1)
02013       return RESULT_SHOWUSAGE;
02014    res = ast_say_time(chan, num, argv[3], chan->language);
02015    if (res == 1)
02016       return RESULT_SUCCESS;
02017    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02018    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02019 }

static int handle_sendimage ( 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(), ast_check_hangup(), ast_send_image(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01776 {
01777    int res;
01778 
01779    if (argc != 3) {
01780       return RESULT_SHOWUSAGE;
01781    }
01782 
01783    res = ast_send_image(chan, argv[2]);
01784    if (!ast_check_hangup(chan)) {
01785       res = 0;
01786    }
01787    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01788    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01789 }

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

Definition at line 1692 of file res_agi.c.

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

01693 {
01694    int res;
01695 
01696    if (argc != 3)
01697       return RESULT_SHOWUSAGE;
01698 
01699    /* At the moment, the parser (perhaps broken) returns with
01700       the last argument PLUS the newline at the end of the input
01701       buffer. This probably needs to be fixed, but I wont do that
01702       because other stuff may break as a result. The right way
01703       would probably be to strip off the trailing newline before
01704       parsing, then here, add a newline at the end of the string
01705       before sending it to ast_sendtext --DUDE */
01706    res = ast_sendtext(chan, argv[2]);
01707    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01708    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01709 }

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

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

02408 {
02409    char tmp[256]="";
02410    char *l = NULL, *n = NULL;
02411 
02412    if (argv[2]) {
02413       ast_copy_string(tmp, argv[2], sizeof(tmp));
02414       ast_callerid_parse(tmp, &n, &l);
02415       if (l)
02416          ast_shrink_phone_number(l);
02417       else
02418          l = "";
02419       if (!n)
02420          n = "";
02421       ast_set_callerid(chan, l, n, NULL);
02422    }
02423 
02424    ast_agi_send(agi->fd, chan, "200 result=1\n");
02425    return RESULT_SUCCESS;
02426 }

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

Definition at line 2096 of file res_agi.c.

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

02097 {
02098 
02099    if (argc != 3)
02100       return RESULT_SHOWUSAGE;
02101    ast_copy_string(chan->context, argv[2], sizeof(chan->context));
02102    ast_agi_send(agi->fd, chan, "200 result=0\n");
02103    return RESULT_SUCCESS;
02104 }

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

Definition at line 2106 of file res_agi.c.

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

02107 {
02108    if (argc != 3)
02109       return RESULT_SHOWUSAGE;
02110    ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
02111    ast_agi_send(agi->fd, chan, "200 result=0\n");
02112    return RESULT_SUCCESS;
02113 }

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

Definition at line 2638 of file res_agi.c.

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

02639 {
02640    if (argc < 3) {
02641       return RESULT_SHOWUSAGE;
02642    }
02643    if (!strncasecmp(argv[2], "on", 2))
02644       ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
02645    else if (!strncasecmp(argv[2], "off", 3))
02646       ast_moh_stop(chan);
02647    ast_agi_send(agi->fd, chan, "200 result=0\n");
02648    return RESULT_SUCCESS;
02649 }

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

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

02116 {
02117    int pri;
02118 
02119    if (argc != 3)
02120       return RESULT_SHOWUSAGE;
02121 
02122    if (sscanf(argv[2], "%30d", &pri) != 1) {
02123       pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2],
02124          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
02125       if (pri < 1)
02126          return RESULT_SHOWUSAGE;
02127    }
02128 
02129    ast_explicit_goto(chan, NULL, NULL, pri);
02130    ast_agi_send(agi->fd, chan, "200 result=0\n");
02131    return RESULT_SUCCESS;
02132 }

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

Definition at line 2450 of file res_agi.c.

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

02451 {
02452    if (argv[3])
02453       pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
02454 
02455    ast_agi_send(agi->fd, chan, "200 result=1\n");
02456    return RESULT_SUCCESS;
02457 }

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

Definition at line 2734 of file res_agi.c.

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

02735 {
02736    if (argc != 4)
02737       return RESULT_SHOWUSAGE;
02738 
02739    if (!agi->speech) {
02740       ast_agi_send(agi->fd, chan, "200 result=0\n");
02741       return RESULT_SUCCESS;
02742    }
02743 
02744    if (ast_speech_grammar_activate(agi->speech, argv[3]))
02745       ast_agi_send(agi->fd, chan, "200 result=0\n");
02746    else
02747       ast_agi_send(agi->fd, chan, "200 result=1\n");
02748 
02749    return RESULT_SUCCESS;
02750 }

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

Definition at line 2651 of file res_agi.c.

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

02652 {
02653    /* If a structure already exists, return an error */
02654         if (agi->speech) {
02655       ast_agi_send(agi->fd, chan, "200 result=0\n");
02656       return RESULT_SUCCESS;
02657    }
02658 
02659    if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02660       ast_agi_send(agi->fd, chan, "200 result=1\n");
02661    else
02662       ast_agi_send(agi->fd, chan, "200 result=0\n");
02663 
02664    return RESULT_SUCCESS;
02665 }

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

Definition at line 2752 of file res_agi.c.

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

02753 {
02754    if (argc != 4)
02755       return RESULT_SHOWUSAGE;
02756 
02757    if (!agi->speech) {
02758       ast_agi_send(agi->fd, chan, "200 result=0\n");
02759       return RESULT_SUCCESS;
02760    }
02761 
02762    if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02763       ast_agi_send(agi->fd, chan, "200 result=0\n");
02764    else
02765       ast_agi_send(agi->fd, chan, "200 result=1\n");
02766 
02767    return RESULT_SUCCESS;
02768 }

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

Definition at line 2685 of file res_agi.c.

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

02686 {
02687    if (agi->speech) {
02688       ast_speech_destroy(agi->speech);
02689       agi->speech = NULL;
02690       ast_agi_send(agi->fd, chan, "200 result=1\n");
02691    } else {
02692       ast_agi_send(agi->fd, chan, "200 result=0\n");
02693    }
02694 
02695    return RESULT_SUCCESS;
02696 }

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

Definition at line 2698 of file res_agi.c.

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

02699 {
02700    if (argc != 5)
02701       return RESULT_SHOWUSAGE;
02702 
02703    if (!agi->speech) {
02704       ast_agi_send(agi->fd, chan, "200 result=0\n");
02705       return RESULT_SUCCESS;
02706    }
02707 
02708    if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02709       ast_agi_send(agi->fd, chan, "200 result=0\n");
02710    else
02711       ast_agi_send(agi->fd, chan, "200 result=1\n");
02712 
02713    return RESULT_SUCCESS;
02714 }

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

Definition at line 2789 of file res_agi.c.

References ast_agi_send(), ast_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, ast_channel::readformat, 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.

02790 {
02791    struct ast_speech *speech = agi->speech;
02792    const char *prompt;
02793    char dtmf = 0, tmp[4096] = "", *buf = tmp;
02794    int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
02795    long current_offset = 0;
02796    const char *reason = NULL;
02797    struct ast_frame *fr = NULL;
02798    struct ast_speech_result *result = NULL;
02799    size_t left = sizeof(tmp);
02800    time_t start = 0, current;
02801 
02802    if (argc < 4)
02803       return RESULT_SHOWUSAGE;
02804 
02805    if (!speech) {
02806       ast_agi_send(agi->fd, chan, "200 result=0\n");
02807       return RESULT_SUCCESS;
02808    }
02809 
02810    prompt = argv[2];
02811    timeout = atoi(argv[3]);
02812 
02813    /* If offset is specified then convert from text to integer */
02814    if (argc == 5)
02815       offset = atoi(argv[4]);
02816 
02817    /* We want frames coming in signed linear */
02818    old_read_format = chan->readformat;
02819    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02820       ast_agi_send(agi->fd, chan, "200 result=0\n");
02821       return RESULT_SUCCESS;
02822    }
02823 
02824    /* Setup speech structure */
02825    if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02826       ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02827       ast_speech_start(speech);
02828    }
02829 
02830    /* Start playing prompt */
02831    speech_streamfile(chan, prompt, chan->language, offset);
02832 
02833    /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
02834    while (ast_strlen_zero(reason)) {
02835       /* Run scheduled items */
02836                 ast_sched_runq(chan->sched);
02837 
02838       /* See maximum time of waiting */
02839       if ((res = ast_sched_wait(chan->sched)) < 0)
02840          res = 1000;
02841 
02842       /* Wait for frame */
02843       if (ast_waitfor(chan, res) > 0) {
02844          if (!(fr = ast_read(chan))) {
02845             reason = "hangup";
02846             break;
02847          }
02848       }
02849 
02850       /* Perform timeout check */
02851       if ((timeout > 0) && (start > 0)) {
02852          time(&current);
02853          if ((current - start) >= timeout) {
02854             reason = "timeout";
02855             if (fr)
02856                ast_frfree(fr);
02857             break;
02858          }
02859       }
02860 
02861       /* Check the speech structure for any changes */
02862       ast_mutex_lock(&speech->lock);
02863 
02864       /* See if we need to quiet the audio stream playback */
02865       if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02866          current_offset = ast_tellstream(chan->stream);
02867          ast_stopstream(chan);
02868          ast_clear_flag(speech, AST_SPEECH_QUIET);
02869       }
02870 
02871       /* Check each state */
02872       switch (speech->state) {
02873       case AST_SPEECH_STATE_READY:
02874          /* If the stream is done, start timeout calculation */
02875          if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02876             ast_stopstream(chan);
02877             time(&start);
02878          }
02879          /* Write audio frame data into speech engine if possible */
02880          if (fr && fr->frametype == AST_FRAME_VOICE)
02881             ast_speech_write(speech, fr->data.ptr, fr->datalen);
02882          break;
02883       case AST_SPEECH_STATE_WAIT:
02884          /* Cue waiting sound if not already playing */
02885          if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
02886             ast_stopstream(chan);
02887             /* If a processing sound exists, or is not none - play it */
02888             if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
02889                speech_streamfile(chan, speech->processing_sound, chan->language, 0);
02890          }
02891          break;
02892       case AST_SPEECH_STATE_DONE:
02893          /* Get the results */
02894          speech->results = ast_speech_results_get(speech);
02895          /* Change state to not ready */
02896          ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02897          reason = "speech";
02898          break;
02899       default:
02900          break;
02901       }
02902       ast_mutex_unlock(&speech->lock);
02903 
02904       /* Check frame for DTMF or hangup */
02905       if (fr) {
02906          if (fr->frametype == AST_FRAME_DTMF) {
02907             reason = "dtmf";
02908             dtmf = fr->subclass.integer;
02909          } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
02910             reason = "hangup";
02911          }
02912          ast_frfree(fr);
02913       }
02914    }
02915 
02916    if (!strcasecmp(reason, "speech")) {
02917       /* Build string containing speech results */
02918                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
02919          /* Build result string */
02920          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);
02921                         /* Increment result count */
02922          i++;
02923       }
02924                 /* Print out */
02925       ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
02926    } else if (!strcasecmp(reason, "dtmf")) {
02927       ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
02928    } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
02929       ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
02930    } else {
02931       ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
02932    }
02933 
02934    return RESULT_SUCCESS;
02935 }

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

Definition at line 2667 of file res_agi.c.

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

02668 {
02669    /* Check for minimum arguments */
02670    if (argc != 4)
02671       return RESULT_SHOWUSAGE;
02672 
02673    /* Check to make sure speech structure exists */
02674    if (!agi->speech) {
02675       ast_agi_send(agi->fd, chan, "200 result=0\n");
02676       return RESULT_SUCCESS;
02677    }
02678 
02679    ast_speech_change(agi->speech, argv[2], argv[3]);
02680    ast_agi_send(agi->fd, chan, "200 result=1\n");
02681 
02682    return RESULT_SUCCESS;
02683 }

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

Definition at line 2716 of file res_agi.c.

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

02717 {
02718    if (argc != 4)
02719       return RESULT_SHOWUSAGE;
02720 
02721    if (!agi->speech) {
02722       ast_agi_send(agi->fd, chan, "200 result=0\n");
02723       return RESULT_SUCCESS;
02724    }
02725 
02726    if (ast_speech_grammar_unload(agi->speech, argv[3]))
02727       ast_agi_send(agi->fd, chan, "200 result=0\n");
02728    else
02729       ast_agi_send(agi->fd, chan, "200 result=1\n");
02730 
02731    return RESULT_SUCCESS;
02732 }

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

Definition at line 1827 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, ast_channel::stream, and ast_filestream::vfs.

01828 {
01829    int res, vres;
01830    struct ast_filestream *fs, *vfs;
01831    long sample_offset = 0, max_length;
01832    const char *edigits = "";
01833 
01834    if (argc < 4 || argc > 5)
01835       return RESULT_SHOWUSAGE;
01836 
01837    if (argv[3])
01838       edigits = argv[3];
01839 
01840    if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01841       return RESULT_SHOWUSAGE;
01842 
01843    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01844       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01845       return RESULT_SUCCESS;
01846    }
01847 
01848    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01849       ast_debug(1, "Ooh, found a video stream, too\n");
01850 
01851    ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01852 
01853    ast_seekstream(fs, 0, SEEK_END);
01854    max_length = ast_tellstream(fs);
01855    ast_seekstream(fs, sample_offset, SEEK_SET);
01856    res = ast_applystream(chan, fs);
01857    if (vfs)
01858       vres = ast_applystream(chan, vfs);
01859    ast_playstream(fs);
01860    if (vfs)
01861       ast_playstream(vfs);
01862 
01863    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01864    /* this is to check for if ast_waitstream closed the stream, we probably are at
01865     * the end of the stream, return that amount, else check for the amount */
01866    sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01867    ast_stopstream(chan);
01868    if (res == 1) {
01869       /* Stop this command, don't print a result line, as there is a new command */
01870       return RESULT_SUCCESS;
01871    }
01872    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01873    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01874 }

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

Definition at line 1748 of file res_agi.c.

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

01749 {
01750    int res, x;
01751 
01752    if (argc != 3)
01753       return RESULT_SHOWUSAGE;
01754 
01755    if (!strncasecmp(argv[2],"on",2)) {
01756       x = 1;
01757    } else  {
01758       x = 0;
01759    }
01760    if (!strncasecmp(argv[2],"mate",4))  {
01761       x = 2;
01762    }
01763    if (!strncasecmp(argv[2],"tdd",3)) {
01764       x = 1;
01765    }
01766    res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
01767    if (res != RESULT_SUCCESS) {
01768       ast_agi_send(agi->fd, chan, "200 result=0\n");
01769    } else {
01770       ast_agi_send(agi->fd, chan, "200 result=1\n");
01771    }
01772    return RESULT_SUCCESS;
01773 }

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

Definition at line 2516 of file res_agi.c.

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

02517 {
02518    int level = 0;
02519 
02520    if (argc < 2)
02521       return RESULT_SHOWUSAGE;
02522 
02523    if (argv[2])
02524       sscanf(argv[2], "%30d", &level);
02525 
02526    ast_verb(level, "%s: %s\n", chan->data, argv[1]);
02527 
02528    ast_agi_send(agi->fd, chan, "200 result=1\n");
02529 
02530    return RESULT_SUCCESS;
02531 }

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

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

01680 {
01681    int res, to;
01682 
01683    if (argc != 4)
01684       return RESULT_SHOWUSAGE;
01685    if (sscanf(argv[3], "%30d", &to) != 1)
01686       return RESULT_SHOWUSAGE;
01687    res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
01688    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01689    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01690 }

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

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

02992 {
02993    char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
02994    struct agi_command *e;
02995 
02996    if (match)
02997       ast_join(matchstr, sizeof(matchstr), match);
02998 
02999    ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
03000    AST_RWLIST_RDLOCK(&agi_commands);
03001    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03002       if (!e->cmda[0])
03003          break;
03004       /* Hide commands that start with '_' */
03005       if ((e->cmda[0])[0] == '_')
03006          continue;
03007       ast_join(fullcmd, sizeof(fullcmd), e->cmda);
03008       if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
03009          continue;
03010       ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
03011    }
03012    AST_RWLIST_UNLOCK(&agi_commands);
03013 
03014    return CLI_SUCCESS;
03015 }

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

Definition at line 1183 of file res_agi.c.

References add_to_agi(), AGI_BUF_SIZE, agi_handle_command(), AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS_ASYNC, AMI_BUF_SIZE, ast_check_hangup(), AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_frfree, ast_log(), ast_read(), ast_speech_destroy(), ast_strlen_zero(), ast_uri_encode(), ast_waitfor(), agi_state::audio, agi_cmd::cmd_buffer, agi_cmd::cmd_id, agi_state::ctrl, EVENT_FLAG_AGI, f, agi_state::fast, agi_state::fd, free_agi_cmd(), get_agi_cmd(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, manager_event, ast_channel::name, setup_env(), and agi_state::speech.

Referenced by launch_script().

01184 {
01185 /* This buffer sizes might cause truncation if the AGI command writes more data
01186    than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
01187    that writes a response larger than 1024 bytes?, I don't think so, most of
01188    them are just result=blah stuff. However probably if GET VARIABLE is called
01189    and the variable has large amount of data, that could be a problem. We could
01190    make this buffers dynamic, but let's leave that as a second step.
01191 
01192    AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
01193    number. Some characters of AGI buf will be url encoded to be sent to manager
01194    clients.  An URL encoded character will take 3 bytes, but again, to cause
01195    truncation more than about 70% of the AGI buffer should be URL encoded for
01196    that to happen.  Not likely at all.
01197 
01198    On the other hand. I wonder if read() could eventually return less data than
01199    the amount already available in the pipe? If so, how to deal with that?
01200    So far, my tests on Linux have not had any problems.
01201  */
01202 #define AGI_BUF_SIZE 1024
01203 #define AMI_BUF_SIZE 2048
01204    struct ast_frame *f;
01205    struct agi_cmd *cmd;
01206    int res, fds[2];
01207    int timeout = 100;
01208    char agi_buffer[AGI_BUF_SIZE + 1];
01209    char ami_buffer[AMI_BUF_SIZE];
01210    enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01211    AGI async_agi;
01212 
01213    if (efd) {
01214       ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
01215       return AGI_RESULT_FAILURE;
01216    }
01217 
01218    /* add AsyncAGI datastore to the channel */
01219    if (add_to_agi(chan)) {
01220       ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
01221       return AGI_RESULT_FAILURE;
01222    }
01223 
01224    /* this pipe allows us to create a "fake" AGI struct to use
01225       the AGI commands */
01226    res = pipe(fds);
01227    if (res) {
01228       ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
01229       /* intentionally do not remove datastore, added with
01230          add_to_agi(), from channel. It will be removed when
01231          the channel is hung up anyways */
01232       return AGI_RESULT_FAILURE;
01233    }
01234 
01235    /* handlers will get the pipe write fd and we read the AGI responses
01236       from the pipe read fd */
01237    async_agi.fd = fds[1];
01238    async_agi.ctrl = fds[1];
01239    async_agi.audio = -1; /* no audio support */
01240    async_agi.fast = 0;
01241    async_agi.speech = NULL;
01242 
01243    /* notify possible manager users of a new channel ready to
01244       receive commands */
01245    setup_env(chan, "async", fds[1], 0, 0, NULL);
01246    /* read the environment */
01247    res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01248    if (!res) {
01249       ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
01250       returnstatus = AGI_RESULT_FAILURE;
01251       goto quit;
01252    }
01253    agi_buffer[res] = '\0';
01254    /* encode it and send it thru the manager so whoever is going to take
01255       care of AGI commands on this channel can decide which AGI commands
01256       to execute based on the setup info */
01257    ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01258    manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
01259    while (1) {
01260       /* bail out if we need to hangup */
01261       if (ast_check_hangup(chan)) {
01262          ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
01263          break;
01264       }
01265       /* retrieve a command
01266          (commands are added via the manager or the cli threads) */
01267       cmd = get_agi_cmd(chan);
01268       if (cmd) {
01269          /* OK, we have a command, let's call the
01270             command handler. */
01271          res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
01272          if (res < 0) {
01273             free_agi_cmd(cmd);
01274             break;
01275          }
01276          /* the command handler must have written to our fake
01277             AGI struct fd (the pipe), let's read the response */
01278          res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01279          if (!res) {
01280             returnstatus = AGI_RESULT_FAILURE;
01281             ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
01282             free_agi_cmd(cmd);
01283             break;
01284          }
01285          /* we have a response, let's send the response thru the
01286             manager. Include the CommandID if it was specified
01287             when the command was added */
01288          agi_buffer[res] = '\0';
01289          ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01290          if (ast_strlen_zero(cmd->cmd_id))
01291             manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
01292          else
01293             manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nCommandID: %s\r\nResult: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
01294          free_agi_cmd(cmd);
01295       } else {
01296          /* no command so far, wait a bit for a frame to read */
01297          res = ast_waitfor(chan, timeout);
01298          if (res < 0) {
01299             ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
01300             break;
01301          }
01302          if (res == 0)
01303             continue;
01304          f = ast_read(chan);
01305          if (!f) {
01306             ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
01307             returnstatus = AGI_RESULT_HANGUP;
01308             break;
01309          }
01310          /* is there any other frame we should care about
01311             besides AST_CONTROL_HANGUP? */
01312          if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) {
01313             ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
01314             ast_frfree(f);
01315             break;
01316          }
01317          ast_frfree(f);
01318       }
01319    }
01320 
01321    if (async_agi.speech) {
01322       ast_speech_destroy(async_agi.speech);
01323    }
01324 quit:
01325    /* notify manager users this channel cannot be
01326       controlled anymore by Async AGI */
01327    manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
01328 
01329    /* close the pipe */
01330    close(fds[0]);
01331    close(fds[1]);
01332 
01333    /* intentionally don't get rid of the datastore. So commands can be
01334       still in the queue in case AsyncAGI gets called again.
01335       Datastore destructor will be called on channel destroy anyway  */
01336 
01337    return returnstatus;
01338 
01339 #undef AGI_BUF_SIZE
01340 #undef AMI_BUF_SIZE
01341 }

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

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

01448 {
01449    char *host, *script;
01450    enum agi_result result = AGI_RESULT_FAILURE;
01451    struct srv_context *context = NULL;
01452    int srv_ret;
01453    char service[256];
01454    char resolved_uri[1024];
01455    const char *srvhost;
01456    unsigned short srvport;
01457 
01458    /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
01459    if (!(host = ast_strdupa(agiurl + 7))) { /* Remove hagi:// */
01460       ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
01461       return AGI_RESULT_FAILURE;
01462    }
01463 
01464    /* Strip off any script name */
01465    if ((script = strchr(host, '/'))) {
01466       *script++ = '\0';
01467    } else {
01468       script = "";
01469    }
01470 
01471    if (strchr(host, ':')) {
01472       ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
01473       return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
01474    }
01475 
01476    snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
01477 
01478    while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
01479       snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
01480       result = launch_netscript(resolved_uri, argv, fds);
01481       if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
01482          ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
01483       } else {
01484          break;
01485       }
01486    }
01487    if (srv_ret < 0) {
01488       ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
01489    } else {
01490         ast_srv_cleanup(&context);
01491     }
01492 
01493    return result;
01494 }

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

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

01346 {
01347    int s, flags, res, port = AGI_PORT;
01348    struct pollfd pfds[1];
01349    char *host, *c, *script;
01350    struct sockaddr_in addr_in;
01351    struct hostent *hp;
01352    struct ast_hostent ahp;
01353 
01354    /* agiurl is "agi://host.domain[:port][/script/name]" */
01355    host = ast_strdupa(agiurl + 6);  /* Remove agi:// */
01356    /* Strip off any script name */
01357    if ((script = strchr(host, '/'))) {
01358       *script++ = '\0';
01359    } else {
01360       script = "";
01361    }
01362 
01363    if ((c = strchr(host, ':'))) {
01364       *c++ = '\0';
01365       port = atoi(c);
01366    }
01367    if (!(hp = ast_gethostbyname(host, &ahp))) {
01368       ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
01369       return -1;
01370    }
01371    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
01372       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01373       return -1;
01374    }
01375    if ((flags = fcntl(s, F_GETFL)) < 0) {
01376       ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
01377       close(s);
01378       return -1;
01379    }
01380    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
01381       ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
01382       close(s);
01383       return -1;
01384    }
01385    memset(&addr_in, 0, sizeof(addr_in));
01386    addr_in.sin_family = AF_INET;
01387    addr_in.sin_port = htons(port);
01388    memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
01389    if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
01390       ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
01391       close(s);
01392       return AGI_RESULT_FAILURE;
01393    }
01394 
01395    pfds[0].fd = s;
01396    pfds[0].events = POLLOUT;
01397    while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
01398       if (errno != EINTR) {
01399          if (!res) {
01400             ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
01401                agiurl, MAX_AGI_CONNECT);
01402          } else
01403             ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01404          close(s);
01405          return AGI_RESULT_FAILURE;
01406       }
01407    }
01408 
01409    if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
01410       if (errno != EINTR) {
01411          ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01412          close(s);
01413          return AGI_RESULT_FAILURE;
01414       }
01415    }
01416 
01417    /* If we have a script parameter, relay it to the fastagi server */
01418    /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
01419    if (!ast_strlen_zero(script))
01420       ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
01421 
01422    ast_debug(4, "Wow, connected!\n");
01423    fds[0] = s;
01424    fds[1] = s;
01425    return AGI_RESULT_SUCCESS_FAST;
01426 }

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

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

01497 {
01498    char tmp[256];
01499    int pid, toast[2], fromast[2], audio[2], res;
01500    struct stat st;
01501 
01502    if (!strncasecmp(script, "agi://", 6)) {
01503       return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01504    }
01505    if (!strncasecmp(script, "hagi://", 7)) {
01506       return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01507    }
01508    if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
01509       return launch_asyncagi(chan, argv, efd);
01510    }
01511 
01512    if (script[0] != '/') {
01513       snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
01514       script = tmp;
01515    }
01516 
01517    /* Before even trying let's see if the file actually exists */
01518    if (stat(script, &st)) {
01519       ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
01520       return AGI_RESULT_NOTFOUND;
01521    }
01522 
01523    if (pipe(toast)) {
01524       ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
01525       return AGI_RESULT_FAILURE;
01526    }
01527    if (pipe(fromast)) {
01528       ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
01529       close(toast[0]);
01530       close(toast[1]);
01531       return AGI_RESULT_FAILURE;
01532    }
01533    if (efd) {
01534       if (pipe(audio)) {
01535          ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
01536          close(fromast[0]);
01537          close(fromast[1]);
01538          close(toast[0]);
01539          close(toast[1]);
01540          return AGI_RESULT_FAILURE;
01541       }
01542       res = fcntl(audio[1], F_GETFL);
01543       if (res > -1)
01544          res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
01545       if (res < 0) {
01546          ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
01547          close(fromast[0]);
01548          close(fromast[1]);
01549          close(toast[0]);
01550          close(toast[1]);
01551          close(audio[0]);
01552          close(audio[1]);
01553          return AGI_RESULT_FAILURE;
01554       }
01555    }
01556 
01557    if ((pid = ast_safe_fork(1)) < 0) {
01558       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
01559       return AGI_RESULT_FAILURE;
01560    }
01561    if (!pid) {
01562       /* Pass paths to AGI via environmental variables */
01563       setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
01564       setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
01565       setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
01566       setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
01567       setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
01568       setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
01569       setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
01570       setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
01571       setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
01572       setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
01573       setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
01574 
01575       /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
01576       ast_set_priority(0);
01577 
01578       /* Redirect stdin and out, provide enhanced audio channel if desired */
01579       dup2(fromast[0], STDIN_FILENO);
01580       dup2(toast[1], STDOUT_FILENO);
01581       if (efd)
01582          dup2(audio[0], STDERR_FILENO + 1);
01583       else
01584          close(STDERR_FILENO + 1);
01585 
01586       /* Close everything but stdin/out/error */
01587       ast_close_fds_above_n(STDERR_FILENO + 1);
01588 
01589       /* Execute script */
01590       /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
01591       execv(script, argv);
01592       /* Can't use ast_log since FD's are closed */
01593       ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
01594       /* Special case to set status of AGI to failure */
01595       fprintf(stdout, "failure\n");
01596       fflush(stdout);
01597       _exit(1);
01598    }
01599    ast_verb(3, "Launched AGI Script %s\n", script);
01600    fds[0] = toast[0];
01601    fds[1] = fromast[1];
01602    if (efd)
01603       *efd = audio[1];
01604    /* close what we're not using in the parent */
01605    close(toast[1]);
01606    close(fromast[0]);
01607 
01608    if (efd)
01609       close(audio[0]);
01610 
01611    *opid = pid;
01612    return AGI_RESULT_SUCCESS;
01613 }

static int load_module ( void   )  [static]

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

03850 {
03851    ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
03852    /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
03853       no other commands have been registered yet
03854    */
03855    (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03856    ast_register_application_xml(deadapp, deadagi_exec);
03857    ast_register_application_xml(eapp, eagi_exec);
03858    ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
03859    AST_TEST_REGISTER(test_agi_null_docs);
03860    return ast_register_application_xml(app, agi_exec);
03861 }

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

Definition at line 3186 of file res_agi.c.

References ast_log(), LOG_WARNING, and MAX_ARGS.

03187 {
03188    int x = 0, quoted = 0, escaped = 0, whitespace = 1;
03189    char *cur;
03190 
03191    cur = s;
03192    while(*s) {
03193       switch(*s) {
03194       case '"':
03195          /* If it's escaped, put a literal quote */
03196          if (escaped)
03197             goto normal;
03198          else
03199             quoted = !quoted;
03200          if (quoted && whitespace) {
03201             /* If we're starting a quote, coming off white space start a new word, too */
03202             argv[x++] = cur;
03203             whitespace=0;
03204          }
03205          escaped = 0;
03206       break;
03207       case ' ':
03208       case '\t':
03209          if (!quoted && !escaped) {
03210             /* If we're not quoted, mark this as whitespace, and
03211                end the previous argument */
03212             whitespace = 1;
03213             *(cur++) = '\0';
03214          } else
03215             /* Otherwise, just treat it as anything else */
03216             goto normal;
03217          break;
03218       case '\\':
03219          /* If we're escaped, print a literal, otherwise enable escaping */
03220          if (escaped) {
03221             goto normal;
03222          } else {
03223             escaped=1;
03224          }
03225          break;
03226       default:
03227 normal:
03228          if (whitespace) {
03229             if (x >= MAX_ARGS -1) {
03230                ast_log(LOG_WARNING, "Too many arguments, truncating\n");
03231                break;
03232             }
03233             /* Coming off of whitespace, start the next argument */
03234             argv[x++] = cur;
03235             whitespace=0;
03236          }
03237          *(cur++) = *s;
03238          escaped=0;
03239       }
03240       s++;
03241    }
03242    /* Null terminate */
03243    *(cur++) = '\0';
03244    argv[x] = NULL;
03245    *max = x;
03246    return 0;
03247 }

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 3325 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_channel_lock, ast_channel_unlock, 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().

03326 {
03327    struct ast_channel *c;
03328    int outfd, ms, needhup = 0;
03329    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
03330    struct ast_frame *f;
03331    char buf[AGI_BUF_LEN];
03332    char *res = NULL;
03333    FILE *readf;
03334    /* how many times we'll retry if ast_waitfor_nandfs will return without either
03335      channel or file descriptor in case select is interrupted by a system call (EINTR) */
03336    int retry = AGI_NANDFS_RETRY;
03337    int send_sighup;
03338    const char *sighup_str;
03339    
03340    ast_channel_lock(chan);
03341    sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
03342    send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
03343    ast_channel_unlock(chan);
03344 
03345    if (!(readf = fdopen(agi->ctrl, "r"))) {
03346       ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
03347       if (send_sighup && pid > -1)
03348          kill(pid, SIGHUP);
03349       close(agi->ctrl);
03350       return AGI_RESULT_FAILURE;
03351    }
03352    
03353    setlinebuf(readf);
03354    setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
03355    for (;;) {
03356       if (needhup) {
03357          needhup = 0;
03358          dead = 1;
03359          if (send_sighup) {
03360             if (pid > -1) {
03361                kill(pid, SIGHUP);
03362             } else if (agi->fast) {
03363                send(agi->ctrl, "HANGUP\n", 7, 0);
03364             }
03365          }
03366       }
03367       ms = -1;
03368       c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
03369       if (c) {
03370          retry = AGI_NANDFS_RETRY;
03371          /* Idle the channel until we get a command */
03372          f = ast_read(c);
03373          if (!f) {
03374             ast_debug(1, "%s hungup\n", chan->name);
03375             returnstatus = AGI_RESULT_HANGUP;
03376             needhup = 1;
03377             continue;
03378          } else {
03379             /* If it's voice, write it to the audio pipe */
03380             if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
03381                /* Write, ignoring errors */
03382                if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
03383                }
03384             }
03385             ast_frfree(f);
03386          }
03387       } else if (outfd > -1) {
03388          size_t len = sizeof(buf);
03389          size_t buflen = 0;
03390 
03391          retry = AGI_NANDFS_RETRY;
03392          buf[0] = '\0';
03393 
03394          while (buflen < (len - 1)) {
03395             res = fgets(buf + buflen, len, readf);
03396             if (feof(readf))
03397                break;
03398             if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
03399                break;
03400             if (res != NULL && !agi->fast)
03401                break;
03402             buflen = strlen(buf);
03403             if (buflen && buf[buflen - 1] == '\n')
03404                break;
03405             len -= buflen;
03406             if (agidebug)
03407                ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
03408          }
03409 
03410          if (!buf[0]) {
03411             /* Program terminated */
03412             if (returnstatus) {
03413                returnstatus = -1;
03414             }
03415             ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
03416             if (pid > 0)
03417                waitpid(pid, status, 0);
03418             /* No need to kill the pid anymore, since they closed us */
03419             pid = -1;
03420             break;
03421          }
03422 
03423          /* Special case for inability to execute child process */
03424          if (*buf && strncasecmp(buf, "failure", 7) == 0) {
03425             returnstatus = AGI_RESULT_FAILURE;
03426             break;
03427          }
03428 
03429          /* get rid of trailing newline, if any */
03430          if (*buf && buf[strlen(buf) - 1] == '\n')
03431             buf[strlen(buf) - 1] = 0;
03432          if (agidebug)
03433             ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
03434          returnstatus |= agi_handle_command(chan, agi, buf, dead);
03435          /* If the handle_command returns -1, we need to stop */
03436          if (returnstatus < 0) {
03437             needhup = 1;
03438             continue;
03439          }
03440       } else {
03441          if (--retry <= 0) {
03442             ast_log(LOG_WARNING, "No channel, no fd?\n");
03443             returnstatus = AGI_RESULT_FAILURE;
03444             break;
03445          }
03446       }
03447    }
03448    if (agi->speech) {
03449       ast_speech_destroy(agi->speech);
03450    }
03451    /* Notify process */
03452    if (send_sighup) {
03453       if (pid > -1) {
03454          if (kill(pid, SIGHUP)) {
03455             ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
03456          } else { /* Give the process a chance to die */
03457             usleep(1);
03458          }
03459          waitpid(pid, status, WNOHANG);
03460       } else if (agi->fast) {
03461          send(agi->ctrl, "HANGUP\n", 7, 0);
03462       }
03463    }
03464    fclose(readf);
03465    return returnstatus;
03466 }

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

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

01616 {
01617    int count;
01618 
01619    /* Print initial environment, with agi_request always being the first
01620       thing */
01621    ast_agi_send(fd, chan, "agi_request: %s\n", request);
01622    ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
01623    ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
01624    ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
01625    ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
01626    ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
01627 
01628    /* ANI/DNIS */
01629    ast_agi_send(fd, chan, "agi_callerid: %s\n",
01630       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "unknown"));
01631    ast_agi_send(fd, chan, "agi_calleridname: %s\n",
01632       S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "unknown"));
01633    ast_agi_send(fd, chan, "agi_callingpres: %d\n",
01634       ast_party_id_presentation(&chan->caller.id));
01635    ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->caller.ani2);
01636    ast_agi_send(fd, chan, "agi_callington: %d\n", chan->caller.id.number.plan);
01637    ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->dialed.transit_network_select);
01638    ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->dialed.number.str, "unknown"));
01639    ast_agi_send(fd, chan, "agi_rdnis: %s\n",
01640       S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "unknown"));
01641 
01642    /* Context information */
01643    ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
01644    ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
01645    ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
01646    ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
01647 
01648    /* User information */
01649    ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
01650    ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
01651 
01652    /* Send any parameters to the fastagi server that have been passed via the agi application */
01653    /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
01654    for(count = 1; count < argc; count++)
01655       ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
01656 
01657    /* End with empty return */
01658    ast_agi_send(fd, chan, "\n");
01659 }

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

Definition at line 2770 of file res_agi.c.

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

02771 {
02772    struct ast_filestream *fs = NULL;
02773 
02774    if (!(fs = ast_openstream(chan, filename, preflang)))
02775       return -1;
02776 
02777    if (offset)
02778       ast_seekstream(fs, offset, SEEK_SET);
02779 
02780    if (ast_applystream(chan, fs))
02781       return -1;
02782 
02783    if (ast_playstream(fs))
02784       return -1;
02785 
02786    return 0;
02787 }

static int unload_module ( void   )  [static]

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

03836 {
03837    ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
03838    /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
03839       we know that these commands were registered by this module and are still registered
03840    */
03841    (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03842    ast_unregister_application(eapp);
03843    ast_unregister_application(deadapp);
03844    ast_manager_unregister("AGI");
03845    AST_TEST_UNREGISTER(test_agi_null_docs);
03846    return ast_unregister_application(app);
03847 }

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

Referenced by write_htmldump().

03575 {
03576    char *cur = str;
03577 
03578    while(*cur) {
03579       switch (*cur) {
03580       case '<':
03581          fprintf(htmlfile, "%s", "&lt;");
03582          break;
03583       case '>':
03584          fprintf(htmlfile, "%s", "&gt;");
03585          break;
03586       case '&':
03587          fprintf(htmlfile, "%s", "&amp;");
03588          break;
03589       case '"':
03590          fprintf(htmlfile, "%s", "&quot;");
03591          break;
03592       default:
03593          fprintf(htmlfile, "%c", *cur);
03594          break;
03595       }
03596       cur++;
03597    }
03598 
03599    return;
03600 }

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

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

03603 {
03604    struct agi_command *command;
03605    char fullcmd[MAX_CMD_LEN];
03606    FILE *htmlfile;
03607 
03608    if (!(htmlfile = fopen(filename, "wt")))
03609       return -1;
03610 
03611    fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03612    fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03613    fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03614 
03615    AST_RWLIST_RDLOCK(&agi_commands);
03616    AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03617 #ifdef AST_XML_DOCS
03618       char *stringptmp;
03619 #endif
03620       char *tempstr, *stringp;
03621 
03622       if (!command->cmda[0])  /* end ? */
03623          break;
03624       /* Hide commands that start with '_' */
03625       if ((command->cmda[0])[0] == '_')
03626          continue;
03627       ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03628 
03629       fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03630       fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03631 #ifdef AST_XML_DOCS
03632       stringptmp = ast_xmldoc_printable(command->usage, 0);
03633       stringp = ast_strdup(stringptmp);
03634 #else
03635       stringp = ast_strdup(command->usage);
03636 #endif
03637       tempstr = strsep(&stringp, "\n");
03638 
03639       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03640       write_html_escaped(htmlfile, tempstr);
03641       fprintf(htmlfile, "</TD></TR>\n");
03642       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03643 
03644       while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03645          write_html_escaped(htmlfile, tempstr);
03646          fprintf(htmlfile, "<BR>\n");
03647       }
03648       fprintf(htmlfile, "</TD></TR>\n");
03649       fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03650       ast_free(stringp);
03651 #ifdef AST_XML_DOCS
03652       ast_free(stringptmp);
03653 #endif
03654    }
03655    AST_RWLIST_UNLOCK(&agi_commands);
03656    fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03657    fclose(htmlfile);
03658    return 0;
03659 }


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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, } [static]

Definition at line 3867 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 930 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 991 of file res_agi.c.

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

int agidebug = 0 [static]

Definition at line 910 of file res_agi.c.

char* app = "AGI" [static]

Definition at line 904 of file res_agi.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 3867 of file res_agi.c.

struct ast_cli_entry cli_agi[] [static]

Definition at line 3788 of file res_agi.c.

Referenced by load_module(), and unload_module().

struct agi_command commands[] [static]

AGI commands list.

Definition at line 2940 of file res_agi.c.

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

char* deadapp = "DeadAGI" [static]

Definition at line 908 of file res_agi.c.

char* eapp = "EAGI" [static]

Definition at line 906 of file res_agi.c.


Generated on Wed Apr 6 11:30:08 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7