aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/agi
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-01-19 00:19:29 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-01-19 00:19:29 +0000
commitf8247040e6231c4b3b5099ea3a526348b7941566 (patch)
tree0cc92ad6ebf6ae49a62f6e7ef8ec819121d63630 /trunk/agi
parentd88e56c61ce2042544c1a8a71c93b69ab2e6ffba (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.agi82
-rw-r--r--trunk/agi/Makefile52
-rw-r--r--trunk/agi/agi-test.agi79
-rw-r--r--trunk/agi/eagi-sphinx-test.c231
-rw-r--r--trunk/agi/eagi-test.c165
-rw-r--r--trunk/agi/fastagi-test94
-rwxr-xr-xtrunk/agi/jukebox.agi488
-rw-r--r--trunk/agi/numeralize44
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);