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.
21 * \brief AGI - the Asterisk Gateway Interface
23 * \author Mark Spencer <markster@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/paths.h" /* use many ast_config_AST_*_DIR */
38 #include "asterisk/network.h"
39 #include "asterisk/file.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/module.h"
43 #include "asterisk/astdb.h"
44 #include "asterisk/callerid.h"
45 #include "asterisk/cli.h"
46 #include "asterisk/image.h"
47 #include "asterisk/say.h"
48 #include "asterisk/app.h"
49 #include "asterisk/dsp.h"
50 #include "asterisk/musiconhold.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/strings.h"
54 #include "asterisk/agi.h"
55 #include "asterisk/manager.h"
56 #include "asterisk/version.h"
57 #include "asterisk/speech.h"
58 #include "asterisk/manager.h"
61 #define AGI_NANDFS_RETRY 3
62 #define AGI_BUF_LEN 2048
64 static char *app = "AGI";
66 static char *eapp = "EAGI";
68 static char *deadapp = "DeadAGI";
70 static char *synopsis = "Executes an AGI compliant application";
71 static char *esynopsis = "Executes an EAGI compliant application";
72 static char *deadsynopsis = "Executes AGI on a hungup channel";
74 static char *descrip =
75 " [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
76 "program on a channel. AGI allows Asterisk to launch external programs\n"
77 "written in any language to control a telephony channel, play audio,\n"
78 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
80 " This channel will stop dialplan execution on hangup inside of this\n"
81 "application, except when using DeadAGI. Otherwise, dialplan execution\n"
82 "will continue normally.\n"
83 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
84 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
85 "variable to \"no\" before executing the AGI application.\n"
86 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
87 "on file descriptor 3\n\n"
88 " Use the CLI command 'agi show' to list available agi commands\n"
89 " This application sets the following channel variable upon completion:\n"
90 " AGISTATUS The status of the attempt to the run the AGI script\n"
91 " text string, one of SUCCESS | FAILURE | NOTFOUND | HANGUP\n";
93 static int agidebug = 0;
95 #define TONE_BLOCK_SIZE 200
97 /* Max time to connect to an AGI remote host */
98 #define MAX_AGI_CONNECT 2000
100 #define AGI_PORT 4573
104 AGI_RESULT_SUCCESS_FAST,
105 AGI_RESULT_SUCCESS_ASYNC,
111 static agi_command *find_command(char *cmds[], int exact);
113 AST_THREADSTORAGE(agi_buf);
114 #define AGI_BUF_INITSIZE 256
116 int ast_agi_fdprintf(struct ast_channel *chan, int fd, char *fmt, ...)
122 if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
126 res = ast_str_set_va(&buf, 0, fmt, ap);
130 ast_log(LOG_ERROR, "Out of memory\n");
136 ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
138 ast_verbose("AGI Tx >> %s", buf->str);
142 return ast_carefulwrite(fd, buf->str, buf->used, 100);
145 /* linked list of AGI commands ready to be executed by Async AGI */
149 AST_LIST_ENTRY(agi_cmd) entry;
152 static void free_agi_cmd(struct agi_cmd *cmd)
154 ast_free(cmd->cmd_buffer);
155 ast_free(cmd->cmd_id);
159 /* AGI datastore destructor */
160 static void agi_destroy_commands_cb(void *data)
163 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
164 AST_LIST_LOCK(chan_cmds);
165 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
168 AST_LIST_UNLOCK(chan_cmds);
169 AST_LIST_HEAD_DESTROY(chan_cmds);
173 /* channel datastore to keep the queue of AGI commands in the channel */
174 static const struct ast_datastore_info agi_commands_datastore_info = {
176 .destroy = agi_destroy_commands_cb
179 static const char mandescr_asyncagi[] =
180 "Description: Add an AGI command to the execute queue of the channel in Async AGI\n"
182 " *Channel: Channel that is currently in Async AGI\n"
183 " *Command: Application to execute\n"
184 " CommandID: comand id. This will be sent back in CommandID header of AsyncAGI exec event notification\n"
187 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
189 struct ast_datastore *store;
191 AST_LIST_HEAD(, agi_cmd) *agi_commands;
193 ast_channel_lock(chan);
194 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
195 ast_channel_unlock(chan);
197 ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
200 agi_commands = store->data;
201 AST_LIST_LOCK(agi_commands);
202 cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
203 AST_LIST_UNLOCK(agi_commands);
207 /* channel is locked when calling this one either from the CLI or manager thread */
208 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
210 struct ast_datastore *store;
212 AST_LIST_HEAD(, agi_cmd) *agi_commands;
214 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
216 ast_log(LOG_WARNING, "Channel %s is not at Async AGI.\n", chan->name);
219 agi_commands = store->data;
220 cmd = ast_calloc(1, sizeof(*cmd));
224 cmd->cmd_buffer = ast_strdup(cmd_buff);
225 if (!cmd->cmd_buffer) {
229 cmd->cmd_id = ast_strdup(cmd_id);
231 ast_free(cmd->cmd_buffer);
235 AST_LIST_LOCK(agi_commands);
236 AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
237 AST_LIST_UNLOCK(agi_commands);
241 static int add_to_agi(struct ast_channel *chan)
243 struct ast_datastore *datastore;
244 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
246 /* check if already on AGI */
247 ast_channel_lock(chan);
248 datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
249 ast_channel_unlock(chan);
251 /* we already have an AGI datastore, let's just
256 /* the channel has never been on Async AGI,
257 let's allocate it's datastore */
258 datastore = ast_channel_datastore_alloc(&agi_commands_datastore_info, "AGI");
262 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
263 if (!agi_cmds_list) {
264 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
265 ast_channel_datastore_free(datastore);
268 datastore->data = agi_cmds_list;
269 AST_LIST_HEAD_INIT(agi_cmds_list);
270 ast_channel_lock(chan);
271 ast_channel_datastore_add(chan, datastore);
272 ast_channel_unlock(chan);
277 * \brief CLI command to add applications to execute in Async AGI
282 * \retval CLI_SUCCESS on success
283 * \retval NULL when init or tab completion is used
285 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
287 struct ast_channel *chan;
290 e->command = "agi exec";
291 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
292 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
296 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
301 return CLI_SHOWUSAGE;
302 chan = ast_get_channel_by_name_locked(a->argv[2]);
304 ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
307 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
308 ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
309 ast_channel_unlock(chan);
312 ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
313 ast_channel_unlock(chan);
318 * \brief Add a new command to execute by the Async AGI application
322 * It will append the application to the specified channel's queue
323 * if the channel is not inside Async AGI application it will return an error
324 * \retval 0 on success or incorrect use
325 * \retval 1 on failure to add the command ( most likely because the channel
326 * is not in Async AGI loop )
328 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
330 const char *channel = astman_get_header(m, "Channel");
331 const char *cmdbuff = astman_get_header(m, "Command");
332 const char *cmdid = astman_get_header(m, "CommandID");
333 struct ast_channel *chan;
335 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
336 astman_send_error(s, m, "Both, Channel and Command are *required*");
339 chan = ast_get_channel_by_name_locked(channel);
341 snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
342 astman_send_error(s, m, buf);
345 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
346 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
347 astman_send_error(s, m, buf);
348 ast_channel_unlock(chan);
351 astman_send_ack(s, m, "Added AGI command to queue");
352 ast_channel_unlock(chan);
356 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
357 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
358 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
360 /* This buffer sizes might cause truncation if the AGI command writes more data
361 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
362 that writes a response larger than 1024 bytes?, I don't think so, most of
363 them are just result=blah stuff. However probably if GET VARIABLE is called
364 and the variable has large amount of data, that could be a problem. We could
365 make this buffers dynamic, but let's leave that as a second step.
367 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
368 number. Some characters of AGI buf will be url encoded to be sent to manager
369 clients. An URL encoded character will take 3 bytes, but again, to cause
370 truncation more than about 70% of the AGI buffer should be URL encoded for
371 that to happen. Not likely at all.
373 On the other hand. I wonder if read() could eventually return less data than
374 the amount already available in the pipe? If so, how to deal with that?
375 So far, my tests on Linux have not had any problems.
377 #define AGI_BUF_SIZE 1024
378 #define AMI_BUF_SIZE 2048
383 char agi_buffer[AGI_BUF_SIZE + 1];
384 char ami_buffer[AMI_BUF_SIZE];
385 enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
389 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
390 return AGI_RESULT_FAILURE;
393 /* add AsyncAGI datastore to the channel */
394 if (add_to_agi(chan)) {
395 ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
396 return AGI_RESULT_FAILURE;
399 /* this pipe allows us to create a "fake" AGI struct to use
403 ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
404 /* intentionally do not remove datastore, added with
405 add_to_agi(), from channel. It will be removed when
406 the channel is hung up anyways */
407 return AGI_RESULT_FAILURE;
409 /* handlers will get the pipe write fd and we read the AGI responses
410 from the pipe read fd */
411 async_agi.fd = fds[1];
412 async_agi.ctrl = fds[1];
413 async_agi.audio = -1; /* no audio support */
416 /* notify possible manager users of a new channel ready to
418 setup_env(chan, "async", fds[1], 0, 0, NULL);
419 /* read the environment */
420 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
422 ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
423 returnstatus = AGI_RESULT_FAILURE;
426 agi_buffer[res] = '\0';
427 /* encode it and send it thru the manager so whoever is going to take
428 care of AGI commands on this channel can decide which AGI commands
429 to execute based on the setup info */
430 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
431 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
433 /* bail out if we need to hangup */
434 if (ast_check_hangup(chan)) {
435 ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
438 /* retrieve a command
439 (commands are added via the manager or the cli threads) */
440 cmd = get_agi_cmd(chan);
442 /* OK, we have a command, let's call the
444 res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
445 if ((res < 0) || (res == AST_PBX_KEEPALIVE)) {
449 /* the command handler must have written to our fake
450 AGI struct fd (the pipe), let's read the response */
451 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
453 returnstatus = AGI_RESULT_FAILURE;
454 ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
458 /* we have a response, let's send the response thru the
459 manager. Include the CommandID if it was specified
460 when the command was added */
461 agi_buffer[res] = '\0';
462 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
463 if (ast_strlen_zero(cmd->cmd_id))
464 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
466 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nCommandID: %s\r\nResult: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
469 /* no command so far, wait a bit for a frame to read */
470 res = ast_waitfor(chan, timeout);
472 ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
479 ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
480 returnstatus = AGI_RESULT_HANGUP;
483 /* is there any other frame we should care about
484 besides AST_CONTROL_HANGUP? */
485 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
486 ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
494 /* notify manager users this channel cannot be
495 controlled anymore by Async AGI */
496 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
502 /* intentionally don't get rid of the datastore. So commands can be
503 still in the queue in case AsyncAGI gets called again.
504 Datastore destructor will be called on channel destroy anyway */
512 /* launch_netscript: The fastagi handler.
513 FastAGI defaults to port 4573 */
514 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
516 int s, flags, res, port = AGI_PORT;
517 struct pollfd pfds[1];
518 char *host, *c, *script = "";
519 struct sockaddr_in sin;
521 struct ast_hostent ahp;
523 /* agiusl is "agi://host.domain[:port][/script/name]" */
524 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
525 /* Strip off any script name */
526 if ((c = strchr(host, '/'))) {
531 if ((c = strchr(host, ':'))) {
537 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
540 if (!(hp = ast_gethostbyname(host, &ahp))) {
541 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
544 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
545 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
548 if ((flags = fcntl(s, F_GETFL)) < 0) {
549 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
553 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
554 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
558 memset(&sin, 0, sizeof(sin));
559 sin.sin_family = AF_INET;
560 sin.sin_port = htons(port);
561 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
562 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
563 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
565 return AGI_RESULT_FAILURE;
569 pfds[0].events = POLLOUT;
570 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
571 if (errno != EINTR) {
573 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
574 agiurl, MAX_AGI_CONNECT);
576 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
578 return AGI_RESULT_FAILURE;
582 if (ast_agi_fdprintf(NULL, s, "agi_network: yes\n") < 0) {
583 if (errno != EINTR) {
584 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
586 return AGI_RESULT_FAILURE;
590 /* If we have a script parameter, relay it to the fastagi server */
591 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
592 if (!ast_strlen_zero(script))
593 ast_agi_fdprintf(NULL, s, "agi_network_script: %s\n", script);
595 ast_debug(4, "Wow, connected!\n");
599 return AGI_RESULT_SUCCESS_FAST;
602 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
605 int pid, toast[2], fromast[2], audio[2], x, res;
606 sigset_t signal_set, old_set;
609 if (!strncasecmp(script, "agi://", 6))
610 return launch_netscript(script, argv, fds, efd, opid);
611 if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
612 return launch_asyncagi(chan, argv, efd);
614 if (script[0] != '/') {
615 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
619 /* Before even trying let's see if the file actually exists */
620 if (stat(script, &st)) {
621 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
622 return AGI_RESULT_NOTFOUND;
626 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
627 return AGI_RESULT_FAILURE;
630 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
633 return AGI_RESULT_FAILURE;
637 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
642 return AGI_RESULT_FAILURE;
644 res = fcntl(audio[1], F_GETFL);
646 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
648 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
655 return AGI_RESULT_FAILURE;
659 /* Block SIGHUP during the fork - prevents a race */
660 sigfillset(&signal_set);
661 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
662 if ((pid = fork()) < 0) {
663 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
664 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
665 return AGI_RESULT_FAILURE;
668 /* Pass paths to AGI via environmental variables */
669 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
670 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
671 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
672 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
673 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
674 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
675 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
676 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
677 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
678 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
679 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
681 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
684 /* Redirect stdin and out, provide enhanced audio channel if desired */
685 dup2(fromast[0], STDIN_FILENO);
686 dup2(toast[1], STDOUT_FILENO);
688 dup2(audio[0], STDERR_FILENO + 1);
690 close(STDERR_FILENO + 1);
692 /* Before we unblock our signals, return our trapped signals back to the defaults */
693 signal(SIGHUP, SIG_DFL);
694 signal(SIGCHLD, SIG_DFL);
695 signal(SIGINT, SIG_DFL);
696 signal(SIGURG, SIG_DFL);
697 signal(SIGTERM, SIG_DFL);
698 signal(SIGPIPE, SIG_DFL);
699 signal(SIGXFSZ, SIG_DFL);
701 /* unblock important signal handlers */
702 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
703 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
707 /* Close everything but stdin/out/error */
708 for (x = STDERR_FILENO + 2; x < 1024; x++)
712 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
714 /* Can't use ast_log since FD's are closed */
715 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
719 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
720 ast_verb(3, "Launched AGI Script %s\n", script);
725 /* close what we're not using in the parent */
733 return AGI_RESULT_SUCCESS;
736 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
740 /* Print initial environment, with agi_request always being the first
742 ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
743 ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
744 ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
745 ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
746 ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
747 ast_agi_fdprintf(chan, fd, "agi_version: %s\n", ast_get_version());
750 ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
751 ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
752 ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
753 ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
754 ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
755 ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
756 ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
757 ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
759 /* Context information */
760 ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
761 ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
762 ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
763 ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
765 /* User information */
766 ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
767 ast_agi_fdprintf(chan, fd, "agi_threadid: %ld\n", (long)pthread_self());
769 /* Send any parameters to the fastagi server that have been passed via the agi application */
770 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
771 for(count = 1; count < argc; count++)
772 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
774 /* End with empty return */
775 ast_agi_fdprintf(chan, fd, "\n");
778 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
782 /* Answer the channel */
783 if (chan->_state != AST_STATE_UP)
784 res = ast_answer(chan);
786 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
787 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
790 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
795 return RESULT_SHOWUSAGE;
796 if (sscanf(argv[3], "%d", &to) != 1)
797 return RESULT_SHOWUSAGE;
798 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
799 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
800 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
803 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
808 return RESULT_SHOWUSAGE;
810 /* At the moment, the parser (perhaps broken) returns with
811 the last argument PLUS the newline at the end of the input
812 buffer. This probably needs to be fixed, but I wont do that
813 because other stuff may break as a result. The right way
814 would probably be to strip off the trailing newline before
815 parsing, then here, add a newline at the end of the string
816 before sending it to ast_sendtext --DUDE */
817 res = ast_sendtext(chan, argv[2]);
818 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
819 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
822 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
827 return RESULT_SHOWUSAGE;
829 res = ast_recvchar(chan,atoi(argv[2]));
831 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
832 return RESULT_SUCCESS;
835 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
836 return RESULT_SUCCESS;
839 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
840 return RESULT_FAILURE;
844 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
849 return RESULT_SHOWUSAGE;
851 buf = ast_recvtext(chan,atoi(argv[2]));
853 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
856 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
858 return RESULT_SUCCESS;
861 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
866 return RESULT_SHOWUSAGE;
868 if (!strncasecmp(argv[2],"on",2))
872 if (!strncasecmp(argv[2],"mate",4))
874 if (!strncasecmp(argv[2],"tdd",3))
876 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
877 if (res != RESULT_SUCCESS)
878 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
880 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
881 return RESULT_SUCCESS;
884 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
889 return RESULT_SHOWUSAGE;
891 res = ast_send_image(chan, argv[2]);
892 if (!ast_check_hangup(chan))
894 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
895 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
898 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
900 int res = 0, skipms = 3000;
901 char *fwd = NULL, *rev = NULL, *pause = NULL, *stop = NULL;
903 if (argc < 5 || argc > 9)
904 return RESULT_SHOWUSAGE;
906 if (!ast_strlen_zero(argv[4]))
911 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
912 return RESULT_SHOWUSAGE;
914 if (argc > 6 && !ast_strlen_zero(argv[6]))
919 if (argc > 7 && !ast_strlen_zero(argv[7]))
924 if (argc > 8 && !ast_strlen_zero(argv[8]))
929 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
931 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
933 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
936 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
939 struct ast_filestream *fs, *vfs;
940 long sample_offset = 0, max_length;
943 if (argc < 4 || argc > 5)
944 return RESULT_SHOWUSAGE;
949 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
950 return RESULT_SHOWUSAGE;
952 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
953 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
954 return RESULT_SUCCESS;
957 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
958 ast_debug(1, "Ooh, found a video stream, too\n");
960 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
962 ast_seekstream(fs, 0, SEEK_END);
963 max_length = ast_tellstream(fs);
964 ast_seekstream(fs, sample_offset, SEEK_SET);
965 res = ast_applystream(chan, fs);
967 vres = ast_applystream(chan, vfs);
972 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
973 /* this is to check for if ast_waitstream closed the stream, we probably are at
974 * the end of the stream, return that amount, else check for the amount */
975 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
976 ast_stopstream(chan);
978 /* Stop this command, don't print a result line, as there is a new command */
979 return RESULT_SUCCESS;
981 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
982 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
985 /* get option - really similar to the handle_streamfile, but with a timeout */
986 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
989 struct ast_filestream *fs, *vfs;
990 long sample_offset = 0, max_length;
994 if ( argc < 4 || argc > 5 )
995 return RESULT_SHOWUSAGE;
1001 timeout = atoi(argv[4]);
1002 else if (chan->pbx->dtimeout) {
1003 /* by default dtimeout is set to 5sec */
1004 timeout = chan->pbx->dtimeout * 1000; /* in msec */
1007 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
1008 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
1009 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
1010 return RESULT_SUCCESS;
1013 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
1014 ast_debug(1, "Ooh, found a video stream, too\n");
1016 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
1018 ast_seekstream(fs, 0, SEEK_END);
1019 max_length = ast_tellstream(fs);
1020 ast_seekstream(fs, sample_offset, SEEK_SET);
1021 res = ast_applystream(chan, fs);
1023 vres = ast_applystream(chan, vfs);
1026 ast_playstream(vfs);
1028 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1029 /* this is to check for if ast_waitstream closed the stream, we probably are at
1030 * the end of the stream, return that amount, else check for the amount */
1031 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
1032 ast_stopstream(chan);
1034 /* Stop this command, don't print a result line, as there is a new command */
1035 return RESULT_SUCCESS;
1038 /* If the user didnt press a key, wait for digitTimeout*/
1040 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
1041 /* Make sure the new result is in the escape digits of the GET OPTION */
1042 if ( !strchr(edigits,res) )
1046 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
1047 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1053 /*--- handle_saynumber: Say number in various language syntaxes ---*/
1054 /* While waiting, we're sending a NULL. */
1055 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1059 if (argc < 4 || argc > 5)
1060 return RESULT_SHOWUSAGE;
1061 if (sscanf(argv[2], "%d", &num) != 1)
1062 return RESULT_SHOWUSAGE;
1063 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
1065 return RESULT_SUCCESS;
1066 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1067 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1070 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1075 return RESULT_SHOWUSAGE;
1076 if (sscanf(argv[2], "%d", &num) != 1)
1077 return RESULT_SHOWUSAGE;
1079 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1080 if (res == 1) /* New command */
1081 return RESULT_SUCCESS;
1082 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1083 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1086 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1091 return RESULT_SHOWUSAGE;
1093 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1094 if (res == 1) /* New command */
1095 return RESULT_SUCCESS;
1096 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1097 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1100 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1105 return RESULT_SHOWUSAGE;
1106 if (sscanf(argv[2], "%d", &num) != 1)
1107 return RESULT_SHOWUSAGE;
1108 res = ast_say_date(chan, num, argv[3], chan->language);
1110 return RESULT_SUCCESS;
1111 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1112 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1115 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1120 return RESULT_SHOWUSAGE;
1121 if (sscanf(argv[2], "%d", &num) != 1)
1122 return RESULT_SHOWUSAGE;
1123 res = ast_say_time(chan, num, argv[3], chan->language);
1125 return RESULT_SUCCESS;
1126 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1127 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1130 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1134 char *format, *zone = NULL;
1137 return RESULT_SHOWUSAGE;
1142 /* XXX this doesn't belong here, but in the 'say' module */
1143 if (!strcasecmp(chan->language, "de")) {
1144 format = "A dBY HMS";
1146 format = "ABdY 'digits/at' IMp";
1150 if (argc > 5 && !ast_strlen_zero(argv[5]))
1153 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
1154 return RESULT_SHOWUSAGE;
1156 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
1158 return RESULT_SUCCESS;
1160 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1161 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1164 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1169 return RESULT_SHOWUSAGE;
1171 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1172 if (res == 1) /* New command */
1173 return RESULT_SUCCESS;
1174 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1175 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1178 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1180 int res, max, timeout;
1184 return RESULT_SHOWUSAGE;
1186 timeout = atoi(argv[3]);
1190 max = atoi(argv[4]);
1193 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
1194 if (res == 2) /* New command */
1195 return RESULT_SUCCESS;
1197 ast_agi_fdprintf(chan, agi->fd, "200 result=%s (timeout)\n", data);
1199 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1201 ast_agi_fdprintf(chan, agi->fd, "200 result=%s\n", data);
1202 return RESULT_SUCCESS;
1205 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1209 return RESULT_SHOWUSAGE;
1210 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
1211 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1212 return RESULT_SUCCESS;
1215 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1218 return RESULT_SHOWUSAGE;
1219 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
1220 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1221 return RESULT_SUCCESS;
1224 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1229 return RESULT_SHOWUSAGE;
1231 if (sscanf(argv[2], "%d", &pri) != 1) {
1232 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
1233 return RESULT_SHOWUSAGE;
1236 ast_explicit_goto(chan, NULL, NULL, pri);
1237 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1238 return RESULT_SUCCESS;
1241 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1243 struct ast_filestream *fs;
1244 struct ast_frame *f;
1245 struct timeval start;
1246 long sample_offset = 0;
1250 struct ast_dsp *sildet=NULL; /* silence detector dsp */
1251 int totalsilence = 0;
1253 int silence = 0; /* amount of silence to allow */
1254 int gotsilence = 0; /* did we timeout for silence? */
1255 char *silencestr=NULL;
1259 /* XXX EAGI FIXME XXX */
1262 return RESULT_SHOWUSAGE;
1263 if (sscanf(argv[5], "%d", &ms) != 1)
1264 return RESULT_SHOWUSAGE;
1267 silencestr = strchr(argv[6],'s');
1268 if ((argc > 7) && (!silencestr))
1269 silencestr = strchr(argv[7],'s');
1270 if ((argc > 8) && (!silencestr))
1271 silencestr = strchr(argv[8],'s');
1274 if (strlen(silencestr) > 2) {
1275 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
1279 silence = atoi(silencestr);
1287 rfmt = chan->readformat;
1288 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1290 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1293 sildet = ast_dsp_new();
1295 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1298 ast_dsp_set_threshold(sildet, 256);
1301 /* backward compatibility, if no offset given, arg[6] would have been
1302 * caught below and taken to be a beep, else if it is a digit then it is a
1304 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
1305 res = ast_streamfile(chan, "beep", chan->language);
1307 if ((argc > 7) && (!strchr(argv[7], '=')))
1308 res = ast_streamfile(chan, "beep", chan->language);
1311 res = ast_waitstream(chan, argv[4]);
1313 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
1315 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
1318 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (writefile)\n", res);
1320 ast_dsp_free(sildet);
1321 return RESULT_FAILURE;
1324 /* Request a video update */
1325 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
1328 ast_applystream(chan,fs);
1329 /* really should have checks */
1330 ast_seekstream(fs, sample_offset, SEEK_SET);
1331 ast_truncstream(fs);
1333 start = ast_tvnow();
1334 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
1335 res = ast_waitfor(chan, -1);
1337 ast_closestream(fs);
1338 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
1340 ast_dsp_free(sildet);
1341 return RESULT_FAILURE;
1345 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
1346 ast_closestream(fs);
1348 ast_dsp_free(sildet);
1349 return RESULT_FAILURE;
1351 switch(f->frametype) {
1352 case AST_FRAME_DTMF:
1353 if (strchr(argv[4], f->subclass)) {
1354 /* This is an interrupting chracter, so rewind to chop off any small
1355 amount of DTMF that may have been recorded
1357 ast_stream_rewind(fs, 200);
1358 ast_truncstream(fs);
1359 sample_offset = ast_tellstream(fs);
1360 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1361 ast_closestream(fs);
1364 ast_dsp_free(sildet);
1365 return RESULT_SUCCESS;
1368 case AST_FRAME_VOICE:
1369 ast_writestream(fs, f);
1370 /* this is a safe place to check progress since we know that fs
1371 * is valid after a write, and it will then have our current
1373 sample_offset = ast_tellstream(fs);
1376 ast_dsp_silence(sildet, f, &dspsilence);
1378 totalsilence = dspsilence;
1382 if (totalsilence > silence) {
1383 /* Ended happily with silence */
1389 case AST_FRAME_VIDEO:
1390 ast_writestream(fs, f);
1392 /* Ignore all other frames */
1401 ast_stream_rewind(fs, silence-1000);
1402 ast_truncstream(fs);
1403 sample_offset = ast_tellstream(fs);
1405 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1406 ast_closestream(fs);
1410 res = ast_set_read_format(chan, rfmt);
1412 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1413 ast_dsp_free(sildet);
1415 return RESULT_SUCCESS;
1418 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1423 return RESULT_SHOWUSAGE;
1424 if (sscanf(argv[2], "%d", &timeout) != 1)
1425 return RESULT_SHOWUSAGE;
1429 chan->whentohangup = time(NULL) + timeout;
1431 chan->whentohangup = 0;
1432 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1433 return RESULT_SUCCESS;
1436 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1438 struct ast_channel *c;
1441 /* no argument: hangup the current channel */
1442 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1443 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1444 return RESULT_SUCCESS;
1445 } else if (argc == 2) {
1446 /* one argument: look for info on the specified channel */
1447 c = ast_get_channel_by_name_locked(argv[1]);
1449 /* we have a matching channel */
1450 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1451 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1452 ast_channel_unlock(c);
1453 return RESULT_SUCCESS;
1455 /* if we get this far no channel name matched the argument given */
1456 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1457 return RESULT_SUCCESS;
1459 return RESULT_SHOWUSAGE;
1463 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1466 struct ast_app *app;
1469 return RESULT_SHOWUSAGE;
1471 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1473 if ((app = pbx_findapp(argv[1]))) {
1474 res = pbx_exec(chan, app, argv[2]);
1476 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1479 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1481 /* Even though this is wrong, users are depending upon this result. */
1485 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1488 char *l = NULL, *n = NULL;
1491 ast_copy_string(tmp, argv[2], sizeof(tmp));
1492 ast_callerid_parse(tmp, &n, &l);
1494 ast_shrink_phone_number(l);
1499 ast_set_callerid(chan, l, n, NULL);
1502 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1503 return RESULT_SUCCESS;
1506 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1508 struct ast_channel *c;
1510 /* no argument: supply info on the current channel */
1511 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1512 return RESULT_SUCCESS;
1513 } else if (argc == 3) {
1514 /* one argument: look for info on the specified channel */
1515 c = ast_get_channel_by_name_locked(argv[2]);
1517 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1518 ast_channel_unlock(c);
1519 return RESULT_SUCCESS;
1521 /* if we get this far no channel name matched the argument given */
1522 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1523 return RESULT_SUCCESS;
1525 return RESULT_SHOWUSAGE;
1529 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1532 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1534 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1535 return RESULT_SUCCESS;
1538 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1544 return RESULT_SHOWUSAGE;
1546 /* check if we want to execute an ast_custom_function */
1547 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1548 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1550 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1554 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1556 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1558 return RESULT_SUCCESS;
1561 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1564 struct ast_channel *chan2=NULL;
1566 if ((argc != 4) && (argc != 5))
1567 return RESULT_SHOWUSAGE;
1569 chan2 = ast_get_channel_by_name_locked(argv[4]);
1574 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1575 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1577 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1579 if (chan2 && (chan2 != chan))
1580 ast_channel_unlock(chan2);
1581 return RESULT_SUCCESS;
1584 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1590 return RESULT_SHOWUSAGE;
1593 sscanf(argv[2], "%d", &level);
1597 prefix = VERBOSE_PREFIX_4;
1600 prefix = VERBOSE_PREFIX_3;
1603 prefix = VERBOSE_PREFIX_2;
1607 prefix = VERBOSE_PREFIX_1;
1611 if (level <= option_verbose)
1612 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
1614 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1616 return RESULT_SUCCESS;
1619 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1625 return RESULT_SHOWUSAGE;
1626 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1628 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1630 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1632 return RESULT_SUCCESS;
1635 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1640 return RESULT_SHOWUSAGE;
1641 res = ast_db_put(argv[2], argv[3], argv[4]);
1642 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1643 return RESULT_SUCCESS;
1646 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1651 return RESULT_SHOWUSAGE;
1652 res = ast_db_del(argv[2], argv[3]);
1653 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1654 return RESULT_SUCCESS;
1657 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1661 if ((argc < 3) || (argc > 4))
1662 return RESULT_SHOWUSAGE;
1664 res = ast_db_deltree(argv[2], argv[3]);
1666 res = ast_db_deltree(argv[2], NULL);
1668 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1669 return RESULT_SUCCESS;
1672 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1676 e->command = "agi debug [off]";
1678 "Usage: agi debug [off]\n"
1679 " Enables/disables dumping of AGI transactions for\n"
1680 " debugging purposes.\n";
1686 if (a->argc < e->args - 1 || a->argc > e->args )
1687 return CLI_SHOWUSAGE;
1688 if (a->argc == e->args - 1) {
1691 if (strncasecmp(a->argv[e->args - 1], "off", 3) == 0) {
1694 return CLI_SHOWUSAGE;
1697 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1701 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1703 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1704 return RESULT_SUCCESS;
1707 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1709 if (!strncasecmp(argv[2], "on", 2))
1710 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1711 else if (!strncasecmp(argv[2], "off", 3))
1713 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1714 return RESULT_SUCCESS;
1717 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1719 /* If a structure already exists, return an error */
1721 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1722 return RESULT_SUCCESS;
1725 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1726 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1728 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1730 return RESULT_SUCCESS;
1733 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1735 /* Check for minimum arguments */
1737 return RESULT_SHOWUSAGE;
1739 /* Check to make sure speech structure exists */
1741 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1742 return RESULT_SUCCESS;
1745 ast_speech_change(agi->speech, argv[2], argv[3]);
1746 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1748 return RESULT_SUCCESS;
1751 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1754 ast_speech_destroy(agi->speech);
1756 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1758 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1761 return RESULT_SUCCESS;
1764 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1767 return RESULT_SHOWUSAGE;
1770 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1771 return RESULT_SUCCESS;
1774 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
1775 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1777 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1779 return RESULT_SUCCESS;
1782 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1785 return RESULT_SHOWUSAGE;
1788 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1789 return RESULT_SUCCESS;
1792 if (ast_speech_grammar_unload(agi->speech, argv[3]))
1793 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1795 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1797 return RESULT_SUCCESS;
1800 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1803 return RESULT_SHOWUSAGE;
1806 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1807 return RESULT_SUCCESS;
1810 if (ast_speech_grammar_activate(agi->speech, argv[3]))
1811 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1813 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1815 return RESULT_SUCCESS;
1818 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1821 return RESULT_SHOWUSAGE;
1824 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1825 return RESULT_SUCCESS;
1828 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
1829 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1831 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1833 return RESULT_SUCCESS;
1836 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
1838 struct ast_filestream *fs = NULL;
1840 if (!(fs = ast_openstream(chan, filename, preflang)))
1844 ast_seekstream(fs, offset, SEEK_SET);
1846 if (ast_applystream(chan, fs))
1849 if (ast_playstream(fs))
1855 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1857 struct ast_speech *speech = agi->speech;
1858 char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
1859 int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
1860 long current_offset = 0;
1861 const char *reason = NULL;
1862 struct ast_frame *fr = NULL;
1863 struct ast_speech_result *result = NULL;
1864 size_t left = sizeof(tmp);
1865 time_t start = 0, current;
1868 return RESULT_SHOWUSAGE;
1871 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1872 return RESULT_SUCCESS;
1876 timeout = atoi(argv[3]);
1878 /* If offset is specified then convert from text to integer */
1880 offset = atoi(argv[4]);
1882 /* We want frames coming in signed linear */
1883 old_read_format = chan->readformat;
1884 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1885 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1886 return RESULT_SUCCESS;
1889 /* Setup speech structure */
1890 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
1891 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1892 ast_speech_start(speech);
1895 /* Start playing prompt */
1896 speech_streamfile(chan, prompt, chan->language, offset);
1898 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
1899 while (ast_strlen_zero(reason)) {
1900 /* Run scheduled items */
1901 ast_sched_runq(chan->sched);
1903 /* See maximum time of waiting */
1904 if ((res = ast_sched_wait(chan->sched)) < 0)
1907 /* Wait for frame */
1908 if (ast_waitfor(chan, res) > 0) {
1909 if (!(fr = ast_read(chan))) {
1915 /* Perform timeout check */
1916 if ((timeout > 0) && (start > 0)) {
1918 if ((current - start) >= timeout) {
1926 /* Check the speech structure for any changes */
1927 ast_mutex_lock(&speech->lock);
1929 /* See if we need to quiet the audio stream playback */
1930 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
1931 current_offset = ast_tellstream(chan->stream);
1932 ast_stopstream(chan);
1933 ast_clear_flag(speech, AST_SPEECH_QUIET);
1936 /* Check each state */
1937 switch (speech->state) {
1938 case AST_SPEECH_STATE_READY:
1939 /* If the stream is done, start timeout calculation */
1940 if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
1941 ast_stopstream(chan);
1944 /* Write audio frame data into speech engine if possible */
1945 if (fr && fr->frametype == AST_FRAME_VOICE)
1946 ast_speech_write(speech, fr->data, fr->datalen);
1948 case AST_SPEECH_STATE_WAIT:
1949 /* Cue waiting sound if not already playing */
1950 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
1951 ast_stopstream(chan);
1952 /* If a processing sound exists, or is not none - play it */
1953 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
1954 speech_streamfile(chan, speech->processing_sound, chan->language, 0);
1957 case AST_SPEECH_STATE_DONE:
1958 /* Get the results */
1959 speech->results = ast_speech_results_get(speech);
1960 /* Change state to not ready */
1961 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1967 ast_mutex_unlock(&speech->lock);
1969 /* Check frame for DTMF or hangup */
1971 if (fr->frametype == AST_FRAME_DTMF) {
1973 dtmf = fr->subclass;
1974 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
1981 if (!strcasecmp(reason, "speech")) {
1982 /* Build string containing speech results */
1983 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
1984 /* Build result string */
1985 ast_build_string(&buf, &left, "%sscore%d=%d text%d=\"%s\" grammar%d=%s", (i > 0 ? " " : ""), i, result->score, i, result->text, i, result->grammar);
1986 /* Increment result count */
1990 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
1991 } else if (!strcasecmp(reason, "dtmf")) {
1992 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
1993 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
1994 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
1996 ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
1999 return RESULT_SUCCESS;
2002 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
2004 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
2005 return AST_PBX_KEEPALIVE;
2008 static char usage_setmusic[] =
2009 " Usage: SET MUSIC ON <on|off> <class>\n"
2010 " Enables/Disables the music on hold generator. If <class> is\n"
2011 " not specified, then the default music on hold class will be used.\n"
2012 " Always returns 0.\n";
2014 static char usage_dbput[] =
2015 " Usage: DATABASE PUT <family> <key> <value>\n"
2016 " Adds or updates an entry in the Asterisk database for a\n"
2017 " given family, key, and value.\n"
2018 " Returns 1 if successful, 0 otherwise.\n";
2020 static char usage_dbget[] =
2021 " Usage: DATABASE GET <family> <key>\n"
2022 " Retrieves an entry in the Asterisk database for a\n"
2023 " given family and key.\n"
2024 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
2025 " is set and returns the variable in parentheses.\n"
2026 " Example return code: 200 result=1 (testvariable)\n";
2028 static char usage_dbdel[] =
2029 " Usage: DATABASE DEL <family> <key>\n"
2030 " Deletes an entry in the Asterisk database for a\n"
2031 " given family and key.\n"
2032 " Returns 1 if successful, 0 otherwise.\n";
2034 static char usage_dbdeltree[] =
2035 " Usage: DATABASE DELTREE <family> [keytree]\n"
2036 " Deletes a family or specific keytree within a family\n"
2037 " in the Asterisk database.\n"
2038 " Returns 1 if successful, 0 otherwise.\n";
2040 static char usage_verbose[] =
2041 " Usage: VERBOSE <message> <level>\n"
2042 " Sends <message> to the console via verbose message system.\n"
2043 " <level> is the the verbose level (1-4)\n"
2044 " Always returns 1.\n";
2046 static char usage_getvariable[] =
2047 " Usage: GET VARIABLE <variablename>\n"
2048 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
2049 " is set and returns the variable in parentheses.\n"
2050 " example return code: 200 result=1 (testvariable)\n";
2052 static char usage_getvariablefull[] =
2053 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
2054 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
2055 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
2056 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
2057 " example return code: 200 result=1 (testvariable)\n";
2059 static char usage_setvariable[] =
2060 " Usage: SET VARIABLE <variablename> <value>\n";
2062 static char usage_channelstatus[] =
2063 " Usage: CHANNEL STATUS [<channelname>]\n"
2064 " Returns the status of the specified channel.\n"
2065 " If no channel name is given the returns the status of the\n"
2066 " current channel. Return values:\n"
2067 " 0 Channel is down and available\n"
2068 " 1 Channel is down, but reserved\n"
2069 " 2 Channel is off hook\n"
2070 " 3 Digits (or equivalent) have been dialed\n"
2071 " 4 Line is ringing\n"
2072 " 5 Remote end is ringing\n"
2074 " 7 Line is busy\n";
2076 static char usage_setcallerid[] =
2077 " Usage: SET CALLERID <number>\n"
2078 " Changes the callerid of the current channel.\n";
2080 static char usage_exec[] =
2081 " Usage: EXEC <application> <options>\n"
2082 " Executes <application> with given <options>.\n"
2083 " Returns whatever the application returns, or -2 on failure to find application\n";
2085 static char usage_hangup[] =
2086 " Usage: HANGUP [<channelname>]\n"
2087 " Hangs up the specified channel.\n"
2088 " If no channel name is given, hangs up the current channel\n";
2090 static char usage_answer[] =
2092 " Answers channel if not already in answer state. Returns -1 on\n"
2093 " channel failure, or 0 if successful.\n";
2095 static char usage_waitfordigit[] =
2096 " Usage: WAIT FOR DIGIT <timeout>\n"
2097 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2098 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2099 " the numerical value of the ascii of the digit if one is received. Use -1\n"
2100 " for the timeout value if you desire the call to block indefinitely.\n";
2102 static char usage_sendtext[] =
2103 " Usage: SEND TEXT \"<text to send>\"\n"
2104 " Sends the given text on a channel. Most channels do not support the\n"
2105 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
2106 " support text transmission. Returns -1 only on error/hangup. Text\n"
2107 " consisting of greater than one word should be placed in quotes since the\n"
2108 " command only accepts a single argument.\n";
2110 static char usage_recvchar[] =
2111 " Usage: RECEIVE CHAR <timeout>\n"
2112 " Receives a character of text on a channel. Specify timeout to be the\n"
2113 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2114 " do not support the reception of text. Returns the decimal value of the character\n"
2115 " if one is received, or 0 if the channel does not support text reception. Returns\n"
2116 " -1 only on error/hangup.\n";
2118 static char usage_recvtext[] =
2119 " Usage: RECEIVE TEXT <timeout>\n"
2120 " Receives a string of text on a channel. Specify timeout to be the\n"
2121 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2122 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2124 static char usage_tddmode[] =
2125 " Usage: TDD MODE <on|off>\n"
2126 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2127 " successful, or 0 if channel is not TDD-capable.\n";
2129 static char usage_sendimage[] =
2130 " Usage: SEND IMAGE <image>\n"
2131 " Sends the given image on a channel. Most channels do not support the\n"
2132 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2133 " support image transmission. Returns -1 only on error/hangup. Image names\n"
2134 " should not include extensions.\n";
2136 static char usage_streamfile[] =
2137 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2138 " Send the given file, allowing playback to be interrupted by the given\n"
2139 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2140 " permitted. If sample offset is provided then the audio will seek to sample\n"
2141 " offset before play starts. Returns 0 if playback completes without a digit\n"
2142 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2143 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2144 " extension must not be included in the filename.\n";
2146 static char usage_controlstreamfile[] =
2147 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2148 " Send the given file, allowing playback to be controled by the given\n"
2149 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2150 " permitted. Returns 0 if playback completes without a digit\n"
2151 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2152 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2153 " extension must not be included in the filename.\n\n"
2154 " Note: ffchar and rewchar default to * and # respectively.\n";
2156 static char usage_getoption[] =
2157 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2158 " Behaves similar to STREAM FILE but used with a timeout option.\n";
2160 static char usage_saynumber[] =
2161 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2162 " Say a given number, returning early if any of the given DTMF digits\n"
2163 " are received on the channel. Returns 0 if playback completes without a digit\n"
2164 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2165 " -1 on error/hangup.\n";
2167 static char usage_saydigits[] =
2168 " Usage: SAY DIGITS <number> <escape digits>\n"
2169 " Say a given digit string, returning early if any of the given DTMF digits\n"
2170 " are received on the channel. Returns 0 if playback completes without a digit\n"
2171 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2172 " -1 on error/hangup.\n";
2174 static char usage_sayalpha[] =
2175 " Usage: SAY ALPHA <number> <escape digits>\n"
2176 " Say a given character string, returning early if any of the given DTMF digits\n"
2177 " are received on the channel. Returns 0 if playback completes without a digit\n"
2178 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2179 " -1 on error/hangup.\n";
2181 static char usage_saydate[] =
2182 " Usage: SAY DATE <date> <escape digits>\n"
2183 " Say a given date, returning early if any of the given DTMF digits are\n"
2184 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
2185 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2186 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2187 " digit if one was pressed or -1 on error/hangup.\n";
2189 static char usage_saytime[] =
2190 " Usage: SAY TIME <time> <escape digits>\n"
2191 " Say a given time, returning early if any of the given DTMF digits are\n"
2192 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2193 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2194 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2195 " digit if one was pressed or -1 on error/hangup.\n";
2197 static char usage_saydatetime[] =
2198 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2199 " Say a given time, returning early if any of the given DTMF digits are\n"
2200 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2201 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2202 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
2203 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
2204 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
2205 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2206 " digit if one was pressed or -1 on error/hangup.\n";
2208 static char usage_sayphonetic[] =
2209 " Usage: SAY PHONETIC <string> <escape digits>\n"
2210 " Say a given character string with phonetics, returning early if any of the\n"
2211 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2212 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2213 " if one was pressed, or -1 on error/hangup.\n";
2215 static char usage_getdata[] =
2216 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
2217 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
2218 "from the channel at the other end.\n";
2220 static char usage_setcontext[] =
2221 " Usage: SET CONTEXT <desired context>\n"
2222 " Sets the context for continuation upon exiting the application.\n";
2224 static char usage_setextension[] =
2225 " Usage: SET EXTENSION <new extension>\n"
2226 " Changes the extension for continuation upon exiting the application.\n";
2228 static char usage_setpriority[] =
2229 " Usage: SET PRIORITY <priority>\n"
2230 " Changes the priority for continuation upon exiting the application.\n"
2231 " The priority must be a valid priority or label.\n";
2233 static char usage_recordfile[] =
2234 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2235 " [offset samples] [BEEP] [s=silence]\n"
2236 " Record to a file until a given dtmf digit in the sequence is received\n"
2237 " Returns -1 on hangup or error. The format will specify what kind of file\n"
2238 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
2239 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2240 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
2241 " of seconds of silence allowed before the function returns despite the\n"
2242 " lack of dtmf digits or reaching timeout. Silence value must be\n"
2243 " preceeded by \"s=\" and is also optional.\n";
2245 static char usage_autohangup[] =
2246 " Usage: SET AUTOHANGUP <time>\n"
2247 " Cause the channel to automatically hangup at <time> seconds in the\n"
2248 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
2249 " cause the autohangup feature to be disabled on this channel.\n";
2251 static char usage_break_aagi[] =
2252 " Usage: ASYNCAGI BREAK\n"
2253 " Break the Async AGI loop.\n";
2255 static char usage_noop[] =
2259 static char usage_speechcreate[] =
2260 " Usage: SPEECH CREATE <engine>\n"
2261 " Create a speech object to be used by the other Speech AGI commands.\n";
2263 static char usage_speechset[] =
2264 " Usage: SPEECH SET <name> <value>\n"
2265 " Set an engine-specific setting.\n";
2267 static char usage_speechdestroy[] =
2268 " Usage: SPEECH DESTROY\n"
2269 " Destroy the speech object created by SPEECH CREATE.\n";
2271 static char usage_speechloadgrammar[] =
2272 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2273 " Loads the specified grammar as the specified name.\n";
2275 static char usage_speechunloadgrammar[] =
2276 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2277 " Unloads the specified grammar.\n";
2279 static char usage_speechactivategrammar[] =
2280 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2281 " Activates the specified grammar on the speech object.\n";
2283 static char usage_speechdeactivategrammar[] =
2284 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2285 " Deactivates the specified grammar on the speech object.\n";
2287 static char usage_speechrecognize[] =
2288 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2289 " Plays back given prompt while listening for speech and dtmf.\n";
2292 * \brief AGI commands list
2294 static struct agi_command commands[] = {
2295 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
2296 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
2297 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
2298 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
2299 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
2300 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
2301 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
2302 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
2303 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
2304 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2305 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2306 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2307 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2308 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2309 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2310 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2311 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2312 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2313 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2314 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2315 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2316 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2317 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2318 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2319 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2320 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2321 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2322 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2323 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2324 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
2325 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2326 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2327 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2328 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2329 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2330 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2331 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2332 { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2333 { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2334 { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2335 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2336 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2337 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2338 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2339 { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2340 { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2343 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2345 static char *help_workhorse(int fd, char *match[])
2347 char fullcmd[80], matchstr[80];
2348 struct agi_command *e;
2351 ast_join(matchstr, sizeof(matchstr), match);
2353 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
2354 AST_RWLIST_RDLOCK(&agi_commands);
2355 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2358 /* Hide commands that start with '_' */
2359 if ((e->cmda[0])[0] == '_')
2361 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2362 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2364 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2366 AST_RWLIST_UNLOCK(&agi_commands);
2371 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2375 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2377 if (!find_command(cmd->cmda,1)) {
2379 AST_RWLIST_WRLOCK(&agi_commands);
2380 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2381 AST_RWLIST_UNLOCK(&agi_commands);
2382 if (mod != ast_module_info->self)
2383 ast_module_ref(ast_module_info->self);
2384 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2387 ast_log(LOG_WARNING, "Command already registered!\n");
2392 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2394 struct agi_command *e;
2395 int unregistered = 0;
2398 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2400 AST_RWLIST_WRLOCK(&agi_commands);
2401 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2403 AST_RWLIST_REMOVE_CURRENT(list);
2404 if (mod != ast_module_info->self)
2405 ast_module_unref(ast_module_info->self);
2410 AST_RWLIST_TRAVERSE_SAFE_END;
2411 AST_RWLIST_UNLOCK(&agi_commands);
2413 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2415 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2416 return unregistered;
2419 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
2423 for (i = 0; i < len; i++)
2424 ast_agi_register(mod, cmd + i);
2428 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
2432 for (i = 0; i < len; i++)
2433 ast_agi_unregister(mod, cmd + i);
2436 static agi_command *find_command(char *cmds[], int exact)
2439 struct agi_command *e;
2441 AST_RWLIST_RDLOCK(&agi_commands);
2442 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2445 /* start optimistic */
2447 for (y = 0; match && cmds[y]; y++) {
2448 /* If there are no more words in the command (and we're looking for
2449 an exact match) or there is a difference between the two words,
2450 then this is not a match */
2451 if (!e->cmda[y] && !exact)
2453 /* don't segfault if the next part of a command doesn't exist */
2456 if (strcasecmp(e->cmda[y], cmds[y]))
2459 /* If more words are needed to complete the command then this is not
2460 a candidate (unless we're looking for a really inexact answer */
2461 if ((exact > -1) && e->cmda[y])
2466 AST_RWLIST_UNLOCK(&agi_commands);
2470 static int parse_args(char *s, int *max, char *argv[])
2472 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2479 /* If it's escaped, put a literal quote */
2484 if (quoted && whitespace) {
2485 /* If we're starting a quote, coming off white space start a new word, too */
2493 if (!quoted && !escaped) {
2494 /* If we're not quoted, mark this as whitespace, and
2495 end the previous argument */
2499 /* Otherwise, just treat it as anything else */
2503 /* If we're escaped, print a literal, otherwise enable escaping */
2513 if (x >= MAX_ARGS -1) {
2514 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2517 /* Coming off of whitespace, start the next argument */
2526 /* Null terminate */
2533 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2535 char *argv[MAX_ARGS];
2536 int argc = MAX_ARGS, res;
2538 const char *ami_res = "Unknown Result";
2539 char *ami_cmd = ast_strdupa(buf);
2540 int command_id = ast_random(), resultcode = 200;
2542 manager_event(EVENT_FLAG_CALL, "AGIExec",
2543 "SubEvent: Start\r\n"
2546 "Command: %s\r\n", chan->name, command_id, ami_cmd);
2547 parse_args(buf, &argc, argv);
2548 if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2549 /* if this command wasnt registered by res_agi, be sure to usecount
2550 the module we are using */
2551 if (c->mod != ast_module_info->self)
2552 ast_module_ref(c->mod);
2553 res = c->handler(chan, agi, argc, argv);
2554 if (c->mod != ast_module_info->self)
2555 ast_module_unref(c->mod);
2557 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2558 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2559 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2560 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2562 manager_event(EVENT_FLAG_CALL, "AGIExec",
2567 "ResultCode: %d\r\n"
2568 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2570 case RESULT_SHOWUSAGE:
2571 ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
2572 ast_agi_fdprintf(chan, agi->fd, c->usage);
2573 ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
2575 case AST_PBX_KEEPALIVE:
2576 /* We've been asked to keep alive, so do so */
2577 return AST_PBX_KEEPALIVE;
2579 case RESULT_FAILURE:
2580 /* They've already given the failure. We've been hung up on so handle this
2584 } else if ((c = find_command(argv, 0))) {
2585 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
2586 manager_event(EVENT_FLAG_CALL, "AGIExec",
2591 "ResultCode: 511\r\n"
2592 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2594 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
2595 manager_event(EVENT_FLAG_CALL, "AGIExec",
2600 "ResultCode: 510\r\n"
2601 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2605 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2607 struct ast_channel *c;
2608 int outfd, ms, needhup = 0;
2609 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2610 struct ast_frame *f;
2611 char buf[AGI_BUF_LEN];
2614 /* how many times we'll retry if ast_waitfor_nandfs will return without either
2615 channel or file descriptor in case select is interrupted by a system call (EINTR) */
2616 int retry = AGI_NANDFS_RETRY;
2618 if (!(readf = fdopen(agi->ctrl, "r"))) {
2619 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2623 return AGI_RESULT_FAILURE;
2626 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2635 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2637 retry = AGI_NANDFS_RETRY;
2638 /* Idle the channel until we get a command */
2641 ast_debug(1, "%s hungup\n", chan->name);
2642 returnstatus = AGI_RESULT_HANGUP;
2646 /* If it's voice, write it to the audio pipe */
2647 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2648 /* Write, ignoring errors */
2649 write(agi->audio, f->data, f->datalen);
2653 } else if (outfd > -1) {
2654 size_t len = sizeof(buf);
2657 retry = AGI_NANDFS_RETRY;
2660 while (buflen < (len - 1)) {
2661 res = fgets(buf + buflen, len, readf);
2664 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
2666 if (res != NULL && !agi->fast)
2668 buflen = strlen(buf);
2669 if (buflen && buf[buflen - 1] == '\n')
2673 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2677 /* Program terminated */
2678 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2680 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2682 waitpid(pid, status, 0);
2683 /* No need to kill the pid anymore, since they closed us */
2688 /* get rid of trailing newline, if any */
2689 if (*buf && buf[strlen(buf) - 1] == '\n')
2690 buf[strlen(buf) - 1] = 0;
2692 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2693 returnstatus |= agi_handle_command(chan, agi, buf, dead);
2694 /* If the handle_command returns -1, we need to stop */
2695 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2701 ast_log(LOG_WARNING, "No channel, no fd?\n");
2702 returnstatus = AGI_RESULT_FAILURE;
2707 /* Notify process */
2709 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2710 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2711 if (kill(pid, SIGHUP))
2712 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2716 return returnstatus;
2719 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2721 struct agi_command *command;
2726 e->command = "agi show";
2728 "Usage: agi show [topic]\n"
2729 " When called with a topic as an argument, displays usage\n"
2730 " information on the given command. If called without a\n"
2731 " topic, it provides a list of AGI commands.\n";
2736 if (a->argc < e->args)
2737 return CLI_SHOWUSAGE;
2738 if (a->argc > e->args) {
2739 command = find_command(a->argv + e->args, 1);
2741 ast_cli(a->fd, command->usage);
2742 ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2744 if (find_command(a->argv + e->args, -1)) {
2745 return help_workhorse(a->fd, a->argv + e->args);
2747 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2748 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2752 return help_workhorse(a->fd, NULL);
2757 /*! \brief Convert string to use HTML escaped characters
2758 \note Maybe this should be a generic function?
2760 static void write_html_escaped(FILE *htmlfile, char *str)
2767 fprintf(htmlfile, "%s", "<");
2770 fprintf(htmlfile, "%s", ">");
2773 fprintf(htmlfile, "%s", "&");
2776 fprintf(htmlfile, "%s", """);
2779 fprintf(htmlfile, "%c", *cur);
2788 static char *handle_cli_agi_dumphtml(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2790 struct agi_command *command;
2796 e->command = "agi dumphtml";
2798 "Usage: agi dumphtml <filename>\n"
2799 " Dumps the AGI command list in HTML format to the given\n"
2805 if (a->argc < e->args + 1)
2806 return CLI_SHOWUSAGE;
2808 if (!(htmlfile = fopen(a->argv[2], "wt"))) {
2809 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2810 return CLI_SHOWUSAGE;
2813 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2814 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2815 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2817 AST_RWLIST_RDLOCK(&agi_commands);
2818 AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2819 char *stringp, *tempstr;
2821 if (!command->cmda[0]) /* end ? */
2823 /* Hide commands that start with '_' */
2824 if ((command->cmda[0])[0] == '_')
2826 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2828 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2829 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2831 stringp = command->usage;
2832 tempstr = strsep(&stringp, "\n");
2834 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2835 write_html_escaped(htmlfile, tempstr);
2836 fprintf(htmlfile, "</TD></TR>\n");
2837 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2839 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2840 write_html_escaped(htmlfile, tempstr);
2841 fprintf(htmlfile, "<BR>\n");
2843 fprintf(htmlfile, "</TD></TR>\n");
2844 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2846 AST_RWLIST_UNLOCK(&agi_commands);
2847 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2849 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2853 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2855 enum agi_result res;
2856 struct ast_module_user *u;
2857 char buf[AGI_BUF_LEN] = "", *tmp = buf;
2858 int fds[2], efd = -1, pid;
2859 AST_DECLARE_APP_ARGS(args,
2860 AST_APP_ARG(arg)[MAX_ARGS];
2864 if (ast_strlen_zero(data)) {
2865 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2869 ast_log(LOG_NOTICE, "Hungup channel detected, running agi in dead mode.\n");
2870 ast_copy_string(buf, data, sizeof(buf));
2871 memset(&agi, 0, sizeof(agi));
2872 AST_STANDARD_APP_ARGS(args, tmp);
2873 args.argv[args.argc] = NULL;
2875 u = ast_module_user_add(chan);
2877 /* Answer if need be */
2878 if (chan->_state != AST_STATE_UP) {
2879 if (ast_answer(chan)) {
2880 ast_module_user_remove(u);
2885 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2886 /* Async AGI do not require run_agi(), so just proceed if normal AGI
2887 or Fast AGI are setup with success. */
2888 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2893 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2894 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2895 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2896 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2897 res = AGI_RESULT_FAILURE;
2898 if (fds[1] != fds[0])
2902 ast_unreplace_sigchld();
2904 ast_module_user_remove(u);
2907 case AGI_RESULT_SUCCESS:
2908 case AGI_RESULT_SUCCESS_FAST:
2909 case AGI_RESULT_SUCCESS_ASYNC:
2910 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2912 case AGI_RESULT_FAILURE:
2913 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2915 case AGI_RESULT_NOTFOUND:
2916 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2918 case AGI_RESULT_HANGUP:
2919 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2926 static int agi_exec(struct ast_channel *chan, void *data)
2928 if (!ast_check_hangup(chan))
2929 return agi_exec_full(chan, data, 0, 0);
2931 return agi_exec_full(chan, data, 0, 1);
2934 static int eagi_exec(struct ast_channel *chan, void *data)
2936 int readformat, res;
2938 if (ast_check_hangup(chan)) {
2939 ast_log(LOG_ERROR, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
2942 readformat = chan->readformat;
2943 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2944 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2947 res = agi_exec_full(chan, data, 1, 0);
2949 if (ast_set_read_format(chan, readformat)) {
2950 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2956 static int deadagi_exec(struct ast_channel *chan, void *data)
2958 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
2959 return agi_exec(chan, data);
2962 static struct ast_cli_entry cli_agi[] = {
2963 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
2964 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
2965 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
2966 AST_CLI_DEFINE(handle_cli_agi_dumphtml, "Dumps a list of AGI commands in HTML format")
2969 static int unload_module(void)
2971 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2972 ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2973 ast_unregister_application(eapp);
2974 ast_unregister_application(deadapp);
2975 ast_manager_unregister("AGI");
2976 return ast_unregister_application(app);
2979 static int load_module(void)
2981 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2982 ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2983 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
2984 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
2985 ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
2986 return ast_register_application(app, agi_exec, synopsis, descrip);
2989 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
2990 .load = load_module,
2991 .unload = unload_module,