67 #include "asterisk/stasis_channels.h"
68 #include "asterisk/stasis_message_router.h"
71 #define AST_API_MODULE
1383 #define MAX_ARGS 128
1384 #define MAX_CMD_LEN 80
1385 #define AGI_NANDFS_RETRY 3
1386 #define AGI_BUF_LEN 2048
1387 #define SRV_PREFIX "_agi._tcp."
1389 static char *app =
"AGI";
1391 static char *eapp =
"EAGI";
1393 static char *deadapp =
"DeadAGI";
1395 static int agidebug = 0;
1397 #define TONE_BLOCK_SIZE 200
1400 #define MAX_AGI_CONNECT 2000
1402 #define AGI_PORT 4573
1405 #define ASYNC_AGI_BREAK 3
1408 AGI_RESULT_FAILURE = -1,
1410 AGI_RESULT_SUCCESS_FAST,
1411 AGI_RESULT_SUCCESS_ASYNC,
1412 AGI_RESULT_NOTFOUND,
1424 if (!channel_string || !event_string) {
1437 return agi_channel_to_ami(
"AGIExecStart", message);
1442 return agi_channel_to_ami(
"AGIExecEnd", message);
1447 return agi_channel_to_ami(
"AsyncAGIStart", message);
1452 return agi_channel_to_ami(
"AsyncAGIExec", message);
1457 return agi_channel_to_ami(
"AsyncAGIEnd", message);
1461 .to_ami = agi_exec_start_to_ami,
1464 .to_ami = agi_exec_end_to_ami,
1467 .to_ami = agi_async_start_to_ami,
1470 .to_ami = agi_async_exec_to_ami,
1473 .to_ami = agi_async_end_to_ami,
1476 static agi_command *find_command(
const char *
const cmds[],
int exact);
1479 #define AGI_BUF_INITSIZE 256
1495 ast_log(LOG_ERROR,
"Out of memory\n");
1501 ast_verbose(
"<%s>AGI Tx >> %s", ast_channel_name(chan),
ast_str_buffer(buf));
1517 static void free_agi_cmd(
struct agi_cmd *cmd)
1519 ast_free(cmd->cmd_buffer);
1520 ast_free(cmd->cmd_id);
1525 static void agi_destroy_commands_cb(
void *data)
1535 ast_free(chan_cmds);
1541 .destroy = agi_destroy_commands_cb
1558 ast_channel_lock(chan);
1560 ast_channel_unlock(chan);
1562 ast_log(LOG_ERROR,
"Huh? Async AGI datastore disappeared on Channel %s!\n",
1563 ast_channel_name(chan));
1575 static int add_agi_cmd(
struct ast_channel *chan,
const char *cmd_buff,
const char *cmd_id)
1583 ast_log(LOG_WARNING,
"Channel %s is not setup for Async AGI.\n", ast_channel_name(chan));
1592 if (!cmd->cmd_buffer) {
1598 ast_free(cmd->cmd_buffer);
1614 ast_channel_lock(chan);
1616 ast_channel_unlock(chan);
1625 datastore = ast_datastore_alloc(&agi_commands_datastore_info,
"AGI");
1629 agi_cmds_list =
ast_calloc(1,
sizeof(*agi_cmds_list));
1630 if (!agi_cmds_list) {
1631 ast_log(LOG_ERROR,
"Unable to allocate Async AGI commands list.\n");
1635 datastore->
data = agi_cmds_list;
1637 ast_channel_lock(chan);
1639 ast_channel_unlock(chan);
1658 e->
usage =
"Usage: agi exec <channel name> <app and arguments> [id]\n"
1659 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1668 return CLI_SHOWUSAGE;
1672 ast_cli(a->fd,
"Channel %s does not exist.\n", a->argv[2]);
1676 ast_channel_lock(chan);
1678 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] :
""))) {
1679 ast_cli(a->fd,
"Failed to add AGI command to queue of channel %s\n", ast_channel_name(chan));
1680 ast_channel_unlock(chan);
1685 ast_debug(1,
"Added AGI command to channel %s queue\n", ast_channel_name(chan));
1687 ast_channel_unlock(chan);
1712 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1718 snprintf(buf,
sizeof(buf),
"Channel %s does not exist.", channel);
1723 ast_channel_lock(chan);
1725 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1726 snprintf(buf,
sizeof(buf),
"Failed to add AGI command to channel %s queue", ast_channel_name(chan));
1728 ast_channel_unlock(chan);
1733 ast_channel_unlock(chan);
1741 static enum agi_result agi_handle_command(
struct ast_channel *chan,
AGI *agi,
char *buf,
int dead);
1742 static void setup_env(
struct ast_channel *chan,
char *request,
int fd,
int enhanced,
int argc,
char *argv[]);
1754 static enum agi_result async_agi_read_frame(
struct ast_channel *chan)
1760 ast_debug(3,
"No frame read on channel %s, going out ...\n", ast_channel_name(chan));
1761 return AGI_RESULT_HANGUP;
1770 ast_debug(3,
"Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
1772 return AGI_RESULT_HANGUP;
1779 return AGI_RESULT_SUCCESS;
1782 static enum agi_result launch_asyncagi(
struct ast_channel *chan,
int argc,
char *argv[],
int *efd)
1801 #define AGI_BUF_SIZE 1024
1802 #define AMI_BUF_SIZE 2048
1803 enum agi_result cmd_status;
1809 char agi_buffer[AGI_BUF_SIZE + 1];
1810 char ami_buffer[AMI_BUF_SIZE];
1811 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1816 ast_log(LOG_WARNING,
"Async AGI does not support Enhanced AGI yet\n");
1817 return AGI_RESULT_FAILURE;
1821 if (add_to_agi(chan)) {
1822 ast_log(LOG_ERROR,
"Failed to start Async AGI on channel %s\n", ast_channel_name(chan));
1823 return AGI_RESULT_FAILURE;
1830 ast_log(LOG_ERROR,
"Failed to create Async AGI pipe\n");
1836 return AGI_RESULT_FAILURE;
1841 async_agi.
fd = fds[1];
1842 async_agi.
ctrl = fds[1];
1843 async_agi.
audio = -1;
1849 setup_env(chan,
"async", fds[1], 0, argc, argv);
1851 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
1853 ast_log(LOG_ERROR,
"Failed to read from Async AGI pipe on channel %s: %s\n",
1854 ast_channel_name(chan), res < 0 ? strerror(errno) :
"EOF");
1855 returnstatus = AGI_RESULT_FAILURE;
1856 goto async_agi_abort;
1858 agi_buffer[res] =
'\0';
1862 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
1867 hungup = ast_check_hangup_locked(chan);
1879 returnstatus = AGI_RESULT_FAILURE;
1880 goto async_agi_done;
1886 cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
1892 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
1894 ast_log(LOG_ERROR,
"Failed to read from Async AGI pipe on channel %s: %s\n",
1895 ast_channel_name(chan), res < 0 ? strerror(errno) :
"EOF");
1897 returnstatus = AGI_RESULT_FAILURE;
1898 goto async_agi_done;
1905 agi_buffer[res] =
'\0';
1906 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
1909 if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
1921 switch (cmd_status) {
1922 case AGI_RESULT_FAILURE:
1925 returnstatus = AGI_RESULT_FAILURE;
1926 goto async_agi_done;
1929 case AGI_RESULT_SUCCESS_ASYNC:
1931 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
1932 goto async_agi_done;
1942 ast_debug(1,
"ast_waitfor returned <= 0 on chan %s\n", ast_channel_name(chan));
1943 returnstatus = AGI_RESULT_FAILURE;
1955 cmd_status = async_agi_read_frame(chan);
1956 if (cmd_status != AGI_RESULT_SUCCESS) {
1957 returnstatus = cmd_status;
1958 goto async_agi_done;
1987 if (returnstatus == AGI_RESULT_SUCCESS) {
1988 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
1990 return returnstatus;
2007 static int handle_connection(
const char *agiurl,
const struct ast_sockaddr addr,
const int netsockfd)
2009 struct pollfd pfds[1];
2013 reslen =
sizeof(conresult);
2015 pfds[0].fd = netsockfd;
2016 pfds[0].events = POLLOUT;
2018 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
2019 if (errno != EINTR) {
2021 ast_log(LOG_WARNING,
"FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
2022 agiurl, MAX_AGI_CONNECT);
2024 ast_log(LOG_WARNING,
"Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2031 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
2032 ast_log(LOG_WARNING,
"Connection to %s failed with error: %s\n",
2038 ast_log(LOG_WARNING,
"Connecting to '%s' failed for url '%s': %s\n",
2048 static enum agi_result launch_netscript(
char *agiurl,
char *argv[],
int *fds)
2051 char *host, *script;
2052 int num_addrs = 0, i = 0;
2059 if ((script = strchr(host,
'/'))) {
2066 ast_log(LOG_WARNING,
"Unable to locate host '%s'\n", host);
2067 return AGI_RESULT_FAILURE;
2070 for (i = 0; i < num_addrs; i++) {
2076 ast_log(LOG_WARNING,
"Unable to create socket: %s\n", strerror(errno));
2080 if (
ast_connect(s, &addrs[i]) && errno == EINPROGRESS) {
2082 if (handle_connection(agiurl, addrs[i], s)) {
2088 ast_log(LOG_WARNING,
"Connection to %s failed with unexpected error: %s\n",
2097 if (i == num_addrs) {
2098 ast_log(LOG_WARNING,
"Couldn't connect to any host. FastAGI failed.\n");
2099 return AGI_RESULT_FAILURE;
2102 if (ast_agi_send(s, NULL,
"agi_network: yes\n") < 0) {
2103 if (errno != EINTR) {
2104 ast_log(LOG_WARNING,
"Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2106 return AGI_RESULT_FAILURE;
2112 if (!ast_strlen_zero(script)) {
2113 ast_agi_send(s, NULL,
"agi_network_script: %s\n", script);
2119 return AGI_RESULT_SUCCESS_FAST;
2141 static enum agi_result launch_ha_netscript(
char *agiurl,
char *argv[],
int *fds)
2143 char *host, *script;
2144 enum agi_result result;
2148 char resolved_uri[1024];
2149 const char *srvhost;
2150 unsigned short srvport;
2153 if (strlen(agiurl) < 7) {
2154 ast_log(LOG_WARNING,
"An error occurred parsing the AGI URI: %s", agiurl);
2155 return AGI_RESULT_FAILURE;
2160 if ((script = strchr(host,
'/'))) {
2166 if (strchr(host,
':')) {
2167 ast_log(LOG_WARNING,
"Specifying a port number disables SRV lookups: %s\n", agiurl);
2168 return launch_netscript(agiurl + 1, argv, fds);
2171 snprintf(service,
sizeof(service),
"%s%s", SRV_PREFIX, host);
2173 while (!(srv_ret =
ast_srv_lookup(&context, service, &srvhost, &srvport))) {
2174 snprintf(resolved_uri,
sizeof(resolved_uri),
"agi://%s:%d/%s", srvhost, srvport, script);
2175 result = launch_netscript(resolved_uri, argv, fds);
2176 if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
2177 ast_log(LOG_WARNING,
"AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
2189 ast_log(LOG_WARNING,
"SRV lookup failed for %s\n", agiurl);
2192 return AGI_RESULT_FAILURE;
2195 static enum agi_result launch_script(
struct ast_channel *chan,
char *script,
int argc,
char *argv[],
int *fds,
int *efd,
int *opid)
2198 int pid, toast[2], fromast[2], audio[2], res;
2201 if (!strncasecmp(script,
"agi://", 6)) {
2202 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2204 if (!strncasecmp(script,
"hagi://", 7)) {
2205 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2207 if (!strncasecmp(script,
"agi:async",
sizeof(
"agi:async") - 1)) {
2208 return launch_asyncagi(chan, argc, argv, efd);
2211 if (script[0] !=
'/') {
2212 snprintf(tmp,
sizeof(tmp),
"%s/%s", ast_config_AST_AGI_DIR, script);
2217 if (stat(script, &st)) {
2218 ast_log(LOG_WARNING,
"Failed to execute '%s': File does not exist.\n", script);
2219 return AGI_RESULT_NOTFOUND;
2223 ast_log(LOG_WARNING,
"Unable to create toast pipe: %s\n",strerror(errno));
2224 return AGI_RESULT_FAILURE;
2226 if (pipe(fromast)) {
2227 ast_log(LOG_WARNING,
"unable to create fromast pipe: %s\n", strerror(errno));
2230 return AGI_RESULT_FAILURE;
2234 ast_log(LOG_WARNING,
"unable to create audio pipe: %s\n", strerror(errno));
2239 return AGI_RESULT_FAILURE;
2244 ast_log(LOG_WARNING,
"unable to set audio pipe parameters: %s\n", strerror(errno));
2251 return AGI_RESULT_FAILURE;
2256 ast_log(LOG_WARNING,
"Failed to fork(): %s\n", strerror(errno));
2257 return AGI_RESULT_FAILURE;
2261 setenv(
"AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
2262 setenv(
"AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
2263 setenv(
"AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
2264 setenv(
"AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
2265 setenv(
"AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
2266 setenv(
"AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
2267 setenv(
"AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
2268 setenv(
"AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
2269 setenv(
"AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
2270 setenv(
"AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
2271 setenv(
"AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
2277 dup2(fromast[0], STDIN_FILENO);
2278 dup2(toast[1], STDOUT_FILENO);
2280 dup2(audio[0], STDERR_FILENO + 1);
2282 close(STDERR_FILENO + 1);
2289 execv(script, argv);
2291 ast_child_verbose(1,
"Failed to execute '%s': %s", script, strerror(errno));
2293 fprintf(stdout,
"failure\n");
2297 ast_verb(3,
"Launched AGI Script %s\n", script);
2299 fds[1] = fromast[1];
2310 return AGI_RESULT_SUCCESS;
2313 static void setup_env(
struct ast_channel *chan,
char *request,
int fd,
int enhanced,
int argc,
char *argv[])
2319 ast_agi_send(fd, chan,
"agi_request: %s\n", request);
2320 ast_agi_send(fd, chan,
"agi_channel: %s\n", ast_channel_name(chan));
2321 ast_agi_send(fd, chan,
"agi_language: %s\n", ast_channel_language(chan));
2323 ast_agi_send(fd, chan,
"agi_uniqueid: %s\n", ast_channel_uniqueid(chan));
2327 ast_agi_send(fd, chan,
"agi_callerid: %s\n",
2328 S_COR(ast_channel_caller(chan)->
id.
number.valid, ast_channel_caller(chan)->
id.
number.str,
"unknown"));
2329 ast_agi_send(fd, chan,
"agi_calleridname: %s\n",
2330 S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str,
"unknown"));
2331 ast_agi_send(fd, chan,
"agi_callingpres: %d\n",
2333 ast_agi_send(fd, chan,
"agi_callingani2: %d\n", ast_channel_caller(chan)->ani2);
2334 ast_agi_send(fd, chan,
"agi_callington: %d\n", ast_channel_caller(chan)->
id.
number.plan);
2335 ast_agi_send(fd, chan,
"agi_callingtns: %d\n", ast_channel_dialed(chan)->transit_network_select);
2336 ast_agi_send(fd, chan,
"agi_dnid: %s\n",
S_OR(ast_channel_dialed(chan)->
number.str,
"unknown"));
2337 ast_agi_send(fd, chan,
"agi_rdnis: %s\n",
2338 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str,
"unknown"));
2341 ast_agi_send(fd, chan,
"agi_context: %s\n", ast_channel_context(chan));
2342 ast_agi_send(fd, chan,
"agi_extension: %s\n", ast_channel_exten(chan));
2343 ast_agi_send(fd, chan,
"agi_priority: %d\n", ast_channel_priority(chan));
2344 ast_agi_send(fd, chan,
"agi_enhanced: %s\n", enhanced ?
"1.0" :
"0.0");
2347 ast_agi_send(fd, chan,
"agi_accountcode: %s\n", ast_channel_accountcode(chan) ? ast_channel_accountcode(chan) :
"");
2348 ast_agi_send(fd, chan,
"agi_threadid: %ld\n", (
long)pthread_self());
2352 for(count = 1; count < argc; count++)
2353 ast_agi_send(fd, chan,
"agi_arg_%d: %s\n", count, argv[count]);
2356 ast_agi_send(fd, chan,
"\n");
2359 static int handle_answer(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2367 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2368 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2371 static int handle_asyncagi_break(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2373 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
2377 static int handle_waitfordigit(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2382 return RESULT_SHOWUSAGE;
2383 if (sscanf(argv[3],
"%30d", &to) != 1)
2384 return RESULT_SHOWUSAGE;
2386 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2387 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2390 static int handle_sendtext(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2395 return RESULT_SHOWUSAGE;
2405 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2406 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2409 static int handle_recvchar(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2414 return RESULT_SHOWUSAGE;
2418 ast_agi_send(agi->
fd, chan,
"200 result=%d (timeout)\n", res);
2419 return RESULT_SUCCESS;
2422 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2423 return RESULT_SUCCESS;
2425 ast_agi_send(agi->
fd, chan,
"200 result=%d (hangup)\n", res);
2426 return RESULT_FAILURE;
2429 static int handle_recvtext(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2434 return RESULT_SHOWUSAGE;
2438 ast_agi_send(agi->
fd, chan,
"200 result=1 (%s)\n", buf);
2441 ast_agi_send(agi->
fd, chan,
"200 result=-1\n");
2443 return RESULT_SUCCESS;
2446 static int handle_tddmode(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2451 return RESULT_SHOWUSAGE;
2453 if (!strncasecmp(argv[2],
"on",2)) {
2458 if (!strncasecmp(argv[2],
"mate",4)) {
2461 if (!strncasecmp(argv[2],
"tdd",3)) {
2467 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
2469 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
2471 return RESULT_SUCCESS;
2474 static int handle_sendimage(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2479 return RESULT_SHOWUSAGE;
2486 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2487 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2490 static int handle_controlstreamfile(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2492 int res = 0, skipms = 3000;
2493 const char *fwd =
"#", *rev =
"*", *suspend = NULL, *
stop = NULL;
2498 if (argc < 5 || argc > 10) {
2499 return RESULT_SHOWUSAGE;
2502 if (!ast_strlen_zero(argv[4])) {
2506 if ((argc > 5) && (sscanf(argv[5],
"%30d", &skipms) != 1)) {
2507 return RESULT_SHOWUSAGE;
2510 if (argc > 6 && !ast_strlen_zero(argv[6])) {
2514 if (argc > 7 && !ast_strlen_zero(argv[7])) {
2518 if (argc > 8 && !ast_strlen_zero(argv[8])) {
2522 if (argc > 9 && (sscanf(argv[9],
"%30ld", &offsetms) != 1)) {
2523 return RESULT_SHOWUSAGE;
2529 if (res > 0 && stop && strchr(stop, res)) {
2531 snprintf(stopkeybuf,
sizeof(stopkeybuf),
"%c", res);
2544 snprintf(offsetbuf,
sizeof(offsetbuf),
"%ld", offsetms);
2547 ast_agi_send(agi->
fd, chan,
"200 result=%d endpos=%ld\n", res, offsetms);
2549 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2552 static int handle_streamfile(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2556 long sample_offset = 0, max_length;
2557 const char *edigits =
"";
2559 if (argc < 4 || argc > 5) {
2560 return RESULT_SHOWUSAGE;
2567 if ((argc > 4) && (sscanf(argv[4],
"%30ld", &sample_offset) != 1)) {
2568 return RESULT_SHOWUSAGE;
2571 if (!(fs =
ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2572 ast_agi_send(agi->
fd, chan,
"200 result=-1 endpos=%ld\n", sample_offset);
2573 return RESULT_FAILURE;
2576 if ((vfs =
ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
2577 ast_debug(1,
"Ooh, found a video stream, too\n");
2579 ast_verb(3,
"<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2581 edigits, sample_offset,
S_OR(ast_channel_language(chan),
"default"));
2598 sample_offset = (ast_channel_stream(chan)) ?
ast_tellstream(fs) : max_length;
2602 return RESULT_SUCCESS;
2604 ast_agi_send(agi->
fd, chan,
"200 result=%d endpos=%ld\n", res, sample_offset);
2607 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2615 long sample_offset = 0, max_length;
2617 const char *edigits =
"";
2619 if ( argc < 4 || argc > 5 )
2620 return RESULT_SHOWUSAGE;
2626 timeout = atoi(argv[4]);
2627 else if (ast_channel_pbx(chan)->dtimeoutms) {
2632 if (!(fs =
ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2633 ast_agi_send(agi->
fd, chan,
"200 result=-1 endpos=%ld\n", sample_offset);
2634 ast_log(LOG_WARNING,
"Unable to open %s\n", argv[2]);
2635 return RESULT_FAILURE;
2638 if ((vfs =
ast_openvstream(chan, argv[2], ast_channel_language(chan))))
2639 ast_debug(1,
"Ooh, found a video stream, too\n");
2641 ast_verb(3,
"Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2656 sample_offset = (ast_channel_stream(chan))?
ast_tellstream(fs):max_length;
2660 return RESULT_SUCCESS;
2667 if ( !strchr(edigits,res) )
2671 ast_agi_send(agi->
fd, chan,
"200 result=%d endpos=%ld\n", res, sample_offset);
2672 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2684 if (argc < 4 || argc > 5)
2685 return RESULT_SHOWUSAGE;
2686 if (sscanf(argv[2],
"%30d", &num) != 1)
2687 return RESULT_SHOWUSAGE;
2690 return RESULT_SUCCESS;
2691 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2692 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2695 static int handle_saydigits(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2700 return RESULT_SHOWUSAGE;
2701 if (sscanf(argv[2],
"%30d", &num) != 1)
2702 return RESULT_SHOWUSAGE;
2706 return RESULT_SUCCESS;
2707 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2708 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2711 static int handle_sayalpha(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2716 if (argc < 4 || argc > 5) {
2717 return RESULT_SHOWUSAGE;
2721 switch (argv[4][0]) {
2741 return RESULT_SHOWUSAGE;
2744 res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->
audio, agi->
ctrl);
2746 return RESULT_SUCCESS;
2747 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2748 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2751 static int handle_saydate(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2756 return RESULT_SHOWUSAGE;
2757 if (sscanf(argv[2],
"%30d", &num) != 1)
2758 return RESULT_SHOWUSAGE;
2759 res = ast_say_date(chan, num, argv[3], ast_channel_language(chan));
2761 return RESULT_SUCCESS;
2762 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2763 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2766 static int handle_saytime(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2771 return RESULT_SHOWUSAGE;
2772 if (sscanf(argv[2],
"%30d", &num) != 1)
2773 return RESULT_SHOWUSAGE;
2774 res = ast_say_time(chan, num, argv[3], ast_channel_language(chan));
2776 return RESULT_SUCCESS;
2777 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2778 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2781 static int handle_saydatetime(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2785 const char *format, *zone = NULL;
2788 return RESULT_SHOWUSAGE;
2794 if (!strcasecmp(ast_channel_language(chan),
"de")) {
2795 format =
"A dBY HMS";
2797 format =
"ABdY 'digits/at' IMp";
2801 if (argc > 5 && !ast_strlen_zero(argv[5]))
2805 return RESULT_SHOWUSAGE;
2807 res = ast_say_date_with_format(chan, unixtime, argv[3], ast_channel_language(chan), format, zone);
2809 return RESULT_SUCCESS;
2811 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2812 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2815 static int handle_sayphonetic(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2820 return RESULT_SHOWUSAGE;
2822 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->
audio, agi->
ctrl);
2824 return RESULT_SUCCESS;
2825 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2826 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2829 static int handle_getdata(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2831 int res, max, timeout;
2835 return RESULT_SHOWUSAGE;
2837 timeout = atoi(argv[3]);
2841 max = atoi(argv[4]);
2846 return RESULT_SUCCESS;
2848 ast_agi_send(agi->
fd, chan,
"200 result=%s (timeout)\n", data);
2850 ast_agi_send(agi->
fd, chan,
"200 result=-1\n");
2852 ast_agi_send(agi->
fd, chan,
"200 result=%s\n", data);
2853 return RESULT_SUCCESS;
2856 static int handle_setcontext(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2860 return RESULT_SHOWUSAGE;
2861 ast_channel_context_set(chan, argv[2]);
2862 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
2863 return RESULT_SUCCESS;
2866 static int handle_setextension(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2869 return RESULT_SHOWUSAGE;
2870 ast_channel_exten_set(chan, argv[2]);
2871 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
2872 return RESULT_SUCCESS;
2875 static int handle_setpriority(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2880 return RESULT_SHOWUSAGE;
2882 if (sscanf(argv[2],
"%30d", &pri) != 1) {
2884 S_COR(ast_channel_caller(chan)->
id.
number.valid, ast_channel_caller(chan)->
id.
number.str, NULL));
2886 return RESULT_SHOWUSAGE;
2890 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
2891 return RESULT_SUCCESS;
2894 static int handle_recordfile(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
2898 struct timeval start;
2899 long sample_offset = 0;
2908 char *silencestr = NULL;
2915 return RESULT_SHOWUSAGE;
2916 if (sscanf(argv[5],
"%30d", &ms) != 1)
2917 return RESULT_SHOWUSAGE;
2920 silencestr = strchr(argv[6],
's');
2921 if ((argc > 7) && (!silencestr))
2922 silencestr = strchr(argv[7],
's');
2923 if ((argc > 8) && (!silencestr))
2924 silencestr = strchr(argv[8],
's');
2927 if (strlen(silencestr) > 2) {
2928 if ((silencestr[0] ==
's') && (silencestr[1] ==
'=')) {
2932 silence = atoi(silencestr);
2940 rfmt =
ao2_bump(ast_channel_readformat(chan));
2943 ast_log(LOG_WARNING,
"Unable to set to linear mode, giving up\n");
2944 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
2945 return RESULT_FAILURE;
2949 ast_log(LOG_WARNING,
"Unable to create silence detector :(\n");
2950 ast_agi_send(agi->
fd, chan,
"200 result=-1\n");
2951 return RESULT_FAILURE;
2966 if ((argc > 6 && sscanf(argv[6],
"%30ld", &sample_offset) != 1 && !
ast_begins_with(argv[6],
"s="))
2974 ast_agi_send(agi->
fd, chan,
"200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
2976 fs =
ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
2979 ast_agi_send(agi->
fd, chan,
"200 result=%d (writefile)\n", res);
2981 ast_dsp_free(sildet);
2982 return RESULT_FAILURE;
2988 ast_channel_stream_set(chan, fs);
2994 if (ast_opt_transmit_silence) {
3003 ast_agi_send(agi->
fd, chan,
"200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3005 ast_dsp_free(sildet);
3008 return RESULT_FAILURE;
3013 ast_agi_send(agi->
fd, chan,
"200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3015 ast_dsp_free(sildet);
3018 return RESULT_FAILURE;
3021 case AST_FRAME_DTMF:
3030 ast_agi_send(agi->
fd, chan,
"200 result=%d (dtmf) endpos=%ld\n", f->
subclass.
integer, sample_offset);
3033 ast_dsp_free(sildet);
3036 return RESULT_SUCCESS;
3049 totalsilence = dspsilence;
3053 if (totalsilence > silence) {
3077 ast_agi_send(agi->
fd, chan,
"200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3083 ast_log(LOG_WARNING,
"Unable to restore read format on '%s'\n", ast_channel_name(chan));
3084 ast_dsp_free(sildet);
3091 return RESULT_SUCCESS;
3094 static int handle_autohangup(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3097 struct timeval whentohangup = { 0, 0 };
3100 return RESULT_SHOWUSAGE;
3101 if (sscanf(argv[2],
"%30lf", &timeout) != 1)
3102 return RESULT_SHOWUSAGE;
3106 whentohangup.tv_sec = timeout;
3107 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3109 ast_channel_lock(chan);
3111 ast_channel_unlock(chan);
3112 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3113 return RESULT_SUCCESS;
3116 static int handle_hangup(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3124 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3125 return RESULT_SUCCESS;
3126 }
else if (argc == 2) {
3133 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3134 return RESULT_SUCCESS;
3137 ast_agi_send(agi->
fd, chan,
"200 result=-1\n");
3138 return RESULT_SUCCESS;
3140 return RESULT_SHOWUSAGE;
3146 int res, workaround;
3148 const char *agi_exec_full_str;
3150 struct ast_str *data_with_var = NULL;
3153 return RESULT_SHOWUSAGE;
3155 ast_verb(3,
"AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] :
"");
3158 ast_channel_lock(chan);
3163 agi_exec_full =
ast_true(agi_exec_full_str);
3164 ast_channel_unlock(chan);
3166 if (agi_exec_full) {
3170 ast_free(data_with_var);
3175 res =
pbx_exec(chan, app_to_exec, argc == 2 ?
"" : argv[2]);
3181 ast_log(LOG_WARNING,
"Could not find application (%s)\n", argv[1]);
3184 ast_agi_send(agi->
fd, chan,
"200 result=%d\n", res);
3190 static int handle_setcallerid(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3193 char *l = NULL, *n = NULL;
3207 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3208 return RESULT_SUCCESS;
3211 static int handle_channelstatus(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3216 return RESULT_SUCCESS;
3217 }
else if (argc == 3) {
3223 ast_agi_send(agi->
fd, chan,
"200 result=%u\n", snapshot->
state);
3225 return RESULT_SUCCESS;
3228 ast_agi_send(agi->
fd, chan,
"200 result=-1\n");
3229 return RESULT_SUCCESS;
3231 return RESULT_SHOWUSAGE;
3235 static int handle_setvariable(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3238 return RESULT_SHOWUSAGE;
3244 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3245 return RESULT_SUCCESS;
3248 static int handle_getvariable(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3251 char tempstr[1024] =
"";
3254 return RESULT_SHOWUSAGE;
3257 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] ==
')')) {
3258 ret =
ast_func_read(chan, argv[2], tempstr,
sizeof(tempstr)) ? NULL : tempstr;
3264 ast_agi_send(agi->
fd, chan,
"200 result=1 (%s)\n", ret);
3266 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3268 return RESULT_SUCCESS;
3271 static int handle_getvariablefull(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3275 if (argc != 4 && argc != 5) {
3276 return RESULT_SHOWUSAGE;
3288 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3289 return RESULT_SUCCESS;
3295 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3302 return RESULT_SUCCESS;
3305 static int handle_verbose(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3310 return RESULT_SHOWUSAGE;
3313 sscanf(argv[2],
"%30d", &level);
3315 ast_verb(level,
"%s: %s\n", ast_channel_data(chan), argv[1]);
3317 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3319 return RESULT_SUCCESS;
3322 static int handle_dbget(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3328 return RESULT_SHOWUSAGE;
3331 ast_agi_send(agi->
fd, chan,
"200 result=-1\n");
3332 return RESULT_SUCCESS;
3347 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3352 return RESULT_SUCCESS;
3355 static int handle_dbput(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3360 return RESULT_SHOWUSAGE;
3362 ast_agi_send(agi->
fd, chan,
"200 result=%c\n", res ?
'0' :
'1');
3363 return RESULT_SUCCESS;
3366 static int handle_dbdel(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3371 return RESULT_SHOWUSAGE;
3373 ast_agi_send(agi->
fd, chan,
"200 result=%c\n", res ?
'0' :
'1');
3374 return RESULT_SUCCESS;
3377 static int handle_dbdeltree(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3381 if ((argc < 3) || (argc > 4)) {
3382 return RESULT_SHOWUSAGE;
3390 ast_agi_send(agi->
fd, chan,
"200 result=%c\n", num_deleted > 0 ?
'0' :
'1');
3391 return RESULT_SUCCESS;
3398 e->
command =
"agi set debug [on|off]";
3400 "Usage: agi set debug [on|off]\n"
3401 " Enables/disables dumping of AGI transactions for\n"
3402 " debugging purposes.\n";
3409 if (a->argc != e->
args)
3410 return CLI_SHOWUSAGE;
3412 if (strncasecmp(a->argv[3],
"off", 3) == 0) {
3414 }
else if (strncasecmp(a->argv[3],
"on", 2) == 0) {
3417 return CLI_SHOWUSAGE;
3419 ast_cli(a->fd,
"AGI Debugging %sabled\n", agidebug ?
"En" :
"Dis");
3423 static int handle_noop(
struct ast_channel *chan,
AGI *agi,
int arg,
const char *
const argv[])
3425 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3426 return RESULT_SUCCESS;
3429 static int handle_setmusic(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3432 return RESULT_SHOWUSAGE;
3434 if (!strncasecmp(argv[2],
"on", 2))
3436 else if (!strncasecmp(argv[2],
"off", 3))
3438 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3439 return RESULT_SUCCESS;
3442 static int handle_speechcreate(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3448 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3449 return RESULT_SUCCESS;
3453 return RESULT_FAILURE;
3457 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3459 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3463 return RESULT_SUCCESS;
3466 static int handle_speechset(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3470 return RESULT_SHOWUSAGE;
3474 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3475 return RESULT_SUCCESS;
3479 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3481 return RESULT_SUCCESS;
3484 static int handle_speechdestroy(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3489 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3491 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3494 return RESULT_SUCCESS;
3497 static int handle_speechloadgrammar(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3500 return RESULT_SHOWUSAGE;
3503 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3504 return RESULT_SUCCESS;
3508 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3510 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3512 return RESULT_SUCCESS;
3515 static int handle_speechunloadgrammar(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3518 return RESULT_SHOWUSAGE;
3521 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3522 return RESULT_SUCCESS;
3526 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3528 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3530 return RESULT_SUCCESS;
3533 static int handle_speechactivategrammar(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3536 return RESULT_SHOWUSAGE;
3539 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3540 return RESULT_SUCCESS;
3544 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3546 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3548 return RESULT_SUCCESS;
3551 static int handle_speechdeactivategrammar(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3554 return RESULT_SHOWUSAGE;
3557 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3558 return RESULT_SUCCESS;
3562 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3564 ast_agi_send(agi->
fd, chan,
"200 result=1\n");
3566 return RESULT_SUCCESS;
3588 static int handle_speechrecognize(
struct ast_channel *chan,
AGI *agi,
int argc,
const char *
const argv[])
3592 char dtmf = 0, tmp[4096] =
"", *buf = tmp;
3593 int timeout = 0, offset = 0, res = 0, i = 0;
3594 long current_offset = 0;
3595 const char *reason = NULL;
3598 size_t left =
sizeof(tmp);
3599 time_t start = 0, current;
3602 return RESULT_SHOWUSAGE;
3605 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3606 return RESULT_SUCCESS;
3610 timeout = atoi(argv[3]);
3614 offset = atoi(argv[4]);
3618 ast_agi_send(agi->
fd, chan,
"200 result=0\n");
3619 return RESULT_SUCCESS;
3623 if (speech->
state == AST_SPEECH_STATE_NOT_READY || speech->
state == AST_SPEECH_STATE_DONE) {
3632 while (ast_strlen_zero(reason)) {
3649 if ((timeout > 0) && (start > 0)) {
3651 if ((current - start) >= timeout) {
3660 ast_mutex_lock(&speech->
lock);
3663 if (ast_test_flag(speech, AST_SPEECH_QUIET) && ast_channel_stream(chan)) {
3666 ast_clear_flag(speech, AST_SPEECH_QUIET);
3670 switch (speech->
state) {
3671 case AST_SPEECH_STATE_READY:
3673 if ((timeout > 0) && start == 0 && ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL))) {
3681 case AST_SPEECH_STATE_WAIT:
3683 if ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL)) {
3690 case AST_SPEECH_STATE_DONE:
3700 ast_mutex_unlock(&speech->
lock);
3714 if (!strcasecmp(reason,
"speech")) {
3723 ast_agi_send(agi->
fd, chan,
"200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3724 }
else if (!strcasecmp(reason,
"dtmf")) {
3725 ast_agi_send(agi->
fd, chan,
"200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3726 }
else if (!strcasecmp(reason,
"hangup") || !strcasecmp(reason,
"timeout")) {
3727 ast_agi_send(agi->
fd, chan,
"200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3729 ast_agi_send(agi->
fd, chan,
"200 result=0 endpos=%ld\n", current_offset);
3732 return RESULT_SUCCESS;
3739 { {
"answer", NULL }, handle_answer, NULL, NULL, 0 },
3740 { {
"asyncagi",
"break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
3741 { {
"channel",
"status", NULL }, handle_channelstatus, NULL, NULL, 0 },
3742 { {
"database",
"del", NULL }, handle_dbdel, NULL, NULL, 1 },
3743 { {
"database",
"deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
3744 { {
"database",
"get", NULL }, handle_dbget, NULL, NULL, 1 },
3745 { {
"database",
"put", NULL }, handle_dbput, NULL, NULL, 1 },
3747 { {
"get",
"data", NULL }, handle_getdata, NULL, NULL, 0 },
3748 { {
"get",
"full",
"variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
3750 { {
"get",
"variable", NULL }, handle_getvariable, NULL, NULL, 1 },
3751 { {
"hangup", NULL }, handle_hangup, NULL, NULL, 0 },
3752 { {
"noop", NULL }, handle_noop, NULL, NULL, 1 },
3753 { {
"receive",
"char", NULL }, handle_recvchar, NULL, NULL, 0 },
3754 { {
"receive",
"text", NULL }, handle_recvtext, NULL, NULL, 0 },
3755 { {
"record",
"file", NULL }, handle_recordfile, NULL, NULL, 0 },
3756 { {
"say",
"alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
3757 { {
"say",
"digits", NULL }, handle_saydigits, NULL, NULL, 0 },
3759 { {
"say",
"phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
3760 { {
"say",
"date", NULL }, handle_saydate, NULL, NULL, 0},
3761 { {
"say",
"time", NULL }, handle_saytime, NULL, NULL, 0},
3762 { {
"say",
"datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
3763 { {
"send",
"image", NULL }, handle_sendimage, NULL, NULL, 0},
3764 { {
"send",
"text", NULL }, handle_sendtext, NULL, NULL, 0},
3765 { {
"set",
"autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
3766 { {
"set",
"callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
3767 { {
"set",
"context", NULL }, handle_setcontext, NULL, NULL, 0},
3768 { {
"set",
"extension", NULL }, handle_setextension, NULL, NULL, 0},
3769 { {
"set",
"music", NULL }, handle_setmusic, NULL, NULL, 0 },
3770 { {
"set",
"priority", NULL }, handle_setpriority, NULL, NULL, 0 },
3771 { {
"set",
"variable", NULL }, handle_setvariable, NULL, NULL, 1 },
3772 { {
"stream",
"file", NULL }, handle_streamfile, NULL, NULL, 0 },
3773 { {
"control",
"stream",
"file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
3774 { {
"tdd",
"mode", NULL }, handle_tddmode, NULL, NULL, 0 },
3775 { {
"verbose", NULL }, handle_verbose, NULL, NULL, 1 },
3776 { {
"wait",
"for",
"digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
3777 { {
"speech",
"create", NULL }, handle_speechcreate, NULL, NULL, 0 },
3778 { {
"speech",
"set", NULL }, handle_speechset, NULL, NULL, 0 },
3779 { {
"speech",
"destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
3780 { {
"speech",
"load",
"grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
3781 { {
"speech",
"unload",
"grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
3782 { {
"speech",
"activate",
"grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
3783 { {
"speech",
"deactivate",
"grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
3784 { {
"speech",
"recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
3789 static char *help_workhorse(
int fd,
const char *
const match[])
3791 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3795 ast_join(matchstr,
sizeof(matchstr), match);
3797 ast_cli(fd,
"%5.5s %30.30s %s\n",
"Dead",
"Command",
"Description");
3803 if ((e->
cmda[0])[0] ==
'_')
3806 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3808 ast_cli(fd,
"%5.5s %30.30s %s\n", e->
dead ?
"Yes" :
"No" , fullcmd,
S_OR(e->
summary,
"Not available"));
3817 char fullcmd[MAX_CMD_LEN];
3819 ast_join(fullcmd,
sizeof(fullcmd), cmd->cmda);
3821 if (!find_command(cmd->cmda, 1)) {
3823 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3831 #ifndef HAVE_NULLSAFE_PRINTF
3832 if (!cmd->summary) {
3841 if (!cmd->seealso) {
3851 ast_verb(5,
"AGI Command '%s' registered\n",fullcmd);
3854 ast_log(LOG_WARNING,
"Command already registered!\n");
3862 int unregistered = 0;
3863 char fullcmd[MAX_CMD_LEN];
3865 ast_join(fullcmd,
sizeof(fullcmd), cmd->cmda);
3870 AST_RWLIST_REMOVE_CURRENT(
list);
3873 ast_free((
char *) e->
summary);
3874 ast_free((
char *) e->
usage);
3875 ast_free((
char *) e->
syntax);
3876 ast_free((
char *) e->
seealso);
3877 *((
char **) &e->
summary) = NULL;
3878 *((
char **) &e->
usage) = NULL;
3879 *((
char **) &e->
syntax) = NULL;
3880 *((
char **) &e->
seealso) = NULL;
3887 AST_RWLIST_TRAVERSE_SAFE_END;
3890 ast_verb(5,
"AGI Command '%s' unregistered\n",fullcmd);
3892 return unregistered;
3897 unsigned int i, x = 0;
3899 for (i = 0; i < len; i++) {
3900 if (ast_agi_register(mod, cmd + i) == 1) {
3908 for (; x > 0; x--) {
3917 (void) ast_agi_unregister(cmd + x - 1);
3930 for (i = 0; i < len; i++) {
3935 res |= ast_agi_unregister(cmd + i);
3941 static agi_command *find_command(
const char *
const cmds[],
int exact)
3952 for (y = 0; match && cmds[y]; y++) {
3956 if (!e->
cmda[y] && !exact)
3963 if (strcasecmp(e->
cmda[y], cmds[y]))
3968 if ((exact > -1) && e->
cmda[y])
3979 static int parse_args(
char *s,
int *max,
const char *argv[])
3981 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
3993 if (quoted && whitespace) {
4002 if (!quoted && !escaped) {
4023 ast_log(LOG_WARNING,
"Too many arguments, truncating\n");
4042 static void publish_async_exec_end(
struct ast_channel *chan,
int command_id,
const char *command,
int result_code,
const char *result)
4046 "CommandId", command_id,
4048 "ResultCode", result_code,
4053 static enum agi_result agi_handle_command(
struct ast_channel *chan,
AGI *agi,
char *buf,
int dead)
4060 const char *ami_res;
4061 int command_id = ast_random();
4066 "CommandId", command_id,
4067 "Command", ami_cmd);
4070 parse_args(buf, &argc, argv);
4071 c = find_command(argv, 0);
4073 ami_res =
"Invalid or unknown command";
4076 ast_agi_send(agi->
fd, chan,
"%d %s\n", resultcode, ami_res);
4078 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4080 return AGI_RESULT_SUCCESS;
4083 if (!dead || (dead && c->
dead)) {
4084 res = c->
handler(chan, agi, argc, argv);
4086 case RESULT_SHOWUSAGE:
4090 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4092 if (ast_strlen_zero(c->
usage)) {
4093 ast_agi_send(agi->
fd, chan,
"520 Invalid command syntax. Proper usage not available.\n");
4095 ast_agi_send(agi->
fd, chan,
"520-Invalid command syntax. Proper usage follows:\n");
4096 ast_agi_send(agi->
fd, chan,
"%s\n", c->
usage);
4097 ast_agi_send(agi->
fd, chan,
"520 End of proper usage.\n");
4101 case RESULT_FAILURE:
4102 ami_res =
"Failure";
4105 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4108 return AGI_RESULT_FAILURE;
4110 ami_res =
"Success";
4113 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4115 return AGI_RESULT_SUCCESS_ASYNC;
4116 case RESULT_SUCCESS:
4117 ami_res =
"Success";
4120 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4124 ami_res =
"Unknown Result";
4127 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4132 ami_res =
"Command Not Permitted on a dead channel or intercept routine";
4135 ast_agi_send(agi->
fd, chan,
"%d %s\n", resultcode, ami_res);
4137 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4141 return AGI_RESULT_SUCCESS;
4144 static enum agi_result
run_agi(
struct ast_channel *chan,
char *request,
AGI *agi,
int pid,
int *status,
int dead,
int argc,
char *argv[])
4150 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
4152 char buf[AGI_BUF_LEN];
4157 int retry = AGI_NANDFS_RETRY;
4159 const char *sighup_str;
4160 const char *exit_on_hangup_str;
4165 ast_channel_lock(chan);
4169 exit_on_hangup =
ast_true(exit_on_hangup_str);
4170 ast_channel_unlock(chan);
4172 if (!(readf = fdopen(agi->
ctrl,
"r"))) {
4173 ast_log(LOG_WARNING,
"Unable to fdopen file descriptor\n");
4174 if (send_sighup && pid > -1)
4177 return AGI_RESULT_FAILURE;
4181 setup_env(chan, request, agi->
fd, (agi->
audio > -1), argc, argv);
4189 }
else if (agi->
fast) {
4190 ast_agi_send(agi->
fd, chan,
"HANGUP\n");
4193 if (exit_on_hangup) {
4198 if (dead || in_intercept) {
4210 retry = AGI_NANDFS_RETRY;
4214 ast_debug(1,
"%s hungup\n", ast_channel_name(chan));
4216 if (!returnstatus) {
4217 returnstatus = AGI_RESULT_HANGUP;
4228 }
else if (outfd > -1) {
4229 size_t len =
sizeof(buf);
4231 enum agi_result cmd_status;
4233 retry = AGI_NANDFS_RETRY;
4237 res = fgets(buf + buflen, len, readf);
4240 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
4242 if (res != NULL && !agi->
fast)
4244 buflen = strlen(buf);
4245 if (buflen && buf[buflen - 1] ==
'\n')
4247 len =
sizeof(buf) - buflen;
4249 ast_verbose(
"AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
4254 ast_verb(3,
"<%s>AGI Script %s completed, returning %d\n", ast_channel_name(chan), request, returnstatus);
4256 waitpid(pid, status, 0);
4263 if (*buf && strncasecmp(buf,
"failure", 7) == 0) {
4264 returnstatus = AGI_RESULT_FAILURE;
4269 buflen = strlen(buf);
4270 if (buflen && buf[buflen - 1] ==
'\n') {
4271 buf[buflen - 1] =
'\0';
4275 ast_verbose(
"<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
4276 cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
4277 switch (cmd_status) {
4278 case AGI_RESULT_FAILURE:
4281 returnstatus = AGI_RESULT_FAILURE;
4289 ast_log(LOG_WARNING,
"No channel, no fd?\n");
4290 returnstatus = AGI_RESULT_FAILURE;
4302 if (kill(pid, SIGHUP)) {
4303 ast_log(LOG_WARNING,
"unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
4307 waitpid(pid, status, WNOHANG);
4308 }
else if (agi->
fast) {
4309 ast_agi_send(agi->
fd, chan,
"HANGUP\n");
4313 return returnstatus;
4319 char fullcmd[MAX_CMD_LEN];
4324 e->
command =
"agi show commands [topic]";
4326 "Usage: agi show commands [topic] <topic>\n"
4327 " When called with a topic as an argument, displays usage\n"
4328 " information on the given command. If called without a\n"
4329 " topic, it provides a list of AGI commands.\n";
4333 if (a->argc < e->
args - 1 || (a->argc >= e->
args && strcasecmp(a->argv[e->
args - 1],
"topic")))
4334 return CLI_SHOWUSAGE;
4335 if (a->argc > e->
args - 1) {
4336 command = find_command(a->argv + e->
args, 1);
4338 char *synopsis = NULL, *description = NULL, *
syntax = NULL, *
seealso = NULL;
4339 char info[30 + MAX_CMD_LEN];
4347 size_t synlen, desclen, seealsolen, stxlen;
4349 term_color(syntitle,
"[Synopsis]\n", COLOR_MAGENTA, 0,
sizeof(syntitle));
4350 term_color(desctitle,
"[Description]\n", COLOR_MAGENTA, 0,
sizeof(desctitle));
4351 term_color(deadtitle,
"[Runs Dead]\n", COLOR_MAGENTA, 0,
sizeof(deadtitle));
4352 term_color(seealsotitle,
"[See Also]\n", COLOR_MAGENTA, 0,
sizeof(seealsotitle));
4353 term_color(stxtitle,
"[Syntax]\n", COLOR_MAGENTA, 0,
sizeof(stxtitle));
4354 term_color(deadcontent, command->
dead ?
"Yes" :
"No", COLOR_CYAN, 0,
sizeof(deadcontent));
4357 snprintf(info,
sizeof(info),
"\n -= Info about agi '%s' =- ", fullcmd);
4358 term_color(infotitle, info, COLOR_CYAN, 0,
sizeof(infotitle));
4364 if (!seealso || !description || !synopsis) {
4366 goto return_cleanup;
4380 if (!synopsis || !description || !seealso) {
4382 goto return_cleanup;
4393 goto return_cleanup;
4397 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,
4398 desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
4399 seealsotitle, seealso);
4402 ast_free(description);
4406 if (find_command(a->argv + e->
args, -1)) {
4407 return help_workhorse(a->fd, a->argv + e->
args);
4410 ast_cli(a->fd,
"No such command '%s'.\n", fullcmd);
4414 return help_workhorse(a->fd, NULL);
4416 return (error ? CLI_FAILURE : CLI_SUCCESS);
4429 fprintf(htmlfile,
"%s",
"<");
4432 fprintf(htmlfile,
"%s",
">");
4435 fprintf(htmlfile,
"%s",
"&");
4438 fprintf(htmlfile,
"%s",
""");
4441 fprintf(htmlfile,
"%c", *cur);
4450 static int write_htmldump(
const char *filename)
4453 char fullcmd[MAX_CMD_LEN];
4456 if (!(htmlfile = fopen(filename,
"wt")))
4459 fprintf(htmlfile,
"<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4460 fprintf(htmlfile,
"<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4461 fprintf(htmlfile,
"<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4465 char *tempstr, *stringp;
4467 if (!command->
cmda[0])
4470 if ((command->
cmda[0])[0] ==
'_')
4474 fprintf(htmlfile,
"<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4475 fprintf(htmlfile,
"<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->
summary);
4481 tempstr = strsep(&stringp,
"\n");
4483 fprintf(htmlfile,
"<TR><TD ALIGN=\"CENTER\">");
4485 fprintf(htmlfile,
"</TD></TR>\n");
4486 fprintf(htmlfile,
"<TR><TD ALIGN=\"CENTER\">\n");
4488 while ((tempstr = strsep(&stringp,
"\n")) != NULL) {
4490 fprintf(htmlfile,
"<BR>\n");
4492 fprintf(htmlfile,
"</TD></TR>\n");
4493 fprintf(htmlfile,
"</TABLE></TD></TR>\n\n");
4497 fprintf(htmlfile,
"</TABLE>\n</BODY>\n</HTML>\n");
4508 "Usage: agi dump html <filename>\n"
4509 " Dumps the AGI command list in HTML format to the given\n"
4515 if (a->argc != e->
args + 1)
4516 return CLI_SHOWUSAGE;
4518 if (write_htmldump(a->argv[e->
args]) < 0) {
4519 ast_cli(a->fd,
"Could not create file '%s'\n", a->argv[e->
args]);
4520 return CLI_SHOWUSAGE;
4522 ast_cli(a->fd,
"AGI HTML commands dumped to: %s\n", a->argv[e->
args]);
4526 static int agi_exec_full(
struct ast_channel *chan,
const char *data,
int enhanced,
int dead)
4528 enum agi_result res;
4530 int fds[2], efd = -1, pid = -1;
4536 if (ast_strlen_zero(data)) {
4537 ast_log(LOG_WARNING,
"AGI requires an argument (script)\n");
4541 ast_debug(3,
"Hungup channel detected, running agi in dead mode.\n");
4542 memset(&agi, 0,
sizeof(agi));
4545 args.arg[args.argc] = NULL;
4553 res = launch_script(chan, args.arg[0], args.argc, args.arg, fds, enhanced ? &efd : NULL, &pid);
4556 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
4561 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
4562 res =
run_agi(chan, args.arg[0], &agi, pid, &status, dead, args.argc, args.arg);
4564 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
4565 res = AGI_RESULT_FAILURE;
4566 if (fds[1] != fds[0])
4574 case AGI_RESULT_SUCCESS:
4575 case AGI_RESULT_SUCCESS_FAST:
4576 case AGI_RESULT_SUCCESS_ASYNC:
4579 case AGI_RESULT_FAILURE:
4582 case AGI_RESULT_NOTFOUND:
4585 case AGI_RESULT_HANGUP:
4593 static int agi_exec(
struct ast_channel *chan,
const char *data)
4596 return agi_exec_full(chan, data, 0, 0);
4598 return agi_exec_full(chan, data, 0, 1);
4601 static int eagi_exec(
struct ast_channel *chan,
const char *data)
4606 const char *requested_format_name;
4609 ast_log(LOG_ERROR,
"EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4614 if (requested_format_name) {
4616 if (requested_format) {
4617 ast_verb(3,
"<%s> Setting EAGI audio pipe format to %s\n",
4620 ast_log(LOG_ERROR,
"Could not find requested format: %s\n", requested_format_name);
4624 readformat =
ao2_bump(ast_channel_readformat(chan));
4626 ast_log(LOG_WARNING,
"Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
4627 ao2_cleanup(requested_format);
4628 ao2_cleanup(readformat);
4631 res = agi_exec_full(chan, data, 1, 0);
4634 ast_log(LOG_WARNING,
"Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
4638 ao2_cleanup(requested_format);
4639 ao2_cleanup(readformat);
4643 static int deadagi_exec(
struct ast_channel *chan,
const char *data)
4645 ast_log(LOG_WARNING,
"DeadAGI has been deprecated, please use AGI in all cases!\n");
4646 return agi_exec(chan, data);
4651 AST_CLI_DEFINE(handle_cli_agi_debug,
"Enable/Disable AGI debugging"),
4652 AST_CLI_DEFINE(handle_cli_agi_show,
"List AGI commands or specific help"),
4653 AST_CLI_DEFINE(handle_cli_agi_dump_html,
"Dumps a list of AGI commands in HTML format")
4656 #ifdef TEST_FRAMEWORK
4659 int res = AST_TEST_PASS;
4661 { {
"testnoop", NULL }, handle_noop, NULL, NULL, 0 };
4665 info->name =
"null_agi_docs";
4666 info->category =
"/res/agi/";
4667 info->summary =
"AGI command with no documentation";
4668 info->description =
"Test whether an AGI command with no documentation will crash Asterisk";
4669 return AST_TEST_NOT_RUN;
4675 ast_test_status_update(
test,
"Unable to register testnoop command, because res_agi is not loaded.\n");
4676 return AST_TEST_NOT_RUN;
4679 #ifndef HAVE_NULLSAFE_PRINTF
4681 if (noop_command.
usage == NULL) {
4682 ast_test_status_update(
test,
"AGI testnoop usage was not updated properly.\n");
4683 res = AST_TEST_FAIL;
4685 if (noop_command.
syntax == NULL) {
4686 ast_test_status_update(
test,
"AGI testnoop syntax was not updated properly.\n");
4687 res = AST_TEST_FAIL;
4691 ast_agi_unregister(&noop_command);
4696 static int unload_module(
void)
4705 ast_agi_unregister_multiple(commands, ARRAY_LEN(commands));
4710 AST_TEST_UNREGISTER(test_agi_null_docs);
4714 static int load_module(
void)
4731 AST_TEST_REGISTER(test_agi_null_docs);
4741 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Asterisk Gateway Interface (AGI)",
4742 .support_level = AST_MODULE_SUPPORT_CORE,
4743 .load = load_module,
4744 .unload = unload_module,
4746 .requires =
"res_speech",
const char *const summary
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
const char *const seealso
Struct containing info for an AMI event to send out.
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
Main Channel structure associated with a channel.
SAY_EXTERN int(* ast_say_number_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_number_full)
Same as ast_say_number() with audiofd for received audio and returns 1 on ctrlfd being readable...
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Generic Speech Recognition API.
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
int(*const handler)(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
String manipulation functions.
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_speech_start(struct ast_speech *speech)
Indicate to the speech engine that audio is now going to start being written.
#define ast_join(s, len, w)
Join an array of strings into a single string.
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Asterisk version information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define ast_channel_unref(c)
Decrease channel reference count.
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
#define MAX_ARGS
Maximum number of arguments for the Stasis dialplan application.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
struct ast_channel_snapshot * snapshot
Convenient Signal Processing routines.
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
AGI Extension interfaces - Asterisk Gateway Interface.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
descriptor for a cli entry.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Support for DNS SRV records, used in to locate SIP services.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Structure representing a snapshot of channel state.
void ast_srv_cleanup(struct srv_context **context)
Cleanup resources associated with ast_srv_lookup.
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Structure for a data store type.
ast_channel_state
ast_channel states
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Get speech recognition results.
static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
Helper function used by speech_background to playback a soundfile.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
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 get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
Retrieve the list head to the requested channel's AGI datastore.
int ast_unregister_application(const char *app)
Unregister an application.
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
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
Socket address structure.
ast_doc_src
From where the documentation come from, this structure is useful for use it inside application/functi...
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
int ast_send_image(struct ast_channel *chan, const char *filename)
Sends an image.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Blob of data associated with a channel.
int args
This gets set in ast_cli_register()
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
#define AST_TERM_MAX_ESCAPE_CHARS
Maximum number of characters needed for a color escape sequence, and another one for a trailing reset...
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
Parse a time (integer) string.
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other fu...
General Asterisk channel definitions for image handling.
int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
Deactivate a grammar on a speech structure.
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest_by_name(const char *name)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
struct ast_filestream * ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
General Asterisk PBX channel definitions.
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Asterisk file paths, configured in asterisk.conf.
SAY_EXTERN int(* ast_say_digit_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_digit_str_full)
Same as ast_say_digit_str() with audiofd for received audio and returns 1 on ctrlfd being readable...
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
#define ast_strdupa(s)
duplicate a string in memory from the stack
void ast_safe_fork_cleanup(void)
Common routine to cleanup after fork'ed process is complete (if reaping was stopped) ...
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
static struct agi_command commands[]
AGI commands list.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
Unload a grammar.
struct ast_speech_result * results
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
Wrapper for network related headers, masking differences between various operating systems...
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applies a open stream to a channel.
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
char * ast_recvtext(struct ast_channel *chan, int timeout)
Receives a text string from a channel Read a string of text from a channel.
const char *const cmda[AST_MAX_CMD_LEN]
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
Activate a grammar on a speech structure.
struct agi_command::@179 list
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
struct ast_speech * speech
static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
Say number in various language syntaxes.
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
union ast_frame::@224 data
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define ast_calloc(num, len)
A wrapper for calloc()
static char * handle_exec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI support for executing application.
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Asterisk XML Documentation API.
Module has failed to load, may be in an inconsistent state.
enum ast_channel_state state
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the node content.
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
#define ast_module_unref(mod)
Release a reference to the module.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
STASIS_MESSAGE_TYPE_DEFN_LOCAL(cdr_sync_message_type)
A message type used to synchronize with the CDR topic.
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
#define ast_channel_ref(c)
Increase channel reference count.
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Standard Command Line Interface.
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
ast_app: A registered application
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
struct ast_speech * ast_speech_new(const char *engine_name, const struct ast_format_cap *formats)
Create a new speech structure.
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_answer(struct ast_channel *chan)
Answer a channel.
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Data structure associated with a single frame of data.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
#define AST_TEST_DEFINE(hdr)
Abstract JSON element (object, array, string, int, ...).
int ast_channel_get_intercept_mode(void)
Am I currently running an intercept dialplan routine.
Handy terminal functions for vt* terms.
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
enum ast_frame_type frametype
#define AST_OPTIONAL_API_NAME(name)
Expands to the name of the implementation function.
static void write_html_escaped(FILE *htmlfile, char *str)
Convert string to use HTML escaped characters.
struct ast_filestream * vfs
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
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.
int ast_speech_write(struct ast_speech *speech, void *data, int len)
Write audio to the speech engine.
int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Load a grammar on a speech structure (not globally)
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s...
struct ast_app * pbx_findapp(const char *app)
Look up an application.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Persistent data storage (akin to *doze registry)
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_waitfordigit_full(struct ast_channel *c, int ms, const char *breakon, int audiofd, int ctrlfd)
Wait for a digit Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to mon...
int ast_stopstream(struct ast_channel *c)
Stops a stream.
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
struct ast_filestream * ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
#define AST_APP_ARG(name)
Define an application argument.
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)