1384#define MAX_CMD_LEN 80
1385#define AGI_NANDFS_RETRY 3
1386#define AGI_BUF_LEN 2048
1387#define SRV_PREFIX "_agi._tcp."
1397#define TONE_BLOCK_SIZE 200
1400#define MAX_AGI_CONNECT 2000
1402#define AGI_PORT 4573
1405#define ASYNC_AGI_BREAK 3
1424 if (!channel_string || !event_string) {
1479#define AGI_BUF_INITSIZE 256
1562 ast_log(
LOG_ERROR,
"Huh? Async AGI datastore disappeared on Channel %s!\n",
1629 agi_cmds_list =
ast_calloc(1,
sizeof(*agi_cmds_list));
1630 if (!agi_cmds_list) {
1635 datastore->
data = agi_cmds_list;
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";
1672 ast_cli(
a->fd,
"Channel %s does not exist.\n",
a->argv[2]);
1678 if (
add_agi_cmd(chan,
a->argv[3], (
a->argc > 4 ?
a->argv[4] :
""))) {
1718 snprintf(
buf,
sizeof(
buf),
"Channel %s does not exist.", channel);
1801#define AGI_BUF_SIZE 1024
1802#define AMI_BUF_SIZE 2048
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);
1853 ast_log(
LOG_ERROR,
"Failed to read from Async AGI pipe on channel %s: %s\n",
1856 goto async_agi_abort;
1858 agi_buffer[res] =
'\0';
1880 goto async_agi_done;
1894 ast_log(
LOG_ERROR,
"Failed to read from Async AGI pipe on channel %s: %s\n",
1898 goto async_agi_done;
1905 agi_buffer[res] =
'\0';
1921 switch (cmd_status) {
1926 goto async_agi_done;
1932 goto async_agi_done;
1957 returnstatus = cmd_status;
1958 goto async_agi_done;
1990 return returnstatus;
2009 struct pollfd pfds[1];
2013 reslen =
sizeof(conresult);
2015 pfds[0].fd = netsockfd;
2016 pfds[0].events = POLLOUT;
2019 if (
errno != EINTR) {
2021 ast_log(
LOG_WARNING,
"FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
2031 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
2051 char *host, *script;
2052 int num_addrs = 0, i = 0;
2059 if ((script = strchr(host,
'/'))) {
2070 for (i = 0; i < num_addrs; i++) {
2097 if (i == num_addrs) {
2103 if (
errno != EINTR) {
2143 char *host, *script;
2148 char resolved_uri[1024];
2149 const char *srvhost;
2150 unsigned short srvport;
2153 if (strlen(agiurl) < 7) {
2160 if ((script = strchr(host,
'/'))) {
2166 if (strchr(host,
':')) {
2174 snprintf(resolved_uri,
sizeof(resolved_uri),
"agi://%s:%d/%s", srvhost, srvport, script);
2177 ast_log(
LOG_WARNING,
"AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
2198 int pid, toast[2], fromast[2], audio[2], res;
2202 *safe_fork_called = 0;
2204 if (!strncasecmp(script,
"agi://", 6)) {
2207 if (!strncasecmp(script,
"hagi://", 7)) {
2210 if (!strncasecmp(script,
"agi:async",
sizeof(
"agi:async") - 1)) {
2214 if (script[0] !=
'/') {
2220 if (stat(script, &st)) {
2229 if (pipe(fromast)) {
2258 *safe_fork_called = 1;
2282 dup2(fromast[0], STDIN_FILENO);
2283 dup2(toast[1], STDOUT_FILENO);
2285 dup2(audio[0], STDERR_FILENO + 1);
2287 close(STDERR_FILENO + 1);
2294 execv(script, argv);
2298 fprintf(stdout,
"failure\n");
2302 ast_verb(3,
"Launched AGI Script %s\n", script);
2304 fds[1] = fromast[1];
2349 ast_agi_send(fd, chan,
"agi_enhanced: %s\n", enhanced ?
"1.0" :
"0.0");
2353 ast_agi_send(fd, chan,
"agi_threadid: %ld\n", (
long)pthread_self());
2357 for(count = 1; count < argc; count++)
2358 ast_agi_send(fd, chan,
"agi_arg_%d: %s\n", count, argv[count]);
2388 if (sscanf(argv[3],
"%30d", &to) != 1)
2458 if (!strncasecmp(argv[2],
"on",2)) {
2463 if (!strncasecmp(argv[2],
"mate",4)) {
2466 if (!strncasecmp(argv[2],
"tdd",3)) {
2497 int res = 0,
skipms = 3000;
2503 if (argc < 5 || argc > 10) {
2511 if ((argc > 5) && (sscanf(argv[5],
"%30d", &
skipms) != 1)) {
2527 if (argc > 9 && (sscanf(argv[9],
"%30ld", &offsetms) != 1)) {
2534 if (res > 0 &&
stop && strchr(
stop, res)) {
2536 snprintf(stopkeybuf,
sizeof(stopkeybuf),
"%c", res);
2549 snprintf(offsetbuf,
sizeof(offsetbuf),
"%ld", offsetms);
2552 ast_agi_send(agi->
fd, chan,
"200 result=%d endpos=%ld\n", res, offsetms);
2561 long sample_offset = 0, max_length;
2562 const char *edigits =
"";
2564 if (argc < 4 || argc > 5) {
2572 if ((argc > 4) && (sscanf(argv[4],
"%30ld", &sample_offset) != 1)) {
2577 ast_agi_send(agi->
fd, chan,
"200 result=-1 endpos=%ld\n", sample_offset);
2582 ast_debug(1,
"Ooh, found a video stream, too\n");
2584 ast_verb(3,
"<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2609 ast_agi_send(agi->
fd, chan,
"200 result=%d endpos=%ld\n", res, sample_offset);
2620 long sample_offset = 0, max_length;
2622 const char *edigits =
"";
2624 if ( argc < 4 || argc > 5 )
2631 timeout = atoi(argv[4]);
2638 ast_agi_send(agi->
fd, chan,
"200 result=-1 endpos=%ld\n", sample_offset);
2644 ast_debug(1,
"Ooh, found a video stream, too\n");
2646 ast_verb(3,
"Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2672 if ( !strchr(edigits,res) )
2676 ast_agi_send(agi->
fd, chan,
"200 result=%d endpos=%ld\n", res, sample_offset);
2689 if (argc < 4 || argc > 5)
2691 if (sscanf(argv[2],
"%30d", &num) != 1)
2706 if (sscanf(argv[2],
"%30d", &num) != 1)
2721 if (argc < 4 || argc > 5) {
2726 switch (argv[4][0]) {
2762 if (sscanf(argv[2],
"%30d", &num) != 1)
2777 if (sscanf(argv[2],
"%30d", &num) != 1)
2790 const char *format, *zone =
NULL;
2800 format =
"A dBY HMS";
2802 format =
"ABdY 'digits/at' IMp";
2836 int res,
max, timeout;
2842 timeout = atoi(argv[3]);
2846 max = atoi(argv[4]);
2887 if (sscanf(argv[2],
"%30d", &pri) != 1) {
2903 struct timeval start;
2904 long sample_offset = 0;
2913 char *silencestr =
NULL;
2921 if (sscanf(argv[5],
"%30d", &ms) != 1)
2925 silencestr = strchr(argv[6],
's');
2926 if ((argc > 7) && (!silencestr))
2927 silencestr = strchr(argv[7],
's');
2928 if ((argc > 8) && (!silencestr))
2929 silencestr = strchr(argv[8],
's');
2932 if (strlen(silencestr) > 2) {
2933 if ((silencestr[0] ==
's') && (silencestr[1] ==
'=')) {
2937 silence = atoi(silencestr);
2971 if ((argc > 6 && sscanf(argv[6],
"%30ld", &sample_offset) != 1 && !
ast_begins_with(argv[6],
"s="))
2979 ast_agi_send(agi->
fd, chan,
"200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
3008 ast_agi_send(agi->
fd, chan,
"200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3018 ast_agi_send(agi->
fd, chan,
"200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3054 totalsilence = dspsilence;
3058 if (totalsilence > silence) {
3082 ast_agi_send(agi->
fd, chan,
"200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3102 struct timeval whentohangup = { 0, 0 };
3106 if (sscanf(argv[2],
"%30lf", &timeout) != 1)
3111 whentohangup.tv_sec = timeout;
3112 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3131 }
else if (argc == 2) {
3151 int res, workaround;
3153 const char *agi_exec_full_str;
3160 ast_verb(3,
"AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] :
"");
3180 res =
pbx_exec(chan, app_to_exec, argc == 2 ?
"" : argv[2]);
3222 }
else if (argc == 3) {
3256 char tempstr[1024] =
"";
3262 if (!
ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] ==
')')) {
3280 if (argc != 4 && argc != 5) {
3318 sscanf(argv[2],
"%30d", &level);
3386 if ((argc < 3) || (argc > 4)) {
3395 ast_agi_send(agi->
fd, chan,
"200 result=%c\n", num_deleted > 0 ?
'0' :
'1');
3403 e->
command =
"agi set debug [on|off]";
3405 "Usage: agi set debug [on|off]\n"
3406 " Enables/disables dumping of AGI transactions for\n"
3407 " debugging purposes.\n";
3414 if (
a->argc != e->
args)
3417 if (strncasecmp(
a->argv[3],
"off", 3) == 0) {
3419 }
else if (strncasecmp(
a->argv[3],
"on", 2) == 0) {
3439 if (!strncasecmp(argv[2],
"on", 2))
3441 else if (!strncasecmp(argv[2],
"off", 3))
3597 char dtmf = 0,
tmp[4096] =
"", *
buf =
tmp;
3598 int timeout = 0, offset = 0, res = 0, i = 0;
3599 long current_offset = 0;
3600 const char *reason =
NULL;
3603 size_t left =
sizeof(
tmp);
3615 timeout = atoi(argv[3]);
3619 offset = atoi(argv[4]);
3654 if ((timeout > 0) && (start > 0)) {
3656 if ((
current - start) >= timeout) {
3677 switch (speech->
state) {
3722 if (!strcasecmp(reason,
"speech")) {
3731 ast_agi_send(agi->
fd, chan,
"200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i,
tmp);
3732 }
else if (!strcasecmp(reason,
"dtmf")) {
3733 ast_agi_send(agi->
fd, chan,
"200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3734 }
else if (!strcasecmp(reason,
"hangup") || !strcasecmp(reason,
"timeout")) {
3735 ast_agi_send(agi->
fd, chan,
"200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3737 ast_agi_send(agi->
fd, chan,
"200 result=0 endpos=%ld\n", current_offset);
3805 ast_cli(fd,
"%5.5s %30.30s %s\n",
"Dead",
"Command",
"Description");
3811 if ((e->
cmda[0])[0] ==
'_')
3814 if (
match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3827 ast_join(fullcmd,
sizeof(fullcmd), cmd->cmda);
3839#ifndef HAVE_NULLSAFE_PRINTF
3840 if (!cmd->summary) {
3849 if (!cmd->seealso) {
3859 ast_verb(5,
"AGI Command '%s' registered\n",fullcmd);
3870 int unregistered = 0;
3873 ast_join(fullcmd,
sizeof(fullcmd), cmd->cmda);
3898 ast_verb(5,
"AGI Command '%s' unregistered\n",fullcmd);
3900 return unregistered;
3905 unsigned int i, x = 0;
3907 for (i = 0; i <
len; i++) {
3916 for (; x > 0; x--) {
3938 for (i = 0; i <
len; i++) {
3960 for (y = 0;
match && cmds[y]; y++) {
3964 if (!e->
cmda[y] && !exact)
3971 if (strcasecmp(e->
cmda[y], cmds[y]))
3976 if ((exact > -1) && e->
cmda[y])
3989 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
4001 if (quoted && whitespace) {
4010 if (!quoted && !escaped) {
4054 "CommandId", command_id,
4056 "ResultCode", result_code,
4068 const char *ami_res;
4074 "CommandId", command_id,
4075 "Command", ami_cmd);
4081 ami_res =
"Invalid or unknown command";
4092 res =
c->handler(chan, agi, argc, argv);
4101 ast_agi_send(agi->
fd, chan,
"520 Invalid command syntax. Proper usage not available.\n");
4103 ast_agi_send(agi->
fd, chan,
"520-Invalid command syntax. Proper usage follows:\n");
4110 ami_res =
"Failure";
4118 ami_res =
"Success";
4125 ami_res =
"Success";
4132 ami_res =
"Unknown Result";
4140 ami_res =
"Command Not Permitted on a dead channel or intercept routine";
4167 const char *sighup_str;
4168 const char *exit_on_hangup_str;
4177 exit_on_hangup =
ast_true(exit_on_hangup_str);
4180 if (!(readf = fdopen(agi->
ctrl,
"r"))) {
4182 if (send_sighup && pid > -1)
4197 }
else if (agi->
fast) {
4201 if (exit_on_hangup) {
4206 if (dead || in_intercept) {
4224 if (!returnstatus) {
4236 }
else if (outfd > -1) {
4237 size_t len =
sizeof(
buf);
4245 res = fgets(
buf + buflen,
len, readf);
4248 if (ferror(readf) && ((
errno != EINTR) && (
errno != EAGAIN)))
4252 buflen = strlen(
buf);
4253 if (buflen &&
buf[buflen - 1] ==
'\n')
4255 len =
sizeof(
buf) - buflen;
4257 ast_verbose(
"AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n",
buf, strerror(
errno));
4271 if (*
buf && strncasecmp(
buf,
"failure", 7) == 0) {
4277 buflen = strlen(
buf);
4278 if (buflen &&
buf[buflen - 1] ==
'\n') {
4279 buf[buflen - 1] =
'\0';
4285 switch (cmd_status) {
4310 if (kill(pid, SIGHUP)) {
4315 waitpid(pid,
status, WNOHANG);
4316 }
else if (agi->
fast) {
4321 return returnstatus;
4332 e->
command =
"agi show commands [topic]";
4334 "Usage: agi show commands [topic] <topic>\n"
4335 " When called with a topic as an argument, displays usage\n"
4336 " information on the given command. If called without a\n"
4337 " topic, it provides a list of AGI commands.\n";
4341 if (
a->argc < e->
args - 1 || (
a->argc >= e->
args && strcasecmp(
a->argv[e->
args - 1],
"topic")))
4343 if (
a->argc > e->
args - 1) {
4355 size_t synlen, desclen, seealsolen, stxlen;
4365 snprintf(
info,
sizeof(
info),
"\n -= Info about agi '%s' =- ", fullcmd);
4374 goto return_cleanup;
4390 goto return_cleanup;
4401 goto return_cleanup;
4405 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,
4406 desctitle, description, syntitle,
synopsis, deadtitle, deadcontent,
4418 ast_cli(
a->fd,
"No such command '%s'.\n", fullcmd);
4437 fprintf(htmlfile,
"%s",
"<");
4440 fprintf(htmlfile,
"%s",
">");
4443 fprintf(htmlfile,
"%s",
"&");
4446 fprintf(htmlfile,
"%s",
""");
4449 fprintf(htmlfile,
"%c", *cur);
4464 if (!(htmlfile = fopen(filename,
"wt")))
4467 fprintf(htmlfile,
"<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4468 fprintf(htmlfile,
"<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4469 fprintf(htmlfile,
"<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4473 char *tempstr, *stringp;
4475 if (!command->
cmda[0])
4478 if ((command->
cmda[0])[0] ==
'_')
4482 fprintf(htmlfile,
"<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4483 fprintf(htmlfile,
"<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->
summary);
4489 tempstr =
strsep(&stringp,
"\n");
4491 fprintf(htmlfile,
"<TR><TD ALIGN=\"CENTER\">");
4493 fprintf(htmlfile,
"</TD></TR>\n");
4494 fprintf(htmlfile,
"<TR><TD ALIGN=\"CENTER\">\n");
4496 while ((tempstr =
strsep(&stringp,
"\n")) !=
NULL) {
4498 fprintf(htmlfile,
"<BR>\n");
4500 fprintf(htmlfile,
"</TD></TR>\n");
4501 fprintf(htmlfile,
"</TABLE></TD></TR>\n\n");
4505 fprintf(htmlfile,
"</TABLE>\n</BODY>\n</HTML>\n");
4516 "Usage: agi dump html <filename>\n"
4517 " Dumps the AGI command list in HTML format to the given\n"
4523 if (
a->argc != e->
args + 1)
4527 ast_cli(
a->fd,
"Could not create file '%s'\n",
a->argv[e->
args]);
4530 ast_cli(
a->fd,
"AGI HTML commands dumped to: %s\n",
a->argv[e->
args]);
4538 int fds[2], efd = -1, pid = -1;
4539 int safe_fork_called = 0;
4550 ast_debug(3,
"Hungup channel detected, running agi in dead mode.\n");
4551 memset(&agi, 0,
sizeof(agi));
4575 if (fds[1] != fds[0])
4580 if (safe_fork_called) {
4617 const char *requested_format_name;
4620 ast_log(
LOG_ERROR,
"EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4625 if (requested_format_name) {
4627 if (requested_format) {
4628 ast_verb(3,
"<%s> Setting EAGI audio pipe format to %s\n",
4631 ast_log(
LOG_ERROR,
"Could not find requested format: %s\n", requested_format_name);
4667#ifdef TEST_FRAMEWORK
4676 info->name =
"null_agi_docs";
4677 info->category =
"/res/agi/";
4678 info->summary =
"AGI command with no documentation";
4679 info->description =
"Test whether an AGI command with no documentation will crash Asterisk";
4690#ifndef HAVE_NULLSAFE_PRINTF
4757 .
requires =
"res_speech",
AGI Extension interfaces - Asterisk Gateway Interface.
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
static struct ast_str * prompt
Asterisk main include file. File version handling, generic pbx functions.
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...
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
enum ast_cc_service_type service
static void suspend(struct cc_core_instance *core_instance)
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
static int request(void *obj)
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
char * ast_recvtext(struct ast_channel *chan, int timeout)
Receives a text string from a channel Read a string of text from a channel.
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
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.
const char * ast_channel_data(const struct ast_channel *chan)
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
#define ast_channel_lock(chan)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.