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