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"
59 #include "asterisk/features.h"
60 #include "asterisk/term.h"
61 #include "asterisk/xmldoc.h"
64 <agi name="answer" language="en_US">
70 <para>Answers channel if not already in answer state. Returns <literal>-1</literal> on
71 channel failure, or <literal>0</literal> if successful.</para>
74 <ref type="agi">hangup</ref>
77 <agi name="channel status" language="en_US">
79 Returns status of the connected channel.
82 <parameter name="channelname" />
85 <para>Returns the status of the specified <replaceable>channelname</replaceable>.
86 If no channel name is given then returns the status of the current channel.</para>
87 <para>Return values:</para>
90 <para>Channel is down and available.</para>
93 <para>Channel is down, but reserved.</para>
96 <para>Channel is off hook.</para>
99 <para>Digits (or equivalent) have been dialed.</para>
102 <para>Line is ringing.</para>
105 <para>Remote end is ringing.</para>
108 <para>Line is up.</para>
111 <para>Line is busy.</para>
116 <agi name="database del" language="en_US">
118 Removes database key/value
121 <parameter name="family" required="true" />
122 <parameter name="key" required="true" />
125 <para>Deletes an entry in the Asterisk database for a given
126 <replaceable>family</replaceable> and <replaceable>key</replaceable>.</para>
127 <para>Returns <literal>1</literal> if successful, <literal>0</literal>
131 <agi name="database deltree" language="en_US">
133 Removes database keytree/value
136 <parameter name="family" required="true" />
137 <parameter name="keytree" />
140 <para>Deletes a <replaceable>family</replaceable> or specific <replaceable>keytree</replaceable>
141 within a <replaceable>family</replaceable> in the Asterisk database.</para>
142 <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
145 <agi name="database get" language="en_US">
150 <parameter name="family" required="true" />
151 <parameter name="key" required="true" />
154 <para>Retrieves an entry in the Asterisk database for a given <replaceable>family</replaceable>
155 and <replaceable>key</replaceable>.</para>
156 <para>Returns <literal>0</literal> if <replaceable>key</replaceable> is not set.
157 Returns <literal>1</literal> if <replaceable>key</replaceable> is set and returns the variable
158 in parenthesis.</para>
159 <para>Example return code: 200 result=1 (testvariable)</para>
162 <agi name="database put" language="en_US">
164 Adds/updates database value
167 <parameter name="family" required="true" />
168 <parameter name="key" required="true" />
169 <parameter name="value" required="true" />
172 <para>Adds or updates an entry in the Asterisk database for a given
173 <replaceable>family</replaceable>, <replaceable>key</replaceable>, and
174 <replaceable>value</replaceable>.</para>
175 <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
178 <agi name="exec" language="en_US">
180 Executes a given Application
183 <parameter name="application" required="true" />
184 <parameter name="options" required="true" />
187 <para>Executes <replaceable>application</replaceable> with given
188 <replaceable>options</replaceable>.</para>
189 <para>Returns whatever the <replaceable>application</replaceable> returns, or
190 <literal>-2</literal> on failure to find <replaceable>application</replaceable>.</para>
193 <agi name="get data" language="en_US">
195 Prompts for DTMF on a channel
198 <parameter name="file" required="true" />
199 <parameter name="timeout" />
200 <parameter name="maxdigits" />
203 <para>Stream the given <replaceable>file</replaceable>, and recieve DTMF data.</para>
204 <para>Returns the digits received from the channel at the other end.</para>
207 <agi name="get full variable" language="en_US">
209 Evaluates a channel expression
212 <parameter name="variablename" required="true" />
213 <parameter name="channel name" />
216 <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set
217 or channel does not exist. Returns <literal>1</literal> if <replaceable>variablename</replaceable>
218 is set and returns the variable in parenthesis. Understands complex variable names and builtin
219 variables, unlike GET VARIABLE.</para>
220 <para>Example return code: 200 result=1 (testvariable)</para>
223 <agi name="set music" language="en_US">
225 Enable/Disable Music on hold generator
228 <parameter required="true">
231 <parameter name="on" literal="true" required="true" />
234 <parameter name="off" literal="true" required="true" />
238 <parameter name="class" required="true" />
241 <para>Enables/Disables the music on hold generator. If <replaceable>class</replaceable>
242 is not specified, then the <literal>default</literal> music on hold class will be
244 <para>Always returns <literal>0</literal>.</para>
250 #define MAX_CMD_LEN 80
251 #define AGI_NANDFS_RETRY 3
252 #define AGI_BUF_LEN 2048
254 static char *app = "AGI";
256 static char *eapp = "EAGI";
258 static char *deadapp = "DeadAGI";
260 static char *synopsis = "Executes an AGI compliant application";
261 static char *esynopsis = "Executes an EAGI compliant application";
262 static char *deadsynopsis = "Executes AGI on a hungup channel";
264 static char *descrip =
265 " [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
266 "program on a channel. AGI allows Asterisk to launch external programs written\n"
267 "in any language to control a telephony channel, play audio, read DTMF digits,\n"
268 "etc. by communicating with the AGI protocol on stdin and stdout.\n"
269 " As of 1.6.0, this channel will not stop dialplan execution on hangup inside\n"
270 "of this application. Dialplan execution will continue normally, even upon\n"
271 "hangup until the AGI application signals a desire to stop (either by exiting\n"
272 "or, in the case of a net script, by closing the connection).\n"
273 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
274 "except when using DeadAGI. A fast AGI server will correspondingly receive a\n"
275 "HANGUP in OOB data. Both of these signals may be disabled by setting the\n"
276 "AGISIGHUP channel variable to \"no\" before executing the AGI application.\n"
277 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
278 "on file descriptor 3.\n\n"
279 " Use the CLI command 'agi show commnands' to list available agi commands.\n"
280 " This application sets the following channel variable upon completion:\n"
281 " AGISTATUS The status of the attempt to the run the AGI script\n"
282 " text string, one of SUCCESS | FAILURE | NOTFOUND | HANGUP\n";
284 static int agidebug = 0;
286 #define TONE_BLOCK_SIZE 200
288 /* Max time to connect to an AGI remote host */
289 #define MAX_AGI_CONNECT 2000
291 #define AGI_PORT 4573
294 AGI_RESULT_FAILURE = -1,
296 AGI_RESULT_SUCCESS_FAST,
297 AGI_RESULT_SUCCESS_ASYNC,
302 static agi_command *find_command(char *cmds[], int exact);
304 AST_THREADSTORAGE(agi_buf);
305 #define AGI_BUF_INITSIZE 256
307 int ast_agi_send(int fd, struct ast_channel *chan, char *fmt, ...)
313 if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
317 res = ast_str_set_va(&buf, 0, fmt, ap);
321 ast_log(LOG_ERROR, "Out of memory\n");
327 ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
329 ast_verbose("AGI Tx >> %s", buf->str);
333 return ast_carefulwrite(fd, buf->str, buf->used, 100);
336 /* linked list of AGI commands ready to be executed by Async AGI */
340 AST_LIST_ENTRY(agi_cmd) entry;
343 static void free_agi_cmd(struct agi_cmd *cmd)
345 ast_free(cmd->cmd_buffer);
346 ast_free(cmd->cmd_id);
350 /* AGI datastore destructor */
351 static void agi_destroy_commands_cb(void *data)
354 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
355 AST_LIST_LOCK(chan_cmds);
356 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
359 AST_LIST_UNLOCK(chan_cmds);
360 AST_LIST_HEAD_DESTROY(chan_cmds);
364 /* channel datastore to keep the queue of AGI commands in the channel */
365 static const struct ast_datastore_info agi_commands_datastore_info = {
367 .destroy = agi_destroy_commands_cb
370 static const char mandescr_asyncagi[] =
371 "Description: Add an AGI command to the execute queue of the channel in Async AGI\n"
373 " *Channel: Channel that is currently in Async AGI\n"
374 " *Command: Application to execute\n"
375 " CommandID: comand id. This will be sent back in CommandID header of AsyncAGI exec event notification\n"
378 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
380 struct ast_datastore *store;
382 AST_LIST_HEAD(, agi_cmd) *agi_commands;
384 ast_channel_lock(chan);
385 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
386 ast_channel_unlock(chan);
388 ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
391 agi_commands = store->data;
392 AST_LIST_LOCK(agi_commands);
393 cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
394 AST_LIST_UNLOCK(agi_commands);
398 /* channel is locked when calling this one either from the CLI or manager thread */
399 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
401 struct ast_datastore *store;
403 AST_LIST_HEAD(, agi_cmd) *agi_commands;
405 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
407 ast_log(LOG_WARNING, "Channel %s is not at Async AGI.\n", chan->name);
410 agi_commands = store->data;
411 cmd = ast_calloc(1, sizeof(*cmd));
415 cmd->cmd_buffer = ast_strdup(cmd_buff);
416 if (!cmd->cmd_buffer) {
420 cmd->cmd_id = ast_strdup(cmd_id);
422 ast_free(cmd->cmd_buffer);
426 AST_LIST_LOCK(agi_commands);
427 AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
428 AST_LIST_UNLOCK(agi_commands);
432 static int add_to_agi(struct ast_channel *chan)
434 struct ast_datastore *datastore;
435 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
437 /* check if already on AGI */
438 ast_channel_lock(chan);
439 datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
440 ast_channel_unlock(chan);
442 /* we already have an AGI datastore, let's just
447 /* the channel has never been on Async AGI,
448 let's allocate it's datastore */
449 datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
453 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
454 if (!agi_cmds_list) {
455 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
456 ast_datastore_free(datastore);
459 datastore->data = agi_cmds_list;
460 AST_LIST_HEAD_INIT(agi_cmds_list);
461 ast_channel_lock(chan);
462 ast_channel_datastore_add(chan, datastore);
463 ast_channel_unlock(chan);
468 * \brief CLI command to add applications to execute in Async AGI
473 * \retval CLI_SUCCESS on success
474 * \retval NULL when init or tab completion is used
476 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
478 struct ast_channel *chan;
481 e->command = "agi exec";
482 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
483 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
487 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
492 return CLI_SHOWUSAGE;
493 chan = ast_get_channel_by_name_locked(a->argv[2]);
495 ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
498 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
499 ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
500 ast_channel_unlock(chan);
503 ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
504 ast_channel_unlock(chan);
509 * \brief Add a new command to execute by the Async AGI application
513 * It will append the application to the specified channel's queue
514 * if the channel is not inside Async AGI application it will return an error
515 * \retval 0 on success or incorrect use
516 * \retval 1 on failure to add the command ( most likely because the channel
517 * is not in Async AGI loop )
519 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
521 const char *channel = astman_get_header(m, "Channel");
522 const char *cmdbuff = astman_get_header(m, "Command");
523 const char *cmdid = astman_get_header(m, "CommandID");
524 struct ast_channel *chan;
526 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
527 astman_send_error(s, m, "Both, Channel and Command are *required*");
530 chan = ast_get_channel_by_name_locked(channel);
532 snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
533 astman_send_error(s, m, buf);
536 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
537 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
538 astman_send_error(s, m, buf);
539 ast_channel_unlock(chan);
542 astman_send_ack(s, m, "Added AGI command to queue");
543 ast_channel_unlock(chan);
547 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
548 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
549 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
551 /* This buffer sizes might cause truncation if the AGI command writes more data
552 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
553 that writes a response larger than 1024 bytes?, I don't think so, most of
554 them are just result=blah stuff. However probably if GET VARIABLE is called
555 and the variable has large amount of data, that could be a problem. We could
556 make this buffers dynamic, but let's leave that as a second step.
558 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
559 number. Some characters of AGI buf will be url encoded to be sent to manager
560 clients. An URL encoded character will take 3 bytes, but again, to cause
561 truncation more than about 70% of the AGI buffer should be URL encoded for
562 that to happen. Not likely at all.
564 On the other hand. I wonder if read() could eventually return less data than
565 the amount already available in the pipe? If so, how to deal with that?
566 So far, my tests on Linux have not had any problems.
568 #define AGI_BUF_SIZE 1024
569 #define AMI_BUF_SIZE 2048
574 char agi_buffer[AGI_BUF_SIZE + 1];
575 char ami_buffer[AMI_BUF_SIZE];
576 enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
580 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
581 return AGI_RESULT_FAILURE;
584 /* add AsyncAGI datastore to the channel */
585 if (add_to_agi(chan)) {
586 ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
587 return AGI_RESULT_FAILURE;
590 /* this pipe allows us to create a "fake" AGI struct to use
594 ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
595 /* intentionally do not remove datastore, added with
596 add_to_agi(), from channel. It will be removed when
597 the channel is hung up anyways */
598 return AGI_RESULT_FAILURE;
601 /* handlers will get the pipe write fd and we read the AGI responses
602 from the pipe read fd */
603 async_agi.fd = fds[1];
604 async_agi.ctrl = fds[1];
605 async_agi.audio = -1; /* no audio support */
608 /* notify possible manager users of a new channel ready to
610 setup_env(chan, "async", fds[1], 0, 0, NULL);
611 /* read the environment */
612 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
614 ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
615 returnstatus = AGI_RESULT_FAILURE;
618 agi_buffer[res] = '\0';
619 /* encode it and send it thru the manager so whoever is going to take
620 care of AGI commands on this channel can decide which AGI commands
621 to execute based on the setup info */
622 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
623 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
625 /* bail out if we need to hangup */
626 if (ast_check_hangup(chan)) {
627 ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
630 /* retrieve a command
631 (commands are added via the manager or the cli threads) */
632 cmd = get_agi_cmd(chan);
634 /* OK, we have a command, let's call the
636 res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
637 if ((res < 0) || (res == AST_PBX_KEEPALIVE)) {
641 /* the command handler must have written to our fake
642 AGI struct fd (the pipe), let's read the response */
643 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
645 returnstatus = AGI_RESULT_FAILURE;
646 ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
650 /* we have a response, let's send the response thru the
651 manager. Include the CommandID if it was specified
652 when the command was added */
653 agi_buffer[res] = '\0';
654 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
655 if (ast_strlen_zero(cmd->cmd_id))
656 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
658 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);
661 /* no command so far, wait a bit for a frame to read */
662 res = ast_waitfor(chan, timeout);
664 ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
671 ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
672 returnstatus = AGI_RESULT_HANGUP;
675 /* is there any other frame we should care about
676 besides AST_CONTROL_HANGUP? */
677 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
678 ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
686 /* notify manager users this channel cannot be
687 controlled anymore by Async AGI */
688 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
694 /* intentionally don't get rid of the datastore. So commands can be
695 still in the queue in case AsyncAGI gets called again.
696 Datastore destructor will be called on channel destroy anyway */
704 /* launch_netscript: The fastagi handler.
705 FastAGI defaults to port 4573 */
706 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
708 int s, flags, res, port = AGI_PORT;
709 struct pollfd pfds[1];
710 char *host, *c, *script = "";
711 struct sockaddr_in addr_in;
713 struct ast_hostent ahp;
715 /* agiusl is "agi://host.domain[:port][/script/name]" */
716 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
717 /* Strip off any script name */
718 if ((c = strchr(host, '/'))) {
723 if ((c = strchr(host, ':'))) {
729 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
732 if (!(hp = ast_gethostbyname(host, &ahp))) {
733 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
736 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
737 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
740 if ((flags = fcntl(s, F_GETFL)) < 0) {
741 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
745 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
746 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
750 memset(&addr_in, 0, sizeof(addr_in));
751 addr_in.sin_family = AF_INET;
752 addr_in.sin_port = htons(port);
753 memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
754 if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
755 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
757 return AGI_RESULT_FAILURE;
761 pfds[0].events = POLLOUT;
762 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
763 if (errno != EINTR) {
765 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
766 agiurl, MAX_AGI_CONNECT);
768 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
770 return AGI_RESULT_FAILURE;
774 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
775 if (errno != EINTR) {
776 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
778 return AGI_RESULT_FAILURE;
782 /* If we have a script parameter, relay it to the fastagi server */
783 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
784 if (!ast_strlen_zero(script))
785 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
787 ast_debug(4, "Wow, connected!\n");
791 return AGI_RESULT_SUCCESS_FAST;
794 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
797 int pid, toast[2], fromast[2], audio[2], res;
800 if (!strncasecmp(script, "agi://", 6))
801 return launch_netscript(script, argv, fds, efd, opid);
802 if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
803 return launch_asyncagi(chan, argv, efd);
805 if (script[0] != '/') {
806 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
810 /* Before even trying let's see if the file actually exists */
811 if (stat(script, &st)) {
812 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
813 return AGI_RESULT_NOTFOUND;
817 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
818 return AGI_RESULT_FAILURE;
821 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
824 return AGI_RESULT_FAILURE;
828 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
833 return AGI_RESULT_FAILURE;
835 res = fcntl(audio[1], F_GETFL);
837 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
839 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
846 return AGI_RESULT_FAILURE;
850 if ((pid = ast_safe_fork(1)) < 0) {
851 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
852 return AGI_RESULT_FAILURE;
855 /* Pass paths to AGI via environmental variables */
856 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
857 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
858 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
859 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
860 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
861 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
862 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
863 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
864 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
865 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
866 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
868 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
871 /* Redirect stdin and out, provide enhanced audio channel if desired */
872 dup2(fromast[0], STDIN_FILENO);
873 dup2(toast[1], STDOUT_FILENO);
875 dup2(audio[0], STDERR_FILENO + 1);
877 close(STDERR_FILENO + 1);
879 /* Close everything but stdin/out/error */
880 ast_close_fds_above_n(STDERR_FILENO + 1);
883 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
885 /* Can't use ast_log since FD's are closed */
886 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
887 /* Special case to set status of AGI to failure */
888 fprintf(stdout, "failure\n");
892 ast_verb(3, "Launched AGI Script %s\n", script);
897 /* close what we're not using in the parent */
905 return AGI_RESULT_SUCCESS;
908 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
912 /* Print initial environment, with agi_request always being the first
914 ast_agi_send(fd, chan, "agi_request: %s\n", request);
915 ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
916 ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
917 ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
918 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
919 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
922 ast_agi_send(fd, chan, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
923 ast_agi_send(fd, chan, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
924 ast_agi_send(fd, chan, "agi_callingpres: %d\n", chan->cid.cid_pres);
925 ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->cid.cid_ani2);
926 ast_agi_send(fd, chan, "agi_callington: %d\n", chan->cid.cid_ton);
927 ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->cid.cid_tns);
928 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
929 ast_agi_send(fd, chan, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
931 /* Context information */
932 ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
933 ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
934 ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
935 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
937 /* User information */
938 ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
939 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
941 /* Send any parameters to the fastagi server that have been passed via the agi application */
942 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
943 for(count = 1; count < argc; count++)
944 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
946 /* End with empty return */
947 ast_agi_send(fd, chan, "\n");
950 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
954 /* Answer the channel */
955 if (chan->_state != AST_STATE_UP)
956 res = ast_answer(chan);
958 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
959 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
962 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
967 return RESULT_SHOWUSAGE;
968 if (sscanf(argv[3], "%d", &to) != 1)
969 return RESULT_SHOWUSAGE;
970 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
971 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
972 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
975 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
980 return RESULT_SHOWUSAGE;
982 /* At the moment, the parser (perhaps broken) returns with
983 the last argument PLUS the newline at the end of the input
984 buffer. This probably needs to be fixed, but I wont do that
985 because other stuff may break as a result. The right way
986 would probably be to strip off the trailing newline before
987 parsing, then here, add a newline at the end of the string
988 before sending it to ast_sendtext --DUDE */
989 res = ast_sendtext(chan, argv[2]);
990 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
991 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
994 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
999 return RESULT_SHOWUSAGE;
1001 res = ast_recvchar(chan,atoi(argv[2]));
1003 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
1004 return RESULT_SUCCESS;
1007 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1008 return RESULT_SUCCESS;
1010 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
1011 return RESULT_FAILURE;
1014 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1019 return RESULT_SHOWUSAGE;
1021 buf = ast_recvtext(chan, atoi(argv[2]));
1023 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
1026 ast_agi_send(agi->fd, chan, "200 result=-1\n");
1028 return RESULT_SUCCESS;
1031 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1036 return RESULT_SHOWUSAGE;
1038 if (!strncasecmp(argv[2],"on",2)) {
1043 if (!strncasecmp(argv[2],"mate",4)) {
1046 if (!strncasecmp(argv[2],"tdd",3)) {
1049 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
1050 if (res != RESULT_SUCCESS) {
1051 ast_agi_send(agi->fd, chan, "200 result=0\n");
1053 ast_agi_send(agi->fd, chan, "200 result=1\n");
1055 return RESULT_SUCCESS;
1058 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1063 return RESULT_SHOWUSAGE;
1066 res = ast_send_image(chan, argv[2]);
1067 if (!ast_check_hangup(chan)) {
1070 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1071 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1074 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1076 int res = 0, skipms = 3000;
1077 char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
1079 if (argc < 5 || argc > 9) {
1080 return RESULT_SHOWUSAGE;
1083 if (!ast_strlen_zero(argv[4])) {
1087 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1)) {
1088 return RESULT_SHOWUSAGE;
1091 if (argc > 6 && !ast_strlen_zero(argv[6])) {
1095 if (argc > 7 && !ast_strlen_zero(argv[7])) {
1099 if (argc > 8 && !ast_strlen_zero(argv[8])) {
1103 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
1105 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1107 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1110 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1113 struct ast_filestream *fs, *vfs;
1114 long sample_offset = 0, max_length;
1117 if (argc < 4 || argc > 5)
1118 return RESULT_SHOWUSAGE;
1123 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
1124 return RESULT_SHOWUSAGE;
1126 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
1127 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
1128 return RESULT_SUCCESS;
1131 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
1132 ast_debug(1, "Ooh, found a video stream, too\n");
1134 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
1136 ast_seekstream(fs, 0, SEEK_END);
1137 max_length = ast_tellstream(fs);
1138 ast_seekstream(fs, sample_offset, SEEK_SET);
1139 res = ast_applystream(chan, fs);
1141 vres = ast_applystream(chan, vfs);
1144 ast_playstream(vfs);
1146 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1147 /* this is to check for if ast_waitstream closed the stream, we probably are at
1148 * the end of the stream, return that amount, else check for the amount */
1149 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
1150 ast_stopstream(chan);
1152 /* Stop this command, don't print a result line, as there is a new command */
1153 return RESULT_SUCCESS;
1155 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
1156 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1159 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
1160 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1163 struct ast_filestream *fs, *vfs;
1164 long sample_offset = 0, max_length;
1168 if ( argc < 4 || argc > 5 )
1169 return RESULT_SHOWUSAGE;
1175 timeout = atoi(argv[4]);
1176 else if (chan->pbx->dtimeoutms) {
1177 /* by default dtimeout is set to 5sec */
1178 timeout = chan->pbx->dtimeoutms; /* in msec */
1181 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
1182 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
1183 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
1184 return RESULT_SUCCESS;
1187 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
1188 ast_debug(1, "Ooh, found a video stream, too\n");
1190 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
1192 ast_seekstream(fs, 0, SEEK_END);
1193 max_length = ast_tellstream(fs);
1194 ast_seekstream(fs, sample_offset, SEEK_SET);
1195 res = ast_applystream(chan, fs);
1197 vres = ast_applystream(chan, vfs);
1200 ast_playstream(vfs);
1202 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1203 /* this is to check for if ast_waitstream closed the stream, we probably are at
1204 * the end of the stream, return that amount, else check for the amount */
1205 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
1206 ast_stopstream(chan);
1208 /* Stop this command, don't print a result line, as there is a new command */
1209 return RESULT_SUCCESS;
1212 /* If the user didnt press a key, wait for digitTimeout*/
1214 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
1215 /* Make sure the new result is in the escape digits of the GET OPTION */
1216 if ( !strchr(edigits,res) )
1220 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
1221 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1227 /*! \brief Say number in various language syntaxes */
1228 /* While waiting, we're sending a NULL. */
1229 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1233 if (argc < 4 || argc > 5)
1234 return RESULT_SHOWUSAGE;
1235 if (sscanf(argv[2], "%d", &num) != 1)
1236 return RESULT_SHOWUSAGE;
1237 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
1239 return RESULT_SUCCESS;
1240 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1241 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1244 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1249 return RESULT_SHOWUSAGE;
1250 if (sscanf(argv[2], "%d", &num) != 1)
1251 return RESULT_SHOWUSAGE;
1253 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1254 if (res == 1) /* New command */
1255 return RESULT_SUCCESS;
1256 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1257 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1260 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1265 return RESULT_SHOWUSAGE;
1267 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1268 if (res == 1) /* New command */
1269 return RESULT_SUCCESS;
1270 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1271 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1274 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1279 return RESULT_SHOWUSAGE;
1280 if (sscanf(argv[2], "%d", &num) != 1)
1281 return RESULT_SHOWUSAGE;
1282 res = ast_say_date(chan, num, argv[3], chan->language);
1284 return RESULT_SUCCESS;
1285 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1286 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1289 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1294 return RESULT_SHOWUSAGE;
1295 if (sscanf(argv[2], "%d", &num) != 1)
1296 return RESULT_SHOWUSAGE;
1297 res = ast_say_time(chan, num, argv[3], chan->language);
1299 return RESULT_SUCCESS;
1300 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1301 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1304 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1308 char *format, *zone = NULL;
1311 return RESULT_SHOWUSAGE;
1316 /* XXX this doesn't belong here, but in the 'say' module */
1317 if (!strcasecmp(chan->language, "de")) {
1318 format = "A dBY HMS";
1320 format = "ABdY 'digits/at' IMp";
1324 if (argc > 5 && !ast_strlen_zero(argv[5]))
1327 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
1328 return RESULT_SHOWUSAGE;
1330 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
1332 return RESULT_SUCCESS;
1334 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1335 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1338 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1343 return RESULT_SHOWUSAGE;
1345 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1346 if (res == 1) /* New command */
1347 return RESULT_SUCCESS;
1348 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1349 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1352 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1354 int res, max, timeout;
1358 return RESULT_SHOWUSAGE;
1360 timeout = atoi(argv[3]);
1364 max = atoi(argv[4]);
1367 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
1368 if (res == 2) /* New command */
1369 return RESULT_SUCCESS;
1371 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
1373 ast_agi_send(agi->fd, chan, "200 result=-1\n");
1375 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
1376 return RESULT_SUCCESS;
1379 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1383 return RESULT_SHOWUSAGE;
1384 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
1385 ast_agi_send(agi->fd, chan, "200 result=0\n");
1386 return RESULT_SUCCESS;
1389 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1392 return RESULT_SHOWUSAGE;
1393 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
1394 ast_agi_send(agi->fd, chan, "200 result=0\n");
1395 return RESULT_SUCCESS;
1398 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1403 return RESULT_SHOWUSAGE;
1405 if (sscanf(argv[2], "%d", &pri) != 1) {
1406 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
1407 return RESULT_SHOWUSAGE;
1410 ast_explicit_goto(chan, NULL, NULL, pri);
1411 ast_agi_send(agi->fd, chan, "200 result=0\n");
1412 return RESULT_SUCCESS;
1415 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1417 struct ast_filestream *fs;
1418 struct ast_frame *f;
1419 struct timeval start;
1420 long sample_offset = 0;
1424 struct ast_dsp *sildet=NULL; /* silence detector dsp */
1425 int totalsilence = 0;
1427 int silence = 0; /* amount of silence to allow */
1428 int gotsilence = 0; /* did we timeout for silence? */
1429 char *silencestr = NULL;
1432 /* XXX EAGI FIXME XXX */
1435 return RESULT_SHOWUSAGE;
1436 if (sscanf(argv[5], "%d", &ms) != 1)
1437 return RESULT_SHOWUSAGE;
1440 silencestr = strchr(argv[6],'s');
1441 if ((argc > 7) && (!silencestr))
1442 silencestr = strchr(argv[7],'s');
1443 if ((argc > 8) && (!silencestr))
1444 silencestr = strchr(argv[8],'s');
1447 if (strlen(silencestr) > 2) {
1448 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
1452 silence = atoi(silencestr);
1460 rfmt = chan->readformat;
1461 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1463 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1466 sildet = ast_dsp_new();
1468 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1471 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
1474 /* backward compatibility, if no offset given, arg[6] would have been
1475 * caught below and taken to be a beep, else if it is a digit then it is a
1477 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
1478 res = ast_streamfile(chan, "beep", chan->language);
1480 if ((argc > 7) && (!strchr(argv[7], '=')))
1481 res = ast_streamfile(chan, "beep", chan->language);
1484 res = ast_waitstream(chan, argv[4]);
1486 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
1488 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
1491 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
1493 ast_dsp_free(sildet);
1494 return RESULT_FAILURE;
1497 /* Request a video update */
1498 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
1501 ast_applystream(chan,fs);
1502 /* really should have checks */
1503 ast_seekstream(fs, sample_offset, SEEK_SET);
1504 ast_truncstream(fs);
1506 start = ast_tvnow();
1507 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
1508 res = ast_waitfor(chan, -1);
1510 ast_closestream(fs);
1511 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
1513 ast_dsp_free(sildet);
1514 return RESULT_FAILURE;
1518 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
1519 ast_closestream(fs);
1521 ast_dsp_free(sildet);
1522 return RESULT_FAILURE;
1524 switch(f->frametype) {
1525 case AST_FRAME_DTMF:
1526 if (strchr(argv[4], f->subclass)) {
1527 /* This is an interrupting chracter, so rewind to chop off any small
1528 amount of DTMF that may have been recorded
1530 ast_stream_rewind(fs, 200);
1531 ast_truncstream(fs);
1532 sample_offset = ast_tellstream(fs);
1533 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1534 ast_closestream(fs);
1537 ast_dsp_free(sildet);
1538 return RESULT_SUCCESS;
1541 case AST_FRAME_VOICE:
1542 ast_writestream(fs, f);
1543 /* this is a safe place to check progress since we know that fs
1544 * is valid after a write, and it will then have our current
1546 sample_offset = ast_tellstream(fs);
1549 ast_dsp_silence(sildet, f, &dspsilence);
1551 totalsilence = dspsilence;
1555 if (totalsilence > silence) {
1556 /* Ended happily with silence */
1562 case AST_FRAME_VIDEO:
1563 ast_writestream(fs, f);
1565 /* Ignore all other frames */
1574 ast_stream_rewind(fs, silence-1000);
1575 ast_truncstream(fs);
1576 sample_offset = ast_tellstream(fs);
1578 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1579 ast_closestream(fs);
1583 res = ast_set_read_format(chan, rfmt);
1585 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1586 ast_dsp_free(sildet);
1589 return RESULT_SUCCESS;
1592 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1595 struct timeval whentohangup = { 0, 0 };
1598 return RESULT_SHOWUSAGE;
1599 if (sscanf(argv[2], "%lf", &timeout) != 1)
1600 return RESULT_SHOWUSAGE;
1604 whentohangup.tv_sec = timeout;
1605 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
1607 ast_channel_setwhentohangup_tv(chan, whentohangup);
1608 ast_agi_send(agi->fd, chan, "200 result=0\n");
1609 return RESULT_SUCCESS;
1612 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1614 struct ast_channel *c;
1617 /* no argument: hangup the current channel */
1618 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1619 ast_agi_send(agi->fd, chan, "200 result=1\n");
1620 return RESULT_SUCCESS;
1621 } else if (argc == 2) {
1622 /* one argument: look for info on the specified channel */
1623 c = ast_get_channel_by_name_locked(argv[1]);
1625 /* we have a matching channel */
1626 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1627 ast_agi_send(agi->fd, chan, "200 result=1\n");
1628 ast_channel_unlock(c);
1629 return RESULT_SUCCESS;
1631 /* if we get this far no channel name matched the argument given */
1632 ast_agi_send(agi->fd, chan, "200 result=-1\n");
1633 return RESULT_SUCCESS;
1635 return RESULT_SHOWUSAGE;
1639 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1642 struct ast_app *app_to_exec;
1645 return RESULT_SHOWUSAGE;
1647 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1649 if ((app_to_exec = pbx_findapp(argv[1]))) {
1650 if(!strcasecmp(argv[1], PARK_APP_NAME)) {
1651 ast_masq_park_call(chan, NULL, 0, NULL);
1653 if (ast_compat_res_agi && !ast_strlen_zero(argv[2])) {
1654 char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
1655 for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
1659 } else if (*vptr == '|') {
1666 res = pbx_exec(chan, app_to_exec, compat);
1668 res = pbx_exec(chan, app_to_exec, argv[2]);
1671 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1674 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
1676 /* Even though this is wrong, users are depending upon this result. */
1680 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1683 char *l = NULL, *n = NULL;
1686 ast_copy_string(tmp, argv[2], sizeof(tmp));
1687 ast_callerid_parse(tmp, &n, &l);
1689 ast_shrink_phone_number(l);
1694 ast_set_callerid(chan, l, n, NULL);
1697 ast_agi_send(agi->fd, chan, "200 result=1\n");
1698 return RESULT_SUCCESS;
1701 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1703 struct ast_channel *c;
1705 /* no argument: supply info on the current channel */
1706 ast_agi_send(agi->fd, chan, "200 result=%d\n", chan->_state);
1707 return RESULT_SUCCESS;
1708 } else if (argc == 3) {
1709 /* one argument: look for info on the specified channel */
1710 c = ast_get_channel_by_name_locked(argv[2]);
1712 ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state);
1713 ast_channel_unlock(c);
1714 return RESULT_SUCCESS;
1716 /* if we get this far no channel name matched the argument given */
1717 ast_agi_send(agi->fd, chan, "200 result=-1\n");
1718 return RESULT_SUCCESS;
1720 return RESULT_SHOWUSAGE;
1724 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1727 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1729 ast_agi_send(agi->fd, chan, "200 result=1\n");
1730 return RESULT_SUCCESS;
1733 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1739 return RESULT_SHOWUSAGE;
1741 /* check if we want to execute an ast_custom_function */
1742 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1743 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1745 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1749 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
1751 ast_agi_send(agi->fd, chan, "200 result=0\n");
1753 return RESULT_SUCCESS;
1756 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1759 struct ast_channel *chan2=NULL;
1761 if ((argc != 4) && (argc != 5))
1762 return RESULT_SHOWUSAGE;
1764 chan2 = ast_get_channel_by_name_locked(argv[4]);
1769 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1770 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", tmp);
1772 ast_agi_send(agi->fd, chan, "200 result=0\n");
1774 if (chan2 && (chan2 != chan))
1775 ast_channel_unlock(chan2);
1776 return RESULT_SUCCESS;
1779 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1784 return RESULT_SHOWUSAGE;
1787 sscanf(argv[2], "%d", &level);
1789 ast_verb(level, "%s: %s\n", chan->data, argv[1]);
1791 ast_agi_send(agi->fd, chan, "200 result=1\n");
1793 return RESULT_SUCCESS;
1796 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1802 return RESULT_SHOWUSAGE;
1803 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1805 ast_agi_send(agi->fd, chan, "200 result=0\n");
1807 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", tmp);
1809 return RESULT_SUCCESS;
1812 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1817 return RESULT_SHOWUSAGE;
1818 res = ast_db_put(argv[2], argv[3], argv[4]);
1819 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
1820 return RESULT_SUCCESS;
1823 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1828 return RESULT_SHOWUSAGE;
1829 res = ast_db_del(argv[2], argv[3]);
1830 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
1831 return RESULT_SUCCESS;
1834 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1838 if ((argc < 3) || (argc > 4))
1839 return RESULT_SHOWUSAGE;
1841 res = ast_db_deltree(argv[2], argv[3]);
1843 res = ast_db_deltree(argv[2], NULL);
1845 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
1846 return RESULT_SUCCESS;
1849 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1853 e->command = "agi set debug [on|off]";
1855 "Usage: agi set debug [on|off]\n"
1856 " Enables/disables dumping of AGI transactions for\n"
1857 " debugging purposes.\n";
1864 if (a->argc != e->args)
1865 return CLI_SHOWUSAGE;
1867 if (strncasecmp(a->argv[3], "off", 3) == 0) {
1869 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
1872 return CLI_SHOWUSAGE;
1874 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1878 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1880 ast_agi_send(agi->fd, chan, "200 result=0\n");
1881 return RESULT_SUCCESS;
1884 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1886 if (!strncasecmp(argv[2], "on", 2))
1887 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1888 else if (!strncasecmp(argv[2], "off", 3))
1890 ast_agi_send(agi->fd, chan, "200 result=0\n");
1891 return RESULT_SUCCESS;
1894 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1896 /* If a structure already exists, return an error */
1898 ast_agi_send(agi->fd, chan, "200 result=0\n");
1899 return RESULT_SUCCESS;
1902 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1903 ast_agi_send(agi->fd, chan, "200 result=1\n");
1905 ast_agi_send(agi->fd, chan, "200 result=0\n");
1907 return RESULT_SUCCESS;
1910 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1912 /* Check for minimum arguments */
1914 return RESULT_SHOWUSAGE;
1916 /* Check to make sure speech structure exists */
1918 ast_agi_send(agi->fd, chan, "200 result=0\n");
1919 return RESULT_SUCCESS;
1922 ast_speech_change(agi->speech, argv[2], argv[3]);
1923 ast_agi_send(agi->fd, chan, "200 result=1\n");
1925 return RESULT_SUCCESS;
1928 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1931 ast_speech_destroy(agi->speech);
1933 ast_agi_send(agi->fd, chan, "200 result=1\n");
1935 ast_agi_send(agi->fd, chan, "200 result=0\n");
1938 return RESULT_SUCCESS;
1941 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1944 return RESULT_SHOWUSAGE;
1947 ast_agi_send(agi->fd, chan, "200 result=0\n");
1948 return RESULT_SUCCESS;
1951 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
1952 ast_agi_send(agi->fd, chan, "200 result=0\n");
1954 ast_agi_send(agi->fd, chan, "200 result=1\n");
1956 return RESULT_SUCCESS;
1959 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1962 return RESULT_SHOWUSAGE;
1965 ast_agi_send(agi->fd, chan, "200 result=0\n");
1966 return RESULT_SUCCESS;
1969 if (ast_speech_grammar_unload(agi->speech, argv[3]))
1970 ast_agi_send(agi->fd, chan, "200 result=0\n");
1972 ast_agi_send(agi->fd, chan, "200 result=1\n");
1974 return RESULT_SUCCESS;
1977 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1980 return RESULT_SHOWUSAGE;
1983 ast_agi_send(agi->fd, chan, "200 result=0\n");
1984 return RESULT_SUCCESS;
1987 if (ast_speech_grammar_activate(agi->speech, argv[3]))
1988 ast_agi_send(agi->fd, chan, "200 result=0\n");
1990 ast_agi_send(agi->fd, chan, "200 result=1\n");
1992 return RESULT_SUCCESS;
1995 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1998 return RESULT_SHOWUSAGE;
2001 ast_agi_send(agi->fd, chan, "200 result=0\n");
2002 return RESULT_SUCCESS;
2005 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
2006 ast_agi_send(agi->fd, chan, "200 result=0\n");
2008 ast_agi_send(agi->fd, chan, "200 result=1\n");
2010 return RESULT_SUCCESS;
2013 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
2015 struct ast_filestream *fs = NULL;
2017 if (!(fs = ast_openstream(chan, filename, preflang)))
2021 ast_seekstream(fs, offset, SEEK_SET);
2023 if (ast_applystream(chan, fs))
2026 if (ast_playstream(fs))
2032 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
2034 struct ast_speech *speech = agi->speech;
2035 char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
2036 int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
2037 long current_offset = 0;
2038 const char *reason = NULL;
2039 struct ast_frame *fr = NULL;
2040 struct ast_speech_result *result = NULL;
2041 size_t left = sizeof(tmp);
2042 time_t start = 0, current;
2045 return RESULT_SHOWUSAGE;
2048 ast_agi_send(agi->fd, chan, "200 result=0\n");
2049 return RESULT_SUCCESS;
2053 timeout = atoi(argv[3]);
2055 /* If offset is specified then convert from text to integer */
2057 offset = atoi(argv[4]);
2059 /* We want frames coming in signed linear */
2060 old_read_format = chan->readformat;
2061 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2062 ast_agi_send(agi->fd, chan, "200 result=0\n");
2063 return RESULT_SUCCESS;
2066 /* Setup speech structure */
2067 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
2068 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
2069 ast_speech_start(speech);
2072 /* Start playing prompt */
2073 speech_streamfile(chan, prompt, chan->language, offset);
2075 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
2076 while (ast_strlen_zero(reason)) {
2077 /* Run scheduled items */
2078 ast_sched_runq(chan->sched);
2080 /* See maximum time of waiting */
2081 if ((res = ast_sched_wait(chan->sched)) < 0)
2084 /* Wait for frame */
2085 if (ast_waitfor(chan, res) > 0) {
2086 if (!(fr = ast_read(chan))) {
2092 /* Perform timeout check */
2093 if ((timeout > 0) && (start > 0)) {
2095 if ((current - start) >= timeout) {
2103 /* Check the speech structure for any changes */
2104 ast_mutex_lock(&speech->lock);
2106 /* See if we need to quiet the audio stream playback */
2107 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
2108 current_offset = ast_tellstream(chan->stream);
2109 ast_stopstream(chan);
2110 ast_clear_flag(speech, AST_SPEECH_QUIET);
2113 /* Check each state */
2114 switch (speech->state) {
2115 case AST_SPEECH_STATE_READY:
2116 /* If the stream is done, start timeout calculation */
2117 if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
2118 ast_stopstream(chan);
2121 /* Write audio frame data into speech engine if possible */
2122 if (fr && fr->frametype == AST_FRAME_VOICE)
2123 ast_speech_write(speech, fr->data.ptr, fr->datalen);
2125 case AST_SPEECH_STATE_WAIT:
2126 /* Cue waiting sound if not already playing */
2127 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
2128 ast_stopstream(chan);
2129 /* If a processing sound exists, or is not none - play it */
2130 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
2131 speech_streamfile(chan, speech->processing_sound, chan->language, 0);
2134 case AST_SPEECH_STATE_DONE:
2135 /* Get the results */
2136 speech->results = ast_speech_results_get(speech);
2137 /* Change state to not ready */
2138 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
2144 ast_mutex_unlock(&speech->lock);
2146 /* Check frame for DTMF or hangup */
2148 if (fr->frametype == AST_FRAME_DTMF) {
2150 dtmf = fr->subclass;
2151 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
2158 if (!strcasecmp(reason, "speech")) {
2159 /* Build string containing speech results */
2160 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
2161 /* Build result string */
2162 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);
2163 /* Increment result count */
2167 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
2168 } else if (!strcasecmp(reason, "dtmf")) {
2169 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
2170 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
2171 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
2173 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
2176 return RESULT_SUCCESS;
2179 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
2181 ast_agi_send(agi->fd, chan, "200 result=0\n");
2182 return AST_PBX_KEEPALIVE;
2185 static char usage_verbose[] =
2186 " Usage: VERBOSE <message> <level>\n"
2187 " Sends <message> to the console via verbose message system.\n"
2188 " <level> is the the verbose level (1-4)\n"
2189 " Always returns 1.\n";
2191 static char usage_getvariable[] =
2192 " Usage: GET VARIABLE <variablename>\n"
2193 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
2194 " is set and returns the variable in parentheses.\n"
2195 " example return code: 200 result=1 (testvariable)\n";
2197 static char usage_setvariable[] =
2198 " Usage: SET VARIABLE <variablename> <value>\n";
2200 static char usage_setcallerid[] =
2201 " Usage: SET CALLERID <number>\n"
2202 " Changes the callerid of the current channel.\n";
2204 static char usage_hangup[] =
2205 " Usage: HANGUP [<channelname>]\n"
2206 " Hangs up the specified channel.\n"
2207 " If no channel name is given, hangs up the current channel\n";
2209 static char usage_waitfordigit[] =
2210 " Usage: WAIT FOR DIGIT <timeout>\n"
2211 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2212 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2213 " the numerical value of the ascii of the digit if one is received. Use -1\n"
2214 " for the timeout value if you desire the call to block indefinitely.\n";
2216 static char usage_sendtext[] =
2217 " Usage: SEND TEXT \"<text to send>\"\n"
2218 " Sends the given text on a channel. Most channels do not support the\n"
2219 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
2220 " support text transmission. Returns -1 only on error/hangup. Text\n"
2221 " consisting of greater than one word should be placed in quotes since the\n"
2222 " command only accepts a single argument.\n";
2224 static char usage_recvchar[] =
2225 " Usage: RECEIVE CHAR <timeout>\n"
2226 " Receives a character of text on a channel. Specify timeout to be the\n"
2227 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2228 " do not support the reception of text. Returns the decimal value of the character\n"
2229 " if one is received, or 0 if the channel does not support text reception. Returns\n"
2230 " -1 only on error/hangup.\n";
2232 static char usage_recvtext[] =
2233 " Usage: RECEIVE TEXT <timeout>\n"
2234 " Receives a string of text on a channel. Specify timeout to be the\n"
2235 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2236 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2238 static char usage_tddmode[] =
2239 " Usage: TDD MODE <on|off>\n"
2240 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2241 " successful, or 0 if channel is not TDD-capable.\n";
2243 static char usage_sendimage[] =
2244 " Usage: SEND IMAGE <image>\n"
2245 " Sends the given image on a channel. Most channels do not support the\n"
2246 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2247 " support image transmission. Returns -1 only on error/hangup. Image names\n"
2248 " should not include extensions.\n";
2250 static char usage_streamfile[] =
2251 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2252 " Send the given file, allowing playback to be interrupted by the given\n"
2253 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2254 " permitted. If sample offset is provided then the audio will seek to sample\n"
2255 " offset before play starts. Returns 0 if playback completes without a digit\n"
2256 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2257 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2258 " extension must not be included in the filename.\n";
2260 static char usage_controlstreamfile[] =
2261 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2262 " Send the given file, allowing playback to be controled by the given\n"
2263 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2264 " permitted. Returns 0 if playback completes without a digit\n"
2265 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2266 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2267 " extension must not be included in the filename.\n\n"
2268 " Note: ffchar and rewchar default to * and # respectively.\n";
2270 static char usage_getoption[] =
2271 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2272 " Behaves similar to STREAM FILE but used with a timeout option.\n";
2274 static char usage_saynumber[] =
2275 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2276 " Say a given number, returning early if any of the given DTMF digits\n"
2277 " are received on the channel. Returns 0 if playback completes without a digit\n"
2278 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2279 " -1 on error/hangup.\n";
2281 static char usage_saydigits[] =
2282 " Usage: SAY DIGITS <number> <escape digits>\n"
2283 " Say a given digit string, returning early if any of the given DTMF digits\n"
2284 " are received on the channel. Returns 0 if playback completes without a digit\n"
2285 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2286 " -1 on error/hangup.\n";
2288 static char usage_sayalpha[] =
2289 " Usage: SAY ALPHA <number> <escape digits>\n"
2290 " Say a given character string, returning early if any of the given DTMF digits\n"
2291 " are received on the channel. Returns 0 if playback completes without a digit\n"
2292 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2293 " -1 on error/hangup.\n";
2295 static char usage_saydate[] =
2296 " Usage: SAY DATE <date> <escape digits>\n"
2297 " Say a given date, returning early if any of the given DTMF digits are\n"
2298 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
2299 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2300 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2301 " digit if one was pressed or -1 on error/hangup.\n";
2303 static char usage_saytime[] =
2304 " Usage: SAY TIME <time> <escape digits>\n"
2305 " Say a given time, returning early if any of the given DTMF digits are\n"
2306 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2307 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2308 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2309 " digit if one was pressed or -1 on error/hangup.\n";
2311 static char usage_saydatetime[] =
2312 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2313 " Say a given time, returning early if any of the given DTMF digits are\n"
2314 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2315 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2316 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
2317 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
2318 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
2319 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2320 " digit if one was pressed or -1 on error/hangup.\n";
2322 static char usage_sayphonetic[] =
2323 " Usage: SAY PHONETIC <string> <escape digits>\n"
2324 " Say a given character string with phonetics, returning early if any of the\n"
2325 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2326 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2327 " if one was pressed, or -1 on error/hangup.\n";
2329 static char usage_setcontext[] =
2330 " Usage: SET CONTEXT <desired context>\n"
2331 " Sets the context for continuation upon exiting the application.\n";
2333 static char usage_setextension[] =
2334 " Usage: SET EXTENSION <new extension>\n"
2335 " Changes the extension for continuation upon exiting the application.\n";
2337 static char usage_setpriority[] =
2338 " Usage: SET PRIORITY <priority>\n"
2339 " Changes the priority for continuation upon exiting the application.\n"
2340 " The priority must be a valid priority or label.\n";
2342 static char usage_recordfile[] =
2343 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2344 " [offset samples] [BEEP] [s=silence]\n"
2345 " Record to a file until a given dtmf digit in the sequence is received\n"
2346 " Returns -1 on hangup or error. The format will specify what kind of file\n"
2347 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
2348 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2349 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
2350 " of seconds of silence allowed before the function returns despite the\n"
2351 " lack of dtmf digits or reaching timeout. Silence value must be\n"
2352 " preceeded by \"s=\" and is also optional.\n";
2354 static char usage_autohangup[] =
2355 " Usage: SET AUTOHANGUP <time>\n"
2356 " Cause the channel to automatically hangup at <time> seconds in the\n"
2357 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
2358 " cause the autohangup feature to be disabled on this channel.\n";
2360 static char usage_break_aagi[] =
2361 " Usage: ASYNCAGI BREAK\n"
2362 " Break the Async AGI loop.\n";
2364 static char usage_noop[] =
2368 static char usage_speechcreate[] =
2369 " Usage: SPEECH CREATE <engine>\n"
2370 " Create a speech object to be used by the other Speech AGI commands.\n";
2372 static char usage_speechset[] =
2373 " Usage: SPEECH SET <name> <value>\n"
2374 " Set an engine-specific setting.\n";
2376 static char usage_speechdestroy[] =
2377 " Usage: SPEECH DESTROY\n"
2378 " Destroy the speech object created by SPEECH CREATE.\n";
2380 static char usage_speechloadgrammar[] =
2381 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2382 " Loads the specified grammar as the specified name.\n";
2384 static char usage_speechunloadgrammar[] =
2385 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2386 " Unloads the specified grammar.\n";
2388 static char usage_speechactivategrammar[] =
2389 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2390 " Activates the specified grammar on the speech object.\n";
2392 static char usage_speechdeactivategrammar[] =
2393 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2394 " Deactivates the specified grammar on the speech object.\n";
2396 static char usage_speechrecognize[] =
2397 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2398 " Plays back given prompt while listening for speech and dtmf.\n";
2401 * \brief AGI commands list
2403 static struct agi_command commands[] = {
2404 { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
2405 { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
2406 { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
2407 { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
2408 { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
2409 { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
2410 { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
2411 { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
2412 { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
2413 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2414 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2415 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2416 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2417 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2418 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2419 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2420 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2421 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2422 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2423 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2424 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2425 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2426 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2427 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2428 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2429 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2430 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2431 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2432 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2433 { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
2434 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2435 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2436 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2437 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2438 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2439 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2440 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2441 { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2442 { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2443 { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2444 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2445 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2446 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2447 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2448 { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2449 { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2452 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2454 static char *help_workhorse(int fd, char *match[])
2456 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
2457 struct agi_command *e;
2460 ast_join(matchstr, sizeof(matchstr), match);
2462 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
2463 AST_RWLIST_RDLOCK(&agi_commands);
2464 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2467 /* Hide commands that start with '_' */
2468 if ((e->cmda[0])[0] == '_')
2470 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2471 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2473 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2475 AST_RWLIST_UNLOCK(&agi_commands);
2480 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2482 char fullcmd[MAX_CMD_LEN];
2484 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2486 if (!find_command(cmd->cmda,1)) {
2487 cmd->docsrc = AST_STATIC_DOC;
2489 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
2490 cmd->summary = ast_xmldoc_build_synopsis("agi", fullcmd);
2491 cmd->usage = ast_xmldoc_build_description("agi", fullcmd);
2492 cmd->syntax = ast_xmldoc_build_syntax("agi", fullcmd);
2493 cmd->seealso = ast_xmldoc_build_seealso("agi", fullcmd);
2494 cmd->docsrc = AST_XML_DOC;
2498 AST_RWLIST_WRLOCK(&agi_commands);
2499 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2500 AST_RWLIST_UNLOCK(&agi_commands);
2501 if (mod != ast_module_info->self)
2502 ast_module_ref(ast_module_info->self);
2503 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2506 ast_log(LOG_WARNING, "Command already registered!\n");
2511 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2513 struct agi_command *e;
2514 int unregistered = 0;
2515 char fullcmd[MAX_CMD_LEN];
2517 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2519 AST_RWLIST_WRLOCK(&agi_commands);
2520 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2522 AST_RWLIST_REMOVE_CURRENT(list);
2523 if (mod != ast_module_info->self)
2524 ast_module_unref(ast_module_info->self);
2526 if (e->docsrc == AST_XML_DOC) {
2527 ast_free(e->summary);
2529 ast_free(e->syntax);
2530 ast_free(e->seealso);
2531 e->summary = NULL, e->usage = NULL;
2532 e->syntax = NULL, e->seealso = NULL;
2539 AST_RWLIST_TRAVERSE_SAFE_END;
2540 AST_RWLIST_UNLOCK(&agi_commands);
2542 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2544 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2545 return unregistered;
2548 int ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
2550 unsigned int i, x = 0;
2552 for (i = 0; i < len; i++) {
2553 if (ast_agi_register(mod, cmd + i) == 1) {
2558 /* registration failed, unregister everything
2559 that had been registered up to that point
2561 for (; x > 0; x--) {
2562 /* we are intentionally ignoring the
2563 result of ast_agi_unregister() here,
2564 but it should be safe to do so since
2565 we just registered these commands and
2566 the only possible way for unregistration
2567 to fail is if the command is not
2570 (void) ast_agi_unregister(mod, cmd + x - 1);
2578 int ast_agi_unregister_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
2583 for (i = 0; i < len; i++) {
2584 /* remember whether any of the unregistration
2585 attempts failed... there is no recourse if
2588 res |= ast_agi_unregister(mod, cmd + i);
2594 static agi_command *find_command(char *cmds[], int exact)
2597 struct agi_command *e;
2599 AST_RWLIST_RDLOCK(&agi_commands);
2600 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2603 /* start optimistic */
2605 for (y = 0; match && cmds[y]; y++) {
2606 /* If there are no more words in the command (and we're looking for
2607 an exact match) or there is a difference between the two words,
2608 then this is not a match */
2609 if (!e->cmda[y] && !exact)
2611 /* don't segfault if the next part of a command doesn't exist */
2613 AST_RWLIST_UNLOCK(&agi_commands);
2616 if (strcasecmp(e->cmda[y], cmds[y]))
2619 /* If more words are needed to complete the command then this is not
2620 a candidate (unless we're looking for a really inexact answer */
2621 if ((exact > -1) && e->cmda[y])
2624 AST_RWLIST_UNLOCK(&agi_commands);
2628 AST_RWLIST_UNLOCK(&agi_commands);
2632 static int parse_args(char *s, int *max, char *argv[])
2634 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2641 /* If it's escaped, put a literal quote */
2646 if (quoted && whitespace) {
2647 /* If we're starting a quote, coming off white space start a new word, too */
2655 if (!quoted && !escaped) {
2656 /* If we're not quoted, mark this as whitespace, and
2657 end the previous argument */
2661 /* Otherwise, just treat it as anything else */
2665 /* If we're escaped, print a literal, otherwise enable escaping */
2675 if (x >= MAX_ARGS -1) {
2676 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2679 /* Coming off of whitespace, start the next argument */
2688 /* Null terminate */
2695 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2697 char *argv[MAX_ARGS];
2698 int argc = MAX_ARGS, res;
2700 const char *ami_res = "Unknown Result";
2701 char *ami_cmd = ast_strdupa(buf);
2702 int command_id = ast_random(), resultcode = 200;
2704 manager_event(EVENT_FLAG_CALL, "AGIExec",
2705 "SubEvent: Start\r\n"
2708 "Command: %s\r\n", chan->name, command_id, ami_cmd);
2709 parse_args(buf, &argc, argv);
2710 if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2711 /* if this command wasnt registered by res_agi, be sure to usecount
2712 the module we are using */
2713 if (c->mod != ast_module_info->self)
2714 ast_module_ref(c->mod);
2715 res = c->handler(chan, agi, argc, argv);
2716 if (c->mod != ast_module_info->self)
2717 ast_module_unref(c->mod);
2719 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2720 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2721 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2722 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2724 manager_event(EVENT_FLAG_CALL, "AGIExec",
2729 "ResultCode: %d\r\n"
2730 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2732 case RESULT_SHOWUSAGE:
2733 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
2734 ast_agi_send(agi->fd, NULL, "%s", c->usage);
2735 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
2737 case AST_PBX_KEEPALIVE:
2738 /* We've been asked to keep alive, so do so */
2739 return AST_PBX_KEEPALIVE;
2741 case RESULT_FAILURE:
2742 /* They've already given the failure. We've been hung up on so handle this
2746 } else if ((c = find_command(argv, 0))) {
2747 ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
2748 manager_event(EVENT_FLAG_CALL, "AGIExec",
2753 "ResultCode: 511\r\n"
2754 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2756 ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
2757 manager_event(EVENT_FLAG_CALL, "AGIExec",
2762 "ResultCode: 510\r\n"
2763 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2767 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2769 struct ast_channel *c;
2770 int outfd, ms, needhup = 0;
2771 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2772 struct ast_frame *f;
2773 char buf[AGI_BUF_LEN];
2776 /* how many times we'll retry if ast_waitfor_nandfs will return without either
2777 channel or file descriptor in case select is interrupted by a system call (EINTR) */
2778 int retry = AGI_NANDFS_RETRY;
2781 if (!(readf = fdopen(agi->ctrl, "r"))) {
2782 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2786 return AGI_RESULT_FAILURE;
2789 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2796 } else if (agi->fast) {
2797 send(agi->ctrl, "HANGUP\n", 7, MSG_OOB);
2801 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2803 retry = AGI_NANDFS_RETRY;
2804 /* Idle the channel until we get a command */
2807 ast_debug(1, "%s hungup\n", chan->name);
2808 returnstatus = AGI_RESULT_HANGUP;
2812 /* If it's voice, write it to the audio pipe */
2813 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2814 /* Write, ignoring errors */
2815 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
2820 } else if (outfd > -1) {
2821 size_t len = sizeof(buf);
2824 retry = AGI_NANDFS_RETRY;
2827 while (buflen < (len - 1)) {
2828 res = fgets(buf + buflen, len, readf);
2831 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
2833 if (res != NULL && !agi->fast)
2835 buflen = strlen(buf);
2836 if (buflen && buf[buflen - 1] == '\n')
2840 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2844 /* Program terminated */
2845 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2847 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2849 waitpid(pid, status, 0);
2850 /* No need to kill the pid anymore, since they closed us */
2855 /* Special case for inability to execute child process */
2856 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
2857 returnstatus = AGI_RESULT_FAILURE;
2861 /* get rid of trailing newline, if any */
2862 if (*buf && buf[strlen(buf) - 1] == '\n')
2863 buf[strlen(buf) - 1] = 0;
2865 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2866 returnstatus |= agi_handle_command(chan, agi, buf, dead);
2867 /* If the handle_command returns -1, we need to stop */
2868 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2874 ast_log(LOG_WARNING, "No channel, no fd?\n");
2875 returnstatus = AGI_RESULT_FAILURE;
2880 /* Notify process */
2881 sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2882 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2884 if (kill(pid, SIGHUP)) {
2885 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2886 } else { /* Give the process a chance to die */
2889 waitpid(pid, status, WNOHANG);
2890 } else if (agi->fast) {
2891 send(agi->ctrl, "HANGUP\n", 7, MSG_OOB);
2895 return returnstatus;
2898 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2900 struct agi_command *command;
2901 char fullcmd[MAX_CMD_LEN];
2906 e->command = "agi show commands [topic]";
2908 "Usage: agi show commands [topic]\n"
2909 " When called with a topic as an argument, displays usage\n"
2910 " information on the given command. If called without a\n"
2911 " topic, it provides a list of AGI commands.\n";
2915 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
2916 return CLI_SHOWUSAGE;
2917 if (a->argc > e->args - 1) {
2918 command = find_command(a->argv + e->args, 1);
2920 char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
2921 char info[30 + MAX_CMD_LEN]; /* '-= Info about...' */
2922 char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS]; /* '-= Info about...' with colors */
2923 char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
2924 char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Description]\n with colors */
2925 char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Runs Dead]\n with colors */
2926 char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS]; /* 'Yes' or 'No' with colors */
2927 char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS]; /* [See Also]\n with colors */
2928 char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
2929 size_t synlen, desclen, seealsolen, stxlen;
2931 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
2932 term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
2933 term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
2934 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
2935 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
2936 term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
2938 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2939 snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
2940 term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
2942 if (command->docsrc == AST_XML_DOC) {
2943 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
2944 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
2945 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
2946 if (!seealso || !description || !synopsis) {
2948 goto return_cleanup;
2953 synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
2954 synopsis = ast_malloc(synlen);
2956 desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
2957 description = ast_malloc(desclen);
2959 seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
2960 seealso = ast_malloc(seealsolen);
2962 if (!synopsis || !description || !seealso) {
2964 goto return_cleanup;
2966 term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
2967 term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
2968 term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
2971 stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
2972 syntax = ast_malloc(stxlen);
2975 goto return_cleanup;
2977 term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
2979 ast_cli(a->fd, "%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n", infotitle, stxtitle, syntax,
2980 desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
2981 seealsotitle, seealso);
2984 ast_free(description);
2988 if (find_command(a->argv + e->args, -1)) {
2989 return help_workhorse(a->fd, a->argv + e->args);
2991 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2992 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2996 return help_workhorse(a->fd, NULL);
2998 return (error ? CLI_FAILURE : CLI_SUCCESS);
3001 /*! \brief Convert string to use HTML escaped characters
3002 \note Maybe this should be a generic function?
3004 static void write_html_escaped(FILE *htmlfile, char *str)
3011 fprintf(htmlfile, "%s", "<");
3014 fprintf(htmlfile, "%s", ">");
3017 fprintf(htmlfile, "%s", "&");
3020 fprintf(htmlfile, "%s", """);
3023 fprintf(htmlfile, "%c", *cur);
3032 static int write_htmldump(char *filename)
3034 struct agi_command *command;
3035 char fullcmd[MAX_CMD_LEN];
3038 if (!(htmlfile = fopen(filename, "wt")))
3041 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
3042 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
3043 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
3045 AST_RWLIST_RDLOCK(&agi_commands);
3046 AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
3050 char *tempstr, *stringp;
3052 if (!command->cmda[0]) /* end ? */
3054 /* Hide commands that start with '_' */
3055 if ((command->cmda[0])[0] == '_')
3057 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
3059 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
3060 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
3062 stringptmp = ast_xmldoc_printable(command->usage, 0);
3063 stringp = stringptmp;
3065 stringp = command->usage;
3067 tempstr = strsep(&stringp, "\n");
3069 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
3070 write_html_escaped(htmlfile, tempstr);
3071 fprintf(htmlfile, "</TD></TR>\n");
3072 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
3074 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
3075 write_html_escaped(htmlfile, tempstr);
3076 fprintf(htmlfile, "<BR>\n");
3078 fprintf(htmlfile, "</TD></TR>\n");
3079 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
3081 ast_free(stringptmp);
3084 AST_RWLIST_UNLOCK(&agi_commands);
3085 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
3090 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3094 e->command = "agi dump html";
3096 "Usage: agi dump html <filename>\n"
3097 " Dumps the AGI command list in HTML format to the given\n"
3103 if (a->argc != e->args + 1)
3104 return CLI_SHOWUSAGE;
3106 if (write_htmldump(a->argv[e->args]) < 0) {
3107 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
3108 return CLI_SHOWUSAGE;
3110 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
3114 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
3116 enum agi_result res;
3117 char buf[AGI_BUF_LEN] = "", *tmp = buf;
3118 int fds[2], efd = -1, pid;
3119 AST_DECLARE_APP_ARGS(args,
3120 AST_APP_ARG(arg)[MAX_ARGS];
3124 if (ast_strlen_zero(data)) {
3125 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
3129 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
3130 ast_copy_string(buf, data, sizeof(buf));
3131 memset(&agi, 0, sizeof(agi));
3132 AST_STANDARD_APP_ARGS(args, tmp);
3133 args.argv[args.argc] = NULL;
3135 /* Answer if need be */
3136 if (chan->_state != AST_STATE_UP) {
3137 if (ast_answer(chan))
3141 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
3142 /* Async AGI do not require run_agi(), so just proceed if normal AGI
3143 or Fast AGI are setup with success. */
3144 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
3149 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
3150 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
3151 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
3152 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
3153 res = AGI_RESULT_FAILURE;
3154 if (fds[1] != fds[0])
3159 ast_safe_fork_cleanup();
3162 case AGI_RESULT_SUCCESS:
3163 case AGI_RESULT_SUCCESS_FAST:
3164 case AGI_RESULT_SUCCESS_ASYNC:
3165 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
3167 case AGI_RESULT_FAILURE:
3168 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
3170 case AGI_RESULT_NOTFOUND:
3171 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
3173 case AGI_RESULT_HANGUP:
3174 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
3181 static int agi_exec(struct ast_channel *chan, void *data)
3183 if (!ast_check_hangup(chan))
3184 return agi_exec_full(chan, data, 0, 0);
3186 return agi_exec_full(chan, data, 0, 1);
3189 static int eagi_exec(struct ast_channel *chan, void *data)
3191 int readformat, res;
3193 if (ast_check_hangup(chan)) {
3194 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
3197 readformat = chan->readformat;
3198 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
3199 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
3202 res = agi_exec_full(chan, data, 1, 0);
3204 if (ast_set_read_format(chan, readformat)) {
3205 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
3211 static int deadagi_exec(struct ast_channel *chan, void *data)
3213 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
3214 return agi_exec(chan, data);
3217 static struct ast_cli_entry cli_agi[] = {
3218 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
3219 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
3220 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
3221 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
3224 static int unload_module(void)
3226 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
3227 /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
3228 we know that these commands were registered by this module and are still registered
3230 (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
3231 ast_unregister_application(eapp);
3232 ast_unregister_application(deadapp);
3233 ast_manager_unregister("AGI");
3234 return ast_unregister_application(app);
3237 static int load_module(void)
3239 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
3240 /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
3241 no other commands have been registered yet
3243 (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
3244 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
3245 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
3246 ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
3247 return ast_register_application(app, agi_exec, synopsis, descrip);
3250 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
3251 .load = load_module,
3252 .unload = unload_module,