#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 int | 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 1373 of file res_agi.c.
References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01374 { 01375 if (argc != 2) 01376 return RESULT_SHOWUSAGE; 01377 agidebug = 1; 01378 ast_cli(fd, "AGI Debugging Enabled\n"); 01379 return RESULT_SUCCESS; 01380 }
static int agi_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2181 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().
02182 { 02183 if (chan->_softhangup) 02184 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n"); 02185 return agi_exec_full(chan, data, 0, 0); 02186 }
static int agi_exec_full | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | enhanced, | |||
int | dead | |||
) | [static] |
Definition at line 2110 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().
02111 { 02112 enum agi_result res; 02113 struct ast_module_user *u; 02114 char *argv[MAX_ARGS]; 02115 char buf[AGI_BUF_LEN] = ""; 02116 char *tmp = (char *)buf; 02117 int argc = 0; 02118 int fds[2]; 02119 int efd = -1; 02120 int pid; 02121 char *stringp; 02122 AGI agi; 02123 02124 if (ast_strlen_zero(data)) { 02125 ast_log(LOG_WARNING, "AGI requires an argument (script)\n"); 02126 return -1; 02127 } 02128 ast_copy_string(buf, data, sizeof(buf)); 02129 02130 memset(&agi, 0, sizeof(agi)); 02131 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS-1) 02132 argv[argc++] = stringp; 02133 argv[argc] = NULL; 02134 02135 u = ast_module_user_add(chan); 02136 #if 0 02137 /* Answer if need be */ 02138 if (chan->_state != AST_STATE_UP) { 02139 if (ast_answer(chan)) { 02140 LOCAL_USER_REMOVE(u); 02141 return -1; 02142 } 02143 } 02144 #endif 02145 ast_replace_sigchld(); 02146 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid); 02147 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) { 02148 int status = 0; 02149 agi.fd = fds[1]; 02150 agi.ctrl = fds[0]; 02151 agi.audio = efd; 02152 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0; 02153 res = run_agi(chan, argv[0], &agi, pid, &status, dead); 02154 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */ 02155 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status) 02156 res = AGI_RESULT_FAILURE; 02157 if (fds[1] != fds[0]) 02158 close(fds[1]); 02159 if (efd > -1) 02160 close(efd); 02161 } 02162 ast_unreplace_sigchld(); 02163 ast_module_user_remove(u); 02164 02165 switch (res) { 02166 case AGI_RESULT_SUCCESS: 02167 case AGI_RESULT_SUCCESS_FAST: 02168 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS"); 02169 break; 02170 case AGI_RESULT_FAILURE: 02171 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE"); 02172 break; 02173 case AGI_RESULT_HANGUP: 02174 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP"); 02175 return -1; 02176 } 02177 02178 return 0; 02179 }
static int agi_handle_command | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
char * | buf | |||
) | [static] |
Definition at line 1858 of file res_agi.c.
References 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().
01859 { 01860 char *argv[MAX_ARGS]; 01861 int argc = MAX_ARGS; 01862 int res; 01863 agi_command *c; 01864 01865 parse_args(buf, &argc, argv); 01866 c = find_command(argv, 0); 01867 if (c) { 01868 /* If the AGI command being executed is an actual application (using agi exec) 01869 the app field will be updated in pbx_exec via handle_exec */ 01870 if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC")) 01871 ast_cdr_setapp(chan->cdr, "AGI", buf); 01872 01873 res = c->handler(chan, agi, argc, argv); 01874 switch(res) { 01875 case RESULT_SHOWUSAGE: 01876 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n"); 01877 fdprintf(agi->fd, "%s", c->usage); 01878 fdprintf(agi->fd, "520 End of proper usage.\n"); 01879 break; 01880 case AST_PBX_KEEPALIVE: 01881 /* We've been asked to keep alive, so do so */ 01882 return AST_PBX_KEEPALIVE; 01883 break; 01884 case RESULT_FAILURE: 01885 /* They've already given the failure. We've been hung up on so handle this 01886 appropriately */ 01887 return -1; 01888 } 01889 } else { 01890 fdprintf(agi->fd, "510 Invalid or unknown command\n"); 01891 } 01892 return 0; 01893 }
static int agi_no_debug | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1391 of file res_agi.c.
References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01392 { 01393 if (argc != 3) 01394 return RESULT_SHOWUSAGE; 01395 agidebug = 0; 01396 ast_cli(fd, "AGI Debugging Disabled\n"); 01397 return RESULT_SUCCESS; 01398 }
static int agi_no_debug_deprecated | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1382 of file res_agi.c.
References ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01383 { 01384 if (argc != 3) 01385 return RESULT_SHOWUSAGE; 01386 agidebug = 0; 01387 ast_cli(fd, "AGI Debugging Disabled\n"); 01388 return RESULT_SUCCESS; 01389 }
int ast_agi_register | ( | agi_command * | agi | ) |
Definition at line 1729 of file res_agi.c.
References ast_log(), agi_command::cmda, commands, LOG_WARNING, and MAX_COMMANDS.
01730 { 01731 int x; 01732 for (x=0; x<MAX_COMMANDS - 1; x++) { 01733 if (commands[x].cmda[0] == agi->cmda[0]) { 01734 ast_log(LOG_WARNING, "Command already registered!\n"); 01735 return -1; 01736 } 01737 } 01738 for (x=0; x<MAX_COMMANDS - 1; x++) { 01739 if (!commands[x].cmda[0]) { 01740 commands[x] = *agi; 01741 return 0; 01742 } 01743 } 01744 ast_log(LOG_WARNING, "No more room for new commands!\n"); 01745 return -1; 01746 }
void ast_agi_unregister | ( | agi_command * | agi | ) |
Definition at line 1748 of file res_agi.c.
References agi_command::cmda, commands, and MAX_COMMANDS.
01749 { 01750 int x; 01751 for (x=0; x<MAX_COMMANDS - 1; x++) { 01752 if (commands[x].cmda[0] == agi->cmda[0]) { 01753 memset(&commands[x], 0, sizeof(agi_command)); 01754 } 01755 } 01756 }
static int deadagi_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2209 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().
02210 { 02211 if (!ast_check_hangup(chan)) 02212 ast_log(LOG_WARNING,"Running DeadAGI on a live channel will cause problems, please use AGI\n"); 02213 return agi_exec_full(chan, data, 0, 1); 02214 }
static int eagi_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2188 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().
02189 { 02190 int readformat; 02191 int res; 02192 02193 if (chan->_softhangup) 02194 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n"); 02195 readformat = chan->readformat; 02196 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { 02197 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name); 02198 return -1; 02199 } 02200 res = agi_exec_full(chan, data, 1, 0); 02201 if (!res) { 02202 if (ast_set_read_format(chan, readformat)) { 02203 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat)); 02204 } 02205 } 02206 return res; 02207 }
static agi_command* find_command | ( | char * | cmds[], | |
int | exact | |||
) | [static] |
Definition at line 1758 of file res_agi.c.
References agi_command::cmda, commands, and match().
01759 { 01760 int x; 01761 int y; 01762 int match; 01763 01764 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) { 01765 if (!commands[x].cmda[0]) 01766 break; 01767 /* start optimistic */ 01768 match = 1; 01769 for (y=0; match && cmds[y]; y++) { 01770 /* If there are no more words in the command (and we're looking for 01771 an exact match) or there is a difference between the two words, 01772 then this is not a match */ 01773 if (!commands[x].cmda[y] && !exact) 01774 break; 01775 /* don't segfault if the next part of a command doesn't exist */ 01776 if (!commands[x].cmda[y]) 01777 return NULL; 01778 if (strcasecmp(commands[x].cmda[y], cmds[y])) 01779 match = 0; 01780 } 01781 /* If more words are needed to complete the command then this is not 01782 a candidate (unless we're looking for a really inexact answer */ 01783 if ((exact > -1) && commands[x].cmda[y]) 01784 match = 0; 01785 if (match) 01786 return &commands[x]; 01787 } 01788 return NULL; 01789 }
static int handle_agidumphtml | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2056 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.
02057 { 02058 struct agi_command *e; 02059 char fullcmd[80]; 02060 int x; 02061 FILE *htmlfile; 02062 02063 if ((argc < 3)) 02064 return RESULT_SHOWUSAGE; 02065 02066 if (!(htmlfile = fopen(argv[2], "wt"))) { 02067 ast_cli(fd, "Could not create file '%s'\n", argv[2]); 02068 return RESULT_SHOWUSAGE; 02069 } 02070 02071 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n"); 02072 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n"); 02073 02074 02075 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n"); 02076 02077 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) { 02078 char *stringp, *tempstr; 02079 02080 e = &commands[x]; 02081 if (!e->cmda[0]) /* end ? */ 02082 break; 02083 /* Hide commands that start with '_' */ 02084 if ((e->cmda[0])[0] == '_') 02085 continue; 02086 ast_join(fullcmd, sizeof(fullcmd), e->cmda); 02087 02088 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n"); 02089 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd,e->summary); 02090 02091 stringp=e->usage; 02092 tempstr = strsep(&stringp, "\n"); 02093 02094 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr); 02095 02096 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n"); 02097 while ((tempstr = strsep(&stringp, "\n")) != NULL) 02098 fprintf(htmlfile, "%s<BR>\n",tempstr); 02099 fprintf(htmlfile, "</TD></TR>\n"); 02100 fprintf(htmlfile, "</TABLE></TD></TR>\n\n"); 02101 02102 } 02103 02104 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n"); 02105 fclose(htmlfile); 02106 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]); 02107 return RESULT_SUCCESS; 02108 }
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 1082 of file res_agi.c.
References agi_state::fd, fdprintf, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_channel::whentohangup.
01083 { 01084 int timeout; 01085 01086 if (argc != 3) 01087 return RESULT_SHOWUSAGE; 01088 if (sscanf(argv[2], "%30d", &timeout) != 1) 01089 return RESULT_SHOWUSAGE; 01090 if (timeout < 0) 01091 timeout = 0; 01092 if (timeout) 01093 chan->whentohangup = time(NULL) + timeout; 01094 else 01095 chan->whentohangup = 0; 01096 fdprintf(agi->fd, "200 result=0\n"); 01097 return RESULT_SUCCESS; 01098 }
static int handle_channelstatus | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1181 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.
01182 { 01183 struct ast_channel *c; 01184 if (argc == 2) { 01185 /* no argument: supply info on the current channel */ 01186 fdprintf(agi->fd, "200 result=%d\n", chan->_state); 01187 return RESULT_SUCCESS; 01188 } else if (argc == 3) { 01189 /* one argument: look for info on the specified channel */ 01190 c = ast_get_channel_by_name_locked(argv[2]); 01191 if (c) { 01192 fdprintf(agi->fd, "200 result=%d\n", c->_state); 01193 ast_channel_unlock(c); 01194 return RESULT_SUCCESS; 01195 } 01196 /* if we get this far no channel name matched the argument given */ 01197 fdprintf(agi->fd, "200 result=-1\n"); 01198 return RESULT_SUCCESS; 01199 } else { 01200 return RESULT_SHOWUSAGE; 01201 } 01202 }
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 1340 of file res_agi.c.
References ast_db_del(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01341 { 01342 int res; 01343 01344 if (argc != 4) 01345 return RESULT_SHOWUSAGE; 01346 res = ast_db_del(argv[2], argv[3]); 01347 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1'); 01348 return RESULT_SUCCESS; 01349 }
static int handle_dbdeltree | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1351 of file res_agi.c.
References ast_db_deltree(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01352 { 01353 int res; 01354 if ((argc < 3) || (argc > 4)) 01355 return RESULT_SHOWUSAGE; 01356 if (argc == 4) 01357 res = ast_db_deltree(argv[2], argv[3]); 01358 else 01359 res = ast_db_deltree(argv[2], NULL); 01360 01361 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1'); 01362 return RESULT_SUCCESS; 01363 }
static int handle_dbget | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1294 of file res_agi.c.
References ast_db_get(), ast_free, ast_malloc, ast_realloc, agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01295 { 01296 int res; 01297 size_t bufsize = 16; 01298 char *buf, *tmp; 01299 01300 if (argc != 4) 01301 return RESULT_SHOWUSAGE; 01302 01303 if (!(buf = ast_malloc(bufsize))) { 01304 fdprintf(agi->fd, "200 result=-1\n"); 01305 return RESULT_SUCCESS; 01306 } 01307 01308 do { 01309 res = ast_db_get(argv[2], argv[3], buf, bufsize); 01310 if (strlen(buf) < bufsize - 1) { 01311 break; 01312 } 01313 bufsize *= 2; 01314 if (!(tmp = ast_realloc(buf, bufsize))) { 01315 break; 01316 } 01317 buf = tmp; 01318 } while (1); 01319 01320 if (res) 01321 fdprintf(agi->fd, "200 result=0\n"); 01322 else 01323 fdprintf(agi->fd, "200 result=1 (%s)\n", buf); 01324 01325 ast_free(buf); 01326 return RESULT_SUCCESS; 01327 }
static int handle_dbput | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1329 of file res_agi.c.
References ast_db_put(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01330 { 01331 int res; 01332 01333 if (argc != 5) 01334 return RESULT_SHOWUSAGE; 01335 res = ast_db_put(argv[2], argv[3], argv[4]); 01336 fdprintf(agi->fd, "200 result=%c\n", res ? '0' : '1'); 01337 return RESULT_SUCCESS; 01338 }
static int handle_exec | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1126 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.
01127 { 01128 int res, workaround; 01129 struct ast_app *app; 01130 01131 if (argc < 2) 01132 return RESULT_SHOWUSAGE; 01133 01134 if (option_verbose > 2) 01135 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]); 01136 01137 app = pbx_findapp(argv[1]); 01138 01139 if (app) { 01140 if(!strcasecmp(argv[1], PARK_APP_NAME)) { 01141 ast_masq_park_call(chan, NULL, 0, NULL); 01142 } 01143 if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) { 01144 ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); 01145 } 01146 res = pbx_exec(chan, app, argc == 2 ? "" : argv[2]); 01147 if (!workaround) { 01148 ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS); 01149 } 01150 } else { 01151 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]); 01152 res = -2; 01153 } 01154 fdprintf(agi->fd, "200 result=%d\n", res); 01155 01156 /* Even though this is wrong, users are depending upon this result. */ 01157 return res; 01158 }
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 1213 of file res_agi.c.
References ast_func_read(), ast_strlen_zero(), agi_state::fd, fdprintf, pbx_retrieve_variable(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01214 { 01215 char *ret; 01216 char tempstr[1024]; 01217 01218 if (argc != 3) 01219 return RESULT_SHOWUSAGE; 01220 01221 /* check if we want to execute an ast_custom_function */ 01222 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) { 01223 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr; 01224 } else { 01225 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL); 01226 } 01227 01228 if (ret) 01229 fdprintf(agi->fd, "200 result=1 (%s)\n", ret); 01230 else 01231 fdprintf(agi->fd, "200 result=0\n"); 01232 01233 return RESULT_SUCCESS; 01234 }
static int handle_getvariablefull | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1236 of file res_agi.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), agi_state::fd, fdprintf, pbx_substitute_variables_helper(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01237 { 01238 char tmp[4096] = ""; 01239 struct ast_channel *chan2=NULL; 01240 01241 if ((argc != 4) && (argc != 5)) 01242 return RESULT_SHOWUSAGE; 01243 if (argc == 5) { 01244 chan2 = ast_get_channel_by_name_locked(argv[4]); 01245 } else { 01246 chan2 = chan; 01247 } 01248 if (chan2) { 01249 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1); 01250 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp); 01251 } else { 01252 fdprintf(agi->fd, "200 result=0\n"); 01253 } 01254 if (chan2 && (chan2 != chan)) 01255 ast_channel_unlock(chan2); 01256 return RESULT_SUCCESS; 01257 }
static int handle_hangup | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1100 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.
01101 { 01102 struct ast_channel *c; 01103 if (argc == 1) { 01104 /* no argument: hangup the current channel */ 01105 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); 01106 fdprintf(agi->fd, "200 result=1\n"); 01107 return RESULT_SUCCESS; 01108 } else if (argc == 2) { 01109 /* one argument: look for info on the specified channel */ 01110 c = ast_get_channel_by_name_locked(argv[1]); 01111 if (c) { 01112 /* we have a matching channel */ 01113 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT); 01114 fdprintf(agi->fd, "200 result=1\n"); 01115 ast_channel_unlock(c); 01116 return RESULT_SUCCESS; 01117 } 01118 /* if we get this far no channel name matched the argument given */ 01119 fdprintf(agi->fd, "200 result=-1\n"); 01120 return RESULT_SUCCESS; 01121 } else { 01122 return RESULT_SHOWUSAGE; 01123 } 01124 }
static int handle_noop | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | arg, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1400 of file res_agi.c.
References agi_state::fd, fdprintf, and RESULT_SUCCESS.
01401 { 01402 fdprintf(agi->fd, "200 result=0\n"); 01403 return RESULT_SUCCESS; 01404 }
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 return -1; 00956 } 00957 sildet = ast_dsp_new(); 00958 if (!sildet) { 00959 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00960 return -1; 00961 } 00962 ast_dsp_set_threshold(sildet, 256); 00963 } 00964 00965 /* backward compatibility, if no offset given, arg[6] would have been 00966 * caught below and taken to be a beep, else if it is a digit then it is a 00967 * offset */ 00968 if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '='))) 00969 res = ast_streamfile(chan, "beep", chan->language); 00970 00971 if ((argc > 7) && (!strchr(argv[7], '='))) 00972 res = ast_streamfile(chan, "beep", chan->language); 00973 00974 if (!res) 00975 res = ast_waitstream(chan, argv[4]); 00976 if (res) { 00977 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); 00978 } else { 00979 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644); 00980 if (!fs) { 00981 res = -1; 00982 fdprintf(agi->fd, "200 result=%d (writefile)\n", res); 00983 if (sildet) 00984 ast_dsp_free(sildet); 00985 return RESULT_FAILURE; 00986 } 00987 00988 /* Request a video update */ 00989 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00990 00991 chan->stream = fs; 00992 ast_applystream(chan,fs); 00993 /* really should have checks */ 00994 ast_seekstream(fs, sample_offset, SEEK_SET); 00995 ast_truncstream(fs); 00996 00997 start = ast_tvnow(); 00998 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) { 00999 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start)); 01000 if (res < 0) { 01001 ast_closestream(fs); 01002 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); 01003 if (sildet) 01004 ast_dsp_free(sildet); 01005 return RESULT_FAILURE; 01006 } 01007 f = ast_read(chan); 01008 if (!f) { 01009 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset); 01010 ast_closestream(fs); 01011 if (sildet) 01012 ast_dsp_free(sildet); 01013 return RESULT_FAILURE; 01014 } 01015 switch(f->frametype) { 01016 case AST_FRAME_DTMF: 01017 if (strchr(argv[4], f->subclass)) { 01018 /* This is an interrupting chracter, so rewind to chop off any small 01019 amount of DTMF that may have been recorded 01020 */ 01021 ast_stream_rewind(fs, 200); 01022 ast_truncstream(fs); 01023 sample_offset = ast_tellstream(fs); 01024 fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset); 01025 ast_closestream(fs); 01026 ast_frfree(f); 01027 if (sildet) 01028 ast_dsp_free(sildet); 01029 return RESULT_SUCCESS; 01030 } 01031 break; 01032 case AST_FRAME_VOICE: 01033 ast_writestream(fs, f); 01034 /* this is a safe place to check progress since we know that fs 01035 * is valid after a write, and it will then have our current 01036 * location */ 01037 sample_offset = ast_tellstream(fs); 01038 if (silence > 0) { 01039 dspsilence = 0; 01040 ast_dsp_silence(sildet, f, &dspsilence); 01041 if (dspsilence) { 01042 totalsilence = dspsilence; 01043 } else { 01044 totalsilence = 0; 01045 } 01046 if (totalsilence > silence) { 01047 /* Ended happily with silence */ 01048 gotsilence = 1; 01049 break; 01050 } 01051 } 01052 break; 01053 case AST_FRAME_VIDEO: 01054 ast_writestream(fs, f); 01055 default: 01056 /* Ignore all other frames */ 01057 break; 01058 } 01059 ast_frfree(f); 01060 if (gotsilence) 01061 break; 01062 } 01063 01064 if (gotsilence) { 01065 ast_stream_rewind(fs, silence-1000); 01066 ast_truncstream(fs); 01067 sample_offset = ast_tellstream(fs); 01068 } 01069 fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); 01070 ast_closestream(fs); 01071 } 01072 01073 if (silence > 0) { 01074 res = ast_set_read_format(chan, rfmt); 01075 if (res) 01076 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); 01077 ast_dsp_free(sildet); 01078 } 01079 return RESULT_SUCCESS; 01080 }
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 1160 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.
01161 { 01162 char tmp[256]=""; 01163 char *l = NULL, *n = NULL; 01164 01165 if (argv[2]) { 01166 ast_copy_string(tmp, argv[2], sizeof(tmp)); 01167 ast_callerid_parse(tmp, &n, &l); 01168 if (l) 01169 ast_shrink_phone_number(l); 01170 else 01171 l = ""; 01172 if (!n) 01173 n = ""; 01174 ast_set_callerid(chan, l, n, NULL); 01175 } 01176 01177 fdprintf(agi->fd, "200 result=1\n"); 01178 return RESULT_SUCCESS; 01179 }
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 1406 of file res_agi.c.
References ast_moh_start(), ast_moh_stop(), agi_state::fd, fdprintf, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01407 { 01408 if (argc < 3) { 01409 return RESULT_SHOWUSAGE; 01410 } 01411 if (!strncasecmp(argv[2], "on", 2)) 01412 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL); 01413 else if (!strncasecmp(argv[2], "off", 3)) 01414 ast_moh_stop(chan); 01415 fdprintf(agi->fd, "200 result=0\n"); 01416 return RESULT_SUCCESS; 01417 }
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 1204 of file res_agi.c.
References agi_state::fd, fdprintf, pbx_builtin_setvar_helper(), and RESULT_SUCCESS.
01205 { 01206 if (argv[3]) 01207 pbx_builtin_setvar_helper(chan, argv[2], argv[3]); 01208 01209 fdprintf(agi->fd, "200 result=1\n"); 01210 return RESULT_SUCCESS; 01211 }
static int handle_showagi | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2032 of file res_agi.c.
References ast_cli(), ast_join(), find_command(), help_workhorse(), RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_command::usage.
02033 { 02034 struct agi_command *e; 02035 char fullcmd[80]; 02036 if ((argc < 2)) 02037 return RESULT_SHOWUSAGE; 02038 if (argc > 2) { 02039 e = find_command(argv + 2, 1); 02040 if (e) 02041 ast_cli(fd, "%s", e->usage); 02042 else { 02043 if (find_command(argv + 2, -1)) { 02044 return help_workhorse(fd, argv + 1); 02045 } else { 02046 ast_join(fullcmd, sizeof(fullcmd), argv+1); 02047 ast_cli(fd, "No such command '%s'.\n", fullcmd); 02048 } 02049 } 02050 } else { 02051 return help_workhorse(fd, NULL); 02052 } 02053 return RESULT_SUCCESS; 02054 }
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 1259 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.
01260 { 01261 int level = 0; 01262 char *prefix; 01263 01264 if (argc < 2) 01265 return RESULT_SHOWUSAGE; 01266 01267 if (argv[2]) 01268 sscanf(argv[2], "%30d", &level); 01269 01270 switch (level) { 01271 case 4: 01272 prefix = VERBOSE_PREFIX_4; 01273 break; 01274 case 3: 01275 prefix = VERBOSE_PREFIX_3; 01276 break; 01277 case 2: 01278 prefix = VERBOSE_PREFIX_2; 01279 break; 01280 case 1: 01281 default: 01282 prefix = VERBOSE_PREFIX_1; 01283 break; 01284 } 01285 01286 if (level <= option_verbose) 01287 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]); 01288 01289 fdprintf(agi->fd, "200 result=1\n"); 01290 01291 return RESULT_SUCCESS; 01292 }
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 1706 of file res_agi.c.
References ast_cli(), ast_join(), agi_command::cmda, commands, and agi_command::summary.
01707 { 01708 char fullcmd[80]; 01709 char matchstr[80]; 01710 int x; 01711 struct agi_command *e; 01712 if (match) 01713 ast_join(matchstr, sizeof(matchstr), match); 01714 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) { 01715 e = &commands[x]; 01716 if (!e->cmda[0]) 01717 break; 01718 /* Hide commands that start with '_' */ 01719 if ((e->cmda[0])[0] == '_') 01720 continue; 01721 ast_join(fullcmd, sizeof(fullcmd), e->cmda); 01722 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr))) 01723 continue; 01724 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary); 01725 } 01726 return 0; 01727 }
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 2306 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().
02307 { 02308 if (ast_pthread_create_background(&shaun_of_the_dead_thread, NULL, shaun_of_the_dead, NULL)) { 02309 ast_log(LOG_ERROR, "Shaun of the Dead wants to kill zombies, but can't?!!\n"); 02310 shaun_of_the_dead_thread = AST_PTHREADT_NULL; 02311 } 02312 ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry)); 02313 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip); 02314 ast_register_application(eapp, eagi_exec, esynopsis, descrip); 02315 return ast_register_application(app, agi_exec, synopsis, descrip); 02316 }
static int parse_args | ( | char * | s, | |
int * | max, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1792 of file res_agi.c.
References ast_log(), LOG_WARNING, and MAX_ARGS.
01793 { 01794 int x=0; 01795 int quoted=0; 01796 int escaped=0; 01797 int whitespace=1; 01798 char *cur; 01799 01800 cur = s; 01801 while(*s) { 01802 switch(*s) { 01803 case '"': 01804 /* If it's escaped, put a literal quote */ 01805 if (escaped) 01806 goto normal; 01807 else 01808 quoted = !quoted; 01809 if (quoted && whitespace) { 01810 /* If we're starting a quote, coming off white space start a new word, too */ 01811 argv[x++] = cur; 01812 whitespace=0; 01813 } 01814 escaped = 0; 01815 break; 01816 case ' ': 01817 case '\t': 01818 if (!quoted && !escaped) { 01819 /* If we're not quoted, mark this as whitespace, and 01820 end the previous argument */ 01821 whitespace = 1; 01822 *(cur++) = '\0'; 01823 } else 01824 /* Otherwise, just treat it as anything else */ 01825 goto normal; 01826 break; 01827 case '\\': 01828 /* If we're escaped, print a literal, otherwise enable escaping */ 01829 if (escaped) { 01830 goto normal; 01831 } else { 01832 escaped=1; 01833 } 01834 break; 01835 default: 01836 normal: 01837 if (whitespace) { 01838 if (x >= MAX_ARGS -1) { 01839 ast_log(LOG_WARNING, "Too many arguments, truncating\n"); 01840 break; 01841 } 01842 /* Coming off of whitespace, start the next argument */ 01843 argv[x++] = cur; 01844 whitespace=0; 01845 } 01846 *(cur++) = *s; 01847 escaped=0; 01848 } 01849 s++; 01850 } 01851 /* Null terminate */ 01852 *(cur++) = '\0'; 01853 argv[x] = NULL; 01854 *max = x; 01855 return 0; 01856 }
static enum agi_result run_agi | ( | struct ast_channel * | chan, | |
char * | request, | |||
AGI * | agi, | |||
int | pid, | |||
int * | status, | |||
int | dead | |||
) | [static] |
Definition at line 1894 of file res_agi.c.
References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, ast_calloc, 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().
01895 { 01896 struct ast_channel *c; 01897 int outfd; 01898 int ms; 01899 enum agi_result returnstatus = AGI_RESULT_SUCCESS; 01900 struct ast_frame *f; 01901 char buf[AGI_BUF_LEN]; 01902 char *res = NULL; 01903 FILE *readf; 01904 /* how many times we'll retry if ast_waitfor_nandfs will return without either 01905 channel or file descriptor in case select is interrupted by a system call (EINTR) */ 01906 int retry = AGI_NANDFS_RETRY; 01907 01908 if (!(readf = fdopen(agi->ctrl, "r"))) { 01909 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n"); 01910 if (pid > -1) 01911 kill(pid, SIGHUP); 01912 close(agi->ctrl); 01913 return AGI_RESULT_FAILURE; 01914 } 01915 setlinebuf(readf); 01916 setup_env(chan, request, agi->fd, (agi->audio > -1)); 01917 for (;;) { 01918 ms = -1; 01919 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms); 01920 if (c) { 01921 retry = AGI_NANDFS_RETRY; 01922 /* Idle the channel until we get a command */ 01923 f = ast_read(c); 01924 if (!f) { 01925 ast_log(LOG_DEBUG, "%s hungup\n", chan->name); 01926 returnstatus = AGI_RESULT_HANGUP; 01927 break; 01928 } else { 01929 /* If it's voice, write it to the audio pipe */ 01930 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) { 01931 /* Write, ignoring errors */ 01932 if (write(agi->audio, f->data, f->datalen) < 0) { 01933 } 01934 } 01935 ast_frfree(f); 01936 } 01937 } else if (outfd > -1) { 01938 size_t len = sizeof(buf); 01939 size_t buflen = 0; 01940 01941 retry = AGI_NANDFS_RETRY; 01942 buf[0] = '\0'; 01943 01944 while (buflen < (len - 1)) { 01945 res = fgets(buf + buflen, len, readf); 01946 if (feof(readf)) 01947 break; 01948 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 01949 break; 01950 if (res != NULL && !agi->fast) 01951 break; 01952 buflen = strlen(buf); 01953 if (buflen && buf[buflen - 1] == '\n') 01954 break; 01955 len -= buflen; 01956 if (agidebug) 01957 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno)); 01958 } 01959 01960 if (!buf[0]) { 01961 /* Program terminated */ 01962 if (returnstatus) 01963 returnstatus = -1; 01964 if (option_verbose > 2) 01965 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus); 01966 if (pid > 0) 01967 waitpid(pid, status, 0); 01968 /* No need to kill the pid anymore, since they closed us */ 01969 pid = -1; 01970 break; 01971 } 01972 01973 /* Special case for inability to execute child process */ 01974 if (*buf && strncasecmp(buf, "failure", 7) == 0) { 01975 returnstatus = AGI_RESULT_FAILURE; 01976 break; 01977 } 01978 01979 /* get rid of trailing newline, if any */ 01980 if (*buf && buf[strlen(buf) - 1] == '\n') 01981 buf[strlen(buf) - 1] = 0; 01982 if (agidebug) 01983 ast_verbose("AGI Rx << %s\n", buf); 01984 returnstatus |= agi_handle_command(chan, agi, buf); 01985 /* If the handle_command returns -1, we need to stop */ 01986 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) { 01987 break; 01988 } 01989 } else { 01990 if (--retry <= 0) { 01991 ast_log(LOG_WARNING, "No channel, no fd?\n"); 01992 returnstatus = AGI_RESULT_FAILURE; 01993 break; 01994 } 01995 } 01996 } 01997 /* Notify process */ 01998 if (pid > -1) { 01999 const char *sighup = pbx_builtin_getvar_helper(chan, "AGISIGHUP"); 02000 if (ast_strlen_zero(sighup) || !ast_false(sighup)) { 02001 if (kill(pid, SIGHUP)) { 02002 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno)); 02003 } else { /* Give the process a chance to die */ 02004 usleep(1); 02005 } 02006 } 02007 /* This is essentially doing the same as without WNOHANG, except that 02008 * it allows the main thread to proceed, even without the child PID 02009 * dying immediately (the child may be doing cleanup, etc.). Without 02010 * this code, zombie processes accumulate for as long as child 02011 * processes exist (which on busy systems may be always, filling up the 02012 * process table). 02013 * 02014 * Note that in trunk, we don't stop interaction at the hangup event 02015 * (instead we transparently switch to DeadAGI operation), so this is a 02016 * short-lived code addition. 02017 */ 02018 if (waitpid(pid, status, WNOHANG) == 0) { 02019 struct zombie *cur = ast_calloc(1, sizeof(*cur)); 02020 if (cur) { 02021 cur->pid = pid; 02022 AST_LIST_LOCK(&zombies); 02023 AST_LIST_INSERT_TAIL(&zombies, cur, list); 02024 AST_LIST_UNLOCK(&zombies); 02025 } 02026 } 02027 } 02028 fclose(readf); 02029 return returnstatus; 02030 }
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 2260 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().
02261 { 02262 struct zombie *cur; 02263 int status; 02264 for (;;) { 02265 if (!AST_LIST_EMPTY(&zombies)) { 02266 /* Don't allow cancellation while we have a lock. */ 02267 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 02268 AST_LIST_LOCK(&zombies); 02269 AST_LIST_TRAVERSE_SAFE_BEGIN(&zombies, cur, list) { 02270 if (waitpid(cur->pid, &status, WNOHANG) != 0) { 02271 AST_LIST_REMOVE_CURRENT(&zombies, list); 02272 ast_free(cur); 02273 } 02274 } 02275 AST_LIST_TRAVERSE_SAFE_END 02276 AST_LIST_UNLOCK(&zombies); 02277 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 02278 } 02279 pthread_testcancel(); 02280 /* Wait for 60 seconds, without engaging in a busy loop. */ 02281 ast_poll(NULL, 0, 60000); 02282 } 02283 return NULL; 02284 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2286 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.
02287 { 02288 int res; 02289 struct zombie *cur; 02290 ast_module_user_hangup_all(); 02291 ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry)); 02292 ast_unregister_application(eapp); 02293 ast_unregister_application(deadapp); 02294 res = ast_unregister_application(app); 02295 if (shaun_of_the_dead_thread != AST_PTHREADT_NULL) { 02296 pthread_cancel(shaun_of_the_dead_thread); 02297 pthread_kill(shaun_of_the_dead_thread, SIGURG); 02298 pthread_join(shaun_of_the_dead_thread, NULL); 02299 } 02300 while ((cur = AST_LIST_REMOVE_HEAD(&zombies, list))) { 02301 ast_free(cur); 02302 } 02303 return res; 02304 }
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 1666 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] |