2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief AGI - the Asterisk Gateway Interface
23 * \author Mark Spencer <markster@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/paths.h" /* use many ast_config_AST_*_DIR */
38 #include "asterisk/network.h"
39 #include "asterisk/file.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/module.h"
43 #include "asterisk/astdb.h"
44 #include "asterisk/callerid.h"
45 #include "asterisk/cli.h"
46 #include "asterisk/image.h"
47 #include "asterisk/say.h"
48 #include "asterisk/app.h"
49 #include "asterisk/dsp.h"
50 #include "asterisk/musiconhold.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/strings.h"
54 #include "asterisk/agi.h"
55 #include "asterisk/manager.h"
56 #include "asterisk/ast_version.h"
57 #include "asterisk/speech.h"
58 #include "asterisk/manager.h"
61 #define AGI_NANDFS_RETRY 3
62 #define AGI_BUF_LEN 2048
64 static char *app = "AGI";
66 static char *eapp = "EAGI";
68 static char *deadapp = "DeadAGI";
70 static char *synopsis = "Executes an AGI compliant application";
71 static char *esynopsis = "Executes an EAGI compliant application";
72 static char *deadsynopsis = "Executes AGI on a hungup channel";
74 static char *descrip =
75 " [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
76 "program on a channel. AGI allows Asterisk to launch external programs\n"
77 "written in any language to control a telephony channel, play audio,\n"
78 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
80 " This channel will stop dialplan execution on hangup inside of this\n"
81 "application, except when using DeadAGI. Otherwise, dialplan execution\n"
82 "will continue normally.\n"
83 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
84 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
85 "variable to \"no\" before executing the AGI application.\n"
86 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
87 "on file descriptor 3\n\n"
88 " Use the CLI command 'agi show' to list available agi commands\n"
89 " This application sets the following channel variable upon completion:\n"
90 " AGISTATUS The status of the attempt to the run the AGI script\n"
91 " text string, one of SUCCESS | FAILURE | NOTFOUND | HANGUP\n";
93 static int agidebug = 0;
95 #define TONE_BLOCK_SIZE 200
97 /* Max time to connect to an AGI remote host */
98 #define MAX_AGI_CONNECT 2000
100 #define AGI_PORT 4573
104 AGI_RESULT_SUCCESS_FAST,
105 AGI_RESULT_SUCCESS_ASYNC,
111 static agi_command *find_command(char *cmds[], int exact);
113 AST_THREADSTORAGE(agi_buf);
114 #define AGI_BUF_INITSIZE 256
116 int ast_agi_fdprintf(struct ast_channel *chan, int fd, char *fmt, ...)
122 if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
126 res = ast_str_set_va(&buf, 0, fmt, ap);
130 ast_log(LOG_ERROR, "Out of memory\n");
136 ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
138 ast_verbose("AGI Tx >> %s", buf->str);
142 return ast_carefulwrite(fd, buf->str, buf->used, 100);
145 /* linked list of AGI commands ready to be executed by Async AGI */
149 AST_LIST_ENTRY(agi_cmd) entry;
152 static void free_agi_cmd(struct agi_cmd *cmd)
154 ast_free(cmd->cmd_buffer);
155 ast_free(cmd->cmd_id);
159 /* AGI datastore destructor */
160 static void agi_destroy_commands_cb(void *data)
163 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
164 AST_LIST_LOCK(chan_cmds);
165 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
168 AST_LIST_UNLOCK(chan_cmds);
169 AST_LIST_HEAD_DESTROY(chan_cmds);
173 /* channel datastore to keep the queue of AGI commands in the channel */
174 static const struct ast_datastore_info agi_commands_datastore_info = {
176 .destroy = agi_destroy_commands_cb
179 static const char mandescr_asyncagi[] =
180 "Description: Add an AGI command to the execute queue of the channel in Async AGI\n"
182 " *Channel: Channel that is currently in Async AGI\n"
183 " *Command: Application to execute\n"
184 " CommandID: comand id. This will be sent back in CommandID header of AsyncAGI exec event notification\n"
187 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
189 struct ast_datastore *store;
191 AST_LIST_HEAD(, agi_cmd) *agi_commands;
193 ast_channel_lock(chan);
194 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
195 ast_channel_unlock(chan);
197 ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
200 agi_commands = store->data;
201 AST_LIST_LOCK(agi_commands);
202 cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
203 AST_LIST_UNLOCK(agi_commands);
207 /* channel is locked when calling this one either from the CLI or manager thread */
208 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
210 struct ast_datastore *store;
212 AST_LIST_HEAD(, agi_cmd) *agi_commands;
214 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
216 ast_log(LOG_WARNING, "Channel %s is not at Async AGI.\n", chan->name);
219 agi_commands = store->data;
220 cmd = ast_calloc(1, sizeof(*cmd));
224 cmd->cmd_buffer = ast_strdup(cmd_buff);
225 if (!cmd->cmd_buffer) {
229 cmd->cmd_id = ast_strdup(cmd_id);
231 ast_free(cmd->cmd_buffer);
235 AST_LIST_LOCK(agi_commands);
236 AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
237 AST_LIST_UNLOCK(agi_commands);
241 static int add_to_agi(struct ast_channel *chan)
243 struct ast_datastore *datastore;
244 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
246 /* check if already on AGI */
247 ast_channel_lock(chan);
248 datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
249 ast_channel_unlock(chan);
251 /* we already have an AGI datastore, let's just
256 /* the channel has never been on Async AGI,
257 let's allocate it's datastore */
258 datastore = ast_channel_datastore_alloc(&agi_commands_datastore_info, "AGI");
262 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
263 if (!agi_cmds_list) {
264 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
265 ast_channel_datastore_free(datastore);
268 datastore->data = agi_cmds_list;
269 AST_LIST_HEAD_INIT(agi_cmds_list);
270 ast_channel_lock(chan);
271 ast_channel_datastore_add(chan, datastore);
272 ast_channel_unlock(chan);
277 * \brief CLI command to add applications to execute in Async AGI
282 * \retval CLI_SUCCESS on success
283 * \retval NULL when init or tab completion is used
285 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
287 struct ast_channel *chan;
290 e->command = "agi exec";
291 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
292 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
296 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
301 return CLI_SHOWUSAGE;
302 chan = ast_get_channel_by_name_locked(a->argv[2]);
304 ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
307 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
308 ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
309 ast_channel_unlock(chan);
312 ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
313 ast_channel_unlock(chan);
318 * \brief Add a new command to execute by the Async AGI application
322 * It will append the application to the specified channel's queue
323 * if the channel is not inside Async AGI application it will return an error
324 * \retval 0 on success or incorrect use
325 * \retval 1 on failure to add the command ( most likely because the channel
326 * is not in Async AGI loop )
328 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
330 const char *channel = astman_get_header(m, "Channel");
331 const char *cmdbuff = astman_get_header(m, "Command");
332 const char *cmdid = astman_get_header(m, "CommandID");
333 struct ast_channel *chan;
335 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
336 astman_send_error(s, m, "Both, Channel and Command are *required*");
339 chan = ast_get_channel_by_name_locked(channel);
341 snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
342 astman_send_error(s, m, buf);
345 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
346 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
347 astman_send_error(s, m, buf);
348 ast_channel_unlock(chan);
351 astman_send_ack(s, m, "Added AGI command to queue");
352 ast_channel_unlock(chan);
356 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
357 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
358 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
360 /* This buffer sizes might cause truncation if the AGI command writes more data
361 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
362 that writes a response larger than 1024 bytes?, I don't think so, most of
363 them are just result=blah stuff. However probably if GET VARIABLE is called
364 and the variable has large amount of data, that could be a problem. We could
365 make this buffers dynamic, but let's leave that as a second step.
367 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
368 number. Some characters of AGI buf will be url encoded to be sent to manager
369 clients. An URL encoded character will take 3 bytes, but again, to cause
370 truncation more than about 70% of the AGI buffer should be URL encoded for
371 that to happen. Not likely at all.
373 On the other hand. I wonder if read() could eventually return less data than
374 the amount already available in the pipe? If so, how to deal with that?
375 So far, my tests on Linux have not had any problems.
377 #define AGI_BUF_SIZE 1024
378 #define AMI_BUF_SIZE 2048
383 char agi_buffer[AGI_BUF_SIZE + 1];
384 char ami_buffer[AMI_BUF_SIZE];
385 enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
389 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
390 return AGI_RESULT_FAILURE;
393 /* add AsyncAGI datastore to the channel */
394 if (add_to_agi(chan)) {
395 ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
396 return AGI_RESULT_FAILURE;
399 /* this pipe allows us to create a "fake" AGI struct to use
403 ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
404 /* intentionally do not remove datastore, added with
405 add_to_agi(), from channel. It will be removed when
406 the channel is hung up anyways */
407 return AGI_RESULT_FAILURE;
410 /* handlers will get the pipe write fd and we read the AGI responses
411 from the pipe read fd */
412 async_agi.fd = fds[1];
413 async_agi.ctrl = fds[1];
414 async_agi.audio = -1; /* no audio support */
417 /* notify possible manager users of a new channel ready to
419 setup_env(chan, "async", fds[1], 0, 0, NULL);
420 /* read the environment */
421 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
423 ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
424 returnstatus = AGI_RESULT_FAILURE;
427 agi_buffer[res] = '\0';
428 /* encode it and send it thru the manager so whoever is going to take
429 care of AGI commands on this channel can decide which AGI commands
430 to execute based on the setup info */
431 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
432 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
434 /* bail out if we need to hangup */
435 if (ast_check_hangup(chan)) {
436 ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
439 /* retrieve a command
440 (commands are added via the manager or the cli threads) */
441 cmd = get_agi_cmd(chan);
443 /* OK, we have a command, let's call the
445 res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
446 if ((res < 0) || (res == AST_PBX_KEEPALIVE)) {
450 /* the command handler must have written to our fake
451 AGI struct fd (the pipe), let's read the response */
452 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
454 returnstatus = AGI_RESULT_FAILURE;
455 ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
459 /* we have a response, let's send the response thru the
460 manager. Include the CommandID if it was specified
461 when the command was added */
462 agi_buffer[res] = '\0';
463 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
464 if (ast_strlen_zero(cmd->cmd_id))
465 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
467 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);
470 /* no command so far, wait a bit for a frame to read */
471 res = ast_waitfor(chan, timeout);
473 ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
480 ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
481 returnstatus = AGI_RESULT_HANGUP;
484 /* is there any other frame we should care about
485 besides AST_CONTROL_HANGUP? */
486 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
487 ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
495 /* notify manager users this channel cannot be
496 controlled anymore by Async AGI */
497 manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
503 /* intentionally don't get rid of the datastore. So commands can be
504 still in the queue in case AsyncAGI gets called again.
505 Datastore destructor will be called on channel destroy anyway */
513 /* launch_netscript: The fastagi handler.
514 FastAGI defaults to port 4573 */
515 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
517 int s, flags, res, port = AGI_PORT;
518 struct pollfd pfds[1];
519 char *host, *c, *script = "";
520 struct sockaddr_in sin;
522 struct ast_hostent ahp;
524 /* agiusl is "agi://host.domain[:port][/script/name]" */
525 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
526 /* Strip off any script name */
527 if ((c = strchr(host, '/'))) {
532 if ((c = strchr(host, ':'))) {
538 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
541 if (!(hp = ast_gethostbyname(host, &ahp))) {
542 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
545 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
546 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
549 if ((flags = fcntl(s, F_GETFL)) < 0) {
550 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
554 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
555 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
559 memset(&sin, 0, sizeof(sin));
560 sin.sin_family = AF_INET;
561 sin.sin_port = htons(port);
562 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
563 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
564 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
566 return AGI_RESULT_FAILURE;
570 pfds[0].events = POLLOUT;
571 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
572 if (errno != EINTR) {
574 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
575 agiurl, MAX_AGI_CONNECT);
577 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
579 return AGI_RESULT_FAILURE;
583 if (ast_agi_fdprintf(NULL, s, "agi_network: yes\n") < 0) {
584 if (errno != EINTR) {
585 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
587 return AGI_RESULT_FAILURE;
591 /* If we have a script parameter, relay it to the fastagi server */
592 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
593 if (!ast_strlen_zero(script))
594 ast_agi_fdprintf(NULL, s, "agi_network_script: %s\n", script);
596 ast_debug(4, "Wow, connected!\n");
600 return AGI_RESULT_SUCCESS_FAST;
603 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
606 int pid, toast[2], fromast[2], audio[2], res;
609 if (!strncasecmp(script, "agi://", 6))
610 return launch_netscript(script, argv, fds, efd, opid);
611 if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
612 return launch_asyncagi(chan, argv, efd);
614 if (script[0] != '/') {
615 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
619 /* Before even trying let's see if the file actually exists */
620 if (stat(script, &st)) {
621 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
622 return AGI_RESULT_NOTFOUND;
626 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
627 return AGI_RESULT_FAILURE;
630 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
633 return AGI_RESULT_FAILURE;
637 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
642 return AGI_RESULT_FAILURE;
644 res = fcntl(audio[1], F_GETFL);
646 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
648 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
655 return AGI_RESULT_FAILURE;
659 if ((pid = ast_safe_fork(1)) < 0) {
660 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
661 return AGI_RESULT_FAILURE;
664 /* Pass paths to AGI via environmental variables */
665 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
666 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
667 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
668 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
669 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
670 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
671 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
672 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
673 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
674 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
675 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
677 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
680 /* Redirect stdin and out, provide enhanced audio channel if desired */
681 dup2(fromast[0], STDIN_FILENO);
682 dup2(toast[1], STDOUT_FILENO);
684 dup2(audio[0], STDERR_FILENO + 1);
686 close(STDERR_FILENO + 1);
688 /* Close everything but stdin/out/error */
689 ast_close_fds_above_n(STDERR_FILENO + 1);
692 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
694 /* Can't use ast_log since FD's are closed */
695 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
696 /* Special case to set status of AGI to failure */
697 fprintf(stdout, "failure\n");
701 ast_verb(3, "Launched AGI Script %s\n", script);
706 /* close what we're not using in the parent */
714 return AGI_RESULT_SUCCESS;
717 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
721 /* Print initial environment, with agi_request always being the first
723 ast_agi_fdprintf(chan, fd, "agi_request: %s\n", request);
724 ast_agi_fdprintf(chan, fd, "agi_channel: %s\n", chan->name);
725 ast_agi_fdprintf(chan, fd, "agi_language: %s\n", chan->language);
726 ast_agi_fdprintf(chan, fd, "agi_type: %s\n", chan->tech->type);
727 ast_agi_fdprintf(chan, fd, "agi_uniqueid: %s\n", chan->uniqueid);
728 ast_agi_fdprintf(chan, fd, "agi_version: %s\n", ast_get_version());
731 ast_agi_fdprintf(chan, fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
732 ast_agi_fdprintf(chan, fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
733 ast_agi_fdprintf(chan, fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
734 ast_agi_fdprintf(chan, fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
735 ast_agi_fdprintf(chan, fd, "agi_callington: %d\n", chan->cid.cid_ton);
736 ast_agi_fdprintf(chan, fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
737 ast_agi_fdprintf(chan, fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
738 ast_agi_fdprintf(chan, fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
740 /* Context information */
741 ast_agi_fdprintf(chan, fd, "agi_context: %s\n", chan->context);
742 ast_agi_fdprintf(chan, fd, "agi_extension: %s\n", chan->exten);
743 ast_agi_fdprintf(chan, fd, "agi_priority: %d\n", chan->priority);
744 ast_agi_fdprintf(chan, fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
746 /* User information */
747 ast_agi_fdprintf(chan, fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
748 ast_agi_fdprintf(chan, fd, "agi_threadid: %ld\n", (long)pthread_self());
750 /* Send any parameters to the fastagi server that have been passed via the agi application */
751 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
752 for(count = 1; count < argc; count++)
753 ast_agi_fdprintf(chan, fd, "agi_arg_%d: %s\n", count, argv[count]);
755 /* End with empty return */
756 ast_agi_fdprintf(chan, fd, "\n");
759 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
763 /* Answer the channel */
764 if (chan->_state != AST_STATE_UP)
765 res = ast_answer(chan);
767 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
768 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
771 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
776 return RESULT_SHOWUSAGE;
777 if (sscanf(argv[3], "%d", &to) != 1)
778 return RESULT_SHOWUSAGE;
779 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
780 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
781 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
784 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
789 return RESULT_SHOWUSAGE;
791 /* At the moment, the parser (perhaps broken) returns with
792 the last argument PLUS the newline at the end of the input
793 buffer. This probably needs to be fixed, but I wont do that
794 because other stuff may break as a result. The right way
795 would probably be to strip off the trailing newline before
796 parsing, then here, add a newline at the end of the string
797 before sending it to ast_sendtext --DUDE */
798 res = ast_sendtext(chan, argv[2]);
799 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
800 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
803 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
808 return RESULT_SHOWUSAGE;
810 res = ast_recvchar(chan,atoi(argv[2]));
812 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
813 return RESULT_SUCCESS;
816 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
817 return RESULT_SUCCESS;
819 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup)\n", res);
820 return RESULT_FAILURE;
823 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
828 return RESULT_SHOWUSAGE;
830 buf = ast_recvtext(chan, atoi(argv[2]));
832 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
835 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
837 return RESULT_SUCCESS;
840 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
845 return RESULT_SHOWUSAGE;
847 if (!strncasecmp(argv[2],"on",2)) {
852 if (!strncasecmp(argv[2],"mate",4)) {
855 if (!strncasecmp(argv[2],"tdd",3)) {
858 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
859 if (res != RESULT_SUCCESS) {
860 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
862 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
864 return RESULT_SUCCESS;
867 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
872 return RESULT_SHOWUSAGE;
875 res = ast_send_image(chan, argv[2]);
876 if (!ast_check_hangup(chan)) {
879 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
880 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
883 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
885 int res = 0, skipms = 3000;
886 char *fwd = "#", *rev = "*", *pause = NULL, *stop = NULL; /* Default values */
888 if (argc < 5 || argc > 9) {
889 return RESULT_SHOWUSAGE;
892 if (!ast_strlen_zero(argv[4])) {
896 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1)) {
897 return RESULT_SHOWUSAGE;
900 if (argc > 6 && !ast_strlen_zero(argv[6])) {
904 if (argc > 7 && !ast_strlen_zero(argv[7])) {
908 if (argc > 8 && !ast_strlen_zero(argv[8])) {
912 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
914 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
916 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
919 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
922 struct ast_filestream *fs, *vfs;
923 long sample_offset = 0, max_length;
926 if (argc < 4 || argc > 5)
927 return RESULT_SHOWUSAGE;
932 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
933 return RESULT_SHOWUSAGE;
935 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
936 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
937 return RESULT_SUCCESS;
940 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
941 ast_debug(1, "Ooh, found a video stream, too\n");
943 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
945 ast_seekstream(fs, 0, SEEK_END);
946 max_length = ast_tellstream(fs);
947 ast_seekstream(fs, sample_offset, SEEK_SET);
948 res = ast_applystream(chan, fs);
950 vres = ast_applystream(chan, vfs);
955 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
956 /* this is to check for if ast_waitstream closed the stream, we probably are at
957 * the end of the stream, return that amount, else check for the amount */
958 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
959 ast_stopstream(chan);
961 /* Stop this command, don't print a result line, as there is a new command */
962 return RESULT_SUCCESS;
964 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
965 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
968 /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
969 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
972 struct ast_filestream *fs, *vfs;
973 long sample_offset = 0, max_length;
977 if ( argc < 4 || argc > 5 )
978 return RESULT_SHOWUSAGE;
984 timeout = atoi(argv[4]);
985 else if (chan->pbx->dtimeoutms) {
986 /* by default dtimeout is set to 5sec */
987 timeout = chan->pbx->dtimeoutms; /* in msec */
990 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
991 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
992 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
993 return RESULT_SUCCESS;
996 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
997 ast_debug(1, "Ooh, found a video stream, too\n");
999 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
1001 ast_seekstream(fs, 0, SEEK_END);
1002 max_length = ast_tellstream(fs);
1003 ast_seekstream(fs, sample_offset, SEEK_SET);
1004 res = ast_applystream(chan, fs);
1006 vres = ast_applystream(chan, vfs);
1009 ast_playstream(vfs);
1011 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
1012 /* this is to check for if ast_waitstream closed the stream, we probably are at
1013 * the end of the stream, return that amount, else check for the amount */
1014 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
1015 ast_stopstream(chan);
1017 /* Stop this command, don't print a result line, as there is a new command */
1018 return RESULT_SUCCESS;
1021 /* If the user didnt press a key, wait for digitTimeout*/
1023 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
1024 /* Make sure the new result is in the escape digits of the GET OPTION */
1025 if ( !strchr(edigits,res) )
1029 ast_agi_fdprintf(chan, agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
1030 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1036 /*! \brief Say number in various language syntaxes */
1037 /* While waiting, we're sending a NULL. */
1038 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1042 if (argc < 4 || argc > 5)
1043 return RESULT_SHOWUSAGE;
1044 if (sscanf(argv[2], "%d", &num) != 1)
1045 return RESULT_SHOWUSAGE;
1046 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
1048 return RESULT_SUCCESS;
1049 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1050 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1053 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1058 return RESULT_SHOWUSAGE;
1059 if (sscanf(argv[2], "%d", &num) != 1)
1060 return RESULT_SHOWUSAGE;
1062 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1063 if (res == 1) /* New command */
1064 return RESULT_SUCCESS;
1065 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1066 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1069 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1074 return RESULT_SHOWUSAGE;
1076 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1077 if (res == 1) /* New command */
1078 return RESULT_SUCCESS;
1079 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1080 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1083 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1088 return RESULT_SHOWUSAGE;
1089 if (sscanf(argv[2], "%d", &num) != 1)
1090 return RESULT_SHOWUSAGE;
1091 res = ast_say_date(chan, num, argv[3], chan->language);
1093 return RESULT_SUCCESS;
1094 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1095 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1098 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1103 return RESULT_SHOWUSAGE;
1104 if (sscanf(argv[2], "%d", &num) != 1)
1105 return RESULT_SHOWUSAGE;
1106 res = ast_say_time(chan, num, argv[3], chan->language);
1108 return RESULT_SUCCESS;
1109 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1110 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1113 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1117 char *format, *zone = NULL;
1120 return RESULT_SHOWUSAGE;
1125 /* XXX this doesn't belong here, but in the 'say' module */
1126 if (!strcasecmp(chan->language, "de")) {
1127 format = "A dBY HMS";
1129 format = "ABdY 'digits/at' IMp";
1133 if (argc > 5 && !ast_strlen_zero(argv[5]))
1136 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
1137 return RESULT_SHOWUSAGE;
1139 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
1141 return RESULT_SUCCESS;
1143 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1144 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1147 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1152 return RESULT_SHOWUSAGE;
1154 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
1155 if (res == 1) /* New command */
1156 return RESULT_SUCCESS;
1157 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1158 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
1161 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1163 int res, max, timeout;
1167 return RESULT_SHOWUSAGE;
1169 timeout = atoi(argv[3]);
1173 max = atoi(argv[4]);
1176 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
1177 if (res == 2) /* New command */
1178 return RESULT_SUCCESS;
1180 ast_agi_fdprintf(chan, agi->fd, "200 result=%s (timeout)\n", data);
1182 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1184 ast_agi_fdprintf(chan, agi->fd, "200 result=%s\n", data);
1185 return RESULT_SUCCESS;
1188 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1192 return RESULT_SHOWUSAGE;
1193 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
1194 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1195 return RESULT_SUCCESS;
1198 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1201 return RESULT_SHOWUSAGE;
1202 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
1203 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1204 return RESULT_SUCCESS;
1207 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1212 return RESULT_SHOWUSAGE;
1214 if (sscanf(argv[2], "%d", &pri) != 1) {
1215 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
1216 return RESULT_SHOWUSAGE;
1219 ast_explicit_goto(chan, NULL, NULL, pri);
1220 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1221 return RESULT_SUCCESS;
1224 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1226 struct ast_filestream *fs;
1227 struct ast_frame *f;
1228 struct timeval start;
1229 long sample_offset = 0;
1233 struct ast_dsp *sildet=NULL; /* silence detector dsp */
1234 int totalsilence = 0;
1236 int silence = 0; /* amount of silence to allow */
1237 int gotsilence = 0; /* did we timeout for silence? */
1238 char *silencestr=NULL;
1242 /* XXX EAGI FIXME XXX */
1245 return RESULT_SHOWUSAGE;
1246 if (sscanf(argv[5], "%d", &ms) != 1)
1247 return RESULT_SHOWUSAGE;
1250 silencestr = strchr(argv[6],'s');
1251 if ((argc > 7) && (!silencestr))
1252 silencestr = strchr(argv[7],'s');
1253 if ((argc > 8) && (!silencestr))
1254 silencestr = strchr(argv[8],'s');
1257 if (strlen(silencestr) > 2) {
1258 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
1262 silence = atoi(silencestr);
1270 rfmt = chan->readformat;
1271 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1273 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
1276 sildet = ast_dsp_new();
1278 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
1281 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
1284 /* backward compatibility, if no offset given, arg[6] would have been
1285 * caught below and taken to be a beep, else if it is a digit then it is a
1287 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
1288 res = ast_streamfile(chan, "beep", chan->language);
1290 if ((argc > 7) && (!strchr(argv[7], '=')))
1291 res = ast_streamfile(chan, "beep", chan->language);
1294 res = ast_waitstream(chan, argv[4]);
1296 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
1298 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
1301 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (writefile)\n", res);
1303 ast_dsp_free(sildet);
1304 return RESULT_FAILURE;
1307 /* Request a video update */
1308 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
1311 ast_applystream(chan,fs);
1312 /* really should have checks */
1313 ast_seekstream(fs, sample_offset, SEEK_SET);
1314 ast_truncstream(fs);
1316 start = ast_tvnow();
1317 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
1318 res = ast_waitfor(chan, -1);
1320 ast_closestream(fs);
1321 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
1323 ast_dsp_free(sildet);
1324 return RESULT_FAILURE;
1328 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
1329 ast_closestream(fs);
1331 ast_dsp_free(sildet);
1332 return RESULT_FAILURE;
1334 switch(f->frametype) {
1335 case AST_FRAME_DTMF:
1336 if (strchr(argv[4], f->subclass)) {
1337 /* This is an interrupting chracter, so rewind to chop off any small
1338 amount of DTMF that may have been recorded
1340 ast_stream_rewind(fs, 200);
1341 ast_truncstream(fs);
1342 sample_offset = ast_tellstream(fs);
1343 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
1344 ast_closestream(fs);
1347 ast_dsp_free(sildet);
1348 return RESULT_SUCCESS;
1351 case AST_FRAME_VOICE:
1352 ast_writestream(fs, f);
1353 /* this is a safe place to check progress since we know that fs
1354 * is valid after a write, and it will then have our current
1356 sample_offset = ast_tellstream(fs);
1359 ast_dsp_silence(sildet, f, &dspsilence);
1361 totalsilence = dspsilence;
1365 if (totalsilence > silence) {
1366 /* Ended happily with silence */
1372 case AST_FRAME_VIDEO:
1373 ast_writestream(fs, f);
1375 /* Ignore all other frames */
1384 ast_stream_rewind(fs, silence-1000);
1385 ast_truncstream(fs);
1386 sample_offset = ast_tellstream(fs);
1388 ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
1389 ast_closestream(fs);
1393 res = ast_set_read_format(chan, rfmt);
1395 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
1396 ast_dsp_free(sildet);
1398 return RESULT_SUCCESS;
1401 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1404 struct timeval whentohangup = { 0, 0 };
1407 return RESULT_SHOWUSAGE;
1408 if (sscanf(argv[2], "%lf", &timeout) != 1)
1409 return RESULT_SHOWUSAGE;
1413 whentohangup.tv_sec = timeout;
1414 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
1416 ast_channel_setwhentohangup_tv(chan, whentohangup);
1417 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1418 return RESULT_SUCCESS;
1421 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1423 struct ast_channel *c;
1426 /* no argument: hangup the current channel */
1427 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
1428 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1429 return RESULT_SUCCESS;
1430 } else if (argc == 2) {
1431 /* one argument: look for info on the specified channel */
1432 c = ast_get_channel_by_name_locked(argv[1]);
1434 /* we have a matching channel */
1435 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
1436 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1437 ast_channel_unlock(c);
1438 return RESULT_SUCCESS;
1440 /* if we get this far no channel name matched the argument given */
1441 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1442 return RESULT_SUCCESS;
1444 return RESULT_SHOWUSAGE;
1448 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1451 struct ast_app *app;
1454 return RESULT_SHOWUSAGE;
1456 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
1458 if ((app = pbx_findapp(argv[1]))) {
1459 if (ast_compat_res_agi && !ast_strlen_zero(argv[2])) {
1460 char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
1461 for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
1465 } else if (*vptr == '|') {
1472 res = pbx_exec(chan, app, compat);
1474 res = pbx_exec(chan, app, argv[2]);
1477 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
1480 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
1482 /* Even though this is wrong, users are depending upon this result. */
1486 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1489 char *l = NULL, *n = NULL;
1492 ast_copy_string(tmp, argv[2], sizeof(tmp));
1493 ast_callerid_parse(tmp, &n, &l);
1495 ast_shrink_phone_number(l);
1500 ast_set_callerid(chan, l, n, NULL);
1503 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1504 return RESULT_SUCCESS;
1507 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1509 struct ast_channel *c;
1511 /* no argument: supply info on the current channel */
1512 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", chan->_state);
1513 return RESULT_SUCCESS;
1514 } else if (argc == 3) {
1515 /* one argument: look for info on the specified channel */
1516 c = ast_get_channel_by_name_locked(argv[2]);
1518 ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", c->_state);
1519 ast_channel_unlock(c);
1520 return RESULT_SUCCESS;
1522 /* if we get this far no channel name matched the argument given */
1523 ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
1524 return RESULT_SUCCESS;
1526 return RESULT_SHOWUSAGE;
1530 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1533 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
1535 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1536 return RESULT_SUCCESS;
1539 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1545 return RESULT_SHOWUSAGE;
1547 /* check if we want to execute an ast_custom_function */
1548 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
1549 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
1551 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
1555 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", ret);
1557 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1559 return RESULT_SUCCESS;
1562 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1565 struct ast_channel *chan2=NULL;
1567 if ((argc != 4) && (argc != 5))
1568 return RESULT_SHOWUSAGE;
1570 chan2 = ast_get_channel_by_name_locked(argv[4]);
1575 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
1576 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1578 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1580 if (chan2 && (chan2 != chan))
1581 ast_channel_unlock(chan2);
1582 return RESULT_SUCCESS;
1585 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1590 return RESULT_SHOWUSAGE;
1593 sscanf(argv[2], "%d", &level);
1595 ast_verb(level, "%s: %s\n", chan->data, argv[1]);
1597 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1599 return RESULT_SUCCESS;
1602 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1608 return RESULT_SHOWUSAGE;
1609 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
1611 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1613 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
1615 return RESULT_SUCCESS;
1618 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1623 return RESULT_SHOWUSAGE;
1624 res = ast_db_put(argv[2], argv[3], argv[4]);
1625 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1626 return RESULT_SUCCESS;
1629 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1634 return RESULT_SHOWUSAGE;
1635 res = ast_db_del(argv[2], argv[3]);
1636 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1637 return RESULT_SUCCESS;
1640 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1644 if ((argc < 3) || (argc > 4))
1645 return RESULT_SHOWUSAGE;
1647 res = ast_db_deltree(argv[2], argv[3]);
1649 res = ast_db_deltree(argv[2], NULL);
1651 ast_agi_fdprintf(chan, agi->fd, "200 result=%c\n", res ? '0' : '1');
1652 return RESULT_SUCCESS;
1655 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1659 e->command = "agi set debug [on|off]";
1661 "Usage: agi set debug [on|off]\n"
1662 " Enables/disables dumping of AGI transactions for\n"
1663 " debugging purposes.\n";
1670 if (a->argc != e->args)
1671 return CLI_SHOWUSAGE;
1673 if (strncasecmp(a->argv[3], "off", 3) == 0) {
1675 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
1678 return CLI_SHOWUSAGE;
1680 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
1684 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
1686 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1687 return RESULT_SUCCESS;
1690 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1692 if (!strncasecmp(argv[2], "on", 2))
1693 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
1694 else if (!strncasecmp(argv[2], "off", 3))
1696 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1697 return RESULT_SUCCESS;
1700 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1702 /* If a structure already exists, return an error */
1704 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1705 return RESULT_SUCCESS;
1708 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
1709 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1711 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1713 return RESULT_SUCCESS;
1716 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1718 /* Check for minimum arguments */
1720 return RESULT_SHOWUSAGE;
1722 /* Check to make sure speech structure exists */
1724 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1725 return RESULT_SUCCESS;
1728 ast_speech_change(agi->speech, argv[2], argv[3]);
1729 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1731 return RESULT_SUCCESS;
1734 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1737 ast_speech_destroy(agi->speech);
1739 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1741 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1744 return RESULT_SUCCESS;
1747 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1750 return RESULT_SHOWUSAGE;
1753 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1754 return RESULT_SUCCESS;
1757 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
1758 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1760 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1762 return RESULT_SUCCESS;
1765 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1768 return RESULT_SHOWUSAGE;
1771 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1772 return RESULT_SUCCESS;
1775 if (ast_speech_grammar_unload(agi->speech, argv[3]))
1776 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1778 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1780 return RESULT_SUCCESS;
1783 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1786 return RESULT_SHOWUSAGE;
1789 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1790 return RESULT_SUCCESS;
1793 if (ast_speech_grammar_activate(agi->speech, argv[3]))
1794 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1796 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1798 return RESULT_SUCCESS;
1801 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1804 return RESULT_SHOWUSAGE;
1807 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1808 return RESULT_SUCCESS;
1811 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
1812 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1814 ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
1816 return RESULT_SUCCESS;
1819 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
1821 struct ast_filestream *fs = NULL;
1823 if (!(fs = ast_openstream(chan, filename, preflang)))
1827 ast_seekstream(fs, offset, SEEK_SET);
1829 if (ast_applystream(chan, fs))
1832 if (ast_playstream(fs))
1838 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
1840 struct ast_speech *speech = agi->speech;
1841 char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
1842 int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
1843 long current_offset = 0;
1844 const char *reason = NULL;
1845 struct ast_frame *fr = NULL;
1846 struct ast_speech_result *result = NULL;
1847 size_t left = sizeof(tmp);
1848 time_t start = 0, current;
1851 return RESULT_SHOWUSAGE;
1854 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1855 return RESULT_SUCCESS;
1859 timeout = atoi(argv[3]);
1861 /* If offset is specified then convert from text to integer */
1863 offset = atoi(argv[4]);
1865 /* We want frames coming in signed linear */
1866 old_read_format = chan->readformat;
1867 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
1868 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1869 return RESULT_SUCCESS;
1872 /* Setup speech structure */
1873 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
1874 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1875 ast_speech_start(speech);
1878 /* Start playing prompt */
1879 speech_streamfile(chan, prompt, chan->language, offset);
1881 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
1882 while (ast_strlen_zero(reason)) {
1883 /* Run scheduled items */
1884 ast_sched_runq(chan->sched);
1886 /* See maximum time of waiting */
1887 if ((res = ast_sched_wait(chan->sched)) < 0)
1890 /* Wait for frame */
1891 if (ast_waitfor(chan, res) > 0) {
1892 if (!(fr = ast_read(chan))) {
1898 /* Perform timeout check */
1899 if ((timeout > 0) && (start > 0)) {
1901 if ((current - start) >= timeout) {
1909 /* Check the speech structure for any changes */
1910 ast_mutex_lock(&speech->lock);
1912 /* See if we need to quiet the audio stream playback */
1913 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
1914 current_offset = ast_tellstream(chan->stream);
1915 ast_stopstream(chan);
1916 ast_clear_flag(speech, AST_SPEECH_QUIET);
1919 /* Check each state */
1920 switch (speech->state) {
1921 case AST_SPEECH_STATE_READY:
1922 /* If the stream is done, start timeout calculation */
1923 if ((timeout > 0) && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
1924 ast_stopstream(chan);
1927 /* Write audio frame data into speech engine if possible */
1928 if (fr && fr->frametype == AST_FRAME_VOICE)
1929 ast_speech_write(speech, fr->data.ptr, fr->datalen);
1931 case AST_SPEECH_STATE_WAIT:
1932 /* Cue waiting sound if not already playing */
1933 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
1934 ast_stopstream(chan);
1935 /* If a processing sound exists, or is not none - play it */
1936 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
1937 speech_streamfile(chan, speech->processing_sound, chan->language, 0);
1940 case AST_SPEECH_STATE_DONE:
1941 /* Get the results */
1942 speech->results = ast_speech_results_get(speech);
1943 /* Change state to not ready */
1944 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
1950 ast_mutex_unlock(&speech->lock);
1952 /* Check frame for DTMF or hangup */
1954 if (fr->frametype == AST_FRAME_DTMF) {
1956 dtmf = fr->subclass;
1957 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
1964 if (!strcasecmp(reason, "speech")) {
1965 /* Build string containing speech results */
1966 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
1967 /* Build result string */
1968 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);
1969 /* Increment result count */
1973 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
1974 } else if (!strcasecmp(reason, "dtmf")) {
1975 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
1976 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
1977 ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
1979 ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
1982 return RESULT_SUCCESS;
1985 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
1987 ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
1988 return AST_PBX_KEEPALIVE;
1991 static char usage_setmusic[] =
1992 " Usage: SET MUSIC ON <on|off> <class>\n"
1993 " Enables/Disables the music on hold generator. If <class> is\n"
1994 " not specified, then the default music on hold class will be used.\n"
1995 " Always returns 0.\n";
1997 static char usage_dbput[] =
1998 " Usage: DATABASE PUT <family> <key> <value>\n"
1999 " Adds or updates an entry in the Asterisk database for a\n"
2000 " given family, key, and value.\n"
2001 " Returns 1 if successful, 0 otherwise.\n";
2003 static char usage_dbget[] =
2004 " Usage: DATABASE GET <family> <key>\n"
2005 " Retrieves an entry in the Asterisk database for a\n"
2006 " given family and key.\n"
2007 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
2008 " is set and returns the variable in parentheses.\n"
2009 " Example return code: 200 result=1 (testvariable)\n";
2011 static char usage_dbdel[] =
2012 " Usage: DATABASE DEL <family> <key>\n"
2013 " Deletes an entry in the Asterisk database for a\n"
2014 " given family and key.\n"
2015 " Returns 1 if successful, 0 otherwise.\n";
2017 static char usage_dbdeltree[] =
2018 " Usage: DATABASE DELTREE <family> [keytree]\n"
2019 " Deletes a family or specific keytree within a family\n"
2020 " in the Asterisk database.\n"
2021 " Returns 1 if successful, 0 otherwise.\n";
2023 static char usage_verbose[] =
2024 " Usage: VERBOSE <message> <level>\n"
2025 " Sends <message> to the console via verbose message system.\n"
2026 " <level> is the the verbose level (1-4)\n"
2027 " Always returns 1.\n";
2029 static char usage_getvariable[] =
2030 " Usage: GET VARIABLE <variablename>\n"
2031 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
2032 " is set and returns the variable in parentheses.\n"
2033 " example return code: 200 result=1 (testvariable)\n";
2035 static char usage_getvariablefull[] =
2036 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
2037 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
2038 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
2039 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
2040 " example return code: 200 result=1 (testvariable)\n";
2042 static char usage_setvariable[] =
2043 " Usage: SET VARIABLE <variablename> <value>\n";
2045 static char usage_channelstatus[] =
2046 " Usage: CHANNEL STATUS [<channelname>]\n"
2047 " Returns the status of the specified channel.\n"
2048 " If no channel name is given the returns the status of the\n"
2049 " current channel. Return values:\n"
2050 " 0 Channel is down and available\n"
2051 " 1 Channel is down, but reserved\n"
2052 " 2 Channel is off hook\n"
2053 " 3 Digits (or equivalent) have been dialed\n"
2054 " 4 Line is ringing\n"
2055 " 5 Remote end is ringing\n"
2057 " 7 Line is busy\n";
2059 static char usage_setcallerid[] =
2060 " Usage: SET CALLERID <number>\n"
2061 " Changes the callerid of the current channel.\n";
2063 static char usage_exec[] =
2064 " Usage: EXEC <application> <options>\n"
2065 " Executes <application> with given <options>.\n"
2066 " Returns whatever the application returns, or -2 on failure to find application\n";
2068 static char usage_hangup[] =
2069 " Usage: HANGUP [<channelname>]\n"
2070 " Hangs up the specified channel.\n"
2071 " If no channel name is given, hangs up the current channel\n";
2073 static char usage_answer[] =
2075 " Answers channel if not already in answer state. Returns -1 on\n"
2076 " channel failure, or 0 if successful.\n";
2078 static char usage_waitfordigit[] =
2079 " Usage: WAIT FOR DIGIT <timeout>\n"
2080 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
2081 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
2082 " the numerical value of the ascii of the digit if one is received. Use -1\n"
2083 " for the timeout value if you desire the call to block indefinitely.\n";
2085 static char usage_sendtext[] =
2086 " Usage: SEND TEXT \"<text to send>\"\n"
2087 " Sends the given text on a channel. Most channels do not support the\n"
2088 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
2089 " support text transmission. Returns -1 only on error/hangup. Text\n"
2090 " consisting of greater than one word should be placed in quotes since the\n"
2091 " command only accepts a single argument.\n";
2093 static char usage_recvchar[] =
2094 " Usage: RECEIVE CHAR <timeout>\n"
2095 " Receives a character of text on a channel. Specify timeout to be the\n"
2096 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2097 " do not support the reception of text. Returns the decimal value of the character\n"
2098 " if one is received, or 0 if the channel does not support text reception. Returns\n"
2099 " -1 only on error/hangup.\n";
2101 static char usage_recvtext[] =
2102 " Usage: RECEIVE TEXT <timeout>\n"
2103 " Receives a string of text on a channel. Specify timeout to be the\n"
2104 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
2105 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
2107 static char usage_tddmode[] =
2108 " Usage: TDD MODE <on|off>\n"
2109 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
2110 " successful, or 0 if channel is not TDD-capable.\n";
2112 static char usage_sendimage[] =
2113 " Usage: SEND IMAGE <image>\n"
2114 " Sends the given image on a channel. Most channels do not support the\n"
2115 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
2116 " support image transmission. Returns -1 only on error/hangup. Image names\n"
2117 " should not include extensions.\n";
2119 static char usage_streamfile[] =
2120 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
2121 " Send the given file, allowing playback to be interrupted by the given\n"
2122 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2123 " permitted. If sample offset is provided then the audio will seek to sample\n"
2124 " offset before play starts. Returns 0 if playback completes without a digit\n"
2125 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2126 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2127 " extension must not be included in the filename.\n";
2129 static char usage_controlstreamfile[] =
2130 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
2131 " Send the given file, allowing playback to be controled by the given\n"
2132 " digits, if any. Use double quotes for the digits if you wish none to be\n"
2133 " permitted. Returns 0 if playback completes without a digit\n"
2134 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
2135 " or -1 on error or if the channel was disconnected. Remember, the file\n"
2136 " extension must not be included in the filename.\n\n"
2137 " Note: ffchar and rewchar default to * and # respectively.\n";
2139 static char usage_getoption[] =
2140 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
2141 " Behaves similar to STREAM FILE but used with a timeout option.\n";
2143 static char usage_saynumber[] =
2144 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
2145 " Say a given number, returning early if any of the given DTMF digits\n"
2146 " are received on the channel. Returns 0 if playback completes without a digit\n"
2147 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2148 " -1 on error/hangup.\n";
2150 static char usage_saydigits[] =
2151 " Usage: SAY DIGITS <number> <escape digits>\n"
2152 " Say a given digit string, returning early if any of the given DTMF digits\n"
2153 " are received on the channel. Returns 0 if playback completes without a digit\n"
2154 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2155 " -1 on error/hangup.\n";
2157 static char usage_sayalpha[] =
2158 " Usage: SAY ALPHA <number> <escape digits>\n"
2159 " Say a given character string, returning early if any of the given DTMF digits\n"
2160 " are received on the channel. Returns 0 if playback completes without a digit\n"
2161 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
2162 " -1 on error/hangup.\n";
2164 static char usage_saydate[] =
2165 " Usage: SAY DATE <date> <escape digits>\n"
2166 " Say a given date, returning early if any of the given DTMF digits are\n"
2167 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
2168 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2169 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2170 " digit if one was pressed or -1 on error/hangup.\n";
2172 static char usage_saytime[] =
2173 " Usage: SAY TIME <time> <escape digits>\n"
2174 " Say a given time, returning early if any of the given DTMF digits are\n"
2175 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2176 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
2177 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2178 " digit if one was pressed or -1 on error/hangup.\n";
2180 static char usage_saydatetime[] =
2181 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
2182 " Say a given time, returning early if any of the given DTMF digits are\n"
2183 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
2184 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
2185 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
2186 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
2187 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
2188 " completes without a digit being pressed, or the ASCII numerical value of the\n"
2189 " digit if one was pressed or -1 on error/hangup.\n";
2191 static char usage_sayphonetic[] =
2192 " Usage: SAY PHONETIC <string> <escape digits>\n"
2193 " Say a given character string with phonetics, returning early if any of the\n"
2194 " given DTMF digits are received on the channel. Returns 0 if playback\n"
2195 " completes without a digit pressed, the ASCII numerical value of the digit\n"
2196 " if one was pressed, or -1 on error/hangup.\n";
2198 static char usage_getdata[] =
2199 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
2200 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
2201 "from the channel at the other end.\n";
2203 static char usage_setcontext[] =
2204 " Usage: SET CONTEXT <desired context>\n"
2205 " Sets the context for continuation upon exiting the application.\n";
2207 static char usage_setextension[] =
2208 " Usage: SET EXTENSION <new extension>\n"
2209 " Changes the extension for continuation upon exiting the application.\n";
2211 static char usage_setpriority[] =
2212 " Usage: SET PRIORITY <priority>\n"
2213 " Changes the priority for continuation upon exiting the application.\n"
2214 " The priority must be a valid priority or label.\n";
2216 static char usage_recordfile[] =
2217 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
2218 " [offset samples] [BEEP] [s=silence]\n"
2219 " Record to a file until a given dtmf digit in the sequence is received\n"
2220 " Returns -1 on hangup or error. The format will specify what kind of file\n"
2221 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
2222 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
2223 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
2224 " of seconds of silence allowed before the function returns despite the\n"
2225 " lack of dtmf digits or reaching timeout. Silence value must be\n"
2226 " preceeded by \"s=\" and is also optional.\n";
2228 static char usage_autohangup[] =
2229 " Usage: SET AUTOHANGUP <time>\n"
2230 " Cause the channel to automatically hangup at <time> seconds in the\n"
2231 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
2232 " cause the autohangup feature to be disabled on this channel.\n";
2234 static char usage_break_aagi[] =
2235 " Usage: ASYNCAGI BREAK\n"
2236 " Break the Async AGI loop.\n";
2238 static char usage_noop[] =
2242 static char usage_speechcreate[] =
2243 " Usage: SPEECH CREATE <engine>\n"
2244 " Create a speech object to be used by the other Speech AGI commands.\n";
2246 static char usage_speechset[] =
2247 " Usage: SPEECH SET <name> <value>\n"
2248 " Set an engine-specific setting.\n";
2250 static char usage_speechdestroy[] =
2251 " Usage: SPEECH DESTROY\n"
2252 " Destroy the speech object created by SPEECH CREATE.\n";
2254 static char usage_speechloadgrammar[] =
2255 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
2256 " Loads the specified grammar as the specified name.\n";
2258 static char usage_speechunloadgrammar[] =
2259 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
2260 " Unloads the specified grammar.\n";
2262 static char usage_speechactivategrammar[] =
2263 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
2264 " Activates the specified grammar on the speech object.\n";
2266 static char usage_speechdeactivategrammar[] =
2267 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
2268 " Deactivates the specified grammar on the speech object.\n";
2270 static char usage_speechrecognize[] =
2271 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
2272 " Plays back given prompt while listening for speech and dtmf.\n";
2275 * \brief AGI commands list
2277 static struct agi_command commands[] = {
2278 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
2279 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
2280 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
2281 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
2282 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
2283 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
2284 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
2285 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
2286 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
2287 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
2288 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
2289 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
2290 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
2291 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
2292 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
2293 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
2294 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
2295 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
2296 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
2297 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
2298 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
2299 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
2300 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
2301 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
2302 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
2303 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
2304 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
2305 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
2306 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
2307 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
2308 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
2309 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
2310 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
2311 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
2312 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
2313 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
2314 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
2315 { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
2316 { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
2317 { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
2318 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
2319 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
2320 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
2321 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
2322 { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
2323 { { "asyncagi", "break", NULL }, handle_asyncagi_break, "Break AsyncAGI loop", usage_break_aagi, 0 },
2326 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
2328 static char *help_workhorse(int fd, char *match[])
2330 char fullcmd[80], matchstr[80];
2331 struct agi_command *e;
2334 ast_join(matchstr, sizeof(matchstr), match);
2336 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
2337 AST_RWLIST_RDLOCK(&agi_commands);
2338 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2341 /* Hide commands that start with '_' */
2342 if ((e->cmda[0])[0] == '_')
2344 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
2345 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
2347 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, e->summary);
2349 AST_RWLIST_UNLOCK(&agi_commands);
2354 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
2358 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2360 if (!find_command(cmd->cmda,1)) {
2362 AST_RWLIST_WRLOCK(&agi_commands);
2363 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
2364 AST_RWLIST_UNLOCK(&agi_commands);
2365 if (mod != ast_module_info->self)
2366 ast_module_ref(ast_module_info->self);
2367 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
2370 ast_log(LOG_WARNING, "Command already registered!\n");
2375 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
2377 struct agi_command *e;
2378 int unregistered = 0;
2381 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
2383 AST_RWLIST_WRLOCK(&agi_commands);
2384 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
2386 AST_RWLIST_REMOVE_CURRENT(list);
2387 if (mod != ast_module_info->self)
2388 ast_module_unref(ast_module_info->self);
2393 AST_RWLIST_TRAVERSE_SAFE_END;
2394 AST_RWLIST_UNLOCK(&agi_commands);
2396 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
2398 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
2399 return unregistered;
2402 void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len)
2406 for (i = 0; i < len; i++)
2407 ast_agi_register(mod, cmd + i);
2411 void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len)
2415 for (i = 0; i < len; i++)
2416 ast_agi_unregister(mod, cmd + i);
2419 static agi_command *find_command(char *cmds[], int exact)
2422 struct agi_command *e;
2424 AST_RWLIST_RDLOCK(&agi_commands);
2425 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
2428 /* start optimistic */
2430 for (y = 0; match && cmds[y]; y++) {
2431 /* If there are no more words in the command (and we're looking for
2432 an exact match) or there is a difference between the two words,
2433 then this is not a match */
2434 if (!e->cmda[y] && !exact)
2436 /* don't segfault if the next part of a command doesn't exist */
2439 if (strcasecmp(e->cmda[y], cmds[y]))
2442 /* If more words are needed to complete the command then this is not
2443 a candidate (unless we're looking for a really inexact answer */
2444 if ((exact > -1) && e->cmda[y])
2449 AST_RWLIST_UNLOCK(&agi_commands);
2453 static int parse_args(char *s, int *max, char *argv[])
2455 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
2462 /* If it's escaped, put a literal quote */
2467 if (quoted && whitespace) {
2468 /* If we're starting a quote, coming off white space start a new word, too */
2476 if (!quoted && !escaped) {
2477 /* If we're not quoted, mark this as whitespace, and
2478 end the previous argument */
2482 /* Otherwise, just treat it as anything else */
2486 /* If we're escaped, print a literal, otherwise enable escaping */
2496 if (x >= MAX_ARGS -1) {
2497 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
2500 /* Coming off of whitespace, start the next argument */
2509 /* Null terminate */
2516 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
2518 char *argv[MAX_ARGS];
2519 int argc = MAX_ARGS, res;
2521 const char *ami_res = "Unknown Result";
2522 char *ami_cmd = ast_strdupa(buf);
2523 int command_id = ast_random(), resultcode = 200;
2525 manager_event(EVENT_FLAG_CALL, "AGIExec",
2526 "SubEvent: Start\r\n"
2529 "Command: %s\r\n", chan->name, command_id, ami_cmd);
2530 parse_args(buf, &argc, argv);
2531 if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
2532 /* if this command wasnt registered by res_agi, be sure to usecount
2533 the module we are using */
2534 if (c->mod != ast_module_info->self)
2535 ast_module_ref(c->mod);
2536 res = c->handler(chan, agi, argc, argv);
2537 if (c->mod != ast_module_info->self)
2538 ast_module_unref(c->mod);
2540 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
2541 case AST_PBX_KEEPALIVE: ami_res = "KeepAlive"; resultcode = 210; break;
2542 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
2543 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
2545 manager_event(EVENT_FLAG_CALL, "AGIExec",
2550 "ResultCode: %d\r\n"
2551 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
2553 case RESULT_SHOWUSAGE:
2554 ast_agi_fdprintf(chan, agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
2555 ast_agi_fdprintf(chan, agi->fd, c->usage);
2556 ast_agi_fdprintf(chan, agi->fd, "520 End of proper usage.\n");
2558 case AST_PBX_KEEPALIVE:
2559 /* We've been asked to keep alive, so do so */
2560 return AST_PBX_KEEPALIVE;
2562 case RESULT_FAILURE:
2563 /* They've already given the failure. We've been hung up on so handle this
2567 } else if ((c = find_command(argv, 0))) {
2568 ast_agi_fdprintf(chan, agi->fd, "511 Command Not Permitted on a dead channel\n");
2569 manager_event(EVENT_FLAG_CALL, "AGIExec",
2574 "ResultCode: 511\r\n"
2575 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
2577 ast_agi_fdprintf(chan, agi->fd, "510 Invalid or unknown command\n");
2578 manager_event(EVENT_FLAG_CALL, "AGIExec",
2583 "ResultCode: 510\r\n"
2584 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
2588 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
2590 struct ast_channel *c;
2591 int outfd, ms, needhup = 0;
2592 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
2593 struct ast_frame *f;
2594 char buf[AGI_BUF_LEN];
2597 /* how many times we'll retry if ast_waitfor_nandfs will return without either
2598 channel or file descriptor in case select is interrupted by a system call (EINTR) */
2599 int retry = AGI_NANDFS_RETRY;
2601 if (!(readf = fdopen(agi->ctrl, "r"))) {
2602 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
2606 return AGI_RESULT_FAILURE;
2609 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
2618 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
2620 retry = AGI_NANDFS_RETRY;
2621 /* Idle the channel until we get a command */
2624 ast_debug(1, "%s hungup\n", chan->name);
2625 returnstatus = AGI_RESULT_HANGUP;
2629 /* If it's voice, write it to the audio pipe */
2630 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
2631 /* Write, ignoring errors */
2632 write(agi->audio, f->data.ptr, f->datalen);
2636 } else if (outfd > -1) {
2637 size_t len = sizeof(buf);
2640 retry = AGI_NANDFS_RETRY;
2643 while (buflen < (len - 1)) {
2644 res = fgets(buf + buflen, len, readf);
2647 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
2649 if (res != NULL && !agi->fast)
2651 buflen = strlen(buf);
2652 if (buflen && buf[buflen - 1] == '\n')
2656 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
2660 /* Program terminated */
2661 if (returnstatus && returnstatus != AST_PBX_KEEPALIVE)
2663 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
2665 waitpid(pid, status, 0);
2666 /* No need to kill the pid anymore, since they closed us */
2671 /* Special case for inability to execute child process */
2672 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
2673 returnstatus = AGI_RESULT_FAILURE;
2677 /* get rid of trailing newline, if any */
2678 if (*buf && buf[strlen(buf) - 1] == '\n')
2679 buf[strlen(buf) - 1] = 0;
2681 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
2682 returnstatus |= agi_handle_command(chan, agi, buf, dead);
2683 /* If the handle_command returns -1, we need to stop */
2684 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
2690 ast_log(LOG_WARNING, "No channel, no fd?\n");
2691 returnstatus = AGI_RESULT_FAILURE;
2696 /* Notify process */
2698 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
2699 if (ast_strlen_zero(sighup) || !ast_false(sighup)) {
2700 if (kill(pid, SIGHUP)) {
2701 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
2702 } else { /* Give the process a chance to die */
2706 waitpid(pid, status, WNOHANG);
2709 return returnstatus;
2712 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2714 struct agi_command *command;
2719 e->command = "agi show";
2721 "Usage: agi show [topic]\n"
2722 " When called with a topic as an argument, displays usage\n"
2723 " information on the given command. If called without a\n"
2724 " topic, it provides a list of AGI commands.\n";
2729 if (a->argc < e->args)
2730 return CLI_SHOWUSAGE;
2731 if (a->argc > e->args) {
2732 command = find_command(a->argv + e->args, 1);
2734 ast_cli(a->fd, "%s", command->usage);
2735 ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
2737 if (find_command(a->argv + e->args, -1)) {
2738 return help_workhorse(a->fd, a->argv + e->args);
2740 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
2741 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
2745 return help_workhorse(a->fd, NULL);
2750 /*! \brief Convert string to use HTML escaped characters
2751 \note Maybe this should be a generic function?
2753 static void write_html_escaped(FILE *htmlfile, char *str)
2760 fprintf(htmlfile, "%s", "<");
2763 fprintf(htmlfile, "%s", ">");
2766 fprintf(htmlfile, "%s", "&");
2769 fprintf(htmlfile, "%s", """);
2772 fprintf(htmlfile, "%c", *cur);
2781 static int write_htmldump(char *filename)
2783 struct agi_command *command;
2787 if (!(htmlfile = fopen(filename, "wt")))
2790 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
2791 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
2792 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
2794 AST_RWLIST_RDLOCK(&agi_commands);
2795 AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
2796 char *stringp, *tempstr;
2798 if (!command->cmda[0]) /* end ? */
2800 /* Hide commands that start with '_' */
2801 if ((command->cmda[0])[0] == '_')
2803 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
2805 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
2806 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
2808 stringp = command->usage;
2809 tempstr = strsep(&stringp, "\n");
2811 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
2812 write_html_escaped(htmlfile, tempstr);
2813 fprintf(htmlfile, "</TD></TR>\n");
2814 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
2816 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
2817 write_html_escaped(htmlfile, tempstr);
2818 fprintf(htmlfile, "<BR>\n");
2820 fprintf(htmlfile, "</TD></TR>\n");
2821 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
2823 AST_RWLIST_UNLOCK(&agi_commands);
2824 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
2829 static char *handle_cli_agi_dumphtml_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2833 e->command = "agi dumphtml";
2835 "Usage: agi dumphtml <filename>\n"
2836 " Dumps the AGI command list in HTML format to the given\n"
2842 if (a->argc < e->args + 1)
2843 return CLI_SHOWUSAGE;
2845 if (write_htmldump(a->argv[2]) < 0) {
2846 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
2847 return CLI_SHOWUSAGE;
2849 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
2853 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2857 e->command = "agi dump html";
2859 "Usage: agi dump html <filename>\n"
2860 " Dumps the AGI command list in HTML format to the given\n"
2866 if (a->argc != e->args + 1)
2867 return CLI_SHOWUSAGE;
2869 if (write_htmldump(a->argv[e->args]) < 0) {
2870 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
2871 return CLI_SHOWUSAGE;
2873 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
2877 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
2879 enum agi_result res;
2880 char buf[AGI_BUF_LEN] = "", *tmp = buf;
2881 int fds[2], efd = -1, pid;
2882 AST_DECLARE_APP_ARGS(args,
2883 AST_APP_ARG(arg)[MAX_ARGS];
2887 if (ast_strlen_zero(data)) {
2888 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
2892 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
2893 ast_copy_string(buf, data, sizeof(buf));
2894 memset(&agi, 0, sizeof(agi));
2895 AST_STANDARD_APP_ARGS(args, tmp);
2896 args.argv[args.argc] = NULL;
2898 /* Answer if need be */
2899 if (chan->_state != AST_STATE_UP) {
2900 if (ast_answer(chan))
2904 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
2905 /* Async AGI do not require run_agi(), so just proceed if normal AGI
2906 or Fast AGI are setup with success. */
2907 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
2912 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
2913 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
2914 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2915 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
2916 res = AGI_RESULT_FAILURE;
2917 if (fds[1] != fds[0])
2922 ast_safe_fork_cleanup();
2925 case AGI_RESULT_SUCCESS:
2926 case AGI_RESULT_SUCCESS_FAST:
2927 case AGI_RESULT_SUCCESS_ASYNC:
2928 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
2930 case AGI_RESULT_FAILURE:
2931 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
2933 case AGI_RESULT_NOTFOUND:
2934 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
2936 case AGI_RESULT_HANGUP:
2937 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
2944 static int agi_exec(struct ast_channel *chan, void *data)
2946 if (!ast_check_hangup(chan))
2947 return agi_exec_full(chan, data, 0, 0);
2949 return agi_exec_full(chan, data, 0, 1);
2952 static int eagi_exec(struct ast_channel *chan, void *data)
2954 int readformat, res;
2956 if (ast_check_hangup(chan)) {
2957 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
2960 readformat = chan->readformat;
2961 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
2962 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
2965 res = agi_exec_full(chan, data, 1, 0);
2967 if (ast_set_read_format(chan, readformat)) {
2968 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
2974 static int deadagi_exec(struct ast_channel *chan, void *data)
2976 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
2977 return agi_exec(chan, data);
2980 static struct ast_cli_entry cli_agi_dumphtml_deprecated = AST_CLI_DEFINE(handle_cli_agi_dumphtml_deprecated, "Dumps a list of AGI commands in HTML format");
2982 static struct ast_cli_entry cli_agi[] = {
2983 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
2984 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
2985 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
2986 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format", .deprecate_cmd = &cli_agi_dumphtml_deprecated)
2989 static int unload_module(void)
2991 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
2992 ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
2993 ast_unregister_application(eapp);
2994 ast_unregister_application(deadapp);
2995 ast_manager_unregister("AGI");
2996 return ast_unregister_application(app);
2999 static int load_module(void)
3001 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
3002 ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command));
3003 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
3004 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
3005 ast_manager_register2("AGI", EVENT_FLAG_CALL, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
3006 return ast_register_application(app, agi_exec, synopsis, descrip);
3009 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
3010 .load = load_module,
3011 .unload = unload_module,