#include "asterisk.h"
#include <math.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pthread.h>
#include "asterisk/paths.h"
#include "asterisk/network.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/astdb.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/image.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/strings.h"
#include "asterisk/manager.h"
#include "asterisk/ast_version.h"
#include "asterisk/speech.h"
#include "asterisk/term.h"
#include "asterisk/xmldoc.h"
#include "asterisk/srv.h"
#include "asterisk/test.h"
#include "asterisk/agi.h"
Go to the source code of this file.
Data Structures | |
struct | agi_cmd |
struct | agi_commands |
Defines | |
#define | AGI_BUF_INITSIZE 256 |
#define | AGI_BUF_LEN 2048 |
#define | AGI_BUF_SIZE 1024 |
#define | AGI_NANDFS_RETRY 3 |
#define | AGI_PORT 4573 |
#define | AMI_BUF_SIZE 2048 |
#define | AST_API_MODULE |
#define | ASYNC_AGI_BREAK 3 |
#define | MAX_AGI_CONNECT 2000 |
#define | MAX_ARGS 128 |
#define | MAX_CMD_LEN 80 |
#define | SRV_PREFIX "_agi._tcp." |
#define | TONE_BLOCK_SIZE 200 |
Enumerations | |
enum | agi_result { AGI_RESULT_FAILURE = -1, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_FAST, AGI_RESULT_SUCCESS_ASYNC, AGI_RESULT_NOTFOUND, AGI_RESULT_HANGUP } |
Functions | |
static void | __init_agi_buf (void) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | action_add_agi_cmd (struct mansession *s, const struct message *m) |
Add a new command to execute by the Async AGI application. | |
static int | add_agi_cmd (struct ast_channel *chan, const char *cmd_buff, const char *cmd_id) |
static int | add_to_agi (struct ast_channel *chan) |
static void | agi_destroy_commands_cb (void *data) |
static int | agi_exec (struct ast_channel *chan, const char *data) |
static int | agi_exec_full (struct ast_channel *chan, const char *data, int enhanced, int dead) |
static enum agi_result | agi_handle_command (struct ast_channel *chan, AGI *agi, char *buf, int dead) |
int AST_OPTIONAL_API_NAME() | ast_agi_register (struct ast_module *mod, agi_command *cmd) |
Registers an AGI command. | |
int AST_OPTIONAL_API_NAME() | ast_agi_register_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len) |
Registers a group of AGI commands, provided as an array of struct agi_command entries. | |
int AST_OPTIONAL_API_NAME() | ast_agi_send (int fd, struct ast_channel *chan, char *fmt,...) |
Sends a string of text to an application connected via AGI. | |
int AST_OPTIONAL_API_NAME() | ast_agi_unregister (struct ast_module *mod, agi_command *cmd) |
Unregisters an AGI command. | |
int AST_OPTIONAL_API_NAME() | ast_agi_unregister_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len) |
Unregisters a group of AGI commands, provided as an array of struct agi_command entries. | |
static enum agi_result | async_agi_read_frame (struct ast_channel *chan) |
static int | deadagi_exec (struct ast_channel *chan, const char *data) |
static int | eagi_exec (struct ast_channel *chan, const char *data) |
static agi_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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 ASYNC_AGI_BREAK 3 |
Special return code for "asyncagi break" command.
Definition at line 923 of file res_agi.c.
Referenced by agi_handle_command(), and handle_asyncagi_break().
#define MAX_AGI_CONNECT 2000 |
#define MAX_CMD_LEN 80 |
Definition at line 902 of file res_agi.c.
Referenced by ast_agi_register(), ast_agi_unregister(), handle_cli_agi_show(), help_workhorse(), and write_htmldump().
#define SRV_PREFIX "_agi._tcp." |
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 925 of file res_agi.c.
00925 { 00926 AGI_RESULT_FAILURE = -1, 00927 AGI_RESULT_SUCCESS, 00928 AGI_RESULT_SUCCESS_FAST, 00929 AGI_RESULT_SUCCESS_ASYNC, 00930 AGI_RESULT_NOTFOUND, 00931 AGI_RESULT_HANGUP, 00932 };
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 1153 of file res_agi.c.
References add_agi_cmd(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and ast_channel::name.
Referenced by load_module().
01154 { 01155 const char *channel = astman_get_header(m, "Channel"); 01156 const char *cmdbuff = astman_get_header(m, "Command"); 01157 const char *cmdid = astman_get_header(m, "CommandID"); 01158 struct ast_channel *chan; 01159 char buf[256]; 01160 01161 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) { 01162 astman_send_error(s, m, "Both, Channel and Command are *required*"); 01163 return 0; 01164 } 01165 01166 if (!(chan = ast_channel_get_by_name(channel))) { 01167 snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel); 01168 astman_send_error(s, m, buf); 01169 return 0; 01170 } 01171 01172 ast_channel_lock(chan); 01173 01174 if (add_agi_cmd(chan, cmdbuff, cmdid)) { 01175 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name); 01176 astman_send_error(s, m, buf); 01177 ast_channel_unlock(chan); 01178 chan = ast_channel_unref(chan); 01179 return 0; 01180 } 01181 01182 ast_channel_unlock(chan); 01183 chan = ast_channel_unref(chan); 01184 01185 astman_send_ack(s, m, "Added AGI command to queue"); 01186 01187 return 0; 01188 }
static int add_agi_cmd | ( | struct ast_channel * | chan, | |
const char * | cmd_buff, | |||
const char * | cmd_id | |||
) | [static] |
Definition at line 1024 of file res_agi.c.
References agi_commands_datastore_info, ast_calloc, ast_channel_datastore_find(), ast_free, AST_LIST_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strdup, ast_datastore::data, agi_cmd::entry, LOG_WARNING, and ast_channel::name.
Referenced by action_add_agi_cmd(), and handle_cli_agi_add_cmd().
01025 { 01026 struct ast_datastore *store; 01027 struct agi_cmd *cmd; 01028 AST_LIST_HEAD(, agi_cmd) *agi_commands; 01029 01030 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL); 01031 if (!store) { 01032 ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", chan->name); 01033 return -1; 01034 } 01035 agi_commands = store->data; 01036 cmd = ast_calloc(1, sizeof(*cmd)); 01037 if (!cmd) { 01038 return -1; 01039 } 01040 cmd->cmd_buffer = ast_strdup(cmd_buff); 01041 if (!cmd->cmd_buffer) { 01042 ast_free(cmd); 01043 return -1; 01044 } 01045 cmd->cmd_id = ast_strdup(cmd_id); 01046 if (!cmd->cmd_id) { 01047 ast_free(cmd->cmd_buffer); 01048 ast_free(cmd); 01049 return -1; 01050 } 01051 AST_LIST_LOCK(agi_commands); 01052 AST_LIST_INSERT_TAIL(agi_commands, cmd, entry); 01053 AST_LIST_UNLOCK(agi_commands); 01054 return 0; 01055 }
static int add_to_agi | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1057 of file res_agi.c.
References agi_commands_datastore_info, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, ast_log(), ast_datastore::data, and LOG_ERROR.
Referenced by launch_asyncagi().
01058 { 01059 struct ast_datastore *datastore; 01060 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list; 01061 01062 /* check if already on AGI */ 01063 ast_channel_lock(chan); 01064 datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL); 01065 ast_channel_unlock(chan); 01066 if (datastore) { 01067 /* we already have an AGI datastore, let's just 01068 return success */ 01069 return 0; 01070 } 01071 01072 /* the channel has never been on Async AGI, 01073 let's allocate it's datastore */ 01074 datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI"); 01075 if (!datastore) { 01076 return -1; 01077 } 01078 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list)); 01079 if (!agi_cmds_list) { 01080 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n"); 01081 ast_datastore_free(datastore); 01082 return -1; 01083 } 01084 datastore->data = agi_cmds_list; 01085 AST_LIST_HEAD_INIT(agi_cmds_list); 01086 ast_channel_lock(chan); 01087 ast_channel_datastore_add(chan, datastore); 01088 ast_channel_unlock(chan); 01089 return 0; 01090 }
static void agi_destroy_commands_cb | ( | void * | data | ) | [static] |
Definition at line 983 of file res_agi.c.
References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, agi_cmd::entry, and free_agi_cmd().
00984 { 00985 struct agi_cmd *cmd; 00986 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data; 00987 AST_LIST_LOCK(chan_cmds); 00988 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) { 00989 free_agi_cmd(cmd); 00990 } 00991 AST_LIST_UNLOCK(chan_cmds); 00992 AST_LIST_HEAD_DESTROY(chan_cmds); 00993 ast_free(chan_cmds); 00994 }
static int agi_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 3892 of file res_agi.c.
References agi_exec_full(), and ast_check_hangup().
Referenced by deadagi_exec(), and load_module().
03893 { 03894 if (!ast_check_hangup(chan)) 03895 return agi_exec_full(chan, data, 0, 0); 03896 else 03897 return agi_exec_full(chan, data, 0, 1); 03898 }
static int agi_exec_full | ( | struct ast_channel * | chan, | |
const char * | data, | |||
int | enhanced, | |||
int | dead | |||
) | [static] |
Definition at line 3825 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().
03826 { 03827 enum agi_result res; 03828 char *buf; 03829 int fds[2], efd = -1, pid = -1; 03830 AST_DECLARE_APP_ARGS(args, 03831 AST_APP_ARG(arg)[MAX_ARGS]; 03832 ); 03833 AGI agi; 03834 03835 if (ast_strlen_zero(data)) { 03836 ast_log(LOG_WARNING, "AGI requires an argument (script)\n"); 03837 return -1; 03838 } 03839 if (dead) 03840 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n"); 03841 memset(&agi, 0, sizeof(agi)); 03842 buf = ast_strdupa(data); 03843 AST_STANDARD_APP_ARGS(args, buf); 03844 args.argv[args.argc] = NULL; 03845 #if 0 03846 /* Answer if need be */ 03847 if (chan->_state != AST_STATE_UP) { 03848 if (ast_answer(chan)) 03849 return -1; 03850 } 03851 #endif 03852 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid); 03853 /* Async AGI do not require run_agi(), so just proceed if normal AGI 03854 or Fast AGI are setup with success. */ 03855 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) { 03856 int status = 0; 03857 agi.fd = fds[1]; 03858 agi.ctrl = fds[0]; 03859 agi.audio = efd; 03860 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0; 03861 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv); 03862 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */ 03863 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status) 03864 res = AGI_RESULT_FAILURE; 03865 if (fds[1] != fds[0]) 03866 close(fds[1]); 03867 if (efd > -1) 03868 close(efd); 03869 } 03870 ast_safe_fork_cleanup(); 03871 03872 switch (res) { 03873 case AGI_RESULT_SUCCESS: 03874 case AGI_RESULT_SUCCESS_FAST: 03875 case AGI_RESULT_SUCCESS_ASYNC: 03876 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS"); 03877 break; 03878 case AGI_RESULT_FAILURE: 03879 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE"); 03880 break; 03881 case AGI_RESULT_NOTFOUND: 03882 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND"); 03883 break; 03884 case AGI_RESULT_HANGUP: 03885 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP"); 03886 return -1; 03887 } 03888 03889 return 0; 03890 }
static enum agi_result agi_handle_command | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
char * | buf, | |||
int | dead | |||
) | [static] |
Definition at line 3350 of file res_agi.c.
References AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, ast_agi_send(), ast_cdr_setapp(), ast_check_hangup(), ast_module_ref(), ast_module_unref(), ast_random(), ast_strdupa, ast_strlen_zero(), ASYNC_AGI_BREAK, ast_channel::cdr, agi_command::dead, EVENT_FLAG_AGI, agi_state::fd, find_command(), agi_command::handler, manager_event, MAX_ARGS, agi_command::mod, ast_channel::name, parse_args(), RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_command::usage.
Referenced by launch_asyncagi(), and run_agi().
03351 { 03352 const char *argv[MAX_ARGS]; 03353 int argc = MAX_ARGS; 03354 int res; 03355 agi_command *c; 03356 const char *ami_res; 03357 char *ami_cmd = ast_strdupa(buf); 03358 int command_id = ast_random(); 03359 int resultcode; 03360 03361 manager_event(EVENT_FLAG_AGI, "AGIExec", 03362 "SubEvent: Start\r\n" 03363 "Channel: %s\r\n" 03364 "CommandId: %d\r\n" 03365 "Command: %s\r\n", chan->name, command_id, ami_cmd); 03366 parse_args(buf, &argc, argv); 03367 c = find_command(argv, 0); 03368 if (c && (!dead || (dead && c->dead))) { 03369 /* if this command wasn't registered by res_agi, be sure to usecount 03370 the module we are using */ 03371 if (c->mod != ast_module_info->self) 03372 ast_module_ref(c->mod); 03373 /* If the AGI command being executed is an actual application (using agi exec) 03374 the app field will be updated in pbx_exec via handle_exec */ 03375 if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC")) 03376 ast_cdr_setapp(chan->cdr, "AGI", buf); 03377 03378 res = c->handler(chan, agi, argc, argv); 03379 if (c->mod != ast_module_info->self) 03380 ast_module_unref(c->mod); 03381 switch (res) { 03382 case RESULT_SHOWUSAGE: 03383 ami_res = "Usage"; 03384 resultcode = 520; 03385 break; 03386 case RESULT_FAILURE: 03387 ami_res = "Failure"; 03388 resultcode = -1; 03389 break; 03390 case ASYNC_AGI_BREAK: 03391 case RESULT_SUCCESS: 03392 ami_res = "Success"; 03393 resultcode = 200; 03394 break; 03395 default: 03396 ami_res = "Unknown Result"; 03397 resultcode = 200; 03398 break; 03399 } 03400 manager_event(EVENT_FLAG_AGI, "AGIExec", 03401 "SubEvent: End\r\n" 03402 "Channel: %s\r\n" 03403 "CommandId: %d\r\n" 03404 "Command: %s\r\n" 03405 "ResultCode: %d\r\n" 03406 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res); 03407 switch (res) { 03408 case RESULT_SHOWUSAGE: 03409 if (ast_strlen_zero(c->usage)) { 03410 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n"); 03411 } else { 03412 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n"); 03413 ast_agi_send(agi->fd, chan, "%s", c->usage); 03414 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n"); 03415 } 03416 break; 03417 case ASYNC_AGI_BREAK: 03418 return AGI_RESULT_SUCCESS_ASYNC; 03419 case RESULT_FAILURE: 03420 /* The RESULT_FAILURE code is usually because the channel hungup. */ 03421 return AGI_RESULT_FAILURE; 03422 default: 03423 break; 03424 } 03425 } else if (c) { 03426 ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n"); 03427 manager_event(EVENT_FLAG_AGI, "AGIExec", 03428 "SubEvent: End\r\n" 03429 "Channel: %s\r\n" 03430 "CommandId: %d\r\n" 03431 "Command: %s\r\n" 03432 "ResultCode: 511\r\n" 03433 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd); 03434 } else { 03435 ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n"); 03436 manager_event(EVENT_FLAG_AGI, "AGIExec", 03437 "SubEvent: End\r\n" 03438 "Channel: %s\r\n" 03439 "CommandId: %d\r\n" 03440 "Command: %s\r\n" 03441 "ResultCode: 510\r\n" 03442 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd); 03443 } 03444 return AGI_RESULT_SUCCESS; 03445 }
int AST_OPTIONAL_API_NAME() ast_agi_register | ( | struct ast_module * | mod, | |
agi_command * | cmd | |||
) |
Registers an AGI command.
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 3118 of file res_agi.c.
References ast_join(), AST_LIST_INSERT_TAIL, ast_log(), ast_module_ref(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_strdup, ast_strlen_zero(), ast_verb, AST_XML_DOC, ast_xmldoc_build_description(), ast_xmldoc_build_seealso(), ast_xmldoc_build_synopsis(), ast_xmldoc_build_syntax(), find_command(), LOG_WARNING, and MAX_CMD_LEN.
Referenced by ast_agi_register_multiple(), and load_module().
03119 { 03120 char fullcmd[MAX_CMD_LEN]; 03121 03122 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda); 03123 03124 if (!find_command(cmd->cmda, 1)) { 03125 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC; 03126 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) { 03127 #ifdef AST_XML_DOCS 03128 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL); 03129 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL); 03130 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL); 03131 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL); 03132 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC; 03133 #endif 03134 #ifndef HAVE_NULLSAFE_PRINTF 03135 if (!cmd->summary) { 03136 *((char **) &cmd->summary) = ast_strdup(""); 03137 } 03138 if (!cmd->usage) { 03139 *((char **) &cmd->usage) = ast_strdup(""); 03140 } 03141 if (!cmd->syntax) { 03142 *((char **) &cmd->syntax) = ast_strdup(""); 03143 } 03144 if (!cmd->seealso) { 03145 *((char **) &cmd->seealso) = ast_strdup(""); 03146 } 03147 #endif 03148 } 03149 03150 cmd->mod = mod; 03151 AST_RWLIST_WRLOCK(&agi_commands); 03152 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list); 03153 AST_RWLIST_UNLOCK(&agi_commands); 03154 if (mod != ast_module_info->self) 03155 ast_module_ref(ast_module_info->self); 03156 ast_verb(2, "AGI Command '%s' registered\n",fullcmd); 03157 return 1; 03158 } else { 03159 ast_log(LOG_WARNING, "Command already registered!\n"); 03160 return 0; 03161 } 03162 }
int AST_OPTIONAL_API_NAME() ast_agi_register_multiple | ( | struct ast_module * | mod, | |
struct agi_command * | cmd, | |||
unsigned int | len | |||
) |
Registers a group of AGI commands, provided as an array of struct agi_command entries.
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 3203 of file res_agi.c.
References ast_agi_register(), ast_agi_unregister(), len(), and agi_command::mod.
Referenced by load_module().
03204 { 03205 unsigned int i, x = 0; 03206 03207 for (i = 0; i < len; i++) { 03208 if (ast_agi_register(mod, cmd + i) == 1) { 03209 x++; 03210 continue; 03211 } 03212 03213 /* registration failed, unregister everything 03214 that had been registered up to that point 03215 */ 03216 for (; x > 0; x--) { 03217 /* we are intentionally ignoring the 03218 result of ast_agi_unregister() here, 03219 but it should be safe to do so since 03220 we just registered these commands and 03221 the only possible way for unregistration 03222 to fail is if the command is not 03223 registered 03224 */ 03225 (void) ast_agi_unregister(mod, cmd + x - 1); 03226 } 03227 return -1; 03228 } 03229 03230 return 0; 03231 }
int AST_OPTIONAL_API_NAME() ast_agi_send | ( | int | fd, | |
struct ast_channel * | chan, | |||
char * | fmt, | |||
... | ||||
) |
Sends a string of text to an application connected via AGI.
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 939 of file res_agi.c.
References agi_buf, AGI_BUF_INITSIZE, ast_carefulwrite(), ast_log(), ast_str_buffer(), ast_str_set_va(), ast_str_strlen(), ast_str_thread_get(), ast_verbose, and LOG_ERROR.
Referenced by agi_handle_command(), handle_answer(), handle_asyncagi_break(), handle_autohangup(), handle_channelstatus(), handle_controlstreamfile(), handle_dbdel(), handle_dbdeltree(), handle_dbget(), handle_dbput(), handle_exec(), handle_getdata(), handle_getoption(), handle_getvariable(), handle_getvariablefull(), handle_gosub(), handle_hangup(), handle_noop(), handle_recordfile(), handle_recvchar(), handle_recvtext(), handle_sayalpha(), handle_saydate(), handle_saydatetime(), handle_saydigits(), handle_saynumber(), handle_sayphonetic(), handle_saytime(), handle_sendimage(), handle_sendtext(), handle_setcallerid(), handle_setcontext(), handle_setextension(), handle_setmusic(), handle_setpriority(), handle_setvariable(), handle_speechactivategrammar(), handle_speechcreate(), handle_speechdeactivategrammar(), handle_speechdestroy(), handle_speechloadgrammar(), handle_speechrecognize(), handle_speechset(), handle_speechunloadgrammar(), handle_streamfile(), handle_tddmode(), handle_verbose(), handle_waitfordigit(), launch_netscript(), run_agi(), and setup_env().
00940 { 00941 int res = 0; 00942 va_list ap; 00943 struct ast_str *buf; 00944 00945 if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE))) 00946 return -1; 00947 00948 va_start(ap, fmt); 00949 res = ast_str_set_va(&buf, 0, fmt, ap); 00950 va_end(ap); 00951 00952 if (res == -1) { 00953 ast_log(LOG_ERROR, "Out of memory\n"); 00954 return -1; 00955 } 00956 00957 if (agidebug) { 00958 if (chan) { 00959 ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf)); 00960 } else { 00961 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf)); 00962 } 00963 } 00964 00965 return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100); 00966 }
int AST_OPTIONAL_API_NAME() ast_agi_unregister | ( | struct ast_module * | mod, | |
agi_command * | cmd | |||
) |
Unregisters an AGI command.
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 3164 of file res_agi.c.
References ast_free, ast_join(), ast_log(), ast_module_unref(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, AST_XML_DOC, LOG_WARNING, and MAX_CMD_LEN.
Referenced by ast_agi_register_multiple(), ast_agi_unregister_multiple(), and unload_module().
03165 { 03166 struct agi_command *e; 03167 int unregistered = 0; 03168 char fullcmd[MAX_CMD_LEN]; 03169 03170 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda); 03171 03172 AST_RWLIST_WRLOCK(&agi_commands); 03173 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) { 03174 if (cmd == e) { 03175 AST_RWLIST_REMOVE_CURRENT(list); 03176 if (mod != ast_module_info->self) 03177 ast_module_unref(ast_module_info->self); 03178 #ifdef AST_XML_DOCS 03179 if (e->docsrc == AST_XML_DOC) { 03180 ast_free((char *) e->summary); 03181 ast_free((char *) e->usage); 03182 ast_free((char *) e->syntax); 03183 ast_free((char *) e->seealso); 03184 *((char **) &e->summary) = NULL; 03185 *((char **) &e->usage) = NULL; 03186 *((char **) &e->syntax) = NULL; 03187 *((char **) &e->seealso) = NULL; 03188 } 03189 #endif 03190 unregistered=1; 03191 break; 03192 } 03193 } 03194 AST_RWLIST_TRAVERSE_SAFE_END; 03195 AST_RWLIST_UNLOCK(&agi_commands); 03196 if (unregistered) 03197 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd); 03198 else 03199 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd); 03200 return unregistered; 03201 }
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple | ( | struct ast_module * | mod, | |
struct agi_command * | cmd, | |||
unsigned int | len | |||
) |
Unregisters a group of AGI commands, provided as an array of struct agi_command entries.
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 3233 of file res_agi.c.
References ast_agi_unregister(), len(), and agi_command::mod.
Referenced by unload_module().
03234 { 03235 unsigned int i; 03236 int res = 0; 03237 03238 for (i = 0; i < len; i++) { 03239 /* remember whether any of the unregistration 03240 attempts failed... there is no recourse if 03241 any of them do 03242 */ 03243 res |= ast_agi_unregister(mod, cmd + i); 03244 } 03245 03246 return res; 03247 }
static enum agi_result async_agi_read_frame | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1203 of file res_agi.c.
References AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, AST_CONTROL_HANGUP, ast_debug, AST_FRAME_CONTROL, ast_frfree, ast_read(), f, and ast_channel::name.
Referenced by launch_asyncagi().
01204 { 01205 struct ast_frame *f; 01206 01207 f = ast_read(chan); 01208 if (!f) { 01209 ast_debug(3, "No frame read on channel %s, going out ...\n", chan->name); 01210 return AGI_RESULT_HANGUP; 01211 } 01212 if (f->frametype == AST_FRAME_CONTROL) { 01213 /* 01214 * Is there any other frame we should care about besides 01215 * AST_CONTROL_HANGUP? 01216 */ 01217 switch (f->subclass.integer) { 01218 case AST_CONTROL_HANGUP: 01219 ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", chan->name); 01220 ast_frfree(f); 01221 return AGI_RESULT_HANGUP; 01222 default: 01223 break; 01224 } 01225 } 01226 ast_frfree(f); 01227 01228 return AGI_RESULT_SUCCESS; 01229 }
static int deadagi_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 3922 of file res_agi.c.
References agi_exec(), ast_log(), and LOG_WARNING.
Referenced by load_module().
03923 { 03924 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n"); 03925 return agi_exec(chan, data); 03926 }
static int eagi_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 3900 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().
03901 { 03902 int readformat, res; 03903 03904 if (ast_check_hangup(chan)) { 03905 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n"); 03906 return 0; 03907 } 03908 readformat = chan->readformat; 03909 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 03910 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name); 03911 return -1; 03912 } 03913 res = agi_exec_full(chan, data, 1, 0); 03914 if (!res) { 03915 if (ast_set_read_format(chan, readformat)) { 03916 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat)); 03917 } 03918 } 03919 return res; 03920 }
static agi_command * find_command | ( | const char *const | cmds[], | |
int | exact | |||
) | [static] |
Definition at line 3249 of file res_agi.c.
References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, agi_command::cmda, agi_command::list, and match().
03250 { 03251 int y, match; 03252 struct agi_command *e; 03253 03254 AST_RWLIST_RDLOCK(&agi_commands); 03255 AST_RWLIST_TRAVERSE(&agi_commands, e, list) { 03256 if (!e->cmda[0]) 03257 break; 03258 /* start optimistic */ 03259 match = 1; 03260 for (y = 0; match && cmds[y]; y++) { 03261 /* If there are no more words in the command (and we're looking for 03262 an exact match) or there is a difference between the two words, 03263 then this is not a match */ 03264 if (!e->cmda[y] && !exact) 03265 break; 03266 /* don't segfault if the next part of a command doesn't exist */ 03267 if (!e->cmda[y]) { 03268 AST_RWLIST_UNLOCK(&agi_commands); 03269 return NULL; 03270 } 03271 if (strcasecmp(e->cmda[y], cmds[y])) 03272 match = 0; 03273 } 03274 /* If more words are needed to complete the command then this is not 03275 a candidate (unless we're looking for a really inexact answer */ 03276 if ((exact > -1) && e->cmda[y]) 03277 match = 0; 03278 if (match) { 03279 AST_RWLIST_UNLOCK(&agi_commands); 03280 return e; 03281 } 03282 } 03283 AST_RWLIST_UNLOCK(&agi_commands); 03284 return NULL; 03285 }
static void free_agi_cmd | ( | struct agi_cmd * | cmd | ) | [static] |
Definition at line 975 of file res_agi.c.
References ast_free.
Referenced by agi_destroy_commands_cb(), and launch_asyncagi().
00976 { 00977 ast_free(cmd->cmd_buffer); 00978 ast_free(cmd->cmd_id); 00979 ast_free(cmd); 00980 }
static struct agi_cmd* get_agi_cmd | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1002 of file res_agi.c.
References agi_commands_datastore_info, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, agi_cmd::entry, LOG_ERROR, and ast_channel::name.
Referenced by launch_asyncagi().
01003 { 01004 struct ast_datastore *store; 01005 struct agi_cmd *cmd; 01006 AST_LIST_HEAD(, agi_cmd) *agi_commands; 01007 01008 ast_channel_lock(chan); 01009 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL); 01010 ast_channel_unlock(chan); 01011 if (!store) { 01012 ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n", 01013 chan->name); 01014 return NULL; 01015 } 01016 agi_commands = store->data; 01017 AST_LIST_LOCK(agi_commands); 01018 cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry); 01019 AST_LIST_UNLOCK(agi_commands); 01020 return cmd; 01021 }
static int handle_answer | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1763 of file res_agi.c.
References ast_channel::_state, ast_agi_send(), ast_answer(), AST_STATE_UP, agi_state::fd, RESULT_FAILURE, and RESULT_SUCCESS.
01764 { 01765 int res = 0; 01766 01767 /* Answer the channel */ 01768 if (chan->_state != AST_STATE_UP) 01769 res = ast_answer(chan); 01770 01771 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 01772 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 01773 }
static int handle_asyncagi_break | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1775 of file res_agi.c.
References ast_agi_send(), ASYNC_AGI_BREAK, and agi_state::fd.
01776 { 01777 ast_agi_send(agi->fd, chan, "200 result=0\n"); 01778 return ASYNC_AGI_BREAK; 01779 }
static int handle_autohangup | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2416 of file res_agi.c.
References ast_agi_send(), ast_channel_setwhentohangup_tv(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02417 { 02418 double timeout; 02419 struct timeval whentohangup = { 0, 0 }; 02420 02421 if (argc != 3) 02422 return RESULT_SHOWUSAGE; 02423 if (sscanf(argv[2], "%30lf", &timeout) != 1) 02424 return RESULT_SHOWUSAGE; 02425 if (timeout < 0) 02426 timeout = 0; 02427 if (timeout) { 02428 whentohangup.tv_sec = timeout; 02429 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0; 02430 } 02431 ast_channel_setwhentohangup_tv(chan, whentohangup); 02432 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02433 return RESULT_SUCCESS; 02434 }
static int handle_channelstatus | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2530 of file res_agi.c.
References ast_channel::_state, ast_agi_send(), ast_channel_get_by_name(), ast_channel_unref, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02531 { 02532 struct ast_channel *c; 02533 if (argc == 2) { 02534 /* no argument: supply info on the current channel */ 02535 ast_agi_send(agi->fd, chan, "200 result=%d\n", chan->_state); 02536 return RESULT_SUCCESS; 02537 } else if (argc == 3) { 02538 /* one argument: look for info on the specified channel */ 02539 if ((c = ast_channel_get_by_name(argv[2]))) { 02540 ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state); 02541 c = ast_channel_unref(c); 02542 return RESULT_SUCCESS; 02543 } 02544 /* if we get this far no channel name matched the argument given */ 02545 ast_agi_send(agi->fd, chan, "200 result=-1\n"); 02546 return RESULT_SUCCESS; 02547 } else { 02548 return RESULT_SHOWUSAGE; 02549 } 02550 }
static char* handle_cli_agi_add_cmd | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
CLI command to add applications to execute in Async AGI.
e | ||
cmd | ||
a |
CLI_SUCCESS | on success | |
NULL | when init or tab completion is used |
Definition at line 1101 of file res_agi.c.
References add_agi_cmd(), ast_cli_args::argc, ast_cli_args::argv, ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), ast_debug, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_channel::name, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
01102 { 01103 struct ast_channel *chan; 01104 switch (cmd) { 01105 case CLI_INIT: 01106 e->command = "agi exec"; 01107 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n" 01108 " Add AGI command to the execute queue of the specified channel in Async AGI\n"; 01109 return NULL; 01110 case CLI_GENERATE: 01111 if (a->pos == 2) 01112 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2); 01113 return NULL; 01114 } 01115 01116 if (a->argc < 4) { 01117 return CLI_SHOWUSAGE; 01118 } 01119 01120 if (!(chan = ast_channel_get_by_name(a->argv[2]))) { 01121 ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]); 01122 return CLI_FAILURE; 01123 } 01124 01125 ast_channel_lock(chan); 01126 01127 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) { 01128 ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", chan->name); 01129 ast_channel_unlock(chan); 01130 chan = ast_channel_unref(chan); 01131 return CLI_FAILURE; 01132 } 01133 01134 ast_debug(1, "Added AGI command to channel %s queue\n", chan->name); 01135 01136 ast_channel_unlock(chan); 01137 chan = ast_channel_unref(chan); 01138 01139 return CLI_SUCCESS; 01140 }
static char* handle_cli_agi_debug | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 2705 of file res_agi.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
02706 { 02707 switch (cmd) { 02708 case CLI_INIT: 02709 e->command = "agi set debug [on|off]"; 02710 e->usage = 02711 "Usage: agi set debug [on|off]\n" 02712 " Enables/disables dumping of AGI transactions for\n" 02713 " debugging purposes.\n"; 02714 return NULL; 02715 02716 case CLI_GENERATE: 02717 return NULL; 02718 } 02719 02720 if (a->argc != e->args) 02721 return CLI_SHOWUSAGE; 02722 02723 if (strncasecmp(a->argv[3], "off", 3) == 0) { 02724 agidebug = 0; 02725 } else if (strncasecmp(a->argv[3], "on", 2) == 0) { 02726 agidebug = 1; 02727 } else { 02728 return CLI_SHOWUSAGE; 02729 } 02730 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis"); 02731 return CLI_SUCCESS; 02732 }
static char* handle_cli_agi_dump_html | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 3801 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().
03802 { 03803 switch (cmd) { 03804 case CLI_INIT: 03805 e->command = "agi dump html"; 03806 e->usage = 03807 "Usage: agi dump html <filename>\n" 03808 " Dumps the AGI command list in HTML format to the given\n" 03809 " file.\n"; 03810 return NULL; 03811 case CLI_GENERATE: 03812 return NULL; 03813 } 03814 if (a->argc != e->args + 1) 03815 return CLI_SHOWUSAGE; 03816 03817 if (write_htmldump(a->argv[e->args]) < 0) { 03818 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]); 03819 return CLI_SHOWUSAGE; 03820 } 03821 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]); 03822 return CLI_SUCCESS; 03823 }
static char* handle_cli_agi_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 3608 of file res_agi.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_free, ast_join(), ast_malloc, AST_TERM_MAX_ESCAPE_CHARS, AST_XML_DOC, ast_xmldoc_printable(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_CYAN, COLOR_MAGENTA, ast_cli_entry::command, agi_command::dead, agi_command::docsrc, ast_cli_args::fd, find_command(), help_workhorse(), MAX_CMD_LEN, S_OR, agi_command::seealso, agi_command::summary, synopsis, agi_command::syntax, term_color(), agi_command::usage, and ast_cli_entry::usage.
03609 { 03610 struct agi_command *command; 03611 char fullcmd[MAX_CMD_LEN]; 03612 int error = 0; 03613 03614 switch (cmd) { 03615 case CLI_INIT: 03616 e->command = "agi show commands [topic]"; 03617 e->usage = 03618 "Usage: agi show commands [topic] <topic>\n" 03619 " When called with a topic as an argument, displays usage\n" 03620 " information on the given command. If called without a\n" 03621 " topic, it provides a list of AGI commands.\n"; 03622 case CLI_GENERATE: 03623 return NULL; 03624 } 03625 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic"))) 03626 return CLI_SHOWUSAGE; 03627 if (a->argc > e->args - 1) { 03628 command = find_command(a->argv + e->args, 1); 03629 if (command) { 03630 char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL; 03631 char info[30 + MAX_CMD_LEN]; /* '-= Info about...' */ 03632 char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS]; /* '-= Info about...' with colors */ 03633 char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */ 03634 char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Description]\n with colors */ 03635 char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Runs Dead]\n with colors */ 03636 char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS]; /* 'Yes' or 'No' with colors */ 03637 char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS]; /* [See Also]\n with colors */ 03638 char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */ 03639 size_t synlen, desclen, seealsolen, stxlen; 03640 03641 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle)); 03642 term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle)); 03643 term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle)); 03644 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle)); 03645 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle)); 03646 term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent)); 03647 03648 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args); 03649 snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd); 03650 term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle)); 03651 #ifdef AST_XML_DOCS 03652 if (command->docsrc == AST_XML_DOC) { 03653 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1); 03654 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1); 03655 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1); 03656 if (!seealso || !description || !synopsis) { 03657 error = 1; 03658 goto return_cleanup; 03659 } 03660 } else 03661 #endif 03662 { 03663 synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS; 03664 synopsis = ast_malloc(synlen); 03665 03666 desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS; 03667 description = ast_malloc(desclen); 03668 03669 seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS; 03670 seealso = ast_malloc(seealsolen); 03671 03672 if (!synopsis || !description || !seealso) { 03673 error = 1; 03674 goto return_cleanup; 03675 } 03676 term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen); 03677 term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen); 03678 term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen); 03679 } 03680 03681 stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS; 03682 syntax = ast_malloc(stxlen); 03683 if (!syntax) { 03684 error = 1; 03685 goto return_cleanup; 03686 } 03687 term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen); 03688 03689 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, 03690 desctitle, description, syntitle, synopsis, deadtitle, deadcontent, 03691 seealsotitle, seealso); 03692 return_cleanup: 03693 ast_free(synopsis); 03694 ast_free(description); 03695 ast_free(syntax); 03696 ast_free(seealso); 03697 } else { 03698 if (find_command(a->argv + e->args, -1)) { 03699 return help_workhorse(a->fd, a->argv + e->args); 03700 } else { 03701 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args); 03702 ast_cli(a->fd, "No such command '%s'.\n", fullcmd); 03703 } 03704 } 03705 } else { 03706 return help_workhorse(a->fd, NULL); 03707 } 03708 return (error ? CLI_FAILURE : CLI_SUCCESS); 03709 }
static int handle_controlstreamfile | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1894 of file res_agi.c.
References ast_agi_send(), ast_control_streamfile(), ast_strlen_zero(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, skipms, stop, and suspend().
01895 { 01896 int res = 0, skipms = 3000; 01897 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */ 01898 01899 if (argc < 5 || argc > 9) { 01900 return RESULT_SHOWUSAGE; 01901 } 01902 01903 if (!ast_strlen_zero(argv[4])) { 01904 stop = argv[4]; 01905 } 01906 01907 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) { 01908 return RESULT_SHOWUSAGE; 01909 } 01910 01911 if (argc > 6 && !ast_strlen_zero(argv[6])) { 01912 fwd = argv[6]; 01913 } 01914 01915 if (argc > 7 && !ast_strlen_zero(argv[7])) { 01916 rev = argv[7]; 01917 } 01918 01919 if (argc > 8 && !ast_strlen_zero(argv[8])) { 01920 suspend = argv[8]; 01921 } 01922 01923 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL); 01924 01925 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 01926 01927 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 01928 }
static int handle_dbdel | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2679 of file res_agi.c.
References ast_agi_send(), ast_db_del(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02680 { 02681 int res; 02682 02683 if (argc != 4) 02684 return RESULT_SHOWUSAGE; 02685 res = ast_db_del(argv[2], argv[3]); 02686 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1'); 02687 return RESULT_SUCCESS; 02688 }
static int handle_dbdeltree | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2690 of file res_agi.c.
References ast_agi_send(), ast_db_deltree(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02691 { 02692 int res; 02693 02694 if ((argc < 3) || (argc > 4)) 02695 return RESULT_SHOWUSAGE; 02696 if (argc == 4) 02697 res = ast_db_deltree(argv[2], argv[3]); 02698 else 02699 res = ast_db_deltree(argv[2], NULL); 02700 02701 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1'); 02702 return RESULT_SUCCESS; 02703 }
static int handle_dbget | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2635 of file res_agi.c.
References ast_agi_send(), ast_db_get(), ast_free, ast_str_buffer(), ast_str_create(), ast_str_make_space(), ast_str_size(), ast_str_strlen(), ast_str_update(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02636 { 02637 int res; 02638 struct ast_str *buf; 02639 02640 if (argc != 4) 02641 return RESULT_SHOWUSAGE; 02642 02643 if (!(buf = ast_str_create(16))) { 02644 ast_agi_send(agi->fd, chan, "200 result=-1\n"); 02645 return RESULT_SUCCESS; 02646 } 02647 02648 do { 02649 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf)); 02650 ast_str_update(buf); 02651 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) { 02652 break; 02653 } 02654 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) { 02655 break; 02656 } 02657 } while (1); 02658 02659 if (res) 02660 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02661 else 02662 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf)); 02663 02664 ast_free(buf); 02665 return RESULT_SUCCESS; 02666 }
static int handle_dbput | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2668 of file res_agi.c.
References ast_agi_send(), ast_db_put(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02669 { 02670 int res; 02671 02672 if (argc != 5) 02673 return RESULT_SHOWUSAGE; 02674 res = ast_db_put(argv[2], argv[3], argv[4]); 02675 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1'); 02676 return RESULT_SUCCESS; 02677 }
static int handle_exec | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2464 of file res_agi.c.
References ast_agi_send(), ast_clear_flag, ast_compat_res_agi, AST_FLAG_DISABLE_WORKAROUNDS, ast_log(), ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_verb, agi_state::fd, LOG_WARNING, pbx_exec(), pbx_findapp(), and RESULT_SHOWUSAGE.
02465 { 02466 int res, workaround; 02467 struct ast_app *app_to_exec; 02468 02469 if (argc < 2) 02470 return RESULT_SHOWUSAGE; 02471 02472 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : ""); 02473 02474 if ((app_to_exec = pbx_findapp(argv[1]))) { 02475 if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) { 02476 ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); 02477 } 02478 if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) { 02479 char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr; 02480 const char *vptr; 02481 for (cptr = compat, vptr = argv[2]; *vptr; vptr++) { 02482 if (*vptr == ',') { 02483 *cptr++ = '\\'; 02484 *cptr++ = ','; 02485 } else if (*vptr == '|') { 02486 *cptr++ = ','; 02487 } else { 02488 *cptr++ = *vptr; 02489 } 02490 } 02491 *cptr = '\0'; 02492 res = pbx_exec(chan, app_to_exec, compat); 02493 } else { 02494 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]); 02495 } 02496 if (!workaround) { 02497 ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); 02498 } 02499 } else { 02500 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]); 02501 res = -2; 02502 } 02503 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02504 02505 /* Even though this is wrong, users are depending upon this result. */ 02506 return res; 02507 }
static int handle_getdata | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2172 of file res_agi.c.
References ast_agi_send(), ast_app_getdata_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02173 { 02174 int res, max, timeout; 02175 char data[1024]; 02176 02177 if (argc < 3) 02178 return RESULT_SHOWUSAGE; 02179 if (argc >= 4) 02180 timeout = atoi(argv[3]); 02181 else 02182 timeout = 0; 02183 if (argc >= 5) 02184 max = atoi(argv[4]); 02185 else 02186 max = 1024; 02187 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl); 02188 if (res == 2) /* New command */ 02189 return RESULT_SUCCESS; 02190 else if (res == 1) 02191 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data); 02192 else if (res < 0 ) 02193 ast_agi_send(agi->fd, chan, "200 result=-1\n"); 02194 else 02195 ast_agi_send(agi->fd, chan, "200 result=%s\n", data); 02196 return RESULT_SUCCESS; 02197 }
static int handle_getoption | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
get option - really similar to the handle_streamfile, but with a timeout
Definition at line 1980 of file res_agi.c.
References ast_agi_send(), ast_applystream(), ast_debug, ast_log(), ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verb, ast_waitfordigit_full(), ast_waitstream_full(), agi_state::audio, agi_state::ctrl, ast_pbx::dtimeoutms, agi_state::fd, ast_channel::language, LOG_WARNING, ast_channel::pbx, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_filestream::vfs.
01981 { 01982 int res; 01983 struct ast_filestream *fs, *vfs; 01984 long sample_offset = 0, max_length; 01985 int timeout = 0; 01986 const char *edigits = ""; 01987 01988 if ( argc < 4 || argc > 5 ) 01989 return RESULT_SHOWUSAGE; 01990 01991 if ( argv[3] ) 01992 edigits = argv[3]; 01993 01994 if ( argc == 5 ) 01995 timeout = atoi(argv[4]); 01996 else if (chan->pbx->dtimeoutms) { 01997 /* by default dtimeout is set to 5sec */ 01998 timeout = chan->pbx->dtimeoutms; /* in msec */ 01999 } 02000 02001 if (!(fs = ast_openstream(chan, argv[2], chan->language))) { 02002 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset); 02003 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]); 02004 return RESULT_SUCCESS; 02005 } 02006 02007 if ((vfs = ast_openvstream(chan, argv[2], chan->language))) 02008 ast_debug(1, "Ooh, found a video stream, too\n"); 02009 02010 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout); 02011 02012 ast_seekstream(fs, 0, SEEK_END); 02013 max_length = ast_tellstream(fs); 02014 ast_seekstream(fs, sample_offset, SEEK_SET); 02015 res = ast_applystream(chan, fs); 02016 if (vfs) 02017 ast_applystream(chan, vfs); 02018 ast_playstream(fs); 02019 if (vfs) 02020 ast_playstream(vfs); 02021 02022 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); 02023 /* this is to check for if ast_waitstream closed the stream, we probably are at 02024 * the end of the stream, return that amount, else check for the amount */ 02025 sample_offset = (chan->stream)?ast_tellstream(fs):max_length; 02026 ast_stopstream(chan); 02027 if (res == 1) { 02028 /* Stop this command, don't print a result line, as there is a new command */ 02029 return RESULT_SUCCESS; 02030 } 02031 02032 /* If the user didnt press a key, wait for digitTimeout*/ 02033 if (res == 0 ) { 02034 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl); 02035 /* Make sure the new result is in the escape digits of the GET OPTION */ 02036 if ( !strchr(edigits,res) ) 02037 res=0; 02038 } 02039 02040 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset); 02041 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02042 }
static int handle_getvariable | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2561 of file res_agi.c.
References ast_agi_send(), ast_func_read(), ast_strlen_zero(), agi_state::fd, pbx_retrieve_variable(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02562 { 02563 char *ret; 02564 char tempstr[1024] = ""; 02565 02566 if (argc != 3) 02567 return RESULT_SHOWUSAGE; 02568 02569 /* check if we want to execute an ast_custom_function */ 02570 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) { 02571 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr; 02572 } else { 02573 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL); 02574 } 02575 02576 if (ret) 02577 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret); 02578 else 02579 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02580 02581 return RESULT_SUCCESS; 02582 }
static int handle_getvariablefull | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2584 of file res_agi.c.
References ast_agi_send(), ast_channel_get_by_name(), ast_channel_ref, ast_channel_unref, ast_free, ast_str_buffer(), ast_str_create(), ast_str_substitute_variables(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and str.
02585 { 02586 struct ast_channel *chan2 = NULL; 02587 02588 if (argc != 4 && argc != 5) { 02589 return RESULT_SHOWUSAGE; 02590 } 02591 02592 if (argc == 5) { 02593 chan2 = ast_channel_get_by_name(argv[4]); 02594 } else { 02595 chan2 = ast_channel_ref(chan); 02596 } 02597 02598 if (chan2) { 02599 struct ast_str *str = ast_str_create(16); 02600 if (!str) { 02601 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02602 return RESULT_SUCCESS; 02603 } 02604 ast_str_substitute_variables(&str, 0, chan2, argv[3]); 02605 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str)); 02606 ast_free(str); 02607 } else { 02608 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02609 } 02610 02611 if (chan2) { 02612 chan2 = ast_channel_unref(chan2); 02613 } 02614 02615 return RESULT_SUCCESS; 02616 }
static int handle_hangup | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2436 of file res_agi.c.
References ast_agi_send(), ast_channel_get_by_name(), ast_channel_unref, ast_set_hangupsource(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02437 { 02438 struct ast_channel *c; 02439 02440 if (argc == 1) { 02441 /* no argument: hangup the current channel */ 02442 ast_set_hangupsource(chan, "dialplan/agi", 0); 02443 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); 02444 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02445 return RESULT_SUCCESS; 02446 } else if (argc == 2) { 02447 /* one argument: look for info on the specified channel */ 02448 if ((c = ast_channel_get_by_name(argv[1]))) { 02449 /* we have a matching channel */ 02450 ast_set_hangupsource(c, "dialplan/agi", 0); 02451 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT); 02452 c = ast_channel_unref(c); 02453 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02454 return RESULT_SUCCESS; 02455 } 02456 /* if we get this far no channel name matched the argument given */ 02457 ast_agi_send(agi->fd, chan, "200 result=-1\n"); 02458 return RESULT_SUCCESS; 02459 } else { 02460 return RESULT_SHOWUSAGE; 02461 } 02462 }
static int handle_noop | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | arg, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2734 of file res_agi.c.
References ast_agi_send(), agi_state::fd, and RESULT_SUCCESS.
02735 { 02736 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02737 return RESULT_SUCCESS; 02738 }
static int handle_recordfile | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2237 of file res_agi.c.
References ast_agi_send(), ast_applystream(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FILE_MODE, AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log(), ast_read(), ast_seekstream(), ast_set_read_format(), ast_stream_rewind(), ast_streamfile(), ast_tellstream(), ast_truncstream(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), f, agi_state::fd, ast_channel::language, LOG_WARNING, ast_channel::name, ast_channel::readformat, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, THRESHOLD_SILENCE, and ast_dsp::totalsilence.
02238 { 02239 struct ast_filestream *fs; 02240 struct ast_frame *f; 02241 struct timeval start; 02242 long sample_offset = 0; 02243 int res = 0; 02244 int ms; 02245 02246 struct ast_dsp *sildet=NULL; /* silence detector dsp */ 02247 int totalsilence = 0; 02248 int dspsilence = 0; 02249 int silence = 0; /* amount of silence to allow */ 02250 int gotsilence = 0; /* did we timeout for silence? */ 02251 char *silencestr = NULL; 02252 int rfmt = 0; 02253 02254 /* XXX EAGI FIXME XXX */ 02255 02256 if (argc < 6) 02257 return RESULT_SHOWUSAGE; 02258 if (sscanf(argv[5], "%30d", &ms) != 1) 02259 return RESULT_SHOWUSAGE; 02260 02261 if (argc > 6) 02262 silencestr = strchr(argv[6],'s'); 02263 if ((argc > 7) && (!silencestr)) 02264 silencestr = strchr(argv[7],'s'); 02265 if ((argc > 8) && (!silencestr)) 02266 silencestr = strchr(argv[8],'s'); 02267 02268 if (silencestr) { 02269 if (strlen(silencestr) > 2) { 02270 if ((silencestr[0] == 's') && (silencestr[1] == '=')) { 02271 silencestr++; 02272 silencestr++; 02273 if (silencestr) 02274 silence = atoi(silencestr); 02275 if (silence > 0) 02276 silence *= 1000; 02277 } 02278 } 02279 } 02280 02281 if (silence > 0) { 02282 rfmt = chan->readformat; 02283 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 02284 if (res < 0) { 02285 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 02286 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02287 return RESULT_FAILURE; 02288 } 02289 sildet = ast_dsp_new(); 02290 if (!sildet) { 02291 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 02292 ast_agi_send(agi->fd, chan, "200 result=-1\n"); 02293 return RESULT_FAILURE; 02294 } 02295 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); 02296 } 02297 02298 /* backward compatibility, if no offset given, arg[6] would have been 02299 * caught below and taken to be a beep, else if it is a digit then it is a 02300 * offset */ 02301 if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '='))) 02302 res = ast_streamfile(chan, "beep", chan->language); 02303 02304 if ((argc > 7) && (!strchr(argv[7], '='))) 02305 res = ast_streamfile(chan, "beep", chan->language); 02306 02307 if (!res) 02308 res = ast_waitstream(chan, argv[4]); 02309 if (res) { 02310 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); 02311 } else { 02312 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE); 02313 if (!fs) { 02314 res = -1; 02315 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res); 02316 if (sildet) 02317 ast_dsp_free(sildet); 02318 return RESULT_FAILURE; 02319 } 02320 02321 /* Request a video update */ 02322 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 02323 02324 chan->stream = fs; 02325 ast_applystream(chan,fs); 02326 /* really should have checks */ 02327 ast_seekstream(fs, sample_offset, SEEK_SET); 02328 ast_truncstream(fs); 02329 02330 start = ast_tvnow(); 02331 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) { 02332 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start)); 02333 if (res < 0) { 02334 ast_closestream(fs); 02335 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); 02336 if (sildet) 02337 ast_dsp_free(sildet); 02338 return RESULT_FAILURE; 02339 } 02340 f = ast_read(chan); 02341 if (!f) { 02342 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset); 02343 ast_closestream(fs); 02344 if (sildet) 02345 ast_dsp_free(sildet); 02346 return RESULT_FAILURE; 02347 } 02348 switch(f->frametype) { 02349 case AST_FRAME_DTMF: 02350 if (strchr(argv[4], f->subclass.integer)) { 02351 /* This is an interrupting chracter, so rewind to chop off any small 02352 amount of DTMF that may have been recorded 02353 */ 02354 ast_stream_rewind(fs, 200); 02355 ast_truncstream(fs); 02356 sample_offset = ast_tellstream(fs); 02357 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset); 02358 ast_closestream(fs); 02359 ast_frfree(f); 02360 if (sildet) 02361 ast_dsp_free(sildet); 02362 return RESULT_SUCCESS; 02363 } 02364 break; 02365 case AST_FRAME_VOICE: 02366 ast_writestream(fs, f); 02367 /* this is a safe place to check progress since we know that fs 02368 * is valid after a write, and it will then have our current 02369 * location */ 02370 sample_offset = ast_tellstream(fs); 02371 if (silence > 0) { 02372 dspsilence = 0; 02373 ast_dsp_silence(sildet, f, &dspsilence); 02374 if (dspsilence) { 02375 totalsilence = dspsilence; 02376 } else { 02377 totalsilence = 0; 02378 } 02379 if (totalsilence > silence) { 02380 /* Ended happily with silence */ 02381 gotsilence = 1; 02382 break; 02383 } 02384 } 02385 break; 02386 case AST_FRAME_VIDEO: 02387 ast_writestream(fs, f); 02388 default: 02389 /* Ignore all other frames */ 02390 break; 02391 } 02392 ast_frfree(f); 02393 if (gotsilence) 02394 break; 02395 } 02396 02397 if (gotsilence) { 02398 ast_stream_rewind(fs, silence-1000); 02399 ast_truncstream(fs); 02400 sample_offset = ast_tellstream(fs); 02401 } 02402 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); 02403 ast_closestream(fs); 02404 } 02405 02406 if (silence > 0) { 02407 res = ast_set_read_format(chan, rfmt); 02408 if (res) 02409 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); 02410 ast_dsp_free(sildet); 02411 } 02412 02413 return RESULT_SUCCESS; 02414 }
static int handle_recvchar | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1813 of file res_agi.c.
References ast_agi_send(), ast_recvchar(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01814 { 01815 int res; 01816 01817 if (argc != 3) 01818 return RESULT_SHOWUSAGE; 01819 01820 res = ast_recvchar(chan,atoi(argv[2])); 01821 if (res == 0) { 01822 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res); 01823 return RESULT_SUCCESS; 01824 } 01825 if (res > 0) { 01826 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 01827 return RESULT_SUCCESS; 01828 } 01829 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res); 01830 return RESULT_FAILURE; 01831 }
static int handle_recvtext | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1833 of file res_agi.c.
References ast_agi_send(), ast_free, ast_recvtext(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01834 { 01835 char *buf; 01836 01837 if (argc != 3) 01838 return RESULT_SHOWUSAGE; 01839 01840 buf = ast_recvtext(chan, atoi(argv[2])); 01841 if (buf) { 01842 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf); 01843 ast_free(buf); 01844 } else { 01845 ast_agi_send(agi->fd, chan, "200 result=-1\n"); 01846 } 01847 return RESULT_SUCCESS; 01848 }
static int handle_sayalpha | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2080 of file res_agi.c.
References ast_agi_send(), ast_say_character_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02081 { 02082 int res; 02083 02084 if (argc != 4) 02085 return RESULT_SHOWUSAGE; 02086 02087 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); 02088 if (res == 1) /* New command */ 02089 return RESULT_SUCCESS; 02090 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02091 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02092 }
static int handle_saydate | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2094 of file res_agi.c.
References ast_agi_send(), ast_say_date, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02095 { 02096 int res, num; 02097 02098 if (argc != 4) 02099 return RESULT_SHOWUSAGE; 02100 if (sscanf(argv[2], "%30d", &num) != 1) 02101 return RESULT_SHOWUSAGE; 02102 res = ast_say_date(chan, num, argv[3], chan->language); 02103 if (res == 1) 02104 return RESULT_SUCCESS; 02105 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02106 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02107 }
static int handle_saydatetime | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2124 of file res_agi.c.
References ast_agi_send(), ast_get_time_t(), ast_say_date_with_format, ast_strlen_zero(), agi_state::fd, format, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02125 { 02126 int res = 0; 02127 time_t unixtime; 02128 const char *format, *zone = NULL; 02129 02130 if (argc < 4) 02131 return RESULT_SHOWUSAGE; 02132 02133 if (argc > 4) { 02134 format = argv[4]; 02135 } else { 02136 /* XXX this doesn't belong here, but in the 'say' module */ 02137 if (!strcasecmp(chan->language, "de")) { 02138 format = "A dBY HMS"; 02139 } else { 02140 format = "ABdY 'digits/at' IMp"; 02141 } 02142 } 02143 02144 if (argc > 5 && !ast_strlen_zero(argv[5])) 02145 zone = argv[5]; 02146 02147 if (ast_get_time_t(argv[2], &unixtime, 0, NULL)) 02148 return RESULT_SHOWUSAGE; 02149 02150 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone); 02151 if (res == 1) 02152 return RESULT_SUCCESS; 02153 02154 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02155 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02156 }
static int handle_saydigits | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2064 of file res_agi.c.
References ast_agi_send(), ast_say_digit_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02065 { 02066 int res, num; 02067 02068 if (argc != 4) 02069 return RESULT_SHOWUSAGE; 02070 if (sscanf(argv[2], "%30d", &num) != 1) 02071 return RESULT_SHOWUSAGE; 02072 02073 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); 02074 if (res == 1) /* New command */ 02075 return RESULT_SUCCESS; 02076 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02077 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02078 }
static int handle_saynumber | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Say number in various language syntaxes.
Definition at line 2049 of file res_agi.c.
References ast_agi_send(), ast_say_number_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02050 { 02051 int res, num; 02052 02053 if (argc < 4 || argc > 5) 02054 return RESULT_SHOWUSAGE; 02055 if (sscanf(argv[2], "%30d", &num) != 1) 02056 return RESULT_SHOWUSAGE; 02057 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl); 02058 if (res == 1) 02059 return RESULT_SUCCESS; 02060 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02061 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02062 }
static int handle_sayphonetic | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2158 of file res_agi.c.
References ast_agi_send(), ast_say_phonetic_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02159 { 02160 int res; 02161 02162 if (argc != 4) 02163 return RESULT_SHOWUSAGE; 02164 02165 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); 02166 if (res == 1) /* New command */ 02167 return RESULT_SUCCESS; 02168 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02169 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02170 }
static int handle_saytime | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2109 of file res_agi.c.
References ast_agi_send(), ast_say_time, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02110 { 02111 int res, num; 02112 02113 if (argc != 4) 02114 return RESULT_SHOWUSAGE; 02115 if (sscanf(argv[2], "%30d", &num) != 1) 02116 return RESULT_SHOWUSAGE; 02117 res = ast_say_time(chan, num, argv[3], chan->language); 02118 if (res == 1) 02119 return RESULT_SUCCESS; 02120 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 02121 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 02122 }
static int handle_sendimage | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1878 of file res_agi.c.
References ast_agi_send(), ast_check_hangup(), ast_send_image(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01879 { 01880 int res; 01881 01882 if (argc != 3) { 01883 return RESULT_SHOWUSAGE; 01884 } 01885 01886 res = ast_send_image(chan, argv[2]); 01887 if (!ast_check_hangup(chan)) { 01888 res = 0; 01889 } 01890 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 01891 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 01892 }
static int handle_sendtext | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1794 of file res_agi.c.
References ast_agi_send(), ast_sendtext(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01795 { 01796 int res; 01797 01798 if (argc != 3) 01799 return RESULT_SHOWUSAGE; 01800 01801 /* At the moment, the parser (perhaps broken) returns with 01802 the last argument PLUS the newline at the end of the input 01803 buffer. This probably needs to be fixed, but I wont do that 01804 because other stuff may break as a result. The right way 01805 would probably be to strip off the trailing newline before 01806 parsing, then here, add a newline at the end of the string 01807 before sending it to ast_sendtext --DUDE */ 01808 res = ast_sendtext(chan, argv[2]); 01809 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 01810 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 01811 }
static int handle_setcallerid | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2509 of file res_agi.c.
References ast_agi_send(), ast_callerid_parse(), ast_copy_string(), ast_set_callerid(), ast_shrink_phone_number(), agi_state::fd, and RESULT_SUCCESS.
02510 { 02511 char tmp[256]=""; 02512 char *l = NULL, *n = NULL; 02513 02514 if (argv[2]) { 02515 ast_copy_string(tmp, argv[2], sizeof(tmp)); 02516 ast_callerid_parse(tmp, &n, &l); 02517 if (l) 02518 ast_shrink_phone_number(l); 02519 else 02520 l = ""; 02521 if (!n) 02522 n = ""; 02523 ast_set_callerid(chan, l, n, NULL); 02524 } 02525 02526 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02527 return RESULT_SUCCESS; 02528 }
static int handle_setcontext | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2199 of file res_agi.c.
References ast_agi_send(), ast_copy_string(), ast_channel::context, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02200 { 02201 02202 if (argc != 3) 02203 return RESULT_SHOWUSAGE; 02204 ast_copy_string(chan->context, argv[2], sizeof(chan->context)); 02205 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02206 return RESULT_SUCCESS; 02207 }
static int handle_setextension | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2209 of file res_agi.c.
References ast_agi_send(), ast_copy_string(), ast_channel::exten, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02210 { 02211 if (argc != 3) 02212 return RESULT_SHOWUSAGE; 02213 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten)); 02214 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02215 return RESULT_SUCCESS; 02216 }
static int handle_setmusic | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2740 of file res_agi.c.
References ast_agi_send(), ast_moh_start(), ast_moh_stop(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02741 { 02742 if (argc < 3) { 02743 return RESULT_SHOWUSAGE; 02744 } 02745 if (!strncasecmp(argv[2], "on", 2)) 02746 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL); 02747 else if (!strncasecmp(argv[2], "off", 3)) 02748 ast_moh_stop(chan); 02749 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02750 return RESULT_SUCCESS; 02751 }
static int handle_setpriority | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2218 of file res_agi.c.
References ast_agi_send(), ast_explicit_goto(), ast_findlabel_extension(), ast_channel::caller, ast_channel::context, ast_channel::exten, agi_state::fd, ast_party_caller::id, ast_party_id::number, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, ast_party_number::str, and ast_party_number::valid.
02219 { 02220 int pri; 02221 02222 if (argc != 3) 02223 return RESULT_SHOWUSAGE; 02224 02225 if (sscanf(argv[2], "%30d", &pri) != 1) { 02226 pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], 02227 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)); 02228 if (pri < 1) 02229 return RESULT_SHOWUSAGE; 02230 } 02231 02232 ast_explicit_goto(chan, NULL, NULL, pri); 02233 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02234 return RESULT_SUCCESS; 02235 }
static int handle_setvariable | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2552 of file res_agi.c.
References ast_agi_send(), agi_state::fd, pbx_builtin_setvar_helper(), and RESULT_SUCCESS.
02553 { 02554 if (argv[3]) 02555 pbx_builtin_setvar_helper(chan, argv[2], argv[3]); 02556 02557 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02558 return RESULT_SUCCESS; 02559 }
static int handle_speechactivategrammar | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2836 of file res_agi.c.
References ast_agi_send(), ast_speech_grammar_activate(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.
02837 { 02838 if (argc != 4) 02839 return RESULT_SHOWUSAGE; 02840 02841 if (!agi->speech) { 02842 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02843 return RESULT_SUCCESS; 02844 } 02845 02846 if (ast_speech_grammar_activate(agi->speech, argv[3])) 02847 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02848 else 02849 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02850 02851 return RESULT_SUCCESS; 02852 }
static int handle_speechcreate | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2753 of file res_agi.c.
References ast_agi_send(), AST_FORMAT_SLINEAR, ast_speech_new(), agi_state::fd, RESULT_SUCCESS, and agi_state::speech.
02754 { 02755 /* If a structure already exists, return an error */ 02756 if (agi->speech) { 02757 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02758 return RESULT_SUCCESS; 02759 } 02760 02761 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR))) 02762 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02763 else 02764 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02765 02766 return RESULT_SUCCESS; 02767 }
static int handle_speechdeactivategrammar | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2854 of file res_agi.c.
References ast_agi_send(), ast_speech_grammar_deactivate(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.
02855 { 02856 if (argc != 4) 02857 return RESULT_SHOWUSAGE; 02858 02859 if (!agi->speech) { 02860 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02861 return RESULT_SUCCESS; 02862 } 02863 02864 if (ast_speech_grammar_deactivate(agi->speech, argv[3])) 02865 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02866 else 02867 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02868 02869 return RESULT_SUCCESS; 02870 }
static int handle_speechdestroy | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2787 of file res_agi.c.
References ast_agi_send(), ast_speech_destroy(), agi_state::fd, RESULT_SUCCESS, and agi_state::speech.
02788 { 02789 if (agi->speech) { 02790 ast_speech_destroy(agi->speech); 02791 agi->speech = NULL; 02792 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02793 } else { 02794 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02795 } 02796 02797 return RESULT_SUCCESS; 02798 }
static int handle_speechloadgrammar | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2800 of file res_agi.c.
References ast_agi_send(), ast_speech_grammar_load(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.
02801 { 02802 if (argc != 5) 02803 return RESULT_SHOWUSAGE; 02804 02805 if (!agi->speech) { 02806 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02807 return RESULT_SUCCESS; 02808 } 02809 02810 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4])) 02811 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02812 else 02813 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02814 02815 return RESULT_SUCCESS; 02816 }
static int handle_speechrecognize | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2891 of file res_agi.c.
References ast_agi_send(), ast_build_string(), ast_clear_flag, AST_CONTROL_HANGUP, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_sched_runq(), ast_sched_wait(), ast_set_read_format(), ast_speech_change_state(), AST_SPEECH_QUIET, ast_speech_results_get(), ast_speech_start(), AST_SPEECH_STATE_DONE, AST_SPEECH_STATE_NOT_READY, AST_SPEECH_STATE_READY, AST_SPEECH_STATE_WAIT, ast_speech_write(), ast_stopstream(), ast_strlen_zero(), ast_tellstream(), ast_test_flag, ast_waitfor(), ast_frame::data, ast_frame::datalen, agi_state::fd, ast_frame::frametype, ast_speech_result::grammar, ast_frame_subclass::integer, ast_channel::language, ast_speech::lock, prompt, ast_frame::ptr, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_speech::results, ast_channel::sched, ast_speech_result::score, agi_state::speech, speech_streamfile(), ast_speech::state, ast_channel::stream, ast_channel::streamid, ast_frame::subclass, ast_speech_result::text, and ast_channel::timingfunc.
02892 { 02893 struct ast_speech *speech = agi->speech; 02894 const char *prompt; 02895 char dtmf = 0, tmp[4096] = "", *buf = tmp; 02896 int timeout = 0, offset = 0, res = 0, i = 0; 02897 long current_offset = 0; 02898 const char *reason = NULL; 02899 struct ast_frame *fr = NULL; 02900 struct ast_speech_result *result = NULL; 02901 size_t left = sizeof(tmp); 02902 time_t start = 0, current; 02903 02904 if (argc < 4) 02905 return RESULT_SHOWUSAGE; 02906 02907 if (!speech) { 02908 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02909 return RESULT_SUCCESS; 02910 } 02911 02912 prompt = argv[2]; 02913 timeout = atoi(argv[3]); 02914 02915 /* If offset is specified then convert from text to integer */ 02916 if (argc == 5) 02917 offset = atoi(argv[4]); 02918 02919 /* We want frames coming in signed linear */ 02920 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 02921 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02922 return RESULT_SUCCESS; 02923 } 02924 02925 /* Setup speech structure */ 02926 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) { 02927 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY); 02928 ast_speech_start(speech); 02929 } 02930 02931 /* Start playing prompt */ 02932 speech_streamfile(chan, prompt, chan->language, offset); 02933 02934 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */ 02935 while (ast_strlen_zero(reason)) { 02936 /* Run scheduled items */ 02937 ast_sched_runq(chan->sched); 02938 02939 /* See maximum time of waiting */ 02940 if ((res = ast_sched_wait(chan->sched)) < 0) 02941 res = 1000; 02942 02943 /* Wait for frame */ 02944 if (ast_waitfor(chan, res) > 0) { 02945 if (!(fr = ast_read(chan))) { 02946 reason = "hangup"; 02947 break; 02948 } 02949 } 02950 02951 /* Perform timeout check */ 02952 if ((timeout > 0) && (start > 0)) { 02953 time(¤t); 02954 if ((current - start) >= timeout) { 02955 reason = "timeout"; 02956 if (fr) 02957 ast_frfree(fr); 02958 break; 02959 } 02960 } 02961 02962 /* Check the speech structure for any changes */ 02963 ast_mutex_lock(&speech->lock); 02964 02965 /* See if we need to quiet the audio stream playback */ 02966 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) { 02967 current_offset = ast_tellstream(chan->stream); 02968 ast_stopstream(chan); 02969 ast_clear_flag(speech, AST_SPEECH_QUIET); 02970 } 02971 02972 /* Check each state */ 02973 switch (speech->state) { 02974 case AST_SPEECH_STATE_READY: 02975 /* If the stream is done, start timeout calculation */ 02976 if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) { 02977 ast_stopstream(chan); 02978 time(&start); 02979 } 02980 /* Write audio frame data into speech engine if possible */ 02981 if (fr && fr->frametype == AST_FRAME_VOICE) 02982 ast_speech_write(speech, fr->data.ptr, fr->datalen); 02983 break; 02984 case AST_SPEECH_STATE_WAIT: 02985 /* Cue waiting sound if not already playing */ 02986 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) { 02987 ast_stopstream(chan); 02988 /* If a processing sound exists, or is not none - play it */ 02989 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none")) 02990 speech_streamfile(chan, speech->processing_sound, chan->language, 0); 02991 } 02992 break; 02993 case AST_SPEECH_STATE_DONE: 02994 /* Get the results */ 02995 speech->results = ast_speech_results_get(speech); 02996 /* Change state to not ready */ 02997 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY); 02998 reason = "speech"; 02999 break; 03000 default: 03001 break; 03002 } 03003 ast_mutex_unlock(&speech->lock); 03004 03005 /* Check frame for DTMF or hangup */ 03006 if (fr) { 03007 if (fr->frametype == AST_FRAME_DTMF) { 03008 reason = "dtmf"; 03009 dtmf = fr->subclass.integer; 03010 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) { 03011 reason = "hangup"; 03012 } 03013 ast_frfree(fr); 03014 } 03015 } 03016 03017 if (!strcasecmp(reason, "speech")) { 03018 /* Build string containing speech results */ 03019 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) { 03020 /* Build result string */ 03021 ast_build_string(&buf, &left, "%sscore%d=%d text%d=\"%s\" grammar%d=%s", (i > 0 ? " " : ""), i, result->score, i, result->text, i, result->grammar); 03022 /* Increment result count */ 03023 i++; 03024 } 03025 /* Print out */ 03026 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp); 03027 } else if (!strcasecmp(reason, "dtmf")) { 03028 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset); 03029 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) { 03030 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset); 03031 } else { 03032 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset); 03033 } 03034 03035 return RESULT_SUCCESS; 03036 }
static int handle_speechset | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2769 of file res_agi.c.
References ast_agi_send(), ast_speech_change(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.
02770 { 02771 /* Check for minimum arguments */ 02772 if (argc != 4) 02773 return RESULT_SHOWUSAGE; 02774 02775 /* Check to make sure speech structure exists */ 02776 if (!agi->speech) { 02777 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02778 return RESULT_SUCCESS; 02779 } 02780 02781 ast_speech_change(agi->speech, argv[2], argv[3]); 02782 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02783 02784 return RESULT_SUCCESS; 02785 }
static int handle_speechunloadgrammar | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2818 of file res_agi.c.
References ast_agi_send(), ast_speech_grammar_unload(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.
02819 { 02820 if (argc != 4) 02821 return RESULT_SHOWUSAGE; 02822 02823 if (!agi->speech) { 02824 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02825 return RESULT_SUCCESS; 02826 } 02827 02828 if (ast_speech_grammar_unload(agi->speech, argv[3])) 02829 ast_agi_send(agi->fd, chan, "200 result=0\n"); 02830 else 02831 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02832 02833 return RESULT_SUCCESS; 02834 }
static int handle_streamfile | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1930 of file res_agi.c.
References ast_agi_send(), ast_applystream(), ast_debug, ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verb, ast_waitstream_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_filestream::vfs.
01931 { 01932 int res; 01933 struct ast_filestream *fs, *vfs; 01934 long sample_offset = 0, max_length; 01935 const char *edigits = ""; 01936 01937 if (argc < 4 || argc > 5) 01938 return RESULT_SHOWUSAGE; 01939 01940 if (argv[3]) 01941 edigits = argv[3]; 01942 01943 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) 01944 return RESULT_SHOWUSAGE; 01945 01946 if (!(fs = ast_openstream(chan, argv[2], chan->language))) { 01947 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset); 01948 return RESULT_SUCCESS; 01949 } 01950 01951 if ((vfs = ast_openvstream(chan, argv[2], chan->language))) 01952 ast_debug(1, "Ooh, found a video stream, too\n"); 01953 01954 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset); 01955 01956 ast_seekstream(fs, 0, SEEK_END); 01957 max_length = ast_tellstream(fs); 01958 ast_seekstream(fs, sample_offset, SEEK_SET); 01959 res = ast_applystream(chan, fs); 01960 if (vfs) 01961 ast_applystream(chan, vfs); 01962 ast_playstream(fs); 01963 if (vfs) 01964 ast_playstream(vfs); 01965 01966 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); 01967 /* this is to check for if ast_waitstream closed the stream, we probably are at 01968 * the end of the stream, return that amount, else check for the amount */ 01969 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length; 01970 ast_stopstream(chan); 01971 if (res == 1) { 01972 /* Stop this command, don't print a result line, as there is a new command */ 01973 return RESULT_SUCCESS; 01974 } 01975 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset); 01976 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 01977 }
static int handle_tddmode | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1850 of file res_agi.c.
References ast_agi_send(), ast_channel_setoption(), AST_OPTION_TDD, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01851 { 01852 int res, x; 01853 01854 if (argc != 3) 01855 return RESULT_SHOWUSAGE; 01856 01857 if (!strncasecmp(argv[2],"on",2)) { 01858 x = 1; 01859 } else { 01860 x = 0; 01861 } 01862 if (!strncasecmp(argv[2],"mate",4)) { 01863 x = 2; 01864 } 01865 if (!strncasecmp(argv[2],"tdd",3)) { 01866 x = 1; 01867 } 01868 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0); 01869 if (res) { 01870 /* Set channel option failed */ 01871 ast_agi_send(agi->fd, chan, "200 result=0\n"); 01872 } else { 01873 ast_agi_send(agi->fd, chan, "200 result=1\n"); 01874 } 01875 return RESULT_SUCCESS; 01876 }
static int handle_verbose | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 2618 of file res_agi.c.
References ast_agi_send(), ast_verb, ast_channel::data, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
02619 { 02620 int level = 0; 02621 02622 if (argc < 2) 02623 return RESULT_SHOWUSAGE; 02624 02625 if (argv[2]) 02626 sscanf(argv[2], "%30d", &level); 02627 02628 ast_verb(level, "%s: %s\n", chan->data, argv[1]); 02629 02630 ast_agi_send(agi->fd, chan, "200 result=1\n"); 02631 02632 return RESULT_SUCCESS; 02633 }
static int handle_waitfordigit | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const | argv[] | |||
) | [static] |
Definition at line 1781 of file res_agi.c.
References ast_agi_send(), ast_waitfordigit_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01782 { 01783 int res, to; 01784 01785 if (argc != 4) 01786 return RESULT_SHOWUSAGE; 01787 if (sscanf(argv[3], "%30d", &to) != 1) 01788 return RESULT_SHOWUSAGE; 01789 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl); 01790 ast_agi_send(agi->fd, chan, "200 result=%d\n", res); 01791 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 01792 }
static char* help_workhorse | ( | int | fd, | |
const char *const | match[] | |||
) | [static] |
Definition at line 3092 of file res_agi.c.
References ast_cli(), ast_join(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_SUCCESS, agi_command::cmda, agi_command::dead, agi_command::list, MAX_CMD_LEN, S_OR, and agi_command::summary.
Referenced by handle_cli_agi_show().
03093 { 03094 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN]; 03095 struct agi_command *e; 03096 03097 if (match) 03098 ast_join(matchstr, sizeof(matchstr), match); 03099 03100 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description"); 03101 AST_RWLIST_RDLOCK(&agi_commands); 03102 AST_RWLIST_TRAVERSE(&agi_commands, e, list) { 03103 if (!e->cmda[0]) 03104 break; 03105 /* Hide commands that start with '_' */ 03106 if ((e->cmda[0])[0] == '_') 03107 continue; 03108 ast_join(fullcmd, sizeof(fullcmd), e->cmda); 03109 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr))) 03110 continue; 03111 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available")); 03112 } 03113 AST_RWLIST_UNLOCK(&agi_commands); 03114 03115 return CLI_SUCCESS; 03116 }
static enum agi_result launch_asyncagi | ( | struct ast_channel * | chan, | |
char * | argv[], | |||
int * | efd | |||
) | [static] |
Definition at line 1231 of file res_agi.c.
References add_to_agi(), AGI_BUF_SIZE, agi_handle_command(), AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, AMI_BUF_SIZE, ast_check_hangup(), ast_debug, ast_log(), ast_speech_destroy(), ast_strlen_zero(), ast_uri_encode(), ast_waitfor(), async_agi_read_frame(), agi_state::audio, agi_cmd::cmd_buffer, agi_cmd::cmd_id, agi_state::ctrl, EVENT_FLAG_AGI, agi_state::fast, agi_state::fd, free_agi_cmd(), get_agi_cmd(), LOG_ERROR, LOG_WARNING, manager_event, ast_channel::name, setup_env(), and agi_state::speech.
Referenced by launch_script().
01232 { 01233 /* This buffer sizes might cause truncation if the AGI command writes more data 01234 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command 01235 that writes a response larger than 1024 bytes?, I don't think so, most of 01236 them are just result=blah stuff. However probably if GET VARIABLE is called 01237 and the variable has large amount of data, that could be a problem. We could 01238 make this buffers dynamic, but let's leave that as a second step. 01239 01240 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe 01241 number. Some characters of AGI buf will be url encoded to be sent to manager 01242 clients. An URL encoded character will take 3 bytes, but again, to cause 01243 truncation more than about 70% of the AGI buffer should be URL encoded for 01244 that to happen. Not likely at all. 01245 01246 On the other hand. I wonder if read() could eventually return less data than 01247 the amount already available in the pipe? If so, how to deal with that? 01248 So far, my tests on Linux have not had any problems. 01249 */ 01250 #define AGI_BUF_SIZE 1024 01251 #define AMI_BUF_SIZE 2048 01252 enum agi_result cmd_status; 01253 struct agi_cmd *cmd; 01254 int res; 01255 int fds[2]; 01256 int hungup; 01257 int timeout = 100; 01258 char agi_buffer[AGI_BUF_SIZE + 1]; 01259 char ami_buffer[AMI_BUF_SIZE]; 01260 enum agi_result returnstatus = AGI_RESULT_SUCCESS; 01261 AGI async_agi; 01262 01263 if (efd) { 01264 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n"); 01265 return AGI_RESULT_FAILURE; 01266 } 01267 01268 /* add AsyncAGI datastore to the channel */ 01269 if (add_to_agi(chan)) { 01270 ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", chan->name); 01271 return AGI_RESULT_FAILURE; 01272 } 01273 01274 /* this pipe allows us to create a "fake" AGI struct to use 01275 the AGI commands */ 01276 res = pipe(fds); 01277 if (res) { 01278 ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n"); 01279 /* 01280 * Intentionally do not remove the datastore added with 01281 * add_to_agi() the from channel. It will be removed when the 01282 * channel is hung up anyway. 01283 */ 01284 return AGI_RESULT_FAILURE; 01285 } 01286 01287 /* handlers will get the pipe write fd and we read the AGI responses 01288 from the pipe read fd */ 01289 async_agi.fd = fds[1]; 01290 async_agi.ctrl = fds[1]; 01291 async_agi.audio = -1; /* no audio support */ 01292 async_agi.fast = 0; 01293 async_agi.speech = NULL; 01294 01295 /* notify possible manager users of a new channel ready to 01296 receive commands */ 01297 setup_env(chan, "async", fds[1], 0, 0, NULL); 01298 /* read the environment */ 01299 res = read(fds[0], agi_buffer, AGI_BUF_SIZE); 01300 if (!res) { 01301 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s\n", 01302 chan->name); 01303 returnstatus = AGI_RESULT_FAILURE; 01304 goto async_agi_abort; 01305 } 01306 agi_buffer[res] = '\0'; 01307 /* encode it and send it thru the manager so whoever is going to take 01308 care of AGI commands on this channel can decide which AGI commands 01309 to execute based on the setup info */ 01310 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1); 01311 manager_event(EVENT_FLAG_AGI, "AsyncAGI", 01312 "SubEvent: Start\r\n" 01313 "Channel: %s\r\n" 01314 "Env: %s\r\n", chan->name, ami_buffer); 01315 hungup = ast_check_hangup(chan); 01316 for (;;) { 01317 /* 01318 * Process as many commands as we can. Commands are added via 01319 * the manager or the cli threads. 01320 */ 01321 while (!hungup && (cmd = get_agi_cmd(chan))) { 01322 /* OK, we have a command, let's call the command handler. */ 01323 cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0); 01324 01325 /* 01326 * The command handler must have written to our fake AGI struct 01327 * fd (the pipe), let's read the response. 01328 */ 01329 res = read(fds[0], agi_buffer, AGI_BUF_SIZE); 01330 if (!res) { 01331 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s\n", 01332 chan->name); 01333 free_agi_cmd(cmd); 01334 returnstatus = AGI_RESULT_FAILURE; 01335 goto async_agi_done; 01336 } 01337 /* 01338 * We have a response, let's send the response thru the manager. 01339 * Include the CommandID if it was specified when the command 01340 * was added. 01341 */ 01342 agi_buffer[res] = '\0'; 01343 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1); 01344 if (ast_strlen_zero(cmd->cmd_id)) { 01345 manager_event(EVENT_FLAG_AGI, "AsyncAGI", 01346 "SubEvent: Exec\r\n" 01347 "Channel: %s\r\n" 01348 "Result: %s\r\n", chan->name, ami_buffer); 01349 } else { 01350 manager_event(EVENT_FLAG_AGI, "AsyncAGI", 01351 "SubEvent: Exec\r\n" 01352 "Channel: %s\r\n" 01353 "CommandID: %s\r\n" 01354 "Result: %s\r\n", chan->name, cmd->cmd_id, ami_buffer); 01355 } 01356 free_agi_cmd(cmd); 01357 01358 /* 01359 * Check the command status to determine if we should continue 01360 * executing more commands. 01361 */ 01362 hungup = ast_check_hangup(chan); 01363 switch (cmd_status) { 01364 case AGI_RESULT_FAILURE: 01365 if (!hungup) { 01366 /* The failure was not because of a hangup. */ 01367 returnstatus = AGI_RESULT_FAILURE; 01368 goto async_agi_done; 01369 } 01370 break; 01371 case AGI_RESULT_SUCCESS_ASYNC: 01372 /* Only the "asyncagi break" command does this. */ 01373 returnstatus = AGI_RESULT_SUCCESS_ASYNC; 01374 goto async_agi_done; 01375 default: 01376 break; 01377 } 01378 } 01379 01380 if (!hungup) { 01381 /* Wait a bit for a frame to read or to poll for a new command. */ 01382 res = ast_waitfor(chan, timeout); 01383 if (res < 0) { 01384 ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", chan->name); 01385 returnstatus = AGI_RESULT_FAILURE; 01386 break; 01387 } 01388 } else { 01389 /* 01390 * Read the channel control queue until it is dry so we can 01391 * quit. 01392 */ 01393 res = 1; 01394 } 01395 if (0 < res) { 01396 do { 01397 cmd_status = async_agi_read_frame(chan); 01398 if (cmd_status != AGI_RESULT_SUCCESS) { 01399 returnstatus = cmd_status; 01400 goto async_agi_done; 01401 } 01402 hungup = ast_check_hangup(chan); 01403 } while (hungup); 01404 } else { 01405 hungup = ast_check_hangup(chan); 01406 } 01407 } 01408 async_agi_done: 01409 01410 if (async_agi.speech) { 01411 ast_speech_destroy(async_agi.speech); 01412 } 01413 /* notify manager users this channel cannot be 01414 controlled anymore by Async AGI */ 01415 manager_event(EVENT_FLAG_AGI, "AsyncAGI", 01416 "SubEvent: End\r\n" 01417 "Channel: %s\r\n", chan->name); 01418 01419 async_agi_abort: 01420 /* close the pipe */ 01421 close(fds[0]); 01422 close(fds[1]); 01423 01424 /* 01425 * Intentionally do not remove the datastore added with 01426 * add_to_agi() the from channel. There might be commands still 01427 * in the queue or in-flight to us and AsyncAGI may get called 01428 * again. The datastore destructor will be called on channel 01429 * destruction anyway. 01430 */ 01431 01432 if (returnstatus == AGI_RESULT_SUCCESS) { 01433 returnstatus = AGI_RESULT_SUCCESS_ASYNC; 01434 } 01435 return returnstatus; 01436 01437 #undef AGI_BUF_SIZE 01438 #undef AMI_BUF_SIZE 01439 }
static enum agi_result launch_ha_netscript | ( | char * | agiurl, | |
char * | argv[], | |||
int * | fds | |||
) | [static] |
Definition at line 1545 of file res_agi.c.
References AGI_RESULT_FAILURE, AGI_RESULT_NOTFOUND, ast_log(), ast_srv_cleanup(), ast_srv_lookup(), ast_strdupa, context, launch_netscript(), LOG_WARNING, service, and SRV_PREFIX.
Referenced by launch_script().
01546 { 01547 char *host, *script; 01548 enum agi_result result; 01549 struct srv_context *context = NULL; 01550 int srv_ret; 01551 char service[256]; 01552 char resolved_uri[1024]; 01553 const char *srvhost; 01554 unsigned short srvport; 01555 01556 /* format of agiurl is "hagi://host.domain[:port][/script/name]" */ 01557 if (!(host = ast_strdupa(agiurl + 7))) { /* Remove hagi:// */ 01558 ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl); 01559 return AGI_RESULT_FAILURE; 01560 } 01561 01562 /* Strip off any script name */ 01563 if ((script = strchr(host, '/'))) { 01564 *script++ = '\0'; 01565 } else { 01566 script = ""; 01567 } 01568 01569 if (strchr(host, ':')) { 01570 ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl); 01571 return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */ 01572 } 01573 01574 snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host); 01575 01576 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) { 01577 snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script); 01578 result = launch_netscript(resolved_uri, argv, fds); 01579 if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) { 01580 ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport); 01581 } else { 01582 /* The script launched so we must cleanup the context. */ 01583 ast_srv_cleanup(&context); 01584 return result; 01585 } 01586 } 01587 /* 01588 * The DNS SRV lookup failed or we ran out of servers to check. 01589 * ast_srv_lookup() has already cleaned up the context for us. 01590 */ 01591 if (srv_ret < 0) { 01592 ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl); 01593 } 01594 01595 return AGI_RESULT_FAILURE; 01596 }
static enum agi_result launch_netscript | ( | char * | agiurl, | |
char * | argv[], | |||
int * | fds | |||
) | [static] |
Definition at line 1443 of file res_agi.c.
References AGI_PORT, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS_FAST, ahp, ast_agi_send(), ast_debug, ast_gethostbyname(), ast_log(), ast_poll, ast_strdupa, ast_strlen_zero(), errno, hp, LOG_WARNING, and MAX_AGI_CONNECT.
Referenced by launch_ha_netscript(), and launch_script().
01444 { 01445 int s, flags, res, port = AGI_PORT; 01446 struct pollfd pfds[1]; 01447 char *host, *c, *script; 01448 struct sockaddr_in addr_in; 01449 struct hostent *hp; 01450 struct ast_hostent ahp; 01451 01452 /* agiurl is "agi://host.domain[:port][/script/name]" */ 01453 host = ast_strdupa(agiurl + 6); /* Remove agi:// */ 01454 /* Strip off any script name */ 01455 if ((script = strchr(host, '/'))) { 01456 *script++ = '\0'; 01457 } else { 01458 script = ""; 01459 } 01460 01461 if ((c = strchr(host, ':'))) { 01462 *c++ = '\0'; 01463 port = atoi(c); 01464 } 01465 if (!(hp = ast_gethostbyname(host, &ahp))) { 01466 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host); 01467 return AGI_RESULT_FAILURE; 01468 } 01469 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 01470 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 01471 return AGI_RESULT_FAILURE; 01472 } 01473 if ((flags = fcntl(s, F_GETFL)) < 0) { 01474 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno)); 01475 close(s); 01476 return AGI_RESULT_FAILURE; 01477 } 01478 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { 01479 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno)); 01480 close(s); 01481 return AGI_RESULT_FAILURE; 01482 } 01483 memset(&addr_in, 0, sizeof(addr_in)); 01484 addr_in.sin_family = AF_INET; 01485 addr_in.sin_port = htons(port); 01486 memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr)); 01487 if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) { 01488 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno)); 01489 close(s); 01490 return AGI_RESULT_FAILURE; 01491 } 01492 01493 pfds[0].fd = s; 01494 pfds[0].events = POLLOUT; 01495 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) { 01496 if (errno != EINTR) { 01497 if (!res) { 01498 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n", 01499 agiurl, MAX_AGI_CONNECT); 01500 } else 01501 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); 01502 close(s); 01503 return AGI_RESULT_FAILURE; 01504 } 01505 } 01506 01507 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) { 01508 if (errno != EINTR) { 01509 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); 01510 close(s); 01511 return AGI_RESULT_FAILURE; 01512 } 01513 } 01514 01515 /* If we have a script parameter, relay it to the fastagi server */ 01516 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */ 01517 if (!ast_strlen_zero(script)) 01518 ast_agi_send(s, NULL, "agi_network_script: %s\n", script); 01519 01520 ast_debug(4, "Wow, connected!\n"); 01521 fds[0] = s; 01522 fds[1] = s; 01523 return AGI_RESULT_SUCCESS_FAST; 01524 }
static enum agi_result launch_script | ( | struct ast_channel * | chan, | |
char * | script, | |||
char * | argv[], | |||
int * | fds, | |||
int * | efd, | |||
int * | opid | |||
) | [static] |
Definition at line 1598 of file res_agi.c.
References AGI_RESULT_FAILURE, AGI_RESULT_NOTFOUND, AGI_RESULT_SUCCESS, ast_child_verbose(), ast_close_fds_above_n(), ast_config_AST_AGI_DIR, ast_config_AST_CONFIG_DIR, ast_config_AST_CONFIG_FILE, ast_config_AST_DATA_DIR, ast_config_AST_KEY_DIR, ast_config_AST_LOG_DIR, ast_config_AST_MODULE_DIR, ast_config_AST_MONITOR_DIR, ast_config_AST_RUN_DIR, ast_config_AST_SPOOL_DIR, ast_config_AST_VAR_DIR, ast_log(), ast_safe_fork(), ast_set_priority(), ast_verb, errno, launch_asyncagi(), launch_ha_netscript(), launch_netscript(), LOG_WARNING, and setenv().
Referenced by agi_exec_full().
01599 { 01600 char tmp[256]; 01601 int pid, toast[2], fromast[2], audio[2], res; 01602 struct stat st; 01603 01604 if (!strncasecmp(script, "agi://", 6)) { 01605 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE; 01606 } 01607 if (!strncasecmp(script, "hagi://", 7)) { 01608 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE; 01609 } 01610 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) { 01611 return launch_asyncagi(chan, argv, efd); 01612 } 01613 01614 if (script[0] != '/') { 01615 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script); 01616 script = tmp; 01617 } 01618 01619 /* Before even trying let's see if the file actually exists */ 01620 if (stat(script, &st)) { 01621 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script); 01622 return AGI_RESULT_NOTFOUND; 01623 } 01624 01625 if (pipe(toast)) { 01626 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno)); 01627 return AGI_RESULT_FAILURE; 01628 } 01629 if (pipe(fromast)) { 01630 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno)); 01631 close(toast[0]); 01632 close(toast[1]); 01633 return AGI_RESULT_FAILURE; 01634 } 01635 if (efd) { 01636 if (pipe(audio)) { 01637 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno)); 01638 close(fromast[0]); 01639 close(fromast[1]); 01640 close(toast[0]); 01641 close(toast[1]); 01642 return AGI_RESULT_FAILURE; 01643 } 01644 res = fcntl(audio[1], F_GETFL); 01645 if (res > -1) 01646 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK); 01647 if (res < 0) { 01648 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno)); 01649 close(fromast[0]); 01650 close(fromast[1]); 01651 close(toast[0]); 01652 close(toast[1]); 01653 close(audio[0]); 01654 close(audio[1]); 01655 return AGI_RESULT_FAILURE; 01656 } 01657 } 01658 01659 if ((pid = ast_safe_fork(1)) < 0) { 01660 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); 01661 return AGI_RESULT_FAILURE; 01662 } 01663 if (!pid) { 01664 /* Pass paths to AGI via environmental variables */ 01665 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1); 01666 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1); 01667 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1); 01668 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1); 01669 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1); 01670 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1); 01671 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1); 01672 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1); 01673 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1); 01674 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1); 01675 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1); 01676 01677 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */ 01678 ast_set_priority(0); 01679 01680 /* Redirect stdin and out, provide enhanced audio channel if desired */ 01681 dup2(fromast[0], STDIN_FILENO); 01682 dup2(toast[1], STDOUT_FILENO); 01683 if (efd) 01684 dup2(audio[0], STDERR_FILENO + 1); 01685 else 01686 close(STDERR_FILENO + 1); 01687 01688 /* Close everything but stdin/out/error */ 01689 ast_close_fds_above_n(STDERR_FILENO + 1); 01690 01691 /* Execute script */ 01692 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */ 01693 execv(script, argv); 01694 /* Can't use ast_log since FD's are closed */ 01695 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno)); 01696 /* Special case to set status of AGI to failure */ 01697 fprintf(stdout, "failure\n"); 01698 fflush(stdout); 01699 _exit(1); 01700 } 01701 ast_verb(3, "Launched AGI Script %s\n", script); 01702 fds[0] = toast[0]; 01703 fds[1] = fromast[1]; 01704 if (efd) 01705 *efd = audio[1]; 01706 /* close what we're not using in the parent */ 01707 close(toast[1]); 01708 close(fromast[0]); 01709 01710 if (efd) 01711 close(audio[0]); 01712 01713 *opid = pid; 01714 return AGI_RESULT_SUCCESS; 01715 }
static int load_module | ( | void | ) | [static] |
Definition at line 3989 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.
03990 { 03991 ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi)); 03992 /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as 03993 no other commands have been registered yet 03994 */ 03995 (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands)); 03996 ast_register_application_xml(deadapp, deadagi_exec); 03997 ast_register_application_xml(eapp, eagi_exec); 03998 ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd); 03999 AST_TEST_REGISTER(test_agi_null_docs); 04000 return ast_register_application_xml(app, agi_exec); 04001 }
static int parse_args | ( | char * | s, | |
int * | max, | |||
const char * | argv[] | |||
) | [static] |
Definition at line 3287 of file res_agi.c.
References ast_log(), LOG_WARNING, and MAX_ARGS.
03288 { 03289 int x = 0, quoted = 0, escaped = 0, whitespace = 1; 03290 char *cur; 03291 03292 cur = s; 03293 while(*s) { 03294 switch(*s) { 03295 case '"': 03296 /* If it's escaped, put a literal quote */ 03297 if (escaped) 03298 goto normal; 03299 else 03300 quoted = !quoted; 03301 if (quoted && whitespace) { 03302 /* If we're starting a quote, coming off white space start a new word, too */ 03303 argv[x++] = cur; 03304 whitespace=0; 03305 } 03306 escaped = 0; 03307 break; 03308 case ' ': 03309 case '\t': 03310 if (!quoted && !escaped) { 03311 /* If we're not quoted, mark this as whitespace, and 03312 end the previous argument */ 03313 whitespace = 1; 03314 *(cur++) = '\0'; 03315 } else 03316 /* Otherwise, just treat it as anything else */ 03317 goto normal; 03318 break; 03319 case '\\': 03320 /* If we're escaped, print a literal, otherwise enable escaping */ 03321 if (escaped) { 03322 goto normal; 03323 } else { 03324 escaped=1; 03325 } 03326 break; 03327 default: 03328 normal: 03329 if (whitespace) { 03330 if (x >= MAX_ARGS -1) { 03331 ast_log(LOG_WARNING, "Too many arguments, truncating\n"); 03332 break; 03333 } 03334 /* Coming off of whitespace, start the next argument */ 03335 argv[x++] = cur; 03336 whitespace=0; 03337 } 03338 *(cur++) = *s; 03339 escaped=0; 03340 } 03341 s++; 03342 } 03343 /* Null terminate */ 03344 *(cur++) = '\0'; 03345 argv[x] = NULL; 03346 *max = x; 03347 return 0; 03348 }
static enum agi_result run_agi | ( | struct ast_channel * | chan, | |
char * | request, | |||
AGI * | agi, | |||
int | pid, | |||
int * | status, | |||
int | dead, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 3446 of file res_agi.c.
References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, ast_agi_send(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_debug, ast_false(), AST_FRAME_VOICE, ast_frfree, ast_log(), ast_read(), ast_strlen_zero(), ast_verb, ast_verbose, ast_waitfor_nandfds(), agi_state::audio, agi_state::ctrl, errno, f, agi_state::fast, agi_state::fd, len(), LOG_WARNING, ast_channel::name, pbx_builtin_getvar_helper(), and setup_env().
Referenced by agi_exec_full().
03447 { 03448 struct ast_channel *c; 03449 int outfd; 03450 int ms; 03451 int needhup = 0; 03452 enum agi_result returnstatus = AGI_RESULT_SUCCESS; 03453 struct ast_frame *f; 03454 char buf[AGI_BUF_LEN]; 03455 char *res = NULL; 03456 FILE *readf; 03457 /* how many times we'll retry if ast_waitfor_nandfs will return without either 03458 channel or file descriptor in case select is interrupted by a system call (EINTR) */ 03459 int retry = AGI_NANDFS_RETRY; 03460 int send_sighup; 03461 const char *sighup_str; 03462 03463 ast_channel_lock(chan); 03464 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); 03465 send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str); 03466 ast_channel_unlock(chan); 03467 03468 if (!(readf = fdopen(agi->ctrl, "r"))) { 03469 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n"); 03470 if (send_sighup && pid > -1) 03471 kill(pid, SIGHUP); 03472 close(agi->ctrl); 03473 return AGI_RESULT_FAILURE; 03474 } 03475 03476 setlinebuf(readf); 03477 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv); 03478 for (;;) { 03479 if (needhup) { 03480 needhup = 0; 03481 dead = 1; 03482 if (send_sighup) { 03483 if (pid > -1) { 03484 kill(pid, SIGHUP); 03485 } else if (agi->fast) { 03486 ast_agi_send(agi->fd, chan, "HANGUP\n"); 03487 } 03488 } 03489 } 03490 ms = -1; 03491 if (dead) { 03492 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms); 03493 } else if (!ast_check_hangup(chan)) { 03494 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms); 03495 } else { 03496 /* 03497 * Read the channel control queue until it is dry so we can 03498 * switch to dead mode. 03499 */ 03500 c = chan; 03501 } 03502 if (c) { 03503 retry = AGI_NANDFS_RETRY; 03504 /* Idle the channel until we get a command */ 03505 f = ast_read(c); 03506 if (!f) { 03507 ast_debug(1, "%s hungup\n", chan->name); 03508 needhup = 1; 03509 if (!returnstatus) { 03510 returnstatus = AGI_RESULT_HANGUP; 03511 } 03512 } else { 03513 /* If it's voice, write it to the audio pipe */ 03514 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) { 03515 /* Write, ignoring errors */ 03516 if (write(agi->audio, f->data.ptr, f->datalen) < 0) { 03517 } 03518 } 03519 ast_frfree(f); 03520 } 03521 } else if (outfd > -1) { 03522 size_t len = sizeof(buf); 03523 size_t buflen = 0; 03524 enum agi_result cmd_status; 03525 03526 retry = AGI_NANDFS_RETRY; 03527 buf[0] = '\0'; 03528 03529 while (len > 1) { 03530 res = fgets(buf + buflen, len, readf); 03531 if (feof(readf)) 03532 break; 03533 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 03534 break; 03535 if (res != NULL && !agi->fast) 03536 break; 03537 buflen = strlen(buf); 03538 if (buflen && buf[buflen - 1] == '\n') 03539 break; 03540 len = sizeof(buf) - buflen; 03541 if (agidebug) 03542 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno)); 03543 } 03544 03545 if (!buf[0]) { 03546 /* Program terminated */ 03547 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus); 03548 if (pid > 0) 03549 waitpid(pid, status, 0); 03550 /* No need to kill the pid anymore, since they closed us */ 03551 pid = -1; 03552 break; 03553 } 03554 03555 /* Special case for inability to execute child process */ 03556 if (*buf && strncasecmp(buf, "failure", 7) == 0) { 03557 returnstatus = AGI_RESULT_FAILURE; 03558 break; 03559 } 03560 03561 /* get rid of trailing newline, if any */ 03562 buflen = strlen(buf); 03563 if (buflen && buf[buflen - 1] == '\n') { 03564 buf[buflen - 1] = '\0'; 03565 } 03566 03567 if (agidebug) 03568 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf); 03569 cmd_status = agi_handle_command(chan, agi, buf, dead); 03570 switch (cmd_status) { 03571 case AGI_RESULT_FAILURE: 03572 if (dead || !ast_check_hangup(chan)) { 03573 /* The failure was not because of a hangup. */ 03574 returnstatus = AGI_RESULT_FAILURE; 03575 } 03576 break; 03577 default: 03578 break; 03579 } 03580 } else { 03581 if (--retry <= 0) { 03582 ast_log(LOG_WARNING, "No channel, no fd?\n"); 03583 returnstatus = AGI_RESULT_FAILURE; 03584 break; 03585 } 03586 } 03587 } 03588 if (agi->speech) { 03589 ast_speech_destroy(agi->speech); 03590 } 03591 /* Notify process */ 03592 if (send_sighup) { 03593 if (pid > -1) { 03594 if (kill(pid, SIGHUP)) { 03595 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno)); 03596 } else { /* Give the process a chance to die */ 03597 usleep(1); 03598 } 03599 waitpid(pid, status, WNOHANG); 03600 } else if (agi->fast) { 03601 ast_agi_send(agi->fd, chan, "HANGUP\n"); 03602 } 03603 } 03604 fclose(readf); 03605 return returnstatus; 03606 }
static void setup_env | ( | struct ast_channel * | chan, | |
char * | request, | |||
int | fd, | |||
int | enhanced, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1717 of file res_agi.c.
References ast_channel::accountcode, ast_party_caller::ani2, ast_agi_send(), ast_get_version(), ast_party_id_presentation(), ast_channel::caller, ast_channel::context, ast_channel::dialed, ast_channel::exten, ast_party_redirecting::from, ast_party_caller::id, ast_channel::language, ast_party_id::name, ast_channel::name, ast_party_dialed::number, ast_party_id::number, ast_party_number::plan, ast_channel::priority, ast_channel::redirecting, S_COR, S_OR, ast_party_dialed::str, ast_party_name::str, ast_party_number::str, ast_channel::tech, ast_party_dialed::transit_network_select, ast_channel_tech::type, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by launch_asyncagi(), and run_agi().
01718 { 01719 int count; 01720 01721 /* Print initial environment, with agi_request always being the first 01722 thing */ 01723 ast_agi_send(fd, chan, "agi_request: %s\n", request); 01724 ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name); 01725 ast_agi_send(fd, chan, "agi_language: %s\n", chan->language); 01726 ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type); 01727 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid); 01728 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version()); 01729 01730 /* ANI/DNIS */ 01731 ast_agi_send(fd, chan, "agi_callerid: %s\n", 01732 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "unknown")); 01733 ast_agi_send(fd, chan, "agi_calleridname: %s\n", 01734 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "unknown")); 01735 ast_agi_send(fd, chan, "agi_callingpres: %d\n", 01736 ast_party_id_presentation(&chan->caller.id)); 01737 ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->caller.ani2); 01738 ast_agi_send(fd, chan, "agi_callington: %d\n", chan->caller.id.number.plan); 01739 ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->dialed.transit_network_select); 01740 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->dialed.number.str, "unknown")); 01741 ast_agi_send(fd, chan, "agi_rdnis: %s\n", 01742 S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "unknown")); 01743 01744 /* Context information */ 01745 ast_agi_send(fd, chan, "agi_context: %s\n", chan->context); 01746 ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten); 01747 ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority); 01748 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0"); 01749 01750 /* User information */ 01751 ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : ""); 01752 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self()); 01753 01754 /* Send any parameters to the fastagi server that have been passed via the agi application */ 01755 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */ 01756 for(count = 1; count < argc; count++) 01757 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]); 01758 01759 /* End with empty return */ 01760 ast_agi_send(fd, chan, "\n"); 01761 }
static int speech_streamfile | ( | struct ast_channel * | chan, | |
const char * | filename, | |||
const char * | preflang, | |||
int | offset | |||
) | [static] |
Definition at line 2872 of file res_agi.c.
References ast_applystream(), ast_openstream(), ast_playstream(), and ast_seekstream().
02873 { 02874 struct ast_filestream *fs = NULL; 02875 02876 if (!(fs = ast_openstream(chan, filename, preflang))) 02877 return -1; 02878 02879 if (offset) 02880 ast_seekstream(fs, offset, SEEK_SET); 02881 02882 if (ast_applystream(chan, fs)) 02883 return -1; 02884 02885 if (ast_playstream(fs)) 02886 return -1; 02887 02888 return 0; 02889 }
static int unload_module | ( | void | ) | [static] |
Definition at line 3975 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.
03976 { 03977 ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi)); 03978 /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as 03979 we know that these commands were registered by this module and are still registered 03980 */ 03981 (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands)); 03982 ast_unregister_application(eapp); 03983 ast_unregister_application(deadapp); 03984 ast_manager_unregister("AGI"); 03985 AST_TEST_UNREGISTER(test_agi_null_docs); 03986 return ast_unregister_application(app); 03987 }
static void write_html_escaped | ( | FILE * | htmlfile, | |
char * | str | |||
) | [static] |
Convert string to use HTML escaped characters.
Definition at line 3714 of file res_agi.c.
Referenced by write_htmldump().
03715 { 03716 char *cur = str; 03717 03718 while(*cur) { 03719 switch (*cur) { 03720 case '<': 03721 fprintf(htmlfile, "%s", "<"); 03722 break; 03723 case '>': 03724 fprintf(htmlfile, "%s", ">"); 03725 break; 03726 case '&': 03727 fprintf(htmlfile, "%s", "&"); 03728 break; 03729 case '"': 03730 fprintf(htmlfile, "%s", """); 03731 break; 03732 default: 03733 fprintf(htmlfile, "%c", *cur); 03734 break; 03735 } 03736 cur++; 03737 } 03738 03739 return; 03740 }
static int write_htmldump | ( | const char * | filename | ) | [static] |
Definition at line 3742 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().
03743 { 03744 struct agi_command *command; 03745 char fullcmd[MAX_CMD_LEN]; 03746 FILE *htmlfile; 03747 03748 if (!(htmlfile = fopen(filename, "wt"))) 03749 return -1; 03750 03751 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n"); 03752 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n"); 03753 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n"); 03754 03755 AST_RWLIST_RDLOCK(&agi_commands); 03756 AST_RWLIST_TRAVERSE(&agi_commands, command, list) { 03757 #ifdef AST_XML_DOCS 03758 char *stringptmp; 03759 #endif 03760 char *tempstr, *stringp; 03761 03762 if (!command->cmda[0]) /* end ? */ 03763 break; 03764 /* Hide commands that start with '_' */ 03765 if ((command->cmda[0])[0] == '_') 03766 continue; 03767 ast_join(fullcmd, sizeof(fullcmd), command->cmda); 03768 03769 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n"); 03770 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary); 03771 #ifdef AST_XML_DOCS 03772 stringptmp = ast_xmldoc_printable(command->usage, 0); 03773 stringp = ast_strdup(stringptmp); 03774 #else 03775 stringp = ast_strdup(command->usage); 03776 #endif 03777 tempstr = strsep(&stringp, "\n"); 03778 03779 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">"); 03780 write_html_escaped(htmlfile, tempstr); 03781 fprintf(htmlfile, "</TD></TR>\n"); 03782 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n"); 03783 03784 while ((tempstr = strsep(&stringp, "\n")) != NULL) { 03785 write_html_escaped(htmlfile, tempstr); 03786 fprintf(htmlfile, "<BR>\n"); 03787 } 03788 fprintf(htmlfile, "</TD></TR>\n"); 03789 fprintf(htmlfile, "</TABLE></TD></TR>\n\n"); 03790 ast_free(stringp); 03791 #ifdef AST_XML_DOCS 03792 ast_free(stringptmp); 03793 #endif 03794 } 03795 AST_RWLIST_UNLOCK(&agi_commands); 03796 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n"); 03797 fclose(htmlfile); 03798 return 0; 03799 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 997 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 3041 of file res_agi.c.
Referenced by aji_dinfo_handler(), dundi_showframe(), load_module(), and unload_module().