#include "asterisk.h"
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/capability.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/astdb.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/options.h"
#include "asterisk/image.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/strings.h"
#include "asterisk/agi.h"
#include "asterisk/features.h"
Go to the source code of this file.
Data Structures | |
struct | zombie |
struct | zombies |
Defines | |
#define | AGI_BUF_LEN 2048 |
#define | AGI_NANDFS_RETRY 3 |
#define | AGI_PORT 4573 |
#define | fdprintf agi_debug_cli |
#define | MAX_AGI_CONNECT 2000 |
#define | MAX_ARGS 128 |
#define | MAX_COMMANDS 128 |
#define | TONE_BLOCK_SIZE 200 |
Enumerations | |
enum | agi_result { AGI_RESULT_FAILURE = -1, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_FAST, AGI_RESULT_HANGUP } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | agi_debug_cli (int fd, char *fmt,...) |
static int | agi_do_debug (int fd, int argc, char *argv[]) |
static int | agi_exec (struct ast_channel *chan, void *data) |
static int | agi_exec_full (struct ast_channel *chan, void *data, int enhanced, int dead) |
static enum agi_result | agi_handle_command (struct ast_channel *chan, AGI *agi, char *buf) |
static int | agi_no_debug (int fd, int argc, char *argv[]) |
static int | agi_no_debug_deprecated (int fd, int argc, char *argv[]) |
int | ast_agi_register (agi_command *agi) |
void | ast_agi_unregister (agi_command *agi) |
static int | deadagi_exec (struct ast_channel *chan, void *data) |
static int | eagi_exec (struct ast_channel *chan, void *data) |
static agi_command * | find_command (char *cmds[], int exact) |
static int | handle_agidumphtml (int fd, int argc, char *argv[]) |
static int | handle_answer (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_autohangup (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_channelstatus (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_controlstreamfile (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_dbdel (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_dbdeltree (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_dbget (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_dbput (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_exec (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_getdata (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_getoption (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_getvariable (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_getvariablefull (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_hangup (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_noop (struct ast_channel *chan, AGI *agi, int arg, char *argv[]) |
static int | handle_recordfile (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_recvchar (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_recvtext (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_sayalpha (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_saydate (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_saydatetime (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_saydigits (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_saynumber (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_sayphonetic (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_saytime (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_sendimage (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_sendtext (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_setcallerid (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_setcontext (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_setextension (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_setmusic (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_setpriority (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_setvariable (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_showagi (int fd, int argc, char *argv[]) |
static int | handle_streamfile (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_tddmode (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | handle_verbose (struct ast_channel *chan, AGI *agi, int argc, char **argv) |
static int | handle_waitfordigit (struct ast_channel *chan, AGI *agi, int argc, char *argv[]) |
static int | help_workhorse (int fd, char *match[]) |
static enum agi_result | launch_netscript (char *agiurl, char *argv[], int *fds, int *efd, int *opid) |
static enum agi_result | launch_script (char *script, char *argv[], int *fds, int *efd, int *opid) |
static int | load_module (void) |
static int | parse_args (char *s, int *max, char *argv[]) |
static enum agi_result | run_agi (struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead) |
static void | setup_env (struct ast_channel *chan, char *request, int fd, int enhanced) |
static void * | shaun_of_the_dead (void *data) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Asterisk Gateway Interface (AGI)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static int | agidebug = 0 |
static char * | app = "AGI" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_agi [] |
static struct ast_cli_entry | cli_agi_no_debug_deprecated |
static struct ast_cli_entry | cli_dump_agihtml_deprecated |
static struct ast_cli_entry | cli_show_agi_deprecated |
static agi_command | commands [MAX_COMMANDS] |
static char * | deadapp = "DeadAGI" |
static char * | deadsynopsis = "Executes AGI on a hungup channel" |
static char | debug_usage [] |
static char * | descrip |
static char | dumpagihtml_help [] |
static char * | eapp = "EAGI" |
static char * | esynopsis = "Executes an EAGI compliant application" |
static char | no_debug_usage [] |
static pthread_t | shaun_of_the_dead_thread = AST_PTHREADT_NULL |
static char | showagi_help [] |
static char * | synopsis = "Executes an AGI compliant application" |
static char | usage_answer [] |
static char | usage_autohangup [] |
static char | usage_channelstatus [] |
static char | usage_controlstreamfile [] |
static char | usage_dbdel [] |
static char | usage_dbdeltree [] |
static char | usage_dbget [] |
static char | usage_dbput [] |
static char | usage_exec [] |
static char | usage_getdata [] |
static char | usage_getoption [] |
static char | usage_getvariable [] |
static char | usage_getvariablefull [] |
static char | usage_hangup [] |
static char | usage_noop [] |
static char | usage_recordfile [] |
static char | usage_recvchar [] |
static char | usage_recvtext [] |
static char | usage_sayalpha [] |
static char | usage_saydate [] |
static char | usage_saydatetime [] |
static char | usage_saydigits [] |
static char | usage_saynumber [] |
static char | usage_sayphonetic [] |
static char | usage_saytime [] |
static char | usage_sendimage [] |
static char | usage_sendtext [] |
static char | usage_setcallerid [] |
static char | usage_setcontext [] |
static char | usage_setextension [] |
static char | usage_setmusic [] |
static char | usage_setpriority [] |
static char | usage_setvariable [] |
static char | usage_streamfile [] |
static char | usage_tddmode [] |
static char | usage_verbose [] |
static char | usage_waitfordigit [] |
Definition in file res_agi.c.
#define AGI_BUF_LEN 2048 |
#define AGI_PORT 4573 |
#define fdprintf agi_debug_cli |
Definition at line 82 of file res_agi.c.
Referenced by agi_handle_command(), handle_answer(), handle_autohangup(), handle_channelstatus(), handle_controlstreamfile(), handle_dbdel(), handle_dbdeltree(), handle_dbget(), handle_dbput(), handle_exec(), handle_getdata(), handle_getoption(), handle_getvariable(), handle_getvariablefull(), handle_hangup(), handle_noop(), handle_recordfile(), handle_recvchar(), handle_recvtext(), handle_sayalpha(), handle_saydate(), handle_saydatetime(), handle_saydigits(), handle_saynumber(), handle_sayphonetic(), handle_saytime(), handle_sendimage(), handle_sendtext(), handle_setcallerid(), handle_setcontext(), handle_setextension(), handle_setmusic(), handle_setpriority(), handle_setvariable(), handle_streamfile(), handle_tddmode(), handle_verbose(), handle_waitfordigit(), launch_netscript(), and setup_env().
#define MAX_AGI_CONNECT 2000 |
#define MAX_COMMANDS 128 |
Definition at line 77 of file res_agi.c.
Referenced by ast_agi_register(), and ast_agi_unregister().
enum agi_result |
Definition at line 124 of file res_agi.c.
00124 { 00125 AGI_RESULT_FAILURE = -1, 00126 AGI_RESULT_SUCCESS, 00127 AGI_RESULT_SUCCESS_FAST, 00128 AGI_RESULT_HANGUP 00129 };
static int agi_debug_cli | ( | int | fd, | |
char * | fmt, | |||
... | ||||
) | [static] |
Definition at line 138 of file res_agi.c.
References ast_carefulwrite(), ast_log(), ast_verbose(), free, LOG_ERROR, and vasprintf.
00139 { 00140 char *stuff; 00141 int res = 0; 00142 00143 va_list ap; 00144 va_start(ap, fmt); 00145 res = vasprintf(&stuff, fmt, ap); 00146 va_end(ap); 00147 if (res == -1) { 00148 ast_log(LOG_ERROR, "Out of memory\n"); 00149 } else { 00150 if (agidebug) 00151 ast_verbose("AGI Tx >> %s", stuff); /* \n provided by caller */ 00152 res = ast_carefulwrite(fd, stuff, strlen(stuff), 100); 00153 free(stuff); 00154 } 00155 00156 return res; 00157 }
static int agi_do_debug | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1375 of file res_agi.c.
References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01376 { 01377 if (argc != 2) 01378 return RESULT_SHOWUSAGE; 01379 agidebug = 1; 01380 ast_cli(fd, "AGI Debugging Enabled\n"); 01381 return RESULT_SUCCESS; 01382 }
static int agi_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2199 of file res_agi.c.
References ast_channel::_softhangup, agi_exec_full(), ast_log(), ast_module_user::chan, and LOG_WARNING.
Referenced by load_module().
02200 { 02201 if (chan->_softhangup) 02202 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n"); 02203 return agi_exec_full(chan, data, 0, 0); 02204 }
static int agi_exec_full | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | enhanced, | |||
int | dead | |||
) | [static] |
Definition at line 2128 of file res_agi.c.
References ast_channel::_state, AGI_BUF_LEN, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_FAST, ast_answer(), ast_copy_string(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_replace_sigchld(), AST_STATE_UP, ast_strlen_zero(), ast_unreplace_sigchld(), ast_module_user::chan, launch_script(), LOG_WARNING, MAX_ARGS, pbx_builtin_setvar_helper(), and run_agi().
Referenced by agi_exec(), deadagi_exec(), and eagi_exec().
02129 { 02130 enum agi_result res; 02131 struct ast_module_user *u; 02132 char *argv[MAX_ARGS]; 02133 char buf[AGI_BUF_LEN] = ""; 02134 char *tmp = (char *)buf; 02135 int argc = 0; 02136 int fds[2]; 02137 int efd = -1; 02138 int pid; 02139 char *stringp; 02140 AGI agi; 02141 02142 if (ast_strlen_zero(data)) { 02143 ast_log(LOG_WARNING, "AGI requires an argument (script)\n"); 02144 return -1; 02145 } 02146 ast_copy_string(buf, data, sizeof(buf)); 02147 02148 memset(&agi, 0, sizeof(agi)); 02149 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1) 02150 argv[argc++] = stringp; 02151 argv[argc] = NULL; 02152 02153 u = ast_module_user_add(chan); 02154 #if 0 02155 /* Answer if need be */ 02156 if (chan->_state != AST_STATE_UP) { 02157 if (ast_answer(chan)) { 02158 LOCAL_USER_REMOVE(u); 02159 return -1; 02160 } 02161 } 02162 #endif 02163 ast_replace_sigchld(); 02164 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid); 02165 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) { 02166 int status = 0; 02167 agi.fd = fds[1]; 02168 agi.ctrl = fds[0]; 02169 agi.audio = efd; 02170 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0; 02171 res = run_agi(chan, argv[0], &agi, pid, &status, dead); 02172 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */ 02173 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status) 02174 res = AGI_RESULT_FAILURE; 02175 if (fds[1] != fds[0]) 02176 close(fds[1]); 02177 if (efd > -1) 02178 close(efd); 02179 } 02180 ast_unreplace_sigchld(); 02181 ast_module_user_remove(u); 02182 02183 switch (res) { 02184 case AGI_RESULT_SUCCESS: 02185 case AGI_RESULT_SUCCESS_FAST: 02186 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS"); 02187 break; 02188 case AGI_RESULT_FAILURE: 02189 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE"); 02190 break; 02191 case AGI_RESULT_HANGUP: 02192 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP"); 02193 return -1; 02194 } 02195 02196 return 0; 02197 }
static enum agi_result agi_handle_command | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
char * | buf | |||
) | [static] |
Definition at line 1860 of file res_agi.c.
References AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, ast_cdr_setapp(), ast_check_hangup(), AST_PBX_KEEPALIVE, ast_channel::cdr, agi_state::fd, fdprintf, find_command(), agi_command::handler, MAX_ARGS, parse_args(), RESULT_FAILURE, RESULT_SHOWUSAGE, and agi_command::usage.
Referenced by run_agi().
01861 { 01862 char *argv[MAX_ARGS]; 01863 int argc = MAX_ARGS; 01864 int res; 01865 agi_command *c; 01866 01867 parse_args(buf, &argc, argv); 01868 c = find_command(argv, 0); 01869 if (c) { 01870 /* If the AGI command being executed is an actual application (using agi exec) 01871 the app field will be updated in pbx_exec via handle_exec */ 01872 if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC")) 01873 ast_cdr_setapp(chan->cdr, "AGI", buf); 01874 01875 res = c->handler(chan, agi, argc, argv); 01876 switch(res) { 01877 case RESULT_SHOWUSAGE: 01878 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n"); 01879 fdprintf(agi->fd, "%s", c->usage); 01880 fdprintf(agi->fd, "520 End of proper usage.\n"); 01881 break; 01882 case AST_PBX_KEEPALIVE: 01883 /* We've been asked to keep alive, so do so */ 01884 return AST_PBX_KEEPALIVE; 01885 break; 01886 case RESULT_FAILURE: 01887 /* The RESULT_FAILURE code is usually because the channel hungup. */ 01888 return AGI_RESULT_FAILURE; 01889 default: 01890 break; 01891 } 01892 } else { 01893 fdprintf(agi->fd, "510 Invalid or unknown command\n"); 01894 } 01895 return AGI_RESULT_SUCCESS; 01896 }
static int agi_no_debug | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1393 of file res_agi.c.
References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01394 { 01395 if (argc != 3) 01396 return RESULT_SHOWUSAGE; 01397 agidebug = 0; 01398 ast_cli(fd, "AGI Debugging Disabled\n"); 01399 return RESULT_SUCCESS; 01400 }
static int agi_no_debug_deprecated | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1384 of file res_agi.c.
References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01385 { 01386 if (argc != 3) 01387 return RESULT_SHOWUSAGE; 01388 agidebug = 0; 01389 ast_cli(fd, "AGI Debugging Disabled\n"); 01390 return RESULT_SUCCESS; 01391 }
int ast_agi_register | ( | agi_command * | agi | ) |
Definition at line 1731 of file res_agi.c.
References ast_log(), agi_command::cmda, commands, LOG_WARNING, and MAX_COMMANDS.
01732 { 01733 int x; 01734 for (x=0; x<MAX_COMMANDS - 1; x++) { 01735 if (commands[x].cmda[0] == agi->cmda[0]) { 01736 ast_log(LOG_WARNING, "Command already registered!\n"); 01737 return -1; 01738 } 01739 } 01740 for (x=0; x<MAX_COMMANDS - 1; x++) { 01741 if (!commands[x].cmda[0]) { 01742 commands[x] = *agi; 01743 return 0; 01744 } 01745 } 01746 ast_log(LOG_WARNING, "No more room for new commands!\n"); 01747 return -1; 01748 }
void ast_agi_unregister | ( | agi_command * | agi | ) |
Definition at line 1750 of file res_agi.c.
References agi_command::cmda, commands, and MAX_COMMANDS.
01751 { 01752 int x; 01753 for (x=0; x<MAX_COMMANDS - 1; x++) { 01754 if (commands[x].cmda[0] == agi->cmda[0]) { 01755 memset(&commands[x], 0, sizeof(agi_command)); 01756 } 01757 } 01758 }
static int deadagi_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2227 of file res_agi.c.
References agi_exec_full(), ast_check_hangup(), ast_log(), ast_module_user::chan, and LOG_WARNING.
Referenced by load_module().
02228 { 02229 if (!ast_check_hangup(chan)) 02230 ast_log(LOG_WARNING,"Running DeadAGI on a live channel will cause problems, please use AGI\n"); 02231 return agi_exec_full(chan, data, 0, 1); 02232 }
static int eagi_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2206 of file res_agi.c.
References ast_channel::_softhangup, agi_exec_full(), AST_FORMAT_SLINEAR, ast_getformatname(), ast_log(), ast_set_read_format(), ast_module_user::chan, LOG_WARNING, ast_channel::name, and ast_channel::readformat.
Referenced by load_module().
02207 { 02208 int readformat; 02209 int res; 02210 02211 if (chan->_softhangup) 02212 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n"); 02213 readformat = chan->readformat; 02214 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 02215 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name); 02216 return -1; 02217 } 02218 res = agi_exec_full(chan, data, 1, 0); 02219 if (!res) { 02220 if (ast_set_read_format(chan, readformat)) { 02221 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat)); 02222 } 02223 } 02224 return res; 02225 }
static agi_command* find_command | ( | char * | cmds[], | |
int | exact | |||
) | [static] |
Definition at line 1760 of file res_agi.c.
References agi_command::cmda, commands, and match().
01761 { 01762 int x; 01763 int y; 01764 int match; 01765 01766 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) { 01767 if (!commands[x].cmda[0]) 01768 break; 01769 /* start optimistic */ 01770 match = 1; 01771 for (y=0; match && cmds[y]; y++) { 01772 /* If there are no more words in the command (and we're looking for 01773 an exact match) or there is a difference between the two words, 01774 then this is not a match */ 01775 if (!commands[x].cmda[y] && !exact) 01776 break; 01777 /* don't segfault if the next part of a command doesn't exist */ 01778 if (!commands[x].cmda[y]) 01779 return NULL; 01780 if (strcasecmp(commands[x].cmda[y], cmds[y])) 01781 match = 0; 01782 } 01783 /* If more words are needed to complete the command then this is not 01784 a candidate (unless we're looking for a really inexact answer */ 01785 if ((exact > -1) && commands[x].cmda[y]) 01786 match = 0; 01787 if (match) 01788 return &commands[x]; 01789 } 01790 return NULL; 01791 }
static int handle_agidumphtml | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2074 of file res_agi.c.
References ast_cli(), ast_join(), agi_command::cmda, commands, RESULT_SHOWUSAGE, RESULT_SUCCESS, agi_command::summary, and agi_command::usage.
02075 { 02076 struct agi_command *e; 02077 char fullcmd[80]; 02078 int x; 02079 FILE *htmlfile; 02080 02081 if ((argc < 3)) 02082 return RESULT_SHOWUSAGE; 02083 02084 if (!(htmlfile = fopen(argv[2], "wt"))) { 02085 ast_cli(fd, "Could not create file '%s'\n", argv[2]); 02086 return RESULT_SHOWUSAGE; 02087 } 02088 02089 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n"); 02090 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n"); 02091 02092 02093 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n"); 02094 02095 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) { 02096 char *stringp, *tempstr; 02097 02098 e = &commands[x]; 02099 if (!e->cmda[0]) /* end ? */ 02100 break; 02101 /* Hide commands that start with '_' */ 02102 if ((e->cmda[0])[0] == '_') 02103 continue; 02104 ast_join(fullcmd, sizeof(fullcmd), e->cmda); 02105 02106 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n"); 02107 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary); 02108 02109 stringp=e->usage; 02110 tempstr = strsep(&stringp, "\n"); 02111 02112 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr); 02113 02114 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n"); 02115 while ((tempstr = strsep(&stringp, "\n")) != NULL) 02116 fprintf(htmlfile, "%s<BR>\n",tempstr); 02117 fprintf(htmlfile, "</TD></TR>\n"); 02118 fprintf(htmlfile, "</TABLE></TD></TR>\n\n"); 02119 02120 } 02121 02122 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n"); 02123 fclose(htmlfile); 02124 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]); 02125 return RESULT_SUCCESS; 02126 }
static int handle_answer | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 433 of file res_agi.c.
References ast_channel::_state, ast_answer(), AST_STATE_UP, agi_state::fd, fdprintf, RESULT_FAILURE, and RESULT_SUCCESS.
00434 { 00435 int res; 00436 res = 0; 00437 if (chan->_state != AST_STATE_UP) { 00438 /* Answer the chan */ 00439 res = ast_answer(chan); 00440 } 00441 fdprintf(agi->fd, "200 result=%d\n", res); 00442 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00443 }
static int handle_autohangup | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1084 of file res_agi.c.
References agi_state::fd, fdprintf, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_channel::whentohangup.
01085 { 01086 int timeout; 01087 01088 if (argc != 3) 01089 return RESULT_SHOWUSAGE; 01090 if (sscanf(argv[2], "%30d", &timeout) != 1) 01091 return RESULT_SHOWUSAGE; 01092 if (timeout < 0) 01093 timeout = 0; 01094 if (timeout) 01095 chan->whentohangup = time(NULL) + timeout; 01096 else 01097 chan->whentohangup = 0; 01098 fdprintf(agi->fd, "200 result=0\n"); 01099 return RESULT_SUCCESS; 01100 }
static int handle_channelstatus | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1183 of file res_agi.c.
References ast_channel::_state, ast_channel_unlock, ast_get_channel_by_name_locked(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01184 { 01185 struct ast_channel *c; 01186 if (argc == 2) { 01187 /* no argument: supply info on the current channel */ 01188 fdprintf(agi->fd, "200 result=%d\n", chan->_state); 01189 return RESULT_SUCCESS; 01190 } else if (argc == 3) { 01191 /* one argument: look for info on the specified channel */ 01192 c = ast_get_channel_by_name_locked(argv[2]); 01193 if (c) { 01194 fdprintf(agi->fd, "200 result=%d\n", c->_state); 01195 ast_channel_unlock(c); 01196 return RESULT_SUCCESS; 01197 } 01198 /* if we get this far no channel name matched the argument given */ 01199 fdprintf(agi->fd, "200 result=-1\n"); 01200 return RESULT_SUCCESS; 01201 } else { 01202 return RESULT_SHOWUSAGE; 01203 } 01204 }
static int handle_controlstreamfile | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 544 of file res_agi.c.
References ast_control_streamfile(), ast_strlen_zero(), agi_state::fd, fdprintf, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, skipms, and stop.
00545 { 00546 int res = 0; 00547 int skipms = 3000; 00548 char *fwd = NULL; 00549 char *rev = NULL; 00550 char *pause = NULL; 00551 char *stop = NULL; 00552 00553 if (argc < 5 || argc > 9) 00554 return RESULT_SHOWUSAGE; 00555 00556 if (!ast_strlen_zero(argv[4])) 00557 stop = argv[4]; 00558 else 00559 stop = NULL; 00560 00561 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) 00562 return RESULT_SHOWUSAGE; 00563 00564 if (argc > 6 && !ast_strlen_zero(argv[6])) 00565 fwd = argv[6]; 00566 else 00567 fwd = "#"; 00568 00569 if (argc > 7 && !ast_strlen_zero(argv[7])) 00570 rev = argv[7]; 00571 else 00572 rev = "*"; 00573 00574 if (argc > 8 && !ast_strlen_zero(argv[8])) 00575 pause = argv[8]; 00576 else 00577 pause = NULL; 00578 00579 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms); 00580 00581 fdprintf(agi->fd, "200 result=%d\n", res); 00582 00583 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00584 }
static int handle_dbdel | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1342 of file res_agi.c.
References ast_db_del(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01343 { 01344 int res; 01345 01346 if (argc != 4) 01347 return RESULT_SHOWUSAGE; 01348 res = ast_db_del(argv[2], argv[3]); 01349 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1'); 01350 return RESULT_SUCCESS; 01351 }
static int handle_dbdeltree | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1353 of file res_agi.c.
References ast_db_deltree(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01354 { 01355 int res; 01356 if ((argc < 3) || (argc > 4)) 01357 return RESULT_SHOWUSAGE; 01358 if (argc == 4) 01359 res = ast_db_deltree(argv[2], argv[3]); 01360 else 01361 res = ast_db_deltree(argv[2], NULL); 01362 01363 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1'); 01364 return RESULT_SUCCESS; 01365 }
static int handle_dbget | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1296 of file res_agi.c.
References ast_db_get(), ast_free, ast_malloc, ast_realloc, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01297 { 01298 int res; 01299 size_t bufsize = 16; 01300 char *buf, *tmp; 01301 01302 if (argc != 4) 01303 return RESULT_SHOWUSAGE; 01304 01305 if (!(buf = ast_malloc(bufsize))) { 01306 fdprintf(agi->fd, "200 result=-1\n"); 01307 return RESULT_SUCCESS; 01308 } 01309 01310 do { 01311 res = ast_db_get(argv[2], argv[3], buf, bufsize); 01312 if (strlen(buf) < bufsize - 1) { 01313 break; 01314 } 01315 bufsize *= 2; 01316 if (!(tmp = ast_realloc(buf, bufsize))) { 01317 break; 01318 } 01319 buf = tmp; 01320 } while (1); 01321 01322 if (res) 01323 fdprintf(agi->fd, "200 result=0\n"); 01324 else 01325 fdprintf(agi->fd, "200 result=1 (%s)\n", buf); 01326 01327 ast_free(buf); 01328 return RESULT_SUCCESS; 01329 }
static int handle_dbput | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1331 of file res_agi.c.
References ast_db_put(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01332 { 01333 int res; 01334 01335 if (argc != 5) 01336 return RESULT_SHOWUSAGE; 01337 res = ast_db_put(argv[2], argv[3], argv[4]); 01338 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1'); 01339 return RESULT_SUCCESS; 01340 }
static int handle_exec | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1128 of file res_agi.c.
References app, ast_clear_flag, AST_FLAG_DISABLE_WORKAROUNDS, ast_log(), ast_masq_park_call(), ast_set_flag, ast_test_flag, ast_verbose(), agi_state::fd, fdprintf, LOG_WARNING, option_verbose, PARK_APP_NAME, pbx_exec(), pbx_findapp(), RESULT_SHOWUSAGE, and VERBOSE_PREFIX_3.
01129 { 01130 int res, workaround; 01131 struct ast_app *app; 01132 01133 if (argc < 2) 01134 return RESULT_SHOWUSAGE; 01135 01136 if (option_verbose > 2) 01137 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]); 01138 01139 app = pbx_findapp(argv[1]); 01140 01141 if (app) { 01142 if(!strcasecmp(argv[1], PARK_APP_NAME)) { 01143 ast_masq_park_call(chan, NULL, 0, NULL); 01144 } 01145 if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) { 01146 ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); 01147 } 01148 res = pbx_exec(chan, app, argc == 2 ? "" : argv[2]); 01149 if (!workaround) { 01150 ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); 01151 } 01152 } else { 01153 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]); 01154 res = -2; 01155 } 01156 fdprintf(agi->fd, "200 result=%d\n", res); 01157 01158 /* Even though this is wrong, users are depending upon this result. */ 01159 return res; 01160 }
static int handle_getdata | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 841 of file res_agi.c.
References ast_app_getdata_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00842 { 00843 int res; 00844 char data[1024]; 00845 int max; 00846 int timeout; 00847 00848 if (argc < 3) 00849 return RESULT_SHOWUSAGE; 00850 if (argc >= 4) 00851 timeout = atoi(argv[3]); 00852 else 00853 timeout = 0; 00854 if (argc >= 5) 00855 max = atoi(argv[4]); 00856 else 00857 max = 1024; 00858 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl); 00859 if (res == 2) /* New command */ 00860 return RESULT_SUCCESS; 00861 else if (res == 1) 00862 fdprintf(agi->fd, "200 result=%s (timeout)\n", data); 00863 else if (res < 0 ) 00864 fdprintf(agi->fd, "200 result=-1\n"); 00865 else 00866 fdprintf(agi->fd, "200 result=%s\n", data); 00867 return RESULT_SUCCESS; 00868 }
static int handle_getoption | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 642 of file res_agi.c.
References ast_applystream(), ast_log(), ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verbose(), ast_waitfordigit_full(), ast_waitstream_full(), agi_state::audio, agi_state::ctrl, ast_pbx::dtimeout, agi_state::fd, fdprintf, ast_channel::language, LOG_DEBUG, LOG_WARNING, option_verbose, ast_channel::pbx, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, VERBOSE_PREFIX_3, and ast_filestream::vfs.
00643 { 00644 int res; 00645 int vres; 00646 struct ast_filestream *fs; 00647 struct ast_filestream *vfs; 00648 long sample_offset = 0; 00649 long max_length; 00650 int timeout = 0; 00651 char *edigits = ""; 00652 00653 if ( argc < 4 || argc > 5 ) 00654 return RESULT_SHOWUSAGE; 00655 00656 if ( argv[3] ) 00657 edigits = argv[3]; 00658 00659 if ( argc == 5 ) 00660 timeout = atoi(argv[4]); 00661 else if (chan->pbx->dtimeout) { 00662 /* by default dtimeout is set to 5sec */ 00663 timeout = chan->pbx->dtimeout * 1000; /* in msec */ 00664 } 00665 00666 fs = ast_openstream(chan, argv[2], chan->language); 00667 if (!fs) { 00668 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset); 00669 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]); 00670 return RESULT_SUCCESS; 00671 } 00672 vfs = ast_openvstream(chan, argv[2], chan->language); 00673 if (vfs) 00674 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n"); 00675 00676 if (option_verbose > 2) 00677 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout); 00678 00679 ast_seekstream(fs, 0, SEEK_END); 00680 max_length = ast_tellstream(fs); 00681 ast_seekstream(fs, sample_offset, SEEK_SET); 00682 res = ast_applystream(chan, fs); 00683 if (vfs) 00684 vres = ast_applystream(chan, vfs); 00685 ast_playstream(fs); 00686 if (vfs) 00687 ast_playstream(vfs); 00688 00689 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); 00690 /* this is to check for if ast_waitstream closed the stream, we probably are at 00691 * the end of the stream, return that amount, else check for the amount */ 00692 sample_offset = (chan->stream)?ast_tellstream(fs):max_length; 00693 ast_stopstream(chan); 00694 if (res == 1) { 00695 /* Stop this command, don't print a result line, as there is a new command */ 00696 return RESULT_SUCCESS; 00697 } 00698 00699 /* If the user didnt press a key, wait for digitTimeout*/ 00700 if (res == 0 ) { 00701 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl); 00702 /* Make sure the new result is in the escape digits of the GET OPTION */ 00703 if ( !strchr(edigits,res) ) 00704 res=0; 00705 } 00706 00707 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset); 00708 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00709 }
static int handle_getvariable | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1215 of file res_agi.c.
References ast_func_read(), ast_strlen_zero(), agi_state::fd, fdprintf, pbx_retrieve_variable(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01216 { 01217 char *ret; 01218 char tempstr[1024] = ""; 01219 01220 if (argc != 3) 01221 return RESULT_SHOWUSAGE; 01222 01223 /* check if we want to execute an ast_custom_function */ 01224 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) { 01225 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr; 01226 } else { 01227 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL); 01228 } 01229 01230 if (ret) 01231 fdprintf(agi->fd, "200 result=1 (%s)\n", ret); 01232 else 01233 fdprintf(agi->fd, "200 result=0\n"); 01234 01235 return RESULT_SUCCESS; 01236 }
static int handle_getvariablefull | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1238 of file res_agi.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), agi_state::fd, fdprintf, ast_channel::name, pbx_substitute_variables_helper(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01239 { 01240 char tmp[4096] = ""; 01241 struct ast_channel *chan2=NULL; 01242 01243 if ((argc != 4) && (argc != 5)) 01244 return RESULT_SHOWUSAGE; 01245 if (argc == 5 && strcasecmp(chan->name, argv[4])) { 01246 chan2 = ast_get_channel_by_name_locked(argv[4]); 01247 } else { 01248 chan2 = chan; 01249 } 01250 if (chan2) { 01251 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1); 01252 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp); 01253 } else { 01254 fdprintf(agi->fd, "200 result=0\n"); 01255 } 01256 if (chan2 && (chan2 != chan)) 01257 ast_channel_unlock(chan2); 01258 return RESULT_SUCCESS; 01259 }
static int handle_hangup | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1102 of file res_agi.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01103 { 01104 struct ast_channel *c; 01105 if (argc == 1) { 01106 /* no argument: hangup the current channel */ 01107 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); 01108 fdprintf(agi->fd, "200 result=1\n"); 01109 return RESULT_SUCCESS; 01110 } else if (argc == 2) { 01111 /* one argument: look for info on the specified channel */ 01112 c = ast_get_channel_by_name_locked(argv[1]); 01113 if (c) { 01114 /* we have a matching channel */ 01115 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT); 01116 fdprintf(agi->fd, "200 result=1\n"); 01117 ast_channel_unlock(c); 01118 return RESULT_SUCCESS; 01119 } 01120 /* if we get this far no channel name matched the argument given */ 01121 fdprintf(agi->fd, "200 result=-1\n"); 01122 return RESULT_SUCCESS; 01123 } else { 01124 return RESULT_SHOWUSAGE; 01125 } 01126 }
static int handle_noop | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | arg, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1402 of file res_agi.c.
References agi_state::fd, fdprintf, and RESULT_SUCCESS.
01403 { 01404 fdprintf(agi->fd, "200 result=0\n"); 01405 return RESULT_SUCCESS; 01406 }
static int handle_recordfile | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 905 of file res_agi.c.
References ast_applystream(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log(), ast_read(), ast_seekstream(), ast_set_read_format(), ast_stream_rewind(), ast_streamfile(), ast_tellstream(), ast_truncstream(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), f, agi_state::fd, fdprintf, ast_channel::language, LOG_WARNING, ast_channel::name, ast_channel::readformat, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, silence, ast_channel::stream, and ast_dsp::totalsilence.
00906 { 00907 struct ast_filestream *fs; 00908 struct ast_frame *f; 00909 struct timeval start; 00910 long sample_offset = 0; 00911 int res = 0; 00912 int ms; 00913 00914 struct ast_dsp *sildet=NULL; /* silence detector dsp */ 00915 int totalsilence = 0; 00916 int dspsilence = 0; 00917 int silence = 0; /* amount of silence to allow */ 00918 int gotsilence = 0; /* did we timeout for silence? */ 00919 char *silencestr=NULL; 00920 int rfmt=0; 00921 00922 00923 /* XXX EAGI FIXME XXX */ 00924 00925 if (argc < 6) 00926 return RESULT_SHOWUSAGE; 00927 if (sscanf(argv[5], "%30d", &ms) != 1) 00928 return RESULT_SHOWUSAGE; 00929 00930 if (argc > 6) 00931 silencestr = strchr(argv[6],'s'); 00932 if ((argc > 7) && (!silencestr)) 00933 silencestr = strchr(argv[7],'s'); 00934 if ((argc > 8) && (!silencestr)) 00935 silencestr = strchr(argv[8],'s'); 00936 00937 if (silencestr) { 00938 if (strlen(silencestr) > 2) { 00939 if ((silencestr[0] == 's') && (silencestr[1] == '=')) { 00940 silencestr++; 00941 silencestr++; 00942 if (silencestr) 00943 silence = atoi(silencestr); 00944 if (silence > 0) 00945 silence *= 1000; 00946 } 00947 } 00948 } 00949 00950 if (silence > 0) { 00951 rfmt = chan->readformat; 00952 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 00953 if (res < 0) { 00954 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 00955 fdprintf(agi->fd, "200 result=%d\n", res); 00956 return RESULT_FAILURE; 00957 } 00958 sildet = ast_dsp_new(); 00959 if (!sildet) { 00960 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00961 fdprintf(agi->fd, "200 result=-1\n"); 00962 return RESULT_FAILURE; 00963 } 00964 ast_dsp_set_threshold(sildet, 256); 00965 } 00966 00967 /* backward compatibility, if no offset given, arg[6] would have been 00968 * caught below and taken to be a beep, else if it is a digit then it is a 00969 * offset */ 00970 if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '='))) 00971 res = ast_streamfile(chan, "beep", chan->language); 00972 00973 if ((argc > 7) && (!strchr(argv[7], '='))) 00974 res = ast_streamfile(chan, "beep", chan->language); 00975 00976 if (!res) 00977 res = ast_waitstream(chan, argv[4]); 00978 if (res) { 00979 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); 00980 } else { 00981 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644); 00982 if (!fs) { 00983 res = -1; 00984 fdprintf(agi->fd, "200 result=%d (writefile)\n", res); 00985 if (sildet) 00986 ast_dsp_free(sildet); 00987 return RESULT_FAILURE; 00988 } 00989 00990 /* Request a video update */ 00991 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00992 00993 chan->stream = fs; 00994 ast_applystream(chan,fs); 00995 /* really should have checks */ 00996 ast_seekstream(fs, sample_offset, SEEK_SET); 00997 ast_truncstream(fs); 00998 00999 start = ast_tvnow(); 01000 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) { 01001 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start)); 01002 if (res < 0) { 01003 ast_closestream(fs); 01004 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); 01005 if (sildet) 01006 ast_dsp_free(sildet); 01007 return RESULT_FAILURE; 01008 } 01009 f = ast_read(chan); 01010 if (!f) { 01011 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset); 01012 ast_closestream(fs); 01013 if (sildet) 01014 ast_dsp_free(sildet); 01015 return RESULT_FAILURE; 01016 } 01017 switch(f->frametype) { 01018 case AST_FRAME_DTMF: 01019 if (strchr(argv[4], f->subclass)) { 01020 /* This is an interrupting chracter, so rewind to chop off any small 01021 amount of DTMF that may have been recorded 01022 */ 01023 ast_stream_rewind(fs, 200); 01024 ast_truncstream(fs); 01025 sample_offset = ast_tellstream(fs); 01026 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset); 01027 ast_closestream(fs); 01028 ast_frfree(f); 01029 if (sildet) 01030 ast_dsp_free(sildet); 01031 return RESULT_SUCCESS; 01032 } 01033 break; 01034 case AST_FRAME_VOICE: 01035 ast_writestream(fs, f); 01036 /* this is a safe place to check progress since we know that fs 01037 * is valid after a write, and it will then have our current 01038 * location */ 01039 sample_offset = ast_tellstream(fs); 01040 if (silence > 0) { 01041 dspsilence = 0; 01042 ast_dsp_silence(sildet, f, &dspsilence); 01043 if (dspsilence) { 01044 totalsilence = dspsilence; 01045 } else { 01046 totalsilence = 0; 01047 } 01048 if (totalsilence > silence) { 01049 /* Ended happily with silence */ 01050 gotsilence = 1; 01051 break; 01052 } 01053 } 01054 break; 01055 case AST_FRAME_VIDEO: 01056 ast_writestream(fs, f); 01057 default: 01058 /* Ignore all other frames */ 01059 break; 01060 } 01061 ast_frfree(f); 01062 if (gotsilence) 01063 break; 01064 } 01065 01066 if (gotsilence) { 01067 ast_stream_rewind(fs, silence-1000); 01068 ast_truncstream(fs); 01069 sample_offset = ast_tellstream(fs); 01070 } 01071 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); 01072 ast_closestream(fs); 01073 } 01074 01075 if (silence > 0) { 01076 res = ast_set_read_format(chan, rfmt); 01077 if (res) 01078 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); 01079 ast_dsp_free(sildet); 01080 } 01081 return RESULT_SUCCESS; 01082 }
static int handle_recvchar | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 475 of file res_agi.c.
References ast_recvchar(), agi_state::fd, fdprintf, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00476 { 00477 int res; 00478 if (argc != 3) 00479 return RESULT_SHOWUSAGE; 00480 res = ast_recvchar(chan,atoi(argv[2])); 00481 if (res == 0) { 00482 fdprintf(agi->fd, "200 result=%d (timeout)\n", res); 00483 return RESULT_SUCCESS; 00484 } 00485 if (res > 0) { 00486 fdprintf(agi->fd, "200 result=%d\n", res); 00487 return RESULT_SUCCESS; 00488 } 00489 else { 00490 fdprintf(agi->fd, "200 result=%d (hangup)\n", res); 00491 return RESULT_FAILURE; 00492 } 00493 }
static int handle_recvtext | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 495 of file res_agi.c.
References ast_recvtext(), ast_hostent::buf, agi_state::fd, fdprintf, free, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00496 { 00497 char *buf; 00498 00499 if (argc != 3) 00500 return RESULT_SHOWUSAGE; 00501 buf = ast_recvtext(chan,atoi(argv[2])); 00502 if (buf) { 00503 fdprintf(agi->fd, "200 result=1 (%s)\n", buf); 00504 free(buf); 00505 } else { 00506 fdprintf(agi->fd, "200 result=-1\n"); 00507 } 00508 return RESULT_SUCCESS; 00509 }
static int handle_sayalpha | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 749 of file res_agi.c.
References ast_say_character_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00750 { 00751 int res; 00752 00753 if (argc != 4) 00754 return RESULT_SHOWUSAGE; 00755 00756 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); 00757 if (res == 1) /* New command */ 00758 return RESULT_SUCCESS; 00759 fdprintf(agi->fd, "200 result=%d\n", res); 00760 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00761 }
static int handle_saydate | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 763 of file res_agi.c.
References ast_say_date, agi_state::fd, fdprintf, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00764 { 00765 int res; 00766 int num; 00767 if (argc != 4) 00768 return RESULT_SHOWUSAGE; 00769 if (sscanf(argv[2], "%30d", &num) != 1) 00770 return RESULT_SHOWUSAGE; 00771 res = ast_say_date(chan, num, argv[3], chan->language); 00772 if (res == 1) 00773 return RESULT_SUCCESS; 00774 fdprintf(agi->fd, "200 result=%d\n", res); 00775 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00776 }
static int handle_saydatetime | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 793 of file res_agi.c.
References ast_get_time_t(), ast_say_date_with_format, ast_strlen_zero(), agi_state::fd, fdprintf, format, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00794 { 00795 int res=0; 00796 time_t unixtime; 00797 char *format, *zone=NULL; 00798 00799 if (argc < 4) 00800 return RESULT_SHOWUSAGE; 00801 00802 if (argc > 4) { 00803 format = argv[4]; 00804 } else { 00805 /* XXX this doesn't belong here, but in the 'say' module */ 00806 if (!strcasecmp(chan->language, "de")) { 00807 format = "A dBY HMS"; 00808 } else { 00809 format = "ABdY 'digits/at' IMp"; 00810 } 00811 } 00812 00813 if (argc > 5 && !ast_strlen_zero(argv[5])) 00814 zone = argv[5]; 00815 00816 if (ast_get_time_t(argv[2], &unixtime, 0, NULL)) 00817 return RESULT_SHOWUSAGE; 00818 00819 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone); 00820 if (res == 1) 00821 return RESULT_SUCCESS; 00822 00823 fdprintf(agi->fd, "200 result=%d\n", res); 00824 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00825 }
static int handle_saydigits | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 732 of file res_agi.c.
References ast_say_digit_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00733 { 00734 int res; 00735 int num; 00736 00737 if (argc != 4) 00738 return RESULT_SHOWUSAGE; 00739 if (sscanf(argv[2], "%30d", &num) != 1) 00740 return RESULT_SHOWUSAGE; 00741 00742 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); 00743 if (res == 1) /* New command */ 00744 return RESULT_SUCCESS; 00745 fdprintf(agi->fd, "200 result=%d\n", res); 00746 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00747 }
static int handle_saynumber | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 717 of file res_agi.c.
References ast_say_number_full, agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00718 { 00719 int res; 00720 int num; 00721 if (argc != 4) 00722 return RESULT_SHOWUSAGE; 00723 if (sscanf(argv[2], "%30d", &num) != 1) 00724 return RESULT_SHOWUSAGE; 00725 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl); 00726 if (res == 1) 00727 return RESULT_SUCCESS; 00728 fdprintf(agi->fd, "200 result=%d\n", res); 00729 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00730 }
static int handle_sayphonetic | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 827 of file res_agi.c.
References ast_say_phonetic_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00828 { 00829 int res; 00830 00831 if (argc != 4) 00832 return RESULT_SHOWUSAGE; 00833 00834 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); 00835 if (res == 1) /* New command */ 00836 return RESULT_SUCCESS; 00837 fdprintf(agi->fd, "200 result=%d\n", res); 00838 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00839 }
static int handle_saytime | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 778 of file res_agi.c.
References ast_say_time, agi_state::fd, fdprintf, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00779 { 00780 int res; 00781 int num; 00782 if (argc != 4) 00783 return RESULT_SHOWUSAGE; 00784 if (sscanf(argv[2], "%30d", &num) != 1) 00785 return RESULT_SHOWUSAGE; 00786 res = ast_say_time(chan, num, argv[3], chan->language); 00787 if (res == 1) 00788 return RESULT_SUCCESS; 00789 fdprintf(agi->fd, "200 result=%d\n", res); 00790 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00791 }
static int handle_sendimage | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 532 of file res_agi.c.
References ast_check_hangup(), ast_send_image(), agi_state::fd, fdprintf, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00533 { 00534 int res; 00535 if (argc != 3) 00536 return RESULT_SHOWUSAGE; 00537 res = ast_send_image(chan, argv[2]); 00538 if (!ast_check_hangup(chan)) 00539 res = 0; 00540 fdprintf(agi->fd, "200 result=%d\n", res); 00541 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00542 }
static int handle_sendtext | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 458 of file res_agi.c.
References ast_sendtext(), agi_state::fd, fdprintf, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00459 { 00460 int res; 00461 if (argc != 3) 00462 return RESULT_SHOWUSAGE; 00463 /* At the moment, the parser (perhaps broken) returns with 00464 the last argument PLUS the newline at the end of the input 00465 buffer. This probably needs to be fixed, but I wont do that 00466 because other stuff may break as a result. The right way 00467 would probably be to strip off the trailing newline before 00468 parsing, then here, add a newline at the end of the string 00469 before sending it to ast_sendtext --DUDE */ 00470 res = ast_sendtext(chan, argv[2]); 00471 fdprintf(agi->fd, "200 result=%d\n", res); 00472 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00473 }
static int handle_setcallerid | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1162 of file res_agi.c.
References ast_callerid_parse(), ast_copy_string(), ast_set_callerid(), ast_shrink_phone_number(), agi_state::fd, fdprintf, and RESULT_SUCCESS.
01163 { 01164 char tmp[256]=""; 01165 char *l = NULL, *n = NULL; 01166 01167 if (argv[2]) { 01168 ast_copy_string(tmp, argv[2], sizeof(tmp)); 01169 ast_callerid_parse(tmp, &n, &l); 01170 if (l) 01171 ast_shrink_phone_number(l); 01172 else 01173 l = ""; 01174 if (!n) 01175 n = ""; 01176 ast_set_callerid(chan, l, n, NULL); 01177 } 01178 01179 fdprintf(agi->fd, "200 result=1\n"); 01180 return RESULT_SUCCESS; 01181 }
static int handle_setcontext | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 870 of file res_agi.c.
References ast_copy_string(), ast_channel::context, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00871 { 00872 00873 if (argc != 3) 00874 return RESULT_SHOWUSAGE; 00875 ast_copy_string(chan->context, argv[2], sizeof(chan->context)); 00876 fdprintf(agi->fd, "200 result=0\n"); 00877 return RESULT_SUCCESS; 00878 }
static int handle_setextension | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 880 of file res_agi.c.
References ast_copy_string(), ast_channel::exten, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00881 { 00882 if (argc != 3) 00883 return RESULT_SHOWUSAGE; 00884 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten)); 00885 fdprintf(agi->fd, "200 result=0\n"); 00886 return RESULT_SUCCESS; 00887 }
static int handle_setmusic | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1408 of file res_agi.c.
References ast_moh_start(), ast_moh_stop(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01409 { 01410 if (argc < 3) { 01411 return RESULT_SHOWUSAGE; 01412 } 01413 if (!strncasecmp(argv[2], "on", 2)) 01414 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL); 01415 else if (!strncasecmp(argv[2], "off", 3)) 01416 ast_moh_stop(chan); 01417 fdprintf(agi->fd, "200 result=0\n"); 01418 return RESULT_SUCCESS; 01419 }
static int handle_setpriority | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 889 of file res_agi.c.
References ast_explicit_goto(), ast_findlabel_extension(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00890 { 00891 int pri; 00892 if (argc != 3) 00893 return RESULT_SHOWUSAGE; 00894 00895 if (sscanf(argv[2], "%30d", &pri) != 1) { 00896 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1) 00897 return RESULT_SHOWUSAGE; 00898 } 00899 00900 ast_explicit_goto(chan, NULL, NULL, pri); 00901 fdprintf(agi->fd, "200 result=0\n"); 00902 return RESULT_SUCCESS; 00903 }
static int handle_setvariable | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1206 of file res_agi.c.
References agi_state::fd, fdprintf, pbx_builtin_setvar_helper(), and RESULT_SUCCESS.
01207 { 01208 if (argv[3]) 01209 pbx_builtin_setvar_helper(chan, argv[2], argv[3]); 01210 01211 fdprintf(agi->fd, "200 result=1\n"); 01212 return RESULT_SUCCESS; 01213 }
static int handle_showagi | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2050 of file res_agi.c.
References ast_cli(), ast_join(), find_command(), help_workhorse(), RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_command::usage.
02051 { 02052 struct agi_command *e; 02053 char fullcmd[80]; 02054 if ((argc < 2)) 02055 return RESULT_SHOWUSAGE; 02056 if (argc > 2) { 02057 e = find_command(argv + 2, 1); 02058 if (e) 02059 ast_cli(fd, "%s", e->usage); 02060 else { 02061 if (find_command(argv + 2, -1)) { 02062 return help_workhorse(fd, argv + 1); 02063 } else { 02064 ast_join(fullcmd, sizeof(fullcmd), argv+1); 02065 ast_cli(fd, "No such command '%s'.\n", fullcmd); 02066 } 02067 } 02068 } else { 02069 return help_workhorse(fd, NULL); 02070 } 02071 return RESULT_SUCCESS; 02072 }
static int handle_streamfile | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 586 of file res_agi.c.
References ast_applystream(), ast_log(), ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verbose(), ast_waitstream_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, ast_channel::language, LOG_DEBUG, option_verbose, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, VERBOSE_PREFIX_3, and ast_filestream::vfs.
00587 { 00588 int res; 00589 int vres; 00590 struct ast_filestream *fs; 00591 struct ast_filestream *vfs; 00592 long sample_offset = 0; 00593 long max_length; 00594 char *edigits = ""; 00595 00596 if (argc < 4 || argc > 5) 00597 return RESULT_SHOWUSAGE; 00598 00599 if (argv[3]) 00600 edigits = argv[3]; 00601 00602 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) 00603 return RESULT_SHOWUSAGE; 00604 00605 fs = ast_openstream(chan, argv[2], chan->language); 00606 00607 if (!fs) { 00608 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset); 00609 return RESULT_SUCCESS; 00610 } 00611 vfs = ast_openvstream(chan, argv[2], chan->language); 00612 if (vfs) 00613 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n"); 00614 00615 if (option_verbose > 2) 00616 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset); 00617 00618 ast_seekstream(fs, 0, SEEK_END); 00619 max_length = ast_tellstream(fs); 00620 ast_seekstream(fs, sample_offset, SEEK_SET); 00621 res = ast_applystream(chan, fs); 00622 if (vfs) 00623 vres = ast_applystream(chan, vfs); 00624 ast_playstream(fs); 00625 if (vfs) 00626 ast_playstream(vfs); 00627 00628 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); 00629 /* this is to check for if ast_waitstream closed the stream, we probably are at 00630 * the end of the stream, return that amount, else check for the amount */ 00631 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length; 00632 ast_stopstream(chan); 00633 if (res == 1) { 00634 /* Stop this command, don't print a result line, as there is a new command */ 00635 return RESULT_SUCCESS; 00636 } 00637 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset); 00638 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00639 }
static int handle_tddmode | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 511 of file res_agi.c.
References ast_channel_setoption(), AST_OPTION_TDD, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00512 { 00513 int res,x; 00514 if (argc != 3) 00515 return RESULT_SHOWUSAGE; 00516 if (!strncasecmp(argv[2],"on",2)) 00517 x = 1; 00518 else 00519 x = 0; 00520 if (!strncasecmp(argv[2],"mate",4)) 00521 x = 2; 00522 if (!strncasecmp(argv[2],"tdd",3)) 00523 x = 1; 00524 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0); 00525 if (res != RESULT_SUCCESS) 00526 fdprintf(agi->fd, "200 result=0\n"); 00527 else 00528 fdprintf(agi->fd, "200 result=1\n"); 00529 return RESULT_SUCCESS; 00530 }
static int handle_verbose | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1261 of file res_agi.c.
References ast_verbose(), ast_channel::data, agi_state::fd, fdprintf, option_verbose, prefix, RESULT_SHOWUSAGE, RESULT_SUCCESS, VERBOSE_PREFIX_1, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and VERBOSE_PREFIX_4.
01262 { 01263 int level = 0; 01264 char *prefix; 01265 01266 if (argc < 2) 01267 return RESULT_SHOWUSAGE; 01268 01269 if (argv[2]) 01270 sscanf(argv[2], "%30d", &level); 01271 01272 switch (level) { 01273 case 4: 01274 prefix = VERBOSE_PREFIX_4; 01275 break; 01276 case 3: 01277 prefix = VERBOSE_PREFIX_3; 01278 break; 01279 case 2: 01280 prefix = VERBOSE_PREFIX_2; 01281 break; 01282 case 1: 01283 default: 01284 prefix = VERBOSE_PREFIX_1; 01285 break; 01286 } 01287 01288 if (level <= option_verbose) 01289 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]); 01290 01291 fdprintf(agi->fd, "200 result=1\n"); 01292 01293 return RESULT_SUCCESS; 01294 }
static int handle_waitfordigit | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 445 of file res_agi.c.
References ast_waitfordigit_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, fdprintf, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00446 { 00447 int res; 00448 int to; 00449 if (argc != 4) 00450 return RESULT_SHOWUSAGE; 00451 if (sscanf(argv[3], "%30d", &to) != 1) 00452 return RESULT_SHOWUSAGE; 00453 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl); 00454 fdprintf(agi->fd, "200 result=%d\n", res); 00455 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE; 00456 }
static int help_workhorse | ( | int | fd, | |
char * | match[] | |||
) | [static] |
Definition at line 1708 of file res_agi.c.
References ast_cli(), ast_join(), agi_command::cmda, commands, and agi_command::summary.
01709 { 01710 char fullcmd[80]; 01711 char matchstr[80]; 01712 int x; 01713 struct agi_command *e; 01714 if (match) 01715 ast_join(matchstr, sizeof(matchstr), match); 01716 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) { 01717 e = &commands[x]; 01718 if (!e->cmda[0]) 01719 break; 01720 /* Hide commands that start with '_' */ 01721 if ((e->cmda[0])[0] == '_') 01722 continue; 01723 ast_join(fullcmd, sizeof(fullcmd), e->cmda); 01724 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr))) 01725 continue; 01726 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary); 01727 } 01728 return 0; 01729 }
static enum agi_result launch_netscript | ( | char * | agiurl, | |
char * | argv[], | |||
int * | fds, | |||
int * | efd, | |||
int * | opid | |||
) | [static] |
Definition at line 161 of file res_agi.c.
References AGI_PORT, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS_FAST, ahp, ast_gethostbyname(), ast_log(), ast_poll, ast_strdupa, ast_strlen_zero(), errno, fdprintf, hp, LOG_DEBUG, LOG_WARNING, MAX_AGI_CONNECT, option_debug, and s.
Referenced by launch_script().
00162 { 00163 int s; 00164 int flags; 00165 struct pollfd pfds[1]; 00166 char *host; 00167 char *c; int port = AGI_PORT; 00168 char *script=""; 00169 struct sockaddr_in sin; 00170 struct hostent *hp; 00171 struct ast_hostent ahp; 00172 int res; 00173 00174 /* agiusl is "agi://host.domain[:port][/script/name]" */ 00175 host = ast_strdupa(agiurl + 6); /* Remove agi:// */ 00176 /* Strip off any script name */ 00177 if ((c = strchr(host, '/'))) { 00178 *c = '\0'; 00179 c++; 00180 script = c; 00181 } 00182 if ((c = strchr(host, ':'))) { 00183 *c = '\0'; 00184 c++; 00185 port = atoi(c); 00186 } 00187 if (efd) { 00188 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n"); 00189 return -1; 00190 } 00191 hp = ast_gethostbyname(host, &ahp); 00192 if (!hp) { 00193 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host); 00194 return -1; 00195 } 00196 s = socket(AF_INET, SOCK_STREAM, 0); 00197 if (s < 0) { 00198 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 00199 return -1; 00200 } 00201 flags = fcntl(s, F_GETFL); 00202 if (flags < 0) { 00203 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno)); 00204 close(s); 00205 return -1; 00206 } 00207 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { 00208 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno)); 00209 close(s); 00210 return -1; 00211 } 00212 memset(&sin, 0, sizeof(sin)); 00213 sin.sin_family = AF_INET; 00214 sin.sin_port = htons(port); 00215 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); 00216 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) { 00217 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno)); 00218 close(s); 00219 return AGI_RESULT_FAILURE; 00220 } 00221 00222 pfds[0].fd = s; 00223 pfds[0].events = POLLOUT; 00224 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) { 00225 if (errno != EINTR) { 00226 if (!res) { 00227 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n", 00228 agiurl, MAX_AGI_CONNECT); 00229 } else 00230 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); 00231 close(s); 00232 return AGI_RESULT_FAILURE; 00233 } 00234 } 00235 00236 if (fdprintf(s, "agi_network: yes\n") < 0) { 00237 if (errno != EINTR) { 00238 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); 00239 close(s); 00240 return AGI_RESULT_FAILURE; 00241 } 00242 } 00243 00244 /* If we have a script parameter, relay it to the fastagi server */ 00245 if (!ast_strlen_zero(script)) 00246 fdprintf(s, "agi_network_script: %s\n", script); 00247 00248 if (option_debug > 3) 00249 ast_log(LOG_DEBUG, "Wow, connected!\n"); 00250 fds[0] = s; 00251 fds[1] = s; 00252 *opid = -1; 00253 return AGI_RESULT_SUCCESS_FAST; 00254 }
static enum agi_result launch_script | ( | char * | script, | |
char * | argv[], | |||
int * | fds, | |||
int * | efd, | |||
int * | opid | |||
) | [static] |
Definition at line 256 of file res_agi.c.
References AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, ast_config_AST_AGI_DIR, ast_config_AST_CONFIG_DIR, ast_config_AST_CONFIG_FILE, ast_config_AST_DATA_DIR, ast_config_AST_KEY_DIR, ast_config_AST_LOG_DIR, ast_config_AST_MODULE_DIR, ast_config_AST_MONITOR_DIR, ast_config_AST_RUN_DIR, ast_config_AST_SPOOL_DIR, ast_config_AST_VAR_DIR, ast_log(), ast_set_priority(), ast_verbose(), errno, launch_netscript(), LOG_WARNING, option_verbose, zombie::pid, and VERBOSE_PREFIX_3.
Referenced by agi_exec_full().
00257 { 00258 char tmp[256]; 00259 int pid; 00260 int toast[2]; 00261 int fromast[2]; 00262 int audio[2]; 00263 int x; 00264 int res; 00265 sigset_t signal_set, old_set; 00266 00267 if (!strncasecmp(script, "agi://", 6)) 00268 return launch_netscript(script, argv, fds, efd, opid); 00269 00270 if (script[0] != '/') { 00271 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script); 00272 script = tmp; 00273 } 00274 if (pipe(toast)) { 00275 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno)); 00276 return AGI_RESULT_FAILURE; 00277 } 00278 if (pipe(fromast)) { 00279 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno)); 00280 close(toast[0]); 00281 close(toast[1]); 00282 return AGI_RESULT_FAILURE; 00283 } 00284 if (efd) { 00285 if (pipe(audio)) { 00286 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno)); 00287 close(fromast[0]); 00288 close(fromast[1]); 00289 close(toast[0]); 00290 close(toast[1]); 00291 return AGI_RESULT_FAILURE; 00292 } 00293 res = fcntl(audio[1], F_GETFL); 00294 if (res > -1) 00295 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK); 00296 if (res < 0) { 00297 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno)); 00298 close(fromast[0]); 00299 close(fromast[1]); 00300 close(toast[0]); 00301 close(toast[1]); 00302 close(audio[0]); 00303 close(audio[1]); 00304 return AGI_RESULT_FAILURE; 00305 } 00306 } 00307 00308 /* Block SIGHUP during the fork - prevents a race */ 00309 sigfillset(&signal_set); 00310 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set); 00311 pid = fork(); 00312 if (pid < 0) { 00313 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); 00314 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00315 return AGI_RESULT_FAILURE; 00316 } 00317 if (!pid) { 00318 #ifdef HAVE_CAP 00319 cap_t cap = cap_from_text("cap_net_admin-eip"); 00320 00321 if (cap_set_proc(cap)) { 00322 /* Careful with order! Logging cannot happen after we close FDs */ 00323 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00324 } 00325 cap_free(cap); 00326 #endif 00327 00328 /* Pass paths to AGI via environmental variables */ 00329 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1); 00330 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1); 00331 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1); 00332 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1); 00333 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1); 00334 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1); 00335 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1); 00336 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1); 00337 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1); 00338 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1); 00339 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1); 00340 00341 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */ 00342 ast_set_priority(0); 00343 00344 /* Redirect stdin and out, provide enhanced audio channel if desired */ 00345 dup2(fromast[0], STDIN_FILENO); 00346 dup2(toast[1], STDOUT_FILENO); 00347 if (efd) { 00348 dup2(audio[0], STDERR_FILENO + 1); 00349 } else { 00350 close(STDERR_FILENO + 1); 00351 } 00352 00353 /* Before we unblock our signals, return our trapped signals back to the defaults */ 00354 signal(SIGHUP, SIG_DFL); 00355 signal(SIGCHLD, SIG_DFL); 00356 signal(SIGINT, SIG_DFL); 00357 signal(SIGURG, SIG_DFL); 00358 signal(SIGTERM, SIG_DFL); 00359 signal(SIGPIPE, SIG_DFL); 00360 signal(SIGXFSZ, SIG_DFL); 00361 00362 /* unblock important signal handlers */ 00363 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) { 00364 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno)); 00365 _exit(1); 00366 } 00367 00368 /* Close everything but stdin/out/error */ 00369 for (x=STDERR_FILENO + 2;x<1024;x++) 00370 close(x); 00371 00372 /* Execute script */ 00373 execv(script, argv); 00374 /* Can't use ast_log since FD's are closed */ 00375 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno)); 00376 /* Special case to set status of AGI to failure */ 00377 fprintf(stdout, "failure\n"); 00378 fflush(stdout); 00379 _exit(1); 00380 } 00381 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00382 if (option_verbose > 2) 00383 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script); 00384 fds[0] = toast[0]; 00385 fds[1] = fromast[1]; 00386 if (efd) { 00387 *efd = audio[1]; 00388 } 00389 /* close what we're not using in the parent */ 00390 close(toast[1]); 00391 close(fromast[0]); 00392 00393 if (efd) 00394 close(audio[0]); 00395 00396 *opid = pid; 00397 return AGI_RESULT_SUCCESS; 00398 }
static int load_module | ( | void | ) | [static] |
Definition at line 2324 of file res_agi.c.
References agi_exec(), ast_cli_register_multiple(), ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_register_application(), cli_agi, deadagi_exec(), eagi_exec(), LOG_ERROR, and shaun_of_the_dead().
02325 { 02326 if (ast_pthread_create_background(&shaun_of_the_dead_thread, NULL, shaun_of_the_dead, NULL)) { 02327 ast_log(LOG_ERROR, "Shaun of the Dead wants to kill zombies, but can't?!!\n"); 02328 shaun_of_the_dead_thread = AST_PTHREADT_NULL; 02329 } 02330 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry)); 02331 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip); 02332 ast_register_application(eapp, eagi_exec, esynopsis, descrip); 02333 return ast_register_application(app, agi_exec, synopsis, descrip); 02334 }
static int parse_args | ( | char * | s, | |
int * | max, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1794 of file res_agi.c.
References ast_log(), LOG_WARNING, and MAX_ARGS.
01795 { 01796 int x=0; 01797 int quoted=0; 01798 int escaped=0; 01799 int whitespace=1; 01800 char *cur; 01801 01802 cur = s; 01803 while(*s) { 01804 switch(*s) { 01805 case '"': 01806 /* If it's escaped, put a literal quote */ 01807 if (escaped) 01808 goto normal; 01809 else 01810 quoted = !quoted; 01811 if (quoted && whitespace) { 01812 /* If we're starting a quote, coming off white space start a new word, too */ 01813 argv[x++] = cur; 01814 whitespace=0; 01815 } 01816 escaped = 0; 01817 break; 01818 case ' ': 01819 case '\t': 01820 if (!quoted && !escaped) { 01821 /* If we're not quoted, mark this as whitespace, and 01822 end the previous argument */ 01823 whitespace = 1; 01824 *(cur++) = '\0'; 01825 } else 01826 /* Otherwise, just treat it as anything else */ 01827 goto normal; 01828 break; 01829 case '\\': 01830 /* If we're escaped, print a literal, otherwise enable escaping */ 01831 if (escaped) { 01832 goto normal; 01833 } else { 01834 escaped=1; 01835 } 01836 break; 01837 default: 01838 normal: 01839 if (whitespace) { 01840 if (x >= MAX_ARGS -1) { 01841 ast_log(LOG_WARNING, "Too many arguments, truncating\n"); 01842 break; 01843 } 01844 /* Coming off of whitespace, start the next argument */ 01845 argv[x++] = cur; 01846 whitespace=0; 01847 } 01848 *(cur++) = *s; 01849 escaped=0; 01850 } 01851 s++; 01852 } 01853 /* Null terminate */ 01854 *(cur++) = '\0'; 01855 argv[x] = NULL; 01856 *max = x; 01857 return 0; 01858 }
static enum agi_result run_agi | ( | struct ast_channel * | chan, | |
char * | request, | |||
AGI * | agi, | |||
int | pid, | |||
int * | status, | |||
int | dead | |||
) | [static] |
Definition at line 1897 of file res_agi.c.
References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, ast_calloc, ast_check_hangup(), ast_false(), AST_FRAME_VOICE, ast_frfree, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_PBX_KEEPALIVE, ast_read(), ast_strlen_zero(), ast_verbose(), ast_waitfor_nandfds(), agi_state::audio, agi_state::ctrl, errno, f, agi_state::fast, agi_state::fd, len(), zombie::list, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), setup_env(), and VERBOSE_PREFIX_3.
Referenced by agi_exec_full().
01898 { 01899 struct ast_channel *c; 01900 int outfd; 01901 int ms; 01902 enum agi_result returnstatus = AGI_RESULT_SUCCESS; 01903 struct ast_frame *f; 01904 char buf[AGI_BUF_LEN]; 01905 char *res = NULL; 01906 FILE *readf; 01907 /* how many times we'll retry if ast_waitfor_nandfs will return without either 01908 channel or file descriptor in case select is interrupted by a system call (EINTR) */ 01909 int retry = AGI_NANDFS_RETRY; 01910 01911 if (!(readf = fdopen(agi->ctrl, "r"))) { 01912 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n"); 01913 if (pid > -1) 01914 kill(pid, SIGHUP); 01915 close(agi->ctrl); 01916 return AGI_RESULT_FAILURE; 01917 } 01918 setlinebuf(readf); 01919 setup_env(chan, request, agi->fd, (agi->audio > -1)); 01920 for (;;) { 01921 ms = -1; 01922 if (dead) { 01923 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms); 01924 } else if (!ast_check_hangup(chan)) { 01925 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms); 01926 } else { 01927 /* 01928 * Read the channel control queue until it is dry so we can 01929 * quit. 01930 */ 01931 c = chan; 01932 } 01933 if (c) { 01934 retry = AGI_NANDFS_RETRY; 01935 /* Idle the channel until we get a command */ 01936 f = ast_read(c); 01937 if (!f) { 01938 ast_log(LOG_DEBUG, "%s hungup\n", chan->name); 01939 returnstatus = AGI_RESULT_HANGUP; 01940 break; 01941 } else { 01942 /* If it's voice, write it to the audio pipe */ 01943 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) { 01944 /* Write, ignoring errors */ 01945 if (write(agi->audio, f->data, f->datalen) < 0) { 01946 } 01947 } 01948 ast_frfree(f); 01949 } 01950 } else if (outfd > -1) { 01951 size_t len = sizeof(buf); 01952 size_t buflen = 0; 01953 enum agi_result cmd_status; 01954 01955 retry = AGI_NANDFS_RETRY; 01956 buf[0] = '\0'; 01957 01958 while (buflen < (len - 1)) { 01959 res = fgets(buf + buflen, len, readf); 01960 if (feof(readf)) 01961 break; 01962 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 01963 break; 01964 if (res != NULL && !agi->fast) 01965 break; 01966 buflen = strlen(buf); 01967 if (buflen && buf[buflen - 1] == '\n') 01968 break; 01969 len -= buflen; 01970 if (agidebug) 01971 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno)); 01972 } 01973 01974 if (!buf[0]) { 01975 /* Program terminated */ 01976 if (option_verbose > 2) 01977 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus); 01978 if (pid > 0) 01979 waitpid(pid, status, 0); 01980 /* No need to kill the pid anymore, since they closed us */ 01981 pid = -1; 01982 break; 01983 } 01984 01985 /* Special case for inability to execute child process */ 01986 if (*buf && strncasecmp(buf, "failure", 7) == 0) { 01987 returnstatus = AGI_RESULT_FAILURE; 01988 break; 01989 } 01990 01991 /* get rid of trailing newline, if any */ 01992 if (*buf && buf[strlen(buf) - 1] == '\n') 01993 buf[strlen(buf) - 1] = 0; 01994 if (agidebug) 01995 ast_verbose("AGI Rx << %s\n", buf); 01996 cmd_status = agi_handle_command(chan, agi, buf); 01997 if (cmd_status == AGI_RESULT_FAILURE) { 01998 if (dead || !ast_check_hangup(chan)) { 01999 /* The failure was not because of a hangup. */ 02000 returnstatus = AGI_RESULT_FAILURE; 02001 break; 02002 } 02003 } else if (cmd_status == AST_PBX_KEEPALIVE) { 02004 returnstatus = AST_PBX_KEEPALIVE; 02005 break; 02006 } 02007 } else { 02008 if (--retry <= 0) { 02009 ast_log(LOG_WARNING, "No channel, no fd?\n"); 02010 returnstatus = AGI_RESULT_FAILURE; 02011 break; 02012 } 02013 } 02014 } 02015 /* Notify process */ 02016 if (pid > -1) { 02017 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); 02018 if (ast_strlen_zero(sighup) || !ast_false(sighup)) { 02019 if (kill(pid, SIGHUP)) { 02020 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno)); 02021 } else { /* Give the process a chance to die */ 02022 usleep(1); 02023 } 02024 } 02025 /* This is essentially doing the same as without WNOHANG, except that 02026 * it allows the main thread to proceed, even without the child PID 02027 * dying immediately (the child may be doing cleanup, etc.). Without 02028 * this code, zombie processes accumulate for as long as child 02029 * processes exist (which on busy systems may be always, filling up the 02030 * process table). 02031 * 02032 * Note that in trunk, we don't stop interaction at the hangup event 02033 * (instead we transparently switch to DeadAGI operation), so this is a 02034 * short-lived code addition. 02035 */ 02036 if (waitpid(pid, status, WNOHANG) == 0) { 02037 struct zombie *cur = ast_calloc(1, sizeof(*cur)); 02038 if (cur) { 02039 cur->pid = pid; 02040 AST_LIST_LOCK(&zombies); 02041 AST_LIST_INSERT_TAIL(&zombies, cur, list); 02042 AST_LIST_UNLOCK(&zombies); 02043 } 02044 } 02045 } 02046 fclose(readf); 02047 return returnstatus; 02048 }
static void setup_env | ( | struct ast_channel * | chan, | |
char * | request, | |||
int | fd, | |||
int | enhanced | |||
) | [static] |
Definition at line 400 of file res_agi.c.
References ast_channel::accountcode, ast_channel::cid, ast_callerid::cid_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::exten, fdprintf, ast_channel::language, ast_channel::name, ast_channel::priority, S_OR, ast_channel::tech, ast_channel_tech::type, and ast_channel::uniqueid.
Referenced by run_agi().
00401 { 00402 /* Print initial environment, with agi_request always being the first 00403 thing */ 00404 fdprintf(fd, "agi_request: %s\n", request); 00405 fdprintf(fd, "agi_channel: %s\n", chan->name); 00406 fdprintf(fd, "agi_language: %s\n", chan->language); 00407 fdprintf(fd, "agi_type: %s\n", chan->tech->type); 00408 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid); 00409 00410 /* ANI/DNIS */ 00411 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown")); 00412 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown")); 00413 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres); 00414 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2); 00415 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton); 00416 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns); 00417 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown")); 00418 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown")); 00419 00420 /* Context information */ 00421 fdprintf(fd, "agi_context: %s\n", chan->context); 00422 fdprintf(fd, "agi_extension: %s\n", chan->exten); 00423 fdprintf(fd, "agi_priority: %d\n", chan->priority); 00424 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0"); 00425 00426 /* User information */ 00427 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : ""); 00428 00429 /* End with empty return */ 00430 fdprintf(fd, "\n"); 00431 }
static void* shaun_of_the_dead | ( | void * | data | ) | [static] |
Definition at line 2278 of file res_agi.c.
References ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_poll, zombie::list, and zombie::pid.
Referenced by load_module().
02279 { 02280 struct zombie *cur; 02281 int status; 02282 for (;;) { 02283 if (!AST_LIST_EMPTY(&zombies)) { 02284 /* Don't allow cancellation while we have a lock. */ 02285 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 02286 AST_LIST_LOCK(&zombies); 02287 AST_LIST_TRAVERSE_SAFE_BEGIN(&zombies, cur, list) { 02288 if (waitpid(cur->pid, &status, WNOHANG) != 0) { 02289 AST_LIST_REMOVE_CURRENT(&zombies, list); 02290 ast_free(cur); 02291 } 02292 } 02293 AST_LIST_TRAVERSE_SAFE_END 02294 AST_LIST_UNLOCK(&zombies); 02295 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 02296 } 02297 pthread_testcancel(); 02298 /* Wait for 60 seconds, without engaging in a busy loop. */ 02299 ast_poll(NULL, 0, 60000); 02300 } 02301 return NULL; 02302 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2304 of file res_agi.c.
References ast_cli_unregister_multiple(), ast_free, AST_LIST_REMOVE_HEAD, ast_module_user_hangup_all, AST_PTHREADT_NULL, ast_unregister_application(), cli_agi, and zombie::list.
02305 { 02306 int res; 02307 struct zombie *cur; 02308 ast_module_user_hangup_all(); 02309 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry)); 02310 ast_unregister_application(eapp); 02311 ast_unregister_application(deadapp); 02312 res = ast_unregister_application(app); 02313 if (shaun_of_the_dead_thread != AST_PTHREADT_NULL) { 02314 pthread_cancel(shaun_of_the_dead_thread); 02315 pthread_kill(shaun_of_the_dead_thread, SIGURG); 02316 pthread_join(shaun_of_the_dead_thread, NULL); 02317 } 02318 while ((cur = AST_LIST_REMOVE_HEAD(&zombies, list))) { 02319 ast_free(cur); 02320 } 02321 return res; 02322 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Asterisk Gateway Interface (AGI)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
struct ast_cli_entry cli_agi[] [static] |
struct ast_cli_entry cli_agi_no_debug_deprecated [static] |
Initial value:
{ { "agi", "no", "debug", NULL }, agi_no_debug_deprecated, NULL, NULL }
struct ast_cli_entry cli_dump_agihtml_deprecated [static] |
Initial value:
{ { "dump", "agihtml", NULL }, handle_agidumphtml, NULL, NULL }
struct ast_cli_entry cli_show_agi_deprecated [static] |
Initial value:
{ { "show", "agi", NULL }, handle_showagi, NULL, NULL }
agi_command commands[MAX_COMMANDS] [static] |
Definition at line 1668 of file res_agi.c.
Referenced by aji_dinfo_handler(), ast_agi_register(), ast_agi_unregister(), dundi_showframe(), find_command(), handle_agidumphtml(), and help_workhorse().
char* deadsynopsis = "Executes AGI on a hungup channel" [static] |
char debug_usage[] [static] |
char dumpagihtml_help[] [static] |
char* esynopsis = "Executes an EAGI compliant application" [static] |
char no_debug_usage[] [static] |
pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL [static] |
char showagi_help[] [static] |
char usage_answer[] [static] |
char usage_autohangup[] [static] |
Initial value:
" Usage: SET AUTOHANGUP <time>\n" " Cause the channel to automatically hangup at <time> seconds in the\n" " future. Of course it can be hungup before then as well. Setting to 0 will\n" " cause the autohangup feature to be disabled on this channel.\n"
char usage_channelstatus[] [static] |
char usage_controlstreamfile[] [static] |
char usage_dbdel[] [static] |
char usage_dbdeltree[] [static] |
char usage_dbget[] [static] |
char usage_dbput[] [static] |
char usage_exec[] [static] |
char usage_getdata[] [static] |
char usage_getoption[] [static] |
char usage_getvariable[] [static] |
char usage_getvariablefull[] [static] |
char usage_hangup[] [static] |
char usage_noop[] [static] |
char usage_recordfile[] [static] |
char usage_recvchar[] [static] |
char usage_recvtext[] [static] |
Initial value:
" Usage: RECEIVE TEXT <timeout>\n" " Receives a string of text on a channel. Specify timeout to be the\n" " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n" " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n"
char usage_sayalpha[] [static] |
char usage_saydate[] [static] |
char usage_saydatetime[] [static] |
char usage_saydigits[] [static] |
char usage_saynumber[] [static] |
char usage_sayphonetic[] [static] |
char usage_saytime[] [static] |
char usage_sendimage[] [static] |
char usage_sendtext[] [static] |
char usage_setcallerid[] [static] |
char usage_setcontext[] [static] |
char usage_setextension[] [static] |
char usage_setmusic[] [static] |
char usage_setpriority[] [static] |
char usage_setvariable[] [static] |
char usage_streamfile[] [static] |
char usage_tddmode[] [static] |
char usage_verbose[] [static] |
char usage_waitfordigit[] [static] |