add note that the user will need to enable codec_ilbc to get it to build
[asterisk-bristuff.git] / res / res_agi.c
blobb0de6db3671c64ff1e8684bb8c0a96cafe58dbe1
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"
68 #define MAX_ARGS 128
69 #define MAX_COMMANDS 128
70 #define AGI_NANDFS_RETRY 3
71 #define AGI_BUF_LEN 2048
73 /* Recycle some stuff from the CLI interface */
74 #define fdprintf agi_debug_cli
76 static char *app = "AGI";
78 static char *eapp = "EAGI";
80 static char *deadapp = "DeadAGI";
82 static char *synopsis = "Executes an AGI compliant application";
83 static char *esynopsis = "Executes an EAGI compliant application";
84 static char *deadsynopsis = "Executes AGI on a hungup channel";
86 static char *descrip =
87 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
88 "program on a channel. AGI allows Asterisk to launch external programs\n"
89 "written in any language to control a telephony channel, play audio,\n"
90 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
91 "and stdout.\n"
92 " This channel will stop dialplan execution on hangup inside of this\n"
93 "application, except when using DeadAGI. Otherwise, dialplan execution\n"
94 "will continue normally.\n"
95 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
96 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
97 "variable to \"no\" before executing the AGI application.\n"
98 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
99 "on file descriptor 3\n\n"
100 " Use the CLI command 'agi show' to list available agi commands\n"
101 " This application sets the following channel variable upon completion:\n"
102 " AGISTATUS The status of the attempt to the run the AGI script\n"
103 " text string, one of SUCCESS | FAILURE | HANGUP\n";
105 static int agidebug = 0;
107 #define TONE_BLOCK_SIZE 200
109 /* Max time to connect to an AGI remote host */
110 #define MAX_AGI_CONNECT 2000
112 #define AGI_PORT 4573
114 enum agi_result {
115 AGI_RESULT_SUCCESS,
116 AGI_RESULT_SUCCESS_FAST,
117 AGI_RESULT_FAILURE,
118 AGI_RESULT_HANGUP
121 static int agi_debug_cli(int fd, char *fmt, ...)
123 char *stuff;
124 int res = 0;
126 va_list ap;
127 va_start(ap, fmt);
128 res = vasprintf(&stuff, fmt, ap);
129 va_end(ap);
130 if (res == -1) {
131 ast_log(LOG_ERROR, "Out of memory\n");
132 } else {
133 if (agidebug)
134 ast_verbose("AGI Tx >> %s", stuff); /* \n provided by caller */
135 res = ast_carefulwrite(fd, stuff, strlen(stuff), 100);
136 free(stuff);
139 return res;
142 /* launch_netscript: The fastagi handler.
143 FastAGI defaults to port 4573 */
144 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
146 int s;
147 int flags;
148 struct pollfd pfds[1];
149 char *host;
150 char *c; int port = AGI_PORT;
151 char *script="";
152 struct sockaddr_in sin;
153 struct hostent *hp;
154 struct ast_hostent ahp;
155 int res;
157 /* agiusl is "agi://host.domain[:port][/script/name]" */
158 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
159 /* Strip off any script name */
160 if ((c = strchr(host, '/'))) {
161 *c = '\0';
162 c++;
163 script = c;
165 if ((c = strchr(host, ':'))) {
166 *c = '\0';
167 c++;
168 port = atoi(c);
170 if (efd) {
171 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
172 return -1;
174 hp = ast_gethostbyname(host, &ahp);
175 if (!hp) {
176 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
177 return -1;
179 s = socket(AF_INET, SOCK_STREAM, 0);
180 if (s < 0) {
181 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
182 return -1;
184 flags = fcntl(s, F_GETFL);
185 if (flags < 0) {
186 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
187 close(s);
188 return -1;
190 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
191 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
192 close(s);
193 return -1;
195 memset(&sin, 0, sizeof(sin));
196 sin.sin_family = AF_INET;
197 sin.sin_port = htons(port);
198 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
199 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
200 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
201 close(s);
202 return AGI_RESULT_FAILURE;
205 pfds[0].fd = s;
206 pfds[0].events = POLLOUT;
207 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
208 if (errno != EINTR) {
209 if (!res) {
210 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
211 agiurl, MAX_AGI_CONNECT);
212 } else
213 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
214 close(s);
215 return AGI_RESULT_FAILURE;
219 if (fdprintf(s, "agi_network: yes\n") < 0) {
220 if (errno != EINTR) {
221 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
222 close(s);
223 return AGI_RESULT_FAILURE;
227 /* If we have a script parameter, relay it to the fastagi server */
228 if (!ast_strlen_zero(script))
229 fdprintf(s, "agi_network_script: %s\n", script);
231 if (option_debug > 3)
232 ast_log(LOG_DEBUG, "Wow, connected!\n");
233 fds[0] = s;
234 fds[1] = s;
235 *opid = -1;
236 return AGI_RESULT_SUCCESS_FAST;
239 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
241 char tmp[256];
242 int pid;
243 int toast[2];
244 int fromast[2];
245 int audio[2];
246 int x;
247 int res;
248 sigset_t signal_set, old_set;
250 if (!strncasecmp(script, "agi://", 6))
251 return launch_netscript(script, argv, fds, efd, opid);
253 if (script[0] != '/') {
254 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
255 script = tmp;
257 if (pipe(toast)) {
258 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
259 return AGI_RESULT_FAILURE;
261 if (pipe(fromast)) {
262 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
263 close(toast[0]);
264 close(toast[1]);
265 return AGI_RESULT_FAILURE;
267 if (efd) {
268 if (pipe(audio)) {
269 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
270 close(fromast[0]);
271 close(fromast[1]);
272 close(toast[0]);
273 close(toast[1]);
274 return AGI_RESULT_FAILURE;
276 res = fcntl(audio[1], F_GETFL);
277 if (res > -1)
278 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
279 if (res < 0) {
280 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
281 close(fromast[0]);
282 close(fromast[1]);
283 close(toast[0]);
284 close(toast[1]);
285 close(audio[0]);
286 close(audio[1]);
287 return AGI_RESULT_FAILURE;
291 /* Block SIGHUP during the fork - prevents a race */
292 sigfillset(&signal_set);
293 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
294 pid = fork();
295 if (pid < 0) {
296 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
297 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
298 return AGI_RESULT_FAILURE;
300 if (!pid) {
301 /* Pass paths to AGI via environmental variables */
302 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
303 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
304 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
305 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
306 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
307 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
308 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
309 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
310 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
311 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
312 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
314 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
315 ast_set_priority(0);
317 /* Redirect stdin and out, provide enhanced audio channel if desired */
318 dup2(fromast[0], STDIN_FILENO);
319 dup2(toast[1], STDOUT_FILENO);
320 if (efd) {
321 dup2(audio[0], STDERR_FILENO + 1);
322 } else {
323 close(STDERR_FILENO + 1);
326 /* Before we unblock our signals, return our trapped signals back to the defaults */
327 signal(SIGHUP, SIG_DFL);
328 signal(SIGCHLD, SIG_DFL);
329 signal(SIGINT, SIG_DFL);
330 signal(SIGURG, SIG_DFL);
331 signal(SIGTERM, SIG_DFL);
332 signal(SIGPIPE, SIG_DFL);
333 signal(SIGXFSZ, SIG_DFL);
335 /* unblock important signal handlers */
336 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
337 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
338 _exit(1);
341 /* Close everything but stdin/out/error */
342 for (x=STDERR_FILENO + 2;x<1024;x++)
343 close(x);
345 /* Execute script */
346 execv(script, argv);
347 /* Can't use ast_log since FD's are closed */
348 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
349 fflush(stdout);
350 _exit(1);
352 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
353 if (option_verbose > 2)
354 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
355 fds[0] = toast[0];
356 fds[1] = fromast[1];
357 if (efd) {
358 *efd = audio[1];
360 /* close what we're not using in the parent */
361 close(toast[1]);
362 close(fromast[0]);
364 if (efd)
365 close(audio[0]);
367 *opid = pid;
368 return AGI_RESULT_SUCCESS;
371 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
373 /* Print initial environment, with agi_request always being the first
374 thing */
375 fdprintf(fd, "agi_request: %s\n", request);
376 fdprintf(fd, "agi_channel: %s\n", chan->name);
377 fdprintf(fd, "agi_language: %s\n", chan->language);
378 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
379 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
381 /* ANI/DNIS */
382 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
383 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
384 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
385 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
386 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
387 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
388 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
389 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
391 /* Context information */
392 fdprintf(fd, "agi_context: %s\n", chan->context);
393 fdprintf(fd, "agi_extension: %s\n", chan->exten);
394 fdprintf(fd, "agi_priority: %d\n", chan->priority);
395 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
397 /* User information */
398 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
400 /* End with empty return */
401 fdprintf(fd, "\n");
404 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
406 int res;
407 res = 0;
408 if (chan->_state != AST_STATE_UP) {
409 /* Answer the chan */
410 res = ast_answer(chan);
412 fdprintf(agi->fd, "200 result=%d\n", res);
413 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
416 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
418 int res;
419 int to;
420 if (argc != 4)
421 return RESULT_SHOWUSAGE;
422 if (sscanf(argv[3], "%d", &to) != 1)
423 return RESULT_SHOWUSAGE;
424 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
425 fdprintf(agi->fd, "200 result=%d\n", res);
426 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
429 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
431 int res;
432 if (argc != 3)
433 return RESULT_SHOWUSAGE;
434 /* At the moment, the parser (perhaps broken) returns with
435 the last argument PLUS the newline at the end of the input
436 buffer. This probably needs to be fixed, but I wont do that
437 because other stuff may break as a result. The right way
438 would probably be to strip off the trailing newline before
439 parsing, then here, add a newline at the end of the string
440 before sending it to ast_sendtext --DUDE */
441 res = ast_sendtext(chan, argv[2]);
442 fdprintf(agi->fd, "200 result=%d\n", res);
443 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
446 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
448 int res;
449 if (argc != 3)
450 return RESULT_SHOWUSAGE;
451 res = ast_recvchar(chan,atoi(argv[2]));
452 if (res == 0) {
453 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
454 return RESULT_SUCCESS;
456 if (res > 0) {
457 fdprintf(agi->fd, "200 result=%d\n", res);
458 return RESULT_SUCCESS;
460 else {
461 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
462 return RESULT_FAILURE;
466 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
468 char *buf;
470 if (argc != 3)
471 return RESULT_SHOWUSAGE;
472 buf = ast_recvtext(chan,atoi(argv[2]));
473 if (buf) {
474 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
475 free(buf);
476 } else {
477 fdprintf(agi->fd, "200 result=-1\n");
479 return RESULT_SUCCESS;
482 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
484 int res,x;
485 if (argc != 3)
486 return RESULT_SHOWUSAGE;
487 if (!strncasecmp(argv[2],"on",2))
488 x = 1;
489 else
490 x = 0;
491 if (!strncasecmp(argv[2],"mate",4))
492 x = 2;
493 if (!strncasecmp(argv[2],"tdd",3))
494 x = 1;
495 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
496 if (res != RESULT_SUCCESS)
497 fdprintf(agi->fd, "200 result=0\n");
498 else
499 fdprintf(agi->fd, "200 result=1\n");
500 return RESULT_SUCCESS;
503 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
505 int res;
506 if (argc != 3)
507 return RESULT_SHOWUSAGE;
508 res = ast_send_image(chan, argv[2]);
509 if (!ast_check_hangup(chan))
510 res = 0;
511 fdprintf(agi->fd, "200 result=%d\n", res);
512 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
515 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
517 int res = 0;
518 int skipms = 3000;
519 char *fwd = NULL;
520 char *rev = NULL;
521 char *pause = NULL;
522 char *stop = NULL;
524 if (argc < 5 || argc > 9)
525 return RESULT_SHOWUSAGE;
527 if (!ast_strlen_zero(argv[4]))
528 stop = argv[4];
529 else
530 stop = NULL;
532 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
533 return RESULT_SHOWUSAGE;
535 if (argc > 6 && !ast_strlen_zero(argv[6]))
536 fwd = argv[6];
537 else
538 fwd = "#";
540 if (argc > 7 && !ast_strlen_zero(argv[7]))
541 rev = argv[7];
542 else
543 rev = "*";
545 if (argc > 8 && !ast_strlen_zero(argv[8]))
546 pause = argv[8];
547 else
548 pause = NULL;
550 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
552 fdprintf(agi->fd, "200 result=%d\n", res);
554 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
557 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
559 int res;
560 int vres;
561 struct ast_filestream *fs;
562 struct ast_filestream *vfs;
563 long sample_offset = 0;
564 long max_length;
565 char *edigits = "";
567 if (argc < 4 || argc > 5)
568 return RESULT_SHOWUSAGE;
570 if (argv[3])
571 edigits = argv[3];
573 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
574 return RESULT_SHOWUSAGE;
576 fs = ast_openstream(chan, argv[2], chan->language);
578 if (!fs) {
579 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
580 return RESULT_SUCCESS;
582 vfs = ast_openvstream(chan, argv[2], chan->language);
583 if (vfs)
584 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
586 if (option_verbose > 2)
587 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
589 ast_seekstream(fs, 0, SEEK_END);
590 max_length = ast_tellstream(fs);
591 ast_seekstream(fs, sample_offset, SEEK_SET);
592 res = ast_applystream(chan, fs);
593 if (vfs)
594 vres = ast_applystream(chan, vfs);
595 ast_playstream(fs);
596 if (vfs)
597 ast_playstream(vfs);
599 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
600 /* this is to check for if ast_waitstream closed the stream, we probably are at
601 * the end of the stream, return that amount, else check for the amount */
602 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
603 ast_stopstream(chan);
604 if (res == 1) {
605 /* Stop this command, don't print a result line, as there is a new command */
606 return RESULT_SUCCESS;
608 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
609 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
612 /* get option - really similar to the handle_streamfile, but with a timeout */
613 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
615 int res;
616 int vres;
617 struct ast_filestream *fs;
618 struct ast_filestream *vfs;
619 long sample_offset = 0;
620 long max_length;
621 int timeout = 0;
622 char *edigits = "";
624 if ( argc < 4 || argc > 5 )
625 return RESULT_SHOWUSAGE;
627 if ( argv[3] )
628 edigits = argv[3];
630 if ( argc == 5 )
631 timeout = atoi(argv[4]);
632 else if (chan->pbx->dtimeout) {
633 /* by default dtimeout is set to 5sec */
634 timeout = chan->pbx->dtimeout * 1000; /* in msec */
637 fs = ast_openstream(chan, argv[2], chan->language);
638 if (!fs) {
639 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
640 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
641 return RESULT_SUCCESS;
643 vfs = ast_openvstream(chan, argv[2], chan->language);
644 if (vfs)
645 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
647 if (option_verbose > 2)
648 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
650 ast_seekstream(fs, 0, SEEK_END);
651 max_length = ast_tellstream(fs);
652 ast_seekstream(fs, sample_offset, SEEK_SET);
653 res = ast_applystream(chan, fs);
654 if (vfs)
655 vres = ast_applystream(chan, vfs);
656 ast_playstream(fs);
657 if (vfs)
658 ast_playstream(vfs);
660 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
661 /* this is to check for if ast_waitstream closed the stream, we probably are at
662 * the end of the stream, return that amount, else check for the amount */
663 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
664 ast_stopstream(chan);
665 if (res == 1) {
666 /* Stop this command, don't print a result line, as there is a new command */
667 return RESULT_SUCCESS;
670 /* If the user didnt press a key, wait for digitTimeout*/
671 if (res == 0 ) {
672 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
673 /* Make sure the new result is in the escape digits of the GET OPTION */
674 if ( !strchr(edigits,res) )
675 res=0;
678 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
679 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
685 /*--- handle_saynumber: Say number in various language syntaxes ---*/
686 /* Need to add option for gender here as well. Coders wanted */
687 /* While waiting, we're sending a (char *) NULL. */
688 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
690 int res;
691 int num;
692 if (argc != 4)
693 return RESULT_SHOWUSAGE;
694 if (sscanf(argv[2], "%d", &num) != 1)
695 return RESULT_SHOWUSAGE;
696 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
697 if (res == 1)
698 return RESULT_SUCCESS;
699 fdprintf(agi->fd, "200 result=%d\n", res);
700 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
703 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
705 int res;
706 int num;
708 if (argc != 4)
709 return RESULT_SHOWUSAGE;
710 if (sscanf(argv[2], "%d", &num) != 1)
711 return RESULT_SHOWUSAGE;
713 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
714 if (res == 1) /* New command */
715 return RESULT_SUCCESS;
716 fdprintf(agi->fd, "200 result=%d\n", res);
717 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
720 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
722 int res;
724 if (argc != 4)
725 return RESULT_SHOWUSAGE;
727 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
728 if (res == 1) /* New command */
729 return RESULT_SUCCESS;
730 fdprintf(agi->fd, "200 result=%d\n", res);
731 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
734 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
736 int res;
737 int num;
738 if (argc != 4)
739 return RESULT_SHOWUSAGE;
740 if (sscanf(argv[2], "%d", &num) != 1)
741 return RESULT_SHOWUSAGE;
742 res = ast_say_date(chan, num, argv[3], chan->language);
743 if (res == 1)
744 return RESULT_SUCCESS;
745 fdprintf(agi->fd, "200 result=%d\n", res);
746 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
749 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
751 int res;
752 int num;
753 if (argc != 4)
754 return RESULT_SHOWUSAGE;
755 if (sscanf(argv[2], "%d", &num) != 1)
756 return RESULT_SHOWUSAGE;
757 res = ast_say_time(chan, num, argv[3], chan->language);
758 if (res == 1)
759 return RESULT_SUCCESS;
760 fdprintf(agi->fd, "200 result=%d\n", res);
761 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
764 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
766 int res=0;
767 time_t unixtime;
768 char *format, *zone=NULL;
770 if (argc < 4)
771 return RESULT_SHOWUSAGE;
773 if (argc > 4) {
774 format = argv[4];
775 } else {
776 /* XXX this doesn't belong here, but in the 'say' module */
777 if (!strcasecmp(chan->language, "de")) {
778 format = "A dBY HMS";
779 } else {
780 format = "ABdY 'digits/at' IMp";
784 if (argc > 5 && !ast_strlen_zero(argv[5]))
785 zone = argv[5];
787 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
788 return RESULT_SHOWUSAGE;
790 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
791 if (res == 1)
792 return RESULT_SUCCESS;
794 fdprintf(agi->fd, "200 result=%d\n", res);
795 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
798 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
800 int res;
802 if (argc != 4)
803 return RESULT_SHOWUSAGE;
805 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
806 if (res == 1) /* New command */
807 return RESULT_SUCCESS;
808 fdprintf(agi->fd, "200 result=%d\n", res);
809 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
812 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
814 int res;
815 char data[1024];
816 int max;
817 int timeout;
819 if (argc < 3)
820 return RESULT_SHOWUSAGE;
821 if (argc >= 4)
822 timeout = atoi(argv[3]);
823 else
824 timeout = 0;
825 if (argc >= 5)
826 max = atoi(argv[4]);
827 else
828 max = 1024;
829 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
830 if (res == 2) /* New command */
831 return RESULT_SUCCESS;
832 else if (res == 1)
833 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
834 else if (res < 0 )
835 fdprintf(agi->fd, "200 result=-1\n");
836 else
837 fdprintf(agi->fd, "200 result=%s\n", data);
838 return RESULT_SUCCESS;
841 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
844 if (argc != 3)
845 return RESULT_SHOWUSAGE;
846 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
847 fdprintf(agi->fd, "200 result=0\n");
848 return RESULT_SUCCESS;
851 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
853 if (argc != 3)
854 return RESULT_SHOWUSAGE;
855 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
856 fdprintf(agi->fd, "200 result=0\n");
857 return RESULT_SUCCESS;
860 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
862 int pri;
863 if (argc != 3)
864 return RESULT_SHOWUSAGE;
866 if (sscanf(argv[2], "%d", &pri) != 1) {
867 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
868 return RESULT_SHOWUSAGE;
871 ast_explicit_goto(chan, NULL, NULL, pri);
872 fdprintf(agi->fd, "200 result=0\n");
873 return RESULT_SUCCESS;
876 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
878 struct ast_filestream *fs;
879 struct ast_frame *f;
880 struct timeval start;
881 long sample_offset = 0;
882 int res = 0;
883 int ms;
885 struct ast_dsp *sildet=NULL; /* silence detector dsp */
886 int totalsilence = 0;
887 int dspsilence = 0;
888 int silence = 0; /* amount of silence to allow */
889 int gotsilence = 0; /* did we timeout for silence? */
890 char *silencestr=NULL;
891 int rfmt=0;
894 /* XXX EAGI FIXME XXX */
896 if (argc < 6)
897 return RESULT_SHOWUSAGE;
898 if (sscanf(argv[5], "%d", &ms) != 1)
899 return RESULT_SHOWUSAGE;
901 if (argc > 6)
902 silencestr = strchr(argv[6],'s');
903 if ((argc > 7) && (!silencestr))
904 silencestr = strchr(argv[7],'s');
905 if ((argc > 8) && (!silencestr))
906 silencestr = strchr(argv[8],'s');
908 if (silencestr) {
909 if (strlen(silencestr) > 2) {
910 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
911 silencestr++;
912 silencestr++;
913 if (silencestr)
914 silence = atoi(silencestr);
915 if (silence > 0)
916 silence *= 1000;
921 if (silence > 0) {
922 rfmt = chan->readformat;
923 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
924 if (res < 0) {
925 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
926 return -1;
928 sildet = ast_dsp_new();
929 if (!sildet) {
930 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
931 return -1;
933 ast_dsp_set_threshold(sildet, 256);
936 /* backward compatibility, if no offset given, arg[6] would have been
937 * caught below and taken to be a beep, else if it is a digit then it is a
938 * offset */
939 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
940 res = ast_streamfile(chan, "beep", chan->language);
942 if ((argc > 7) && (!strchr(argv[7], '=')))
943 res = ast_streamfile(chan, "beep", chan->language);
945 if (!res)
946 res = ast_waitstream(chan, argv[4]);
947 if (res) {
948 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
949 } else {
950 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
951 if (!fs) {
952 res = -1;
953 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
954 if (sildet)
955 ast_dsp_free(sildet);
956 return RESULT_FAILURE;
959 /* Request a video update */
960 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
962 chan->stream = fs;
963 ast_applystream(chan,fs);
964 /* really should have checks */
965 ast_seekstream(fs, sample_offset, SEEK_SET);
966 ast_truncstream(fs);
968 start = ast_tvnow();
969 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
970 res = ast_waitfor(chan, -1);
971 if (res < 0) {
972 ast_closestream(fs);
973 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
974 if (sildet)
975 ast_dsp_free(sildet);
976 return RESULT_FAILURE;
978 f = ast_read(chan);
979 if (!f) {
980 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
981 ast_closestream(fs);
982 if (sildet)
983 ast_dsp_free(sildet);
984 return RESULT_FAILURE;
986 switch(f->frametype) {
987 case AST_FRAME_DTMF:
988 if (strchr(argv[4], f->subclass)) {
989 /* This is an interrupting chracter, so rewind to chop off any small
990 amount of DTMF that may have been recorded
992 ast_stream_rewind(fs, 200);
993 ast_truncstream(fs);
994 sample_offset = ast_tellstream(fs);
995 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
996 ast_closestream(fs);
997 ast_frfree(f);
998 if (sildet)
999 ast_dsp_free(sildet);
1000 return RESULT_SUCCESS;
1002 break;
1003 case AST_FRAME_VOICE:
1004 ast_writestream(fs, f);
1005 /* this is a safe place to check progress since we know that fs
1006 * is valid after a write, and it will then have our current
1007 * location */
1008 sample_offset = ast_tellstream(fs);
1009 if (silence > 0) {
1010 dspsilence = 0;
1011 ast_dsp_silence(sildet, f, &dspsilence);
1012 if (dspsilence) {
1013 totalsilence = dspsilence;
1014 } else {
1015 totalsilence = 0;
1017 if (totalsilence > silence) {
1018 /* Ended happily with silence */
1019 gotsilence = 1;
1020 break;
1023 break;
1024 case AST_FRAME_VIDEO:
1025 ast_writestream(fs, f);
1026 default:
1027 /* Ignore all other frames */
1028 break;
1030 ast_frfree(f);
1031 if (gotsilence)
1032 break;
1035 if (gotsilence) {
1036 ast_stream_rewind(fs, silence-1000);
1037 ast_truncstream(fs);
1038 sample_offset = ast_tellstream(fs);
1040 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1041 ast_closestream(fs);
1044 if (silence > 0) {
1045 res = ast_set_read_format(chan, rfmt);
1046 if (res)
1047 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1048 ast_dsp_free(sildet);
1050 return RESULT_SUCCESS;
1053 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1055 int timeout;
1057 if (argc != 3)
1058 return RESULT_SHOWUSAGE;
1059 if (sscanf(argv[2], "%d", &timeout) != 1)
1060 return RESULT_SHOWUSAGE;
1061 if (timeout < 0)
1062 timeout = 0;
1063 if (timeout)
1064 chan->whentohangup = time(NULL) + timeout;
1065 else
1066 chan->whentohangup = 0;
1067 fdprintf(agi->fd, "200 result=0\n");
1068 return RESULT_SUCCESS;
1071 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1073 struct ast_channel *c;
1074 if (argc == 1) {
1075 /* no argument: hangup the current channel */
1076 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1077 fdprintf(agi->fd, "200 result=1\n");
1078 return RESULT_SUCCESS;
1079 } else if (argc == 2) {
1080 /* one argument: look for info on the specified channel */
1081 c = ast_get_channel_by_name_locked(argv[1]);
1082 if (c) {
1083 /* we have a matching channel */
1084 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1085 fdprintf(agi->fd, "200 result=1\n");
1086 ast_channel_unlock(c);
1087 return RESULT_SUCCESS;
1089 /* if we get this far no channel name matched the argument given */
1090 fdprintf(agi->fd, "200 result=-1\n");
1091 return RESULT_SUCCESS;
1092 } else {
1093 return RESULT_SHOWUSAGE;
1097 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1099 int res;
1100 struct ast_app *app;
1102 if (argc < 2)
1103 return RESULT_SHOWUSAGE;
1105 if (option_verbose > 2)
1106 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1108 app = pbx_findapp(argv[1]);
1110 if (app) {
1111 res = pbx_exec(chan, app, argv[2]);
1112 } else {
1113 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1114 res = -2;
1116 fdprintf(agi->fd, "200 result=%d\n", res);
1118 /* Even though this is wrong, users are depending upon this result. */
1119 return res;
1122 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1124 char tmp[256]="";
1125 char *l = NULL, *n = NULL;
1127 if (argv[2]) {
1128 ast_copy_string(tmp, argv[2], sizeof(tmp));
1129 ast_callerid_parse(tmp, &n, &l);
1130 if (l)
1131 ast_shrink_phone_number(l);
1132 else
1133 l = "";
1134 if (!n)
1135 n = "";
1136 ast_set_callerid(chan, l, n, NULL);
1139 fdprintf(agi->fd, "200 result=1\n");
1140 return RESULT_SUCCESS;
1143 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1145 struct ast_channel *c;
1146 if (argc == 2) {
1147 /* no argument: supply info on the current channel */
1148 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1149 return RESULT_SUCCESS;
1150 } else if (argc == 3) {
1151 /* one argument: look for info on the specified channel */
1152 c = ast_get_channel_by_name_locked(argv[2]);
1153 if (c) {
1154 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1155 ast_channel_unlock(c);
1156 return RESULT_SUCCESS;
1158 /* if we get this far no channel name matched the argument given */
1159 fdprintf(agi->fd, "200 result=-1\n");
1160 return RESULT_SUCCESS;
1161 } else {
1162 return RESULT_SHOWUSAGE;
1166 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1168 if (argv[3])
1169 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1171 fdprintf(agi->fd, "200 result=1\n");
1172 return RESULT_SUCCESS;
1175 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1177 char *ret;
1178 char tempstr[1024];
1180 if (argc != 3)
1181 return RESULT_SHOWUSAGE;
1183 /* check if we want to execute an ast_custom_function */
1184 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1185 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1186 } else {
1187 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1190 if (ret)
1191 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1192 else
1193 fdprintf(agi->fd, "200 result=0\n");
1195 return RESULT_SUCCESS;
1198 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1200 char tmp[4096] = "";
1201 struct ast_channel *chan2=NULL;
1203 if ((argc != 4) && (argc != 5))
1204 return RESULT_SHOWUSAGE;
1205 if (argc == 5) {
1206 chan2 = ast_get_channel_by_name_locked(argv[4]);
1207 } else {
1208 chan2 = chan;
1210 if (chan2) {
1211 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1212 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1213 } else {
1214 fdprintf(agi->fd, "200 result=0\n");
1216 if (chan2 && (chan2 != chan))
1217 ast_channel_unlock(chan2);
1218 return RESULT_SUCCESS;
1221 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1223 int level = 0;
1224 char *prefix;
1226 if (argc < 2)
1227 return RESULT_SHOWUSAGE;
1229 if (argv[2])
1230 sscanf(argv[2], "%d", &level);
1232 switch (level) {
1233 case 4:
1234 prefix = VERBOSE_PREFIX_4;
1235 break;
1236 case 3:
1237 prefix = VERBOSE_PREFIX_3;
1238 break;
1239 case 2:
1240 prefix = VERBOSE_PREFIX_2;
1241 break;
1242 case 1:
1243 default:
1244 prefix = VERBOSE_PREFIX_1;
1245 break;
1248 if (level <= option_verbose)
1249 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1251 fdprintf(agi->fd, "200 result=1\n");
1253 return RESULT_SUCCESS;
1256 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1258 int res;
1259 char tmp[256];
1261 if (argc != 4)
1262 return RESULT_SHOWUSAGE;
1263 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1264 if (res)
1265 fdprintf(agi->fd, "200 result=0\n");
1266 else
1267 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1269 return RESULT_SUCCESS;
1272 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1274 int res;
1276 if (argc != 5)
1277 return RESULT_SHOWUSAGE;
1278 res = ast_db_put(argv[2], argv[3], argv[4]);
1279 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1280 return RESULT_SUCCESS;
1283 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1285 int res;
1287 if (argc != 4)
1288 return RESULT_SHOWUSAGE;
1289 res = ast_db_del(argv[2], argv[3]);
1290 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1291 return RESULT_SUCCESS;
1294 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1296 int res;
1297 if ((argc < 3) || (argc > 4))
1298 return RESULT_SHOWUSAGE;
1299 if (argc == 4)
1300 res = ast_db_deltree(argv[2], argv[3]);
1301 else
1302 res = ast_db_deltree(argv[2], NULL);
1304 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1305 return RESULT_SUCCESS;
1308 static char debug_usage[] =
1309 "Usage: agi debug\n"
1310 " Enables dumping of AGI transactions for debugging purposes\n";
1312 static char no_debug_usage[] =
1313 "Usage: agi debug off\n"
1314 " Disables dumping of AGI transactions for debugging purposes\n";
1316 static int agi_do_debug(int fd, int argc, char *argv[])
1318 if (argc != 2)
1319 return RESULT_SHOWUSAGE;
1320 agidebug = 1;
1321 ast_cli(fd, "AGI Debugging Enabled\n");
1322 return RESULT_SUCCESS;
1325 static int agi_no_debug_deprecated(int fd, int argc, char *argv[])
1327 if (argc != 3)
1328 return RESULT_SHOWUSAGE;
1329 agidebug = 0;
1330 ast_cli(fd, "AGI Debugging Disabled\n");
1331 return RESULT_SUCCESS;
1334 static int agi_no_debug(int fd, int argc, char *argv[])
1336 if (argc != 3)
1337 return RESULT_SHOWUSAGE;
1338 agidebug = 0;
1339 ast_cli(fd, "AGI Debugging Disabled\n");
1340 return RESULT_SUCCESS;
1343 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1345 fdprintf(agi->fd, "200 result=0\n");
1346 return RESULT_SUCCESS;
1349 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1351 if (!strncasecmp(argv[2], "on", 2))
1352 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1353 else if (!strncasecmp(argv[2], "off", 3))
1354 ast_moh_stop(chan);
1355 fdprintf(agi->fd, "200 result=0\n");
1356 return RESULT_SUCCESS;
1359 static char usage_setmusic[] =
1360 " Usage: SET MUSIC ON <on|off> <class>\n"
1361 " Enables/Disables the music on hold generator. If <class> is\n"
1362 " not specified, then the default music on hold class will be used.\n"
1363 " Always returns 0.\n";
1365 static char usage_dbput[] =
1366 " Usage: DATABASE PUT <family> <key> <value>\n"
1367 " Adds or updates an entry in the Asterisk database for a\n"
1368 " given family, key, and value.\n"
1369 " Returns 1 if successful, 0 otherwise.\n";
1371 static char usage_dbget[] =
1372 " Usage: DATABASE GET <family> <key>\n"
1373 " Retrieves an entry in the Asterisk database for a\n"
1374 " given family and key.\n"
1375 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1376 " is set and returns the variable in parentheses.\n"
1377 " Example return code: 200 result=1 (testvariable)\n";
1379 static char usage_dbdel[] =
1380 " Usage: DATABASE DEL <family> <key>\n"
1381 " Deletes an entry in the Asterisk database for a\n"
1382 " given family and key.\n"
1383 " Returns 1 if successful, 0 otherwise.\n";
1385 static char usage_dbdeltree[] =
1386 " Usage: DATABASE DELTREE <family> [keytree]\n"
1387 " Deletes a family or specific keytree within a family\n"
1388 " in the Asterisk database.\n"
1389 " Returns 1 if successful, 0 otherwise.\n";
1391 static char usage_verbose[] =
1392 " Usage: VERBOSE <message> <level>\n"
1393 " Sends <message> to the console via verbose message system.\n"
1394 " <level> is the the verbose level (1-4)\n"
1395 " Always returns 1.\n";
1397 static char usage_getvariable[] =
1398 " Usage: GET VARIABLE <variablename>\n"
1399 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1400 " is set and returns the variable in parentheses.\n"
1401 " example return code: 200 result=1 (testvariable)\n";
1403 static char usage_getvariablefull[] =
1404 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1405 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1406 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1407 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1408 " example return code: 200 result=1 (testvariable)\n";
1410 static char usage_setvariable[] =
1411 " Usage: SET VARIABLE <variablename> <value>\n";
1413 static char usage_channelstatus[] =
1414 " Usage: CHANNEL STATUS [<channelname>]\n"
1415 " Returns the status of the specified channel.\n"
1416 " If no channel name is given the returns the status of the\n"
1417 " current channel. Return values:\n"
1418 " 0 Channel is down and available\n"
1419 " 1 Channel is down, but reserved\n"
1420 " 2 Channel is off hook\n"
1421 " 3 Digits (or equivalent) have been dialed\n"
1422 " 4 Line is ringing\n"
1423 " 5 Remote end is ringing\n"
1424 " 6 Line is up\n"
1425 " 7 Line is busy\n";
1427 static char usage_setcallerid[] =
1428 " Usage: SET CALLERID <number>\n"
1429 " Changes the callerid of the current channel.\n";
1431 static char usage_exec[] =
1432 " Usage: EXEC <application> <options>\n"
1433 " Executes <application> with given <options>.\n"
1434 " Returns whatever the application returns, or -2 on failure to find application\n";
1436 static char usage_hangup[] =
1437 " Usage: HANGUP [<channelname>]\n"
1438 " Hangs up the specified channel.\n"
1439 " If no channel name is given, hangs up the current channel\n";
1441 static char usage_answer[] =
1442 " Usage: ANSWER\n"
1443 " Answers channel if not already in answer state. Returns -1 on\n"
1444 " channel failure, or 0 if successful.\n";
1446 static char usage_waitfordigit[] =
1447 " Usage: WAIT FOR DIGIT <timeout>\n"
1448 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1449 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1450 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1451 " for the timeout value if you desire the call to block indefinitely.\n";
1453 static char usage_sendtext[] =
1454 " Usage: SEND TEXT \"<text to send>\"\n"
1455 " Sends the given text on a channel. Most channels do not support the\n"
1456 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1457 " support text transmission. Returns -1 only on error/hangup. Text\n"
1458 " consisting of greater than one word should be placed in quotes since the\n"
1459 " command only accepts a single argument.\n";
1461 static char usage_recvchar[] =
1462 " Usage: RECEIVE CHAR <timeout>\n"
1463 " Receives a character of text on a channel. Specify timeout to be the\n"
1464 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1465 " do not support the reception of text. Returns the decimal value of the character\n"
1466 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1467 " -1 only on error/hangup.\n";
1469 static char usage_recvtext[] =
1470 " Usage: RECEIVE TEXT <timeout>\n"
1471 " Receives a string of text on a channel. Specify timeout to be the\n"
1472 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1473 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1475 static char usage_tddmode[] =
1476 " Usage: TDD MODE <on|off>\n"
1477 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1478 " successful, or 0 if channel is not TDD-capable.\n";
1480 static char usage_sendimage[] =
1481 " Usage: SEND IMAGE <image>\n"
1482 " Sends the given image on a channel. Most channels do not support the\n"
1483 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1484 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1485 " should not include extensions.\n";
1487 static char usage_streamfile[] =
1488 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1489 " Send the given file, allowing playback to be interrupted by the given\n"
1490 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1491 " permitted. If sample offset is provided then the audio will seek to sample\n"
1492 " offset before play starts. Returns 0 if playback completes without a digit\n"
1493 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1494 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1495 " extension must not be included in the filename.\n";
1497 static char usage_controlstreamfile[] =
1498 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1499 " Send the given file, allowing playback to be controled by the given\n"
1500 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1501 " permitted. Returns 0 if playback completes without a digit\n"
1502 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1503 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1504 " extension must not be included in the filename.\n\n"
1505 " Note: ffchar and rewchar default to * and # respectively.\n";
1507 static char usage_getoption[] =
1508 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1509 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1511 static char usage_saynumber[] =
1512 " Usage: SAY NUMBER <number> <escape digits>\n"
1513 " Say a given number, returning early if any of the given DTMF digits\n"
1514 " are received on the channel. Returns 0 if playback completes without a digit\n"
1515 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1516 " -1 on error/hangup.\n";
1518 static char usage_saydigits[] =
1519 " Usage: SAY DIGITS <number> <escape digits>\n"
1520 " Say a given digit string, returning early if any of the given DTMF digits\n"
1521 " are received on the channel. Returns 0 if playback completes without a digit\n"
1522 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1523 " -1 on error/hangup.\n";
1525 static char usage_sayalpha[] =
1526 " Usage: SAY ALPHA <number> <escape digits>\n"
1527 " Say a given character string, returning early if any of the given DTMF digits\n"
1528 " are received on the channel. Returns 0 if playback completes without a digit\n"
1529 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1530 " -1 on error/hangup.\n";
1532 static char usage_saydate[] =
1533 " Usage: SAY DATE <date> <escape digits>\n"
1534 " Say a given date, returning early if any of the given DTMF digits are\n"
1535 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1536 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1537 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1538 " digit if one was pressed or -1 on error/hangup.\n";
1540 static char usage_saytime[] =
1541 " Usage: SAY TIME <time> <escape digits>\n"
1542 " Say a given time, returning early if any of the given DTMF digits are\n"
1543 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1544 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1545 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1546 " digit if one was pressed or -1 on error/hangup.\n";
1548 static char usage_saydatetime[] =
1549 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1550 " Say a given time, returning early if any of the given DTMF digits are\n"
1551 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1552 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1553 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1554 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1555 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1556 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1557 " digit if one was pressed or -1 on error/hangup.\n";
1559 static char usage_sayphonetic[] =
1560 " Usage: SAY PHONETIC <string> <escape digits>\n"
1561 " Say a given character string with phonetics, returning early if any of the\n"
1562 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1563 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1564 " if one was pressed, or -1 on error/hangup.\n";
1566 static char usage_getdata[] =
1567 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1568 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1569 "from the channel at the other end.\n";
1571 static char usage_setcontext[] =
1572 " Usage: SET CONTEXT <desired context>\n"
1573 " Sets the context for continuation upon exiting the application.\n";
1575 static char usage_setextension[] =
1576 " Usage: SET EXTENSION <new extension>\n"
1577 " Changes the extension for continuation upon exiting the application.\n";
1579 static char usage_setpriority[] =
1580 " Usage: SET PRIORITY <priority>\n"
1581 " Changes the priority for continuation upon exiting the application.\n"
1582 " The priority must be a valid priority or label.\n";
1584 static char usage_recordfile[] =
1585 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1586 " [offset samples] [BEEP] [s=silence]\n"
1587 " Record to a file until a given dtmf digit in the sequence is received\n"
1588 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1589 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1590 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1591 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1592 " of seconds of silence allowed before the function returns despite the\n"
1593 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1594 " preceeded by \"s=\" and is also optional.\n";
1596 static char usage_autohangup[] =
1597 " Usage: SET AUTOHANGUP <time>\n"
1598 " Cause the channel to automatically hangup at <time> seconds in the\n"
1599 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1600 " cause the autohangup feature to be disabled on this channel.\n";
1602 static char usage_noop[] =
1603 " Usage: NoOp\n"
1604 " Does nothing.\n";
1606 static agi_command commands[MAX_COMMANDS] = {
1607 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1608 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1609 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1610 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1611 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1612 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1613 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1614 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1615 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1616 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1617 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1618 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1619 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1620 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1621 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1622 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1623 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1624 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1625 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1626 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1627 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1628 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1629 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1630 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1631 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1632 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1633 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1634 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1635 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1636 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1637 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1638 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1639 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1640 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1641 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1642 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1643 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1646 static int help_workhorse(int fd, char *match[])
1648 char fullcmd[80];
1649 char matchstr[80];
1650 int x;
1651 struct agi_command *e;
1652 if (match)
1653 ast_join(matchstr, sizeof(matchstr), match);
1654 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1655 e = &commands[x];
1656 if (!e->cmda[0])
1657 break;
1658 /* Hide commands that start with '_' */
1659 if ((e->cmda[0])[0] == '_')
1660 continue;
1661 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1662 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1663 continue;
1664 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1666 return 0;
1669 int ast_agi_register(agi_command *agi)
1671 int x;
1672 for (x=0; x<MAX_COMMANDS - 1; x++) {
1673 if (commands[x].cmda[0] == agi->cmda[0]) {
1674 ast_log(LOG_WARNING, "Command already registered!\n");
1675 return -1;
1678 for (x=0; x<MAX_COMMANDS - 1; x++) {
1679 if (!commands[x].cmda[0]) {
1680 commands[x] = *agi;
1681 return 0;
1684 ast_log(LOG_WARNING, "No more room for new commands!\n");
1685 return -1;
1688 void ast_agi_unregister(agi_command *agi)
1690 int x;
1691 for (x=0; x<MAX_COMMANDS - 1; x++) {
1692 if (commands[x].cmda[0] == agi->cmda[0]) {
1693 memset(&commands[x], 0, sizeof(agi_command));
1698 static agi_command *find_command(char *cmds[], int exact)
1700 int x;
1701 int y;
1702 int match;
1704 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1705 if (!commands[x].cmda[0])
1706 break;
1707 /* start optimistic */
1708 match = 1;
1709 for (y=0; match && cmds[y]; y++) {
1710 /* If there are no more words in the command (and we're looking for
1711 an exact match) or there is a difference between the two words,
1712 then this is not a match */
1713 if (!commands[x].cmda[y] && !exact)
1714 break;
1715 /* don't segfault if the next part of a command doesn't exist */
1716 if (!commands[x].cmda[y])
1717 return NULL;
1718 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1719 match = 0;
1721 /* If more words are needed to complete the command then this is not
1722 a candidate (unless we're looking for a really inexact answer */
1723 if ((exact > -1) && commands[x].cmda[y])
1724 match = 0;
1725 if (match)
1726 return &commands[x];
1728 return NULL;
1732 static int parse_args(char *s, int *max, char *argv[])
1734 int x=0;
1735 int quoted=0;
1736 int escaped=0;
1737 int whitespace=1;
1738 char *cur;
1740 cur = s;
1741 while(*s) {
1742 switch(*s) {
1743 case '"':
1744 /* If it's escaped, put a literal quote */
1745 if (escaped)
1746 goto normal;
1747 else
1748 quoted = !quoted;
1749 if (quoted && whitespace) {
1750 /* If we're starting a quote, coming off white space start a new word, too */
1751 argv[x++] = cur;
1752 whitespace=0;
1754 escaped = 0;
1755 break;
1756 case ' ':
1757 case '\t':
1758 if (!quoted && !escaped) {
1759 /* If we're not quoted, mark this as whitespace, and
1760 end the previous argument */
1761 whitespace = 1;
1762 *(cur++) = '\0';
1763 } else
1764 /* Otherwise, just treat it as anything else */
1765 goto normal;
1766 break;
1767 case '\\':
1768 /* If we're escaped, print a literal, otherwise enable escaping */
1769 if (escaped) {
1770 goto normal;
1771 } else {
1772 escaped=1;
1774 break;
1775 default:
1776 normal:
1777 if (whitespace) {
1778 if (x >= MAX_ARGS -1) {
1779 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1780 break;
1782 /* Coming off of whitespace, start the next argument */
1783 argv[x++] = cur;
1784 whitespace=0;
1786 *(cur++) = *s;
1787 escaped=0;
1789 s++;
1791 /* Null terminate */
1792 *(cur++) = '\0';
1793 argv[x] = NULL;
1794 *max = x;
1795 return 0;
1798 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1800 char *argv[MAX_ARGS];
1801 int argc = MAX_ARGS;
1802 int res;
1803 agi_command *c;
1805 parse_args(buf, &argc, argv);
1806 c = find_command(argv, 0);
1807 if (c) {
1808 res = c->handler(chan, agi, argc, argv);
1809 switch(res) {
1810 case RESULT_SHOWUSAGE:
1811 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1812 fdprintf(agi->fd, c->usage);
1813 fdprintf(agi->fd, "520 End of proper usage.\n");
1814 break;
1815 case AST_PBX_KEEPALIVE:
1816 /* We've been asked to keep alive, so do so */
1817 return AST_PBX_KEEPALIVE;
1818 break;
1819 case RESULT_FAILURE:
1820 /* They've already given the failure. We've been hung up on so handle this
1821 appropriately */
1822 return -1;
1824 } else {
1825 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1827 return 0;
1829 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead)
1831 struct ast_channel *c;
1832 int outfd;
1833 int ms;
1834 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1835 struct ast_frame *f;
1836 char buf[AGI_BUF_LEN];
1837 char *res = NULL;
1838 FILE *readf;
1839 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1840 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1841 int retry = AGI_NANDFS_RETRY;
1843 if (!(readf = fdopen(agi->ctrl, "r"))) {
1844 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1845 if (pid > -1)
1846 kill(pid, SIGHUP);
1847 close(agi->ctrl);
1848 return AGI_RESULT_FAILURE;
1850 setlinebuf(readf);
1851 setup_env(chan, request, agi->fd, (agi->audio > -1));
1852 for (;;) {
1853 ms = -1;
1854 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1855 if (c) {
1856 retry = AGI_NANDFS_RETRY;
1857 /* Idle the channel until we get a command */
1858 f = ast_read(c);
1859 if (!f) {
1860 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1861 returnstatus = AGI_RESULT_HANGUP;
1862 break;
1863 } else {
1864 /* If it's voice, write it to the audio pipe */
1865 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1866 /* Write, ignoring errors */
1867 write(agi->audio, f->data, f->datalen);
1869 ast_frfree(f);
1871 } else if (outfd > -1) {
1872 size_t len = sizeof(buf);
1873 size_t buflen = 0;
1875 retry = AGI_NANDFS_RETRY;
1876 buf[0] = '\0';
1878 while (buflen < (len - 1)) {
1879 res = fgets(buf + buflen, len, readf);
1880 if (feof(readf))
1881 break;
1882 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
1883 break;
1884 if (res != NULL && !agi->fast)
1885 break;
1886 buflen = strlen(buf);
1887 if (buflen && buf[buflen - 1] == '\n')
1888 break;
1889 len -= buflen;
1890 if (agidebug)
1891 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
1894 if (!buf[0]) {
1895 /* Program terminated */
1896 if (returnstatus)
1897 returnstatus = -1;
1898 if (option_verbose > 2)
1899 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1900 if (pid > 0)
1901 waitpid(pid, status, 0);
1902 /* No need to kill the pid anymore, since they closed us */
1903 pid = -1;
1904 break;
1907 /* get rid of trailing newline, if any */
1908 if (*buf && buf[strlen(buf) - 1] == '\n')
1909 buf[strlen(buf) - 1] = 0;
1910 if (agidebug)
1911 ast_verbose("AGI Rx << %s\n", buf);
1912 returnstatus |= agi_handle_command(chan, agi, buf);
1913 /* If the handle_command returns -1, we need to stop */
1914 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1915 break;
1917 } else {
1918 if (--retry <= 0) {
1919 ast_log(LOG_WARNING, "No channel, no fd?\n");
1920 returnstatus = AGI_RESULT_FAILURE;
1921 break;
1925 /* Notify process */
1926 if (pid > -1) {
1927 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1928 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1929 if (kill(pid, SIGHUP))
1930 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1933 fclose(readf);
1934 return returnstatus;
1937 static int handle_showagi(int fd, int argc, char *argv[])
1939 struct agi_command *e;
1940 char fullcmd[80];
1941 if ((argc < 2))
1942 return RESULT_SHOWUSAGE;
1943 if (argc > 2) {
1944 e = find_command(argv + 2, 1);
1945 if (e)
1946 ast_cli(fd, e->usage);
1947 else {
1948 if (find_command(argv + 2, -1)) {
1949 return help_workhorse(fd, argv + 1);
1950 } else {
1951 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1952 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1955 } else {
1956 return help_workhorse(fd, NULL);
1958 return RESULT_SUCCESS;
1961 static int handle_agidumphtml(int fd, int argc, char *argv[])
1963 struct agi_command *e;
1964 char fullcmd[80];
1965 int x;
1966 FILE *htmlfile;
1968 if ((argc < 3))
1969 return RESULT_SHOWUSAGE;
1971 if (!(htmlfile = fopen(argv[2], "wt"))) {
1972 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1973 return RESULT_SHOWUSAGE;
1976 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1977 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1980 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1982 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1983 char *stringp, *tempstr;
1985 e = &commands[x];
1986 if (!e->cmda[0]) /* end ? */
1987 break;
1988 /* Hide commands that start with '_' */
1989 if ((e->cmda[0])[0] == '_')
1990 continue;
1991 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1993 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1994 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary);
1996 stringp=e->usage;
1997 tempstr = strsep(&stringp, "\n");
1999 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
2001 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2002 while ((tempstr = strsep(&stringp, "\n")) != NULL)
2003 fprintf(htmlfile, "%s<BR>\n",tempstr);
2004 fprintf(htmlfile, "</TD></TR>\n");
2005 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2009 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2010 fclose(htmlfile);
2011 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
2012 return RESULT_SUCCESS;
2015 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2017 enum agi_result res;
2018 struct ast_module_user *u;
2019 char *argv[MAX_ARGS];
2020 char buf[AGI_BUF_LEN] = "";
2021 char *tmp = (char *)buf;
2022 int argc = 0;
2023 int fds[2];
2024 int efd = -1;
2025 int pid;
2026 char *stringp;
2027 AGI agi;
2029 if (ast_strlen_zero(data)) {
2030 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2031 return -1;
2033 ast_copy_string(buf, data, sizeof(buf));
2035 memset(&agi, 0, sizeof(agi));
2036 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
2037 argv[argc++] = stringp;
2038 argv[argc] = NULL;
2040 u = ast_module_user_add(chan);
2041 #if 0
2042 /* Answer if need be */
2043 if (chan->_state != AST_STATE_UP) {
2044 if (ast_answer(chan)) {
2045 LOCAL_USER_REMOVE(u);
2046 return -1;
2049 #endif
2050 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2051 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2052 int status = 0;
2053 agi.fd = fds[1];
2054 agi.ctrl = fds[0];
2055 agi.audio = efd;
2056 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2057 res = run_agi(chan, argv[0], &agi, pid, &status, dead);
2058 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2059 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2060 res = AGI_RESULT_FAILURE;
2061 if (fds[1] != fds[0])
2062 close(fds[1]);
2063 if (efd > -1)
2064 close(efd);
2065 ast_unreplace_sigchld();
2067 ast_module_user_remove(u);
2069 switch (res) {
2070 case AGI_RESULT_SUCCESS:
2071 case AGI_RESULT_SUCCESS_FAST:
2072 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2073 break;
2074 case AGI_RESULT_FAILURE:
2075 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2076 break;
2077 case AGI_RESULT_HANGUP:
2078 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2079 return -1;
2082 return 0;
2085 static int agi_exec(struct ast_channel *chan, void *data)
2087 if (chan->_softhangup)
2088 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2089 return agi_exec_full(chan, data, 0, 0);
2092 static int eagi_exec(struct ast_channel *chan, void *data)
2094 int readformat;
2095 int res;
2097 if (chan->_softhangup)
2098 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2099 readformat = chan->readformat;
2100 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2101 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2102 return -1;
2104 res = agi_exec_full(chan, data, 1, 0);
2105 if (!res) {
2106 if (ast_set_read_format(chan, readformat)) {
2107 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2110 return res;
2113 static int deadagi_exec(struct ast_channel *chan, void *data)
2115 if (!ast_check_hangup(chan))
2116 ast_log(LOG_WARNING,"Running DeadAGI on a live channel will cause problems, please use AGI\n");
2117 return agi_exec_full(chan, data, 0, 1);
2120 static char showagi_help[] =
2121 "Usage: agi show [topic]\n"
2122 " When called with a topic as an argument, displays usage\n"
2123 " information on the given command. If called without a\n"
2124 " topic, it provides a list of AGI commands.\n";
2127 static char dumpagihtml_help[] =
2128 "Usage: agi dumphtml <filename>\n"
2129 " Dumps the agi command list in html format to given filename\n";
2131 static struct ast_cli_entry cli_show_agi_deprecated = {
2132 { "show", "agi", NULL },
2133 handle_showagi, NULL,
2134 NULL };
2136 static struct ast_cli_entry cli_dump_agihtml_deprecated = {
2137 { "dump", "agihtml", NULL },
2138 handle_agidumphtml, NULL,
2139 NULL };
2141 static struct ast_cli_entry cli_agi_no_debug_deprecated = {
2142 { "agi", "no", "debug", NULL },
2143 agi_no_debug_deprecated, NULL,
2144 NULL };
2146 static struct ast_cli_entry cli_agi[] = {
2147 { { "agi", "debug", NULL },
2148 agi_do_debug, "Enable AGI debugging",
2149 debug_usage },
2151 { { "agi", "debug", "off", NULL },
2152 agi_no_debug, "Disable AGI debugging",
2153 no_debug_usage, NULL, &cli_agi_no_debug_deprecated },
2155 { { "agi", "show", NULL },
2156 handle_showagi, "List AGI commands or specific help",
2157 showagi_help, NULL, &cli_show_agi_deprecated },
2159 { { "agi", "dumphtml", NULL },
2160 handle_agidumphtml, "Dumps a list of agi commands in html format",
2161 dumpagihtml_help, NULL, &cli_dump_agihtml_deprecated },
2164 static int unload_module(void)
2166 ast_module_user_hangup_all();
2167 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2168 ast_unregister_application(eapp);
2169 ast_unregister_application(deadapp);
2170 return ast_unregister_application(app);
2173 static int load_module(void)
2175 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2176 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2177 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2178 return ast_register_application(app, agi_exec, synopsis, descrip);
2181 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2182 .load = load_module,
2183 .unload = unload_module,