Sun Feb 23 07:00:00 CET 2003

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@621 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Matteo Brancaleoni 23 years ago
parent 877a281b74
commit 17769619c2

@ -1,3 +1,4 @@
-- Add "Enhanced" AGI with audio pass-through (voice recognition anyone?)
-- Choose best priority from codec from allow/disallow -- Choose best priority from codec from allow/disallow
-- Reject SIP calls to self -- Reject SIP calls to self
-- Allow SIP registration to provide an alternative contact -- Allow SIP registration to provide an alternative contact

@ -0,0 +1,2 @@
eagi-test
eagi-sphinx-test

@ -11,7 +11,7 @@
# the GNU General Public License # the GNU General Public License
# #
AGIS=agi-test.agi AGIS=agi-test.agi eagi-test eagi-sphinx-test
CFLAGS+= CFLAGS+=
@ -20,6 +20,12 @@ all: $(AGIS)
install: all install: all
for x in $(AGIS); do $(INSTALL) -m 755 $$x $(AGI_DIR) ; done for x in $(AGIS); do $(INSTALL) -m 755 $$x $(AGI_DIR) ; done
eagi-test: eagi-test.o
$(CC) -o eagi-test eagi-test.o
eagi-sphinx-test: eagi-sphinx-test.o
$(CC) -o eagi-sphinx-test eagi-sphinx-test.o
clean: clean:
rm -f *.so *.o look rm -f *.so *.o look

