#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_command * | find_command (const char *const cmds[], int exact) |
static void | free_agi_cmd (struct agi_cmd *cmd) |
static struct agi_cmd * | get_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_info * | ast_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" |
Definition in file res_agi.c.
#define AGI_BUF_INITSIZE 256 |
#define AGI_BUF_SIZE 1024 |
Referenced by launch_asyncagi().
#define AGI_PORT 4573 |
#define AMI_BUF_SIZE 2048 |
Referenced by launch_asyncagi().
#define MAX_AGI_CONNECT 2000 |
#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." |
enum agi_result |
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.
00919 { 00920 AGI_RESULT_FAILURE = -1, 00921 AGI_RESULT_SUCCESS, 00922 AGI_RESULT_SUCCESS_FAST, 00923 AGI_RESULT_SUCCESS_ASYNC, 00924 AGI_RESULT_NOTFOUND, 00925 AGI_RESULT_HANGUP, 00926 };
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.
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 |
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.
mod | Pointer to the module_info structure for the module that is registering the command | |
cmd | Pointer to the descriptor for the command |
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.
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) |
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.
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 |
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.
mod | Pointer to the module_info structure for the module that is unregistering the command | |
cmd | Pointer to the descriptor for the command |
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.
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) |
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.
e | ||
cmd | ||
a |
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(¤t); 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.
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", "<"); 03582 break; 03583 case '>': 03584 fprintf(htmlfile, "%s", ">"); 03585 break; 03586 case '&': 03587 fprintf(htmlfile, "%s", "&"); 03588 break; 03589 case '"': 03590 fprintf(htmlfile, "%s", """); 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 }
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] |
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().
struct ast_module_info* ast_module_info = &__mod_info [static] |
struct ast_cli_entry cli_agi[] [static] |
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().