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/ast_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 /*! \brief 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;
410 /* handlers will get the pipe write fd and we read the AGI responses
411 from the pipe read fd */
412 async_agi.fd = fds[1];
413 async_agi.ctrl = fds[1];
414 async_agi.audio = -1; /* no audio support */
417 /* notify possible manager users of a new channel ready to
419 setup_env(chan, "async", fds[1], 0, 0, NULL);
420 /* read the environment */
421 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
423 ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
424 returnstatus = AGI_RESULT_FAILURE;
427 ast_set_flag(chan, AST_FLAG_ASYNCAGI);
429 agi_buffer[res] = '\0';
430 /* encode it and send it thru the manager so whoever is going to take
431 care of AGI commands on this channel can decide which AGI commands
432 to execute based on the setup info */
433 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
434 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
436 /* bail out if we need to hangup */
437 if (ast_check_hangup(chan)) {
438 ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
441 /* retrieve a command
442 (commands are added via the manager or the cli threads) */
443 cmd = get_agi_cmd(chan);
445 /* OK, we have a command, let's call the
447 res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
448 if ((res < 0) || (res == AST_PBX_KEEPALIVE)) {
452 /* the command handler must have written to our fake
453 AGI struct fd (the pipe), let's read the response */
454 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
456 returnstatus = AGI_RESULT_FAILURE;
457 ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
461 /* we have a response, let's send the response thru the
462 manager. Include the CommandID if it was specified
463 when the command was added */
464 agi_buffer[res] = '\0';
465 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
466 if (ast_strlen_zero(cmd->cmd_id))
467 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
469 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);
472 /* no command so far, wait a bit for a frame to read */
473 res = ast_waitfor(chan, timeout);
475 ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
482 ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
483 returnstatus = AGI_RESULT_HANGUP;
486 /* is there any other frame we should care about
487 besides AST_CONTROL_HANGUP? */
488 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
489 ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
497 /* notify manager users this channel cannot be
498 controlled anymore by Async AGI */
499 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
505 /* intentionally don't get rid of the datastore. So commands can be
506 still in the queue in case AsyncAGI gets called again.
507 Datastore destructor will be called on channel destroy anyway */
515 /* launch_netscript: The fastagi handler.
516 FastAGI defaults to port 4573 */
517 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
519 int s, flags, res, port = AGI_PORT;
520 struct pollfd pfds[1];
521 char *host, *c, *script = "";
522 struct sockaddr_in sin;
524 struct ast_hostent ahp;
526 /* agiusl is "agi://host.domain[:port][/script/name]" */
527 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
528 /* Strip off any script name */
529 if ((c = strchr(host, '/'))) {
534 if ((c = strchr(host, ':'))) {
540 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
543 if (!(hp = ast_gethostbyname(host, &ahp))) {
544 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
547 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
548 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
551 if ((flags = fcntl(s, F_GETFL)) < 0) {
552 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
556 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
557 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
561 memset(&sin, 0, sizeof(sin));
562 sin.sin_family = AF_INET;
563 sin.sin_port = htons(port);
564 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
565 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
566 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
568 return AGI_RESULT_FAILURE;
572 pfds[0].events = POLLOUT;
573 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
574 if (errno != EINTR) {
576 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
577 agiurl, MAX_AGI_CONNECT);
579 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
581 return AGI_RESULT_FAILURE;
585 if (ast_agi_fdprintf(NULL, s, "agi_network: yes\n") < 0) {
586 if (errno != EINTR) {
587 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
589 return AGI_RESULT_FAILURE;
593 /* If we have a script parameter, relay it to the fastagi server */
594 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
595 if (!ast_strlen_zero(script))
596 ast_agi_fdprintf(NULL, s, "agi_network_script: %s\n", script);
598 ast_debug(4, "Wow, connected!\n");
602 return AGI_RESULT_SUCCESS_FAST;
605 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
608 int pid, toast[2], fromast[2], audio[2], res;
611 if (!strncasecmp(script, "agi://", 6)) {
612 ast_set_flag(chan, AST_FLAG_FASTAGI);
613 return launch_netscript(script, argv, fds, efd, opid);
615 if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
616 return launch_asyncagi(chan, argv, efd);
618 if (script[0] != '/') {
619 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
623 /* Before even trying let's see if the file actually exists */
624 if (stat(script, &st)) {
625 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
626 return AGI_RESULT_NOTFOUND;
630 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
631 return AGI_RESULT_FAILURE;
634 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
637 return AGI_RESULT_FAILURE;
641 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
646 return AGI_RESULT_FAILURE;
648 res = fcntl(audio[1], F_GETFL);
650 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
652 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
659 return AGI_RESULT_FAILURE;
663 if ((pid = ast_safe_fork(1)) < 0) {
664 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
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 /* Close everything but stdin/out/error */
693 ast_close_fds_above_n(STDERR_FILENO + 1);
696 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
698 /* Can't use ast_log since FD's are closed */
699 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
700 /* Special case to set status of AGI to failure */
701 fprintf(stdout, "failure\n");
705 ast_verb(3, "Launched AGI Script %s\n", script);
710 /* close what we're not using in the parent */
718 ast_set_flag(chan, AST_FLAG_AGI);
719 return AGI_RESULT_SUCCESS;
722 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
726 /* Print initial environment, with agi_request always being the first
728 ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
729 ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
730 ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
731 ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
732 ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
733 ast_agi_fdprintf(chan, fd, "agi_version: %s\n", ast_get_version());
736 ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
737 ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
738 ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
739 ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
740 ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
741 ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
742 ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
743 ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
745 /* Context information */
746 ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
747 ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
748 ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
749 ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
751 /* User information */
752 ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
753 ast_agi_fdprintf(chan, fd, "agi_threadid: %ld\n", (long)pthread_self());
755 /* Send any parameters to the fastagi server that have been passed via the agi application */
756 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
757 for(count = 1; count < argc; count++)
758 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
760 /* End with empty return */
761 ast_agi_fdprintf(chan, fd, "\n");
764 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
768 /* Answer the channel */
769 if (chan->_state != AST_STATE_UP)
770 res = ast_answer(chan);
772 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
773 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
776 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
781 return RESULT_SHOWUSAGE;
782 if (sscanf(argv[3], "%d", &to) != 1)
783 return RESULT_SHOWUSAGE;
784 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
785 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
786 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
789 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
794 return RESULT_SHOWUSAGE;
796 /* At the moment, the parser (perhaps broken) returns with
797 the last argument PLUS the newline at the end of the input
798 buffer. This probably needs to be fixed, but I wont do that
799 because other stuff may break as a result. The right way
800 would probably be to strip off the trailing newline before
801 parsing, then here, add a newline at the end of the string
802 before sending it to ast_sendtext --DUDE */
803 res = ast_sendtext(chan, argv[2]);
804 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
805 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
808 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
813 return RESULT_SHOWUSAGE;
815 res = ast_recvchar(chan,atoi(argv[2]));
817 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
818 return RESULT_SUCCESS;
821 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
822 return RESULT_SUCCESS;
824 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
825 return RESULT_FAILURE;
828 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
833 return RESULT_SHOWUSAGE;
835 buf = ast_recvtext(chan, atoi(argv[2]));
837 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
840 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
842 return RESULT_SUCCESS;
845 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
850 return RESULT_SHOWUSAGE;
852 if (!strncasecmp(argv[2],"on",2)) {
857 if (!strncasecmp(argv[2],"mate",4)) {
860 if (!strncasecmp(argv[2],"tdd",3)) {
863 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
864 if (res != RESULT_SUCCESS) {
865 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
867 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
869 return RESULT_SUCCESS;
872 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
877 return RESULT_SHOWUSAGE;
880 res = ast_send_image(chan, argv[2]);
881 if (!ast_check_hangup(chan)) {
884 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
885 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
888 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
890 int res = 0, skipms = 3000;
891 char *fwd = "#", *rev = "*", *pause = NULL, *stop = NULL; /* Default values */
893 if (argc < 5 || argc > 9) {
894 return RESULT_SHOWUSAGE;
897 if (!ast_strlen_zero(argv[4])) {
901 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1)) {
902 return RESULT_SHOWUSAGE;
905 if (argc > 6 && !ast_strlen_zero(argv[6])) {
909 if (argc > 7 && !ast_strlen_zero(argv[7])) {
913 if (argc > 8 && !ast_strlen_zero(argv[8])) {
917 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
919 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
921 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
924 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
927 struct ast_filestream *fs, *vfs;
928 long sample_offset = 0, max_length;
931 if (argc < 4 || argc > 5)
932 return RESULT_SHOWUSAGE;
937 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
938 return RESULT_SHOWUSAGE;
940 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
941 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
942 return RESULT_SUCCESS;
945 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
946 ast_debug(1, "Ooh, found a video stream, too\n");
948 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
950 ast_seekstream(fs, 0, SEEK_END);
951 max_length = ast_tellstream(fs);
952 ast_seekstream(fs, sample_offset, SEEK_SET);
953 res = ast_applystream(chan, fs);
955 vres = ast_applystream(chan, vfs);
960 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
961 /* this is to check for if ast_waitstream closed the stream, we probably are at
962 * the end of the stream, return that amount, else check for the amount */
963 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
964 ast_stopstream(chan);
966 /* Stop this command, don't print a result line, as there is a new command */
967 return RESULT_SUCCESS;
969 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
970 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
973 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
974 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
977 struct ast_filestream *fs, *vfs;
978 long sample_offset = 0, max_length;
982 if ( argc < 4 || argc > 5 )
983 return RESULT_SHOWUSAGE;
989 timeout = atoi(argv[4]);
990 else if (chan->pbx->dtimeoutms) {
991 /* by default dtimeout is set to 5sec */
992 timeout = chan->pbx->dtimeoutms; /* in msec */
995 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
996 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
997 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
998 return RESULT_SUCCESS;
1001 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
1002 ast_debug(1, "Ooh, found a video stream, too\n");
1004 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
1006 ast_seekstream(fs, 0, SEEK_END);
1007 max_length = ast_tellstream(fs);
1008 ast_seekstream(fs, sample_offset, SEEK_SET);
1009 res = ast_applystream(chan, fs);
1011 vres = ast_applystream(chan, vfs);
1014 ast_playstream(vfs);
1016 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1017 /* this is to check for if ast_waitstream closed the stream, we probably are at
1018 * the end of the stream, return that amount, else check for the amount */
1019 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
1020 ast_stopstream(chan);
1022 /* Stop this command, don't print a result line, as there is a new command */
1023 return RESULT_SUCCESS;
1026 /* If the user didnt press a key, wait for digitTimeout*/
1028 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
1029 /* Make sure the new result is in the escape digits of the GET OPTION */
1030 if ( !strchr(edigits,res) )
1034 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
1035 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1041 /*! \brief Say number in various language syntaxes */
1042 /* While waiting, we're sending a NULL. */
1043 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1047 if (argc < 4 || argc > 5)
1048 return RESULT_SHOWUSAGE;
1049 if (sscanf(argv[2], "%d", &num) != 1)
1050 return RESULT_SHOWUSAGE;
1051 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
1053 return RESULT_SUCCESS;
1054 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1055 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1058 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1063 return RESULT_SHOWUSAGE;
1064 if (sscanf(argv[2], "%d", &num) != 1)
1065 return RESULT_SHOWUSAGE;
1067 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1068 if (res == 1) /* New command */
1069 return RESULT_SUCCESS;
1070 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1071 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1074 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1079 return RESULT_SHOWUSAGE;
1081 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1082 if (res == 1) /* New command */
1083 return RESULT_SUCCESS;
1084 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1085 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1088 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1093 return RESULT_SHOWUSAGE;
1094 if (sscanf(argv[2], "%d", &num) != 1)
1095 return RESULT_SHOWUSAGE;
1096 res = ast_say_date(chan, num, argv[3], chan->language);
1098 return RESULT_SUCCESS;
1099 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1100 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1103 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1108 return RESULT_SHOWUSAGE;
1109 if (sscanf(argv[2], "%d", &num) != 1)
1110 return RESULT_SHOWUSAGE;
1111 res = ast_say_time(chan, num, argv[3], chan->language);
1113 return RESULT_SUCCESS;
1114 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1115 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1118 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1122 char *format, *zone = NULL;
1125 return RESULT_SHOWUSAGE;
1130 /* XXX this doesn't belong here, but in the 'say' module */
1131 if (!strcasecmp(chan->language, "de")) {
1132 format = "A dBY HMS";
1134 format = "ABdY 'digits/at' IMp";
1138 if (argc > 5 && !ast_strlen_zero(argv[5]))
1141 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
1142 return RESULT_SHOWUSAGE;
1144 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
1146 return RESULT_SUCCESS;
1148 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1149 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1152 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1157 return RESULT_SHOWUSAGE;
1159 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1160 if (res == 1) /* New command */
1161 return RESULT_SUCCESS;
1162 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1163 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1166 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1168 int res, max, timeout;
1172 return RESULT_SHOWUSAGE;
1174 timeout = atoi(argv[3]);
1178 max = atoi(argv[4]);
1181 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
1182 if (res == 2) /* New command */
1183 return RESULT_SUCCESS;
1185 ast_agi_fdprintf(chan, agi->fd, "200 result=%s (timeout)\n", data);
1187 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1189 ast_agi_fdprintf(chan, agi->fd, "200 result=%s\n", data);
1190 return RESULT_SUCCESS;
1193 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1197 return RESULT_SHOWUSAGE;
1198 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
1199 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1200 return RESULT_SUCCESS;
1203 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1206 return RESULT_SHOWUSAGE;
1207 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
1208 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1209 return RESULT_SUCCESS;
1212 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1217 return RESULT_SHOWUSAGE;
1219 if (sscanf(argv[2], "%d", &pri) != 1) {
1220 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
1221 return RESULT_SHOWUSAGE;
1224 ast_explicit_goto(chan, NULL, NULL, pri);
1225 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1226 return RESULT_SUCCESS;
1229 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1231 struct ast_filestream *fs;
1232 struct ast_frame *f;
1233 struct timeval start;
1234 long sample_offset = 0;
1238 struct ast_dsp *sildet=NULL; /* silence detector dsp */
1239 int totalsilence = 0;
1241 int silence = 0; /* amount of silence to allow */
1242 int gotsilence = 0; /* did we timeout for silence? */
1243 char *silencestr = NULL;
1246 /* XXX EAGI FIXME XXX */
1249 return RESULT_SHOWUSAGE;
1250 if (sscanf(argv[5], "%d", &ms) != 1)
1251 return RESULT_SHOWUSAGE;
1254 silencestr = strchr(argv[6],'s');
1255 if ((argc > 7) && (!silencestr))
1256 silencestr = strchr(argv[7],'s');
1257 if ((argc > 8) && (!silencestr))
1258 silencestr = strchr(argv[8],'s');
1261 if (strlen(silencestr) > 2) {
1262 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
1266 silence = atoi(silencestr);
1274 rfmt = chan->readformat;
1275 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1277 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1280 sildet = ast_dsp_new();
1282 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1285 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
1288 /* backward compatibility, if no offset given, arg[6] would have been
1289 * caught below and taken to be a beep, else if it is a digit then it is a
1291 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
1292 res = ast_streamfile(chan, "beep", chan->language);
1294 if ((argc > 7) && (!strchr(argv[7], '=')))
1295 res = ast_streamfile(chan, "beep", chan->language);
1298 res = ast_waitstream(chan, argv[4]);
1300 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
1302 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
1305 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (writefile)\n", res);
1307 ast_dsp_free(sildet);
1308 return RESULT_FAILURE;
1311 /* Request a video update */
1312 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
1315 ast_applystream(chan,fs);
1316 /* really should have checks */
1317 ast_seekstream(fs, sample_offset, SEEK_SET);
1318 ast_truncstream(fs);
1320 start = ast_tvnow();
1321 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
1322 res = ast_waitfor(chan, -1);
1324 ast_closestream(fs);
1325 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
1327 ast_dsp_free(sildet);
1328 return RESULT_FAILURE;
1332 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
1333 ast_closestream(fs);
1335 ast_dsp_free(sildet);
1336 return RESULT_FAILURE;
1338 switch(f->frametype) {
1339 case AST_FRAME_DTMF:
1340 if (strchr(argv[4], f->subclass)) {
1341 /* This is an interrupting chracter, so rewind to chop off any small
1342 amount of DTMF that may have been recorded
1344 ast_stream_rewind(fs, 200);
1345 ast_truncstream(fs);
1346 sample_offset = ast_tellstream(fs);
1347 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1348 ast_closestream(fs);
1351 ast_dsp_free(sildet);
1352 return RESULT_SUCCESS;
1355 case AST_FRAME_VOICE:
1356 ast_writestream(fs, f);
1357 /* this is a safe place to check progress since we know that fs
1358 * is valid after a write, and it will then have our current
1360 sample_offset = ast_tellstream(fs);
1363 ast_dsp_silence(sildet, f, &dspsilence);
1365 totalsilence = dspsilence;
1369 if (totalsilence > silence) {
1370 /* Ended happily with silence */
1376 case AST_FRAME_VIDEO:
1377 ast_writestream(fs, f);
1379 /* Ignore all other frames */
1388 ast_stream_rewind(fs, silence-1000);
1389 ast_truncstream(fs);
1390 sample_offset = ast_tellstream(fs);
1392 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1393 ast_closestream(fs);
1397 res = ast_set_read_format(chan, rfmt);
1399 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1400 ast_dsp_free(sildet);
1403 return RESULT_SUCCESS;
1406 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1409 struct timeval whentohangup = { 0, 0 };
1412 return RESULT_SHOWUSAGE;
1413 if (sscanf(argv[2], "%lf", &timeout) != 1)
1414 return RESULT_SHOWUSAGE;
1418 whentohangup.tv_sec = timeout;
1419 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
1421 ast_channel_setwhentohangup_tv(chan, whentohangup);
1422 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1423 return RESULT_SUCCESS;
1426 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1428 struct ast_channel *c;
1431 /* no argument: hangup the current channel */
1432 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1433 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1434 return RESULT_SUCCESS;
1435 } else if (argc == 2) {
1436 /* one argument: look for info on the specified channel */
1437 c = ast_get_channel_by_name_locked(argv[1]);
1439 /* we have a matching channel */
1440 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1441 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1442 ast_channel_unlock(c);
1443 return RESULT_SUCCESS;
1445 /* if we get this far no channel name matched the argument given */
1446 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1447 return RESULT_SUCCESS;
1449 return RESULT_SHOWUSAGE;
1453 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1456 struct ast_app *app;
1459 return RESULT_SHOWUSAGE;
1461 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1463 if ((app = pbx_findapp(argv[1]))) {
1464 if (ast_compat_res_agi && !ast_strlen_zero(argv[2])) {
1465 char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
1466 for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
1470 } else if (*vptr == '|') {
1477 res = pbx_exec(chan, app, compat);
1479 res = pbx_exec(chan, app, argv[2]);
1482 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1485 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1487 /* Even though this is wrong, users are depending upon this result. */
1491 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1494 char *l = NULL, *n = NULL;
1497 ast_copy_string(tmp, argv[2], sizeof(tmp));
1498 ast_callerid_parse(tmp, &n, &l);
1500 ast_shrink_phone_number(l);
1505 ast_set_callerid(chan, l, n, NULL);
1508 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1509 return RESULT_SUCCESS;
1512 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1514 struct ast_channel *c;
1516 /* no argument: supply info on the current channel */
1517 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1518 return RESULT_SUCCESS;
1519 } else if (argc == 3) {
1520 /* one argument: look for info on the specified channel */
1521 c = ast_get_channel_by_name_locked(argv[2]);
1523 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1524 ast_channel_unlock(c);
1525 return RESULT_SUCCESS;
1527 /* if we get this far no channel name matched the argument given */
1528 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1529 return RESULT_SUCCESS;
1531 return RESULT_SHOWUSAGE;
1535 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1538 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1540 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1541 return RESULT_SUCCESS;
1544 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1550 return RESULT_SHOWUSAGE;
1552 /* check if we want to execute an ast_custom_function */
1553 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1554 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1556 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1560 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1562 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1564 return RESULT_SUCCESS;
1567 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1570 struct ast_channel *chan2=NULL;
1572 if ((argc != 4) && (argc != 5))
1573 return RESULT_SHOWUSAGE;
1575 chan2 = ast_get_channel_by_name_locked(argv[4]);
1580 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1581 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1583 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1585 if (chan2 && (chan2 != chan))
1586 ast_channel_unlock(chan2);
1587 return RESULT_SUCCESS;
1590 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1595 return RESULT_SHOWUSAGE;
1598 sscanf(argv[2], "%d", &level);
1600 ast_verb(level, "%s: %s\n", chan->data, argv[1]);
1602 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1604 return RESULT_SUCCESS;
1607 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1613 return RESULT_SHOWUSAGE;
1614 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1616 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1618 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1620 return RESULT_SUCCESS;
1623 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1628 return RESULT_SHOWUSAGE;
1629 res = ast_db_put(argv[2], argv[3], argv[4]);
1630 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1631 return RESULT_SUCCESS;
1634 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1639 return RESULT_SHOWUSAGE;
1640 res = ast_db_del(argv[2], argv[3]);
1641 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1642 return RESULT_SUCCESS;
1645 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1649 if ((argc < 3) || (argc > 4))
1650 return RESULT_SHOWUSAGE;
1652 res = ast_db_deltree(argv[2], argv[3]);
1654 res = ast_db_deltree(argv[2], NULL);
1656 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1657 return RESULT_SUCCESS;
1660 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1664 e->command = "agi set debug [on|off]";
1666 "Usage: agi set debug [on|off]\n"
1667 " Enables/disables dumping of AGI transactions for\n"
1668 " debugging purposes.\n";
1675 if (a->argc != e->args)
1676 return CLI_SHOWUSAGE;
1678 if (strncasecmp(a->argv[3], "off", 3) == 0) {
1680 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
1683 return CLI_SHOWUSAGE;
1685 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1689 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1691 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1692 return RESULT_SUCCESS;
1695 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1697 if (!strncasecmp(argv[2], "on", 2))
1698 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1699 else if (!strncasecmp(argv[2], "off", 3))
1701 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1702 return RESULT_SUCCESS;
1705 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1707 /* If a structure already exists, return an error */
1709 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1710 return RESULT_SUCCESS;
1713 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1714 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1716 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1718 return RESULT_SUCCESS;
1721 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1723 /* Check for minimum arguments */
1725 return RESULT_SHOWUSAGE;
1727 /* Check to make sure speech structure exists */
1729 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1730 return RESULT_SUCCESS;
1733 ast_speech_change(agi->speech, argv[2], argv[3]);
1734 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1736 return RESULT_SUCCESS;
1739 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1742 ast_speech_destroy(agi->speech);
1744 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1746 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1749 return RESULT_SUCCESS;
1752 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1755 return RESULT_SHOWUSAGE;
1758 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1759 return RESULT_SUCCESS;
1762 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
1763 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1765 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1767 return RESULT_SUCCESS;
1770 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1773 return RESULT_SHOWUSAGE;
1776 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1777 return RESULT_SUCCESS;
1780 if (ast_speech_grammar_unload(agi->speech, argv[3]))
1781 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1783 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1785 return RESULT_SUCCESS;
1788 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1791 return RESULT_SHOWUSAGE;
1794 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1795 return RESULT_SUCCESS;
1798 if (ast_speech_grammar_activate(agi->speech, argv[3]))
1799 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1801 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1803 return RESULT_SUCCESS;
1806 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1809 return RESULT_SHOWUSAGE;
1812 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1813 return RESULT_SUCCESS;
1816 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
1817 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1819 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1821 return RESULT_SUCCESS;
1824 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
1826 struct ast_filestream *fs = NULL;
1828 if (!(fs = ast_openstream(chan, filename, preflang)))
1832 ast_seekstream(fs, offset, SEEK_SET);
1834 if (ast_applystream(chan, fs))
1837 if (ast_playstream(fs))
1843 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1845 struct ast_speech *speech = agi->speech;
1846 char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
1847 int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
1848 long current_offset = 0;
1849 const char *reason = NULL;
1850 struct ast_frame *fr = NULL;
1851 struct ast_speech_result *result = NULL;
1852 size_t left = sizeof(tmp);
1853 time_t start = 0, current;
1856 return RESULT_SHOWUSAGE;
1859 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1860 return RESULT_SUCCESS;
1864 timeout = atoi(argv[3]);
1866 /* If offset is specified then convert from text to integer */
1868 offset = atoi(argv[4]);
1870 /* We want frames coming in signed linear */
1871 old_read_format = chan->readformat;
1872 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1873 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1874 return RESULT_SUCCESS;
1877 /* Setup speech structure */
1878 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
1879 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1880 ast_speech_start(speech);
1883 /* Start playing prompt */
1884 speech_streamfile(chan, prompt, chan->language, offset);
1886 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
1887 while (ast_strlen_zero(reason)) {
1888 /* Run scheduled items */
1889 ast_sched_runq(chan->sched);
1891 /* See maximum time of waiting */
1892 if ((res = ast_sched_wait(chan->sched)) < 0)
1895 /* Wait for frame */
1896 if (ast_waitfor(chan, res) > 0) {
1897 if (!(fr = ast_read(chan))) {
1903 /* Perform timeout check */
1904 if ((timeout > 0) && (start > 0)) {
1906 if ((current - start) >= timeout) {
1914 /* Check the speech structure for any changes */
1915 ast_mutex_lock(&speech->lock);
1917 /* See if we need to quiet the audio stream playback */
1918 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
1919 current_offset = ast_tellstream(chan->stream);
1920 ast_stopstream(chan);
1921 ast_clear_flag(speech, AST_SPEECH_QUIET);
1924 /* Check each state */
1925 switch (speech->state) {
1926 case AST_SPEECH_STATE_READY:
1927 /* If the stream is done, start timeout calculation */
1928 if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
1929 ast_stopstream(chan);
1932 /* Write audio frame data into speech engine if possible */
1933 if (fr && fr->frametype == AST_FRAME_VOICE)
1934 ast_speech_write(speech, fr->data.ptr, fr->datalen);
1936 case AST_SPEECH_STATE_WAIT:
1937 /* Cue waiting sound if not already playing */
1938 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
1939 ast_stopstream(chan);
1940 /* If a processing sound exists, or is not none - play it */
1941 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
1942 speech_streamfile(chan, speech->processing_sound, chan->language, 0);
1945 case AST_SPEECH_STATE_DONE:
1946 /* Get the results */
1947 speech->results = ast_speech_results_get(speech);
1948 /* Change state to not ready */
1949 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1955 ast_mutex_unlock(&speech->lock);
1957 /* Check frame for DTMF or hangup */
1959 if (fr->frametype == AST_FRAME_DTMF) {
1961 dtmf = fr->subclass;
1962 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
1969 if (!strcasecmp(reason, "speech")) {
1970 /* Build string containing speech results */
1971 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
1972 /* Build result string */
1973 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);
1974 /* Increment result count */
1978 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
1979 } else if (!strcasecmp(reason, "dtmf")) {
1980 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
1981 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
1982 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
1984 ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
1987 return RESULT_SUCCESS;
1990 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1992 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1993 return AST_PBX_KEEPALIVE;
1996 static char usage_setmusic[] =
1997 " Usage: SET MUSIC ON <on|off> <class>\n"
1998 " Enables/Disables the music on hold generator. If <class> is\n"
1999 " not specified, then the default music on hold class will be used.\n"
2000 " Always returns 0.\n";
2002 static char usage_dbput[] =
2003 " Usage: DATABASE PUT <family> <key> <value>\n"
2004 " Adds or updates an entry in the Asterisk database for a\n"
2005 " given family, key, and value.\n"
2006 " Returns 1 if successful, 0 otherwise.\n";
2008 static char usage_dbget[] =
2009 " Usage: DATABASE GET <family> <key>\n"
2010 " Retrieves an entry in the Asterisk database for a\n"
2011 " given family and key.\n"
2012 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
2013 " is set and returns the variable in parentheses.\n"
2014 " Example return code: 200 result=1 (testvariable)\n";
2016 static char usage_dbdel[] =
2017 " Usage: DATABASE DEL <family> <key>\n"
2018 " Deletes an entry in the Asterisk database for a\n"
2019 " given family and key.\n"
2020 " Returns 1 if successful, 0 otherwise.\n";
2022 static char usage_dbdeltree[] =
2023 " Usage: DATABASE DELTREE <family> [keytree]\n"
2024 " Deletes a family or specific keytree within a family\n"
2025 " in the Asterisk database.\n"
2026 " Returns 1 if successful, 0 otherwise.\n";
2028 static char usage_verbose[] =
2029 " Usage: VERBOSE <message> <level>\n"
2030 " Sends <message> to the console via verbose message system.\n"
2031 " <level> is the the verbose level (1-4)\n"
2032 " Always returns 1.\n";
2034 static char usage_getvariable[] =
2035 " Usage: GET VARIABLE <variablename>\n"
2036 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
2037 " is set and returns the variable in parentheses.\n"
2038 " example return code: 200 result=1 (testvariable)\n";
2040 static char usage_getvariablefull[] =
2041 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
2042 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
2043 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
2044 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
2045 " example return code: 200 result=1 (testvariable)\n";
2047 static char usage_setvariable[] =
2048 " Usage: SET VARIABLE <variablename> <value>\n";
2050 static char usage_channelstatus[] =
2051 " Usage: CHANNEL STATUS [<channelname>]\n"
2052 " Returns the status of the specified channel.\n"
2053 " If no channel name is given the returns the status of the\n"
2054 " current channel. Return values:\n"
2055 " 0 Channel is down and available\n"
2056 " 1 Channel is down, but reserved\n"
2057 " 2 Channel is off hook\n"
2058 " 3 Digits (or equivalent) have been dialed\n"
2059 " 4 Line is ringing\n"
2060 " 5 Remote end is ringing\n"
2062 " 7 Line is busy\n";
2064 static char usage_setcallerid[] =
2065 " Usage: SET CALLERID <number>\n"
2066 " Changes the callerid of the current channel.\n";
2068 static char usage_exec[] =
2069 " Usage: EXEC <application> <options>\n"
2070 " Executes <application> with given <options>.\n"
2071 " Returns whatever the application returns, or -2 on failure to find application\n";
2073 static char usage_hangup[] =
2074 " Usage: HANGUP [<channelname>]\n"
2075 " Hangs up the specified channel.\n"
2076 " If no channel name is given, hangs up the current channel\n";
2078 static char usage_answer[] =
2080 " Answers channel if not already in answer state. Returns -1 on\n"
2081 " channel failure, or 0 if successful.\n";
2083 static char usage_waitfordigit[] =
2084 " Usage: WAIT FOR DIGIT <timeout>\n"
2085 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2086 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2087 " the numerical value of the ascii of the digit if one is received. Use -1\n"
2088 " for the timeout value if you desire the call to block indefinitely.\n";
2090 static char usage_sendtext[] =
2091 " Usage: SEND TEXT \"<text to send>\"\n"
2092 " Sends the given text on a channel. Most channels do not support the\n"
2093 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
2094 " support text transmission. Returns -1 only on error/hangup. Text\n"
2095 " consisting of greater than one word should be placed in quotes since the\n"
2096 " command only accepts a single argument.\n";
2098 static char usage_recvchar[] =
2099 " Usage: RECEIVE CHAR <timeout>\n"
2100 " Receives a character of text on a channel. Specify timeout to be the\n"
2101 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2102 " do not support the reception of text. Returns the decimal value of the character\n"
2103 " if one is received, or 0 if the channel does not support text reception. Returns\n"
2104 " -1 only on error/hangup.\n";
2106 static char usage_recvtext[] =
2107 " Usage: RECEIVE TEXT <timeout>\n"
2108 " Receives a string of text on a channel. Specify timeout to be the\n"
2109 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2110 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2112 static char usage_tddmode[] =
2113 " Usage: TDD MODE <on|off>\n"
2114 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2115 " successful, or 0 if channel is not TDD-capable.\n";
2117 static char usage_sendimage[] =
2118 " Usage: SEND IMAGE <image>\n"
2119 " Sends the given image on a channel. Most channels do not support the\n"
2120 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2121 " support image transmission. Returns -1 only on error/hangup. Image names\n"
2122 " should not include extensions.\n";
2124 static char usage_streamfile[] =
2125 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2126 " Send the given file, allowing playback to be interrupted by the given\n"
2127 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2128 " permitted. If sample offset is provided then the audio will seek to sample\n"
2129 " offset before play starts. Returns 0 if playback completes without a digit\n"
2130 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2131 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2132 " extension must not be included in the filename.\n";
2134 static char usage_controlstreamfile[] =
2135 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2136 " Send the given file, allowing playback to be controled by the given\n"
2137 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2138 " permitted. Returns 0 if playback completes without a digit\n"
2139 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2140 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2141 " extension must not be included in the filename.\n\n"
2142 " Note: ffchar and rewchar default to * and # respectively.\n";
2144 static char usage_getoption[] =
2145 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2146 " Behaves similar to STREAM FILE but used with a timeout option.\n";
2148 static char usage_saynumber[] =
2149 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2150 " Say a given number, returning early if any of the given DTMF digits\n"
2151 " are received on the channel. Returns 0 if playback completes without a digit\n"
2152 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2153 " -1 on error/hangup.\n";
2155 static char usage_saydigits[] =
2156 " Usage: SAY DIGITS <number> <escape digits>\n"
2157 " Say a given digit string, returning early if any of the given DTMF digits\n"
2158 " are received on the channel. Returns 0 if playback completes without a digit\n"
2159 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2160 " -1 on error/hangup.\n";
2162 static char usage_sayalpha[] =
2163 " Usage: SAY ALPHA <number> <escape digits>\n"
2164 " Say a given character string, returning early if any of the given DTMF digits\n"
2165 " are received on the channel. Returns 0 if playback completes without a digit\n"
2166 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2167 " -1 on error/hangup.\n";
2169 static char usage_saydate[] =
2170 " Usage: SAY DATE <date> <escape digits>\n"
2171 " Say a given date, returning early if any of the given DTMF digits are\n"
2172 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
2173 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2174 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2175 " digit if one was pressed or -1 on error/hangup.\n";
2177 static char usage_saytime[] =
2178 " Usage: SAY TIME <time> <escape digits>\n"
2179 " Say a given time, returning early if any of the given DTMF digits are\n"
2180 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2181 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2182 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2183 " digit if one was pressed or -1 on error/hangup.\n";
2185 static char usage_saydatetime[] =
2186 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2187 " Say a given time, returning early if any of the given DTMF digits are\n"
2188 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2189 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2190 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
2191 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
2192 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
2193 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2194 " digit if one was pressed or -1 on error/hangup.\n";
2196 static char usage_sayphonetic[] =
2197 " Usage: SAY PHONETIC <string> <escape digits>\n"
2198 " Say a given character string with phonetics, returning early if any of the\n"
2199 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2200 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2201 " if one was pressed, or -1 on error/hangup.\n";
2203 static char usage_getdata[] =
2204 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
2205 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
2206 "from the channel at the other end.\n";
2208 static char usage_setcontext[] =
2209 " Usage: SET CONTEXT <desired context>\n"
2210 " Sets the context for continuation upon exiting the application.\n";
2212 static char usage_setextension[] =
2213 " Usage: SET EXTENSION <new extension>\n"
2214 " Changes the extension for continuation upon exiting the application.\n";
2216 static char usage_setpriority[] =
2217 " Usage: SET PRIORITY <priority>\n"
2218 " Changes the priority for continuation upon exiting the application.\n"
2219 " The priority must be a valid priority or label.\n";
2221 static char usage_recordfile[] =
2222 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2223 " [offset samples] [BEEP] [s=silence]\n"
2224 " Record to a file until a given dtmf digit in the sequence is received\n"
2225 " Returns -1 on hangup or error. The format will specify what kind of file\n"
2226 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
2227 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2228 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
2229 " of seconds of silence allowed before the function returns despite the\n"
2230 " lack of dtmf digits or reaching timeout. Silence value must be\n"
2231 " preceeded by \"s=\" and is also optional.\n";
2233 static char usage_autohangup[] =
2234 " Usage: SET AUTOHANGUP <time>\n"
2235 " Cause the channel to automatically hangup at <time> seconds in the\n"
2236 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
2237 " cause the autohangup feature to be disabled on this channel.\n";
2239 static char usage_break_aagi[] =
2240 " Usage: ASYNCAGI BREAK\n"
2241 " Break the Async AGI loop.\n";
2243 static char usage_noop[] =
2247 static char usage_speechcreate[] =
2248 " Usage: SPEECH CREATE <engine>\n"
2249 " Create a speech object to be used by the other Speech AGI commands.\n";
2251 static char usage_speechset[] =
2252 " Usage: SPEECH SET <name> <value>\n"
2253 " Set an engine-specific setting.\n";
2255 static char usage_speechdestroy[] =
2256 " Usage: SPEECH DESTROY\n"
2257 " Destroy the speech object created by SPEECH CREATE.\n";
2259 static char usage_speechloadgrammar[] =
2260 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2261 " Loads the specified grammar as the specified name.\n";
2263 static char usage_speechunloadgrammar[] =
2264 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2265 " Unloads the specified grammar.\n";
2267 static char usage_speechactivategrammar[] =
2268 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2269 " Activates the specified grammar on the speech object.\n";
2271 static char usage_speechdeactivategrammar[] =
2272 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2273 " Deactivates the specified grammar on the speech object.\n";
2275 static char usage_speechrecognize[] =
2276 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2277 " Plays back given prompt while listening for speech and dtmf.\n";
2280 * \brief AGI commands list
2282 static struct agi_command commands[] = {
2283 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
2284 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
2285 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
2286 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
2287 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
2288 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
2289 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
2290 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
2291 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
2292 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2293 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2294 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2295 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2296 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2297 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2298 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2299 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2300 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2301 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2302 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2303 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2304 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2305 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2306 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2307 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2308 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2309 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2310 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2311 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2312 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
2313 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2314 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2315 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2316 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2317 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2318 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2319 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2320 { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2321 { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2322 { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2323 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2324 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2325 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2326 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2327 { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2328 { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2331 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2333 static char *help_workhorse(int fd, char *match[])
2335 char fullcmd[80], matchstr[80];
2336 struct agi_command *e;
2339 ast_join(matchstr, sizeof(matchstr), match);
2341 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
2342 AST_RWLIST_RDLOCK(&agi_commands);
2343 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2346 /* Hide commands that start with '_' */
2347 if ((e->cmda[0])[0] == '_')
2349 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2350 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2352 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2354 AST_RWLIST_UNLOCK(&agi_commands);
2359 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2363 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2365 if (!find_command(cmd->cmda,1)) {
2367 AST_RWLIST_WRLOCK(&agi_commands);
2368 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2369 AST_RWLIST_UNLOCK(&agi_commands);
2370 if (mod != ast_module_info->self)
2371 ast_module_ref(ast_module_info->self);
2372 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2375 ast_log(LOG_WARNING, "Command already registered!\n");
2380 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2382 struct agi_command *e;
2383 int unregistered = 0;
2386 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2388 AST_RWLIST_WRLOCK(&agi_commands);
2389 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2391 AST_RWLIST_REMOVE_CURRENT(list);
2392 if (mod != ast_module_info->self)
2393 ast_module_unref(ast_module_info->self);
2398 AST_RWLIST_TRAVERSE_SAFE_END;
2399 AST_RWLIST_UNLOCK(&agi_commands);
2401 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2403 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2404 return unregistered;
2407 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
2411 for (i = 0; i < len; i++)
2412 ast_agi_register(mod, cmd + i);
2416 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
2420 for (i = 0; i < len; i++)
2421 ast_agi_unregister(mod, cmd + i);
2424 static agi_command *find_command(char *cmds[], int exact)
2427 struct agi_command *e;
2429 AST_RWLIST_RDLOCK(&agi_commands);
2430 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2433 /* start optimistic */
2435 for (y = 0; match && cmds[y]; y++) {
2436 /* If there are no more words in the command (and we're looking for
2437 an exact match) or there is a difference between the two words,
2438 then this is not a match */
2439 if (!e->cmda[y] && !exact)
2441 /* don't segfault if the next part of a command doesn't exist */
2444 if (strcasecmp(e->cmda[y], cmds[y]))
2447 /* If more words are needed to complete the command then this is not
2448 a candidate (unless we're looking for a really inexact answer */
2449 if ((exact > -1) && e->cmda[y])
2454 AST_RWLIST_UNLOCK(&agi_commands);
2458 static int parse_args(char *s, int *max, char *argv[])
2460 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2467 /* If it's escaped, put a literal quote */
2472 if (quoted && whitespace) {
2473 /* If we're starting a quote, coming off white space start a new word, too */
2481 if (!quoted && !escaped) {
2482 /* If we're not quoted, mark this as whitespace, and
2483 end the previous argument */
2487 /* Otherwise, just treat it as anything else */
2491 /* If we're escaped, print a literal, otherwise enable escaping */
2501 if (x >= MAX_ARGS -1) {
2502 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2505 /* Coming off of whitespace, start the next argument */
2514 /* Null terminate */
2521 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2523 char *argv[MAX_ARGS];
2524 int argc = MAX_ARGS, res;
2526 const char *ami_res = "Unknown Result";
2527 char *ami_cmd = ast_strdupa(buf);
2528 int command_id = ast_random(), resultcode = 200;
2530 manager_event(EVENT_FLAG_CALL, "AGIExec",
2531 "SubEvent: Start\r\n"
2534 "Command: %s\r\n", chan->name, command_id, ami_cmd);
2535 parse_args(buf, &argc, argv);
2536 if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2537 /* if this command wasnt registered by res_agi, be sure to usecount
2538 the module we are using */
2539 if (c->mod != ast_module_info->self)
2540 ast_module_ref(c->mod);
2541 res = c->handler(chan, agi, argc, argv);
2542 if (c->mod != ast_module_info->self)
2543 ast_module_unref(c->mod);
2545 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2546 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2547 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2548 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2550 manager_event(EVENT_FLAG_CALL, "AGIExec",
2555 "ResultCode: %d\r\n"
2556 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2558 case RESULT_SHOWUSAGE:
2559 ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
2560 ast_agi_fdprintf(chan, agi->fd, c->usage);
2561 ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
2563 case AST_PBX_KEEPALIVE:
2564 /* We've been asked to keep alive, so do so */
2565 return AST_PBX_KEEPALIVE;
2567 case RESULT_FAILURE:
2568 /* They've already given the failure. We've been hung up on so handle this
2572 } else if ((c = find_command(argv, 0))) {
2573 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
2574 manager_event(EVENT_FLAG_CALL, "AGIExec",
2579 "ResultCode: 511\r\n"
2580 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2582 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
2583 manager_event(EVENT_FLAG_CALL, "AGIExec",
2588 "ResultCode: 510\r\n"
2589 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2593 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2595 struct ast_channel *c;
2596 int outfd, ms, needhup = 0;
2597 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2598 struct ast_frame *f;
2599 char buf[AGI_BUF_LEN];
2602 /* how many times we'll retry if ast_waitfor_nandfs will return without either
2603 channel or file descriptor in case select is interrupted by a system call (EINTR) */
2604 int retry = AGI_NANDFS_RETRY;
2606 if (!(readf = fdopen(agi->ctrl, "r"))) {
2607 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2611 return AGI_RESULT_FAILURE;
2614 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2623 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2625 retry = AGI_NANDFS_RETRY;
2626 /* Idle the channel until we get a command */
2629 ast_debug(1, "%s hungup\n", chan->name);
2630 returnstatus = AGI_RESULT_HANGUP;
2634 /* If it's voice, write it to the audio pipe */
2635 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2636 /* Write, ignoring errors */
2637 write(agi->audio, f->data.ptr, f->datalen);
2641 } else if (outfd > -1) {
2642 size_t len = sizeof(buf);
2645 retry = AGI_NANDFS_RETRY;
2648 while (buflen < (len - 1)) {
2649 res = fgets(buf + buflen, len, readf);
2652 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
2654 if (res != NULL && !agi->fast)
2656 buflen = strlen(buf);
2657 if (buflen && buf[buflen - 1] == '\n')
2661 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2665 /* Program terminated */
2666 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2668 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2670 waitpid(pid, status, 0);
2671 /* No need to kill the pid anymore, since they closed us */
2676 /* Special case for inability to execute child process */
2677 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
2678 returnstatus = AGI_RESULT_FAILURE;
2682 /* get rid of trailing newline, if any */
2683 if (*buf && buf[strlen(buf) - 1] == '\n')
2684 buf[strlen(buf) - 1] = 0;
2686 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2687 returnstatus |= agi_handle_command(chan, agi, buf, dead);
2688 /* If the handle_command returns -1, we need to stop */
2689 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2695 ast_log(LOG_WARNING, "No channel, no fd?\n");
2696 returnstatus = AGI_RESULT_FAILURE;
2701 /* Notify process */
2703 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2704 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2705 if (kill(pid, SIGHUP)) {
2706 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2707 } else { /* Give the process a chance to die */
2711 waitpid(pid, status, WNOHANG);
2714 return returnstatus;
2717 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2719 struct agi_command *command;
2724 e->command = "agi show";
2726 "Usage: agi show [topic]\n"
2727 " When called with a topic as an argument, displays usage\n"
2728 " information on the given command. If called without a\n"
2729 " topic, it provides a list of AGI commands.\n";
2733 if (a->argc < e->args)
2734 return CLI_SHOWUSAGE;
2735 if (a->argc > e->args) {
2736 command = find_command(a->argv + e->args, 1);
2738 ast_cli(a->fd, "%s", command->usage);
2739 ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2741 if (find_command(a->argv + e->args, -1)) {
2742 return help_workhorse(a->fd, a->argv + e->args);
2744 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2745 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2749 return help_workhorse(a->fd, NULL);
2754 /*! \brief Convert string to use HTML escaped characters
2755 \note Maybe this should be a generic function?
2757 static void write_html_escaped(FILE *htmlfile, char *str)
2764 fprintf(htmlfile, "%s", "<");
2767 fprintf(htmlfile, "%s", ">");
2770 fprintf(htmlfile, "%s", "&");
2773 fprintf(htmlfile, "%s", """);
2776 fprintf(htmlfile, "%c", *cur);
2785 static int write_htmldump(char *filename)
2787 struct agi_command *command;
2791 if (!(htmlfile = fopen(filename, "wt")))
2794 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2795 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2796 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2798 AST_RWLIST_RDLOCK(&agi_commands);
2799 AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2800 char *stringp, *tempstr;
2802 if (!command->cmda[0]) /* end ? */
2804 /* Hide commands that start with '_' */
2805 if ((command->cmda[0])[0] == '_')
2807 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2809 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2810 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2812 stringp = command->usage;
2813 tempstr = strsep(&stringp, "\n");
2815 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2816 write_html_escaped(htmlfile, tempstr);
2817 fprintf(htmlfile, "</TD></TR>\n");
2818 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2820 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2821 write_html_escaped(htmlfile, tempstr);
2822 fprintf(htmlfile, "<BR>\n");
2824 fprintf(htmlfile, "</TD></TR>\n");
2825 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2827 AST_RWLIST_UNLOCK(&agi_commands);
2828 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2833 static char *handle_cli_agi_dumphtml_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2837 e->command = "agi dumphtml";
2839 "Usage: agi dumphtml <filename>\n"
2840 " Dumps the AGI command list in HTML format to the given\n"
2846 if (a->argc < e->args + 1)
2847 return CLI_SHOWUSAGE;
2849 if (write_htmldump(a->argv[2]) < 0) {
2850 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2851 return CLI_SHOWUSAGE;
2853 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2857 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2861 e->command = "agi dump html";
2863 "Usage: agi dump html <filename>\n"
2864 " Dumps the AGI command list in HTML format to the given\n"
2870 if (a->argc != e->args + 1)
2871 return CLI_SHOWUSAGE;
2873 if (write_htmldump(a->argv[e->args]) < 0) {
2874 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
2875 return CLI_SHOWUSAGE;
2877 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
2881 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2883 enum agi_result res;
2884 char buf[AGI_BUF_LEN] = "", *tmp = buf;
2885 int fds[2], efd = -1, pid;
2886 AST_DECLARE_APP_ARGS(args,
2887 AST_APP_ARG(arg)[MAX_ARGS];
2891 if (ast_strlen_zero(data)) {
2892 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2896 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
2897 ast_copy_string(buf, data, sizeof(buf));
2898 memset(&agi, 0, sizeof(agi));
2899 AST_STANDARD_APP_ARGS(args, tmp);
2900 args.argv[args.argc] = NULL;
2902 /* Answer if need be */
2903 if (chan->_state != AST_STATE_UP) {
2904 if (ast_answer(chan))
2908 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2909 /* Async AGI do not require run_agi(), so just proceed if normal AGI
2910 or Fast AGI are setup with success. */
2911 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2916 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2917 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2918 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2919 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2920 res = AGI_RESULT_FAILURE;
2921 if (fds[1] != fds[0])
2926 ast_safe_fork_cleanup();
2927 ast_clear_flag(chan, AST_FLAG_AGI);
2928 ast_clear_flag(chan, AST_FLAG_FASTAGI);
2929 ast_clear_flag(chan, AST_FLAG_ASYNCAGI);
2932 case AGI_RESULT_SUCCESS:
2933 case AGI_RESULT_SUCCESS_FAST:
2934 case AGI_RESULT_SUCCESS_ASYNC:
2935 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2937 case AGI_RESULT_FAILURE:
2938 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2940 case AGI_RESULT_NOTFOUND:
2941 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2943 case AGI_RESULT_HANGUP:
2944 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2951 static int agi_exec(struct ast_channel *chan, void *data)
2953 if (!ast_check_hangup(chan))
2954 return agi_exec_full(chan, data, 0, 0);
2956 return agi_exec_full(chan, data, 0, 1);
2959 static int eagi_exec(struct ast_channel *chan, void *data)
2961 int readformat, res;
2963 if (ast_check_hangup(chan)) {
2964 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
2967 readformat = chan->readformat;
2968 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2969 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2972 res = agi_exec_full(chan, data, 1, 0);
2974 if (ast_set_read_format(chan, readformat)) {
2975 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2981 static int deadagi_exec(struct ast_channel *chan, void *data)
2983 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
2984 return agi_exec(chan, data);
2987 static struct ast_cli_entry cli_agi_dumphtml_deprecated = AST_CLI_DEFINE(handle_cli_agi_dumphtml_deprecated, "Dumps a list of AGI commands in HTML format");
2989 static struct ast_cli_entry cli_agi[] = {
2990 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
2991 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
2992 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
2993 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format", .deprecate_cmd = &cli_agi_dumphtml_deprecated)
2996 static int unload_module(void)
2998 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2999 ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
3000 ast_unregister_application(eapp);
3001 ast_unregister_application(deadapp);
3002 ast_manager_unregister("AGI");
3003 return ast_unregister_application(app);
3006 static int load_module(void)
3008 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
3009 ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
3010 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
3011 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
3012 ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
3013 return ast_register_application(app, agi_exec, synopsis, descrip);
3016 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
3017 .load = load_module,
3018 .unload = unload_module,