2 * Asterisk -- A telephony toolkit for Linux.
4 * Asterisk Gateway Interface
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/types.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/module.h>
20 #include <asterisk/astdb.h>
31 #include <asterisk/cli.h>
32 #include <asterisk/logger.h>
33 #include <asterisk/options.h>
34 #include <asterisk/image.h>
35 #include <asterisk/say.h>
36 #include <asterisk/app.h>
37 #include <asterisk/dsp.h>
38 #include <asterisk/musiconhold.h>
39 #include "../asterisk.h"
40 #include "../astconf.h"
46 /* Recycle some stuff from the CLI interface */
47 #define fdprintf ast_cli
49 typedef struct agi_state {
50 int fd; /* FD for general output */
51 int audio; /* FD for audio output */
52 int ctrl; /* FD for input control */
55 typedef struct agi_command {
56 /* Null terminated list of the words of the command */
57 char *cmda[AST_MAX_CMD_LEN];
58 /* Handler for the command (channel, AGI state, # of arguments, argument list).
59 Returns RESULT_SHOWUSAGE for improper arguments */
60 int (*handler)(struct ast_channel *chan, AGI *agi, int argc, char *argv[]);
61 /* Summary of the command (< 60 characters) */
63 /* Detailed usage information */
67 static char *tdesc = "Asterisk Gateway Interface (AGI)";
69 static char *app = "AGI";
71 static char *eapp = "EAGI";
73 static char *deadapp = "DeadAGI";
75 static char *synopsis = "Executes an AGI compliant application";
76 static char *esynopsis = "Executes an EAGI compliant application";
77 static char *deadsynopsis = "Executes AGI on a hungup channel";
79 static char *descrip =
80 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
81 "program on a channel. AGI allows Asterisk to launch external programs\n"
82 "written in any language to control a telephony channel, play audio,\n"
83 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
85 "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
86 " hangup, or 0 on non-hangup exit. \n"
87 "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
88 "on file descriptor 3\n\n"
89 "Use the CLI command 'show agi' to list available agi commands\n";
96 #define TONE_BLOCK_SIZE 200
98 static int launch_script(char *script, char *args, int *fds, int *efd, int *opid)
107 if (script[0] != '/') {
108 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
112 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
116 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
123 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
130 res = fcntl(audio[1], F_GETFL);
132 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
134 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
146 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
150 /* Redirect stdin and out, provide enhanced audio channel if desired */
151 dup2(fromast[0], STDIN_FILENO);
152 dup2(toast[1], STDOUT_FILENO);
154 dup2(audio[0], STDERR_FILENO + 1);
156 close(STDERR_FILENO + 1);
158 /* Close everything but stdin/out/error */
159 for (x=STDERR_FILENO + 2;x<1024;x++)
162 execl(script, script, args, (char *)NULL);
163 /* Can't use ast_log since FD's are closed */
164 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
167 if (option_verbose > 2)
168 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
174 /* close what we're not using in the parent */
188 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
190 /* Print initial environment, with agi_request always being the first
192 fdprintf(fd, "agi_request: %s\n", request);
193 fdprintf(fd, "agi_channel: %s\n", chan->name);
194 fdprintf(fd, "agi_language: %s\n", chan->language);
195 fdprintf(fd, "agi_type: %s\n", chan->type);
196 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
199 fdprintf(fd, "agi_callerid: %s\n", chan->callerid ? chan->callerid : "unknown");
200 fdprintf(fd, "agi_dnid: %s\n", chan->dnid ? chan->dnid : "unknown");
201 fdprintf(fd, "agi_rdnis: %s\n", chan->rdnis ? chan->rdnis : "unknown");
203 /* Context information */
204 fdprintf(fd, "agi_context: %s\n", chan->context);
205 fdprintf(fd, "agi_extension: %s\n", chan->exten);
206 fdprintf(fd, "agi_priority: %d\n", chan->priority);
207 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
209 /* User information */
210 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
212 /* End with empty return */
216 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
220 if (chan->_state != AST_STATE_UP) {
221 /* Answer the chan */
222 res = ast_answer(chan);
224 fdprintf(agi->fd, "200 result=%d\n", res);
226 return RESULT_SUCCESS;
228 return RESULT_FAILURE;
231 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
236 return RESULT_SHOWUSAGE;
237 if (sscanf(argv[3], "%i", &to) != 1)
238 return RESULT_SHOWUSAGE;
239 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
240 fdprintf(agi->fd, "200 result=%d\n", res);
242 return RESULT_SUCCESS;
244 return RESULT_FAILURE;
247 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
251 return RESULT_SHOWUSAGE;
252 /* At the moment, the parser (perhaps broken) returns with
253 the last argument PLUS the newline at the end of the input
254 buffer. This probably needs to be fixed, but I wont do that
255 because other stuff may break as a result. The right way
256 would probably be to strip off the trailing newline before
257 parsing, then here, add a newline at the end of the string
258 before sending it to ast_sendtext --DUDE */
259 res = ast_sendtext(chan, argv[2]);
260 fdprintf(agi->fd, "200 result=%d\n", res);
262 return RESULT_SUCCESS;
264 return RESULT_FAILURE;
267 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
271 return RESULT_SHOWUSAGE;
272 res = ast_recvchar(chan,atoi(argv[2]));
274 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
275 return RESULT_SUCCESS;
278 fdprintf(agi->fd, "200 result=%d\n", res);
279 return RESULT_SUCCESS;
282 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
283 return RESULT_FAILURE;
287 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
291 return RESULT_SHOWUSAGE;
292 if (!strncasecmp(argv[2],"on",2)) x = 1; else x = 0;
293 if (!strncasecmp(argv[2],"mate",4)) x = 2;
294 if (!strncasecmp(argv[2],"tdd",3)) x = 1;
295 res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
296 fdprintf(agi->fd, "200 result=%d\n", res);
298 return RESULT_SUCCESS;
300 return RESULT_FAILURE;
303 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
307 return RESULT_SHOWUSAGE;
308 res = ast_send_image(chan, argv[2]);
309 if (!ast_check_hangup(chan))
311 fdprintf(agi->fd, "200 result=%d\n", res);
313 return RESULT_SUCCESS;
315 return RESULT_FAILURE;
318 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
321 struct ast_filestream *fs;
322 long sample_offset = 0;
326 return RESULT_SHOWUSAGE;
328 return RESULT_SHOWUSAGE;
329 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
330 return RESULT_SHOWUSAGE;
332 fs = ast_openstream(chan, argv[2], chan->language);
334 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
335 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
336 return RESULT_FAILURE;
338 ast_seekstream(fs, 0, SEEK_END);
339 max_length = ast_tellstream(fs);
340 ast_seekstream(fs, sample_offset, SEEK_SET);
341 res = ast_applystream(chan, fs);
342 res = ast_playstream(fs);
344 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
346 return RESULT_SHOWUSAGE;
348 return RESULT_FAILURE;
350 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
351 /* this is to check for if ast_waitstream closed the stream, we probably are at
352 * the end of the stream, return that amount, else check for the amount */
353 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
354 ast_stopstream(chan);
356 /* Stop this command, don't print a result line, as there is a new command */
357 return RESULT_SUCCESS;
359 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
361 return RESULT_SUCCESS;
363 return RESULT_FAILURE;
366 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
371 return RESULT_SHOWUSAGE;
372 if (sscanf(argv[2], "%i", &num) != 1)
373 return RESULT_SHOWUSAGE;
374 res = ast_say_number_full(chan, num, argv[3], chan->language, agi->audio, agi->ctrl);
376 return RESULT_SUCCESS;
377 fdprintf(agi->fd, "200 result=%d\n", res);
379 return RESULT_SUCCESS;
381 return RESULT_FAILURE;
384 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
389 return RESULT_SHOWUSAGE;
390 if (sscanf(argv[2], "%i", &num) != 1)
391 return RESULT_SHOWUSAGE;
392 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
393 if (res == 1) /* New command */
394 return RESULT_SUCCESS;
395 fdprintf(agi->fd, "200 result=%d\n", res);
397 return RESULT_SUCCESS;
399 return RESULT_FAILURE;
402 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
407 return RESULT_SHOWUSAGE;
408 if (sscanf(argv[2], "%i", &num) != 1)
409 return RESULT_SHOWUSAGE;
410 res = ast_say_time(chan, num, argv[3], chan->language);
412 return RESULT_SUCCESS;
413 fdprintf(agi->fd, "200 result=%d\n", res);
415 return RESULT_SUCCESS;
417 return RESULT_FAILURE;
420 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
428 return RESULT_SHOWUSAGE;
429 if (argc >= 4) timeout = atoi(argv[3]); else timeout = 0;
430 if (argc >= 5) max = atoi(argv[4]); else max = 1024;
431 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
432 if (res == 2) /* New command */
433 return RESULT_SUCCESS;
435 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
437 fdprintf(agi->fd, "200 result=-1\n");
439 fdprintf(agi->fd, "200 result=%s\n", data);
441 return RESULT_SUCCESS;
443 return RESULT_FAILURE;
446 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
450 return RESULT_SHOWUSAGE;
451 strncpy(chan->context, argv[2], sizeof(chan->context)-1);
452 fdprintf(agi->fd, "200 result=0\n");
453 return RESULT_SUCCESS;
456 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
459 return RESULT_SHOWUSAGE;
460 strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
461 fdprintf(agi->fd, "200 result=0\n");
462 return RESULT_SUCCESS;
465 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
469 return RESULT_SHOWUSAGE;
470 if (sscanf(argv[2], "%i", &pri) != 1)
471 return RESULT_SHOWUSAGE;
472 chan->priority = pri - 1;
473 fdprintf(agi->fd, "200 result=0\n");
474 return RESULT_SUCCESS;
477 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
479 struct ast_filestream *fs;
481 struct timeval tv, start;
482 long sample_offset = 0;
486 struct ast_dsp *sildet=NULL; /* silence detector dsp */
487 int totalsilence = 0;
489 int silence = 0; /* amount of silence to allow */
490 int gotsilence = 0; /* did we timeout for silence? */
491 char *silencestr=NULL;
495 /* XXX EAGI FIXME XXX */
498 return RESULT_SHOWUSAGE;
499 if (sscanf(argv[5], "%i", &ms) != 1)
500 return RESULT_SHOWUSAGE;
503 silencestr = strchr(argv[6],'s');
504 if ((argc > 7) && (!silencestr))
505 silencestr = strchr(argv[7],'s');
506 if ((argc > 8) && (!silencestr))
507 silencestr = strchr(argv[8],'s');
510 if (strlen(silencestr) > 2) {
511 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
515 silence = atoi(silencestr);
523 rfmt = chan->readformat;
524 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
526 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
529 sildet = ast_dsp_new();
531 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
534 ast_dsp_set_threshold(sildet, 256);
537 /* backward compatibility, if no offset given, arg[6] would have been
538 * caught below and taken to be a beep, else if it is a digit then it is a
540 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
541 res = ast_streamfile(chan, "beep", chan->language);
543 if ((argc > 7) && (!strchr(argv[7], '=')))
544 res = ast_streamfile(chan, "beep", chan->language);
547 res = ast_waitstream(chan, argv[4]);
549 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
552 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
554 ast_dsp_free(sildet);
555 return RESULT_FAILURE;
559 ast_applystream(chan,fs);
560 /* really should have checks */
561 ast_seekstream(fs, sample_offset, SEEK_SET);
564 gettimeofday(&start, NULL);
565 gettimeofday(&tv, NULL);
566 while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
567 res = ast_waitfor(chan, -1);
570 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
572 ast_dsp_free(sildet);
573 return RESULT_FAILURE;
577 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
580 ast_dsp_free(sildet);
581 return RESULT_FAILURE;
583 switch(f->frametype) {
585 if (strchr(argv[4], f->subclass)) {
586 /* This is an interrupting chracter */
587 sample_offset = ast_tellstream(fs);
588 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
592 ast_dsp_free(sildet);
593 return RESULT_SUCCESS;
596 case AST_FRAME_VOICE:
597 ast_writestream(fs, f);
598 /* this is a safe place to check progress since we know that fs
599 * is valid after a write, and it will then have our current
601 sample_offset = ast_tellstream(fs);
604 ast_dsp_silence(sildet, f, &dspsilence);
606 totalsilence = dspsilence;
610 if (totalsilence > silence) {
611 /* Ended happily with silence */
620 gettimeofday(&tv, NULL);
626 ast_stream_rewind(fs, silence-1000);
628 sample_offset = ast_tellstream(fs);
630 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
633 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
636 res = ast_set_read_format(chan, rfmt);
638 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
639 ast_dsp_free(sildet);
641 return RESULT_SUCCESS;
644 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
649 return RESULT_SHOWUSAGE;
650 if (sscanf(argv[2], "%d", &timeout) != 1)
651 return RESULT_SHOWUSAGE;
655 chan->whentohangup = time(NULL) + timeout;
657 chan->whentohangup = 0;
658 fdprintf(agi->fd, "200 result=0\n");
659 return RESULT_SUCCESS;
662 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
664 struct ast_channel *c;
666 /* no argument: hangup the current channel */
667 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
668 fdprintf(agi->fd, "200 result=1\n");
669 return RESULT_SUCCESS;
670 } else if (argc==2) {
671 /* one argument: look for info on the specified channel */
672 c = ast_channel_walk(NULL);
674 if (strcasecmp(argv[1],c->name)==0) {
675 /* we have a matching channel */
676 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
677 fdprintf(agi->fd, "200 result=1\n");
678 return RESULT_SUCCESS;
680 c = ast_channel_walk(c);
682 /* if we get this far no channel name matched the argument given */
683 fdprintf(agi->fd, "200 result=-1\n");
684 return RESULT_SUCCESS;
686 return RESULT_SHOWUSAGE;
690 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
696 return RESULT_SHOWUSAGE;
698 if (option_verbose > 2)
699 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
701 app = pbx_findapp(argv[1]);
704 res = pbx_exec(chan, app, argv[2], 1);
706 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
709 fdprintf(agi->fd, "200 result=%d\n", res);
714 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
717 ast_set_callerid(chan, argv[2], 0);
719 /* strncpy(chan->callerid, argv[2], sizeof(chan->callerid)-1);
720 */ fdprintf(agi->fd, "200 result=1\n");
721 return RESULT_SUCCESS;
724 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
726 struct ast_channel *c;
728 /* no argument: supply info on the current channel */
729 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
730 return RESULT_SUCCESS;
731 } else if (argc==3) {
732 /* one argument: look for info on the specified channel */
733 c = ast_channel_walk(NULL);
735 if (strcasecmp(argv[2],c->name)==0) {
736 fdprintf(agi->fd, "200 result=%d\n", c->_state);
737 return RESULT_SUCCESS;
739 c = ast_channel_walk(c);
741 /* if we get this far no channel name matched the argument given */
742 fdprintf(agi->fd, "200 result=-1\n");
743 return RESULT_SUCCESS;
745 return RESULT_SHOWUSAGE;
749 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
752 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
754 fdprintf(agi->fd, "200 result=1\n");
755 return RESULT_SUCCESS;
758 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
762 if ((tempstr = pbx_builtin_getvar_helper(chan, argv[2])) )
763 fdprintf(agi->fd, "200 result=1 (%s)\n", tempstr);
765 fdprintf(agi->fd, "200 result=0\n");
767 return RESULT_SUCCESS;
770 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
776 return RESULT_SHOWUSAGE;
779 sscanf(argv[2], "%d", &level);
783 prefix = VERBOSE_PREFIX_4;
786 prefix = VERBOSE_PREFIX_3;
789 prefix = VERBOSE_PREFIX_2;
793 prefix = VERBOSE_PREFIX_1;
797 if (level <= option_verbose)
798 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
800 fdprintf(agi->fd, "200 result=1\n");
802 return RESULT_SUCCESS;
805 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
810 return RESULT_SHOWUSAGE;
811 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
813 fdprintf(agi->fd, "200 result=0\n");
815 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
817 return RESULT_SUCCESS;
820 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
824 return RESULT_SHOWUSAGE;
825 res = ast_db_put(argv[2], argv[3], argv[4]);
827 fdprintf(agi->fd, "200 result=0\n");
829 fdprintf(agi->fd, "200 result=1\n");
831 return RESULT_SUCCESS;
834 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
838 return RESULT_SHOWUSAGE;
839 res = ast_db_del(argv[2], argv[3]);
841 fdprintf(agi->fd, "200 result=0\n");
843 fdprintf(agi->fd, "200 result=1\n");
845 return RESULT_SUCCESS;
848 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
851 if ((argc < 3) || (argc > 4))
852 return RESULT_SHOWUSAGE;
854 res = ast_db_deltree(argv[2], argv[3]);
856 res = ast_db_deltree(argv[2], NULL);
859 fdprintf(agi->fd, "200 result=0\n");
861 fdprintf(agi->fd, "200 result=1\n");
862 return RESULT_SUCCESS;
865 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
867 fdprintf(agi->fd, "200 result=0\n");
868 return RESULT_SUCCESS;
871 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
873 if (!strncasecmp(argv[2],"on",2)) {
875 ast_moh_start(chan, argv[3]);
877 ast_moh_start(chan, NULL);
879 if (!strncasecmp(argv[2],"off",3)) {
882 fdprintf(agi->fd, "200 result=0\n");
883 return RESULT_SUCCESS;
886 static char usage_setmusic[] =
887 " Usage: SET MUSIC ON <on|off> <class>\n"
888 " Enables/Disables the music on hold generator. If <class> is\n"
889 " not specified then the default music on hold class will be used.\n"
890 " Always returns 0\n";
892 static char usage_dbput[] =
893 " Usage: DATABASE PUT <family> <key> <value>\n"
894 " Adds or updates an entry in the Asterisk database for a\n"
895 " given family, key, and value.\n"
896 " Returns 1 if succesful, 0 otherwise\n";
898 static char usage_dbget[] =
899 " Usage: DATABASE GET <family> <key>\n"
900 " Retrieves an entry in the Asterisk database for a\n"
901 " given family and key.\n"
902 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
903 " is set and returns the variable in parenthesis\n"
904 " example return code: 200 result=1 (testvariable)\n";
906 static char usage_dbdel[] =
907 " Usage: DATABASE DEL <family> <key>\n"
908 " Deletes an entry in the Asterisk database for a\n"
909 " given family and key.\n"
910 " Returns 1 if succesful, 0 otherwise\n";
912 static char usage_dbdeltree[] =
913 " Usage: DATABASE DELTREE <family> [keytree]\n"
914 " Deletes a family or specific keytree withing a family\n"
915 " in the Asterisk database.\n"
916 " Returns 1 if succesful, 0 otherwise\n";
918 static char usage_verbose[] =
919 " Usage: VERBOSE <message> <level>\n"
920 " Sends <message> to the console via verbose message system.\n"
921 " <level> is the the verbose level (1-4)\n"
922 " Always returns 1\n";
924 static char usage_getvariable[] =
925 " Usage: GET VARIABLE <variablename>\n"
926 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
927 " is set and returns the variable in parenthesis\n"
928 " example return code: 200 result=1 (testvariable)\n";
930 static char usage_setvariable[] =
931 " Usage: SET VARIABLE <variablename> <value>\n";
933 static char usage_channelstatus[] =
934 " Usage: CHANNEL STATUS [<channelname>]\n"
935 " Returns the status of the specified channel.\n"
936 " If no channel name is given the returns the status of the\n"
937 " current channel.\n"
939 " 0 Channel is down and available\n"
940 " 1 Channel is down, but reserved\n"
941 " 2 Channel is off hook\n"
942 " 3 Digits (or equivalent) have been dialed\n"
943 " 4 Line is ringing\n"
944 " 5 Remote end is ringing\n"
948 static char usage_setcallerid[] =
949 " Usage: SET CALLERID <number>\n"
950 " Changes the callerid of the current channel.\n";
952 static char usage_exec[] =
953 " Usage: EXEC <application> <options>\n"
954 " Executes <application> with given <options>.\n"
955 " Returns whatever the application returns, or -2 on failure to find application\n";
957 static char usage_hangup[] =
958 " Usage: HANGUP [<channelname>]\n"
959 " Hangs up the specified channel.\n"
960 " If no channel name is given, hangs up the current channel\n";
962 static char usage_answer[] =
964 " Answers channel if not already in answer state. Returns -1 on\n"
965 " channel failure, or 0 if successful.\n";
967 static char usage_waitfordigit[] =
968 " Usage: WAIT FOR DIGIT <timeout>\n"
969 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
970 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
971 " the numerical value of the ascii of the digit if one is received. Use -1\n"
972 " for the timeout value if you desire the call to block indefinitely.\n";
974 static char usage_sendtext[] =
975 " Usage: SEND TEXT \"<text to send>\"\n"
976 " Sends the given text on a channel. Most channels do not support the\n"
977 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
978 " support text transmission. Returns -1 only on error/hangup. Text\n"
979 " consisting of greater than one word should be placed in quotes since the\n"
980 " command only accepts a single argument.\n";
982 static char usage_recvchar[] =
983 " Usage: RECEIVE CHAR <timeout>\n"
984 " Receives a character of text on a channel. Specify timeout to be the\n"
985 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
986 " do not support the reception of text. Returns the decimal value of the character\n"
987 " if one is received, or 0 if the channel does not support text reception. Returns\n"
988 " -1 only on error/hangup.\n";
990 static char usage_tddmode[] =
991 " Usage: TDD MODE <on|off>\n"
992 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
993 " successful, or 0 if channel is not TDD-capable.\n";
995 static char usage_sendimage[] =
996 " Usage: SEND IMAGE <image>\n"
997 " Sends the given image on a channel. Most channels do not support the\n"
998 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
999 " support image transmission. Returns -1 only on error/hangup. Image names\n"
1000 " should not include extensions.\n";
1002 static char usage_streamfile[] =
1003 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
1004 " Send the given file, allowing playback to be interrupted by the given\n"
1005 " digits, if any. Use double quotes for the digits if you wish none to be\n"
1006 " permitted. If sample offset is provided then the audio will seek to sample\n"
1007 " offset before play starts. Returns 0 if playback completes without a digit\n"
1008 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
1009 " or -1 on error or if the channel was disconnected. Remember, the file\n"
1010 " extension must not be included in the filename.\n";
1012 static char usage_saynumber[] =
1013 " Usage: SAY NUMBER <number> <escape digits>\n"
1014 " Say a given number, returning early if any of the given DTMF digits\n"
1015 " are received on the channel. Returns 0 if playback completes without a digit\n"
1016 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1017 " -1 on error/hangup.\n";
1019 static char usage_saydigits[] =
1020 " Usage: SAY DIGITS <number> <escape digits>\n"
1021 " Say a given digit string, returning early if any of the given DTMF digits\n"
1022 " are received on the channel. Returns 0 if playback completes without a digit\n"
1023 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
1024 " -1 on error/hangup.\n";
1026 static char usage_saytime[] =
1027 " Usage: SAY TIME <time> <escape digits>\n"
1028 " Say a given time, returning early if any of the given DTMF digits are\n"
1029 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
1030 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
1031 " completes without a digit being pressed, or the ASCII numerical value of the\n"
1032 " digit if one was pressed or -1 on error/hangup.\n";
1034 static char usage_getdata[] =
1035 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
1036 " Stream the given file, and recieve DTMF data. Returns the digits recieved\n"
1037 "from the channel at the other end.\n";
1039 static char usage_setcontext[] =
1040 " Usage: SET CONTEXT <desired context>\n"
1041 " Sets the context for continuation upon exiting the application.\n";
1043 static char usage_setextension[] =
1044 " Usage: SET EXTENSION <new extension>\n"
1045 " Changes the extension for continuation upon exiting the application.\n";
1047 static char usage_setpriority[] =
1048 " Usage: SET PRIORITY <num>\n"
1049 " Changes the priority for continuation upon exiting the application.\n";
1051 static char usage_recordfile[] =
1052 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> [offset samples] [BEEP] [s=silence]\n"
1053 " Record to a file until a given dtmf digit in the sequence is received\n"
1054 " Returns -1 on hangup or error. The format will specify what kind of file\n"
1055 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
1056 " -1 for no timeout. Offset samples is optional, and if provided will seek to\n"
1057 " the offset without exceeding the end of the file. \"silence\" is the number\n"
1058 " of seconds of silence allowed before the function returns despite the\n"
1059 " lack of dtmf digits or reaching timeout. Silence value must be\n"
1060 " preceeded by \"s=\" and is optional.\n";
1063 static char usage_autohangup[] =
1064 " Usage: SET AUTOHANGUP <time>\n"
1065 " Cause the channel to automatically hangup at <time> seconds in the\n"
1066 "future. Of course it can be hungup before then as well. Setting to\n"
1067 "0 will cause the autohangup feature to be disabled on this channel.\n";
1069 static char usage_noop[] =
1073 static agi_command commands[] = {
1074 { { "answer", NULL }, handle_answer, "Asserts answer", usage_answer },
1075 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
1076 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
1077 { { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
1078 { { "tdd", "mode", NULL }, handle_tddmode, "Sends text to channels supporting it", usage_tddmode },
1079 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
1080 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
1081 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
1082 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
1083 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
1084 { { "get", "data", NULL }, handle_getdata, "Gets data on a channel", usage_getdata },
1085 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
1086 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
1087 { { "set", "priority", NULL }, handle_setpriority, "Prioritizes the channel", usage_setpriority },
1088 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
1089 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
1090 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
1091 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
1092 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
1093 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
1094 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
1095 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
1096 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
1097 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
1098 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
1099 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
1100 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
1101 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
1102 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic }
1105 static void join(char *s, int len, char *w[])
1108 /* Join words into a string */
1110 for (x=0;w[x];x++) {
1112 strncat(s, " ", len - strlen(s));
1113 strncat(s, w[x], len - strlen(s));
1117 static int help_workhorse(int fd, char *match[])
1122 struct agi_command *e;
1124 join(matchstr, sizeof(matchstr), match);
1125 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1128 join(fullcmd, sizeof(fullcmd), e->cmda);
1129 /* Hide commands that start with '_' */
1130 if (fullcmd[0] == '_')
1133 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
1137 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
1142 static agi_command *find_command(char *cmds[], int exact)
1147 for (x=0;x < sizeof(commands) / sizeof(commands[0]);x++) {
1148 /* start optimistic */
1150 for (y=0;match && cmds[y]; y++) {
1151 /* If there are no more words in the command (and we're looking for
1152 an exact match) or there is a difference between the two words,
1153 then this is not a match */
1154 if (!commands[x].cmda[y] && !exact)
1156 /* don't segfault if the next part of a command doesn't exist */
1157 if (!commands[x].cmda[y]) return NULL;
1158 if (strcasecmp(commands[x].cmda[y], cmds[y]))
1161 /* If more words are needed to complete the command then this is not
1162 a candidate (unless we're looking for a really inexact answer */
1163 if ((exact > -1) && commands[x].cmda[y])
1166 return &commands[x];
1172 static int parse_args(char *s, int *max, char *argv[])
1184 /* If it's escaped, put a literal quote */
1189 if (quoted && whitespace) {
1190 /* If we're starting a quote, coming off white space start a new word, too */
1198 if (!quoted && !escaped) {
1199 /* If we're not quoted, mark this as whitespace, and
1200 end the previous argument */
1204 /* Otherwise, just treat it as anything else */
1208 /* If we're escaped, print a literal, otherwise enable escaping */
1218 if (x >= MAX_ARGS -1) {
1219 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
1222 /* Coming off of whitespace, start the next argument */
1231 /* Null terminate */
1238 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
1240 char *argv[MAX_ARGS];
1245 parse_args(buf, &argc, argv);
1248 for (x=0;x<argc;x++)
1249 fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
1251 c = find_command(argv, 0);
1253 res = c->handler(chan, agi, argc, argv);
1255 case RESULT_SHOWUSAGE:
1256 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
1257 fdprintf(agi->fd, c->usage);
1258 fdprintf(agi->fd, "520 End of proper usage.\n");
1260 case AST_PBX_KEEPALIVE:
1261 /* We've been asked to keep alive, so do so */
1262 return AST_PBX_KEEPALIVE;
1264 case RESULT_FAILURE:
1265 /* They've already given the failure. We've been hung up on so handle this
1270 fdprintf(agi->fd, "510 Invalid or unknown command\n");
1275 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
1277 struct ast_channel *c;
1280 int returnstatus = 0;
1281 struct ast_frame *f;
1284 /* how many times we'll retry if ast_waitfor_nandfs will return without either
1285 channel or file descriptor in case select is interrupted by a system call (EINTR) */
1288 if (!(readf = fdopen(agi->ctrl, "r"))) {
1289 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
1294 setup_env(chan, request, agi->fd, (agi->audio > -1));
1297 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
1300 /* Idle the channel until we get a command */
1303 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
1307 /* If it's voice, write it to the audio pipe */
1308 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
1309 /* Write, ignoring errors */
1310 write(agi->audio, f->data, f->datalen);
1314 } else if (outfd > -1) {
1316 if (!fgets(buf, sizeof(buf), readf)) {
1317 /* Program terminated */
1320 if (option_verbose > 2)
1321 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
1322 /* No need to kill the pid anymore, since they closed us */
1326 /* get rid of trailing newline, if any */
1327 if (*buf && buf[strlen(buf) - 1] == '\n')
1328 buf[strlen(buf) - 1] = 0;
1330 returnstatus |= agi_handle_command(chan, agi, buf);
1331 /* If the handle_command returns -1, we need to stop */
1332 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
1337 ast_log(LOG_WARNING, "No channel, no fd?\n");
1343 /* Notify process */
1347 return returnstatus;
1350 static int handle_showagi(int fd, int argc, char *argv[]) {
1351 struct agi_command *e;
1354 return RESULT_SHOWUSAGE;
1356 e = find_command(argv + 2, 1);
1358 ast_cli(fd, e->usage);
1360 if (find_command(argv + 2, -1)) {
1361 return help_workhorse(fd, argv + 1);
1363 join(fullcmd, sizeof(fullcmd), argv+1);
1364 ast_cli(fd, "No such command '%s'.\n", fullcmd);
1368 return help_workhorse(fd, NULL);
1370 return RESULT_SUCCESS;
1373 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
1374 struct agi_command *e;
1381 return RESULT_SHOWUSAGE;
1383 if (!(htmlfile = fopen(argv[2], "wt"))) {
1384 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
1385 return RESULT_SHOWUSAGE;
1388 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
1389 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
1392 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
1394 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
1398 join(fullcmd, sizeof(fullcmd), e->cmda);
1399 /* Hide commands that start with '_' */
1400 if (fullcmd[0] == '_')
1403 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
1404 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
1408 tempstr = strsep(&stringp, "\n");
1410 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
1412 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
1413 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
1414 fprintf(htmlfile, "%s<BR>\n",tempstr);
1417 fprintf(htmlfile, "</TD></TR>\n");
1418 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
1422 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
1424 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
1425 return RESULT_SUCCESS;
1428 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
1431 struct localuser *u;
1439 if (!data || !strlen(data)) {
1440 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
1445 memset(&agi, 0, sizeof(agi));
1446 strncpy(tmp, data, sizeof(tmp)-1);
1447 strsep(&stringp, "|");
1448 args = strsep(&stringp, "|");
1449 ringy = strsep(&stringp,"|");
1454 /* Answer if need be */
1455 if (chan->_state != AST_STATE_UP) {
1456 if (ringy) { /* if for ringing first */
1457 /* a little ringy-dingy first */
1458 ast_indicate(chan, AST_CONTROL_RINGING);
1461 if (ast_answer(chan)) {
1462 LOCAL_USER_REMOVE(u);
1467 res = launch_script(tmp, args, fds, enhanced ? &efd : NULL, &pid);
1472 res = run_agi(chan, tmp, &agi, pid, dead);
1478 LOCAL_USER_REMOVE(u);
1482 static int agi_exec(struct ast_channel *chan, void *data)
1484 return agi_exec_full(chan, data, 0, 0);
1487 static int eagi_exec(struct ast_channel *chan, void *data)
1491 readformat = chan->readformat;
1492 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1493 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
1496 res = agi_exec_full(chan, data, 1, 0);
1498 if (ast_set_read_format(chan, readformat)) {
1499 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
1505 static int deadagi_exec(struct ast_channel *chan, void *data)
1507 return agi_exec_full(chan, data, 0, 1);
1510 static char showagi_help[] =
1511 "Usage: show agi [topic]\n"
1512 " When called with a topic as an argument, displays usage\n"
1513 " information on the given command. If called without a\n"
1514 " topic, it provides a list of AGI commands.\n";
1517 static char dumpagihtml_help[] =
1518 "Usage: dump agihtml <filename>\n"
1519 " Dumps the agi command list in html format to given filename\n";
1521 static struct ast_cli_entry showagi =
1522 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
1524 static struct ast_cli_entry dumpagihtml =
1525 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
1527 int unload_module(void)
1529 STANDARD_HANGUP_LOCALUSERS;
1530 ast_cli_unregister(&showagi);
1531 ast_cli_unregister(&dumpagihtml);
1532 ast_unregister_application(eapp);
1533 ast_unregister_application(deadapp);
1534 return ast_unregister_application(app);
1537 int load_module(void)
1539 ast_cli_register(&showagi);
1540 ast_cli_register(&dumpagihtml);
1541 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
1542 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
1543 return ast_register_application(app, agi_exec, synopsis, descrip);
1546 char *description(void)
1554 STANDARD_USECOUNT(res);
1560 return ASTERISK_GPL_KEY;