@ -0,0 +1,216 @@
/*
* Extended AGI test application
*
* Copyright (C) 2003, Digium, Inc.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define AUDIO_FILENO (STDERR_FILENO + 1)
#define SPHINX_HOST "192.168.1.108"
#define SPHINX_PORT 3460
static int sphinx_sock = -1;
static int connect_sphinx(void)
{
struct hostent *hp;
struct sockaddr_in sin;
int res;
hp = gethostbyname(SPHINX_HOST);
if (!hp) {
fprintf(stderr, "Unable to resolve '%s'\n", SPHINX_HOST);
return -1;
}
sphinx_sock = socket(PF_INET, SOCK_STREAM, 0);
if (sphinx_sock < 0) {
fprintf(stderr, "Unable to allocate socket: %s\n", strerror(errno));
return -1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SPHINX_PORT);
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
if (connect(sphinx_sock, &sin, sizeof(sin))) {
fprintf(stderr, "Unable to connect on socket: %s\n", strerror(errno));
close(sphinx_sock);
sphinx_sock = -1;
return -1;
}
res = fcntl(sphinx_sock, F_GETFL);
if ((res < 0) || (fcntl(sphinx_sock, F_SETFL, res | O_NONBLOCK) < 0)) {
fprintf(stderr, "Unable to set flags on socket: %s\n", strerror(errno));
close(sphinx_sock);
sphinx_sock = -1;
return -1;
}
return 0;
}
static int read_environment(void)
{
char buf[256];
char *val;
/* Read environment */
for(;;) {
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '\0';
/* Check for end of environment */
if (!strlen(buf))
return 0;
val = strchr(buf, ':');
if (!val) {
fprintf(stderr, "Invalid environment: '%s'\n", buf);
return -1;
}
*val = '\0';
val++;
val++;
/* Skip space */
fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
/* Load into normal environment */
setenv(buf, val, 1);
}
/* Never reached */
return 0;
}
static char *wait_result(void)
{
fd_set fds;
int res;
int max;
static char astresp[256];
static char sphinxresp[256];
char audiobuf[4096];
for (;;) {
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
FD_SET(AUDIO_FILENO, &fds);
max = AUDIO_FILENO;
if (sphinx_sock > -1) {
FD_SET(sphinx_sock, &fds);
if (sphinx_sock > max)
max = sphinx_sock;
}
/* Wait for *some* sort of I/O */
res = select(max + 1, &fds, NULL, NULL, NULL);
if (res < 0) {
fprintf(stderr, "Error in select: %s\n", strerror(errno));
return NULL;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
fgets(astresp, sizeof(astresp), stdin);
if (feof(stdin)) {
fprintf(stderr, "Got hungup on apparently\n");
return NULL;
}
astresp[strlen(astresp) - 1] = '\0';
fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
return astresp;
}
if (FD_ISSET(AUDIO_FILENO, &fds)) {
res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
if (res > 0) {
if (sphinx_sock > -1)
write(sphinx_sock, audiobuf, res);
}
}
if ((sphinx_sock > -1) && FD_ISSET(sphinx_sock, &fds)) {
res = read(sphinx_sock, sphinxresp, sizeof(sphinxresp));
if (res > 0) {
fprintf(stderr, "Oooh, Sphinx found a token: '%s'\n", sphinxresp);
return sphinxresp;
} else if (res == 0) {
fprintf(stderr, "Hrm, lost sphinx, guess we're on our own\n");
close(sphinx_sock);
sphinx_sock = -1;
}
}
}
}
static char *run_command(char *command)
{
fprintf(stdout, "%s\n", command);
return wait_result();
}
static int run_script(void)
{
char *res;
res = run_command("STREAM FILE demo-enterkeywords 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "1. Result is '%s'\n", res);
res = run_command("STREAM FILE demo-nomatch 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "2. Result is '%s'\n", res);
res = run_command("SAY NUMBER 23452345 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "3. Result is '%s'\n", res);
res = run_command("GET DATA demo-enterkeywords");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "4. Result is '%s'\n", res);
res = run_command("STREAM FILE auth-thankyou \"\"");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "5. Result is '%s'\n", res);
return 0;
}
int main(int argc, char *argv[])
{
char *tmp;
int ver = 0;
int subver = 0;
/* Setup stdin/stdout for line buffering */
setlinebuf(stdin);
setlinebuf(stdout);
if (read_environment()) {
fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
exit(1);
}
connect_sphinx();
tmp = getenv("agi_enhanced");
if (tmp) {
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
if (ver < 1) {
fprintf(stderr, "No enhanced AGI services available. Use EAGI, not AGI\n");
exit(1);
}
if (run_script())
return -1;
exit(0);
}

@ -0,0 +1,160 @@
/*
* Extended AGI test application
*
* Copyright (C) 2003, Digium, Inc.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#define AUDIO_FILENO (STDERR_FILENO + 1)
static int read_environment(void)
{
char buf[256];
char *val;
/* Read environment */
for(;;) {
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '\0';
/* Check for end of environment */
if (!strlen(buf))
return 0;
val = strchr(buf, ':');
if (!val) {
fprintf(stderr, "Invalid environment: '%s'\n", buf);
return -1;
}
*val = '\0';
val++;
val++;
/* Skip space */
fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
/* Load into normal environment */
setenv(buf, val, 1);
}
/* Never reached */
return 0;
}
static char *wait_result(void)
{
fd_set fds;
int res;
int bytes = 0;
static char astresp[256];
char audiobuf[4096];
for (;;) {
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
FD_SET(AUDIO_FILENO, &fds);
/* Wait for *some* sort of I/O */
res = select(AUDIO_FILENO + 1, &fds, NULL, NULL, NULL);
if (res < 0) {
fprintf(stderr, "Error in select: %s\n", strerror(errno));
return NULL;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
fgets(astresp, sizeof(astresp), stdin);
if (feof(stdin)) {
fprintf(stderr, "Got hungup on apparently\n");
return NULL;
}
astresp[strlen(astresp) - 1] = '\0';
fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
return astresp;
}
if (FD_ISSET(AUDIO_FILENO, &fds)) {
res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
if (res > 0) {
/* XXX Process the audio with sphinx here XXX */
#if 0
fprintf(stderr, "Got %d/%d bytes of audio\n", res, bytes);
#endif
bytes += res;
/* Prentend we detected some audio after 3 seconds */
if (bytes > 16000 * 3) {
return "Sample Message";
bytes = 0;
}
}
}
}
}
static char *run_command(char *command)
{
fprintf(stdout, "%s\n", command);
return wait_result();
}
static int run_script(void)
{
char *res;
res = run_command("STREAM FILE demo-enterkeywords 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "1. Result is '%s'\n", res);
res = run_command("STREAM FILE demo-nomatch 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "2. Result is '%s'\n", res);
res = run_command("SAY NUMBER 23452345 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "3. Result is '%s'\n", res);
res = run_command("GET DATA demo-enterkeywords");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "4. Result is '%s'\n", res);
res = run_command("STREAM FILE auth-thankyou \"\"");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "5. Result is '%s'\n", res);
return 0;
}
int main(int argc, char *argv[])
{
char *tmp;
int ver = 0;
int subver = 0;
/* Setup stdin/stdout for line buffering */
setlinebuf(stdin);
setlinebuf(stdout);
if (read_environment()) {
fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
exit(1);
}
tmp = getenv("agi_enhanced");
if (tmp) {
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
if (ver < 1) {
fprintf(stderr, "No enhanced AGI services available. Use EAGI, not AGI\n");
exit(1);
}
if (run_script())
return -1;
exit(0);
}

18
app.c

@ -34,6 +34,7 @@
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout) int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
{ {
int res,to,fto; int res,to,fto;
/* XXX Merge with full version? XXX */
if (prompt) { if (prompt) {
res = ast_streamfile(c, prompt, c->language); res = ast_streamfile(c, prompt, c->language);
if (res < 0) if (res < 0)
@ -47,6 +48,23 @@ int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, in
return res; return res;
} }
int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
{
int res,to,fto;
if (prompt) {
res = ast_streamfile(c, prompt, c->language);
if (res < 0)
return res;
}
fto = 6000;
to = 2000;
if (timeout > 0) fto = to = timeout;
if (timeout < 0) fto = to = 1000000000;
res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
return res;
}
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec) int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
{ {
int res; int res;

@ -18,7 +18,8 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.
app_zapateller.so app_datetime.so app_setcallerid.so app_festival.so \ app_zapateller.so app_datetime.so app_setcallerid.so app_festival.so \
app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \ app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \ app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
app_authenticate.so app_softhangup.so app_lookupblacklist.so app_authenticate.so app_softhangup.so app_lookupblacklist.so \
app_waitforring.so
#APPS+=app_sql_postgres.so #APPS+=app_sql_postgres.so
#APPS+=app_sql_odbc.so #APPS+=app_sql_odbc.so

@ -32,6 +32,7 @@
#include <asterisk/options.h> #include <asterisk/options.h>
#include <asterisk/image.h> #include <asterisk/image.h>
#include <asterisk/say.h> #include <asterisk/say.h>
#include <asterisk/app.h>
#include "../asterisk.h" #include "../asterisk.h"
#include "../astconf.h" #include "../astconf.h"
@ -42,12 +43,18 @@
/* Recycle some stuff from the CLI interface */ /* Recycle some stuff from the CLI interface */
#define fdprintf ast_cli #define fdprintf ast_cli
typedef struct agi_state {
int fd; /* FD for general output */
int audio; /* FD for audio output */
int ctrl; /* FD for input control */
} AGI;
typedef struct agi_command { typedef struct agi_command {
/* Null terminated list of the words of the command */ /* Null terminated list of the words of the command */
char *cmda[AST_MAX_CMD_LEN]; char *cmda[AST_MAX_CMD_LEN];
/* Handler for the command (fd for output, # of arguments, argument list). /* Handler for the command (channel, AGI state, # of arguments, argument list).
Returns RESULT_SHOWUSAGE for improper arguments */ Returns RESULT_SHOWUSAGE for improper arguments */
int (*handler)(struct ast_channel *chan, int fd, int argc, char *argv[]); int (*handler)(struct ast_channel *chan, AGI *agi, int argc, char *argv[]);
/* Summary of the command (< 60 characters) */ /* Summary of the command (< 60 characters) */
char *summary; char *summary;
/* Detailed usage information */ /* Detailed usage information */
@ -58,15 +65,18 @@ static char *tdesc = "Asterisk Gateway Interface (AGI)";
static char *app = "AGI"; static char *app = "AGI";
static char *eapp = "EAGI";
static char *synopsis = "Executes an AGI compliant application"; static char *synopsis = "Executes an AGI compliant application";
static char *descrip = static char *descrip =
" AGI(command|args): Executes an Asterisk Gateway Interface compliant\n" " [E]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
"program on a channel. AGI allows Asterisk to launch external programs\n" "program on a channel. AGI allows Asterisk to launch external programs\n"
"written in any language to control a telephony channel, play audio,\n" "written in any language to control a telephony channel, play audio,\n"
"read DTMF digits, etc. by communicating with the AGI protocol on stdin\n" "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
"and stdout. Returns -1 on hangup or if application requested hangup, or\n" "and stdout. Returns -1 on hangup or if application requested hangup, or\n"
"0 on non-hangup exit.\n"; "0 on non-hangup exit. Using 'EAGI' provides enhanced AGI, with audio\n"
"available out of band on file descriptor 3\n";
STANDARD_LOCAL_USER; STANDARD_LOCAL_USER;
@ -75,33 +85,15 @@ LOCAL_USER_DECL;
#define TONE_BLOCK_SIZE 200 #define TONE_BLOCK_SIZE 200
static float loudness = 8192.0; static int launch_script(char *script, char *args, int *fds, int *efd, int *opid)
unsigned char linear2ulaw(short sample);
static void make_tone_block(unsigned char *data, float f1, int *x);
static void make_tone_block(unsigned char *data, float f1, int *x)
{
int i;
float val;
for(i = 0; i < TONE_BLOCK_SIZE; i++)
{
val = loudness * sin((f1 * 2.0 * M_PI * (*x)++)/8000.0);
data[i] = linear2ulaw((int)val);
}
/* wrap back around from 8000 */
if (*x >= 8000) *x = 0;
return;
}
static int launch_script(char *script, char *args, int *fds, int *opid)
{ {
char tmp[256]; char tmp[256];
int pid; int pid;
int toast[2]; int toast[2];
int fromast[2]; int fromast[2];
int audio[2];
int x; int x;
int res;
if (script[0] != '/') { if (script[0] != '/') {
snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script); snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
script = tmp; script = tmp;
@ -116,17 +108,45 @@ static int launch_script(char *script, char *args, int *fds, int *opid)
close(toast[1]); close(toast[1]);
return -1; return -1;
} }
if (efd) {
if (pipe(audio)) {
ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
close(fromast[0]);
close(fromast[1]);
close(toast[0]);
close(toast[1]);
return -1;
}
res = fcntl(audio[1], F_GETFL);
if (res > -1)
res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
if (res < 0) {
ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
close(fromast[0]);
close(fromast[1]);
close(toast[0]);
close(toast[1]);
close(audio[0]);
close(audio[1]);
return -1;
}
}
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
return -1; return -1;
} }
if (!pid) { if (!pid) {
/* Redirect stdin and out */ /* Redirect stdin and out, provide enhanced audio channel if desired */
dup2(fromast[0], STDIN_FILENO); dup2(fromast[0], STDIN_FILENO);
dup2(toast[1], STDOUT_FILENO); dup2(toast[1], STDOUT_FILENO);
if (efd) {
dup2(audio[0], STDERR_FILENO + 1);
} else {
close(STDERR_FILENO + 1);
}
/* Close everything but stdin/out/error */ /* Close everything but stdin/out/error */
for (x=STDERR_FILENO + 1;x<1024;x++) for (x=STDERR_FILENO + 2;x<1024;x++)
close(x); close(x);
/* Execute script */ /* Execute script */
execl(script, script, args, NULL); execl(script, script, args, NULL);
@ -138,6 +158,9 @@ static int launch_script(char *script, char *args, int *fds, int *opid)
ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script); ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
fds[0] = toast[0]; fds[0] = toast[0];
fds[1] = fromast[1]; fds[1] = fromast[1];
if (efd) {
*efd = audio[1];
}
/* close what we're not using in the parent */ /* close what we're not using in the parent */
close(toast[1]); close(toast[1]);
close(fromast[0]); close(fromast[0]);
@ -146,7 +169,7 @@ static int launch_script(char *script, char *args, int *fds, int *opid)
} }
static void setup_env(struct ast_channel *chan, char *request, int fd) static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
{ {
/* Print initial environment, with agi_request always being the first /* Print initial environment, with agi_request always being the first
thing */ thing */
@ -164,12 +187,13 @@ static void setup_env(struct ast_channel *chan, char *request, int fd)
fdprintf(fd, "agi_context: %s\n", chan->context); fdprintf(fd, "agi_context: %s\n", chan->context);
fdprintf(fd, "agi_extension: %s\n", chan->exten); fdprintf(fd, "agi_extension: %s\n", chan->exten);
fdprintf(fd, "agi_priority: %d\n", chan->priority); fdprintf(fd, "agi_priority: %d\n", chan->priority);
fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
/* End with empty return */ /* End with empty return */
fdprintf(fd, "\n"); fdprintf(fd, "\n");
} }
static int handle_answer(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
res = 0; res = 0;
@ -177,14 +201,14 @@ static int handle_answer(struct ast_channel *chan, int fd, int argc, char *argv[
/* Answer the chan */ /* Answer the chan */
res = ast_answer(chan); res = ast_answer(chan);
} }
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_waitfordigit(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
int to; int to;
@ -192,15 +216,15 @@ static int handle_waitfordigit(struct ast_channel *chan, int fd, int argc, char
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
if (sscanf(argv[3], "%i", &to) != 1) if (sscanf(argv[3], "%i", &to) != 1)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_waitfordigit(chan, to); res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_sendtext(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
if (argc != 3) if (argc != 3)
@ -213,34 +237,34 @@ static int handle_sendtext(struct ast_channel *chan, int fd, int argc, char *arg
parsing, then here, add a newline at the end of the string parsing, then here, add a newline at the end of the string
before sending it to ast_sendtext --DUDE */ before sending it to ast_sendtext --DUDE */
res = ast_sendtext(chan, argv[2]); res = ast_sendtext(chan, argv[2]);
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_recvchar(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
if (argc != 3) if (argc != 3)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_recvchar(chan,atoi(argv[2])); res = ast_recvchar(chan,atoi(argv[2]));
if (res == 0) { if (res == 0) {
fdprintf(fd, "200 result=%d (timeout)\n", res); fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
if (res > 0) { if (res > 0) {
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
else { else {
fdprintf(fd, "200 result=%d (hangup)\n", res); fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
return RESULT_FAILURE; return RESULT_FAILURE;
} }
} }
static int handle_tddmode(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res,x; int res,x;
if (argc != 3) if (argc != 3)
@ -249,14 +273,14 @@ static int handle_tddmode(struct ast_channel *chan, int fd, int argc, char *argv
if (!strncasecmp(argv[2],"mate",4)) x = 2; if (!strncasecmp(argv[2],"mate",4)) x = 2;
if (!strncasecmp(argv[2],"tdd",3)) x = 1; if (!strncasecmp(argv[2],"tdd",3)) x = 1;
res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0); res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_sendimage(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
if (argc != 3) if (argc != 3)
@ -264,14 +288,14 @@ static int handle_sendimage(struct ast_channel *chan, int fd, int argc, char *ar
res = ast_send_image(chan, argv[2]); res = ast_send_image(chan, argv[2]);
if (!ast_check_hangup(chan)) if (!ast_check_hangup(chan))
res = 0; res = 0;
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_streamfile(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
struct ast_filestream *fs; struct ast_filestream *fs;
@ -287,7 +311,7 @@ static int handle_streamfile(struct ast_channel *chan, int fd, int argc, char *a
fs = ast_openstream(chan, argv[2], chan->language); fs = ast_openstream(chan, argv[2], chan->language);
if(!fs){ if(!fs){
fdprintf(fd, "200 result=%d endpos=%ld\n", 0, sample_offset); fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]); ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
return RESULT_FAILURE; return RESULT_FAILURE;
} }
@ -297,25 +321,29 @@ static int handle_streamfile(struct ast_channel *chan, int fd, int argc, char *a
res = ast_applystream(chan, fs); res = ast_applystream(chan, fs);
res = ast_playstream(fs); res = ast_playstream(fs);
if (res) { if (res) {
fdprintf(fd, "200 result=%d endpos=%ld\n", res, sample_offset); fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
if (res >= 0) if (res >= 0)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
res = ast_waitstream(chan, argv[3]); res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
/* this is to check for if ast_waitstream closed the stream, we probably are at /* this is to check for if ast_waitstream closed the stream, we probably are at
* the end of the stream, return that amount, else check for the amount */ * the end of the stream, return that amount, else check for the amount */
sample_offset = (chan->stream)?ast_tellstream(fs):max_length; sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
ast_stopstream(chan); ast_stopstream(chan);
fdprintf(fd, "200 result=%d endpos=%ld\n", res, sample_offset); if (res == 1) {
/* Stop this command, don't print a result line, as there is a new command */
return RESULT_SUCCESS;
}
fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_saynumber(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
int num; int num;
@ -323,15 +351,17 @@ static int handle_saynumber(struct ast_channel *chan, int fd, int argc, char *ar
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
if (sscanf(argv[2], "%i", &num) != 1) if (sscanf(argv[2], "%i", &num) != 1)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_say_number(chan, num, argv[3], chan->language); res = ast_say_number_full(chan, num, argv[3], chan->language, agi->audio, agi->ctrl);
fdprintf(fd, "200 result=%d\n", res); if (res == 1)
return RESULT_SUCCESS;
fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_saydigits(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int res; int res;
int num; int num;
@ -339,17 +369,17 @@ static int handle_saydigits(struct ast_channel *chan, int fd, int argc, char *ar
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
if (sscanf(argv[2], "%i", &num) != 1) if (sscanf(argv[2], "%i", &num) != 1)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_say_digit_str(chan, argv[2], argv[3], chan->language); res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
fdprintf(fd, "200 result=%d\n", res); if (res == 1) /* New command */
return RESULT_SUCCESS;
fdprintf(agi->fd, "200 result=%d\n", res);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout); static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_getdata(struct ast_channel *chan, int fd, int argc, char *argv[])
{ {
int res; int res;
char data[1024]; char data[1024];
@ -360,37 +390,39 @@ static int handle_getdata(struct ast_channel *chan, int fd, int argc, char *argv
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
if (argc >= 4) timeout = atoi(argv[3]); else timeout = 0; if (argc >= 4) timeout = atoi(argv[3]); else timeout = 0;
if (argc >= 5) max = atoi(argv[4]); else max = 1024; if (argc >= 5) max = atoi(argv[4]); else max = 1024;
res = ast_app_getdata(chan, argv[2], data, max, timeout); res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
if (res == 1) if (res == 2) /* New command */
fdprintf(fd, "200 result=%s (timeout)\n", data); return RESULT_SUCCESS;
else if (res == 1)
fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
else else
fdprintf(fd, "200 result=%s\n", data); fdprintf(agi->fd, "200 result=%s\n", data);
if (res >= 0) if (res >= 0)
return RESULT_SUCCESS; return RESULT_SUCCESS;
else else
return RESULT_FAILURE; return RESULT_FAILURE;
} }
static int handle_setcontext(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
if (argc != 3) if (argc != 3)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
strncpy(chan->context, argv[2], sizeof(chan->context)-1); strncpy(chan->context, argv[2], sizeof(chan->context)-1);
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_setextension(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
if (argc != 3) if (argc != 3)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
strncpy(chan->exten, argv[2], sizeof(chan->exten)-1); strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_setpriority(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int pri; int pri;
if (argc != 3) if (argc != 3)
@ -398,20 +430,11 @@ static int handle_setpriority(struct ast_channel *chan, int fd, int argc, char *
if (sscanf(argv[2], "%i", &pri) != 1) if (sscanf(argv[2], "%i", &pri) != 1)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
chan->priority = pri - 1; chan->priority = pri - 1;
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int ms_diff(struct timeval *tv1, struct timeval *tv2) static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{
int ms;
ms = (tv1->tv_sec - tv2->tv_sec) * 1000;
ms += (tv1->tv_usec - tv2->tv_usec) / 1000;
return(ms);
}
static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *argv[])
{ {
struct ast_filestream *fs; struct ast_filestream *fs;
struct ast_frame *f; struct ast_frame *f;
@ -420,6 +443,8 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a
int res = 0; int res = 0;
int ms; int ms;
/* XXX EAGI FIXME XXX */
if (argc < 6) if (argc < 6)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
if (sscanf(argv[5], "%i", &ms) != 1) if (sscanf(argv[5], "%i", &ms) != 1)
@ -438,7 +463,7 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a
fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY, 0, 0644); fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY, 0, 0644);
if (!fs) { if (!fs) {
res = -1; res = -1;
fdprintf(fd, "200 result=%d (writefile)\n", res); fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
return RESULT_FAILURE; return RESULT_FAILURE;
} }
@ -454,12 +479,12 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a
res = ast_waitfor(chan, -1); res = ast_waitfor(chan, -1);
if (res < 0) { if (res < 0) {
ast_closestream(fs); ast_closestream(fs);
fdprintf(fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
return RESULT_FAILURE; return RESULT_FAILURE;
} }
f = ast_read(chan); f = ast_read(chan);
if (!f) { if (!f) {
fdprintf(fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset); fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset);
ast_closestream(fs); ast_closestream(fs);
return RESULT_FAILURE; return RESULT_FAILURE;
} }
@ -468,7 +493,7 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a
if (strchr(argv[4], f->subclass)) { if (strchr(argv[4], f->subclass)) {
/* This is an interrupting chracter */ /* This is an interrupting chracter */
sample_offset = ast_tellstream(fs); sample_offset = ast_tellstream(fs);
fdprintf(fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset); fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
ast_closestream(fs); ast_closestream(fs);
ast_frfree(f); ast_frfree(f);
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -485,14 +510,14 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a
ast_frfree(f); ast_frfree(f);
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
} }
fdprintf(fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
ast_closestream(fs); ast_closestream(fs);
} else } else
fdprintf(fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_autohangup(struct ast_channel *chan, int fd, int argc, char *argv[]) static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
{ {
int timeout; int timeout;
@ -506,17 +531,17 @@ static int handle_autohangup(struct ast_channel *chan, int fd, int argc, char *a
chan->whentohangup = time(NULL) + timeout; chan->whentohangup = time(NULL) + timeout;
else else
chan->whentohangup = 0; chan->whentohangup = 0;
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_hangup(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
struct ast_channel *c; struct ast_channel *c;
if (argc==1) { if (argc==1) {
/* no argument: hangup the current channel */ /* no argument: hangup the current channel */
ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} else if (argc==2) { } else if (argc==2) {
/* one argument: look for info on the specified channel */ /* one argument: look for info on the specified channel */
@ -525,20 +550,20 @@ static int handle_hangup(struct ast_channel *chan, int fd, int argc, char **argv
if (strcasecmp(argv[1],c->name)==0) { if (strcasecmp(argv[1],c->name)==0) {
/* we have a matching channel */ /* we have a matching channel */
ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT); ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
c = ast_channel_walk(c); c = ast_channel_walk(c);
} }
/* if we get this far no channel name matched the argument given */ /* if we get this far no channel name matched the argument given */
fdprintf(fd, "200 result=-1\n"); fdprintf(agi->fd, "200 result=-1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} else { } else {
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
} }
} }
static int handle_exec(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int res; int res;
struct ast_app *app; struct ast_app *app;
@ -557,68 +582,68 @@ static int handle_exec(struct ast_channel *chan, int fd, int argc, char **argv)
ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]); ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
res = -2; res = -2;
} }
fdprintf(fd, "200 result=%d\n", res); fdprintf(agi->fd, "200 result=%d\n", res);
return res; return res;
} }
static int handle_setcallerid(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
if (argv[2]) if (argv[2])
ast_set_callerid(chan, argv[2], 0); ast_set_callerid(chan, argv[2], 0);
/* strncpy(chan->callerid, argv[2], sizeof(chan->callerid)-1); /* strncpy(chan->callerid, argv[2], sizeof(chan->callerid)-1);
*/ fdprintf(fd, "200 result=1\n"); */ fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_channelstatus(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
struct ast_channel *c; struct ast_channel *c;
if (argc==2) { if (argc==2) {
/* no argument: supply info on the current channel */ /* no argument: supply info on the current channel */
fdprintf(fd, "200 result=%d\n", chan->_state); fdprintf(agi->fd, "200 result=%d\n", chan->_state);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} else if (argc==3) { } else if (argc==3) {
/* one argument: look for info on the specified channel */ /* one argument: look for info on the specified channel */
c = ast_channel_walk(NULL); c = ast_channel_walk(NULL);
while (c) { while (c) {
if (strcasecmp(argv[2],c->name)==0) { if (strcasecmp(argv[2],c->name)==0) {
fdprintf(fd, "200 result=%d\n", c->_state); fdprintf(agi->fd, "200 result=%d\n", c->_state);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
c = ast_channel_walk(c); c = ast_channel_walk(c);
} }
/* if we get this far no channel name matched the argument given */ /* if we get this far no channel name matched the argument given */
fdprintf(fd, "200 result=-1\n"); fdprintf(agi->fd, "200 result=-1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} else { } else {
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
} }
} }
static int handle_setvariable(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
if (argv[3]) if (argv[3])
pbx_builtin_setvar_helper(chan, argv[2], argv[3]); pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_getvariable(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
char *tempstr; char *tempstr;
if ((tempstr = pbx_builtin_getvar_helper(chan, argv[2])) ) if ((tempstr = pbx_builtin_getvar_helper(chan, argv[2])) )
fdprintf(fd, "200 result=1 (%s)\n", tempstr); fdprintf(agi->fd, "200 result=1 (%s)\n", tempstr);
else else
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_verbose(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int level = 0; int level = 0;
char *prefix; char *prefix;
@ -648,12 +673,12 @@ static int handle_verbose(struct ast_channel *chan, int fd, int argc, char **arg
if (level <= option_verbose) if (level <= option_verbose)
ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]); ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_dbget(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int res; int res;
char tmp[256]; char tmp[256];
@ -661,42 +686,42 @@ static int handle_dbget(struct ast_channel *chan, int fd, int argc, char **argv)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp)); res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
if (res) if (res)
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
else else
fdprintf(fd, "200 result=1 (%s)\n", tmp); fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_dbput(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int res; int res;
if (argc != 5) if (argc != 5)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_db_put(argv[2], argv[3], argv[4]); res = ast_db_put(argv[2], argv[3], argv[4]);
if (res) if (res)
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
else else
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_dbdel(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int res; int res;
if (argc != 4) if (argc != 4)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
res = ast_db_del(argv[2], argv[3]); res = ast_db_del(argv[2], argv[3]);
if (res) if (res)
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
else else
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_dbdeltree(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
{ {
int res; int res;
if ((argc < 3) || (argc > 4)) if ((argc < 3) || (argc > 4))
@ -707,9 +732,15 @@ static int handle_dbdeltree(struct ast_channel *chan, int fd, int argc, char **a
res = ast_db_deltree(argv[2], NULL); res = ast_db_deltree(argv[2], NULL);
if (res) if (res)
fdprintf(fd, "200 result=0\n"); fdprintf(agi->fd, "200 result=0\n");
else else
fdprintf(fd, "200 result=1\n"); fdprintf(agi->fd, "200 result=1\n");
return RESULT_SUCCESS;
}
static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
{
fdprintf(agi->fd, "200 result=0\n");
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -878,6 +909,10 @@ static char usage_autohangup[] =
"future. Of course it can be hungup before then as well. Setting to\n" "future. Of course it can be hungup before then as well. Setting to\n"
"0 will cause the autohangup feature to be disabled on this channel.\n"; "0 will cause the autohangup feature to be disabled on this channel.\n";
static char usage_noop[] =
" Usage: NOOP\n"
" Does nothing.\n";
agi_command commands[] = { agi_command commands[] = {
{ { "answer", NULL }, handle_answer, "Asserts answer", usage_answer }, { { "answer", NULL }, handle_answer, "Asserts answer", usage_answer },
{ { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit }, { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
@ -904,7 +939,8 @@ agi_command commands[] = {
{ { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget }, { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
{ { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput }, { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
{ { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel }, { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
{ { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree } { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
{ { "noop", NULL }, handle_noop, "Does nothing", usage_noop }
}; };
static void join(char *s, int len, char *w[]) static void join(char *s, int len, char *w[])
@ -1040,7 +1076,7 @@ normal:
return 0; return 0;
} }
static int agi_handle_command(struct ast_channel *chan, int fd, char *buf) static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
{ {
char *argv[MAX_ARGS]; char *argv[MAX_ARGS];
int argc = 0; int argc = 0;
@ -1055,12 +1091,12 @@ static int agi_handle_command(struct ast_channel *chan, int fd, char *buf)
#endif #endif
c = find_command(argv, 0); c = find_command(argv, 0);
if (c) { if (c) {
res = c->handler(chan, fd, argc, argv); res = c->handler(chan, agi, argc, argv);
switch(res) { switch(res) {
case RESULT_SHOWUSAGE: case RESULT_SHOWUSAGE:
fdprintf(fd, "520-Invalid command syntax. Proper usage follows:\n"); fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
fdprintf(fd, c->usage); fdprintf(agi->fd, c->usage);
fdprintf(fd, "520 End of proper usage.\n"); fdprintf(agi->fd, "520 End of proper usage.\n");
break; break;
case RESULT_FAILURE: case RESULT_FAILURE:
/* They've already given the failure. We've been hung up on so handle this /* They've already given the failure. We've been hung up on so handle this
@ -1068,12 +1104,12 @@ static int agi_handle_command(struct ast_channel *chan, int fd, char *buf)
return -1; return -1;
} }
} else { } else {
fdprintf(fd, "510 Invalid or unknown command\n"); fdprintf(agi->fd, "510 Invalid or unknown command\n");
} }
return 0; return 0;
} }
static int run_agi(struct ast_channel *chan, char *request, int *fds, int pid) static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid)
{ {
struct ast_channel *c; struct ast_channel *c;
int outfd; int outfd;
@ -1082,16 +1118,16 @@ static int run_agi(struct ast_channel *chan, char *request, int *fds, int pid)
struct ast_frame *f; struct ast_frame *f;
char buf[2048]; char buf[2048];
FILE *readf; FILE *readf;
if (!(readf = fdopen(fds[0], "r"))) { if (!(readf = fdopen(agi->ctrl, "r"))) {
ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n"); ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
kill(pid, SIGHUP); kill(pid, SIGHUP);
return -1; return -1;
} }
setlinebuf(readf); setlinebuf(readf);
setup_env(chan, request, fds[1]); setup_env(chan, request, agi->fd, (agi->audio > -1));
for (;;) { for (;;) {
ms = -1; ms = -1;
c = ast_waitfor_nandfds(&chan, 1, &fds[0], 1, NULL, &outfd, &ms); c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
if (c) { if (c) {
/* Idle the channel until we get a command */ /* Idle the channel until we get a command */
f = ast_read(c); f = ast_read(c);
@ -1100,6 +1136,11 @@ static int run_agi(struct ast_channel *chan, char *request, int *fds, int pid)
returnstatus = -1; returnstatus = -1;
break; break;
} else { } else {
/* If it's voice, write it to the audio pipe */
if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
/* Write, ignoring errors */
write(agi->audio, f->data, f->datalen);
}
ast_frfree(f); ast_frfree(f);
} }
} else if (outfd > -1) { } else if (outfd > -1) {
@ -1117,7 +1158,7 @@ static int run_agi(struct ast_channel *chan, char *request, int *fds, int pid)
if (*buf && buf[strlen(buf) - 1] == '\n') if (*buf && buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0; buf[strlen(buf) - 1] = 0;
returnstatus |= agi_handle_command(chan, fds[1], buf); returnstatus |= agi_handle_command(chan, agi, buf);
/* If the handle_command returns -1, we need to stop */ /* If the handle_command returns -1, we need to stop */
if (returnstatus < 0) { if (returnstatus < 0) {
break; break;
@ -1213,21 +1254,24 @@ static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int agi_exec(struct ast_channel *chan, void *data) static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced)
{ {
int res=0; int res=0;
struct localuser *u; struct localuser *u;
char *args,*ringy; char *args,*ringy;
char tmp[256]; char tmp[256];
int fds[2]; int fds[2];
int efd = -1;
int pid; int pid;
char *stringp=tmp; char *stringp=tmp;
AGI agi;
if (!data || !strlen(data)) { if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "AGI requires an argument (script)\n"); ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
return -1; return -1;
} }
memset(&agi, 0, sizeof(agi));
strncpy(tmp, data, sizeof(tmp)-1); strncpy(tmp, data, sizeof(tmp)-1);
strsep(&stringp, "|"); strsep(&stringp, "|");
args = strsep(&stringp, "|"); args = strsep(&stringp, "|");
@ -1249,16 +1293,44 @@ static int agi_exec(struct ast_channel *chan, void *data)
} }
} }
#endif #endif
res = launch_script(tmp, args, fds, &pid); res = launch_script(tmp, args, fds, enhanced ? &efd : NULL, &pid);
if (!res) { if (!res) {
res = run_agi(chan, tmp, fds, pid); agi.fd = fds[1];
agi.ctrl = fds[0];
agi.audio = efd;
res = run_agi(chan, tmp, &agi, pid);
close(fds[0]); close(fds[0]);
close(fds[1]); close(fds[1]);
if (efd > -1)
close(efd);
} }
LOCAL_USER_REMOVE(u); LOCAL_USER_REMOVE(u);
return res; return res;
} }
static int agi_exec(struct ast_channel *chan, void *data)
{
return agi_exec_full(chan, data, 0);
}
static int eagi_exec(struct ast_channel *chan, void *data)
{
int readformat;
int res;
readformat = chan->readformat;
if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
return -1;
}
res = agi_exec_full(chan, data, 1);
if (!res) {
if (ast_set_read_format(chan, readformat)) {
ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d\n", chan->name, readformat);
}
}
return res;
}
static char showagi_help[] = static char showagi_help[] =
"Usage: show agi [topic]\n" "Usage: show agi [topic]\n"
" When called with a topic as an argument, displays usage\n" " When called with a topic as an argument, displays usage\n"
@ -1281,6 +1353,7 @@ int unload_module(void)
STANDARD_HANGUP_LOCALUSERS; STANDARD_HANGUP_LOCALUSERS;
ast_cli_unregister(&showagi); ast_cli_unregister(&showagi);
ast_cli_unregister(&dumpagihtml); ast_cli_unregister(&dumpagihtml);
ast_unregister_application(eapp);
return ast_unregister_application(app); return ast_unregister_application(app);
} }
@ -1288,6 +1361,7 @@ int load_module(void)
{ {
ast_cli_register(&showagi); ast_cli_register(&showagi);
ast_cli_register(&dumpagihtml); ast_cli_register(&dumpagihtml);
ast_register_application(eapp, eagi_exec, synopsis, descrip);
return ast_register_application(app, agi_exec, synopsis, descrip); return ast_register_application(app, agi_exec, synopsis, descrip);
} }
@ -1308,44 +1382,3 @@ char *key()
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;
} }
#define CLIP 32635
#define BIAS 0x84
unsigned char
linear2ulaw(sample)
short sample; {
static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
int sign, exponent, mantissa;
unsigned char ulawbyte;
/* Get the sample into sign-magnitude. */
sign = (sample >> 8) & 0x80; /* set aside the sign */
if (sign != 0) sample = -sample; /* get magnitude */
if (sample > CLIP) sample = CLIP; /* clip the magnitude */
/* Convert from 16 bit linear to ulaw. */
sample = sample + BIAS;
exponent = exp_lut[(sample >> 7) & 0xFF];
mantissa = (sample >> (exponent + 3)) & 0x0F;
ulawbyte = ~(sign | (exponent << 4) | mantissa);
#ifdef ZEROTRAP
if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
#endif
return(ulawbyte);
}

@ -0,0 +1,130 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Wait for Ring Application
*
* Copyright (C) 2003, Digium
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/options.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
static char *synopsis = "Wait for Ring Application";
static char *tdesc = "Waits until first ring after time";
static char *desc = " WaitForRing(timeout)\n"
"Returns 0 after waiting at least timeout seconds. and\n"
"only after the next ring has completed. Returns 0 on\n"
"success or -1 on hangup\n";
static char *app = "WaitForRing";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int waitforring_exec(struct ast_channel *chan, void *data)
{
struct localuser *u;
struct ast_frame *f;
int res = 0;
int ms;
if (!data || (sscanf(data, "%d", &ms) != 1)) {
ast_log(LOG_WARNING, "SoftHangup requires an argument (minimum seconds)\n");
return 0;
}
ms *= 1000;
LOCAL_USER_ADD(u);
while(ms > 0) {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
res = ms;
break;
}
if (ms > 0) {
f = ast_read(chan);
if (!f) {
res = -1;
break;
}
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Got a ring but still waiting for timeout\n");
}
ast_frfree(f);
}
}
/* Now we're really ready for the ring */
if (!res) {
ms = 99999999;
while(ms > 0) {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
res = ms;
break;
}
if (ms > 0) {
f = ast_read(chan);
if (!f) {
res = -1;
break;
}
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Got a ring after the timeout\n");
ast_frfree(f);
break;
}
ast_frfree(f);
}
}
}
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, waitforring_exec, synopsis, desc);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

@ -869,6 +869,7 @@ int ast_waitfor(struct ast_channel *c, int ms)
char ast_waitfordigit(struct ast_channel *c, int ms) char ast_waitfordigit(struct ast_channel *c, int ms)
{ {
/* XXX Should I be merged with waitfordigit_full XXX */
struct ast_frame *f; struct ast_frame *f;
char result = 0; char result = 0;
/* Stop if we're a zombie or need a soft hangup */ /* Stop if we're a zombie or need a soft hangup */
@ -893,6 +894,36 @@ char ast_waitfordigit(struct ast_channel *c, int ms)
return result; return result;
} }
char ast_waitfordigit_full(struct ast_channel *c, int ms, int audio, int ctrl)
{
struct ast_frame *f;
char result = 0;
struct ast_channel *rchan;
int outfd;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c))
return -1;
/* Wait for a digit, no more than ms milliseconds total. */
while(ms && !result) {
rchan = ast_waitfor_nandfds(&c, 1, &audio, (audio > -1) ? 1 : 0, NULL, &outfd, &ms);
if ((!rchan) && (outfd < 0) && (ms)) /* Error */
result = -1;
else if (outfd > -1) {
result = 1;
} else if (rchan) {
/* Read something */
f = ast_read(c);
if (f) {
if (f->frametype == AST_FRAME_DTMF)
result = f->subclass;
ast_frfree(f);
} else
result = -1;
}
}
return result;
}
struct ast_frame *ast_read(struct ast_channel *chan) struct ast_frame *ast_read(struct ast_channel *chan)
{ {
struct ast_frame *f = NULL; struct ast_frame *f = NULL;
@ -1383,6 +1414,7 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
int pos=0; int pos=0;
int to = ftimeout; int to = ftimeout;
char d; char d;
/* XXX Merge with full version? XXX */
/* Stop if we're a zombie or need a soft hangup */ /* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c)) if (c->zombie || ast_check_hangup(c))
return -1; return -1;
@ -1416,6 +1448,48 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
return 0; return 0;
} }
int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders, int audiofd, int ctrlfd)
{
int pos=0;
int to = ftimeout;
char d;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c))
return -1;
if (!len)
return -1;
do {
if (c->streamid > -1) {
d = ast_waitstream_full(c, AST_DIGIT_ANY, audiofd, ctrlfd);
ast_stopstream(c);
usleep(1000);
if (!d)
d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
} else {
d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
}
if (d < 0)
return -1;
if (d == 0) {
s[pos]='\0';
return 1;
}
if (d == 1) {
s[pos]='\0';
return 2;
}
if (!strchr(enders, d))
s[pos++] = d;
if (strchr(enders, d) || (pos >= len)) {
s[pos]='\0';
return 0;
}
to = timeout;
} while(1);
/* Never reached */
return 0;
}
int ast_channel_supports_html(struct ast_channel *chan) int ast_channel_supports_html(struct ast_channel *chan)
{ {
if (chan->pvt->send_html) if (chan->pvt->send_html)

@ -698,13 +698,38 @@ static int sip_hangup(struct ast_channel *ast)
static int sip_answer(struct ast_channel *ast) static int sip_answer(struct ast_channel *ast)
{ {
int res = 0; int res = 0,fmt,capability;
char *codec;
struct sip_pvt *p = ast->pvt->pvt; struct sip_pvt *p = ast->pvt->pvt;
struct sip_codec_pref *oldpref=NULL;
if (ast->_state != AST_STATE_UP) { if (ast->_state != AST_STATE_UP) {
codec=pbx_builtin_getvar_helper(p->owner,"SIP_CODEC");
if (codec) {
ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n",codec);
fmt=ast_getformatbyname(codec);
if (fmt) {
oldpref=prefs;
prefs=NULL;
sip_pref_append(fmt);
capability=p->capability;
p->capability=fmt;
} else ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized codec: %s\n",codec);
}
ast_setstate(ast, AST_STATE_UP); ast_setstate(ast, AST_STATE_UP);
if (option_debug) if (option_debug)
ast_log(LOG_DEBUG, "sip_answer(%s)\n", ast->name); ast_log(LOG_DEBUG, "sip_answer(%s)\n", ast->name);
res = transmit_response_with_sdp(p, "200 OK", &p->initreq); res = transmit_response_with_sdp(p, "200 OK", &p->initreq);
sip_prefs_free();
if (oldpref) {
prefs=oldpref;
p->capability=capability;
}
} }
return res; return res;
} }
@ -1676,7 +1701,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p, struct ast_rtp *
if ((codec = ast2rtp(cur->codec)) > -1) { if ((codec = ast2rtp(cur->codec)) > -1) {
snprintf(costr, sizeof(costr), " %d", codec); snprintf(costr, sizeof(costr), " %d", codec);
strcat(m, costr); strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast2rtpn(x)); snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast2rtpn(rtp2ast(codec)));
strcat(a, costr); strcat(a, costr);
} }
} }

@ -341,11 +341,12 @@ sub message_audio()
# Mailbox and folder are already verified # Mailbox and folder are already verified
if (open(AUDIO, "<$path")) { if (open(AUDIO, "<$path")) {
$size = -s $path;
$|=1; $|=1;
if ($forcedownload) { if ($forcedownload) {
print header(-type=>$formats{$format}->{'mime'}, -attachment => "msg${msgid}.$format"); print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size, -attachment => "msg${msgid}.$format");
} else { } else {
print header(-type=>$formats{$format}->{'mime'}); print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size);
} }
while(($amt = sysread(AUDIO, $data, 4096)) > 0) { while(($amt = sysread(AUDIO, $data, 4096)) > 0) {

@ -605,6 +605,7 @@ struct ast_filestream *ast_writefile(char *filename, char *type, char *comment,
char ast_waitstream(struct ast_channel *c, char *breakon) char ast_waitstream(struct ast_channel *c, char *breakon)
{ {
/* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
int res; int res;
struct ast_frame *fr; struct ast_frame *fr;
while(c->stream) { while(c->stream) {
@ -658,3 +659,67 @@ char ast_waitstream(struct ast_channel *c, char *breakon)
return (c->_softhangup ? -1 : 0); return (c->_softhangup ? -1 : 0);
} }
char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
{
int res;
int ms;
int outfd;
struct ast_frame *fr;
struct ast_channel *rchan;
while(c->stream) {
ms = ast_sched_wait(c->sched);
if (ms < 0) {
ast_closestream(c->stream);
break;
}
rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
if (!rchan && (outfd < 0) && (ms)) {
ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
return -1;
} else if (outfd > -1) {
/* The FD we were watching has something waiting */
return 1;
} else if (rchan) {
fr = ast_read(c);
if (!fr) {
#if 0
ast_log(LOG_DEBUG, "Got hung up\n");
#endif
return -1;
}
switch(fr->frametype) {
case AST_FRAME_DTMF:
res = fr->subclass;
if (strchr(breakon, res)) {
ast_frfree(fr);
return res;
}
break;
case AST_FRAME_CONTROL:
switch(fr->subclass) {
case AST_CONTROL_HANGUP:
ast_frfree(fr);
return -1;
case AST_CONTROL_RINGING:
case AST_CONTROL_ANSWER:
/* Unimportant */
break;
default:
ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
}
case AST_FRAME_VOICE:
/* Write audio if appropriate */
if (audiofd > -1)
write(audiofd, fr->data, fr->datalen);
}
/* Ignore */
ast_frfree(fr);
} else
ast_sched_runq(c->sched);
}
return (c->_softhangup ? -1 : 0);
}

@ -33,6 +33,9 @@ extern "C" {
*/ */
extern int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout); extern int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout);
/* Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions */
extern int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd);
//! Record voice (after playing prompt if specified), waiting for silence (in ms) up to a given timeout (in s) or '#' //! Record voice (after playing prompt if specified), waiting for silence (in ms) up to a given timeout (in s) or '#'
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec); int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec);

@ -465,6 +465,10 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev);
* Wait for a digit. Returns <0 on error, 0 on no entry, and the digit on success. */ * Wait for a digit. Returns <0 on error, 0 on no entry, and the digit on success. */
char ast_waitfordigit(struct ast_channel *c, int ms); char ast_waitfordigit(struct ast_channel *c, int ms);
/* Same as above with audio fd for outputing read audio and ctrlfd to monitor for
reading. Returns 1 if ctrlfd becomes available */
char ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
//! Reads multiple digits //! Reads multiple digits
/*! /*!
* \param c channel to read from * \param c channel to read from
@ -476,8 +480,10 @@ char ast_waitfordigit(struct ast_channel *c, int ms);
* Read in a digit string "s", max length "len", maximum timeout between * Read in a digit string "s", max length "len", maximum timeout between
digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
for the first digit. Returns 0 on normal return, or 1 on a timeout. In the case of for the first digit. Returns 0 on normal return, or 1 on a timeout. In the case of
a timeout, any digits that were read before the timeout will still be available in s. */ a timeout, any digits that were read before the timeout will still be available in s.
RETURNS 2 in full version when ctrlfd is available, NOT 1*/
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders); int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd);
/*! Report DTMF on channel 0 */ /*! Report DTMF on channel 0 */
#define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0) #define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0)

@ -123,6 +123,10 @@ int ast_filecopy(char *oldname, char *newname, char *fmt);
*/ */
char ast_waitstream(struct ast_channel *c, char *breakon); char ast_waitstream(struct ast_channel *c, char *breakon);
/* Same as waitstream, but with audio output to fd and monitored fd checking. Returns
1 if monfd is ready for reading */
char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int monfd);
//! Starts writing a file //! Starts writing a file
/*! /*!
* \param filename the name of the file to write to * \param filename the name of the file to write to

@ -34,6 +34,9 @@ extern "C" {
*/ */
int ast_say_number(struct ast_channel *chan, int num, char *ints, char *lang); int ast_say_number(struct ast_channel *chan, int num, char *ints, char *lang);
/* Same as above with audiofd for received audio and returns 1 on ctrlfd being readable */
int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd);
//! says digits //! says digits
/*! /*!
* \param chan channel to act upon * \param chan channel to act upon
@ -44,6 +47,7 @@ int ast_say_number(struct ast_channel *chan, int num, char *ints, char *lang);
* Returns 0 on success, dtmf if interrupted, -1 on failure * Returns 0 on success, dtmf if interrupted, -1 on failure
*/ */
int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang); int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang);
int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd);
//! says digits of a string //! says digits of a string
/*! /*!
@ -55,6 +59,7 @@ int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang);
* Returns 0 on success, dtmf if interrupted, -1 on failure * Returns 0 on success, dtmf if interrupted, -1 on failure
*/ */
int ast_say_digit_str(struct ast_channel *chan, char *num, char *ints, char *lang); int ast_say_digit_str(struct ast_channel *chan, char *num, char *ints, char *lang);
int ast_say_digit_str_full(struct ast_channel *chan, char *num, char *ints, char *lang, int audiofd, int ctrlfd);
int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang); int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang);

123
pbx.c

@ -727,88 +727,99 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char *
*cp4 = pri; *cp4 = pri;
} else { } else {
AST_LIST_TRAVERSE(headp,variables,entries) { AST_LIST_TRAVERSE(headp,variables,entries) {
// ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables)); #if 0
if (strncasecmp(ast_var_name(variables),cp3,strlen(cp3))==0) ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
#endif
if (strcasecmp(ast_var_name(variables),cp3)==0)
*cp4=ast_var_value(variables); *cp4=ast_var_value(variables);
} }
if (!(*cp4)) { if (!(*cp4)) {
/* Try globals */ /* Try globals */
AST_LIST_TRAVERSE(&globals,variables,entries) { AST_LIST_TRAVERSE(&globals,variables,entries) {
// ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables)); #if 0
if (strncasecmp(ast_var_name(variables),cp3,strlen(cp3))==0) ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
#endif
if (strcasecmp(ast_var_name(variables),cp3)==0)
*cp4=ast_var_value(variables); *cp4=ast_var_value(variables);
} }
} }
} }
} }
static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char **ecp2) static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char **ecp2,int count)
{ {
char *cp4,*cp2; char *cp4,*cp2;
char *tmp,*wherearewe,*finish; char *tmp,*wherearewe,*finish,*ltmp,*lval,*nextvar;
int length; int length,variables=0;
wherearewe=tmp=cp1; wherearewe=tmp=cp1;
cp2=*ecp2; cp2=*ecp2;
*cp2='\0'; *cp2='\0';
do { do {
char *start,*start2;
if (!(*wherearewe)) break; if (!(*wherearewe)) break;
if ((tmp=strstr(wherearewe,"${"))) { if ((tmp=strstr(wherearewe,"${"))) {
variables++;
length=(int)(tmp-wherearewe); length=(int)(tmp-wherearewe);
strncat(cp2,wherearewe,length); strncat(cp2,wherearewe,length);
wherearewe=tmp; wherearewe=tmp;
if (!strncmp(tmp+2,"${",2)) {
char *ltmp,*lval; ltmp=malloc(sizeof(char)*256);
ltmp=malloc(sizeof(char)*256); start=start2=tmp+1;
finish=strchr(tmp+2,'}'); do {
/* get the one before the last closing bracket */ if (variables==0) {
do { nextvar=strstr(start2,"${");
if (strlen(finish)<2) if (nextvar) {
break; if ((int)(finish-nextvar)>0) {
if (finish[1]=='}' && finish[2]=='}') variables++;
finish++; start2=nextvar+1;
else break; } else break;
} while (1); } else break;
if (!finish) {
ast_log(LOG_WARNING, "Something went wrong with ${VARIABLE}\n");
*ecp2="";
break;
}
length=(int)(finish-tmp-1);
wherearewe+=length+3;
lval=strndup(tmp+2,length);
pbx_substitute_variables_helper(c,lval,&ltmp);
free(lval);
pbx_substitute_variables_temp(c,ltmp,&cp4);
if (cp4) {
length=strlen(cp4);
strncat(cp2,cp4,length);
}
} else {
char value[256];
finish=strchr(tmp+2,'}');
if (!finish) {
ast_log(LOG_WARNING, "Something went wrong with ${VARIABLE}\n");
*ecp2="";
break;
} }
length=(int)(finish-tmp)-2; finish=strchr(start,'}');
wherearewe+=length+3; if (finish) {
strncpy(value,tmp+2,length); variables--;
value[length]='\0'; start=finish+1;
pbx_substitute_variables_temp(c,value,&cp4); } else {
if (cp4) { if (variables>0) {
length=strlen(cp4); ast_log(LOG_NOTICE, "Error in extension logic\n");
strncat(cp2,cp4,length); cp2[0]='\0';
return;
}
break;
} }
} while (1);
length=(int)(finish-tmp);
wherearewe+=length+1;
lval=strndup(tmp+2,length-2);
pbx_substitute_variables_helper(c,lval,&ltmp,count+1);
free(lval);
if (ltmp) {
length=strlen(ltmp);
strncat(cp2,ltmp,length);
} }
} else { } else {
if (*wherearewe) { if (wherearewe!=cp1) {
length=strlen(wherearewe); if (*wherearewe) {
strncat(cp2,wherearewe,length); length=strlen(wherearewe);
strncat(cp2,wherearewe,length);
}
strcat(cp2,"\0");
cp1=cp2;
}
pbx_substitute_variables_temp(c,cp1,&cp4);
if (cp4) {
/* reset output variable so we could store the result */
*cp2='\0';
length=strlen(cp4);
strncat(cp2,cp4,length);
} else {
if (count) cp2[0]='\0';
} }
strcat(cp2,"\0");
break; break;
} }
} while(1); } while(1);
@ -827,7 +838,7 @@ static void *pbx_substitute_variables(struct ast_channel *c, struct ast_exten *e
cp1=e->data; cp1=e->data;
cp2=malloc(sizeof(char)*256); cp2=malloc(sizeof(char)*256);
pbx_substitute_variables_helper(c,cp1,(char **)&cp2); pbx_substitute_variables_helper(c,cp1,(char **)&cp2,0);
/* Second stage, expression evaluation */ /* Second stage, expression evaluation */
if ((strstr(cp2,"$[")==NULL)) { if ((strstr(cp2,"$[")==NULL)) {
@ -3527,7 +3538,7 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value
headp=&globals; headp=&globals;
AST_LIST_TRAVERSE (headp,newvariable,entries) { AST_LIST_TRAVERSE (headp,newvariable,entries) {
if (strncasecmp(ast_var_name(newvariable),name,strlen(name))==0) { if (strcasecmp(ast_var_name(newvariable),name)==0) {
/* there is already such a variable, delete it */ /* there is already such a variable, delete it */
AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries); AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries);
ast_var_delete(newvariable); ast_var_delete(newvariable);

90
say.c

@ -19,6 +19,7 @@
int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang) int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
{ {
/* XXX Merge with full version? XXX */
char fn[256] = ""; char fn[256] = "";
int num = 0; int num = 0;
int res = 0; int res = 0;
@ -33,14 +34,102 @@ int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lan
return res; return res;
} }
int ast_say_digit_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
{
char fn[256] = "";
int num = 0;
int res = 0;
while(fn2[num] && !res) {
snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
res = ast_streamfile(chan, fn, lang);
if (!res)
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
ast_stopstream(chan);
num++;
}
return res;
}
int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang) int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang)
{ {
/* XXX Should I be merged with say_digits_full XXX */
char fn2[256]; char fn2[256];
snprintf(fn2, sizeof(fn2), "%d", num); snprintf(fn2, sizeof(fn2), "%d", num);
return ast_say_digit_str(chan, fn2, ints, lang); return ast_say_digit_str(chan, fn2, ints, lang);
} }
int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd)
{
char fn2[256];
snprintf(fn2, sizeof(fn2), "%d", num);
return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
}
int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
{
int res = 0;
int playh = 0;
char fn[256] = "";
if (!num)
return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
if (0) {
/* XXX Only works for english XXX */
} else {
/* Use english numbers */
language = "en";
while(!res && (num || playh)) {
if (playh) {
snprintf(fn, sizeof(fn), "digits/hundred");
playh = 0;
} else
if (num < 20) {
snprintf(fn, sizeof(fn), "digits/%d", num);
num = 0;
} else
if (num < 100) {
snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
num -= ((num / 10) * 10);
} else {
if (num < 1000){
snprintf(fn, sizeof(fn), "digits/%d", (num/100));
playh++;
num -= ((num / 100) * 100);
} else {
if (num < 1000000) {
res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
if (res)
return res;
num = num % 1000;
snprintf(fn, sizeof(fn), "digits/thousand");
} else {
if (num < 1000000000) {
res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
if (res)
return res;
num = num % 1000000;
snprintf(fn, sizeof(fn), "digits/million");
} else {
ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
res = -1;
}
}
}
}
if (!res) {
res = ast_streamfile(chan, fn, language);
if (!res)
res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
ast_stopstream(chan);
}
}
}
return res;
}
int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language) int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language)
{ {
/* XXX Should I be merged with ast_say_number_full XXX */
int res = 0; int res = 0;
int playh = 0; int playh = 0;
char fn[256] = ""; char fn[256] = "";
@ -100,7 +189,6 @@ int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language
} }
return res; return res;
} }
int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang) int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
{ {
struct tm *tm; struct tm *tm;

@ -341,11 +341,12 @@ sub message_audio()
# Mailbox and folder are already verified # Mailbox and folder are already verified
if (open(AUDIO, "<$path")) { if (open(AUDIO, "<$path")) {
$size = -s $path;
$|=1; $|=1;
if ($forcedownload) { if ($forcedownload) {
print header(-type=>$formats{$format}->{'mime'}, -attachment => "msg${msgid}.$format"); print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size, -attachment => "msg${msgid}.$format");
} else { } else {
print header(-type=>$formats{$format}->{'mime'}); print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size);
} }
while(($amt = sysread(AUDIO, $data, 4096)) > 0) { while(($amt = sysread(AUDIO, $data, 4096)) > 0) {

Loading…
Cancel
Save