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