Let's also include aclocal.m4
[asterisk-bristuff.git] / res / res_agi.c
bloba60155087c4c65f9b94dfeb9c4c94475dfff163f
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief AGI - the Asterisk Gateway Interface
23 * \author Mark Spencer <markster@digium.com>
26 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <sys/types.h>
31 #include <netdb.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
36 #include <math.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <signal.h>
42 #include <sys/time.h>
43 #include <stdio.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <sys/wait.h>
48 #include "asterisk/file.h"
49 #include "asterisk/logger.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/pbx.h"
52 #include "asterisk/module.h"
53 #include "asterisk/astdb.h"
54 #include "asterisk/callerid.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/logger.h"
57 #include "asterisk/options.h"
58 #include "asterisk/image.h"
59 #include "asterisk/say.h"
60 #include "asterisk/app.h"
61 #include "asterisk/dsp.h"
62 #include "asterisk/musiconhold.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/lock.h"
65 #include "asterisk/strings.h"
66 #include "asterisk/agi.h"
67 #include "asterisk/features.h"
69 #define MAX_ARGS 128
70 #define MAX_COMMANDS 128
71 #define AGI_NANDFS_RETRY 3
72 #define AGI_BUF_LEN 2048
74 /* Recycle some stuff from the CLI interface */
75 #define fdprintf agi_debug_cli
77 static char *app = "AGI";
79 static char *eapp = "EAGI";
81 static char *deadapp = "DeadAGI";
83 static char *synopsis = "Executes an AGI compliant application";
84 static char *esynopsis = "Executes an EAGI compliant application";
85 static char *deadsynopsis = "Executes AGI on a hungup channel";
87 static char *descrip =
88 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
89 "program on a channel. AGI allows Asterisk to launch external programs\n"
90 "written in any language to control a telephony channel, play audio,\n"
91 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
92 "and stdout.\n"
93 " This channel will stop dialplan execution on hangup inside of this\n"
94 "application, except when using DeadAGI. Otherwise, dialplan execution\n"
95 "will continue normally.\n"
96 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
97 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
98 "variable to \"no\" before executing the AGI application.\n"
99 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
100 "on file descriptor 3\n\n"
101 " Use the CLI command 'agi show' to list available agi commands\n"
102 " This application sets the following channel variable upon completion:\n"
103 " AGISTATUS The status of the attempt to the run the AGI script\n"
104 " text string, one of SUCCESS | FAILURE | HANGUP\n";
106 static int agidebug = 0;
108 #define TONE_BLOCK_SIZE 200
110 /* Max time to connect to an AGI remote host */
111 #define MAX_AGI_CONNECT 2000
113 #define AGI_PORT 4573
115 enum agi_result {
116 AGI_RESULT_FAILURE = -1,
117 AGI_RESULT_SUCCESS,
118 AGI_RESULT_SUCCESS_FAST,
119 AGI_RESULT_HANGUP
122 static int agi_debug_cli(int fd, char *fmt, ...)
124 char *stuff;
125 int res = 0;
127 va_list ap;
128 va_start(ap, fmt);
129 res = vasprintf(&stuff, fmt, ap);
130 va_end(ap);
131 if (res == -1) {
132 ast_log(LOG_ERROR, "Out of memory\n");
133 } else {
134 if (agidebug)
135 ast_verbose("AGI Tx >> %s", stuff); /* \n provided by caller */
136 res = ast_carefulwrite(fd, stuff, strlen(stuff), 100);
137 free(stuff);
140 return res;
143 /* launch_netscript: The fastagi handler.
144 FastAGI defaults to port 4573 */
145 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
147 int s;
148 int flags;
149 struct pollfd pfds[1];
150 char *host;
151 char *c; int port = AGI_PORT;
152 char *script="";
153 struct sockaddr_in sin;
154 struct hostent *hp;
155 struct ast_hostent ahp;
156 int res;
158 /* agiusl is "agi://host.domain[:port][/script/name]" */
159 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
160 /* Strip off any script name */
161 if ((c = strchr(host, '/'))) {
162 *c = '\0';
163 c++;
164 script = c;
166 if ((c = strchr(host, ':'))) {
167 *c = '\0';
168 c++;
169 port = atoi(c);
171 if (efd) {
172 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
173 return -1;
175 hp = ast_gethostbyname(host, &ahp);
176 if (!hp) {
177 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
178 return -1;
180 s = socket(AF_INET, SOCK_STREAM, 0);
181 if (s < 0) {
182 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
183 return -1;
185 flags = fcntl(s, F_GETFL);
186 if (flags < 0) {
187 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
188 close(s);
189 return -1;
191 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
192 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
193 close(s);
194 return -1;
196 memset(&sin, 0, sizeof(sin));
197 sin.sin_family = AF_INET;
198 sin.sin_port = htons(port);
199 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
200 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
201 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
202 close(s);
203 return AGI_RESULT_FAILURE;
206 pfds[0].fd = s;
207 pfds[0].events = POLLOUT;
208 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
209 if (errno != EINTR) {
210 if (!res) {
211 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
212 agiurl, MAX_AGI_CONNECT);
213 } else
214 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
215 close(s);
216 return AGI_RESULT_FAILURE;
220 if (fdprintf(s, "agi_network: yes\n") < 0) {
221 if (errno != EINTR) {
222 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
223 close(s);
224 return AGI_RESULT_FAILURE;
228 /* If we have a script parameter, relay it to the fastagi server */
229 if (!ast_strlen_zero(script))
230 fdprintf(s, "agi_network_script: %s\n", script);
232 if (option_debug > 3)
233 ast_log(LOG_DEBUG, "Wow, connected!\n");
234 fds[0] = s;
235 fds[1] = s;
236 *opid = -1;
237 return AGI_RESULT_SUCCESS_FAST;
240 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
242 char tmp[256];
243 int pid;
244 int toast[2];
245 int fromast[2];
246 int audio[2];
247 int x;
248 int res;
249 sigset_t signal_set, old_set;
251 if (!strncasecmp(script, "agi://", 6))
252 return launch_netscript(script, argv, fds, efd, opid);
254 if (script[0] != '/') {
255 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
256 script = tmp;
258 if (pipe(toast)) {
259 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
260 return AGI_RESULT_FAILURE;
262 if (pipe(fromast)) {
263 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
264 close(toast[0]);
265 close(toast[1]);
266 return AGI_RESULT_FAILURE;
268 if (efd) {
269 if (pipe(audio)) {
270 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
271 close(fromast[0]);
272 close(fromast[1]);
273 close(toast[0]);
274 close(toast[1]);
275 return AGI_RESULT_FAILURE;
277 res = fcntl(audio[1], F_GETFL);
278 if (res > -1)
279 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
280 if (res < 0) {
281 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
282 close(fromast[0]);
283 close(fromast[1]);
284 close(toast[0]);
285 close(toast[1]);
286 close(audio[0]);
287 close(audio[1]);
288 return AGI_RESULT_FAILURE;
292 /* Block SIGHUP during the fork - prevents a race */
293 sigfillset(&signal_set);
294 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
295 pid = fork();
296 if (pid < 0) {
297 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
298 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
299 return AGI_RESULT_FAILURE;
301 if (!pid) {
302 /* Pass paths to AGI via environmental variables */
303 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
304 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
305 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
306 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
307 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
308 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
309 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
310 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
311 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
312 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
313 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
315 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
316 ast_set_priority(0);
318 /* Redirect stdin and out, provide enhanced audio channel if desired */
319 dup2(fromast[0], STDIN_FILENO);
320 dup2(toast[1], STDOUT_FILENO);
321 if (efd) {
322 dup2(audio[0], STDERR_FILENO + 1);
323 } else {
324 close(STDERR_FILENO + 1);
327 /* Before we unblock our signals, return our trapped signals back to the defaults */
328 signal(SIGHUP, SIG_DFL);
329 signal(SIGCHLD, SIG_DFL);
330 signal(SIGINT, SIG_DFL);
331 signal(SIGURG, SIG_DFL);
332 signal(SIGTERM, SIG_DFL);
333 signal(SIGPIPE, SIG_DFL);
334 signal(SIGXFSZ, SIG_DFL);
336 /* unblock important signal handlers */
337 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
338 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
339 _exit(1);
342 /* Close everything but stdin/out/error */
343 for (x=STDERR_FILENO + 2;x<1024;x++)
344 close(x);
346 /* Execute script */
347 execv(script, argv);
348 /* Can't use ast_log since FD's are closed */
349 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
350 /* Special case to set status of AGI to failure */
351 fprintf(stdout, "failure\n");
352 fflush(stdout);
353 _exit(1);
355 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
356 if (option_verbose > 2)
357 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
358 fds[0] = toast[0];
359 fds[1] = fromast[1];
360 if (efd) {
361 *efd = audio[1];
363 /* close what we're not using in the parent */
364 close(toast[1]);
365 close(fromast[0]);
367 if (efd)
368 close(audio[0]);
370 *opid = pid;
371 return AGI_RESULT_SUCCESS;
374 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
376 /* Print initial environment, with agi_request always being the first
377 thing */
378 fdprintf(fd, "agi_request: %s\n", request);
379 fdprintf(fd, "agi_channel: %s\n", chan->name);
380 fdprintf(fd, "agi_language: %s\n", chan->language);
381 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
382 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
384 /* ANI/DNIS */
385 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
386 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
387 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
388 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
389 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
390 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
391 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
392 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
394 /* Context information */
395 fdprintf(fd, "agi_context: %s\n", chan->context);
396 fdprintf(fd, "agi_extension: %s\n", chan->exten);
397 fdprintf(fd, "agi_priority: %d\n", chan->priority);
398 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
400 /* User information */
401 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
403 /* End with empty return */
404 fdprintf(fd, "\n");
407 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
409 int res;
410 res = 0;
411 if (chan->_state != AST_STATE_UP) {
412 /* Answer the chan */
413 res = ast_answer(chan);
415 fdprintf(agi->fd, "200 result=%d\n", res);
416 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
419 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
421 int res;
422 int to;
423 if (argc != 4)
424 return RESULT_SHOWUSAGE;
425 if (sscanf(argv[3], "%d", &to) != 1)
426 return RESULT_SHOWUSAGE;
427 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
428 fdprintf(agi->fd, "200 result=%d\n", res);
429 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
432 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
434 int res;
435 if (argc != 3)
436 return RESULT_SHOWUSAGE;
437 /* At the moment, the parser (perhaps broken) returns with
438 the last argument PLUS the newline at the end of the input
439 buffer. This probably needs to be fixed, but I wont do that
440 because other stuff may break as a result. The right way
441 would probably be to strip off the trailing newline before
442 parsing, then here, add a newline at the end of the string
443 before sending it to ast_sendtext --DUDE */
444 res = ast_sendtext(chan, argv[2]);
445 fdprintf(agi->fd, "200 result=%d\n", res);
446 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
449 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
451 int res;
452 if (argc != 3)
453 return RESULT_SHOWUSAGE;
454 res = ast_recvchar(chan,atoi(argv[2]));
455 if (res == 0) {
456 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
457 return RESULT_SUCCESS;
459 if (res > 0) {
460 fdprintf(agi->fd, "200 result=%d\n", res);
461 return RESULT_SUCCESS;
463 else {
464 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
465 return RESULT_FAILURE;
469 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
471 char *buf;
473 if (argc != 3)
474 return RESULT_SHOWUSAGE;
475 buf = ast_recvtext(chan,atoi(argv[2]));
476 if (buf) {
477 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
478 free(buf);
479 } else {
480 fdprintf(agi->fd, "200 result=-1\n");
482 return RESULT_SUCCESS;
485 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
487 int res,x;
488 if (argc != 3)
489 return RESULT_SHOWUSAGE;
490 if (!strncasecmp(argv[2],"on",2))
491 x = 1;
492 else
493 x = 0;
494 if (!strncasecmp(argv[2],"mate",4))
495 x = 2;
496 if (!strncasecmp(argv[2],"tdd",3))
497 x = 1;
498 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
499 if (res != RESULT_SUCCESS)
500 fdprintf(agi->fd, "200 result=0\n");
501 else
502 fdprintf(agi->fd, "200 result=1\n");
503 return RESULT_SUCCESS;
506 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
508 int res;
509 if (argc != 3)
510 return RESULT_SHOWUSAGE;
511 res = ast_send_image(chan, argv[2]);
512 if (!ast_check_hangup(chan))
513 res = 0;
514 fdprintf(agi->fd, "200 result=%d\n", res);
515 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
518 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
520 int res = 0;
521 int skipms = 3000;
522 char *fwd = NULL;
523 char *rev = NULL;
524 char *pause = NULL;
525 char *stop = NULL;
527 if (argc < 5 || argc > 9)
528 return RESULT_SHOWUSAGE;
530 if (!ast_strlen_zero(argv[4]))
531 stop = argv[4];
532 else
533 stop = NULL;
535 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
536 return RESULT_SHOWUSAGE;
538 if (argc > 6 && !ast_strlen_zero(argv[6]))
539 fwd = argv[6];
540 else
541 fwd = "#";
543 if (argc > 7 && !ast_strlen_zero(argv[7]))
544 rev = argv[7];
545 else
546 rev = "*";
548 if (argc > 8 && !ast_strlen_zero(argv[8]))
549 pause = argv[8];
550 else
551 pause = NULL;
553 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
555 fdprintf(agi->fd, "200 result=%d\n", res);
557 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
560 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
562 int res;
563 int vres;
564 struct ast_filestream *fs;
565 struct ast_filestream *vfs;
566 long sample_offset = 0;
567 long max_length;
568 char *edigits = "";
570 if (argc < 4 || argc > 5)
571 return RESULT_SHOWUSAGE;
573 if (argv[3])
574 edigits = argv[3];
576 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
577 return RESULT_SHOWUSAGE;
579 fs = ast_openstream(chan, argv[2], chan->language);
581 if (!fs) {
582 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
583 return RESULT_SUCCESS;
585 vfs = ast_openvstream(chan, argv[2], chan->language);
586 if (vfs)
587 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
589 if (option_verbose > 2)
590 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
592 ast_seekstream(fs, 0, SEEK_END);
593 max_length = ast_tellstream(fs);
594 ast_seekstream(fs, sample_offset, SEEK_SET);
595 res = ast_applystream(chan, fs);
596 if (vfs)
597 vres = ast_applystream(chan, vfs);
598 ast_playstream(fs);
599 if (vfs)
600 ast_playstream(vfs);
602 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
603 /* this is to check for if ast_waitstream closed the stream, we probably are at
604 * the end of the stream, return that amount, else check for the amount */
605 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
606 ast_stopstream(chan);
607 if (res == 1) {
608 /* Stop this command, don't print a result line, as there is a new command */
609 return RESULT_SUCCESS;
611 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
612 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
615 /* get option - really similar to the handle_streamfile, but with a timeout */
616 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
618 int res;
619 int vres;
620 struct ast_filestream *fs;
621 struct ast_filestream *vfs;
622 long sample_offset = 0;
623 long max_length;
624 int timeout = 0;
625 char *edigits = "";
627 if ( argc < 4 || argc > 5 )
628 return RESULT_SHOWUSAGE;
630 if ( argv[3] )
631 edigits = argv[3];
633 if ( argc == 5 )
634 timeout = atoi(argv[4]);
635 else if (chan->pbx->dtimeout) {
636 /* by default dtimeout is set to 5sec */
637 timeout = chan->pbx->dtimeout * 1000; /* in msec */
640 fs = ast_openstream(chan, argv[2], chan->language);
641 if (!fs) {
642 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
643 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
644 return RESULT_SUCCESS;
646 vfs = ast_openvstream(chan, argv[2], chan->language);
647 if (vfs)
648 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
650 if (option_verbose > 2)
651 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
653 ast_seekstream(fs, 0, SEEK_END);
654 max_length = ast_tellstream(fs);
655 ast_seekstream(fs, sample_offset, SEEK_SET);
656 res = ast_applystream(chan, fs);
657 if (vfs)
658 vres = ast_applystream(chan, vfs);
659 ast_playstream(fs);
660 if (vfs)
661 ast_playstream(vfs);
663 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
664 /* this is to check for if ast_waitstream closed the stream, we probably are at
665 * the end of the stream, return that amount, else check for the amount */
666 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
667 ast_stopstream(chan);
668 if (res == 1) {
669 /* Stop this command, don't print a result line, as there is a new command */
670 return RESULT_SUCCESS;
673 /* If the user didnt press a key, wait for digitTimeout*/
674 if (res == 0 ) {
675 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
676 /* Make sure the new result is in the escape digits of the GET OPTION */
677 if ( !strchr(edigits,res) )
678 res=0;
681 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
682 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
688 /*--- handle_saynumber: Say number in various language syntaxes ---*/
689 /* Need to add option for gender here as well. Coders wanted */
690 /* While waiting, we're sending a (char *) NULL. */
691 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
693 int res;
694 int num;
695 if (argc != 4)
696 return RESULT_SHOWUSAGE;
697 if (sscanf(argv[2], "%d", &num) != 1)
698 return RESULT_SHOWUSAGE;
699 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
700 if (res == 1)
701 return RESULT_SUCCESS;
702 fdprintf(agi->fd, "200 result=%d\n", res);
703 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
706 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
708 int res;
709 int num;
711 if (argc != 4)
712 return RESULT_SHOWUSAGE;
713 if (sscanf(argv[2], "%d", &num) != 1)
714 return RESULT_SHOWUSAGE;
716 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
717 if (res == 1) /* New command */
718 return RESULT_SUCCESS;
719 fdprintf(agi->fd, "200 result=%d\n", res);
720 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
723 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
725 int res;
727 if (argc != 4)
728 return RESULT_SHOWUSAGE;
730 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
731 if (res == 1) /* New command */
732 return RESULT_SUCCESS;
733 fdprintf(agi->fd, "200 result=%d\n", res);
734 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
737 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
739 int res;
740 int num;
741 if (argc != 4)
742 return RESULT_SHOWUSAGE;
743 if (sscanf(argv[2], "%d", &num) != 1)
744 return RESULT_SHOWUSAGE;
745 res = ast_say_date(chan, num, argv[3], chan->language);
746 if (res == 1)
747 return RESULT_SUCCESS;
748 fdprintf(agi->fd, "200 result=%d\n", res);
749 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
752 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
754 int res;
755 int num;
756 if (argc != 4)
757 return RESULT_SHOWUSAGE;
758 if (sscanf(argv[2], "%d", &num) != 1)
759 return RESULT_SHOWUSAGE;
760 res = ast_say_time(chan, num, argv[3], chan->language);
761 if (res == 1)
762 return RESULT_SUCCESS;
763 fdprintf(agi->fd, "200 result=%d\n", res);
764 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
767 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
769 int res=0;
770 time_t unixtime;
771 char *format, *zone=NULL;
773 if (argc < 4)
774 return RESULT_SHOWUSAGE;
776 if (argc > 4) {
777 format = argv[4];
778 } else {
779 /* XXX this doesn't belong here, but in the 'say' module */
780 if (!strcasecmp(chan->language, "de")) {
781 format = "A dBY HMS";
782 } else {
783 format = "ABdY 'digits/at' IMp";
787 if (argc > 5 && !ast_strlen_zero(argv[5]))
788 zone = argv[5];
790 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
791 return RESULT_SHOWUSAGE;
793 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
794 if (res == 1)
795 return RESULT_SUCCESS;
797 fdprintf(agi->fd, "200 result=%d\n", res);
798 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
801 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
803 int res;
805 if (argc != 4)
806 return RESULT_SHOWUSAGE;
808 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
809 if (res == 1) /* New command */
810 return RESULT_SUCCESS;
811 fdprintf(agi->fd, "200 result=%d\n", res);
812 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
815 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
817 int res;
818 char data[1024];
819 int max;
820 int timeout;
822 if (argc < 3)
823 return RESULT_SHOWUSAGE;
824 if (argc >= 4)
825 timeout = atoi(argv[3]);
826 else
827 timeout = 0;
828 if (argc >= 5)
829 max = atoi(argv[4]);
830 else
831 max = 1024;
832 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
833 if (res == 2) /* New command */
834 return RESULT_SUCCESS;
835 else if (res == 1)
836 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
837 else if (res < 0 )
838 fdprintf(agi->fd, "200 result=-1\n");
839 else
840 fdprintf(agi->fd, "200 result=%s\n", data);
841 return RESULT_SUCCESS;
844 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
847 if (argc != 3)
848 return RESULT_SHOWUSAGE;
849 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
850 fdprintf(agi->fd, "200 result=0\n");
851 return RESULT_SUCCESS;
854 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
856 if (argc != 3)
857 return RESULT_SHOWUSAGE;
858 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
859 fdprintf(agi->fd, "200 result=0\n");
860 return RESULT_SUCCESS;
863 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
865 int pri;
866 if (argc != 3)
867 return RESULT_SHOWUSAGE;
869 if (sscanf(argv[2], "%d", &pri) != 1) {
870 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
871 return RESULT_SHOWUSAGE;
874 ast_explicit_goto(chan, NULL, NULL, pri);
875 fdprintf(agi->fd, "200 result=0\n");
876 return RESULT_SUCCESS;
879 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
881 struct ast_filestream *fs;
882 struct ast_frame *f;
883 struct timeval start;
884 long sample_offset = 0;
885 int res = 0;
886 int ms;
888 struct ast_dsp *sildet=NULL; /* silence detector dsp */
889 int totalsilence = 0;
890 int dspsilence = 0;
891 int silence = 0; /* amount of silence to allow */
892 int gotsilence = 0; /* did we timeout for silence? */
893 char *silencestr=NULL;
894 int rfmt=0;
897 /* XXX EAGI FIXME XXX */
899 if (argc < 6)
900 return RESULT_SHOWUSAGE;
901 if (sscanf(argv[5], "%d", &ms) != 1)
902 return RESULT_SHOWUSAGE;
904 if (argc > 6)
905 silencestr = strchr(argv[6],'s');
906 if ((argc > 7) && (!silencestr))
907 silencestr = strchr(argv[7],'s');
908 if ((argc > 8) && (!silencestr))
909 silencestr = strchr(argv[8],'s');
911 if (silencestr) {
912 if (strlen(silencestr) > 2) {
913 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
914 silencestr++;
915 silencestr++;
916 if (silencestr)
917 silence = atoi(silencestr);
918 if (silence > 0)
919 silence *= 1000;
924 if (silence > 0) {
925 rfmt = chan->readformat;
926 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
927 if (res < 0) {
928 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
929 return -1;
931 sildet = ast_dsp_new();
932 if (!sildet) {
933 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
934 return -1;
936 ast_dsp_set_threshold(sildet, 256);
939 /* backward compatibility, if no offset given, arg[6] would have been
940 * caught below and taken to be a beep, else if it is a digit then it is a
941 * offset */
942 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
943 res = ast_streamfile(chan, "beep", chan->language);
945 if ((argc > 7) && (!strchr(argv[7], '=')))
946 res = ast_streamfile(chan, "beep", chan->language);
948 if (!res)
949 res = ast_waitstream(chan, argv[4]);
950 if (res) {
951 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
952 } else {
953 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
954 if (!fs) {
955 res = -1;
956 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
957 if (sildet)
958 ast_dsp_free(sildet);
959 return RESULT_FAILURE;
962 /* Request a video update */
963 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
965 chan->stream = fs;
966 ast_applystream(chan,fs);
967 /* really should have checks */
968 ast_seekstream(fs, sample_offset, SEEK_SET);
969 ast_truncstream(fs);
971 start = ast_tvnow();
972 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
973 res = ast_waitfor(chan, -1);
974 if (res < 0) {
975 ast_closestream(fs);
976 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
977 if (sildet)
978 ast_dsp_free(sildet);
979 return RESULT_FAILURE;
981 f = ast_read(chan);
982 if (!f) {
983 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
984 ast_closestream(fs);
985 if (sildet)
986 ast_dsp_free(sildet);
987 return RESULT_FAILURE;
989 switch(f->frametype) {
990 case AST_FRAME_DTMF:
991 if (strchr(argv[4], f->subclass)) {
992 /* This is an interrupting chracter, so rewind to chop off any small
993 amount of DTMF that may have been recorded
995 ast_stream_rewind(fs, 200);
996 ast_truncstream(fs);
997 sample_offset = ast_tellstream(fs);
998 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
999 ast_closestream(fs);
1000 ast_frfree(f);
1001 if (sildet)
1002 ast_dsp_free(sildet);
1003 return RESULT_SUCCESS;
1005 break;
1006 case AST_FRAME_VOICE:
1007 ast_writestream(fs, f);
1008 /* this is a safe place to check progress since we know that fs
1009 * is valid after a write, and it will then have our current
1010 * location */
1011 sample_offset = ast_tellstream(fs);
1012 if (silence > 0) {
1013 dspsilence = 0;
1014 ast_dsp_silence(sildet, f, &dspsilence);
1015 if (dspsilence) {
1016 totalsilence = dspsilence;
1017 } else {
1018 totalsilence = 0;
1020 if (totalsilence > silence) {
1021 /* Ended happily with silence */
1022 gotsilence = 1;
1023 break;
1026 break;
1027 case AST_FRAME_VIDEO:
1028 ast_writestream(fs, f);
1029 default:
1030 /* Ignore all other frames */
1031 break;
1033 ast_frfree(f);
1034 if (gotsilence)
1035 break;
1038 if (gotsilence) {
1039 ast_stream_rewind(fs, silence-1000);
1040 ast_truncstream(fs);
1041 sample_offset = ast_tellstream(fs);
1043 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1044 ast_closestream(fs);
1047 if (silence > 0) {
1048 res = ast_set_read_format(chan, rfmt);
1049 if (res)
1050 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1051 ast_dsp_free(sildet);
1053 return RESULT_SUCCESS;
1056 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1058 int timeout;
1060 if (argc != 3)
1061 return RESULT_SHOWUSAGE;
1062 if (sscanf(argv[2], "%d", &timeout) != 1)
1063 return RESULT_SHOWUSAGE;
1064 if (timeout < 0)
1065 timeout = 0;
1066 if (timeout)
1067 chan->whentohangup = time(NULL) + timeout;
1068 else
1069 chan->whentohangup = 0;
1070 fdprintf(agi->fd, "200 result=0\n");
1071 return RESULT_SUCCESS;
1074 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1076 struct ast_channel *c;
1077 if (argc == 1) {
1078 /* no argument: hangup the current channel */
1079 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1080 fdprintf(agi->fd, "200 result=1\n");
1081 return RESULT_SUCCESS;
1082 } else if (argc == 2) {
1083 /* one argument: look for info on the specified channel */
1084 c = ast_get_channel_by_name_locked(argv[1]);
1085 if (c) {
1086 /* we have a matching channel */
1087 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1088 fdprintf(agi->fd, "200 result=1\n");
1089 ast_channel_unlock(c);
1090 return RESULT_SUCCESS;
1092 /* if we get this far no channel name matched the argument given */
1093 fdprintf(agi->fd, "200 result=-1\n");
1094 return RESULT_SUCCESS;
1095 } else {
1096 return RESULT_SHOWUSAGE;
1100 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1102 int res;
1103 struct ast_app *app;
1105 if (argc < 2)
1106 return RESULT_SHOWUSAGE;
1108 if (option_verbose > 2)
1109 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1111 app = pbx_findapp(argv[1]);
1113 if (app) {
1114 if(!strcasecmp(argv[1], PARK_APP_NAME)) {
1115 ast_masq_park_call(chan, NULL, 0, NULL);
1117 res = pbx_exec(chan, app, argv[2]);
1118 } else {
1119 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1120 res = -2;
1122 fdprintf(agi->fd, "200 result=%d\n", res);
1124 /* Even though this is wrong, users are depending upon this result. */
1125 return res;
1128 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1130 char tmp[256]="";
1131 char *l = NULL, *n = NULL;
1133 if (argv[2]) {
1134 ast_copy_string(tmp, argv[2], sizeof(tmp));
1135 ast_callerid_parse(tmp, &n, &l);
1136 if (l)
1137 ast_shrink_phone_number(l);
1138 else
1139 l = "";
1140 if (!n)
1141 n = "";
1142 ast_set_callerid(chan, l, n, NULL);
1145 fdprintf(agi->fd, "200 result=1\n");
1146 return RESULT_SUCCESS;
1149 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1151 struct ast_channel *c;
1152 if (argc == 2) {
1153 /* no argument: supply info on the current channel */
1154 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1155 return RESULT_SUCCESS;
1156 } else if (argc == 3) {
1157 /* one argument: look for info on the specified channel */
1158 c = ast_get_channel_by_name_locked(argv[2]);
1159 if (c) {
1160 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1161 ast_channel_unlock(c);
1162 return RESULT_SUCCESS;
1164 /* if we get this far no channel name matched the argument given */
1165 fdprintf(agi->fd, "200 result=-1\n");
1166 return RESULT_SUCCESS;
1167 } else {
1168 return RESULT_SHOWUSAGE;
1172 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1174 if (argv[3])
1175 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1177 fdprintf(agi->fd, "200 result=1\n");
1178 return RESULT_SUCCESS;
1181 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1183 char *ret;
1184 char tempstr[1024];
1186 if (argc != 3)
1187 return RESULT_SHOWUSAGE;
1189 /* check if we want to execute an ast_custom_function */
1190 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1191 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1192 } else {
1193 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1196 if (ret)
1197 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1198 else
1199 fdprintf(agi->fd, "200 result=0\n");
1201 return RESULT_SUCCESS;
1204 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1206 char tmp[4096] = "";
1207 struct ast_channel *chan2=NULL;
1209 if ((argc != 4) && (argc != 5))
1210 return RESULT_SHOWUSAGE;
1211 if (argc == 5) {
1212 chan2 = ast_get_channel_by_name_locked(argv[4]);
1213 } else {
1214 chan2 = chan;
1216 if (chan2) {
1217 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1218 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1219 } else {
1220 fdprintf(agi->fd, "200 result=0\n");
1222 if (chan2 && (chan2 != chan))
1223 ast_channel_unlock(chan2);
1224 return RESULT_SUCCESS;
1227 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1229 int level = 0;
1230 char *prefix;
1232 if (argc < 2)
1233 return RESULT_SHOWUSAGE;
1235 if (argv[2])
1236 sscanf(argv[2], "%d", &level);
1238 switch (level) {
1239 case 4:
1240 prefix = VERBOSE_PREFIX_4;
1241 break;
1242 case 3:
1243 prefix = VERBOSE_PREFIX_3;
1244 break;
1245 case 2:
1246 prefix = VERBOSE_PREFIX_2;
1247 break;
1248 case 1:
1249 default:
1250 prefix = VERBOSE_PREFIX_1;
1251 break;
1254 if (level <= option_verbose)
1255 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1257 fdprintf(agi->fd, "200 result=1\n");
1259 return RESULT_SUCCESS;
1262 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1264 int res;
1265 char tmp[256];
1267 if (argc != 4)
1268 return RESULT_SHOWUSAGE;
1269 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1270 if (res)
1271 fdprintf(agi->fd, "200 result=0\n");
1272 else
1273 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1275 return RESULT_SUCCESS;
1278 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1280 int res;
1282 if (argc != 5)
1283 return RESULT_SHOWUSAGE;
1284 res = ast_db_put(argv[2], argv[3], argv[4]);
1285 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1286 return RESULT_SUCCESS;
1289 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1291 int res;
1293 if (argc != 4)
1294 return RESULT_SHOWUSAGE;
1295 res = ast_db_del(argv[2], argv[3]);
1296 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1297 return RESULT_SUCCESS;
1300 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1302 int res;
1303 if ((argc < 3) || (argc > 4))
1304 return RESULT_SHOWUSAGE;
1305 if (argc == 4)
1306 res = ast_db_deltree(argv[2], argv[3]);
1307 else
1308 res = ast_db_deltree(argv[2], NULL);
1310 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1311 return RESULT_SUCCESS;
1314 static char debug_usage[] =
1315 "Usage: agi debug\n"
1316 " Enables dumping of AGI transactions for debugging purposes\n";
1318 static char no_debug_usage[] =
1319 "Usage: agi debug off\n"
1320 " Disables dumping of AGI transactions for debugging purposes\n";
1322 static int agi_do_debug(int fd, int argc, char *argv[])
1324 if (argc != 2)
1325 return RESULT_SHOWUSAGE;
1326 agidebug = 1;
1327 ast_cli(fd, "AGI Debugging Enabled\n");
1328 return RESULT_SUCCESS;
1331 static int agi_no_debug_deprecated(int fd, int argc, char *argv[])
1333 if (argc != 3)
1334 return RESULT_SHOWUSAGE;
1335 agidebug = 0;
1336 ast_cli(fd, "AGI Debugging Disabled\n");
1337 return RESULT_SUCCESS;
1340 static int agi_no_debug(int fd, int argc, char *argv[])
1342 if (argc != 3)
1343 return RESULT_SHOWUSAGE;
1344 agidebug = 0;
1345 ast_cli(fd, "AGI Debugging Disabled\n");
1346 return RESULT_SUCCESS;
1349 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1351 fdprintf(agi->fd, "200 result=0\n");
1352 return RESULT_SUCCESS;
1355 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1357 if (!strncasecmp(argv[2], "on", 2))
1358 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1359 else if (!strncasecmp(argv[2], "off", 3))
1360 ast_moh_stop(chan);
1361 fdprintf(agi->fd, "200 result=0\n");
1362 return RESULT_SUCCESS;
1365 static char usage_setmusic[] =
1366 " Usage: SET MUSIC ON <on|off> <class>\n"
1367 " Enables/Disables the music on hold generator. If <class> is\n"
1368 " not specified, then the default music on hold class will be used.\n"
1369 " Always returns 0.\n";
1371 static char usage_dbput[] =
1372 " Usage: DATABASE PUT <family> <key> <value>\n"
1373 " Adds or updates an entry in the Asterisk database for a\n"
1374 " given family, key, and value.\n"
1375 " Returns 1 if successful, 0 otherwise.\n";
1377 static char usage_dbget[] =
1378 " Usage: DATABASE GET <family> <key>\n"
1379 " Retrieves an entry in the Asterisk database for a\n"
1380 " given family and key.\n"
1381 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1382 " is set and returns the variable in parentheses.\n"
1383 " Example return code: 200 result=1 (testvariable)\n";
1385 static char usage_dbdel[] =
1386 " Usage: DATABASE DEL <family> <key>\n"
1387 " Deletes an entry in the Asterisk database for a\n"
1388 " given family and key.\n"
1389 " Returns 1 if successful, 0 otherwise.\n";
1391 static char usage_dbdeltree[] =
1392 " Usage: DATABASE DELTREE <family> [keytree]\n"
1393 " Deletes a family or specific keytree within a family\n"
1394 " in the Asterisk database.\n"
1395 " Returns 1 if successful, 0 otherwise.\n";
1397 static char usage_verbose[] =
1398 " Usage: VERBOSE <message> <level>\n"
1399 " Sends <message> to the console via verbose message system.\n"
1400 " <level> is the the verbose level (1-4)\n"
1401 " Always returns 1.\n";
1403 static char usage_getvariable[] =
1404 " Usage: GET VARIABLE <variablename>\n"
1405 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1406 " is set and returns the variable in parentheses.\n"
1407 " example return code: 200 result=1 (testvariable)\n";
1409 static char usage_getvariablefull[] =
1410 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1411 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1412 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1413 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1414 " example return code: 200 result=1 (testvariable)\n";
1416 static char usage_setvariable[] =
1417 " Usage: SET VARIABLE <variablename> <value>\n";
1419 static char usage_channelstatus[] =
1420 " Usage: CHANNEL STATUS [<channelname>]\n"
1421 " Returns the status of the specified channel.\n"
1422 " If no channel name is given the returns the status of the\n"
1423 " current channel. Return values:\n"
1424 " 0 Channel is down and available\n"
1425 " 1 Channel is down, but reserved\n"
1426 " 2 Channel is off hook\n"
1427 " 3 Digits (or equivalent) have been dialed\n"
1428 " 4 Line is ringing\n"
1429 " 5 Remote end is ringing\n"
1430 " 6 Line is up\n"
1431 " 7 Line is busy\n";
1433 static char usage_setcallerid[] =
1434 " Usage: SET CALLERID <number>\n"
1435 " Changes the callerid of the current channel.\n";
1437 static char usage_exec[] =
1438 " Usage: EXEC <application> <options>\n"
1439 " Executes <application> with given <options>.\n"
1440 " Returns whatever the application returns, or -2 on failure to find application\n";
1442 static char usage_hangup[] =
1443 " Usage: HANGUP [<channelname>]\n"
1444 " Hangs up the specified channel.\n"
1445 " If no channel name is given, hangs up the current channel\n";
1447 static char usage_answer[] =
1448 " Usage: ANSWER\n"
1449 " Answers channel if not already in answer state. Returns -1 on\n"
1450 " channel failure, or 0 if successful.\n";
1452 static char usage_waitfordigit[] =
1453 " Usage: WAIT FOR DIGIT <timeout>\n"
1454 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1455 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1456 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1457 " for the timeout value if you desire the call to block indefinitely.\n";
1459 static char usage_sendtext[] =
1460 " Usage: SEND TEXT \"<text to send>\"\n"
1461 " Sends the given text on a channel. Most channels do not support the\n"
1462 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1463 " support text transmission. Returns -1 only on error/hangup. Text\n"
1464 " consisting of greater than one word should be placed in quotes since the\n"
1465 " command only accepts a single argument.\n";
1467 static char usage_recvchar[] =
1468 " Usage: RECEIVE CHAR <timeout>\n"
1469 " Receives a character of text on a channel. Specify timeout to be the\n"
1470 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1471 " do not support the reception of text. Returns the decimal value of the character\n"
1472 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1473 " -1 only on error/hangup.\n";
1475 static char usage_recvtext[] =
1476 " Usage: RECEIVE TEXT <timeout>\n"
1477 " Receives a string of text on a channel. Specify timeout to be the\n"
1478 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1479 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1481 static char usage_tddmode[] =
1482 " Usage: TDD MODE <on|off>\n"
1483 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1484 " successful, or 0 if channel is not TDD-capable.\n";
1486 static char usage_sendimage[] =
1487 " Usage: SEND IMAGE <image>\n"
1488 " Sends the given image on a channel. Most channels do not support the\n"
1489 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1490 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1491 " should not include extensions.\n";
1493 static char usage_streamfile[] =
1494 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1495 " Send the given file, allowing playback to be interrupted by the given\n"
1496 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1497 " permitted. If sample offset is provided then the audio will seek to sample\n"
1498 " offset before play starts. Returns 0 if playback completes without a digit\n"
1499 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1500 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1501 " extension must not be included in the filename.\n";
1503 static char usage_controlstreamfile[] =
1504 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1505 " Send the given file, allowing playback to be controled by the given\n"
1506 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1507 " permitted. Returns 0 if playback completes without a digit\n"
1508 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1509 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1510 " extension must not be included in the filename.\n\n"
1511 " Note: ffchar and rewchar default to * and # respectively.\n";
1513 static char usage_getoption[] =
1514 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1515 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1517 static char usage_saynumber[] =
1518 " Usage: SAY NUMBER <number> <escape digits>\n"
1519 " Say a given number, returning early if any of the given DTMF digits\n"
1520 " are received on the channel. Returns 0 if playback completes without a digit\n"
1521 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1522 " -1 on error/hangup.\n";
1524 static char usage_saydigits[] =
1525 " Usage: SAY DIGITS <number> <escape digits>\n"
1526 " Say a given digit string, returning early if any of the given DTMF digits\n"
1527 " are received on the channel. Returns 0 if playback completes without a digit\n"
1528 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1529 " -1 on error/hangup.\n";
1531 static char usage_sayalpha[] =
1532 " Usage: SAY ALPHA <number> <escape digits>\n"
1533 " Say a given character string, returning early if any of the given DTMF digits\n"
1534 " are received on the channel. Returns 0 if playback completes without a digit\n"
1535 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1536 " -1 on error/hangup.\n";
1538 static char usage_saydate[] =
1539 " Usage: SAY DATE <date> <escape digits>\n"
1540 " Say a given date, returning early if any of the given DTMF digits are\n"
1541 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1542 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1543 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1544 " digit if one was pressed or -1 on error/hangup.\n";
1546 static char usage_saytime[] =
1547 " Usage: SAY TIME <time> <escape digits>\n"
1548 " Say a given time, returning early if any of the given DTMF digits are\n"
1549 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1550 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1551 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1552 " digit if one was pressed or -1 on error/hangup.\n";
1554 static char usage_saydatetime[] =
1555 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1556 " Say a given time, returning early if any of the given DTMF digits are\n"
1557 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1558 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1559 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1560 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1561 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1562 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1563 " digit if one was pressed or -1 on error/hangup.\n";
1565 static char usage_sayphonetic[] =
1566 " Usage: SAY PHONETIC <string> <escape digits>\n"
1567 " Say a given character string with phonetics, returning early if any of the\n"
1568 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1569 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1570 " if one was pressed, or -1 on error/hangup.\n";
1572 static char usage_getdata[] =
1573 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1574 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1575 "from the channel at the other end.\n";
1577 static char usage_setcontext[] =
1578 " Usage: SET CONTEXT <desired context>\n"
1579 " Sets the context for continuation upon exiting the application.\n";
1581 static char usage_setextension[] =
1582 " Usage: SET EXTENSION <new extension>\n"
1583 " Changes the extension for continuation upon exiting the application.\n";
1585 static char usage_setpriority[] =
1586 " Usage: SET PRIORITY <priority>\n"
1587 " Changes the priority for continuation upon exiting the application.\n"
1588 " The priority must be a valid priority or label.\n";
1590 static char usage_recordfile[] =
1591 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1592 " [offset samples] [BEEP] [s=silence]\n"
1593 " Record to a file until a given dtmf digit in the sequence is received\n"
1594 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1595 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1596 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1597 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1598 " of seconds of silence allowed before the function returns despite the\n"
1599 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1600 " preceeded by \"s=\" and is also optional.\n";
1602 static char usage_autohangup[] =
1603 " Usage: SET AUTOHANGUP <time>\n"
1604 " Cause the channel to automatically hangup at <time> seconds in the\n"
1605 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1606 " cause the autohangup feature to be disabled on this channel.\n";
1608 static char usage_noop[] =
1609 " Usage: NoOp\n"
1610 " Does nothing.\n";
1612 static agi_command commands[MAX_COMMANDS] = {
1613 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1614 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1615 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1616 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1617 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1618 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1619 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1620 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1621 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1622 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1623 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1624 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1625 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1626 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1627 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1628 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1629 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1630 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1631 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1632 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1633 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1634 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1635 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1636 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1637 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1638 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1639 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1640 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1641 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1642 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1643 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1644 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1645 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1646 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1647 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1648 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1649 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1652 static int help_workhorse(int fd, char *match[])
1654 char fullcmd[80];
1655 char matchstr[80];
1656 int x;
1657 struct agi_command *e;
1658 if (match)
1659 ast_join(matchstr, sizeof(matchstr), match);
1660 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1661 e = &commands[x];
1662 if (!e->cmda[0])
1663 break;
1664 /* Hide commands that start with '_' */
1665 if ((e->cmda[0])[0] == '_')
1666 continue;
1667 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1668 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1669 continue;
1670 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1672 return 0;
1675 int ast_agi_register(agi_command *agi)
1677 int x;
1678 for (x=0; x<MAX_COMMANDS - 1; x++) {
1679 if (commands[x].cmda[0] == agi->cmda[0]) {
1680 ast_log(LOG_WARNING, "Command already registered!\n");
1681 return -1;
1684 for (x=0; x<MAX_COMMANDS - 1; x++) {
1685 if (!commands[x].cmda[0]) {
1686 commands[x] = *agi;
1687 return 0;
1690 ast_log(LOG_WARNING, "No more room for new commands!\n");
1691 return -1;
1694 void ast_agi_unregister(agi_command *agi)
1696 int x;
1697 for (x=0; x<MAX_COMMANDS - 1; x++) {
1698 if (commands[x].cmda[0] == agi->cmda[0]) {
1699 memset(&commands[x], 0, sizeof(agi_command));
1704 static agi_command *find_command(char *cmds[], int exact)
1706 int x;
1707 int y;
1708 int match;
1710 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1711 if (!commands[x].cmda[0])
1712 break;
1713 /* start optimistic */
1714 match = 1;
1715 for (y=0; match && cmds[y]; y++) {
1716 /* If there are no more words in the command (and we're looking for
1717 an exact match) or there is a difference between the two words,
1718 then this is not a match */
1719 if (!commands[x].cmda[y] && !exact)
1720 break;
1721 /* don't segfault if the next part of a command doesn't exist */
1722 if (!commands[x].cmda[y])
1723 return NULL;
1724 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1725 match = 0;
1727 /* If more words are needed to complete the command then this is not
1728 a candidate (unless we're looking for a really inexact answer */
1729 if ((exact > -1) && commands[x].cmda[y])
1730 match = 0;
1731 if (match)
1732 return &commands[x];
1734 return NULL;
1738 static int parse_args(char *s, int *max, char *argv[])
1740 int x=0;
1741 int quoted=0;
1742 int escaped=0;
1743 int whitespace=1;
1744 char *cur;
1746 cur = s;
1747 while(*s) {
1748 switch(*s) {
1749 case '"':
1750 /* If it's escaped, put a literal quote */
1751 if (escaped)
1752 goto normal;
1753 else
1754 quoted = !quoted;
1755 if (quoted && whitespace) {
1756 /* If we're starting a quote, coming off white space start a new word, too */
1757 argv[x++] = cur;
1758 whitespace=0;
1760 escaped = 0;
1761 break;
1762 case ' ':
1763 case '\t':
1764 if (!quoted && !escaped) {
1765 /* If we're not quoted, mark this as whitespace, and
1766 end the previous argument */
1767 whitespace = 1;
1768 *(cur++) = '\0';
1769 } else
1770 /* Otherwise, just treat it as anything else */
1771 goto normal;
1772 break;
1773 case '\\':
1774 /* If we're escaped, print a literal, otherwise enable escaping */
1775 if (escaped) {
1776 goto normal;
1777 } else {
1778 escaped=1;
1780 break;
1781 default:
1782 normal:
1783 if (whitespace) {
1784 if (x >= MAX_ARGS -1) {
1785 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1786 break;
1788 /* Coming off of whitespace, start the next argument */
1789 argv[x++] = cur;
1790 whitespace=0;
1792 *(cur++) = *s;
1793 escaped=0;
1795 s++;
1797 /* Null terminate */
1798 *(cur++) = '\0';
1799 argv[x] = NULL;
1800 *max = x;
1801 return 0;
1804 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1806 char *argv[MAX_ARGS];
1807 int argc = MAX_ARGS;
1808 int res;
1809 agi_command *c;
1811 parse_args(buf, &argc, argv);
1812 c = find_command(argv, 0);
1813 if (c) {
1814 res = c->handler(chan, agi, argc, argv);
1815 switch(res) {
1816 case RESULT_SHOWUSAGE:
1817 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1818 fdprintf(agi->fd, c->usage);
1819 fdprintf(agi->fd, "520 End of proper usage.\n");
1820 break;
1821 case AST_PBX_KEEPALIVE:
1822 /* We've been asked to keep alive, so do so */
1823 return AST_PBX_KEEPALIVE;
1824 break;
1825 case RESULT_FAILURE:
1826 /* They've already given the failure. We've been hung up on so handle this
1827 appropriately */
1828 return -1;
1830 } else {
1831 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1833 return 0;
1835 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead)
1837 struct ast_channel *c;
1838 int outfd;
1839 int ms;
1840 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1841 struct ast_frame *f;
1842 char buf[AGI_BUF_LEN];
1843 char *res = NULL;
1844 FILE *readf;
1845 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1846 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1847 int retry = AGI_NANDFS_RETRY;
1849 if (!(readf = fdopen(agi->ctrl, "r"))) {
1850 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1851 if (pid > -1)
1852 kill(pid, SIGHUP);
1853 close(agi->ctrl);
1854 return AGI_RESULT_FAILURE;
1856 setlinebuf(readf);
1857 setup_env(chan, request, agi->fd, (agi->audio > -1));
1858 for (;;) {
1859 ms = -1;
1860 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1861 if (c) {
1862 retry = AGI_NANDFS_RETRY;
1863 /* Idle the channel until we get a command */
1864 f = ast_read(c);
1865 if (!f) {
1866 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1867 returnstatus = AGI_RESULT_HANGUP;
1868 break;
1869 } else {
1870 /* If it's voice, write it to the audio pipe */
1871 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1872 /* Write, ignoring errors */
1873 write(agi->audio, f->data, f->datalen);
1875 ast_frfree(f);
1877 } else if (outfd > -1) {
1878 size_t len = sizeof(buf);
1879 size_t buflen = 0;
1881 retry = AGI_NANDFS_RETRY;
1882 buf[0] = '\0';
1884 while (buflen < (len - 1)) {
1885 res = fgets(buf + buflen, len, readf);
1886 if (feof(readf))
1887 break;
1888 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
1889 break;
1890 if (res != NULL && !agi->fast)
1891 break;
1892 buflen = strlen(buf);
1893 if (buflen && buf[buflen - 1] == '\n')
1894 break;
1895 len -= buflen;
1896 if (agidebug)
1897 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
1900 if (!buf[0]) {
1901 /* Program terminated */
1902 if (returnstatus)
1903 returnstatus = -1;
1904 if (option_verbose > 2)
1905 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1906 if (pid > 0)
1907 waitpid(pid, status, 0);
1908 /* No need to kill the pid anymore, since they closed us */
1909 pid = -1;
1910 break;
1913 /* Special case for inability to execute child process */
1914 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
1915 returnstatus = AGI_RESULT_FAILURE;
1916 break;
1919 /* get rid of trailing newline, if any */
1920 if (*buf && buf[strlen(buf) - 1] == '\n')
1921 buf[strlen(buf) - 1] = 0;
1922 if (agidebug)
1923 ast_verbose("AGI Rx << %s\n", buf);
1924 returnstatus |= agi_handle_command(chan, agi, buf);
1925 /* If the handle_command returns -1, we need to stop */
1926 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1927 break;
1929 } else {
1930 if (--retry <= 0) {
1931 ast_log(LOG_WARNING, "No channel, no fd?\n");
1932 returnstatus = AGI_RESULT_FAILURE;
1933 break;
1937 /* Notify process */
1938 if (pid > -1) {
1939 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1940 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1941 if (kill(pid, SIGHUP)) {
1942 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1943 } else { /* Give the process a chance to die */
1944 usleep(1);
1947 waitpid(pid, status, WNOHANG);
1949 fclose(readf);
1950 return returnstatus;
1953 static int handle_showagi(int fd, int argc, char *argv[])
1955 struct agi_command *e;
1956 char fullcmd[80];
1957 if ((argc < 2))
1958 return RESULT_SHOWUSAGE;
1959 if (argc > 2) {
1960 e = find_command(argv + 2, 1);
1961 if (e)
1962 ast_cli(fd, e->usage);
1963 else {
1964 if (find_command(argv + 2, -1)) {
1965 return help_workhorse(fd, argv + 1);
1966 } else {
1967 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1968 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1971 } else {
1972 return help_workhorse(fd, NULL);
1974 return RESULT_SUCCESS;
1977 static int handle_agidumphtml(int fd, int argc, char *argv[])
1979 struct agi_command *e;
1980 char fullcmd[80];
1981 int x;
1982 FILE *htmlfile;
1984 if ((argc < 3))
1985 return RESULT_SHOWUSAGE;
1987 if (!(htmlfile = fopen(argv[2], "wt"))) {
1988 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1989 return RESULT_SHOWUSAGE;
1992 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1993 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1996 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1998 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1999 char *stringp, *tempstr;
2001 e = &commands[x];
2002 if (!e->cmda[0]) /* end ? */
2003 break;
2004 /* Hide commands that start with '_' */
2005 if ((e->cmda[0])[0] == '_')
2006 continue;
2007 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2009 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2010 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary);
2012 stringp=e->usage;
2013 tempstr = strsep(&stringp, "\n");
2015 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
2017 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2018 while ((tempstr = strsep(&stringp, "\n")) != NULL)
2019 fprintf(htmlfile, "%s<BR>\n",tempstr);
2020 fprintf(htmlfile, "</TD></TR>\n");
2021 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2025 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2026 fclose(htmlfile);
2027 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
2028 return RESULT_SUCCESS;
2031 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2033 enum agi_result res;
2034 struct ast_module_user *u;
2035 char *argv[MAX_ARGS];
2036 char buf[AGI_BUF_LEN] = "";
2037 char *tmp = (char *)buf;
2038 int argc = 0;
2039 int fds[2];
2040 int efd = -1;
2041 int pid;
2042 char *stringp;
2043 AGI agi;
2045 if (ast_strlen_zero(data)) {
2046 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2047 return -1;
2049 ast_copy_string(buf, data, sizeof(buf));
2051 memset(&agi, 0, sizeof(agi));
2052 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
2053 argv[argc++] = stringp;
2054 argv[argc] = NULL;
2056 u = ast_module_user_add(chan);
2057 #if 0
2058 /* Answer if need be */
2059 if (chan->_state != AST_STATE_UP) {
2060 if (ast_answer(chan)) {
2061 LOCAL_USER_REMOVE(u);
2062 return -1;
2065 #endif
2066 ast_replace_sigchld();
2067 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2068 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2069 int status = 0;
2070 agi.fd = fds[1];
2071 agi.ctrl = fds[0];
2072 agi.audio = efd;
2073 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2074 res = run_agi(chan, argv[0], &agi, pid, &status, dead);
2075 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2076 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2077 res = AGI_RESULT_FAILURE;
2078 if (fds[1] != fds[0])
2079 close(fds[1]);
2080 if (efd > -1)
2081 close(efd);
2083 ast_unreplace_sigchld();
2084 ast_module_user_remove(u);
2086 switch (res) {
2087 case AGI_RESULT_SUCCESS:
2088 case AGI_RESULT_SUCCESS_FAST:
2089 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2090 break;
2091 case AGI_RESULT_FAILURE:
2092 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2093 break;
2094 case AGI_RESULT_HANGUP:
2095 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2096 return -1;
2099 return 0;
2102 static int agi_exec(struct ast_channel *chan, void *data)
2104 if (chan->_softhangup)
2105 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2106 return agi_exec_full(chan, data, 0, 0);
2109 static int eagi_exec(struct ast_channel *chan, void *data)
2111 int readformat;
2112 int res;
2114 if (chan->_softhangup)
2115 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2116 readformat = chan->readformat;
2117 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2118 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2119 return -1;
2121 res = agi_exec_full(chan, data, 1, 0);
2122 if (!res) {
2123 if (ast_set_read_format(chan, readformat)) {
2124 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2127 return res;
2130 static int deadagi_exec(struct ast_channel *chan, void *data)
2132 if (!ast_check_hangup(chan))
2133 ast_log(LOG_WARNING,"Running DeadAGI on a live channel will cause problems, please use AGI\n");
2134 return agi_exec_full(chan, data, 0, 1);
2137 static char showagi_help[] =
2138 "Usage: agi show [topic]\n"
2139 " When called with a topic as an argument, displays usage\n"
2140 " information on the given command. If called without a\n"
2141 " topic, it provides a list of AGI commands.\n";
2144 static char dumpagihtml_help[] =
2145 "Usage: agi dumphtml <filename>\n"
2146 " Dumps the agi command list in html format to given filename\n";
2148 static struct ast_cli_entry cli_show_agi_deprecated = {
2149 { "show", "agi", NULL },
2150 handle_showagi, NULL,
2151 NULL };
2153 static struct ast_cli_entry cli_dump_agihtml_deprecated = {
2154 { "dump", "agihtml", NULL },
2155 handle_agidumphtml, NULL,
2156 NULL };
2158 static struct ast_cli_entry cli_agi_no_debug_deprecated = {
2159 { "agi", "no", "debug", NULL },
2160 agi_no_debug_deprecated, NULL,
2161 NULL };
2163 static struct ast_cli_entry cli_agi[] = {
2164 { { "agi", "debug", NULL },
2165 agi_do_debug, "Enable AGI debugging",
2166 debug_usage },
2168 { { "agi", "debug", "off", NULL },
2169 agi_no_debug, "Disable AGI debugging",
2170 no_debug_usage, NULL, &cli_agi_no_debug_deprecated },
2172 { { "agi", "show", NULL },
2173 handle_showagi, "List AGI commands or specific help",
2174 showagi_help, NULL, &cli_show_agi_deprecated },
2176 { { "agi", "dumphtml", NULL },
2177 handle_agidumphtml, "Dumps a list of agi commands in html format",
2178 dumpagihtml_help, NULL, &cli_dump_agihtml_deprecated },
2181 static int unload_module(void)
2183 ast_module_user_hangup_all();
2184 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2185 ast_unregister_application(eapp);
2186 ast_unregister_application(deadapp);
2187 return ast_unregister_application(app);
2190 static int load_module(void)
2192 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2193 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2194 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2195 return ast_register_application(app, agi_exec, synopsis, descrip);
2198 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2199 .load = load_module,
2200 .unload = unload_module,