Correction to commmit 120863, make sure proper destructor function is called as well...
[asterisk-bristuff.git] / res / res_agi.c
blobea1f329d272fcdb90941507caafc8f4537fe9ac6
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 /* Special case to set status of AGI to failure */
350 fprintf(stdout, "failure\n");
351 fflush(stdout);
352 _exit(1);
354 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
355 if (option_verbose > 2)
356 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
357 fds[0] = toast[0];
358 fds[1] = fromast[1];
359 if (efd) {
360 *efd = audio[1];
362 /* close what we're not using in the parent */
363 close(toast[1]);
364 close(fromast[0]);
366 if (efd)
367 close(audio[0]);
369 *opid = pid;
370 return AGI_RESULT_SUCCESS;
373 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
375 /* Print initial environment, with agi_request always being the first
376 thing */
377 fdprintf(fd, "agi_request: %s\n", request);
378 fdprintf(fd, "agi_channel: %s\n", chan->name);
379 fdprintf(fd, "agi_language: %s\n", chan->language);
380 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
381 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
383 /* ANI/DNIS */
384 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
385 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
386 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
387 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
388 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
389 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
390 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
391 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
393 /* Context information */
394 fdprintf(fd, "agi_context: %s\n", chan->context);
395 fdprintf(fd, "agi_extension: %s\n", chan->exten);
396 fdprintf(fd, "agi_priority: %d\n", chan->priority);
397 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
399 /* User information */
400 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
402 /* End with empty return */
403 fdprintf(fd, "\n");
406 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
408 int res;
409 res = 0;
410 if (chan->_state != AST_STATE_UP) {
411 /* Answer the chan */
412 res = ast_answer(chan);
414 fdprintf(agi->fd, "200 result=%d\n", res);
415 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
418 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
420 int res;
421 int to;
422 if (argc != 4)
423 return RESULT_SHOWUSAGE;
424 if (sscanf(argv[3], "%d", &to) != 1)
425 return RESULT_SHOWUSAGE;
426 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
427 fdprintf(agi->fd, "200 result=%d\n", res);
428 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
431 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
433 int res;
434 if (argc != 3)
435 return RESULT_SHOWUSAGE;
436 /* At the moment, the parser (perhaps broken) returns with
437 the last argument PLUS the newline at the end of the input
438 buffer. This probably needs to be fixed, but I wont do that
439 because other stuff may break as a result. The right way
440 would probably be to strip off the trailing newline before
441 parsing, then here, add a newline at the end of the string
442 before sending it to ast_sendtext --DUDE */
443 res = ast_sendtext(chan, argv[2]);
444 fdprintf(agi->fd, "200 result=%d\n", res);
445 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
448 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
450 int res;
451 if (argc != 3)
452 return RESULT_SHOWUSAGE;
453 res = ast_recvchar(chan,atoi(argv[2]));
454 if (res == 0) {
455 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
456 return RESULT_SUCCESS;
458 if (res > 0) {
459 fdprintf(agi->fd, "200 result=%d\n", res);
460 return RESULT_SUCCESS;
462 else {
463 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
464 return RESULT_FAILURE;
468 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
470 char *buf;
472 if (argc != 3)
473 return RESULT_SHOWUSAGE;
474 buf = ast_recvtext(chan,atoi(argv[2]));
475 if (buf) {
476 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
477 free(buf);
478 } else {
479 fdprintf(agi->fd, "200 result=-1\n");
481 return RESULT_SUCCESS;
484 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
486 int res,x;
487 if (argc != 3)
488 return RESULT_SHOWUSAGE;
489 if (!strncasecmp(argv[2],"on",2))
490 x = 1;
491 else
492 x = 0;
493 if (!strncasecmp(argv[2],"mate",4))
494 x = 2;
495 if (!strncasecmp(argv[2],"tdd",3))
496 x = 1;
497 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
498 if (res != RESULT_SUCCESS)
499 fdprintf(agi->fd, "200 result=0\n");
500 else
501 fdprintf(agi->fd, "200 result=1\n");
502 return RESULT_SUCCESS;
505 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
507 int res;
508 if (argc != 3)
509 return RESULT_SHOWUSAGE;
510 res = ast_send_image(chan, argv[2]);
511 if (!ast_check_hangup(chan))
512 res = 0;
513 fdprintf(agi->fd, "200 result=%d\n", res);
514 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
517 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
519 int res = 0;
520 int skipms = 3000;
521 char *fwd = NULL;
522 char *rev = NULL;
523 char *pause = NULL;
524 char *stop = NULL;
526 if (argc < 5 || argc > 9)
527 return RESULT_SHOWUSAGE;
529 if (!ast_strlen_zero(argv[4]))
530 stop = argv[4];
531 else
532 stop = NULL;
534 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
535 return RESULT_SHOWUSAGE;
537 if (argc > 6 && !ast_strlen_zero(argv[6]))
538 fwd = argv[6];
539 else
540 fwd = "#";
542 if (argc > 7 && !ast_strlen_zero(argv[7]))
543 rev = argv[7];
544 else
545 rev = "*";
547 if (argc > 8 && !ast_strlen_zero(argv[8]))
548 pause = argv[8];
549 else
550 pause = NULL;
552 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
554 fdprintf(agi->fd, "200 result=%d\n", res);
556 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
559 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
561 int res;
562 int vres;
563 struct ast_filestream *fs;
564 struct ast_filestream *vfs;
565 long sample_offset = 0;
566 long max_length;
567 char *edigits = "";
569 if (argc < 4 || argc > 5)
570 return RESULT_SHOWUSAGE;
572 if (argv[3])
573 edigits = argv[3];
575 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
576 return RESULT_SHOWUSAGE;
578 fs = ast_openstream(chan, argv[2], chan->language);
580 if (!fs) {
581 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
582 return RESULT_SUCCESS;
584 vfs = ast_openvstream(chan, argv[2], chan->language);
585 if (vfs)
586 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
588 if (option_verbose > 2)
589 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
591 ast_seekstream(fs, 0, SEEK_END);
592 max_length = ast_tellstream(fs);
593 ast_seekstream(fs, sample_offset, SEEK_SET);
594 res = ast_applystream(chan, fs);
595 if (vfs)
596 vres = ast_applystream(chan, vfs);
597 ast_playstream(fs);
598 if (vfs)
599 ast_playstream(vfs);
601 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
602 /* this is to check for if ast_waitstream closed the stream, we probably are at
603 * the end of the stream, return that amount, else check for the amount */
604 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
605 ast_stopstream(chan);
606 if (res == 1) {
607 /* Stop this command, don't print a result line, as there is a new command */
608 return RESULT_SUCCESS;
610 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
611 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
614 /* get option - really similar to the handle_streamfile, but with a timeout */
615 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
617 int res;
618 int vres;
619 struct ast_filestream *fs;
620 struct ast_filestream *vfs;
621 long sample_offset = 0;
622 long max_length;
623 int timeout = 0;
624 char *edigits = "";
626 if ( argc < 4 || argc > 5 )
627 return RESULT_SHOWUSAGE;
629 if ( argv[3] )
630 edigits = argv[3];
632 if ( argc == 5 )
633 timeout = atoi(argv[4]);
634 else if (chan->pbx->dtimeout) {
635 /* by default dtimeout is set to 5sec */
636 timeout = chan->pbx->dtimeout * 1000; /* in msec */
639 fs = ast_openstream(chan, argv[2], chan->language);
640 if (!fs) {
641 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
642 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
643 return RESULT_SUCCESS;
645 vfs = ast_openvstream(chan, argv[2], chan->language);
646 if (vfs)
647 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
649 if (option_verbose > 2)
650 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
652 ast_seekstream(fs, 0, SEEK_END);
653 max_length = ast_tellstream(fs);
654 ast_seekstream(fs, sample_offset, SEEK_SET);
655 res = ast_applystream(chan, fs);
656 if (vfs)
657 vres = ast_applystream(chan, vfs);
658 ast_playstream(fs);
659 if (vfs)
660 ast_playstream(vfs);
662 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
663 /* this is to check for if ast_waitstream closed the stream, we probably are at
664 * the end of the stream, return that amount, else check for the amount */
665 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
666 ast_stopstream(chan);
667 if (res == 1) {
668 /* Stop this command, don't print a result line, as there is a new command */
669 return RESULT_SUCCESS;
672 /* If the user didnt press a key, wait for digitTimeout*/
673 if (res == 0 ) {
674 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
675 /* Make sure the new result is in the escape digits of the GET OPTION */
676 if ( !strchr(edigits,res) )
677 res=0;
680 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
681 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
687 /*--- handle_saynumber: Say number in various language syntaxes ---*/
688 /* Need to add option for gender here as well. Coders wanted */
689 /* While waiting, we're sending a (char *) NULL. */
690 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
692 int res;
693 int num;
694 if (argc != 4)
695 return RESULT_SHOWUSAGE;
696 if (sscanf(argv[2], "%d", &num) != 1)
697 return RESULT_SHOWUSAGE;
698 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
699 if (res == 1)
700 return RESULT_SUCCESS;
701 fdprintf(agi->fd, "200 result=%d\n", res);
702 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
705 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
707 int res;
708 int num;
710 if (argc != 4)
711 return RESULT_SHOWUSAGE;
712 if (sscanf(argv[2], "%d", &num) != 1)
713 return RESULT_SHOWUSAGE;
715 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
716 if (res == 1) /* New command */
717 return RESULT_SUCCESS;
718 fdprintf(agi->fd, "200 result=%d\n", res);
719 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
722 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
724 int res;
726 if (argc != 4)
727 return RESULT_SHOWUSAGE;
729 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
730 if (res == 1) /* New command */
731 return RESULT_SUCCESS;
732 fdprintf(agi->fd, "200 result=%d\n", res);
733 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
736 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
738 int res;
739 int num;
740 if (argc != 4)
741 return RESULT_SHOWUSAGE;
742 if (sscanf(argv[2], "%d", &num) != 1)
743 return RESULT_SHOWUSAGE;
744 res = ast_say_date(chan, num, argv[3], chan->language);
745 if (res == 1)
746 return RESULT_SUCCESS;
747 fdprintf(agi->fd, "200 result=%d\n", res);
748 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
751 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
753 int res;
754 int num;
755 if (argc != 4)
756 return RESULT_SHOWUSAGE;
757 if (sscanf(argv[2], "%d", &num) != 1)
758 return RESULT_SHOWUSAGE;
759 res = ast_say_time(chan, num, argv[3], chan->language);
760 if (res == 1)
761 return RESULT_SUCCESS;
762 fdprintf(agi->fd, "200 result=%d\n", res);
763 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
766 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
768 int res=0;
769 time_t unixtime;
770 char *format, *zone=NULL;
772 if (argc < 4)
773 return RESULT_SHOWUSAGE;
775 if (argc > 4) {
776 format = argv[4];
777 } else {
778 /* XXX this doesn't belong here, but in the 'say' module */
779 if (!strcasecmp(chan->language, "de")) {
780 format = "A dBY HMS";
781 } else {
782 format = "ABdY 'digits/at' IMp";
786 if (argc > 5 && !ast_strlen_zero(argv[5]))
787 zone = argv[5];
789 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
790 return RESULT_SHOWUSAGE;
792 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
793 if (res == 1)
794 return RESULT_SUCCESS;
796 fdprintf(agi->fd, "200 result=%d\n", res);
797 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
800 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
802 int res;
804 if (argc != 4)
805 return RESULT_SHOWUSAGE;
807 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
808 if (res == 1) /* New command */
809 return RESULT_SUCCESS;
810 fdprintf(agi->fd, "200 result=%d\n", res);
811 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
814 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
816 int res;
817 char data[1024];
818 int max;
819 int timeout;
821 if (argc < 3)
822 return RESULT_SHOWUSAGE;
823 if (argc >= 4)
824 timeout = atoi(argv[3]);
825 else
826 timeout = 0;
827 if (argc >= 5)
828 max = atoi(argv[4]);
829 else
830 max = 1024;
831 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
832 if (res == 2) /* New command */
833 return RESULT_SUCCESS;
834 else if (res == 1)
835 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
836 else if (res < 0 )
837 fdprintf(agi->fd, "200 result=-1\n");
838 else
839 fdprintf(agi->fd, "200 result=%s\n", data);
840 return RESULT_SUCCESS;
843 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
846 if (argc != 3)
847 return RESULT_SHOWUSAGE;
848 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
849 fdprintf(agi->fd, "200 result=0\n");
850 return RESULT_SUCCESS;
853 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
855 if (argc != 3)
856 return RESULT_SHOWUSAGE;
857 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
858 fdprintf(agi->fd, "200 result=0\n");
859 return RESULT_SUCCESS;
862 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
864 int pri;
865 if (argc != 3)
866 return RESULT_SHOWUSAGE;
868 if (sscanf(argv[2], "%d", &pri) != 1) {
869 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
870 return RESULT_SHOWUSAGE;
873 ast_explicit_goto(chan, NULL, NULL, pri);
874 fdprintf(agi->fd, "200 result=0\n");
875 return RESULT_SUCCESS;
878 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
880 struct ast_filestream *fs;
881 struct ast_frame *f;
882 struct timeval start;
883 long sample_offset = 0;
884 int res = 0;
885 int ms;
887 struct ast_dsp *sildet=NULL; /* silence detector dsp */
888 int totalsilence = 0;
889 int dspsilence = 0;
890 int silence = 0; /* amount of silence to allow */
891 int gotsilence = 0; /* did we timeout for silence? */
892 char *silencestr=NULL;
893 int rfmt=0;
896 /* XXX EAGI FIXME XXX */
898 if (argc < 6)
899 return RESULT_SHOWUSAGE;
900 if (sscanf(argv[5], "%d", &ms) != 1)
901 return RESULT_SHOWUSAGE;
903 if (argc > 6)
904 silencestr = strchr(argv[6],'s');
905 if ((argc > 7) && (!silencestr))
906 silencestr = strchr(argv[7],'s');
907 if ((argc > 8) && (!silencestr))
908 silencestr = strchr(argv[8],'s');
910 if (silencestr) {
911 if (strlen(silencestr) > 2) {
912 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
913 silencestr++;
914 silencestr++;
915 if (silencestr)
916 silence = atoi(silencestr);
917 if (silence > 0)
918 silence *= 1000;
923 if (silence > 0) {
924 rfmt = chan->readformat;
925 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
926 if (res < 0) {
927 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
928 return -1;
930 sildet = ast_dsp_new();
931 if (!sildet) {
932 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
933 return -1;
935 ast_dsp_set_threshold(sildet, 256);
938 /* backward compatibility, if no offset given, arg[6] would have been
939 * caught below and taken to be a beep, else if it is a digit then it is a
940 * offset */
941 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
942 res = ast_streamfile(chan, "beep", chan->language);
944 if ((argc > 7) && (!strchr(argv[7], '=')))
945 res = ast_streamfile(chan, "beep", chan->language);
947 if (!res)
948 res = ast_waitstream(chan, argv[4]);
949 if (res) {
950 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
951 } else {
952 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
953 if (!fs) {
954 res = -1;
955 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
956 if (sildet)
957 ast_dsp_free(sildet);
958 return RESULT_FAILURE;
961 /* Request a video update */
962 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
964 chan->stream = fs;
965 ast_applystream(chan,fs);
966 /* really should have checks */
967 ast_seekstream(fs, sample_offset, SEEK_SET);
968 ast_truncstream(fs);
970 start = ast_tvnow();
971 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
972 res = ast_waitfor(chan, -1);
973 if (res < 0) {
974 ast_closestream(fs);
975 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
976 if (sildet)
977 ast_dsp_free(sildet);
978 return RESULT_FAILURE;
980 f = ast_read(chan);
981 if (!f) {
982 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
983 ast_closestream(fs);
984 if (sildet)
985 ast_dsp_free(sildet);
986 return RESULT_FAILURE;
988 switch(f->frametype) {
989 case AST_FRAME_DTMF:
990 if (strchr(argv[4], f->subclass)) {
991 /* This is an interrupting chracter, so rewind to chop off any small
992 amount of DTMF that may have been recorded
994 ast_stream_rewind(fs, 200);
995 ast_truncstream(fs);
996 sample_offset = ast_tellstream(fs);
997 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
998 ast_closestream(fs);
999 ast_frfree(f);
1000 if (sildet)
1001 ast_dsp_free(sildet);
1002 return RESULT_SUCCESS;
1004 break;
1005 case AST_FRAME_VOICE:
1006 ast_writestream(fs, f);
1007 /* this is a safe place to check progress since we know that fs
1008 * is valid after a write, and it will then have our current
1009 * location */
1010 sample_offset = ast_tellstream(fs);
1011 if (silence > 0) {
1012 dspsilence = 0;
1013 ast_dsp_silence(sildet, f, &dspsilence);
1014 if (dspsilence) {
1015 totalsilence = dspsilence;
1016 } else {
1017 totalsilence = 0;
1019 if (totalsilence > silence) {
1020 /* Ended happily with silence */
1021 gotsilence = 1;
1022 break;
1025 break;
1026 case AST_FRAME_VIDEO:
1027 ast_writestream(fs, f);
1028 default:
1029 /* Ignore all other frames */
1030 break;
1032 ast_frfree(f);
1033 if (gotsilence)
1034 break;
1037 if (gotsilence) {
1038 ast_stream_rewind(fs, silence-1000);
1039 ast_truncstream(fs);
1040 sample_offset = ast_tellstream(fs);
1042 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1043 ast_closestream(fs);
1046 if (silence > 0) {
1047 res = ast_set_read_format(chan, rfmt);
1048 if (res)
1049 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1050 ast_dsp_free(sildet);
1052 return RESULT_SUCCESS;
1055 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1057 int timeout;
1059 if (argc != 3)
1060 return RESULT_SHOWUSAGE;
1061 if (sscanf(argv[2], "%d", &timeout) != 1)
1062 return RESULT_SHOWUSAGE;
1063 if (timeout < 0)
1064 timeout = 0;
1065 if (timeout)
1066 chan->whentohangup = time(NULL) + timeout;
1067 else
1068 chan->whentohangup = 0;
1069 fdprintf(agi->fd, "200 result=0\n");
1070 return RESULT_SUCCESS;
1073 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1075 struct ast_channel *c;
1076 if (argc == 1) {
1077 /* no argument: hangup the current channel */
1078 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1079 fdprintf(agi->fd, "200 result=1\n");
1080 return RESULT_SUCCESS;
1081 } else if (argc == 2) {
1082 /* one argument: look for info on the specified channel */
1083 c = ast_get_channel_by_name_locked(argv[1]);
1084 if (c) {
1085 /* we have a matching channel */
1086 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1087 fdprintf(agi->fd, "200 result=1\n");
1088 ast_channel_unlock(c);
1089 return RESULT_SUCCESS;
1091 /* if we get this far no channel name matched the argument given */
1092 fdprintf(agi->fd, "200 result=-1\n");
1093 return RESULT_SUCCESS;
1094 } else {
1095 return RESULT_SHOWUSAGE;
1099 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1101 int res;
1102 struct ast_app *app;
1104 if (argc < 2)
1105 return RESULT_SHOWUSAGE;
1107 if (option_verbose > 2)
1108 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1110 app = pbx_findapp(argv[1]);
1112 if (app) {
1113 res = pbx_exec(chan, app, argv[2]);
1114 } else {
1115 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1116 res = -2;
1118 fdprintf(agi->fd, "200 result=%d\n", res);
1120 /* Even though this is wrong, users are depending upon this result. */
1121 return res;
1124 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1126 char tmp[256]="";
1127 char *l = NULL, *n = NULL;
1129 if (argv[2]) {
1130 ast_copy_string(tmp, argv[2], sizeof(tmp));
1131 ast_callerid_parse(tmp, &n, &l);
1132 if (l)
1133 ast_shrink_phone_number(l);
1134 else
1135 l = "";
1136 if (!n)
1137 n = "";
1138 ast_set_callerid(chan, l, n, NULL);
1141 fdprintf(agi->fd, "200 result=1\n");
1142 return RESULT_SUCCESS;
1145 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1147 struct ast_channel *c;
1148 if (argc == 2) {
1149 /* no argument: supply info on the current channel */
1150 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
1151 return RESULT_SUCCESS;
1152 } else if (argc == 3) {
1153 /* one argument: look for info on the specified channel */
1154 c = ast_get_channel_by_name_locked(argv[2]);
1155 if (c) {
1156 fdprintf(agi->fd, "200 result=%d\n", c->_state);
1157 ast_channel_unlock(c);
1158 return RESULT_SUCCESS;
1160 /* if we get this far no channel name matched the argument given */
1161 fdprintf(agi->fd, "200 result=-1\n");
1162 return RESULT_SUCCESS;
1163 } else {
1164 return RESULT_SHOWUSAGE;
1168 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1170 if (argv[3])
1171 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1173 fdprintf(agi->fd, "200 result=1\n");
1174 return RESULT_SUCCESS;
1177 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1179 char *ret;
1180 char tempstr[1024];
1182 if (argc != 3)
1183 return RESULT_SHOWUSAGE;
1185 /* check if we want to execute an ast_custom_function */
1186 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1187 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1188 } else {
1189 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1192 if (ret)
1193 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
1194 else
1195 fdprintf(agi->fd, "200 result=0\n");
1197 return RESULT_SUCCESS;
1200 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1202 char tmp[4096] = "";
1203 struct ast_channel *chan2=NULL;
1205 if ((argc != 4) && (argc != 5))
1206 return RESULT_SHOWUSAGE;
1207 if (argc == 5) {
1208 chan2 = ast_get_channel_by_name_locked(argv[4]);
1209 } else {
1210 chan2 = chan;
1212 if (chan2) {
1213 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1214 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1215 } else {
1216 fdprintf(agi->fd, "200 result=0\n");
1218 if (chan2 && (chan2 != chan))
1219 ast_channel_unlock(chan2);
1220 return RESULT_SUCCESS;
1223 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1225 int level = 0;
1226 char *prefix;
1228 if (argc < 2)
1229 return RESULT_SHOWUSAGE;
1231 if (argv[2])
1232 sscanf(argv[2], "%d", &level);
1234 switch (level) {
1235 case 4:
1236 prefix = VERBOSE_PREFIX_4;
1237 break;
1238 case 3:
1239 prefix = VERBOSE_PREFIX_3;
1240 break;
1241 case 2:
1242 prefix = VERBOSE_PREFIX_2;
1243 break;
1244 case 1:
1245 default:
1246 prefix = VERBOSE_PREFIX_1;
1247 break;
1250 if (level <= option_verbose)
1251 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1253 fdprintf(agi->fd, "200 result=1\n");
1255 return RESULT_SUCCESS;
1258 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1260 int res;
1261 char tmp[256];
1263 if (argc != 4)
1264 return RESULT_SHOWUSAGE;
1265 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1266 if (res)
1267 fdprintf(agi->fd, "200 result=0\n");
1268 else
1269 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
1271 return RESULT_SUCCESS;
1274 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1276 int res;
1278 if (argc != 5)
1279 return RESULT_SHOWUSAGE;
1280 res = ast_db_put(argv[2], argv[3], argv[4]);
1281 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1282 return RESULT_SUCCESS;
1285 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1287 int res;
1289 if (argc != 4)
1290 return RESULT_SHOWUSAGE;
1291 res = ast_db_del(argv[2], argv[3]);
1292 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1293 return RESULT_SUCCESS;
1296 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1298 int res;
1299 if ((argc < 3) || (argc > 4))
1300 return RESULT_SHOWUSAGE;
1301 if (argc == 4)
1302 res = ast_db_deltree(argv[2], argv[3]);
1303 else
1304 res = ast_db_deltree(argv[2], NULL);
1306 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1');
1307 return RESULT_SUCCESS;
1310 static char debug_usage[] =
1311 "Usage: agi debug\n"
1312 " Enables dumping of AGI transactions for debugging purposes\n";
1314 static char no_debug_usage[] =
1315 "Usage: agi debug off\n"
1316 " Disables dumping of AGI transactions for debugging purposes\n";
1318 static int agi_do_debug(int fd, int argc, char *argv[])
1320 if (argc != 2)
1321 return RESULT_SHOWUSAGE;
1322 agidebug = 1;
1323 ast_cli(fd, "AGI Debugging Enabled\n");
1324 return RESULT_SUCCESS;
1327 static int agi_no_debug_deprecated(int fd, int argc, char *argv[])
1329 if (argc != 3)
1330 return RESULT_SHOWUSAGE;
1331 agidebug = 0;
1332 ast_cli(fd, "AGI Debugging Disabled\n");
1333 return RESULT_SUCCESS;
1336 static int agi_no_debug(int fd, int argc, char *argv[])
1338 if (argc != 3)
1339 return RESULT_SHOWUSAGE;
1340 agidebug = 0;
1341 ast_cli(fd, "AGI Debugging Disabled\n");
1342 return RESULT_SUCCESS;
1345 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1347 fdprintf(agi->fd, "200 result=0\n");
1348 return RESULT_SUCCESS;
1351 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1353 if (!strncasecmp(argv[2], "on", 2))
1354 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1355 else if (!strncasecmp(argv[2], "off", 3))
1356 ast_moh_stop(chan);
1357 fdprintf(agi->fd, "200 result=0\n");
1358 return RESULT_SUCCESS;
1361 static char usage_setmusic[] =
1362 " Usage: SET MUSIC ON <on|off> <class>\n"
1363 " Enables/Disables the music on hold generator. If <class> is\n"
1364 " not specified, then the default music on hold class will be used.\n"
1365 " Always returns 0.\n";
1367 static char usage_dbput[] =
1368 " Usage: DATABASE PUT <family> <key> <value>\n"
1369 " Adds or updates an entry in the Asterisk database for a\n"
1370 " given family, key, and value.\n"
1371 " Returns 1 if successful, 0 otherwise.\n";
1373 static char usage_dbget[] =
1374 " Usage: DATABASE GET <family> <key>\n"
1375 " Retrieves an entry in the Asterisk database for a\n"
1376 " given family and key.\n"
1377 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
1378 " is set and returns the variable in parentheses.\n"
1379 " Example return code: 200 result=1 (testvariable)\n";
1381 static char usage_dbdel[] =
1382 " Usage: DATABASE DEL <family> <key>\n"
1383 " Deletes an entry in the Asterisk database for a\n"
1384 " given family and key.\n"
1385 " Returns 1 if successful, 0 otherwise.\n";
1387 static char usage_dbdeltree[] =
1388 " Usage: DATABASE DELTREE <family> [keytree]\n"
1389 " Deletes a family or specific keytree within a family\n"
1390 " in the Asterisk database.\n"
1391 " Returns 1 if successful, 0 otherwise.\n";
1393 static char usage_verbose[] =
1394 " Usage: VERBOSE <message> <level>\n"
1395 " Sends <message> to the console via verbose message system.\n"
1396 " <level> is the the verbose level (1-4)\n"
1397 " Always returns 1.\n";
1399 static char usage_getvariable[] =
1400 " Usage: GET VARIABLE <variablename>\n"
1401 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
1402 " is set and returns the variable in parentheses.\n"
1403 " example return code: 200 result=1 (testvariable)\n";
1405 static char usage_getvariablefull[] =
1406 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
1407 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
1408 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
1409 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
1410 " example return code: 200 result=1 (testvariable)\n";
1412 static char usage_setvariable[] =
1413 " Usage: SET VARIABLE <variablename> <value>\n";
1415 static char usage_channelstatus[] =
1416 " Usage: CHANNEL STATUS [<channelname>]\n"
1417 " Returns the status of the specified channel.\n"
1418 " If no channel name is given the returns the status of the\n"
1419 " current channel. Return values:\n"
1420 " 0 Channel is down and available\n"
1421 " 1 Channel is down, but reserved\n"
1422 " 2 Channel is off hook\n"
1423 " 3 Digits (or equivalent) have been dialed\n"
1424 " 4 Line is ringing\n"
1425 " 5 Remote end is ringing\n"
1426 " 6 Line is up\n"
1427 " 7 Line is busy\n";
1429 static char usage_setcallerid[] =
1430 " Usage: SET CALLERID <number>\n"
1431 " Changes the callerid of the current channel.\n";
1433 static char usage_exec[] =
1434 " Usage: EXEC <application> <options>\n"
1435 " Executes <application> with given <options>.\n"
1436 " Returns whatever the application returns, or -2 on failure to find application\n";
1438 static char usage_hangup[] =
1439 " Usage: HANGUP [<channelname>]\n"
1440 " Hangs up the specified channel.\n"
1441 " If no channel name is given, hangs up the current channel\n";
1443 static char usage_answer[] =
1444 " Usage: ANSWER\n"
1445 " Answers channel if not already in answer state. Returns -1 on\n"
1446 " channel failure, or 0 if successful.\n";
1448 static char usage_waitfordigit[] =
1449 " Usage: WAIT FOR DIGIT <timeout>\n"
1450 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
1451 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
1452 " the numerical value of the ascii of the digit if one is received. Use -1\n"
1453 " for the timeout value if you desire the call to block indefinitely.\n";
1455 static char usage_sendtext[] =
1456 " Usage: SEND TEXT \"<text to send>\"\n"
1457 " Sends the given text on a channel. Most channels do not support the\n"
1458 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
1459 " support text transmission. Returns -1 only on error/hangup. Text\n"
1460 " consisting of greater than one word should be placed in quotes since the\n"
1461 " command only accepts a single argument.\n";
1463 static char usage_recvchar[] =
1464 " Usage: RECEIVE CHAR <timeout>\n"
1465 " Receives a character of text on a channel. Specify timeout to be the\n"
1466 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1467 " do not support the reception of text. Returns the decimal value of the character\n"
1468 " if one is received, or 0 if the channel does not support text reception. Returns\n"
1469 " -1 only on error/hangup.\n";
1471 static char usage_recvtext[] =
1472 " Usage: RECEIVE TEXT <timeout>\n"
1473 " Receives a string of text on a channel. Specify timeout to be the\n"
1474 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
1475 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
1477 static char usage_tddmode[] =
1478 " Usage: TDD MODE <on|off>\n"
1479 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
1480 " successful, or 0 if channel is not TDD-capable.\n";
1482 static char usage_sendimage[] =
1483 " Usage: SEND IMAGE <image>\n"
1484 " Sends the given image on a channel. Most channels do not support the\n"
1485 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
1486 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1487 " should not include extensions.\n";
1489 static char usage_streamfile[] =
1490 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1491 " Send the given file, allowing playback to be interrupted by the given\n"
1492 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1493 " permitted. If sample offset is provided then the audio will seek to sample\n"
1494 " offset before play starts. Returns 0 if playback completes without a digit\n"
1495 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1496 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1497 " extension must not be included in the filename.\n";
1499 static char usage_controlstreamfile[] =
1500 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
1501 " Send the given file, allowing playback to be controled by the given\n"
1502 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1503 " permitted. Returns 0 if playback completes without a digit\n"
1504 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1505 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1506 " extension must not be included in the filename.\n\n"
1507 " Note: ffchar and rewchar default to * and # respectively.\n";
1509 static char usage_getoption[] =
1510 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
1511 " Behaves similar to STREAM FILE but used with a timeout option.\n";
1513 static char usage_saynumber[] =
1514 " Usage: SAY NUMBER <number> <escape digits>\n"
1515 " Say a given number, returning early if any of the given DTMF digits\n"
1516 " are received on the channel. Returns 0 if playback completes without a digit\n"
1517 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1518 " -1 on error/hangup.\n";
1520 static char usage_saydigits[] =
1521 " Usage: SAY DIGITS <number> <escape digits>\n"
1522 " Say a given digit string, returning early if any of the given DTMF digits\n"
1523 " are received on the channel. Returns 0 if playback completes without a digit\n"
1524 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1525 " -1 on error/hangup.\n";
1527 static char usage_sayalpha[] =
1528 " Usage: SAY ALPHA <number> <escape digits>\n"
1529 " Say a given character string, returning early if any of the given DTMF digits\n"
1530 " are received on the channel. Returns 0 if playback completes without a digit\n"
1531 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1532 " -1 on error/hangup.\n";
1534 static char usage_saydate[] =
1535 " Usage: SAY DATE <date> <escape digits>\n"
1536 " Say a given date, returning early if any of the given DTMF digits are\n"
1537 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
1538 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1539 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1540 " digit if one was pressed or -1 on error/hangup.\n";
1542 static char usage_saytime[] =
1543 " Usage: SAY TIME <time> <escape digits>\n"
1544 " Say a given time, returning early if any of the given DTMF digits are\n"
1545 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1546 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1547 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1548 " digit if one was pressed or -1 on error/hangup.\n";
1550 static char usage_saydatetime[] =
1551 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
1552 " Say a given time, returning early if any of the given DTMF digits are\n"
1553 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1554 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
1555 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
1556 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
1557 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
1558 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1559 " digit if one was pressed or -1 on error/hangup.\n";
1561 static char usage_sayphonetic[] =
1562 " Usage: SAY PHONETIC <string> <escape digits>\n"
1563 " Say a given character string with phonetics, returning early if any of the\n"
1564 " given DTMF digits are received on the channel. Returns 0 if playback\n"
1565 " completes without a digit pressed, the ASCII numerical value of the digit\n"
1566 " if one was pressed, or -1 on error/hangup.\n";
1568 static char usage_getdata[] =
1569 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1570 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
1571 "from the channel at the other end.\n";
1573 static char usage_setcontext[] =
1574 " Usage: SET CONTEXT <desired context>\n"
1575 " Sets the context for continuation upon exiting the application.\n";
1577 static char usage_setextension[] =
1578 " Usage: SET EXTENSION <new extension>\n"
1579 " Changes the extension for continuation upon exiting the application.\n";
1581 static char usage_setpriority[] =
1582 " Usage: SET PRIORITY <priority>\n"
1583 " Changes the priority for continuation upon exiting the application.\n"
1584 " The priority must be a valid priority or label.\n";
1586 static char usage_recordfile[] =
1587 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
1588 " [offset samples] [BEEP] [s=silence]\n"
1589 " Record to a file until a given dtmf digit in the sequence is received\n"
1590 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1591 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1592 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
1593 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
1594 " of seconds of silence allowed before the function returns despite the\n"
1595 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1596 " preceeded by \"s=\" and is also optional.\n";
1598 static char usage_autohangup[] =
1599 " Usage: SET AUTOHANGUP <time>\n"
1600 " Cause the channel to automatically hangup at <time> seconds in the\n"
1601 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
1602 " cause the autohangup feature to be disabled on this channel.\n";
1604 static char usage_noop[] =
1605 " Usage: NoOp\n"
1606 " Does nothing.\n";
1608 static agi_command commands[MAX_COMMANDS] = {
1609 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
1610 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1611 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1612 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1613 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1614 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1615 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1616 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
1617 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
1618 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
1619 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1620 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1621 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1622 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
1623 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
1624 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1625 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
1626 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1627 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1628 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
1629 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
1630 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1631 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
1632 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1633 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1634 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1635 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1636 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1637 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1638 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
1639 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
1640 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1641 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1642 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
1643 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
1644 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1645 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1648 static int help_workhorse(int fd, char *match[])
1650 char fullcmd[80];
1651 char matchstr[80];
1652 int x;
1653 struct agi_command *e;
1654 if (match)
1655 ast_join(matchstr, sizeof(matchstr), match);
1656 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1657 e = &commands[x];
1658 if (!e->cmda[0])
1659 break;
1660 /* Hide commands that start with '_' */
1661 if ((e->cmda[0])[0] == '_')
1662 continue;
1663 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
1664 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
1665 continue;
1666 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1668 return 0;
1671 int ast_agi_register(agi_command *agi)
1673 int x;
1674 for (x=0; x<MAX_COMMANDS - 1; x++) {
1675 if (commands[x].cmda[0] == agi->cmda[0]) {
1676 ast_log(LOG_WARNING, "Command already registered!\n");
1677 return -1;
1680 for (x=0; x<MAX_COMMANDS - 1; x++) {
1681 if (!commands[x].cmda[0]) {
1682 commands[x] = *agi;
1683 return 0;
1686 ast_log(LOG_WARNING, "No more room for new commands!\n");
1687 return -1;
1690 void ast_agi_unregister(agi_command *agi)
1692 int x;
1693 for (x=0; x<MAX_COMMANDS - 1; x++) {
1694 if (commands[x].cmda[0] == agi->cmda[0]) {
1695 memset(&commands[x], 0, sizeof(agi_command));
1700 static agi_command *find_command(char *cmds[], int exact)
1702 int x;
1703 int y;
1704 int match;
1706 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
1707 if (!commands[x].cmda[0])
1708 break;
1709 /* start optimistic */
1710 match = 1;
1711 for (y=0; match && cmds[y]; y++) {
1712 /* If there are no more words in the command (and we're looking for
1713 an exact match) or there is a difference between the two words,
1714 then this is not a match */
1715 if (!commands[x].cmda[y] && !exact)
1716 break;
1717 /* don't segfault if the next part of a command doesn't exist */
1718 if (!commands[x].cmda[y])
1719 return NULL;
1720 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1721 match = 0;
1723 /* If more words are needed to complete the command then this is not
1724 a candidate (unless we're looking for a really inexact answer */
1725 if ((exact > -1) && commands[x].cmda[y])
1726 match = 0;
1727 if (match)
1728 return &commands[x];
1730 return NULL;
1734 static int parse_args(char *s, int *max, char *argv[])
1736 int x=0;
1737 int quoted=0;
1738 int escaped=0;
1739 int whitespace=1;
1740 char *cur;
1742 cur = s;
1743 while(*s) {
1744 switch(*s) {
1745 case '"':
1746 /* If it's escaped, put a literal quote */
1747 if (escaped)
1748 goto normal;
1749 else
1750 quoted = !quoted;
1751 if (quoted && whitespace) {
1752 /* If we're starting a quote, coming off white space start a new word, too */
1753 argv[x++] = cur;
1754 whitespace=0;
1756 escaped = 0;
1757 break;
1758 case ' ':
1759 case '\t':
1760 if (!quoted && !escaped) {
1761 /* If we're not quoted, mark this as whitespace, and
1762 end the previous argument */
1763 whitespace = 1;
1764 *(cur++) = '\0';
1765 } else
1766 /* Otherwise, just treat it as anything else */
1767 goto normal;
1768 break;
1769 case '\\':
1770 /* If we're escaped, print a literal, otherwise enable escaping */
1771 if (escaped) {
1772 goto normal;
1773 } else {
1774 escaped=1;
1776 break;
1777 default:
1778 normal:
1779 if (whitespace) {
1780 if (x >= MAX_ARGS -1) {
1781 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1782 break;
1784 /* Coming off of whitespace, start the next argument */
1785 argv[x++] = cur;
1786 whitespace=0;
1788 *(cur++) = *s;
1789 escaped=0;
1791 s++;
1793 /* Null terminate */
1794 *(cur++) = '\0';
1795 argv[x] = NULL;
1796 *max = x;
1797 return 0;
1800 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1802 char *argv[MAX_ARGS];
1803 int argc = MAX_ARGS;
1804 int res;
1805 agi_command *c;
1807 parse_args(buf, &argc, argv);
1808 c = find_command(argv, 0);
1809 if (c) {
1810 res = c->handler(chan, agi, argc, argv);
1811 switch(res) {
1812 case RESULT_SHOWUSAGE:
1813 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1814 fdprintf(agi->fd, c->usage);
1815 fdprintf(agi->fd, "520 End of proper usage.\n");
1816 break;
1817 case AST_PBX_KEEPALIVE:
1818 /* We've been asked to keep alive, so do so */
1819 return AST_PBX_KEEPALIVE;
1820 break;
1821 case RESULT_FAILURE:
1822 /* They've already given the failure. We've been hung up on so handle this
1823 appropriately */
1824 return -1;
1826 } else {
1827 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1829 return 0;
1831 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead)
1833 struct ast_channel *c;
1834 int outfd;
1835 int ms;
1836 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1837 struct ast_frame *f;
1838 char buf[AGI_BUF_LEN];
1839 char *res = NULL;
1840 FILE *readf;
1841 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1842 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1843 int retry = AGI_NANDFS_RETRY;
1845 if (!(readf = fdopen(agi->ctrl, "r"))) {
1846 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1847 if (pid > -1)
1848 kill(pid, SIGHUP);
1849 close(agi->ctrl);
1850 return AGI_RESULT_FAILURE;
1852 setlinebuf(readf);
1853 setup_env(chan, request, agi->fd, (agi->audio > -1));
1854 for (;;) {
1855 ms = -1;
1856 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1857 if (c) {
1858 retry = AGI_NANDFS_RETRY;
1859 /* Idle the channel until we get a command */
1860 f = ast_read(c);
1861 if (!f) {
1862 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1863 returnstatus = AGI_RESULT_HANGUP;
1864 break;
1865 } else {
1866 /* If it's voice, write it to the audio pipe */
1867 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1868 /* Write, ignoring errors */
1869 write(agi->audio, f->data, f->datalen);
1871 ast_frfree(f);
1873 } else if (outfd > -1) {
1874 size_t len = sizeof(buf);
1875 size_t buflen = 0;
1877 retry = AGI_NANDFS_RETRY;
1878 buf[0] = '\0';
1880 while (buflen < (len - 1)) {
1881 res = fgets(buf + buflen, len, readf);
1882 if (feof(readf))
1883 break;
1884 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
1885 break;
1886 if (res != NULL && !agi->fast)
1887 break;
1888 buflen = strlen(buf);
1889 if (buflen && buf[buflen - 1] == '\n')
1890 break;
1891 len -= buflen;
1892 if (agidebug)
1893 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
1896 if (!buf[0]) {
1897 /* Program terminated */
1898 if (returnstatus)
1899 returnstatus = -1;
1900 if (option_verbose > 2)
1901 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1902 if (pid > 0)
1903 waitpid(pid, status, 0);
1904 /* No need to kill the pid anymore, since they closed us */
1905 pid = -1;
1906 break;
1909 /* Special case for inability to execute child process */
1910 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
1911 returnstatus = AGI_RESULT_FAILURE;
1912 break;
1915 /* get rid of trailing newline, if any */
1916 if (*buf && buf[strlen(buf) - 1] == '\n')
1917 buf[strlen(buf) - 1] = 0;
1918 if (agidebug)
1919 ast_verbose("AGI Rx << %s\n", buf);
1920 returnstatus |= agi_handle_command(chan, agi, buf);
1921 /* If the handle_command returns -1, we need to stop */
1922 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1923 break;
1925 } else {
1926 if (--retry <= 0) {
1927 ast_log(LOG_WARNING, "No channel, no fd?\n");
1928 returnstatus = AGI_RESULT_FAILURE;
1929 break;
1933 /* Notify process */
1934 if (pid > -1) {
1935 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
1936 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
1937 if (kill(pid, SIGHUP)) {
1938 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
1939 } else { /* Give the process a chance to die */
1940 usleep(1);
1943 waitpid(pid, status, WNOHANG);
1945 fclose(readf);
1946 return returnstatus;
1949 static int handle_showagi(int fd, int argc, char *argv[])
1951 struct agi_command *e;
1952 char fullcmd[80];
1953 if ((argc < 2))
1954 return RESULT_SHOWUSAGE;
1955 if (argc > 2) {
1956 e = find_command(argv + 2, 1);
1957 if (e)
1958 ast_cli(fd, e->usage);
1959 else {
1960 if (find_command(argv + 2, -1)) {
1961 return help_workhorse(fd, argv + 1);
1962 } else {
1963 ast_join(fullcmd, sizeof(fullcmd), argv+1);
1964 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1967 } else {
1968 return help_workhorse(fd, NULL);
1970 return RESULT_SUCCESS;
1973 static int handle_agidumphtml(int fd, int argc, char *argv[])
1975 struct agi_command *e;
1976 char fullcmd[80];
1977 int x;
1978 FILE *htmlfile;
1980 if ((argc < 3))
1981 return RESULT_SHOWUSAGE;
1983 if (!(htmlfile = fopen(argv[2], "wt"))) {
1984 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1985 return RESULT_SHOWUSAGE;
1988 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1989 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1992 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1994 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1995 char *stringp, *tempstr;
1997 e = &commands[x];
1998 if (!e->cmda[0]) /* end ? */
1999 break;
2000 /* Hide commands that start with '_' */
2001 if ((e->cmda[0])[0] == '_')
2002 continue;
2003 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2005 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2006 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary);
2008 stringp=e->usage;
2009 tempstr = strsep(&stringp, "\n");
2011 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
2013 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2014 while ((tempstr = strsep(&stringp, "\n")) != NULL)
2015 fprintf(htmlfile, "%s<BR>\n",tempstr);
2016 fprintf(htmlfile, "</TD></TR>\n");
2017 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2021 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2022 fclose(htmlfile);
2023 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
2024 return RESULT_SUCCESS;
2027 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2029 enum agi_result res;
2030 struct ast_module_user *u;
2031 char *argv[MAX_ARGS];
2032 char buf[AGI_BUF_LEN] = "";
2033 char *tmp = (char *)buf;
2034 int argc = 0;
2035 int fds[2];
2036 int efd = -1;
2037 int pid;
2038 char *stringp;
2039 AGI agi;
2041 if (ast_strlen_zero(data)) {
2042 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2043 return -1;
2045 ast_copy_string(buf, data, sizeof(buf));
2047 memset(&agi, 0, sizeof(agi));
2048 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1)
2049 argv[argc++] = stringp;
2050 argv[argc] = NULL;
2052 u = ast_module_user_add(chan);
2053 #if 0
2054 /* Answer if need be */
2055 if (chan->_state != AST_STATE_UP) {
2056 if (ast_answer(chan)) {
2057 LOCAL_USER_REMOVE(u);
2058 return -1;
2061 #endif
2062 ast_replace_sigchld();
2063 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
2064 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2065 int status = 0;
2066 agi.fd = fds[1];
2067 agi.ctrl = fds[0];
2068 agi.audio = efd;
2069 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2070 res = run_agi(chan, argv[0], &agi, pid, &status, dead);
2071 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2072 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2073 res = AGI_RESULT_FAILURE;
2074 if (fds[1] != fds[0])
2075 close(fds[1]);
2076 if (efd > -1)
2077 close(efd);
2079 ast_unreplace_sigchld();
2080 ast_module_user_remove(u);
2082 switch (res) {
2083 case AGI_RESULT_SUCCESS:
2084 case AGI_RESULT_SUCCESS_FAST:
2085 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2086 break;
2087 case AGI_RESULT_FAILURE:
2088 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2089 break;
2090 case AGI_RESULT_HANGUP:
2091 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2092 return -1;
2095 return 0;
2098 static int agi_exec(struct ast_channel *chan, void *data)
2100 if (chan->_softhangup)
2101 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2102 return agi_exec_full(chan, data, 0, 0);
2105 static int eagi_exec(struct ast_channel *chan, void *data)
2107 int readformat;
2108 int res;
2110 if (chan->_softhangup)
2111 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2112 readformat = chan->readformat;
2113 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2114 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2115 return -1;
2117 res = agi_exec_full(chan, data, 1, 0);
2118 if (!res) {
2119 if (ast_set_read_format(chan, readformat)) {
2120 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2123 return res;
2126 static int deadagi_exec(struct ast_channel *chan, void *data)
2128 if (!ast_check_hangup(chan))
2129 ast_log(LOG_WARNING,"Running DeadAGI on a live channel will cause problems, please use AGI\n");
2130 return agi_exec_full(chan, data, 0, 1);
2133 static char showagi_help[] =
2134 "Usage: agi show [topic]\n"
2135 " When called with a topic as an argument, displays usage\n"
2136 " information on the given command. If called without a\n"
2137 " topic, it provides a list of AGI commands.\n";
2140 static char dumpagihtml_help[] =
2141 "Usage: agi dumphtml <filename>\n"
2142 " Dumps the agi command list in html format to given filename\n";
2144 static struct ast_cli_entry cli_show_agi_deprecated = {
2145 { "show", "agi", NULL },
2146 handle_showagi, NULL,
2147 NULL };
2149 static struct ast_cli_entry cli_dump_agihtml_deprecated = {
2150 { "dump", "agihtml", NULL },
2151 handle_agidumphtml, NULL,
2152 NULL };
2154 static struct ast_cli_entry cli_agi_no_debug_deprecated = {
2155 { "agi", "no", "debug", NULL },
2156 agi_no_debug_deprecated, NULL,
2157 NULL };
2159 static struct ast_cli_entry cli_agi[] = {
2160 { { "agi", "debug", NULL },
2161 agi_do_debug, "Enable AGI debugging",
2162 debug_usage },
2164 { { "agi", "debug", "off", NULL },
2165 agi_no_debug, "Disable AGI debugging",
2166 no_debug_usage, NULL, &cli_agi_no_debug_deprecated },
2168 { { "agi", "show", NULL },
2169 handle_showagi, "List AGI commands or specific help",
2170 showagi_help, NULL, &cli_show_agi_deprecated },
2172 { { "agi", "dumphtml", NULL },
2173 handle_agidumphtml, "Dumps a list of agi commands in html format",
2174 dumpagihtml_help, NULL, &cli_dump_agihtml_deprecated },
2177 static int unload_module(void)
2179 ast_module_user_hangup_all();
2180 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2181 ast_unregister_application(eapp);
2182 ast_unregister_application(deadapp);
2183 return ast_unregister_application(app);
2186 static int load_module(void)
2188 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2189 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2190 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2191 return ast_register_application(app, agi_exec, synopsis, descrip);
2194 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2195 .load = load_module,
2196 .unload = unload_module,