diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-01-19 00:19:29 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-01-19 00:19:29 +0000 |
commit | f8247040e6231c4b3b5099ea3a526348b7941566 (patch) | |
tree | 0cc92ad6ebf6ae49a62f6e7ef8ec819121d63630 /trunk/agi | |
parent | d88e56c61ce2042544c1a8a71c93b69ab2e6ffba (diff) |
Creating tag for the release of asterisk-1.6.0-beta1v1.6.0-beta1
git-svn-id: http://svn.digium.com/svn/asterisk/tags/1.6.0-beta1@99163 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'trunk/agi')
-rw-r--r-- | trunk/agi/DialAnMp3.agi | 82 | ||||
-rw-r--r-- | trunk/agi/Makefile | 52 | ||||
-rw-r--r-- | trunk/agi/agi-test.agi | 79 | ||||
-rw-r--r-- | trunk/agi/eagi-sphinx-test.c | 231 | ||||
-rw-r--r-- | trunk/agi/eagi-test.c | 165 | ||||
-rw-r--r-- | trunk/agi/fastagi-test | 94 | ||||
-rwxr-xr-x | trunk/agi/jukebox.agi | 488 | ||||
-rw-r--r-- | trunk/agi/numeralize | 44 |
8 files changed, 1235 insertions, 0 deletions
diff --git a/trunk/agi/DialAnMp3.agi b/trunk/agi/DialAnMp3.agi new file mode 100644 index 000000000..59a54265e --- /dev/null +++ b/trunk/agi/DialAnMp3.agi @@ -0,0 +1,82 @@ +#!/usr/bin/perl +# +# Simple AGI application to play mp3's selected by a user both using +# xmms and over the phone itself. +# +$|=1; +while(<STDIN>) { + chomp; + last unless length($_); + if (/^agi_(\w+)\:\s+(.*)$/) { + $AGI{$1} = $2; + } +} + +print STDERR "AGI Environment Dump:\n"; +foreach $i (sort keys %AGI) { + print STDERR " -- $i = $AGI{$i}\n"; +} + +dbmopen(%DIGITS, "/var/lib/asterisk/mp3list", 0644) || die("Unable to open mp3list");; + +sub checkresult { + my ($res) = @_; + my $retval; + $tests++; + chomp $res; + if ($res =~ /^200/) { + $res =~ /result=(-?[\w\*\#]+)/; + return $1; + } else { + return -1; + } +} + +#print STDERR "1. Playing beep...\n"; +#print "STREAM FILE beep \"\"\n"; +#$result = <STDIN>; +#checkresult($result); + +print STDERR "2. Getting song name...\n"; +print "GET DATA demo-enterkeywords\n"; +$result = <STDIN>; +$digitstr = checkresult($result); +if ($digitstr < 0) { + exit(1); +} +$digitstr =~ s/\*/ /g; + +print STDERR "Resulting songname is $digitstr\n"; +@searchwords = split (/\s+/, $digitstr); +print STDERR "Searchwords: " . join(':', @searchwords) . "\n"; + +foreach $key (sort keys %DIGITS) { + @words = split(/\s+/, $DIGITS{$key}); + $match = 1; + foreach $search (@searchwords) { + $match = 0 unless grep(/$search/, @words); + } + if ($match > 0) { + print STDERR "File $key matches\n"; + # Play a beep + print "STREAM FILE beep \"\"\n"; + system("xmms", $key); + $result = <STDIN>; + if (&checkresult($result) < 0) { + exit 0; + } + print "EXEC MP3Player \"$key\"\n"; +# print "WAIT FOR DIGIT 60000\n"; + $result = <STDIN>; + if (&checkresult($result) < 0) { + exit 0; + } + print STDERR "Got here...\n"; + } +} + +print STDERR "4. Testing 'saynumber' of $digitstr...\n"; +print "STREAM FILE demo-nomatch\"\"\n"; +$result = <STDIN>; +checkresult($result); + diff --git a/trunk/agi/Makefile b/trunk/agi/Makefile new file mode 100644 index 000000000..0cb6f3f02 --- /dev/null +++ b/trunk/agi/Makefile @@ -0,0 +1,52 @@ +# +# Asterisk -- A telephony toolkit for Linux. +# +# Makefile for AGI-related stuff +# +# Copyright (C) 1999-2006, Digium +# +# Mark Spencer <markster@digium.com> +# +# This program is free software, distributed under the terms of +# the GNU General Public License +# + +.PHONY: clean all uninstall + +AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi + +ifeq ($(OSARCH),SunOS) + LIBS+=-lsocket -lnsl +endif + +ifeq ($(OSARCH),mingw32) + AGIS:= +endif + +include $(ASTTOPDIR)/Makefile.rules + +all: $(AGIS) + +strcompat.c: ../main/strcompat.c + @cp $< $@ + +eagi-test: eagi-test.o strcompat.o + +eagi-sphinx-test: eagi-sphinx-test.o + +install: all + mkdir -p $(DESTDIR)$(AGI_DIR) + for x in $(AGIS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(AGI_DIR) ; done + +uninstall: + for x in $(AGIS); do rm -f $(DESTDIR)$(AGI_DIR)/$$x ; done + +clean: + rm -f *.so *.o look eagi-test eagi-sphinx-test + rm -f .*.o.d .*.oo.d + rm -f *.s *.i + rm -f strcompat.c + +ifneq ($(wildcard .*.d),) + include .*.d +endif diff --git a/trunk/agi/agi-test.agi b/trunk/agi/agi-test.agi new file mode 100644 index 000000000..4fc36eda8 --- /dev/null +++ b/trunk/agi/agi-test.agi @@ -0,0 +1,79 @@ +#!/usr/bin/perl +use strict; + +$|=1; + +# Setup some variables +my %AGI; my $tests = 0; my $fail = 0; my $pass = 0; + +while(<STDIN>) { + chomp; + last unless length($_); + if (/^agi_(\w+)\:\s+(.*)$/) { + $AGI{$1} = $2; + } +} + +print STDERR "AGI Environment Dump:\n"; +foreach my $i (sort keys %AGI) { + print STDERR " -- $i = $AGI{$i}\n"; +} + +sub checkresult { + my ($res) = @_; + my $retval; + $tests++; + chomp $res; + if ($res =~ /^200/) { + $res =~ /result=(-?\d+)/; + if (!length($1)) { + print STDERR "FAIL ($res)\n"; + $fail++; + } else { + print STDERR "PASS ($1)\n"; + $pass++; + } + } else { + print STDERR "FAIL (unexpected result '$res')\n"; + $fail++; + } +} + +print STDERR "1. Testing 'sendfile'..."; +print "STREAM FILE beep \"\"\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "2. Testing 'sendtext'..."; +print "SEND TEXT \"hello world\"\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "3. Testing 'sendimage'..."; +print "SEND IMAGE asterisk-image\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "4. Testing 'saynumber'..."; +print "SAY NUMBER 192837465 \"\"\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "5. Testing 'waitdtmf'..."; +print "WAIT FOR DIGIT 1000\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "6. Testing 'record'..."; +print "RECORD FILE testagi gsm 1234 3000\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "6a. Testing 'record' playback..."; +print "STREAM FILE testagi \"\"\n"; +my $result = <STDIN>; +&checkresult($result); + +print STDERR "================== Complete ======================\n"; +print STDERR "$tests tests completed, $pass passed, $fail failed\n"; +print STDERR "==================================================\n"; diff --git a/trunk/agi/eagi-sphinx-test.c b/trunk/agi/eagi-sphinx-test.c new file mode 100644 index 000000000..d2898763c --- /dev/null +++ b/trunk/agi/eagi-sphinx-test.c @@ -0,0 +1,231 @@ +/* + * Extended AGI test application + * + * This code is released into public domain + * without any warranty of any kind. + * + */ + +/*! \file + * Extended AGI test application + * + * This code is released into public domain + * without any warranty of any kind. + * + * \ingroup agi + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/select.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include "asterisk.h" + +#include "asterisk/compat.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, (struct sockaddr *)&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); +} diff --git a/trunk/agi/eagi-test.c b/trunk/agi/eagi-test.c new file mode 100644 index 000000000..704fd7b22 --- /dev/null +++ b/trunk/agi/eagi-test.c @@ -0,0 +1,165 @@ +/* + * Extended AGI test application + * + * This code is released into the public domain + * with no warranty of any kind + */ + +#include "asterisk.h" + +#define AUDIO_FILENO (STDERR_FILENO + 1) + +/*! \file + * Extended AGI test application + * + * This code is released into the public domain + * with no warranty of any kind + * + * \ingroup agi + */ + +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); +} diff --git a/trunk/agi/fastagi-test b/trunk/agi/fastagi-test new file mode 100644 index 000000000..d3f13cf6b --- /dev/null +++ b/trunk/agi/fastagi-test @@ -0,0 +1,94 @@ +#!/usr/bin/perl +use strict; +use Socket; +use Carp; +use IO::Handle; + +my $port = 4573; + +$|=1; + +# Setup some variables +my %AGI; my $tests = 0; my $fail = 0; my $pass = 0; + +sub checkresult { + my ($res) = @_; + my $retval; + $tests++; + chomp $res; + if ($res =~ /^200/) { + $res =~ /result=(-?\d+)/; + if (!length($1)) { + print STDERR "FAIL ($res)\n"; + $fail++; + } else { + print STDERR "PASS ($1)\n"; + $pass++; + } + } else { + print STDERR "FAIL (unexpected result '$res')\n"; + $fail++; + } +} + +socket(SERVER, PF_INET, SOCK_STREAM, 0); +setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); +bind(SERVER, sockaddr_in($port, INADDR_ANY)) || die("can't bind\n"); +listen(SERVER, SOMAXCONN); + +for(;;) { + my $raddr = accept(CLIENT, SERVER); + my ($s, $p) = sockaddr_in($raddr); + CLIENT->autoflush(1); + while(<CLIENT>) { + chomp; + last unless length($_); + if (/^agi_(\w+)\:\s+(.*)$/) { + $AGI{$1} = $2; + } + } + print STDERR "AGI Environment Dump from $s:$p --\n"; + foreach my $i (sort keys %AGI) { + print STDERR " -- $i = $AGI{$i}\n"; + } + + print STDERR "1. Testing 'sendfile'..."; + print CLIENT "STREAM FILE beep \"\"\n"; + my $result = <CLIENT>; + &checkresult($result); + + print STDERR "2. Testing 'sendtext'..."; + print CLIENT "SEND TEXT \"hello world\"\n"; + my $result = <CLIENT>; + &checkresult($result); + + print STDERR "3. Testing 'sendimage'..."; + print CLIENT "SEND IMAGE asterisk-image\n"; + my $result = <CLIENT>; + &checkresult($result); + + print STDERR "4. Testing 'saynumber'..."; + print CLIENT "SAY NUMBER 192837465 \"\"\n"; + my $result = <CLIENT>; + &checkresult($result); + + print STDERR "5. Testing 'waitdtmf'..."; + print CLIENT "WAIT FOR DIGIT 1000\n"; + my $result = <CLIENT>; + &checkresult($result); + + print STDERR "6. Testing 'record'..."; + print CLIENT "RECORD FILE testagi gsm 1234 3000\n"; + my $result = <CLIENT>; + &checkresult($result); + + print STDERR "6a. Testing 'record' playback..."; + print CLIENT "STREAM FILE testagi \"\"\n"; + my $result = <CLIENT>; + &checkresult($result); + close(CLIENT); + print STDERR "================== Complete ======================\n"; + print STDERR "$tests tests completed, $pass passed, $fail failed\n"; + print STDERR "==================================================\n"; +} + diff --git a/trunk/agi/jukebox.agi b/trunk/agi/jukebox.agi new file mode 100755 index 000000000..7bd9c10f9 --- /dev/null +++ b/trunk/agi/jukebox.agi @@ -0,0 +1,488 @@ +#!/usr/bin/perl +# +# Jukebox 0.2 +# +# A music manager for Asterisk. +# +# Copyright (C) 2005-2006, Justin Tunney +# +# Justin Tunney <jesuscyborg@gmail.com> +# +# This program is free software, distributed under the terms of the +# GNU General Public License v2. +# +# Keep it open source pigs +# +# -------------------------------------------------------------------- +# +# Uses festival to list off all your MP3 music files over a channel in +# a hierarchical fashion. Put this file in your agi-bin folder which +# is located at: /var/lib/asterisk/agi-bin Be sure to chmod +x it! +# +# Invocation Example: +# exten => 68742,1,Answer() +# exten => 68742,2,agi,jukebox.agi|/home/justin/Music +# exten => 68742,3,Hangup() +# +# exten => 68742,1,Answer() +# exten => 68742,2,agi,jukebox.agi|/home/justin/Music|pm +# exten => 68742,3,Hangup() +# +# Options: +# p - Precache text2wave outputs for every possible filename. +# It is much better to set this option because if a caller +# presses a key during a cache operation, it will be ignored. +# m - Go back to menu after playing song +# g - Do not play the greeting message +# +# Usage Instructions: +# - Press '*' to go up a directory. If you are in the root music +# folder you will be exitted from the script. +# - If you have a really long list of files, you can filter the list +# at any time by pressing '#' and spelling out a few letters you +# expect the files to start with. For example, if you wanted to +# know what extension 'Requiem For A Dream' was, you'd type: +# '#737'. Note, phone keypads don't include Q and Z. Q is 7 and +# Z is 9. +# +# Notes: +# - This AGI script uses the MP3Player command which uses the +# mpg123 Program. Grab yourself a copy of this program by +# going to http://www.mpg123.de/cgi-bin/sitexplorer.cgi?/mpg123/ +# Be sure to download mpg123-0.59r.tar.gz because it is known to +# work with Asterisk and hopefully isn't the release with that +# awful security problem. If you're using Fedora Core 3 with +# Alsa like me, make linux-alsa isn't going to work. Do make +# linux-devel and you're peachy keen. +# +# - You won't get nifty STDERR debug messages if you're using a +# remote asterisk shell. +# +# - For some reason, caching certain files will generate the +# error: 'using default diphone ax-ax for y-pau'. Example: +# # echo "Depeche Mode - CUW - 05 - The Meaning of Love" | text2wave -o /var/jukeboxcache/jukeboxcache/Depeche_Mode/Depeche_Mode_-_CUW_-_05_-_The_Meaning_of_Love.mp3.ul -otype ulaw - +# The temporary work around is to just touch these files. +# +# - The background app doesn't like to get more than 2031 chars +# of input. +# + +use strict; + +$|=1; + +# Setup some variables +my %AGI; my $tests = 0; my $fail = 0; my $pass = 0; +my @masterCacheList = (); +my $maxNumber = 10; + +while (<STDIN>) { + chomp; + last unless length($_); + if (/^agi_(\w+)\:\s+(.*)$/) { + $AGI{$1} = $2; + } +} + +# setup options +my $SHOWGREET = 1; +my $PRECACHE = 0; +my $MENUAFTERSONG = 0; + +$PRECACHE = 1 if $ARGV[1] =~ /p/; +$MENUAFTERSONG = 1 if $ARGV[1] =~ /m/; +$SHOWGREET = 0 if $ARGV[1] =~ /g/; + +# setup folders +my $MUSIC = $ARGV[0]; +$MUSIC = &rmts($MUSIC); +my $FESTIVALCACHE = "/var/jukeboxcache"; +if (! -e $FESTIVALCACHE) { + `mkdir -p -m0776 $FESTIVALCACHE`; +} + +# make sure we have some essential files +if (! -e "$FESTIVALCACHE/jukebox_greet.ul") { + `echo "Welcome to the Asterisk Jukebox" | text2wave -o $FESTIVALCACHE/jukebox_greet.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_press.ul") { + `echo "Press" | text2wave -o $FESTIVALCACHE/jukebox_press.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_for.ul") { + `echo "For" | text2wave -o $FESTIVALCACHE/jukebox_for.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_toplay.ul") { + `echo "To play" | text2wave -o $FESTIVALCACHE/jukebox_toplay.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_nonefound.ul") { + `echo "There were no music files found in this folder" | text2wave -o $FESTIVALCACHE/jukebox_nonefound.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_percent.ul") { + `echo "Percent" | text2wave -o $FESTIVALCACHE/jukebox_percent.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_generate.ul") { + `echo "Please wait while Astrisk Jukebox cashes the files of your music collection" | text2wave -o $FESTIVALCACHE/jukebox_generate.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_invalid.ul") { + `echo "You have entered an invalid selection" | text2wave -o $FESTIVALCACHE/jukebox_invalid.ul -otype ulaw -`; +} +if (! -e "$FESTIVALCACHE/jukebox_thankyou.ul") { + `echo "Thank you for using Astrisk Jukebox, Goodbye" | text2wave -o $FESTIVALCACHE/jukebox_thankyou.ul -otype ulaw -`; +} + +# greet the user +if ($SHOWGREET) { + print "EXEC Playback \"$FESTIVALCACHE/jukebox_greet\"\n"; + my $result = <STDIN>; &check_result($result); +} + +# go through the directories +music_dir_cache() if $PRECACHE; +music_dir_menu('/'); + +exit 0; + +########################################################################## + +sub music_dir_menu { + my $dir = shift; + +# generate a list of mp3's and directories and assign each one it's +# own selection number. Then make sure that we've got a sound clip +# for the file name + if (!opendir(THEDIR, rmts($MUSIC.$dir))) { + print STDERR "Failed to open music directory: $dir\n"; + exit 1; + } + my @files = sort readdir THEDIR; + my $cnt = 1; + my @masterBgList = (); + + foreach my $file (@files) { + chomp($file); + if ($file ne '.' && $file ne '..' && $file ne 'festivalcache') { # ignore special files + my $real_version = &rmts($MUSIC.$dir).'/'.$file; + my $cache_version = &rmts($FESTIVALCACHE.$dir).'/'.$file.'.ul'; + my $cache_version2 = &rmts($FESTIVALCACHE.$dir).'/'.$file; + my $cache_version_esc = &clean_file($cache_version); + my $cache_version2_esc = &clean_file($cache_version2); + + if (-d $real_version) { +# 0:id 1:type 2:text2wav-file 3:for-filtering 4:the-directory 5:text2wav echo + push(@masterBgList, [$cnt++, 1, $cache_version2_esc, &remove_special_chars($file), $file, "for the $file folder"]); + } elsif ($real_version =~ /\.mp3$/) { +# 0:id 1:type 2:text2wav-file 3:for-filtering 4:the-mp3 + push(@masterBgList, [$cnt++, 2, $cache_version2_esc, &remove_special_chars($file), $real_version, "to play $file"]); + } + } + } + close(THEDIR); + + my @filterList = @masterBgList; + + if (@filterList == 0) { + print "EXEC Playback \"$FESTIVALCACHE/jukebox_nonefound\"\n"; + my $result = <STDIN>; &check_result($result); + return 0; + } + + for (;;) { +MYCONTINUE: + +# play bg selections and figure out their selection + my $digit = ''; + my $digitstr = ''; + for (my $n=0; $n<@filterList; $n++) { + &cache_speech(&remove_file_extension($filterList[$n][5]), "$filterList[$n][2].ul") if ! -e "$filterList[$n][2].ul"; + &cache_speech("Press $filterList[$n][0]", "$FESTIVALCACHE/jukebox_$filterList[$n][0].ul") if ! -e "$FESTIVALCACHE/jukebox_$filterList[$n][0].ul"; + print "EXEC Background \"$filterList[$n][2]&$FESTIVALCACHE/jukebox_$filterList[$n][0]\"\n"; + my $result = <STDIN>; + $digit = &check_result($result); + if ($digit > 0) { + $digitstr .= chr($digit); + last; + } + } + for (;;) { + print "WAIT FOR DIGIT 3000\n"; + my $result = <STDIN>; + $digit = &check_result($result); + last if $digit <= 0; + $digitstr .= chr($digit); + } + +# see if it's a valid selection + print STDERR "Digits Entered: '$digitstr'\n"; + exit 0 if $digitstr eq ''; + my $found = 0; + goto EXITSUB if $digitstr =~ /\*/; + +# filter the list + if ($digitstr =~ /^\#\d+/) { + my $regexp = ''; + for (my $n=1; $n<length($digitstr); $n++) { + my $d = substr($digitstr, $n, 1); + if ($d == 2) { + $regexp .= '[abc]'; + } elsif ($d == 3) { + $regexp .= '[def]'; + } elsif ($d == 4) { + $regexp .= '[ghi]'; + } elsif ($d == 5) { + $regexp .= '[jkl]'; + } elsif ($d == 6) { + $regexp .= '[mno]'; + } elsif ($d == 7) { + $regexp .= '[pqrs]'; + } elsif ($d == 8) { + $regexp .= '[tuv]'; + } elsif ($d == 9) { + $regexp .= '[wxyz]'; + } + } + @filterList = (); + for (my $n=1; $n<@masterBgList; $n++) { + push(@filterList, $masterBgList[$n]) if $masterBgList[$n][3] =~ /^$regexp/i; + } + goto MYCONTINUE; + } + + for (my $n=0; $n<@masterBgList; $n++) { + if ($digitstr == $masterBgList[$n][0]) { + if ($masterBgList[$n][1] == 1) { # a folder + &music_dir_menu(rmts($dir).'/'.$masterBgList[$n][4]); + @filterList = @masterBgList; + goto MYCONTINUE; + } elsif ($masterBgList[$n][1] == 2) { # a file +# because *'s scripting language is crunk and won't allow us to escape +# funny filenames, we need to create a temporary symlink to the mp3 +# file + my $mp3 = &escape_file($masterBgList[$n][4]); + my $link = `mktemp`; + chomp($link); + $link .= '.mp3'; + print STDERR "ln -s $mp3 $link\n"; + my $cmdr = `ln -s $mp3 $link`; + chomp($cmdr); + print "Failed to create symlink to mp3: $cmdr\n" if $cmdr ne ''; + + print "EXEC MP3Player \"$link\"\n"; + my $result = <STDIN>; &check_result($result); + + `rm $link`; + + if (!$MENUAFTERSONG) { + print "EXEC Playback \"$FESTIVALCACHE/jukebox_thankyou\"\n"; + my $result = <STDIN>; &check_result($result); + exit 0; + } else { + goto MYCONTINUE; + } + } + } + } + print "EXEC Playback \"$FESTIVALCACHE/jukebox_invalid\"\n"; + my $result = <STDIN>; &check_result($result); + } + EXITSUB: +} + +sub cache_speech { + my $speech = shift; + my $file = shift; + + my $theDir = extract_file_dir($file); + `mkdir -p -m0776 $theDir`; + + print STDERR "echo \"$speech\" | text2wave -o $file -otype ulaw -\n"; + my $cmdr = `echo "$speech" | text2wave -o $file -otype ulaw -`; + chomp($cmdr); + if ($cmdr =~ /using default diphone/) { +# temporary bug work around.... + `touch $file`; + } elsif ($cmdr ne '') { + print STDERR "Command Failed\n"; + exit 1; + } +} + +sub music_dir_cache { +# generate list of text2speech files to generate + if (!music_dir_cache_genlist('/')) { + print STDERR "Horrible Dreadful Error: No Music Found in $MUSIC!"; + exit 1; + } + +# add to list how many 'number' files we have to generate. We can't +# use the SayNumber app in Asterisk because we want to chain all +# talking in one Background command. We also want a consistent +# voice... + for (my $n=1; $n<=$maxNumber; $n++) { + push(@masterCacheList, [3, "Press $n", "$FESTIVALCACHE/jukebox_$n.ul"]) if ! -e "$FESTIVALCACHE/jukebox_$n.ul"; + } + +# now generate all these darn text2speech files + if (@masterCacheList > 5) { + print "EXEC Playback \"$FESTIVALCACHE/jukebox_generate\"\n"; + my $result = <STDIN>; &check_result($result); + } + my $theTime = time(); + for (my $n=0; $n < @masterCacheList; $n++) { + my $cmdr = ''; + if ($masterCacheList[$n][0] == 1) { # directory + &cache_speech("for folder $masterCacheList[$n][1]", $masterCacheList[$n][2]); + } elsif ($masterCacheList[$n][0] == 2) { # file + &cache_speech("to play $masterCacheList[$n][1]", $masterCacheList[$n][2]); + } elsif ($masterCacheList[$n][0] == 3) { # number + &cache_speech($masterCacheList[$n][1], $masterCacheList[$n][2]); + } + if (time() >= $theTime + 30) { + my $percent = int($n / @masterCacheList * 100); + print "SAY NUMBER $percent \"\"\n"; + my $result = <STDIN>; &check_result($result); + print "EXEC Playback \"$FESTIVALCACHE/jukebox_percent\"\n"; + my $result = <STDIN>; &check_result($result); + $theTime = time(); + } + } +} + +# this function will fill the @masterCacheList of all the files that +# need to have text2speeced ulaw files of their names generated +sub music_dir_cache_genlist { + my $dir = shift; + if (!opendir(THEDIR, rmts($MUSIC.$dir))) { + print STDERR "Failed to open music directory: $dir\n"; + exit 1; + } + my @files = sort readdir THEDIR; + my $foundFiles = 0; + my $tmpMaxNum = 0; + foreach my $file (@files) { + chomp; + if ($file ne '.' && $file ne '..' && $file ne 'festivalcache') { # ignore special files + my $real_version = &rmts($MUSIC.$dir).'/'.$file; + my $cache_version = &rmts($FESTIVALCACHE.$dir).'/'.$file.'.ul'; + my $cache_version2 = &rmts($FESTIVALCACHE.$dir).'/'.$file; + my $cache_version_esc = &clean_file($cache_version); + my $cache_version2_esc = &clean_file($cache_version2); + + if (-d $real_version) { + if (music_dir_cache_genlist(rmts($dir).'/'.$file)) { + $tmpMaxNum++; + $maxNumber = $tmpMaxNum if $tmpMaxNum > $maxNumber; + push(@masterCacheList, [1, $file, $cache_version_esc]) if ! -e $cache_version_esc; + $foundFiles = 1; + } + } elsif ($real_version =~ /\.mp3$/) { + $tmpMaxNum++; + $maxNumber = $tmpMaxNum if $tmpMaxNum > $maxNumber; + push(@masterCacheList, [2, &remove_file_extension($file), $cache_version_esc]) if ! -e $cache_version_esc; + $foundFiles = 1; + } + } + } + close(THEDIR); + return $foundFiles; +} + +sub rmts { # remove trailing slash + my $hog = shift; + $hog =~ s/\/$//; + return $hog; +} + +sub extract_file_name { + my $hog = shift; + $hog =~ /\/?([^\/]+)$/; + return $1; +} + +sub extract_file_dir { + my $hog = shift; + return $hog if ! ($hog =~ /\//); + $hog =~ /(.*)\/[^\/]*$/; + return $1; +} + +sub remove_file_extension { + my $hog = shift; + return $hog if ! ($hog =~ /\./); + $hog =~ /(.*)\.[^.]*$/; + return $1; +} + +sub clean_file { + my $hog = shift; + $hog =~ s/\\/_/g; + $hog =~ s/ /_/g; + $hog =~ s/\t/_/g; + $hog =~ s/\'/_/g; + $hog =~ s/\"/_/g; + $hog =~ s/\(/_/g; + $hog =~ s/\)/_/g; + $hog =~ s/&/_/g; + $hog =~ s/\[/_/g; + $hog =~ s/\]/_/g; + $hog =~ s/\$/_/g; + $hog =~ s/\|/_/g; + $hog =~ s/\^/_/g; + return $hog; +} + +sub remove_special_chars { + my $hog = shift; + $hog =~ s/\\//g; + $hog =~ s/ //g; + $hog =~ s/\t//g; + $hog =~ s/\'//g; + $hog =~ s/\"//g; + $hog =~ s/\(//g; + $hog =~ s/\)//g; + $hog =~ s/&//g; + $hog =~ s/\[//g; + $hog =~ s/\]//g; + $hog =~ s/\$//g; + $hog =~ s/\|//g; + $hog =~ s/\^//g; + return $hog; +} + +sub escape_file { + my $hog = shift; + $hog =~ s/\\/\\\\/g; + $hog =~ s/ /\\ /g; + $hog =~ s/\t/\\\t/g; + $hog =~ s/\'/\\\'/g; + $hog =~ s/\"/\\\"/g; + $hog =~ s/\(/\\\(/g; + $hog =~ s/\)/\\\)/g; + $hog =~ s/&/\\&/g; + $hog =~ s/\[/\\\[/g; + $hog =~ s/\]/\\\]/g; + $hog =~ s/\$/\\\$/g; + $hog =~ s/\|/\\\|/g; + $hog =~ s/\^/\\\^/g; + return $hog; +} + +sub check_result { + my ($res) = @_; + my $retval; + $tests++; + chomp $res; + if ($res =~ /^200/) { + $res =~ /result=(-?\d+)/; + if (!length($1)) { + print STDERR "FAIL ($res)\n"; + $fail++; + exit 1; + } else { + print STDERR "PASS ($1)\n"; + return $1; + } + } else { + print STDERR "FAIL (unexpected result '$res')\n"; + exit 1; + } +} diff --git a/trunk/agi/numeralize b/trunk/agi/numeralize new file mode 100644 index 000000000..5ca51913d --- /dev/null +++ b/trunk/agi/numeralize @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# +# Build a database linking filenames to their numerical representations +# using a keypad for the DialAnMp3 application +# + +$mp3dir="/usr/media/mpeg3"; + +dbmopen(%DIGITS, "/var/lib/asterisk/mp3list", 0644) || die("Unable to open mp3list");; +sub process_dir { + my ($dir) = @_; + my $file; + my $digits; + my @entries; + opendir(DIR, $dir); + @entries = readdir(DIR); + closedir(DIR); + foreach $_ (@entries) { + if (!/^\./) { + $file = "$dir/$_"; + if (-d "$file") { + process_dir("$file"); + } else { + $digits = $_; + $digits =~ s/[^ \w]+//g; + $digits =~ s/\_/ /g; + $digits =~ tr/[a-z]/[A-Z]/; + $digits =~ tr/[A-C]/2/; + $digits =~ tr/[D-F]/3/; + $digits =~ tr/[G-I]/4/; + $digits =~ tr/[J-L]/5/; + $digits =~ tr/[M-O]/6/; + $digits =~ tr/[P-S]/7/; + $digits =~ tr/[T-V]/8/; + $digits =~ tr/[W-Z]/9/; + $digits =~ s/\s+/ /; + print "File: $file, digits: $digits\n"; + $DIGITS{$file} = $digits; + } + } + } +} + +process_dir($mp3dir); |