aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/pbx
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/pbx')
-rw-r--r--trunk/pbx/Makefile32
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest10/extensions.ael131
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest12/extensions.ael13
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/extensions.ael7
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/qq.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t1/a.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t1/b.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t1/c.ael13
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t2/d.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t2/e.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t2/f.ael9
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/g.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/h.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/i.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/j.ael6
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-ntest9/extensions.ael12
-rw-r--r--trunk/pbx/ael/ael-test/ael-test1/extensions.ael163
-rw-r--r--trunk/pbx/ael/ael-test/ael-test11/extensions.ael57
-rw-r--r--trunk/pbx/ael/ael-test/ael-test14/extensions.ael20
-rw-r--r--trunk/pbx/ael/ael-test/ael-test15/extensions.ael17
-rw-r--r--trunk/pbx/ael/ael-test/ael-test16/extensions.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-test18/extensions.ael40
-rw-r--r--trunk/pbx/ael/ael-test/ael-test19/extensions.ael377
-rw-r--r--trunk/pbx/ael/ael-test/ael-test2/apptest.ael2146
-rw-r--r--trunk/pbx/ael/ael-test/ael-test2/extensions.ael8
-rw-r--r--trunk/pbx/ael/ael-test/ael-test20/extensions.ael8
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-test3/extensions.ael3184
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include1.ael23
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include2.ael24
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include3.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include4.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include5.ael21
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-test3/telemarket_torture.ael2812
-rw-r--r--trunk/pbx/ael/ael-test/ael-test4/apptest.ael2146
-rw-r--r--trunk/pbx/ael/ael-test/ael-test4/extensions.ael8
-rw-r--r--trunk/pbx/ael/ael-test/ael-test5/extensions.ael838
-rw-r--r--trunk/pbx/ael/ael-test/ael-test6/extensions.ael833
-rw-r--r--trunk/pbx/ael/ael-test/ael-test7/extensions.ael460
-rw-r--r--trunk/pbx/ael/ael-test/ael-test8/extensions.ael27
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-vtest13/extensions.ael3183
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include1.ael23
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include2.ael24
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include3.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include4.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include5.ael21
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-vtest13/telemarket_torture.ael2812
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest17/extensions.ael116
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest21/extensions.ael14
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest10171
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest1230
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest2254
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest923
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test118
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1113
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1411
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1512
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1612
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1811
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1918
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test228
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test2011
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test399
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test428
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test514
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test624
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test719
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test811
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-vtest133030
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-vtest1769
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-vtest219
-rwxr-xr-xtrunk/pbx/ael/ael-test/runtests56
-rwxr-xr-xtrunk/pbx/ael/ael-test/setref7
-rw-r--r--trunk/pbx/dundi-parser.c846
-rw-r--r--trunk/pbx/dundi-parser.h88
-rw-r--r--trunk/pbx/pbx_ael.c313
-rw-r--r--trunk/pbx/pbx_config.c1668
-rw-r--r--trunk/pbx/pbx_dundi.c4847
-rw-r--r--trunk/pbx/pbx_gtkconsole.c502
-rw-r--r--trunk/pbx/pbx_loopback.c176
-rw-r--r--trunk/pbx/pbx_lua.c1354
-rw-r--r--trunk/pbx/pbx_realtime.c251
-rw-r--r--trunk/pbx/pbx_spool.c509
82 files changed, 25892 insertions, 0 deletions
diff --git a/trunk/pbx/Makefile b/trunk/pbx/Makefile
new file mode 100644
index 000000000..731057b1d
--- /dev/null
+++ b/trunk/pbx/Makefile
@@ -0,0 +1,32 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Makefile for PBX modules
+#
+# Copyright (C) 1999-2006, Digium, Inc.
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+-include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps
+
+MODULE_PREFIX=pbx
+MENUSELECT_CATEGORY=PBX
+MENUSELECT_DESCRIPTION=PBX Modules
+
+all: _all
+
+include $(ASTTOPDIR)/Makefile.moddir_rules
+
+ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
+ LIBS+= -lres_ael_share.so -lres_monitor.so
+endif
+
+clean::
+ rm -f ael/*.o
+
+dundi-parser.o: dundi-parser.h
+dundi-parser.o: ASTCFLAGS+=-I.
+
+$(if $(filter pbx_dundi,$(EMBEDDED_MODS)),modules.link,pbx_dundi.so): dundi-parser.o
diff --git a/trunk/pbx/ael/ael-test/ael-ntest10/extensions.ael b/trunk/pbx/ael/ael-test/ael-ntest10/extensions.ael
new file mode 100644
index 000000000..4a8386ccf
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest10/extensions.ael
@@ -0,0 +1,131 @@
+macro endsess()
+{
+ NoOp(hithere);
+}
+
+macro nullchk(type)
+{
+ NoOp(${type} is this);
+}
+
+macro endcall(type) {
+ switch(${type}) {
+ case out:
+ &nullchk(callid);
+ if(${testnotnull}) {
+ &endsess();
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ else {
+ptr1: // <-- valid label
+ Softhangup(${CHANNEL});
+ break ;
+ }
+ Noop(esac) ;
+ }
+}
+
+macro endcall2(type) {
+ switch(${type}) {
+ case out:
+ &nullchk(callid);
+ if(${testnotnull}) {
+ &endsess();
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ case out2:
+ {
+ptr1: // <-- valid label
+ Softhangup(${CHANNEL});
+ break ;
+ }
+ Noop(esac) ;
+ }
+}
+
+macro endcall3(type) {
+ switch(${type}) {
+ case out:
+ &nullchk(callid);
+ if(${testnotnull}) {
+ &endsess();
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ Noop(esac) ;
+ }
+ if(${testnotnull}) {
+ goto ptr1;
+ }
+ switch(${type}) {
+ case out:
+ if(${testnotnull}) {
+ptr1: // <-- valid label
+ Softhangup(${CHANNEL});
+ break ;
+ }
+ Noop(esac) ;
+ }
+}
+
+macro endcall4(type) {
+ switch(${type}) {
+ case out:
+ &nullchk(callid);
+ if(${testnotnull}) {
+ &endsess();
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ Noop(esac) ;
+ }
+ if(${testnotnull}) {
+ goto ptr1;
+ }
+ switch(${type}) {
+ case out:
+ switch(${type})
+ {
+ case in:
+ if(${testnotnull}) {
+ptr1: // <-- valid label
+ Softhangup(${CHANNEL});
+ break ;
+ }
+ Noop(esac) ;
+ }
+ }
+}
+
+macro endcall5(type) {
+ switch(${type}) {
+ case out:
+ &nullchk(callid);
+ if(${testnotnull}) {
+ &endsess();
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ case in:
+ &nullchk(callid);
+ ptr2:
+ if(${testnotnull}) {
+ &endsess();
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ Noop(esac) ;
+ }
+ if(${testnotnull}) {
+ goto ptr1;
+ }
+ switch(${type}) {
+ case out:
+ switch(${type})
+ {
+ case in:
+ if(${testnotnull}) {
+ptr1: // <-- valid label
+ Softhangup(${CHANNEL});
+ break ;
+ }
+ Noop(esac) ;
+ }
+ }
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest12/extensions.ael b/trunk/pbx/ael/ael-test/ael-ntest12/extensions.ael
new file mode 100644
index 000000000..1e3183358
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest12/extensions.ael
@@ -0,0 +1,13 @@
+context test1
+{
+ 771 => {
+ for( i=0;
+ ${i} <= 3;
+ i = ${i} + 1 )
+ NoOp(i is '${i}');
+ }
+ 772 => {
+ for(i=0; ${i} <= 3;i= ${i} + 1 )
+ NoOp(i is '${i}');
+ }
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/extensions.ael b/trunk/pbx/ael/ael-test/ael-ntest22/extensions.ael
new file mode 100644
index 000000000..b787f4b03
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/extensions.ael
@@ -0,0 +1,7 @@
+#include "t1/*.ael"
+
+context z
+{
+ 123 => NoOp(hi there, z);
+ 124 => NoOp(hi there, z);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/qq.ael b/trunk/pbx/ael/ael-test/ael-ntest22/qq.ael
new file mode 100644
index 000000000..c446f53fc
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/qq.ael
@@ -0,0 +1,6 @@
+
+
+context qq
+{
+ 567 => NoOp(hi there, qq);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t1/a.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t1/a.ael
new file mode 100644
index 000000000..62e3fc588
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t1/a.ael
@@ -0,0 +1,4 @@
+context a
+{
+ 134 => NoOp(hi there, a);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t1/b.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t1/b.ael
new file mode 100644
index 000000000..29d8d1ff4
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t1/b.ael
@@ -0,0 +1,6 @@
+
+
+context b
+{
+ 456 => NoOp(hithere, b);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t1/c.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t1/c.ael
new file mode 100644
index 000000000..3c6df4bde
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t1/c.ael
@@ -0,0 +1,13 @@
+
+
+context c
+{
+ 567 => NoOp(hi there, c);
+}
+
+#include "t2/*.ael"
+
+context w
+{
+ 890 => NoOp(hi there, w);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t2/d.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t2/d.ael
new file mode 100644
index 000000000..6362278f7
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t2/d.ael
@@ -0,0 +1,4 @@
+context d
+{
+ 134 => NoOp(hi there, d);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t2/e.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t2/e.ael
new file mode 100644
index 000000000..9465c8b4e
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t2/e.ael
@@ -0,0 +1,6 @@
+
+
+context e
+{
+ 456 => NoOp(hithere, e);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t2/f.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t2/f.ael
new file mode 100644
index 000000000..ba15a6389
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t2/f.ael
@@ -0,0 +1,9 @@
+#include "qq.ael"
+
+context f
+{
+ 567 => NoOp(hi there, f);
+}
+
+#include "t3/*.ael"
+
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t3/g.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t3/g.ael
new file mode 100644
index 000000000..0f1ecc805
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t3/g.ael
@@ -0,0 +1,4 @@
+context g
+{
+ 134 => NoOp(hi there, g);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t3/h.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t3/h.ael
new file mode 100644
index 000000000..f9e3ca89f
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t3/h.ael
@@ -0,0 +1,6 @@
+
+
+context h
+{
+ 456 => NoOp(hithere, h);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t3/i.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t3/i.ael
new file mode 100644
index 000000000..5639a1e98
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t3/i.ael
@@ -0,0 +1,4 @@
+context i
+{
+ 134 => NoOp(hi there, i);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest22/t3/j.ael b/trunk/pbx/ael/ael-test/ael-ntest22/t3/j.ael
new file mode 100644
index 000000000..8dfc6c05f
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest22/t3/j.ael
@@ -0,0 +1,6 @@
+
+
+context j
+{
+ 567 => NoOp(hi there, j);
+}
diff --git a/trunk/pbx/ael/ael-test/ael-ntest9/extensions.ael b/trunk/pbx/ael/ael-test/ael-ntest9/extensions.ael
new file mode 100755
index 000000000..b9762ed54
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-ntest9/extensions.ael
@@ -0,0 +1,12 @@
+
+context workext {
+ ignorepat => 8;
+ ignorepat => 9;
+ 793 => {
+ Set(QUERYSTRING=SELECT\ foo\,\ bar\ FROM\ foobar);
+ Verbose(2|${QUERYSTRING});
+ query="SELECT foo\, bar FROM foobar" ;
+ Verbose(2|${query}) ;
+ }
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-test1/extensions.ael b/trunk/pbx/ael/ael-test/ael-test1/extensions.ael
new file mode 100644
index 000000000..e1943f67c
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test1/extensions.ael
@@ -0,0 +1,163 @@
+
+macro testdial(number, timeout) {
+ Dial(IAX2/vpconnect-t02/${number},${timeout},${OG_DIAL_FLAGS});
+ switch (${DIALSTATUS}) {
+ case CHANUNAVAIL:
+ goto dial-trunk2;
+ break;
+ default:
+ NoOp(t02 Unavailable - ${DIALSTATUS});
+ return;
+ }
+
+dial-trunk2:
+ Dial(IAX2/vpconnect-t01/${number},${timeout},${OG_DIAL_FLAGS});
+
+}
+
+macro exten-gen(name,pword)
+{
+ if( ${DB_EXISTS(org/${GroupID}/${name}/secret)} = 0 )
+ goto other|nomatch|begin;
+ if( ${DB(org/${GroupID}/${name}/secret)}foo != ${pword}foo )
+ goto other|nomatch|begin;
+
+};
+
+context what {
+ who =>
+ {
+ random(51) NoOp(This should appear 51% of the time);
+
+ random( 60 )
+ {
+ NoOp( This should appear 60% of the time );
+ }
+ else
+ {
+ random(75)
+ {
+ NoOp( This should appear 30% of the time! );
+ }
+ else
+ {
+ NoOp( This should appear 10% of the time! );
+ }
+ }
+ }
+}
+
+context other {
+ nomatch => {
+ begin:
+ NoOp(Hello!);
+ switch(${DIALSTATUS})
+ {
+ case BUSY:
+ NoOp(wow);
+ case TORTURE:
+ NoOp(woow);
+ };
+ NoOp(woohoo);
+ };
+};
+
+context testloop {
+ includes {
+ other|16:00-23:59|m0n-fri|*|*;
+ };
+
+ 1 => {
+ for (x=0; ${x} < 3; x=${x} + 1) {
+ Verbose(x is ${x} !);
+ if( ${x} = 1 )
+ continue;
+ if( ${x} = 2 )
+ break;
+ };
+ ifTime(14:00-25:00|sat-sun|*|*) {
+ BackGround(Hello);
+ } else
+ BackGround(Sorry);
+ NoOp(This is a totally useless NOOP);
+ };
+ 2 => {
+ y=10;
+ while (${y} >= 0) {
+ Verbose(y is ${y} !);
+ if( ${y} = 1 )
+ continue;
+ if( ${y} = 2 )
+ break;
+ if( ${y} = 3 )
+ return;
+ y=${y}-1;
+ };
+ };
+ regexten hint(nasty/Thingy&nasty/Thingamabob) 3 => {
+ for (x=0; ${x} < 3; x=${x} + 1)
+ {
+ Verbose(x is ${x} !);
+ if( ${x} = 4 )
+ break;
+ if( ${x} = 5 )
+ continue;
+ if( ${x} = 6 )
+ return;
+
+ y=10;
+ while (${y} >= 0)
+ {
+ Verbose(y is ${y} !);
+ if( ${y} = 4 )
+ break;
+ if( ${y} = 5 )
+ continue;
+ if( ${y} = 6 )
+ return;
+ y=${y}-1;
+ };
+ };
+ };
+ 4 => {
+ y=10;
+ while (${y} >= 0)
+ {
+ Verbose(y is ${y} !);
+ if( ${y} = 4 )
+ break;
+ if( ${y} = 5 )
+ continue;
+ if( ${y} = 6 )
+ return;
+ for (x=0; ${x} < 3; x=${x} + 1)
+ {
+ Verbose(x is ${x} !);
+ if( ${x} = 4 )
+ break;
+ if( ${x} = 5 )
+ continue;
+ if( ${x} = 6 )
+ return;
+ for (z=0; ${z} < 17; z=${z} + 1)
+ {
+ Verbose(z is ${z} !);
+ Verbose(z is ${z} !);
+ if( ${z} = 4 )
+ break;
+ if( ${z} = 5 )
+ continue;
+ if( ${z} = 6 )
+ return;
+ Verbose(z is ${z} !);
+ Verbose(z is ${z} !);
+ };
+
+ };
+ y=${y}-1;
+ };
+ };
+ 5 => {
+ &exten-gen(axel,brain);
+ };
+};
diff --git a/trunk/pbx/ael/ael-test/ael-test11/extensions.ael b/trunk/pbx/ael/ael-test/ael-test11/extensions.ael
new file mode 100644
index 000000000..a6b2226f8
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test11/extensions.ael
@@ -0,0 +1,57 @@
+context test1
+{
+ s =>
+ {
+ goto lab1;
+ if( ${testnotnull} )
+ {
+ lab1:
+ NoOp(hello);
+ }
+ else
+ {
+ lab1:
+ MoOp(goodbye);
+ }
+ }
+
+ 1 =>
+ {
+ lab1:
+ NoOp(This one is OK.);
+ }
+}
+
+macro endcall5(type) {
+ switch(${type}) {
+ case out:
+ if(${testnotnull}) {
+ NoOp(whoosh);
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ case in:
+ ptr1: // The First label is the valid one...
+ if(${testnotnull}) {
+ NoOp(wow);
+ goto ptr1 ; // <-- goto call to valid label
+ }
+ Noop(esac) ;
+ }
+ if(${testnotnull}) {
+ goto ptr1;
+ }
+ switch(${type}) {
+ case out:
+ switch(${type})
+ {
+ case in:
+ if(${testnotnull}) {
+ptr1: // <-- duplicate label (macros are about the equiv of an extension)
+ Softhangup(${CHANNEL});
+ break ;
+ }
+ Noop(esac) ;
+ }
+ }
+ return;
+}
diff --git a/trunk/pbx/ael/ael-test/ael-test14/extensions.ael b/trunk/pbx/ael/ael-test/ael-test14/extensions.ael
new file mode 100644
index 000000000..20d69134f
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test14/extensions.ael
@@ -0,0 +1,20 @@
+context test1
+{
+ 10 => {
+ // nothing but a comment!
+ }
+
+ 11 => {
+ switch(${somevar})
+ {
+ case somecase:
+ // nothing but a comment!
+ break;
+ case somecase:
+ // nothing but a comment!
+ continue;
+ }
+ break;
+ }
+
+}
diff --git a/trunk/pbx/ael/ael-test/ael-test15/extensions.ael b/trunk/pbx/ael/ael-test/ael-test15/extensions.ael
new file mode 100644
index 000000000..c9cfdab96
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test15/extensions.ael
@@ -0,0 +1,17 @@
+/* and some comments
+ would make a nice touch */
+
+context t1
+{
+ /* this a test of block comments */
+
+ _15x => {
+ /* more comments
+ across several lines
+ * what do you think*
+ */
+ }
+
+}
+
+/* amd some more */
diff --git a/trunk/pbx/ael/ael-test/ael-test16/extensions.ael b/trunk/pbx/ael/ael-test/ael-test16/extensions.ael
new file mode 100644
index 000000000..5f3b2e4e9
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test16/extensions.ael
@@ -0,0 +1,4 @@
+context real-small {
+
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-test18/extensions.ael b/trunk/pbx/ael/ael-test/ael-test18/extensions.ael
new file mode 100644
index 000000000..ee03d5909
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test18/extensions.ael
@@ -0,0 +1,40 @@
+context default
+{
+
+706/3077610011 => {
+ JabberStatus(asterisk|jmls@mike,StatusCode);
+
+ switch(${StatusCode}) {
+ case 1:
+ Dial(SIP/706,12);
+ switch(${DIALSTATUS}) {
+ case BUSY:
+ Voicemail(b706);
+ break;
+ default:
+ Voicemail(u706);
+ };
+ BackGround(hello);
+ break;
+ default:
+ Voicemail(u706);
+ };
+ ifTime(3:00-13:00|*|*|*)
+ {
+ NoOp(hello);
+ label1:
+ NoOp(goodbye);
+ }
+ else
+ {
+ NoOp(hithere);
+ label2:
+ NoOp(whatonearth?);
+ }
+ goto label1;
+ goto label2;
+ Hangup();
+ };
+
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-test19/extensions.ael b/trunk/pbx/ael/ael-test/ael-test19/extensions.ael
new file mode 100644
index 000000000..07af91482
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test19/extensions.ael
@@ -0,0 +1,377 @@
+context dialextens
+{
+ /*
+ 101 thru 123, 149 thru 152
+ */
+ _10X => Dial(Zap/${EXTEN:2},30,Ttw);
+ _1ZX => Dial(Zap/${EXTEN:1},30,Ttw);
+}
+/*
+ Due to extenal wiring:
+
+ dialing 125 will ring 101
+ dialing 126 will ring 102
+ and so on until
+ dialing 147 will ring 123
+
+We can dial out on zap 69 thru 72; and 25-47
+
+*/
+
+context dialthrus
+{
+ /* 369-372; 325-347 */
+ _3XX => Dial(Zap/${EXTEN:1},30,Ttw);
+}
+
+context t1incoming
+{
+ includes
+ {
+ dialextens;
+ parkedcalls;
+ }
+ s => {
+ Answer();
+ Background(welcome-to-test-machine);
+ }
+
+}
+
+context t1extension
+{
+ includes
+ {
+ dialextens;
+ dialthrus;
+ }
+
+}
+
+context incoming
+{
+ includes
+ {
+ dialextens;
+ parkedcalls;
+ }
+ s => {
+ Answer();
+ Background(welcome-to-test-machine);
+ }
+}
+
+context incoming
+{
+ s => {
+ Answer();
+ }
+}
+
+macro std-priv-exten( dev, ext , timeout, opts, torcont, dontcont )
+{
+ // &increment_chosecount();
+ dial_again:
+ Dial(${dev},${timeout},${opts});
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+
+ case BUSY:
+ label_busy:
+ Read(reply|work-exten-busy|1||2|15);
+ if ("${reply}"=="")
+ goto label_busy; // infinite loop if Read has probs!!
+ switch(${reply})
+ {
+ case 1:
+ Set(time1=${EPOCH});
+
+ label_redial:
+
+ WaitMusicOnHold(5);
+ Dial(${dev},${timeout},${opts});
+
+ switch(${DIALSTATUS})
+ {
+ case BUSY:
+ if(${EPOCH}-${time1} >= 20)
+ goto label_busy;
+ goto label_redial;
+
+ default:
+ return;// goto work_line|s|loopback;
+ }
+ break;
+ case 2:
+ Voicemail(${ext}|b);
+ break;
+ case 3:
+ return; // goto work_line|s|loopback;
+ default:
+ Background(invalid);
+ goto label_busy;
+ }
+ break;
+
+ case ANSWER:
+ break;
+
+ case NOANSWER:
+ noanswer_label:
+ Read(reply|work-exten-noanswer|1|skip|2|15);
+ switch(${reply})
+ {
+ case 1:
+ switch(${ext})
+ {
+ case 10:
+ Background(no-cell);
+ break;
+ case 11:
+ // &ciddial(2729495,3072729495,30,tw,${GRAMS_TELCO},${WORK_TELCO});
+ break;
+ case 12:
+ // &ciddial(2725560,3072725560,30,tw,${GRAMS_TELCO},${WORK_TELCO});
+ break;
+ case 13:
+ // &ciddial(2720197,3072720197,30,tw,${GRAMS_TELCO},${WORK_TELCO});
+ break;
+ case 14:
+ // &ciddial(2501174,3072501174,30,tw,${GRAMS_TELCO},${WORK_TELCO});
+ break;
+ case 15:
+ Background(no-cell);
+ break;
+ case 16:
+ Background(no-cell);
+ break;
+ default:
+ Background(invalid);
+ break;
+ }
+ goto noanswer_label;
+ break;
+ case 2:
+ Voicemail(${ext}|u);
+ break;
+ case 3:
+ return; // goto work_line|s|loopback;
+ default:
+ Background(invalid);
+ goto noanswer_label;
+ }
+ Voicemail(${ext}|u);
+ break;
+ default:
+ Voicemail(${ext}|u);
+ }
+}
+/* Putting these 3 funcs in extensions.conf!
+macro funcC(a,b)
+{
+ Set(Key=);
+ menu:
+ Read(Key,main-menu,1,n,1,5);
+ if("${Key}" = "2")
+ goto y,lab1;
+ catch y
+ { lab1:
+ &funcB(${a},${b});
+ }
+}
+
+macro funcB(a,b)
+{
+ Set(Key=);
+ menu:
+ Read(Key,tt-monkeys,1,n,1,5);
+ if("${Key}" = "2")
+ goto z,lab2;
+ catch z
+ { lab2:
+ &funcC(${a},${b});
+ }
+}
+
+macro funcA()
+{
+ &funcB(1,2);
+}
+*/
+
+context extension
+{
+ includes
+ {
+ dialextens;
+ dialthrus;
+ parkedcalls;
+ }
+ 5 => {
+ Record(recording:wav);
+ Background(recording);
+ }
+
+ 81 => {
+ iterations=1000000;
+ Set(time1=${EPOCH});
+ for(i=1; ${i}<${iterations}; i=${i}+1)
+ {
+ NoOp(Hello);
+ }
+ Set(time2=${EPOCH});
+ Verbose(The time diff is $[${time2} - ${time1} ] seconds);
+ Verbose(Which means that the priorities/sec = $[4* ${iterations} / (${time2} - ${time1}) ]);
+ SayNumber($[4 * ${iterations} / (${time2} - ${time1}) ]);
+ }
+ 82 => {
+ &ndeep(100000);
+ Verbose(Finished 100000 levels deep call!);
+ }
+ 83 => {
+ switch (${EXTEN})
+ {
+ pattern 8X:
+ Verbose(do something to prepare it);
+ pattern 9X:
+ Verbose(handle both 1xx and 2xx calls);
+ pattern [4-7]X:
+ Verbose(and this too!);
+ }
+ Set(junky=${RAND(0|99999)});
+ Verbose(Here is a random number: ${junky}.);
+ }
+ 84 => {
+ agi(agi://192.168.134.252/|hello|goodbye|whatever|whoknows,hell2,hello3);
+ }
+ 85 => {
+ &std-priv-exten( Zap/50, 150 , 25, mtw, torcont, dontcont );
+ }
+ 86 => {
+ Verbose(The version is: ${VERSION()} );
+ Verbose(The versionnum is: ${VERSION(ASTERISK_VERSION_NUM)} );
+ Verbose(The user is: ${VERSION(BUILD_USER)} );
+ Verbose(The hostname is: ${VERSION(BUILD_HOSTNAME)} );
+ Verbose(The machine is: ${VERSION(BUILD_MACHINE)} );
+ Verbose(The OS is: ${VERSION(BUILD_OS)} );
+ Verbose(The date is: ${VERSION(BUILD_DATE)} );
+ Verbose(The kernel is: ${VERSION(BUILD_KERNEL)} );
+ Set(vinf=${VERSION()});
+ Set(vrand=${RAND()});
+ if( ${ISNULL(${vinf})} )
+ {
+ if( ${ISNULL(${vrand})} )
+ Verbose(Version 1.2 or earlier);
+ else
+ Verbose(Version 1.4!!!);
+ }
+ else
+ Verbose(${vinf} indicates version pre-1.6 or higher);
+ }
+ 871 => {
+ NoOp( 1 1 1 1 1 1 1);
+ NoOp( 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6);
+ NoOp(012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678890123456789012345678901234567890);
+ NoOp(${EXTEN:1:2} ${EXTEN} ${EXTEN:1} 1 1 1 1 1 1 1);
+ &dialoutpstn(${TDIRECTCALL-PST}/0${EXTEN},${E${CALLERID(num)}-OPT},${TDIRECTCALL-CID},${TDIRECTCALL-MAX},RotaPadrao) ;
+
+ }
+ 872 => {
+ Set(ChannelOnly=${CUT(CHANNEL||1)});
+ Verbose(ChannelOnly=${ChannelOnly}; neat huh?);
+ Set(ChannelOnly=${CUT(CHANNEL,,1)});
+ Verbose(ChannelOnly=${ChannelOnly}; neat huh?);
+ }
+ 873 => {
+ NOOP(this is a forkcdr test);
+ Set(CALLERID(num)=1234567890);
+ Set(CALLERID(name)=before fork);
+ Forkcdr(v);
+ Set(CALLERID(num)=0987654321);
+ Set(CALLERID(name)=after fork);
+ Answer();
+ Echo();
+ Hangup();
+ }
+ 874 => {
+ SayDigits(307-754-5675);
+ SayPhoneNumber(307-754-5675);
+ SayDigits(--);
+ SayPhoneNumber(123-456-7890);
+ SayDigits(++);
+ SayPhoneNumber(307-754-4454);
+ }
+ 875 => {
+ &funcA();
+ &funcD();
+ }
+ 876 => {
+ NoOp(Query resultid ${connid} SELECT var1\, var2 FROM did);
+ NoOp($["Query resultid ${connid} SELECT var1\, var2 FROM did"]);
+ NoOp($["Query resultid ${connid} SELECT var1, var2 FROM did"]);
+ goto test5,s,1;
+ }
+ 88 => {
+ SET(LIMIT_PLAYAUDIO_CALLER=yes);
+ SET(LIMIT_PLAYAUDIO_CALLEE=no);
+ SET(LIMIT_TIMEOUT_FILE=timeup);
+ SET(LIMIT_CONNECT_FILE=limit60);
+ SET(LIMIT_WARNING_FILE=almostup);
+ Dial(Zap/51,20,L(60000:30000:8000));
+ }
+ 89 => {
+ goto callbackmenu|100|1;
+ }
+}
+
+context income1
+{
+ s => {
+ Answer();
+ Dial(Zap/50,20,m);
+ }
+ 150 => Dial(Zap/50,20,m);
+}
+
+context callbackmenu
+{
+ _X. => {
+ Answer();
+ Wait(1);
+ Set(TIMEOUT(digit)=5);
+ Set(TIMEOUT(response)=30);
+ DISA(no-password,callbackdialout);
+ }
+}
+
+context callbackdialout
+{
+ _X. => {
+ Dial(Zap/51,20,w);
+ }
+
+}
+
+
+macro dialoutpstn(something1, something2, something3, something4, something5)
+{
+ Verbose(${something1}--- ${something2}--- ${something3}--- ${something4}--- ${something5});
+}
+
+macro ndeep(level)
+{
+ if( ${level} == 0)
+ {
+ Verbose(2|Got to Level 0);
+ return;
+ }
+ &ndeep($[${level}-1]);
+ return;
+}
diff --git a/trunk/pbx/ael/ael-test/ael-test2/apptest.ael2 b/trunk/pbx/ael/ael-test/ael-test2/apptest.ael2
new file mode 100644
index 000000000..c477d8531
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test2/apptest.ael2
@@ -0,0 +1,146 @@
+// this is a quick test to see how many of the apps we can spot j options in
+// include this in a macro or extension
+// at this moment, there are 18 apps that accept the j option.
+
+ AddQueueMember(zork,iface,20,j);
+ ADSIProg(sfile);
+ AgentCallbackLogin(agent,s,30@cont);
+ AgentLogin(agent,s);
+ AgentMonitorOutgoing(dcn);
+ AGI(whatever);
+ AlarmReceiver();
+ Answer(2);
+ AppendCDRUserField(value);
+ Authenticate(pword,adjmr);
+ BackGround(filename,snm,eng);
+ BackgroundDetect(filename,20,2,10);
+ Busy(10);
+ ChangeMonitor(fnamebase);
+ ChanIsAvail(Zap/5,sj);
+ ChanSpy(prefix,bg()qrv);
+ Congestion(5);
+ ControlPlayback(filename,10,6,4,0,5,7,j);
+ DateTime(unixtime,tz,fmt);
+ DBdel(fam/key);
+ DBdeltree(fam);
+ DeadAGI(command);
+ Dial(zap/1,45,A()CdD()fgG()hHjL()m()M()nNoprS()tTwW);
+ Dictate(basedir);
+ Directory(cont,dcont,f);
+ DISA(68986869876,context);
+ DumpChan(verblev);
+ DUNDiLookup(90709780978,context,bj);
+ EAGI(command);
+ Echo();
+ EndWhile();
+ Exec(appname,args);
+ ExecIf(expr,app,data);
+ ExecIfTime(*,*,*,*,appname);
+ ExternalIVR(command,arg1);
+ Festival(text);
+ Flash();
+ ForkCDR(v);
+ GetCPEID();
+ Gosub(cont,exten,priority);
+ GosubIf(cond?label);
+ Goto(cont,exten,prior);
+ GotoIf(cond?t:f);
+ GotoIfTime(*,*,*,*?cont,ext,prior);
+ Hangup();
+ HasNewVoicemail(vmbox,var,j);
+ HasVoicemail(vmbox,var,j);
+ IAX2Provision(template);
+ ICES(xmlconfig);
+ ImportVar(nevar@chann,var);
+ Log(NOTICE,message);
+ LookupBlacklist(j);
+ LookupCIDName();
+ Macro(macro,arg1);
+ MacroExit();
+ MacroIf(expr?etc);
+ MailboxExists(mbox@cont,j);
+ Math(v,2+2);
+ MeetMe(5555,aAbcdDeimMpPqrstTovwxX);
+ MeetMeAdmin(5555,e,user);
+ MeetMeCount(5555,var);
+ Milliwatt();
+ MixMonitor(filename,abv()V()W(),command);
+ Monitor(file.fmt,base,mb);
+ MP3Player(location);
+ MusicOnHold(class);
+ NBScat();
+ NoCDR();
+ NoOp(ignored);
+ Page(Zap/1,dq);
+ Park(exten);
+ ParkAndAnnounce(template,5,238,retcont);
+ ParkedCall(exten);
+ PauseQueueMember(queue,zap,j);
+ Pickup(ext@cont);
+ Playback(file,j);
+ PlayTones(arg);
+ PrivacyManager(3,4,j);
+ Progress();
+ Queue(queuename,dhHnrtTwW,http://www.where.what,over,5);
+ Random(30,cont,ext,pri);
+ Read(var,fname,10,skip,2,5);
+ ReadFile(var=file,10);
+ RealTime(fam,2,val,prefix);
+ RealTimeUpdate(fam,2,val,2,newval);
+ Record(file,2,10,anqst);
+ RemoveQueueMember(queuename,iface,j);
+ ResetCDR(wav);
+ RetryDial(annound,4,2);
+ Return();
+ Ringing();
+ RxFAX(fname,caller);
+ SayAlpha(string);
+ SayDigits(string);
+ SayNumber(digits);
+ SayPhonetic(string);
+ SayUnixTime(unixtime,tz,fmt);
+ SendDTMF(digits,10);
+ SendImage(filename);
+ SendText(text,j);
+ SendURL(URL);
+ Set(a=b);
+ SetAMAFlags();
+ SetCallerID(clid,a);
+ SetCallerPres(allowed_passed_screen);
+ SetCDRUserField(value);
+ SetGlobalVar(var=val);
+ SetMusicOnHold(class);
+ SetTransferCapability(SPEECH);
+ SIPAddHeader(header);
+ SIPDtmfMode(inband,info,rfc);
+ SIPGetHeader(var@headername);
+ SMS(name);
+ SoftHangup(zap/1,a);
+ StackPop();
+ StartMusicOnHold(class);
+ StopMonitor();
+ StopMusicOnHold();
+ StopPlayTones();
+ System(command);
+ TestClient(testid);
+ TestServer();
+ Transfer(zap/1,j);
+ TrySystem(command);
+ TxFAX(filename,caller,debug);
+ UnpauseQueueMember(queuename,iface,j);
+ UserEvent(eventanme,body);
+ Verbose(5,message);
+ VMAuthenticate(mailbox@cont,s);
+ VoiceMail(mailbox@cont,bg()suj);
+ VoiceMailMain(mailbox@cont,pg()s);
+ Wait(2);
+ WaitExten(3,m());
+ WaitForRing(2);
+ WaitForSilence(2,y);
+ WaitMusicOnHold(2);
+ While(expr);
+ Zapateller(answer,5);
+ ZapBarge(channel);
+ ZapRAS(arg);
+ ZapScan(group);
+ ZapSendKeypadFacility();
diff --git a/trunk/pbx/ael/ael-test/ael-test2/extensions.ael b/trunk/pbx/ael/ael-test/ael-test2/extensions.ael
new file mode 100644
index 000000000..176338872
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test2/extensions.ael
@@ -0,0 +1,8 @@
+context test1
+{
+ s =>
+ {
+ #include "apptest.ael2";
+ }
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-test20/extensions.ael b/trunk/pbx/ael/ael-test/ael-test20/extensions.ael
new file mode 100644
index 000000000..8ec219864
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test20/extensions.ael
@@ -0,0 +1,8 @@
+context interesting {
+ eswitches {
+ Realtime/default@extensions;
+ IAX2/context@${CURSERVER};
+ }
+ 13 => NoOp(LuckyNumber!);
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-test3/extensions.ael b/trunk/pbx/ael/ael-test/ael-test3/extensions.ael
new file mode 100755
index 000000000..ff1f6aea5
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/extensions.ael
@@ -0,0 +1,3184 @@
+globals
+{
+ static=yes;
+ writeprotect=yes;
+ CONSOLE=Console/dsp; // Console interface for demo
+ IAXINFO=murf:tlhfckoct; // IAXtel username/password
+ FWDNUMBER=544788 ; // your calling number
+ FWDCIDNAME="Joe-Worker"; // your caller id
+ FWDPASSWORD=zingledoodle ; // your password
+ FWDRINGS=Zap/6 ; // the phone to ring
+ FWDVMBOX=1 ; // the VM box for this user
+}
+
+macro std-exten( ext , dev )
+{
+ Dial(${dev}/${ext},20);
+ goto privacyManagerFailed|s|begin;
+ switch(${DIALSTATUS})
+ {
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ case ANSWER:
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+ catch a {
+ VoiceMailMain(${ext});
+ }
+}
+
+macro std-priv-exten_1( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_2( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_3( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_4( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_5( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_6( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_7( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_8( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_9( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_10( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_11( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_12( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_13( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_14( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_15( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_16( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_17( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_18( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_19( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_20( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_21( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_22( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_23( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_24( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_25( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_26( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_27( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_28( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_29( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_30( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_31( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_32( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_33( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_34( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_35( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_36( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_37( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_38( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_39( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_40( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_41( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_42( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_43( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_44( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_45( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_46( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_47( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_48( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_49( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_50( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_51( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_52( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_53( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_54( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_55( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_56( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_57( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_58( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_59( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_60( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_61( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_62( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_63( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_64( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_65( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_66( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_67( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_68( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_69( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_70( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_71( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_72( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_73( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+macro fillcidname()
+{
+ if( "${CALLERID(num)}" = "" ) // nothing to work with, quit!!!
+ return;
+ Set(cidn=${DB(cidname/${CALLERID(num)})});
+ if( "${CALLERID(name)}" != "" )
+ {
+ if( ("${cidn}" = "Privacy Manager" & "${CALLERID(name)}" != "Privacy Manager") | "${cidn}" = "" ) // if the entry isn't in the database,
+ // or if an entry exists, and it's "Privacy Manager", empty, (or add other useless possibilities).
+ {
+ Set(DB(cidname/${CALLERID(num)})=${CALLERID(name)}); // then set or override what's in the DB
+ }
+ }
+ // Now, we fill in the callerid info from the incoming entry, if it's stuff worth using
+ // Ignore fundamentally semi-anonymous information from local cell phones
+ // if the db has an entry for this number, and it's not a canned string from a cell phone company
+ if( ( "${cidn}" != "" ) & ( "${CALLERID(name)}" = ""
+ | "${CALLERID(name)}" = "CODY,WY "
+ | "${CALLERID(name)}" = "POWELL,WY "
+ | "${CALLERID(name)}" = "WIRELESS CALLER"
+ | "${CALLERID(name)}" = "SUBSCRIBER,WIRE"
+ | "${CALLERID(name)}" = "CELLULAR ONE"
+ | "${CALLERID(name)}" = "Cellular One Customer"
+ | "${CALLERID(name)}" = "CELLULAR ONE "
+ | "${CALLERID(name)}" = "Privacy Manager"
+ | "${CALLERID(name)}" = "RIVERTON,WY "
+ | "${CALLERID(name)}" = "BASIN,WY "
+ | "${CALLERID(name)}" = "BILLINGS,MT "
+ | "${CALLERID(name)}" = "PROVO,UT "
+ | "${CALLERID(name)}" = "TOLL FREE " ) ) // put stuff in the above, that the phone company tends to put in your callerid,
+ // that you would rather override with DB info
+ // there's no way to guess them all, but you can get the most popular ones...
+ // why cell phones can't do CID like everybody else, ....?
+ {
+ Set(CALLERID(name)=${cidn}); // Override what the phone company provides with what's in the DB for this number.
+ }
+}
+
+macro ciddial(dialnum, lookup, waittime, dialopts, ddev)
+{
+ Set(cidnu=${CALLERID(num)});
+ Set(cidn=${DB(cidname/${lookup})});
+ Set(CALLERID(name)=${cidn});
+ Dial(${ddev}/${dialnum}|${waittime}|${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_voip);
+ CALLERID(num)=7075679201;
+ Dial(SIP/1${lookup}@tctwest,${waittime},${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_cell);
+ CALLERID(num)=${cidnu}; // put the original number back
+ Dial(Zap/2/${lookup},${waittime},${dialopts});
+ }
+ }
+}
+
+macro ciddial3(dialnum, lookup, waittime, dialopts, ddev)
+{
+ Set(cidnu=${CALLERID(num)});
+ Set(cidn=${DB(cidname/${lookup})});
+ Set(CALLERID(name)=${cidn});
+ Dial(${ddev}/${dialnum}|${waittime}|${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_cell);
+ Dial(Zap/2/${lookup},${waittime},${dialopts});
+ }
+}
+
+macro ciddial2(dialnum, lookup, waittime, dialopts, ddev) // give priority to tctwest, then the ZAP in emergencies
+{
+ Set(cidn=${DB(cidname/${lookup})});
+ Set(cidnu=${CALLERID(num)});
+ Set(CALLERID(name)=${cidn});
+ Set(CALLERID(num)=7075679201);
+ Dial(SIP/1${lookup}@tctwest,${waittime},${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ Set(CALLERID(num)=${cidnu}); // put the original number back
+ BackGround(try_zap);
+ Dial(${ddev}/${dialnum},${waittime}|${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_cell);
+ Dial(Zap/2/${lookup},${waittime},${dialopts});
+ }
+ }
+}
+
+macro callerid-liar()
+{
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/priv-callerintros/LIAR.gsm&);
+ Background(priv-liar); // Script: OOOps! Sorry! I don't allow men with ski masks pulled over their
+ // faces to get in the front door, and unidentified callers won't fair
+ // any better. You entered *MY* phone number. That won't work.
+ // If you are telemarketing, cross me off the list, and don't call again.
+ // If you did this by mistake, forgive my defenses, and call again.
+ // Alternate: (priv-liar2)
+ // Script: You have chosen to try to deceive my system and withold your CallerID,
+ // by entering my own phone number as YOUR CallerID. I find this
+ // offensive because you are being dishonest. I will not do business nor
+ // waste my time talking to anyone who is less than honest and forthcoming.
+ // Take me off your call list and do not call me again.
+ Hangup();
+}
+
+macro callerid-bad()
+{
+ mycid=${CALLERID(num)}:"1([0-9]+)";
+ Set(CALLERID(num)=${mycid});
+ Wait(0);
+}
+
+context privacyManagerFailed {
+ s => {
+ begin:
+ Background(PrivManInstructions); // Script: OOps, that didn't go well. You need to enter *your* area code, and *your* 7 digit
+ // phone number, for a total of 10 digits, or you'll be handed over to the monkeys. Let's
+ // try this again, and hopefully you can get past our front-line defenses!
+ PrivacyManager();
+ if( "${PRIVACYMGRSTATUS}" = "FAILED" )
+ {
+ Background(tt-allbusy);
+ Background(tt-somethingwrong);
+ Background(tt-monkeysintro);
+ Background(tt-monkeys);
+ Background(tt-weasels);
+ Hangup();
+ }
+ else
+ {
+ goto homeline|s|postPriv;
+ }
+ }
+}
+
+// Some comments
+// Some more comments
+
+context homeline {
+ s => {
+ begin:
+ Answer();
+ Set(repeatcount=0);
+ Zapateller(nocallerid);
+ PrivacyManager();
+ if( "${PRIVACYMGRSTATUS}" = "FAILED" )
+ {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/privmanfailed.gsm);
+ &std-priv-exten(Zap/3r1&Zap/5r1,2,25,mtw,telemarket,telemarket);
+ Hangup();
+ return;
+// goto privacyManagerFailed|s|begin;
+ }
+ postPriv:
+ &fillcidname();
+ Set(CONFCIDNA=${CALLERID(name)});
+ Set(CONFCIDNU=${CALLERID(num)});
+ AGI(callall);
+ AGI(submit-announce.agi);
+ if( "${CALLERID(num)}" : "1" )
+ {
+ &callerid-bad();
+ }
+ if( "${CALLERID(num)}" = "7077577685" & "${CALLERID(name)}" : "Privacy Manager" )
+ {
+ &callerid-liar();
+ }
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ Set(lds=${DB(playlds/${CALLERID(num)})});
+ if( "${lds}" = "1" )
+ {
+ SetMusicOnHold(mohlds);
+ }
+ direct=${DB(DirectCall/${CALLERID(num)})};
+ if( "${direct}" != "" & ${direct} != 0 )
+ {
+ verbose(direct is XXX#${direct}XXXX);
+ Playback(greetings/direct); // Welcome to the Murphy residence. This system will automatically try to connect you to...
+ Playback(/var/spool/asterisk/voicemail/default/${direct}/greet);
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/${direct}/greet.wav&);
+ switch(${direct})
+ {
+ case 1: //Steve
+ &std-priv-exten(Zap/6r3&Sip/murf,1,25,mpA(beep)tw,telemarket,telemarket);
+ goto s|loopback;
+ case 2: //Sonya
+ &std-priv-exten(Zap/3r1&Zap/5r1,2,25,mtw,telemarket,telemarket);
+ goto s|loopback;
+ default: // all the kids
+ Set(z=${direct}-2);
+ goto homeline-kids|${z}|1;
+ }
+ }
+ loopback:
+ ifTime(*|*|20-25|dec)
+ {
+ Playback(greetings/christmas);
+ }
+ else ifTime(*|*|31|dec)
+ {
+ Playback(greetings/newyear);
+ }
+ else ifTime(*|*|1|jan)
+ {
+ Playback(greetings/newyear);
+ }
+ else ifTime(*|*|14|feb)
+ {
+ Playback(greetings/valentines);
+ }
+ else ifTime(*|*|17|mar)
+ {
+ Playback(greetings/stPat);
+ }
+ else ifTime(*|*|31|oct)
+ {
+ Playback(greetings/halloween);
+ }
+ else ifTime(*|mon|15-21|jan)
+ {
+ Playback(greetings/mlkDay);
+ }
+ else ifTime(*|thu|22-28|nov)
+ {
+ Playback(greetings/thanksgiving);
+ }
+ else ifTime(*|mon|25-31|may)
+ {
+ Playback(greetings/memorial);
+ }
+ else ifTime(*|mon|1-7|sep)
+ {
+ Playback(greetings/labor);
+ }
+ else ifTime(*|mon|15-21|feb)
+ {
+ Playback(greetings/president);
+ }
+ else ifTime(*|sun|8-14|may)
+ {
+ Playback(greetings/mothers);
+ }
+ else ifTime(*|sun|15-21|jun)
+ {
+ Playback(greetings/fathers);
+ }
+ else
+ {
+ Playback(greetings/hello); // None of the above? Just a plain hello will do
+ }
+ Background(murphy-homeline-intro1); // Script: Hello-- Welcome to the Murphy's! If you already know what
+ // option you want, you don't have to wait for this entire spiel-- just
+ // have at it.
+ // If you are calling because this number is on a list of some sort, dial 6.
+ // If you want Sonya, dial 1.
+ // If you want one of the kids, dial 2.
+ // If you want Steve, dial 3.
+ // to play with your introduction, dial 5.
+ // If we don't seem to be giving you the time of day, try 7.
+ // Have a good day!
+
+ }
+ 1 => { // Sonya
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/2/greet.wav&);
+ &std-priv-exten(Zap/3r1&Zap/5r1,2,25,mtw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 2 => { // Kids
+ goto homeline-kids|s|begin;
+ }
+ 21 => {
+ Dial(IAX2/seaniax,20,T);
+ }
+ 3 => { // Steve
+ &std-priv-exten(Zap/6r3&Sip/murf,1,25,mpA(beep)tw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 4 => { // Voicemail
+ VoicemailMain();
+ goto s|loopback;
+ }
+ 5 => { // play with intro
+ goto home-introduction|s|begin;
+ }
+ 6 => { // Telemarketers
+ goto telemarket|s|begin;
+ }
+ 7 => { // time of day, riddle
+ agi(tts-riddle.agi);
+ Background(gsm/what-time-it-is2);
+ SayUnixTime();
+ goto s|loopback;
+ }
+ 792 => { // Page All
+ goto pageall|s|begin;
+ }
+ 793 => { // check the tone recognition
+ Read(zz,,0,,1,0);
+ SayDigits(${zz});
+ }
+ t => {
+ Set(repeatcount=${repeatcount} + 1);
+ if( ${repeatcount} < 3 )
+ {
+ goto s|loopback; // just loopback isn't enough
+ }
+ Hangup();
+ }
+ i => {
+ Background(invalid);
+ goto s|loopback;
+ }
+ o => {
+ Congestion();
+ }
+ fax => {
+ Dial(Zap/4);
+ }
+}
+
+// Some comments
+// Some more comments
+
+context pageall {
+ s => {
+ begin:
+ AGI(callall);
+ MeetMe(5555,dtqp);
+ MeetMeAdmin(5555,K);
+ Hangup();
+ }
+
+ h => {
+ begin:
+ MeetMeAdmin(5555,K);
+ Background(conf-muted);
+ Hangup();
+ }
+}
+
+// Some comments
+// Some more comments
+
+context add-to-conference {
+ start => {
+ NoCDR();
+ MeetMe(5555,dmqp);
+ }
+ h => {
+ Hangup();
+ }
+}
+
+context home-introduction {
+ s => {
+ begin:
+ Background(intro-options); // Script: To hear your Introduction, dial 1.
+ // to record a new introduction, dial 2.
+ // to return to the main menu, dial 3.
+ // to hear what this is all about, dial 4.
+ }
+ 1 => {
+ Playback(priv-callerintros/${CALLERID(num)});
+ goto s|begin;
+ }
+ 2 => {
+ goto home-introduction-record|s|begin;
+ }
+ 3 => {
+ goto homeline|s|loopback;
+ }
+ 4 => {
+ Playback(intro-intro); // Script:
+ // This may seem a little strange, but it really is a neat
+ // thing, both for you and for us. I've taped a short introduction
+ // for many of the folks who normally call us. Using the Caller ID
+ // from each incoming call, the system plays the introduction
+ // for that phone number over a speaker, just as the call comes in.
+ // This helps the folks
+ // here in the house more quickly determine who is calling.
+ // and gets the right ones to gravitate to the phone.
+ // You can listen to, and record a new intro for your phone number
+ // using this menu.
+ goto s|begin;
+ }
+ t => {
+ goto s|begin;
+ }
+ i => {
+ Background(invalid);
+ goto s|begin;
+ }
+ o => {
+ goto s|begin;
+ }
+}
+
+context home-introduction-record {
+ s => {
+ begin:
+ Background(intro-record-choices); // Script:
+ // If you want some advice about recording your
+ // introduction, dial 1.
+ // otherwise, dial 2, and introduce yourself after
+ // the beep.
+ }
+ 1 => {
+ Playback(intro-record);
+ // Your introduction should be short and sweet and crisp.
+ // Your introduction will be limited to 10 seconds.
+ // This is NOT meant to be a voice mail message, so
+ // please, don't say anything about why you are calling.
+ // After we are done making the recording, your introduction
+ // will be saved for playback.
+ // If you are the only person that would call from this number,
+ // please state your name. Otherwise, state your business
+ // or residence name instead. For instance, if you are
+ // friend of the family, say, Olie McPherson, and both
+ // you and your kids might call here a lot, you might
+ // say: "This is the distinguished Olie McPherson Residence!"
+ // If you are the only person calling, you might say this:
+ // "This is the illustrious Kermit McFrog! Pick up the Phone, someone!!"
+ // If you are calling from a business, you might pronounce a more sedate introduction,like,
+ // "Fritz from McDonalds calling.", or perhaps the more original introduction:
+ // "John, from the Park County Morgue. You stab 'em, we slab 'em!".
+ // Just one caution: the kids will hear what you record every time
+ // you call. So watch your language!
+ // I will begin recording after the tone.
+ // When you are done, hit the # key. Gather your thoughts and get
+ // ready. Remember, the # key will end the recording, and play back
+ // your intro. Good Luck, and Thank you!"
+ goto 2|begin;
+ }
+ 2 => {
+ begin:
+ Background(intro-start);
+ // OK, here we go! After the beep, please give your introduction.
+ Background(beep);
+ Record(priv-callerintros/${CALLERID(num)}:gsm,3);
+ Background(priv-callerintros/${CALLERID(num)});
+ goto home-introduction|s|begin;
+ }
+ t => {
+ goto s|begin;
+ }
+ i => {
+ Background(invalid);
+ goto s|begin;
+ }
+ o => {
+ goto s|begin;
+ }
+}
+
+context homeline-kids {
+ s => {
+ begin:
+ Background(murphy-homeline-kids); // Which Kid? 1=Sean, 2:Eric, 3:Ryan, 4:Kyle, 5:Amber, 6:Alex, 7:Neal
+ }
+ 1 => { // SEAN
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/3/greet.wav&);
+ // &std-priv-exten(Zap/3r2&Zap/5r2,3,35,mtw,telemarket,telemarket);
+ &std-priv-exten(IAX2/seaniax&Zap/5r2,3,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 2 => { // ERIC
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/4/greet.wav&);
+ Voicemail(u4);
+ goto homeline|s|loopback;
+
+ // SetMusicOnHold(erics);
+ // TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ // TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/4/greet.wav&);
+ // &std-priv-exten(Zap/3r2&Zap/5r2,4,35,mtw,telemarket,telemarket);
+ // goto homeline|s|loopback;
+ }
+ 3 => { // RYAN
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/5/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,5,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 4 => { // KYLE
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/6/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,6,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 5 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/7/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,7,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+
+ }
+ 6 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/8/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,8,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 7 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/9/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,9,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ t => {
+ goto s|begin;
+ }
+ i => {
+ Background(invalid);
+ goto s|begin;
+ }
+ o => {
+ goto s|begin;
+ }
+}
+
+context voipworkline {
+ s => {
+ begin:
+ Answer();
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ goto workline|s|loopback;
+ }
+ 7075679201 => {
+ Answer();
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ goto workline|s|loopback;
+ }
+}
+
+context workline {
+ s => {
+ begin:
+ Answer();
+ Wait(1);
+ Set(repeatcount=0);
+ Zapateller(nocallerid);
+// PrivacyManager();
+// if( "${PRIVACYMGRSTATUS}" = "FAILED" )
+// {
+// goto privacyManagerFailed|s|begin;
+// }
+ &fillcidname();
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ loopback:
+ Background(greetings/greeting); //script: Hello
+ Background(murphy-office-intro1); //script: welcome to Steve Murphy's office. If you are dialing
+ // this number because it was on a calling list of any sort, dial 6.
+ // Otherwise, dial 1, and hopefully, you will reach Steve.
+ }
+ 1 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/1/greet.wav&);
+
+ &std-priv-exten(Zap/6&Sip/murf,1,30,mtw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 4 => {
+ VoicemailMain();
+ goto s|loopback;
+ }
+ 6 => {
+ goto telemarket|s|begin;
+ }
+ 793 => { // check the tone recognition
+ Read(zz,,0,,1,0);
+ SayDigits(${zz});
+ }
+ t => {
+ repeatcount=${repeatcount} + 1;
+ if( ${repeatcount} < 3 )
+ {
+ goto s|loopback; // just loopback isn't enough
+ }
+ Hangup();
+ }
+ i => {
+ Background(invalid);
+ goto s|loopback;
+ }
+ o => {
+ Congestion();
+ }
+ fax => {
+ Answer();
+ Dial(Zap/4);
+ }
+}
+
+context dialFWD {
+ ignorepat => 8;
+ ignorepat => 9;
+ _83. => {
+ Set(CALLERID(name)=${FWDCIDNAME});
+ Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2},60,r);
+ Congestion();
+ }
+ _82NXX => {
+ Set(CALLERID(name)=${FWDCIDNAME});
+ Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2},60,r);
+ Congestion();
+ }
+ _92NXX => {
+ Set(CALLERID(name)=${FWDCIDNAME});
+ Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2},60,r);
+ Congestion();
+ }
+}
+
+context dialiaxtel {
+ ignorepat => 8;
+ ignorepat => 9;
+ _81700NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+ _81800NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+ _91700NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+ _91800NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+
+}
+
+context dialgoiax {
+ ignorepat => 9;
+ _93. => {
+ Set(CALLERID(name)="Joe Worker");
+ Dial(IAX2/878201007658:stickyfinger295@server1.goiax.com/${EXTEN:2},60,r);
+ Congestion();
+ }
+
+}
+
+context homefirst {
+ ignorepat => 9;
+ _91NXXNXXXXXX => {
+ &ciddial(${EXTEN:1},${EXTEN:2},30,TW,Zap/1);
+ }
+ _9754XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9574XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9202XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9219XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9254XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9716XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9NXXXXXX => {
+ &ciddial(1707${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9011. => {
+ &ciddial(${EXTEN:1},${EXTEN:1},30,TW,Zap/1);
+ }
+ _9911 => {
+ Dial(Zap/1/911,30,T);
+ }
+ _9411 => {
+ Dial(Zap/1/411,30,T);
+ }
+}
+
+context workfirst {
+ ignorepat => 9;
+ _91NXXNXXXXXX => {
+ &ciddial2(${EXTEN:1},${EXTEN:2},30,TW,Zap/1);
+ }
+ _9754XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9574XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9202XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9219XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9254XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9716XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9NXXXXXX => {
+ &ciddial2(1707${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9911 => {
+ Dial(Zap/1/911,30,T);
+ }
+ _9411 => {
+ Dial(Zap/1/411,30,T);
+ }
+}
+
+context force_cell {
+ ignorepat => 8;
+ _81NXXNXXXXXX => {
+ &ciddial(${EXTEN:1}#,${EXTEN:2},30,TW,Zap/2);
+ }
+ _8754XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8574XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8202XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8219XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8254XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8716XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8NXXXXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8911 => {
+ Dial(Zap/1/911|30|T);
+ }
+ _8411 => {
+ Dial(Zap/1/411|30|T);
+ }
+}
+
+context force_home {
+ ignorepat => 8;
+ _81NXXNXXXXXX => {
+ &ciddial3(${EXTEN:1}#,${EXTEN:2},30,TW,Zap/1);
+ }
+ _8754XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8574XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8202XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8219XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8254XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8716XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8NXXXXXX => {
+ &ciddial3(1707${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8911 => {
+ Dial(Zap/1/911|30|T);
+ }
+ _8411 => {
+ Dial(Zap/1/411|30|T);
+ }
+}
+
+context homeext {
+ ignorepat => 8;
+ ignorepat => 9;
+ includes {
+ parkedcalls;
+ homefirst;
+ force_cell;
+ }
+ s => {
+ loopback:
+ Wait(0);
+ }
+ 1 => {
+ &std-priv-exten(Zap/3&Zap/5,2,35,mtw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 2 => {
+ &std-priv-exten(Zap/6&Zap/5,1,35,mpA(beep3)Tt,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 4 => {
+ VoicemailMain();
+ }
+ 5 => {
+ Record(recording:gsm);
+ Background(recording);
+ }
+ 6 => {
+ Background(recording);
+ }
+ 760 => {
+ DateTime();
+ goto s|loopback;
+ }
+ 761 => {
+ Record(announcement:gsm);
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/announcement.gsm&);
+ goto s|loopback;
+ }
+ 762 => {
+ agi(tts-riddle.agi);
+ Background(gsm/what-time-it-is2);
+ SayUnixTime();
+ goto s|loopback;
+ }
+ 763 => {
+ Set(CALLERID(num)=);
+ Dial(Zap/6r3,35,mptA(beep3)); //results: it should ALWAYS ask for an intro; the intro should not be left behind
+ Hangup();
+ }
+ 764 => {
+ Set(CALLERID(num)=);
+ Dial(Zap/6r3,35,mptnA(beep3)); //results: Don't save the intro; shouldn't anyway if no callerid
+ Hangup();
+ }
+ 765 => {
+ Set(CALLERID(num)=);
+ Dial(Zap/6r3,35,mptNA(beep3)); //results: Don't screen if there's CALLERID; it should screen the call.
+ Hangup();
+ }
+ 766 => {
+ Dial(Zap/6r3,35,mptNA(beep3)); //results: Don't screen if there's CALLERID; it should screen the call.
+ Hangup();
+ }
+ 767 => {
+ Dial(Zap/6r3,35,mptnA(beep3)); //results: Don't save the intro; the interesting case, because callerID should be present.
+ Hangup();
+ }
+ 769 => {
+ Playtones(dial);
+ Wait(2);
+ Playtones(busy);
+ Wait(2);
+ Playtones(ring);
+ Wait(2);
+ Playtones(congestion);
+ Wait(2);
+ Playtones(callwaiting);
+ Wait(2);
+ Playtones(dialrecall);
+ Wait(2);
+ Playtones(record);
+ Wait(2);
+ Playtones(info);
+ Wait(5);
+ Hangup();
+ }
+ 790 => {
+ MeetMe(790,p);
+ }
+ 792 => {
+ goto pageall|s|begin;
+ }
+ 795 => {
+ AGI(wakeup.agi);Congestion();
+ }
+ 544716 => { // Incoming call from FWD
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ goto s|loopback;
+ }
+
+ i => {
+ Background(invalid);
+ goto s|loopback;
+ }
+ o => {
+ goto s|loopback;
+ }
+ t => {
+ Congestion();
+ }
+}
+
+context fromvmhome {
+ 1 => {
+ Dial(Zap/6&Sip/murf|20|Tt);
+ }
+ 2 => {
+ Dial(Zap/3&Zap/5|20|Tt);
+ }
+ _707202XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707219XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707254XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707716XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707754XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707574XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _NXXNXXXXXX => {
+ &ciddial(1${EXTEN},${EXTEN},30,TW,Zap/1);
+ }
+ _1NXXNXXXXXX => { // HAND DIALING
+ &ciddial(${EXTEN},${EXTEN:1},30,TW,Zap/1);
+ }
+ _754XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _574XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _NXXXXXX => {
+ &ciddial(1707${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _911 => {
+ &ciddial(911,911,30,TW,Zap/1);
+ }
+ _411 => {
+ &ciddial(411,411,30,TW,Zap/1);
+ }
+}
+
+context fromvmwork {
+ 1 => {
+ Dial(Zap/6&Sip/murf|20|Tt);
+ }
+ 2 => {
+ Dial(Zap/3&Zap/5|20|Tt);
+ }
+ _707202XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707219XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707254XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707716XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707754XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707574XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _NXXNXXXXXX => {
+ &ciddial(1${EXTEN},${EXTEN},30,TW,Zap/1);
+ }
+ _1NXXNXXXXXX => { // HAND DIALING
+ &ciddial(${EXTEN},${EXTEN:1},30,TW,Zap/1);
+ }
+ _754XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _574XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _NXXXXXX => {
+ &ciddial(1707${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ 911 => {
+ &ciddial(911,911,30,TW,Zap/1);
+ }
+ 411 => {
+ &ciddial(411,411,30,TW,Zap/1);
+ }
+}
+
+context fromSeanUniden {
+ includes
+ {
+ parkedcalls;
+ }
+ 21 => {
+ Dial(IAX2/seaniax,20,T);
+ }
+ _707202XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707219XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707254XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707716XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707754XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707574XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _NXXNXXXXXX => {
+ &ciddial(1${EXTEN},${EXTEN},30,TW,Zap/1);
+ }
+ _1NXXNXXXXXX => {
+ &ciddial(${EXTEN},${EXTEN:1},30,TW,Zap/1);
+ }
+ _754XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _574XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _NXXXXXX => {
+ &ciddial(1707${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ 911 => {
+ &ciddial(911,911,30,TW,Zap/1);
+ }
+ 411 => {
+ &ciddial(411,411,30,TW,Zap/1);
+ }
+}
+
+context workext {
+ ignorepat => 8;
+ ignorepat => 9;
+ includes {
+ parkedcalls;
+ workfirst;
+ force_home;
+ dialFWD;
+ dialiaxtel;
+ dialgoiax;
+ }
+ s => {
+ loopback:
+ Wait(0);
+ }
+ 1 => {
+ Dial(Zap/3&Zap/5,20,tT);
+ }
+ 2 => {
+ Dial(Zap/5&Zap/6,20,tT);
+ }
+ 21 => {
+ Dial(IAX2/seaniax,20,T);
+ }
+ 22 => {
+ Set(CALLERID(num)=1234567890);
+ Set(CALLERID(name)=TestCaller);
+ Dial(Zap/5,20,mP()A(beep)tw);
+ NoOp(here is dialstatus: ${DIALSTATUS}...);
+ goto s|loopback;
+ }
+ 4 => {
+ VoicemailMain();
+ goto s|loopback;
+ }
+ 5 => {
+ Record(recording:gsm);
+ Background(recording);
+ }
+ 6 => {
+ ZapBarge();
+ }
+ 760 => {
+ DateTime();
+ goto s|loopback;
+ }
+ 761 => {
+ ZapBarge();
+ goto s|loopback;
+ }
+ 765 => {
+ Playback(demo-echotest);
+ Echo();
+ Playback(demo-echodone);
+ goto s|loopback;
+ }
+ 766 => {
+ Festival(The other thing to watch is neuro-electronics: the ability to interface technology with our neural system: My wife: Sigrid: has had a cochlear implant since 1996. This once profoundly deaf person now uses the phone: recognizes accents: and listens to movies and recorded books.);
+ goto s|loopback;
+ }
+ 767 => {
+ agi(tts-riddle.agi);
+ Background(gsm/what-time-it-is2);
+ SayUnixTime();
+ goto s|loopback;
+ }
+ 768 => {
+ agi(tts-computer.agi);
+ }
+ 771 => {
+ eagi(eagi-test);
+ agi(my-agi-test);
+ }
+ 772 => {
+ agi(wakeup.agi);
+ }
+ 775 => {
+ if( ${EXTEN}=${EXTEN} )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ if( ${EXTEN}=${LANGUAGE} )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ BackGround(digits/2);
+ }
+ 776 => {
+ Set(TEST=00359889811777);
+ if( ${TEST}= 00359889811777 )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ if( ${TEST}= 00359889811888 )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ Hangup();
+ }
+ 790 => {
+ MeetMe(790,p);
+ }
+ 792 => {
+ goto pageall|s|begin;
+ }
+ 793 => {
+ #include "include1.ael2"
+ }
+ 795 => {
+ AGI(wakeup.agi);
+ Congestion();
+ }
+ 797 => {
+ Set(CONFCIDNA=${CALLERID(name)});
+ Set(CONFCIDNU=${CALLERID(num)});
+ AGI(callall);
+ AGI(submit-announce.agi);
+ Hangup();
+ }
+}
+
+context wakeup {
+ 3 => {
+ Dial(Zap/3|30);
+ }
+ 4 => {
+ Dial(Zap/4|30);
+
+ }
+ 5 => {
+ Dial(Zap/5|30);
+
+ }
+ 6 => {
+ Dial(Zap/6|30);
+
+ }
+ 99 => {
+ Dial(IAX2/murfiaxphone|30);
+ }
+ 97 => {
+ Dial(IAX2/ryaniax|30);
+ }
+ 94 => {
+ Dial(IAX2/seaniax|30);
+ }
+}
+
+context announce-all {
+ s => {
+ begin:
+ MeetMe(5555,dtqp);
+ MeetMeAdmin(5555,K);
+ Hangup();
+ }
+ h => {
+ MeetMeAdmin(5555,K);
+ Hangup();
+ }
+}
+
+// now include the telemarketer torture scripts!
+
+#include "telemarket_torture.ael2"
+
+
diff --git a/trunk/pbx/ael/ael-test/ael-test3/include1.ael2 b/trunk/pbx/ael/ael-test/ael-test3/include1.ael2
new file mode 100644
index 000000000..80c562cb2
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/include1.ael2
@@ -0,0 +1,3 @@
+ NoOp(Hello, this is included from include1.ael2);
+ #include "include2.ael2"
+
diff --git a/trunk/pbx/ael/ael-test/ael-test3/include2.ael2 b/trunk/pbx/ael/ael-test/ael-test3/include2.ael2
new file mode 100644
index 000000000..8d892fb0c
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/include2.ael2
@@ -0,0 +1,4 @@
+ NoOp(This was included from include2.ael2);
+ #include "include3.ael2"
+ #include "include4.ael2"
+
diff --git a/trunk/pbx/ael/ael-test/ael-test3/include3.ael2 b/trunk/pbx/ael/ael-test/ael-test3/include3.ael2
new file mode 100644
index 000000000..3c6c1e3dd
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/include3.ael2
@@ -0,0 +1,2 @@
+ NoOp(This is include3.ael2!);
+ #include "include5.ael2"
diff --git a/trunk/pbx/ael/ael-test/ael-test3/include4.ael2 b/trunk/pbx/ael/ael-test/ael-test3/include4.ael2
new file mode 100644
index 000000000..7d3703a5e
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/include4.ael2
@@ -0,0 +1,2 @@
+ NoOp(This is include4.ael2! Isn't it cool!?!?!?!);
+ NoOp(4 doesn't include anything);
diff --git a/trunk/pbx/ael/ael-test/ael-test3/include5.ael2 b/trunk/pbx/ael/ael-test/ael-test3/include5.ael2
new file mode 100644
index 000000000..0e18983ef
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/include5.ael2
@@ -0,0 +1 @@
+ NoOp(Include5.ael2 doesn't include anything, either!);
diff --git a/trunk/pbx/ael/ael-test/ael-test3/telemarket_torture.ael2 b/trunk/pbx/ael/ael-test/ael-test3/telemarket_torture.ael2
new file mode 100755
index 000000000..ebd8e9f2f
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test3/telemarket_torture.ael2
@@ -0,0 +1,812 @@
+//
+// AN EXCERSIZE IN BAD DIALPLAN DESIGN
+// (What better testing ground than on telemarketers?)
+//
+
+
+// BAD DESIGN: long, boring introductions followed by long, drawn out menus of choices.
+// if they survive to the last option, how will they remember the choices?
+//
+
+// BAD DESIGN: Amateur Recording. Poor voice quality, too quiet.
+// Also, the announcer is definitely not vocally gifted.
+// Also, the long pauses and clicks between the intro
+// and menu choices might lead some to think that
+// the announcements are over, and hang up. Too bad!
+
+// WORSE DESIGN: Instead of using the Background application, the Playback
+// application is used. After taking so much time and trouble
+// to record this material, the caller must listen and enjoy
+// every syllable before they can make an option choice. None
+// of that interrupting with a choice. We want them to savour
+// every word!
+
+// GOOD/BAD, ER INSIDIOUS -- DANGLE A CARROT-- GIVE THE LISTENER A GOOD REASON TO
+// HANG ON AND VOLUNTARILY LISTEN TO THE TORTURE.
+// BUT, DON'T MAKE PROMISES YOU WON'T KEEP!
+
+
+context telemarket {
+ s => {
+ begin:
+ Playback(telemarketer-intro); // ; Script:
+ // Due to the extremely high volume of calls from everything from telemarketers
+ // to Septic System Bacteria vendors, we are asking all such organizations
+ // to remove this number from their call list, or as need be, to add this
+ // number to their No-Call list, whichever is relevent.
+
+ // [THE CARROT:]
+ // We HAVE made some exceptions, and if you wish to see if your organization
+ // has been exempted, please listen to and follow the following prompts.
+ //
+ // Otherwise, please Cease calling this number!
+ //
+ Playback(telemarketer-choices);
+ // if you represent a charitable organization, please dial 1,
+ // if you represent a political organization, please dial 2.
+ // if you represent a polling company, please dial 3,
+ // if you represent a market research organization, please dial 4.
+ // if you represent a magazine or newsletter, please dial 5.
+ // if you represent a commercial organization, please dial 6.
+ }
+ 1 => goto telemarket-charity|s|begin;
+ 2 => goto telemarket-political|s|begin;
+ 3 => goto telemarket-pollster|s|begin;
+ 4 => goto telemarket-research|s|begin;
+ 5 => goto telemarket-magazine|s|begin;
+ 6 => goto telemarket-commercial|s|begin;
+ 7 => goto telemarket-other|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-charity {
+ s => {
+ begin:
+ Playback(telemark-charity-intro);
+ // We have contributed generously to many worthy causes in the past, and will
+ // continue to do so in the future. But we suspect that such organizatons
+ // have sold our name and phone number to each other until we are now hounded
+ // day and night by literally hundreds of such organizations.
+ // Enough is Enough!
+ //
+ // If we have contributed to your cause in the past, we may, perhaps, be disposed to
+ // do so in the future, at our option,
+ // we give no pledges nor make any commitments here.
+ // Send us material via the post if you feel this necessary
+ // but do not even consider email. Any email or further phone calls from your organization
+ // in the future, will be considered an act of aggression, and we will
+ // blacklist your organization for the rest of our natural lives.
+ //
+ // To see if your organization is exempt from these prohibitions, please
+ // comply with the following options.
+ Playback(telemark-charity-choices);
+ // If your organization is disease or genetic defect related, dial 1,
+ // If your organization is handicap related, dial 2.
+ // If your organization is a police or fireman or other similar support entity, please dial 3.
+ // If your organization is a grade school to high school related
+ // fund raiser or other type of activity, please dial 4.
+ // If your organization is a college or univerity or alumnis organization, please dial 5.
+ // If your organization is animal rights or ecology related organization, please dial 6.
+ // If your organization is a political action or candidate support related, please dial 7.
+ // If your organization is a substance abuse related organization or cause, please dial 8.
+ // And any other charity or tax exempt organization should dial 9.
+ }
+ 1 => goto telemarket-char-disease|s|begin;
+ 2 => goto telemarket-char-handicap|s|begin;
+ 3 => goto telemarket-char-police|s|begin;
+ 4 => goto telemarket-char-school|s|begin;
+ 5 => goto telemarket-char-college|s|begin;
+ 6 => goto telemarket-char-animal|s|begin;
+ 7 => goto telemarket-char-candidate|s|begin;
+ 8 => goto telemarket-char-abuse|s|begin;
+ 9 => goto telemarket-char-other|s|begin;
+// BAD DESIGN: referring all timeouts,invalid choices, etc, back to the root of the menu tree will frustrate users no end!
+// WORSE DESIGN: How about having the user have to push a button to repeat the current menu? When a time out could just
+// automatically do it for the user?
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-char-disease {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-handicap {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-police {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-school {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-college {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-animal {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-candidate {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-abuse {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-other {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-sorry {
+ s => {
+ begin:
+ Playback(telemarket-sorry);
+ // Sorry -- your organization is not exempt. Please stop calling us.
+ // Thank you. goodbye.
+ Hangup();
+ }
+}
+
+
+// BAD DESIGN: Hanging up on your audience, no matter what the outcome, is not a nice thing to do!
+
+context telemarket-exception {
+ s => {
+ begin:
+ Playback(telemarket-success);
+ // Congratulations. Your organization IS exempt. Please call us back,
+ // but this time, just act like a normal caller. Thank you. Goodbye.
+ Hangup();
+ }
+}
+
+
+// BAD DESIGN: Making long cascading menu choices is a nasty thing to do to callers!
+// BAD DESIGN: Putting the most frequently encountered items at the end of a list is also a nasty thing to do!
+
+
+// GOOD DESIGN: All rejection notices use a single context. All Acceptance also. To change a rejection to an
+// acceptance, just change the reference from telemarket-sorry to telemarket-exception
+
+
+context telemarket-political {
+ s => {
+ begin:
+ Playback(telemark-polit-intro);
+ // To see if your organization is exempt from our prohibitions,
+ // please follow the following prompts.
+ // please note that they are not in alphabetical order, and you will have to
+ // give them your full attention.
+ Playback(telemark-polit-choices);
+ // if You represent the America First Party, dial 1.
+ // if You represent the American Party, dial 2.
+ // if You represent the American Heritage Party, dial 3.
+ // if You represent the American Independent Party, dial 4.
+ // if You represent the American Nazi Party, dial 5.
+ // if You represent the Pot Party, dial 6.
+ // if You represent the American Reform Party, dial 7.
+ // if You represent the Christian Falenqist Party of America, dial 8.
+ // all others, please dial 9.
+ }
+ 1 => goto telemarket-poli-Am1st|s|begin;
+ 2 => goto telemarket-poli-American|s|begin;
+ 3 => goto telemarket-poli-AmHer|s|begin;
+ 4 => goto telemarket-poli-AmInd|s|begin;
+ 5 => goto telemarket-poli-AmNaz|s|begin;
+ 6 => goto telemarket-poli-Pot|s|begin;
+ 7 => goto telemarket-poli-AmRef|s|begin;
+ 8 => goto telemarket-poli-CFP|s|begin;
+ 9 => goto telemarket-political2|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-political2 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ // Thank you for your patience, and I congratulate you for your persistence.
+ // Just a few more options!
+ //
+ Playback(telemark-polit2-choices);
+ // if You represent the Communist Party USA, dial 1.
+ // if You represent the Constitution Party, dial 2.
+ // if You represent the Family Values Party, dial 3.
+ // if You represent the Freedom Socialist Party, dial 4.
+ // if You represent the Grass Roots Party, dial 5.
+ // if You represent the Green Party, dial 6.
+ // if You represent the Greens Party, dial 7.
+ // if You represent the Independence Party, dial 8.
+ // all others, goto 9.
+ }
+ 1 => goto telemarket-poli-Communist|s|begin;
+ 2 => goto telemarket-poli-Constit|s|begin;
+ 3 => goto telemarket-poli-FamVal|s|begin;
+ 4 => goto telemarket-poli-FreedSoc|s|begin;
+ 5 => goto telemarket-poli-Grassroot|s|begin;
+ 6 => goto telemarket-poli-Green|s|begin;
+ 7 => goto telemarket-poli-Greens|s|begin;
+ 8 => goto telemarket-poli-Independence|s|begin;
+ 9 => goto telemarket-political3|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-political3 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ Playback(telemark-polit3-choices);
+ // if You represent the Independant American Party, dial 1.
+ // if You represent the Labor Party, dial 2.
+ // if You represent the Libertarian Party, dial 3.
+ // if You represent the Light Party, dial 4.
+ // if You represent the Natural Law Party, dial 5.
+ // if You represent the New Party, dial 6.
+ // if You represent the New Union Party, dial 7.
+ // if You represent the Peace and Freedom Party, dial 8.
+ // all others, hang on, dial 9.
+ }
+ 1 => goto telemarket-poli-IndAm|s|begin;
+ 2 => goto telemarket-poli-Labor|s|begin;
+ 3 => goto telemarket-poli-Liber|s|begin;
+ 4 => goto telemarket-poli-Light|s|begin;
+ 5 => goto telemarket-poli-NatLaw|s|begin;
+ 6 => goto telemarket-poli-New|s|begin;
+ 7 => goto telemarket-poli-NewUn|s|begin;
+ 8 => goto telemarket-poli-PeaceFree|s|begin;
+ 9 => goto telemarket-political4|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-political4 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ Playback(telemark-polit4-choices);
+ // if You represent the Prohibition Party, dial 1.
+ // if You represent the Reform Party, dial 2.
+ // if You represent the Revolution , dial 3.
+ // if You represent the Socialist Party USA, dial 4.
+ // if You represent the Socialist Action Party, dial 5.
+ // if You represent the Socialist Equality Party, dial 6.
+ // if You represent the Socialist Labor Party, dial 7.
+ // if You represent the Socialist Workers Party, dial 8.
+ // all others, hang on, and dial 9.
+ }
+ 1 => goto telemarket-poli-Prohib|s|begin;
+ 2 => goto telemarket-poli-Ref|s|begin;
+ 3 => goto telemarket-poli-Revol|s|begin;
+ 4 => goto telemarket-poli-SocPart|s|begin;
+ 5 => goto telemarket-poli-SocAct|s|begin;
+ 6 => goto telemarket-poli-SocEq|s|begin;
+ 7 => goto telemarket-poli-SocLab|s|begin;
+ 8 => goto telemarket-poli-SocWork|s|begin;
+ 9 => goto telemarket-political5|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-political5 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ Playback(telemark-polit5-choices);
+ // if You represent the Southern Party, dial 1.
+ // if You represent the Southern Independence Party, dial 2.
+ // if You represent the US Pacifist Party, dial 3.
+ // if You represent the We the People Party, dial 4.
+ // if You represent the Workers World Party, dial 5.
+ // if You represent the Democratic Party, dial 6.
+ // if You represent the Republican Party, dial 7.
+ // all others, may dial 8.
+ }
+ 1 => goto telemarket-poli-South|s|begin;
+ 2 => goto telemarket-poli-SoInd|s|begin;
+ 3 => goto telemarket-poli-USPac|s|begin;
+ 4 => goto telemarket-poli-WTP|s|begin;
+ 5 => goto telemarket-poli-WWP|s|begin;
+ 6 => goto telemarket-poli-Democrat|s|begin;
+ 7 => goto telemarket-poli-Repub|s|begin;
+ 8 => goto telemarket-poli-other|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-poli-other {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Repub {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Democrat {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-WWP {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-WTP {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-USPac {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SoInd {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-South {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocWork {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocLab {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocEq {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocAct {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocPart {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Revol {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Ref {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Prohib {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-PeaceFree {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-NewUn {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-New {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-NatLaw {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Light {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Liber {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Labor {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-IndAm {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Independence {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Greens {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Green {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Grassroot {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-FreedSoc {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-FamVal {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Constit {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Communist {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-CFP {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-AmRef {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+// BAD DESIGN: Putting in infinite loops in the menus, whether by design or mistake is not nice!
+context telemarket-poli-Pot {
+ s => {
+ begin:
+ goto telemarket-political|s|begin; // will the Pot Party Guys even notice an infinite loop?
+ }
+}
+
+context telemarket-poli-AmNaz {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-AmInd {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-AmHer {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-American {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Am1st {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+
+context telemarket-pollster {
+ s => {
+ begin:
+ Playback(telemark-poll-intro);
+ // I'm sorry-- We are just not available for doing any polling at the moment. So,
+ // please remove us from your list.
+ goto telemarket-sorry|s|begin;
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-research {
+ s => {
+ begin:
+ Playback(telemark-research-intro);
+ // I'd like to say I'd love to help you with your market survey, but that would be a complete
+ // and total lie. I am not interested in helping you with Market Surveys.
+ //
+ // Please remove me from your call list. It just doesn't pay enough. But Thank you.
+ goto telemarket-sorry|s|begin;
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-magazine {
+ s => {
+ begin:
+ Playback(telemark-mag-choices);
+ // If you are calling to see if I would like a NEW free subscription
+ // to your magazine or newsletter, please dial 1.
+ // If you are calling to see if I want to Renew an existing subscription, please dial 2.
+ // If you are representing some publisher, and want my opinion about something, or are doing
+ // some kind of survey, please dial 3.
+ // If you are calling to verify that some previous caller actually called me, and the
+ // verification information is correct, please dial 4.
+ // and if your call purpose doesn't match any of the above, please dial 5.
+ }
+ 1 => goto telemark-mag-new|s|begin;
+ 2 => goto telemark-mag-renew|s|begin;
+ 3 => goto telemark-mag-survey|s|begin;
+ 4 => goto telemark-mag-verify|s|begin;
+ 5 => goto telemark-mag-other|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-new {
+ s => {
+ begin:
+ Playback(telemark-mag-new);
+ // I'm sorry, I'm maxed out, and the answer is NO.
+ // If you really think I'd LOVE to add your publication to the pile I already get,
+ // Send something via the post. Don't call me.
+ // Thank you. bye.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-renew {
+ s => {
+ begin:
+ Playback(telemark-mag-renew);
+ // So, you want to see if I want to Renew, do you? The answer is most likely "YES".
+ //
+ // But, I will not answer a long list of questions over the phone. Send such
+ // categorization info via the post, and stop bothering me over the phone,
+ // if this is what you want.
+ // Do you need verification information? Normally I opt out of such nonsense, if possible.
+ // If not, use whatever of the following you can:
+ // My birth month is October.
+ // My birthplace is Kigali, in Rwanda, in Afica.
+ // My eye color is orange.
+ // All of these are wonderfully false, but I use them regularly for such purposes. Thank you.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-survey {
+ s => {
+ begin:
+ Playback(telemark-mag-survey);
+ // Sorry, I don't have time to answer survey or opinion questions. Find someone
+ // else to help build your marketing database, I guess. Good Luck.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-verify {
+ s => {
+ begin:
+ Playback(telemark-mag-verify);
+ // If you are calling to verify that your own agents aren't ripping you off,
+ // sorry, I can't help you. I opt out whenever I can, mainly because I'm not
+ // paid enough for this kind of thing. I always lie, and I can't remember
+ // what I might have said. Sorry. Goodbye.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-other {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+
+
+// BAD DESIGN: Is it entrapment, when you lure telemarketers to reveal their contact information,
+// Just so you can report them to the FTC/FCC? If it is, isn't it unethical for them
+// to hide their CID (via Anonymous, usually), to hide their identities from the public?
+
+// BTW -- What telemarketer would be stupid enough to fall for this? I'll bet not a single one!
+// For that matter, what telemarketer will be stupid enough to even enter any of this? I'll bet not a single one!
+// (but it was fun messing around).
+
+context telemarket-commercial {
+ s => {
+ begin:
+ Playback(telemark-comm-intro); // Script: Please leave your name, organization, and phone number, plus
+ // a short description of the purpose of your call, at the prompt.
+ // We will do our best to respond to your call! And, in the mean time,
+ // do not forget to add us to your no-call list!
+ Voicemail(u82);
+ goto telemarket-sorry|s|begin;
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-other {
+ s => {
+ begin:
+ Playback(telemark-other-intro);
+ // Please review the previous menu options, and see if you really don't
+ // fit in one of the previous categories.
+ // If you do not, go ahead, and call me again, and let me know what category
+ // I should have included in the above list. I appreciate this. Thank you much!
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
diff --git a/trunk/pbx/ael/ael-test/ael-test4/apptest.ael2 b/trunk/pbx/ael/ael-test/ael-test4/apptest.ael2
new file mode 100644
index 000000000..c477d8531
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test4/apptest.ael2
@@ -0,0 +1,146 @@
+// this is a quick test to see how many of the apps we can spot j options in
+// include this in a macro or extension
+// at this moment, there are 18 apps that accept the j option.
+
+ AddQueueMember(zork,iface,20,j);
+ ADSIProg(sfile);
+ AgentCallbackLogin(agent,s,30@cont);
+ AgentLogin(agent,s);
+ AgentMonitorOutgoing(dcn);
+ AGI(whatever);
+ AlarmReceiver();
+ Answer(2);
+ AppendCDRUserField(value);
+ Authenticate(pword,adjmr);
+ BackGround(filename,snm,eng);
+ BackgroundDetect(filename,20,2,10);
+ Busy(10);
+ ChangeMonitor(fnamebase);
+ ChanIsAvail(Zap/5,sj);
+ ChanSpy(prefix,bg()qrv);
+ Congestion(5);
+ ControlPlayback(filename,10,6,4,0,5,7,j);
+ DateTime(unixtime,tz,fmt);
+ DBdel(fam/key);
+ DBdeltree(fam);
+ DeadAGI(command);
+ Dial(zap/1,45,A()CdD()fgG()hHjL()m()M()nNoprS()tTwW);
+ Dictate(basedir);
+ Directory(cont,dcont,f);
+ DISA(68986869876,context);
+ DumpChan(verblev);
+ DUNDiLookup(90709780978,context,bj);
+ EAGI(command);
+ Echo();
+ EndWhile();
+ Exec(appname,args);
+ ExecIf(expr,app,data);
+ ExecIfTime(*,*,*,*,appname);
+ ExternalIVR(command,arg1);
+ Festival(text);
+ Flash();
+ ForkCDR(v);
+ GetCPEID();
+ Gosub(cont,exten,priority);
+ GosubIf(cond?label);
+ Goto(cont,exten,prior);
+ GotoIf(cond?t:f);
+ GotoIfTime(*,*,*,*?cont,ext,prior);
+ Hangup();
+ HasNewVoicemail(vmbox,var,j);
+ HasVoicemail(vmbox,var,j);
+ IAX2Provision(template);
+ ICES(xmlconfig);
+ ImportVar(nevar@chann,var);
+ Log(NOTICE,message);
+ LookupBlacklist(j);
+ LookupCIDName();
+ Macro(macro,arg1);
+ MacroExit();
+ MacroIf(expr?etc);
+ MailboxExists(mbox@cont,j);
+ Math(v,2+2);
+ MeetMe(5555,aAbcdDeimMpPqrstTovwxX);
+ MeetMeAdmin(5555,e,user);
+ MeetMeCount(5555,var);
+ Milliwatt();
+ MixMonitor(filename,abv()V()W(),command);
+ Monitor(file.fmt,base,mb);
+ MP3Player(location);
+ MusicOnHold(class);
+ NBScat();
+ NoCDR();
+ NoOp(ignored);
+ Page(Zap/1,dq);
+ Park(exten);
+ ParkAndAnnounce(template,5,238,retcont);
+ ParkedCall(exten);
+ PauseQueueMember(queue,zap,j);
+ Pickup(ext@cont);
+ Playback(file,j);
+ PlayTones(arg);
+ PrivacyManager(3,4,j);
+ Progress();
+ Queue(queuename,dhHnrtTwW,http://www.where.what,over,5);
+ Random(30,cont,ext,pri);
+ Read(var,fname,10,skip,2,5);
+ ReadFile(var=file,10);
+ RealTime(fam,2,val,prefix);
+ RealTimeUpdate(fam,2,val,2,newval);
+ Record(file,2,10,anqst);
+ RemoveQueueMember(queuename,iface,j);
+ ResetCDR(wav);
+ RetryDial(annound,4,2);
+ Return();
+ Ringing();
+ RxFAX(fname,caller);
+ SayAlpha(string);
+ SayDigits(string);
+ SayNumber(digits);
+ SayPhonetic(string);
+ SayUnixTime(unixtime,tz,fmt);
+ SendDTMF(digits,10);
+ SendImage(filename);
+ SendText(text,j);
+ SendURL(URL);
+ Set(a=b);
+ SetAMAFlags();
+ SetCallerID(clid,a);
+ SetCallerPres(allowed_passed_screen);
+ SetCDRUserField(value);
+ SetGlobalVar(var=val);
+ SetMusicOnHold(class);
+ SetTransferCapability(SPEECH);
+ SIPAddHeader(header);
+ SIPDtmfMode(inband,info,rfc);
+ SIPGetHeader(var@headername);
+ SMS(name);
+ SoftHangup(zap/1,a);
+ StackPop();
+ StartMusicOnHold(class);
+ StopMonitor();
+ StopMusicOnHold();
+ StopPlayTones();
+ System(command);
+ TestClient(testid);
+ TestServer();
+ Transfer(zap/1,j);
+ TrySystem(command);
+ TxFAX(filename,caller,debug);
+ UnpauseQueueMember(queuename,iface,j);
+ UserEvent(eventanme,body);
+ Verbose(5,message);
+ VMAuthenticate(mailbox@cont,s);
+ VoiceMail(mailbox@cont,bg()suj);
+ VoiceMailMain(mailbox@cont,pg()s);
+ Wait(2);
+ WaitExten(3,m());
+ WaitForRing(2);
+ WaitForSilence(2,y);
+ WaitMusicOnHold(2);
+ While(expr);
+ Zapateller(answer,5);
+ ZapBarge(channel);
+ ZapRAS(arg);
+ ZapScan(group);
+ ZapSendKeypadFacility();
diff --git a/trunk/pbx/ael/ael-test/ael-test4/extensions.ael b/trunk/pbx/ael/ael-test/ael-test4/extensions.ael
new file mode 100644
index 000000000..838aa2489
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test4/extensions.ael
@@ -0,0 +1,8 @@
+context test1
+{
+ test2 =>
+ {
+ #include "apptest.ael2";
+ }
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-test5/extensions.ael b/trunk/pbx/ael/ael-test/ael-test5/extensions.ael
new file mode 100644
index 000000000..e4f703b86
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test5/extensions.ael
@@ -0,0 +1,838 @@
+///////////////////////////////////////////////////////////////////////////////
+// Helpdesk Queue
+
+context hd-queue {
+ s => {
+ NoOp(Add a background sound to tell the user their options);
+ Queue(helpdesk|t);
+ NoOp(Put in options to apologize and send user to voicemail);
+ };
+
+ 0 => goto default|0|1;
+ 1 => {
+ Dial(u41950@ixtlchochitl.zvbwu.edu);
+ Congestion(10);
+ Hangup;
+ };
+};
+
+
+context l903-calling {
+ _9903NXXXXXX => {
+ Realtime(l903_ext,exchange,${EXTEN:4:3},l903_);
+ if ("${l903_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+};
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from houston.conf
+// Converted the extension list to the database
+
+context houston-calling {
+ _9713NXXXXXX => {
+ Realtime(hou_713_ext,exchange,${EXTEN:4:3},hou_713_);
+ if ("${hou_713_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+
+ _9281NXXXXXX => {
+ Realtime(hou_281_ext,exchange,${EXTEN:4:3},hou_281_);
+ if ("${hou_281_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+
+ _9832NXXXXXX => {
+ Realtime(hou_832_ext,exchange,${EXTEN:4:3},hou_832_);
+ if ("${hou_832_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from huntsville.conf
+// Converted the extension list to the database
+
+context huntsville-calling {
+ _9NXXXXXX => {
+ Realtime(hv_ext,exchange,${EXTEN:1:3},hv_);
+ if ("${hv_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+
+ _NXXXXXX => {
+ NoOp(Stripping last four to see what extension we're dialing);
+ Set(LAST4=${EXTEN:3});
+ StripLSD(4);
+ };
+
+ i => Playback(pbx-invalid);
+ h => Hangup;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from macros.conf
+
+macro dialout( number ) {
+ Realtime(call_info,exten,${CALLERIDNUM:5},mon_);
+ if ("${mon_monitor}" = "YES") {
+ Dial(SIP/${number}@zgw1.zvbwu.edu,,wW);
+ Dial(SIP/${number}@zgw2.zvbwu.edu,,wW);
+ } else {
+ Dial(SIP/${number}@zgw1.zvbwu.edu);
+ Dial(SIP/${number}@zgw2.zvbwu.edu);
+ };
+ return;
+};
+
+// Standard extension macro:
+// ${ext} - Extension
+macro stdexten( ext ) {
+ Realtime(sipusers,name,${ext},sip_user_);
+ Realtime(call_info,exten|${ext},info_);
+ if ("${sip_user_name}foo" = "foo") {
+ Wait(1);
+ &dialout(${ext});
+ Congestion(10);
+ Hangup;
+ };
+ NoOp(${CALLERIDNUM});
+ RealtimeUpdate(call_info,exten,${ext},calltrace,${CALLERIDNUM});
+ System(/usr/local/bin/db_update.sh call_info calltrace ${CALLERIDNUM} exten ${ext} &);
+ &checkdnd(${ext});
+ &checkcf(${ext});
+ Realtime(call_info,exten,${CALLERIDNUM:5},mon_);
+ if ("${mon_monitor}" = "YES") {
+ Dial(SIP/${info_forwardto},25,wW);
+ } else {
+ Dial(SIP/${info_forwardto},25);
+ };
+ switch ("${DIALSTATUS}") {
+ case "BUSY":
+ &checkcfb(${ext});
+ break;
+ case "CHANUNAVAIL":
+ Dial(IAX2/asterisk:password@ixtlchochitl.zvbwu.edu/${info_forwardto},25,wW);
+ MailboxExists(${ext});
+// if ("${VMBOXEXISTSSTATUS}" = "FAILED") {
+// Congestion(10);
+// Hangup;
+// };
+ &uvm(${ext});
+ Hangup;
+ break;
+ case "CONGESTION":
+ MailboxExists(${ext});
+ if ("${VMBOXEXISTSSTATUS}" = "FAILED") {
+ Congestion(10);
+ Hangup;
+ };
+ &bvm(${ext});
+ Hangup;
+ break;
+ default:
+ MailboxExists(${ext});
+ if ("${VMBOXEXISTSSTATUS}" = "FAILED") {
+ Congestion(10);
+ Hangup;
+ };
+ &uvm(${ext});
+ Hangup;
+ };
+ Hangup;
+};
+
+macro uvm( ext ) {
+ Dial(SIP/u${ext}@ixtlchochitl.zvbwu.edu);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Congestion(10);
+ Hangup;
+};
+
+macro bvm( ext ) {
+ Dial(SIP/b${ext}@ixtlchochitl.zvbwu.edu);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Congestion(10);
+ Hangup;
+};
+
+macro checkdnd( ext ) {
+ if ("${info_donotdisturb}foo" = "foo") {
+ NoOp(Do Not Disturb is not active);
+ } else
+ &uvm(${ext});
+ return;
+};
+
+macro checkcf( ext ) {
+ if ("${info_forwardto}foo" = "foo")
+ if ("${ext}" = "43974") {
+ Set(info_forwardto=${ext}&SCCP/${ext});
+ } else {
+ Set(info_forwardto=${ext}&SIP/${ext}w);
+ };
+ return;
+};
+
+macro checkcfb( ext ) {
+ if ("${info_forwardbusy}foo" = "foo") {
+ Wait(1);
+ MailboxExists(${ext});
+ if ("${VMBOXEXISTSSTATUS}" = "FAILED") {
+ &dialout(${ext});
+ Hangup;
+ };
+ &bvm(${ext});
+ Hangup;
+ };
+ &stdexten(${info_forwardbusy});
+ return;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from test.conf
+
+context test-include {
+ includes {
+ test-digium;
+ test-sounds;
+ test-phinfo;
+ };
+};
+
+context test-digium {
+ *500 => {
+ Dial(IAX2/guest@misery.digium.com/s@default);
+ Playback(demo-nogo);
+ Hangup;
+ };
+};
+
+context test-sounds {
+ *501 => {
+ Answer;
+ Musiconhold;
+ Wait(1);
+ Hangup;
+ };
+};
+
+context test-phinfo {
+ *505 => {
+ Answer;
+ NoOp(${CALLERIDNUM:5});
+ SayDigits(${CALLERIDNUM:5});
+ Hangup;
+ };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from external.conf
+
+context long-distance {
+ includes {
+ local1;
+ };
+
+ _91XXXXXXXXXX => &dialout(${EXTEN});
+ _9011. => &dialout(${EXTEN});
+};
+
+context local1 {
+ includes {
+ default;
+ };
+
+ 911 => &dialout(911);
+ 9911 => &dialout(9911);
+
+ _9NXXXXXX => goto huntsville-calling|${EXTEN}|1;
+ _936NXXXXXX => {
+ goto 9${EXTEN:3}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _832NXXXXXX => {
+ goto 9${EXTEN}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _713NXXXXXX => {
+ goto 9${EXTEN}|1 ;
+ Congestion(10);
+ Hangup;
+ };
+
+ _281NXXXXXX => {
+ goto 9${EXTEN}|1;
+ Congestion(10);
+ Hangup;
+
+ };
+
+ _NXXNXXXXXX => {
+ goto 9${EXTEN}|1;
+ goto 91${EXTEN}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _91800NXXXXXX => &dialout(${EXTEN});
+ _91866NXXXXXX => &dialout(${EXTEN});
+ _91877NXXXXXX => &dialout(${EXTEN});
+ _91888NXXXXXX => &dialout(${EXTEN});
+ _91900NXXXXXX => &dialout(${EXTEN});
+ _91976NXXXXXX => &dialout(${EXTEN});
+ _9713NXXXXXX => goto houston-calling|${EXTEN}|1;
+ _9281NXXXXXX => goto houston-calling|${EXTEN}|1;
+ _9832NXXXXXX => goto houston-calling|${EXTEN}|1;
+ _9903NXXXXXX => goto l903-calling|${EXTEN}|1;
+
+ _31NXXNXXXXXX => &dialout(${EXTEN});
+
+ h => Hangup;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from internal.conf
+
+context from-scm2 {
+ _4XXXX => {
+ NoOp(DIALING SIP EXTENSION ${EXTEN} - FROM ${CALLERIDNUM});
+ Dial(SIP/${EXTEN},20,wW);
+ Hangup;
+ };
+
+ _6XXXX => {
+ NoOp(DIALING SIP EXTENSION ${EXTEN} - FROM ${CALLERIDNUM});
+ Dial(SIP/${EXTEN},20,wW);
+ Hangup;
+ };
+};
+
+///////////////////////////////////////////////////////////
+// All internal extensions work through the default context
+// Phones that can only make internal calls should be in
+// this context.
+///////////////////////////////////////////////////////////
+
+context default {
+// Include the contexts in the files that allow us to make these phone calls
+ includes {
+ vm-include;
+ apps-include;
+ test-include;
+ };
+
+// ALWAYS have an 'h' extension
+ h => {
+ NoOp(Hangup cause was: ${HANGUPCAUSE});
+ Hangup;
+ };
+
+// We like to hear that we dialed an invalid extension
+ i => Playback(pbx-invalid);
+
+// Dial the operator
+ 0 => &dialout(0);
+
+// Send voicemail calls to the vm-* contexts to be handled
+ voicemail => goto vm-direct|s|1;
+ 5555 => goto vm-direct|s|1;
+ 62100 => goto vm-extension|s|1;
+
+// These are our campus extensions, send them to the macro
+ _6XXXX => &stdexten(${EXTEN});
+ _4XXXX => &stdexten(${EXTEN});
+// These are campus extensions as well, might need to take this out though.
+ _9294XXXX => goto _4XXXX|1;
+ _9496XXXX => goto _6XXXX|1;
+
+// These allows us to dial from the directory in our phone without worrying about dialing 9
+ _936294XXXX => {
+ goto ${EXTEN:5}|1;
+ goto 9${EXTEN:3}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _936496XXXX => {
+ goto ${EXTEN:5}|1;
+ goto 9${EXTEN:3}|1;
+ Congestion(10);
+ Hangup;
+ };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from apps.conf
+
+context apps-include {
+ includes {
+ app-agents;
+ app-dnd;
+ app-callforward;
+ app-calltrace;
+ app-conferences;
+ app-ssd;
+ app-psd;
+ app-idblock;
+ app-helpdesk;
+ app-dictate;
+ app-set-monitor;
+ };
+};
+
+context app-agents {
+ *54 => {
+ Answer;
+ Wait(1);
+ Read(agent_no|agent-user);
+ AgentCallbackLogin(${agent_no}|s${CALLERIDNUM:5});
+ Playback(agent-loginok);
+ Hangup;
+ };
+
+ *55 => {
+ Answer;
+ Wait(1);
+ AgentCallbackLogin(${agent_no});
+ Hangup;
+ };
+};
+
+context app-calltrace {
+// caller dials this to find out the last call missed and possibly call back
+ *69 => goto app-calltrace-perform|s|1;
+};
+
+context app-calltrace-perform {
+ s => {
+ Answer;
+ Wait(1);
+ Background(info-about-last-call);
+ Background(telephone-number);
+ RealTime(call_info|exten|${CALLERIDNUM:5}|ct_);
+ if ("${ct_calltrace}foo" = "foo") {
+ Playback(loligo/from-unknown-caller);
+ Hangup;
+ } else {
+ SayDigits("${ct_calltrace}");
+ Set(TIMEOUT(digit)=3);
+ Set(TIMEOUT(response)=7);
+ Background(loligo/to-call-this-number);
+ Background(press-1);
+ Background(loligo/silence/5);
+ };
+ };
+
+ 1 => goto local1|${ct_calltrace}|1;
+
+ i => {
+ Playback(vm-goodbye);
+ Hangup;
+ };
+
+ t => {
+ Playback(vm-goodbye);
+ Hangup;
+ };
+};
+
+context app-set-monitor {
+ *50 => {
+ Realtime(call_info,exten,${CALLERIDNUM:5},mon_set_);
+ if ("${mon_set_monitor}" = "YES") {
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},monitor|);
+ System(/usr/local/bin/db_update.sh call_info monitor '' exten ${CALLERIDNUM:5} &);
+ } else {
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},monitor,YES);
+ System(/usr/local/bin/db_update.sh call_info monitor YES exten ${CALLERIDNUM:5} &);
+ };
+ NoOp(${mon_set_monitor});
+ Hangup;
+ };
+};
+
+context app-dnd {
+ *78 => {
+ Answer;
+ Wait(1);
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},donotdisturb,YES);
+ System(/usr/local/bin/db_update.sh call_info donotdisturb YES exten ${CALLERIDNUM:5} &);
+ Playback(do-not-disturb);
+ Playback(loligo/activated);
+ Hangup;
+ };
+
+ *79 => {
+ Answer;
+ Wait(1);
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},donotdisturb|);
+ System(/usr/local/bin/db_update.sh call_info donotdisturb '' exten ${CALLERIDNUM:5} &);
+ Playback(do-not-disturb);
+ Playback(loligo/de-activated);
+ Hangup;
+ };
+};
+
+context app-callforward {
+ // forwards calling extension to input number *72{EXTEN}
+ _*72. => {
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},forwardto,${EXTEN:3});
+ System(/usr/local/bin/db_update.sh call_info forwardto ${EXTEN:3} exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-unconditional);
+ Playback(loligo/for);
+ Playback(loligo/extension);
+ SayDigits(${CALLERIDNUM:5});
+ Playback(loligo/is-set-to);
+ SayDigits(${EXTEN:3});
+ Hangup;
+ };
+
+ // prompts for extension to forward to
+ *72 => {
+ Answer;
+ Wait(1);
+ Playback(please-enter-your);
+ Playback(extension);
+ Background(then-press-pound);
+ VMAuthenticate(|s);
+ Background(loligo/ent-target-attendant);
+ Read(toext,loligo/then-press-pound);
+ Wait(1);
+ RealtimeUpdate(call_info,exten,${AUTH_MAILBOX},forwardto,${toext});
+ System(/usr/local/bin/db_update.sh call_info forwardto ${toext} exten ${AUTH_MAILBOX} &);
+ Playback(loligo/call-fwd-unconditional);
+ Playback(loligo/for);
+ Playback(loligo/extension);
+ SayDigits(${AUTH_MAILBOX});
+ Playback(loligo/is-set-to);
+ SayDigits(${toext});
+ Hangup;
+ };
+
+ // cancels dialed extension call forward
+ _*73. => {
+ Realtime(voicemail,mailbox,${EXTEN:3},auth_);
+ Answer;
+ Wait(1);
+ Authenticate(${auth_password});
+ RealtimeUpdate(call_info,exten,${EXTEN:3},forwardto,);
+ System(/usr/local/bin/db_update.sh call_info forwardto '' exten ${EXTEN:3} &);
+ Wait(1);
+ SayDigits(${EXTEN:3});
+ Playback(loligo/call-fwd-cancelled);
+ Hangup;
+ };
+
+ // cancels call forward for calling extension
+ *73 => {
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},forwardto,);
+ System(/usr/local/bin/db_update.sh call_info forwardto '' exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-cancelled);
+ Hangup;
+ };
+
+ // dialed call forward on busy
+ _*90. => {
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},forwardbusy,${EXTEN:3});
+ System(/usr/local/bin/db_update.sh call_info forwardbusy ${EXTEN:3} exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-on-busy);
+ Playback(loligo/for);
+ Playback(loligo/extension);
+ SayDigits(${CALLERIDNUM:5});
+ Playback(loligo/is-set-to);
+ SayDigits(${EXTEN:3});
+ Hangup;
+ };
+
+ // cancels call forward on busy for calling extension
+ *91 => {
+ RealtimeUpdate(call_info,exten,${CALLERIDNUM:5},forwardbusy|);
+ System(/usr/local/bin/db_update.sh call_info forwardbusy '' exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-on-busy);
+ Playback(loligo/de-activated);
+ Hangup;
+ };
+
+ h => Hangup;
+};
+
+context app-idblock {
+ _*67. => {
+ Set(CALLERID(name)=Anonymous);
+ &stdexten(${EXTEN:3});
+ };
+};
+
+context app-dictate {
+ *1 => {
+ Dictate();
+ Hangup;
+ };
+};
+
+context app-ssd {
+// *59 <xx> <y.> - Set system speed dial <xx> to digits <y.>
+// *59 <xx> 0 - Delete system speed dial <xx>
+// *59 <xx> - Review system speed dial <xx>
+// *1xx - Dial speed dial <xx>
+ _*59XXX. => {
+ Answer;
+ RealtimeUpdate(ssd,sd,${EXTEN:3:2},extension,${EXTEN:5});
+ System(/usr/local/bin/db_update.sh systemsd extension ${EXTEN:5} sd ${EXTEN:3:2} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-set-to);
+ SayDigits(${EXTEN:5});
+ Hangup;
+ };
+
+ _*59XX0 => {
+ Answer;
+ RealtimeUpdate(ssd,sd,${EXTEN:3:2},extension,);
+ System(/usr/local/bin/db_update.sh systemsd extension '' sd ${EXTEN:3:2} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-cleared);
+ Hangup;
+ };
+
+ _*59XX => {
+ Answer;
+ Realtime(ssd,sd,${EXTEN:3},ssd_);
+ if ("${ssd_extension}foo" = "foo") {
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-set-to);
+ SayDigits(${ssd_extension});
+ Hangup;
+ };
+
+ // NTC = number to call
+ _*1XX => {
+ Realtime(ssd,sd,${EXTEN:2},ssd_);
+ if ("${ssd_extension}foo" = "foo") {
+ Answer;
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ &stdexten(${ssd_extension});
+ Congestion(10);
+ Hangup;
+ };
+};
+
+macro check-psd-exists ( ext ) {
+ Realtime(psd,extension,${ext},psd_);
+ if ("${psd_extension}foo" = "foo") {
+ System(/usr/local/bin/create_psd.sh ${ext});
+ } else
+ NoOp(PSD set for ${ext});
+ return;
+};
+
+context app-psd {
+// *89 <xx> <y.> - Set personal speed dial <xx> to digits <y.>
+// *89 <xx> 0 - Delete personal speed dial <xx>
+// *89 <xx> - Review personal speed dial <xx>
+// *2xx - Dial personal speed dial <xx>
+ _*89XXX. => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Answer;
+ RealtimeUpdate(psd,extension,${CALLERIDNUM:5},s${EXTEN:3:2},${EXTEN:5});
+ System(/usr/local/bin/db_update.sh personalsd s${EXTEN:3:2} ${EXTEN:5} extension ${CALLERIDNUM:5} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-set-to);
+ SayDigits(${EXTEN:5});
+ Hangup;
+ };
+
+ _*89XX0 => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Answer;
+ RealtimeUpdate(psd|extension|${CALLERIDNUM:5}|s${EXTEN:3:2}|);
+ System(/usr/local/bin/db_update.sh personalsd s${EXTEN:3:2} '' extension ${CALLERIDNUM:5} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-cleared);
+ Hangup;
+ };
+
+ _*89XX => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Answer;
+ Realtime(psd|extension|${CALLERIDNUM:5}|psd_);
+ Wait(1);
+ if ("${psd_s${EXTEN:3:2}}foo" = "foo") {
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-set-to);
+ SayDigits(${psd_s${EXTEN:3:2}});
+ Hangup;
+ };
+
+ // NTC = number to call
+ _*2XX => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Realtime(psd|extension|${CALLERIDNUM:5}|psd_);
+ if ("${psd_s${EXTEN:2}}foo" = "foo") {
+ Answer;
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ &stdexten(${psd_s${EXTEN:2}});
+ Congestion(10);
+ Hangup;
+ };
+};
+
+context app-helpdesk {
+ *4357 => {
+ &stdexten(41950);
+ Congestion;
+ };
+};
+
+context app-conferences {
+// waiting for room number announcement
+ *86 => goto app-conf-hidden|s|1;
+};
+
+context app-conf-hidden {
+ s => {
+ Wait(1);
+ Playback(loligo/please-enter-the);
+ Playback(loligo/extension);
+ read(roomtoenter,loligo/then-press-pound);
+ Meetme(${roomtoenter});
+ Waitexten(8);
+ Hangup;
+ };
+
+ _1. => Meetme(${EXTEN});
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from vm.conf:
+
+context vm-include {
+ includes {
+ vm-direct;
+ vm-extension;
+ vm-directory;
+ };
+};
+
+context vm-direct {
+ s => {
+ Dial(SIP/5555@ixtlchochitl.zvbwu.edu,20);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Playback(extra/pls-try-call-later);
+ Congestion(10);
+ Hangup;
+ };
+};
+
+context vm-extension {
+ s => {
+ Dial(SIP/62100@ixtlchochitl.zvbwu.edu,20);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Playback(extra/pls-try-call-later);
+ Congestion(10);
+ Hangup;
+ };
+};
+
+context vm-directory {
+ 5556 => {
+ Dial(SIP/5556@ixtlchochitl.zvbwu.edu);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Playback(extra/pls-try-call-later);
+ Congestion(10);
+ Hangup;
+ };
+};
diff --git a/trunk/pbx/ael/ael-test/ael-test6/extensions.ael b/trunk/pbx/ael/ael-test/ael-test6/extensions.ael
new file mode 100644
index 000000000..13ebf67fd
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test6/extensions.ael
@@ -0,0 +1,833 @@
+///////////////////////////////////////////////////////////////////////////////
+// Helpdesk Queue
+
+context hd-queue {
+ s => {
+ NoOp(Add a background sound to tell the user their options);
+ Queue(helpdesk|t);
+ NoOp(Put in options to apologize and send user to voicemail);
+ };
+
+ 0 => goto default|0|1;
+ 1 => {
+ Dial(u41950@svm1.shsu.edu);
+ Congestion(10);
+ Hangup;
+ };
+};
+
+
+context l903-calling {
+ _9903NXXXXXX => {
+ Realtime(l903_ext|exchange|${EXTEN:4:3}|l903_);
+ if ("${l903_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+};
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from houston.conf
+// Converted the extension list to the database
+
+context houston-calling {
+ _9713NXXXXXX => {
+ Realtime(hou_713_ext|exchange|${EXTEN:4:3}|hou_713_);
+ if ("${hou_713_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+
+ _9281NXXXXXX => {
+ Realtime(hou_281_ext|exchange|${EXTEN:4:3}|hou_281_);
+ if ("${hou_281_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+
+ _9832NXXXXXX => {
+ Realtime(hou_832_ext|exchange|${EXTEN:4:3}|hou_832_);
+ if ("${hou_832_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from huntsville.conf
+// Converted the extension list to the database
+
+context huntsville-calling {
+ _9NXXXXXX => {
+ Realtime(hv_ext|exchange|${EXTEN:1:3}|hv_);
+ if ("${hv_exchange}foo" = "foo") {
+ Playback(num-outside-area);
+ SayDigits(1);
+ Playback(and-area-code);
+ Playback(before-the-number);
+ Hangup;
+ };
+ &dialout(${EXTEN});
+ Congestion(10);
+ Hangup;
+ };
+
+ _NXXXXXX => {
+ NoOp(Stripping last four to see what extension we're dialing);
+ Set(LAST4=${EXTEN:3});
+ StripLSD(4);
+ };
+
+ i => Playback(pbx-invalid);
+ h => Hangup;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from macros.conf
+
+macro dialout( number ) {
+ Realtime(call_info|exten|${CALLERIDNUM:5}|mon_);
+ if ("${mon_monitor}" = "YES") {
+ Dial(SIP/${number}@sgw1.shsu.edu,,wW);
+ Dial(SIP/${number}@sgw2.shsu.edu,,wW);
+ } else {
+ Dial(SIP/${number}@sgw1.shsu.edu);
+ Dial(SIP/${number}@sgw2.shsu.edu);
+ };
+};
+
+// Standard extension macro:
+// ${ext} - Extension
+macro stdexten( ext ) {
+ Realtime(sipusers|name|${ext}|sip_user_);
+ Realtime(call_info|exten|${ext}|info_);
+ if ("${sip_user_name}foo" = "foo") {
+ Wait(1);
+ &dialout(${ext});
+ Congestion(10);
+ Hangup;
+ };
+ NoOp(${CALLERIDNUM});
+ RealtimeUpdate(call_info|exten|${ext}|calltrace|${CALLERIDNUM});
+ System(/usr/local/bin/db_update.sh call_info calltrace ${CALLERIDNUM} exten ${ext} &);
+ &checkdnd(${ext});
+ &checkcf(${ext});
+ Realtime(call_info|exten|${CALLERIDNUM:5}|mon_);
+ if ("${mon_monitor}" = "YES") {
+ Dial(SIP/${info_forwardto},25,wW);
+ } else {
+ Dial(SIP/${info_forwardto},25);
+ };
+ switch ("${DIALSTATUS}") {
+ case "BUSY":
+ &checkcfb(${ext});
+ break;
+ case "CHANUNAVAIL":
+ Dial(IAX2/asterisk:password@scm2.shsu.edu/${info_forwardto},25,wW);
+ MailboxExists(${ext});
+// if ("${VMBOXEXISTSSTATUS}" = "FAILED") {
+// Congestion(10);
+// Hangup;
+// };
+ &uvm(${ext});
+ Hangup;
+ break;
+ case "CONGESTION":
+ MailboxExists(${ext});
+ if ("$(VMBOXEXISTSSTATUS}" = "FAILED") {
+ Congestion(10);
+ Hangup;
+ };
+ &bvm(${ext});
+ Hangup;
+ break;
+ default:
+ MailboxExists(${ext});
+ if ("$(VMBOXEXISTSSTATUS}" = "FAILED") {
+ Congestion(10);
+ Hangup;
+ };
+ &uvm(${ext});
+ Hangup;
+ };
+ Hangup;
+};
+
+macro uvm( ext ) {
+ Dial(SIP/u${ext}@svm1.shsu.edu);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Congestion(10);
+ Hangup;
+};
+
+macro bvm( ext ) {
+ Dial(SIP/b${ext}@svm1.shsu.edu);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Congestion(10);
+ Hangup;
+};
+
+macro checkdnd( ext ) {
+ if ("${info_donotdisturb}foo" = "foo") {
+ NoOp(Do Not Disturb is not active);
+ } else
+ &uvm(${ext});
+};
+
+macro checkcf( ext ) {
+ if ("${info_forwardto}foo" = "foo")
+ if ("${ext}" = "43974") {
+ Set(info_forwardto=${ext}&SCCP/${ext});
+ } else {
+ Set(info_forwardto=${ext}&SIP/${ext}w);
+ };
+};
+
+macro checkcfb( ext ) {
+ if ("${info_forwardbusy}foo" = "foo") {
+ Wait(1);
+ MailboxExists(${ext});
+ if ("$(VMBOXEXISTSSTATUS}" = "FAILED") {
+ &dialout(${ext});
+ Hangup;
+ };
+ &bvm(${ext});
+ Hangup;
+ };
+ &stdexten(${info_forwardbusy});
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from test.conf
+
+context test-include {
+ includes {
+ test-digium;
+ test-sounds;
+ test-phinfo;
+ };
+};
+
+context test-digium {
+ *500 => {
+ Dial(IAX2/guest@misery.digium.com/s@default);
+ Playback(demo-nogo);
+ Hangup;
+ };
+};
+
+context test-sounds {
+ *501 => {
+ Answer;
+ Musiconhold;
+ Wait(1);
+ Hangup;
+ };
+};
+
+context test-phinfo {
+ *505 => {
+ Answer;
+ NoOp(${CALLERIDNUM:5});
+ SayDigits(${CALLERIDNUM:5});
+ Hangup;
+ };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from external.conf
+
+context long-distance {
+ includes {
+ local1;
+ };
+
+ _91XXXXXXXXXX => &dialout(${EXTEN});
+ _9011. => &dialout(${EXTEN});
+};
+
+context local1 {
+ includes {
+ default;
+ };
+
+ 911 => &dialout(911);
+ 9911 => &dialout(9911);
+
+ _9NXXXXXX => goto huntsville-calling|${EXTEN}|1;
+ _936NXXXXXX => {
+ Goto 9${EXTEN:3}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _832NXXXXXX => {
+ goto 9${EXTEN}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _713NXXXXXX => {
+ goto 9${EXTEN}|1 ;
+ Congestion(10);
+ Hangup;
+ };
+
+ _281NXXXXXX => {
+ goto 9${EXTEN}|1;
+ Congestion(10);
+ Hangup;
+
+ };
+
+ _NXXNXXXXXX => {
+ goto 9${EXTEN}|1;
+ goto 91${EXTEN}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _91800NXXXXXX => &dialout(${EXTEN});
+ _91866NXXXXXX => &dialout(${EXTEN});
+ _91877NXXXXXX => &dialout(${EXTEN});
+ _91888NXXXXXX => &dialout(${EXTEN});
+ _91900NXXXXXX => &dialout(${EXTEN});
+ _91976NXXXXXX => &dialout(${EXTEN});
+ _9713NXXXXXX => goto houston-calling|${EXTEN}|1;
+ _9281NXXXXXX => goto houston-calling|${EXTEN}|1;
+ _9832NXXXXXX => goto houston-calling|${EXTEN}|1;
+ _9903NXXXXXX => goto l903-calling|${EXTEN}|1;
+
+ _31NXXNXXXXXX => &dialout(${EXTEN});
+
+ h => Hangup;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from internal.conf
+
+context from-scm2 {
+ _4XXXX => {
+ NoOp(DIALING SIP EXTENSION ${EXTEN} - FROM ${CALLERIDNUM});
+ Dial(SIP/${EXTEN},20,wW);
+ Hangup;
+ };
+
+ _6XXXX => {
+ NoOp(DIALING SIP EXTENSION ${EXTEN} - FROM ${CALLERIDNUM});
+ Dial(SIP/${EXTEN},20,wW);
+ Hangup;
+ };
+};
+
+///////////////////////////////////////////////////////////
+// All internal extensions work through the default context
+// Phones that can only make internal calls should be in
+// this context.
+///////////////////////////////////////////////////////////
+
+context default {
+// Include the contexts in the files that allow us to make these phone calls
+ includes {
+ vm-include;
+ apps-include;
+ test-include;
+ };
+
+// ALWAYS have an 'h' extension
+ h => {
+ NoOp(Hangup cause was: ${HANGUPCAUSE});
+ Hangup;
+ };
+
+// We like to hear that we dialed an invalid extension
+ i => Playback(pbx-invalid);
+
+// Dial the operator
+ 0 => &dialout(0);
+
+// Send voicemail calls to the vm-* contexts to be handled
+ voicemail => goto vm-direct|s|1;
+ 5555 => goto vm-direct|s|1;
+ 62100 => goto vm-extension|s|1;
+
+// These are our campus extensions, send them to the macro
+ _6XXXX => &stdexten(${EXTEN});
+ _4XXXX => &stdexten(${EXTEN});
+// These are campus extensions as well, might need to take this out though.
+ _9294XXXX => goto _4XXXX|1;
+ _9496XXXX => goto _6XXXX|1;
+
+// These allows us to dial from the directory in our phone without worrying about dialing 9
+ _936294XXXX => {
+ goto ${EXTEN:5}|1;
+ goto 9${EXTEN:3}|1;
+ Congestion(10);
+ Hangup;
+ };
+
+ _936496XXXX => {
+ goto ${EXTEN:5}|1;
+ goto 9${EXTEN:3}|1;
+ Congestion(10);
+ Hangup;
+ };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from apps.conf
+
+context apps-include {
+ includes {
+ app-agents;
+ app-dnd;
+ app-callforward;
+ app-calltrace;
+ app-conferences;
+ app-ssd;
+ app-psd;
+ app-idblock;
+ app-helpdesk;
+ app-dictate;
+ app-set-monitor;
+ };
+};
+
+context app-agents {
+ *54 => {
+ Answer;
+ Wait(1);
+ Read(agent_no|agent-user);
+ AgentCallbackLogin(${agent_no}|s${CALLERIDNUM:5});
+ Playback(agent-loginok);
+ Hangup;
+ };
+
+ *55 => {
+ Answer;
+ Wait(1);
+ AgentCallbackLogin(${agent_no});
+ Hangup;
+ };
+};
+
+context app-calltrace {
+// caller dials this to find out the last call missed and possibly call back
+ *69 => goto app-calltrace-perform|s|1;
+};
+
+context app-calltrace-perform {
+ s => {
+ Answer;
+ Wait(1);
+ Background(info-about-last-call);
+ Background(telephone-number);
+ RealTime(call_info|exten|${CALLERIDNUM:5}|ct_);
+ if ("${ct_calltrace}foo" = "foo") {
+ Playback(loligo/from-unknown-caller);
+ Hangup;
+ } else {
+ SayDigits("${ct_calltrace}");
+ Set(TIMEOUT(digit)=3);
+ Set(TIMEOUT(response)=7);
+ Background(loligo/to-call-this-number);
+ Background(press-1);
+ Background(loligo/silence/5);
+ };
+ };
+
+ 1 => goto local1|${ct_calltrace}|1;
+
+ i => {
+ Playback(vm-goodbye);
+ Hangup;
+ };
+
+ t => {
+ Playback(vm-goodbye);
+ Hangup;
+ };
+};
+
+context app-set-monitor {
+ *50 => {
+ Realtime(call_info|exten|${CALLERIDNUM:5}|mon_set_);
+ if ("${mon_set_monitor}" = "YES") {
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|monitor|);
+ System(/usr/local/bin/db_update.sh call_info monitor '' exten ${CALLERIDNUM:5} &);
+ } else {
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|monitor|YES);
+ System(/usr/local/bin/db_update.sh call_info monitor YES exten ${CALLERIDNUM:5} &);
+ };
+ NoOp(${mon_set_monitor});
+ Hangup;
+ };
+};
+
+context app-dnd {
+ *78 => {
+ Answer;
+ Wait(1);
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|donotdisturb|YES);
+ System(/usr/local/bin/db_update.sh call_info donotdisturb YES exten ${CALLERIDNUM:5} &);
+ Playback(do-not-disturb);
+ Playback(loligo/activated);
+ Hangup;
+ };
+
+ *79 => {
+ Answer;
+ Wait(1);
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|donotdisturb|);
+ System(/usr/local/bin/db_update.sh call_info donotdisturb '' exten ${CALLERIDNUM:5} &);
+ Playback(do-not-disturb);
+ Playback(loligo/de-activated);
+ Hangup;
+ };
+};
+
+context app-callforward {
+ // forwards calling extension to input number *72{EXTEN}
+ _*72. => {
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|forwardto|${EXTEN:3});
+ System(/usr/local/bin/db_update.sh call_info forwardto ${EXTEN:3} exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-unconditional);
+ Playback(loligo/for);
+ Playback(loligo/extension);
+ SayDigits(${CALLERIDNUM:5});
+ Playback(loligo/is-set-to);
+ SayDigits(${EXTEN:3});
+ Hangup;
+ };
+
+ // prompts for extension to forward to
+ *72 => {
+ Answer;
+ Wait(1);
+ Playback(please-enter-your);
+ Playback(extension);
+ Background(then-press-pound);
+ VMAuthenticate(|s);
+ Background(loligo/ent-target-attendant);
+ Read(toext,loligo/then-press-pound);
+ Wait(1);
+ RealtimeUpdate(call_info|exten|${AUTH_MAILBOX}|forwardto|${toext});
+ System(/usr/local/bin/db_update.sh call_info forwardto ${toext} exten ${AUTH_MAILBOX} &);
+ Playback(loligo/call-fwd-unconditional);
+ Playback(loligo/for);
+ Playback(loligo/extension);
+ SayDigits(${AUTH_MAILBOX});
+ Playback(loligo/is-set-to);
+ SayDigits(${toext});
+ Hangup;
+ };
+
+ // cancels dialed extension call forward
+ _*73. => {
+ Realtime(voicemail|mailbox|${EXTEN:3}|auth_);
+ Answer;
+ Wait(1);
+ Authenticate(${auth_password});
+ RealtimeUpdate(call_info|exten|${EXTEN:3}|forwardto|);
+ System(/usr/local/bin/db_update.sh call_info forwardto '' exten ${EXTEN:3} &);
+ Wait(1);
+ SayDigits(${EXTEN:3});
+ Playback(loligo/call-fwd-cancelled);
+ Hangup;
+ };
+
+ // cancels call forward for calling extension
+ *73 => {
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|forwardto|);
+ System(/usr/local/bin/db_update.sh call_info forwardto '' exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-cancelled);
+ Hangup;
+ };
+
+ // dialed call forward on busy
+ _*90. => {
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|forwardbusy|${EXTEN:3});
+ System(/usr/local/bin/db_update.sh call_info forwardbusy ${EXTEN:3} exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-on-busy);
+ Playback(loligo/for);
+ Playback(loligo/extension);
+ SayDigits(${CALLERIDNUM:5});
+ Playback(loligo/is-set-to);
+ SayDigits(${EXTEN:3});
+ Hangup;
+ };
+
+ // cancels call forward on busy for calling extension
+ *91 => {
+ RealtimeUpdate(call_info|exten|${CALLERIDNUM:5}|forwardbusy|);
+ System(/usr/local/bin/db_update.sh call_info forwardbusy '' exten ${CALLERIDNUM:5} &);
+ Answer;
+ Wait(1);
+ Playback(loligo/call-fwd-on-busy);
+ Playback(loligo/de-activated);
+ Hangup;
+ };
+
+ h => Hangup;
+};
+
+context app-idblock {
+ _*67. => {
+ Set(CALLERID(name)=Anonymous);
+ &stdexten(${EXTEN:3});
+ };
+};
+
+context app-dictate {
+ *1 => {
+ Dictate();
+ Hangup;
+ };
+};
+
+context app-ssd {
+// *59 <xx> <y.> - Set system speed dial <xx> to digits <y.>
+// *59 <xx> 0 - Delete system speed dial <xx>
+// *59 <xx> - Review system speed dial <xx>
+// *1xx - Dial speed dial <xx>
+ _*59XXX. => {
+ Answer;
+ RealtimeUpdate(ssd|sd|${EXTEN:3:2}|extension|${EXTEN:5});
+ System(/usr/local/bin/db_update.sh systemsd extension ${EXTEN:5} sd ${EXTEN:3:2} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-set-to);
+ SayDigits(${EXTEN:5});
+ Hangup;
+ };
+
+ _*59XX0 => {
+ Answer;
+ RealtimeUpdate(ssd|sd|${EXTEN:3:2}|extension|);
+ System(/usr/local/bin/db_update.sh systemsd extension '' sd ${EXTEN:3:2} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-cleared);
+ Hangup;
+ };
+
+ _*59XX => {
+ Answer;
+ Realtime(ssd|sd|${EXTEN:3}|ssd_);
+ if ("${ssd_extension}foo" = "foo") {
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-set-to);
+ SayDigits(${ssd_extension});
+ Hangup;
+ };
+
+ // NTC = number to call
+ _*1XX => {
+ Realtime(ssd|sd|${EXTEN:2}|ssd_);
+ if ("${ssd_extension}foo" = "foo") {
+ Answer;
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ &stdexten(${ssd_extension});
+ Congestion(10);
+ Hangup;
+ };
+};
+
+macro check-psd-exists ( ext ) {
+ Realtime(psd|extension|${ext}|psd_);
+ if ("${psd_extension}foo" = "foo") {
+ System(/usr/local/bin/create_psd.sh ${ext});
+ } else
+ NoOp(PSD set for ${ext});
+};
+
+context app-psd {
+// *89 <xx> <y.> - Set personal speed dial <xx> to digits <y.>
+// *89 <xx> 0 - Delete personal speed dial <xx>
+// *89 <xx> - Review personal speed dial <xx>
+// *2xx - Dial personal speed dial <xx>
+ _*89XXX. => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Answer;
+ RealtimeUpdate(psd|extension|${CALLERIDNUM:5}|s${EXTEN:3:2}|${EXTEN:5});
+ System(/usr/local/bin/db_update.sh personalsd s${EXTEN:3:2} ${EXTEN:5} extension ${CALLERIDNUM:5} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-set-to);
+ SayDigits(${EXTEN:5});
+ Hangup;
+ };
+
+ _*89XX0 => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Answer;
+ RealtimeUpdate(psd|extension|${CALLERIDNUM:5}|s${EXTEN:3:2}|);
+ System(/usr/local/bin/db_update.sh personalsd s${EXTEN:3:2} '' extension ${CALLERIDNUM:5} &);
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/has-been-cleared);
+ Hangup;
+ };
+
+ _*89XX => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Answer;
+ Realtime(psd|extension|${CALLERIDNUM:5}|psd_);
+ Wait(1);
+ if ("${psd_s${EXTEN:3:2}}foo" = "foo") {
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:3:2});
+ Playback(loligo/is-set-to);
+ SayDigits(${psd_s${EXTEN:3:2}});
+ Hangup;
+ };
+
+ // NTC = number to call
+ _*2XX => {
+ &check-psd-exists(${CALLERIDNUM:5});
+ Realtime(psd|extension|${CALLERIDNUM:5}|psd_);
+ if ("${psd_s${EXTEN:2}}foo" = "foo") {
+ Answer;
+ Wait(1);
+ Playback(loligo/speed-dial);
+ SayDigits(${EXTEN:2});
+ Playback(loligo/is-not-set);
+ Hangup;
+ };
+ &stdexten(${psd_s${EXTEN:2}});
+ Congestion(10);
+ Hangup;
+ };
+};
+
+context app-helpdesk {
+ *4357 => {
+ &stdexten(41950);
+ Congestion;
+ };
+};
+
+context app-conferences {
+// waiting for room number announcement
+ *86 => goto app-conf-hidden|s|1;
+};
+
+context app-conf-hidden {
+ s => {
+ Wait(1);
+ Playback(loligo/please-enter-the);
+ Playback(loligo/extension);
+ read(roomtoenter,loligo/then-press-pound);
+ Meetme(${roomtoenter});
+ Waitexten(8);
+ Hangup;
+ };
+
+ _1. => Meetme(${EXTEN});
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Extensions pulled from vm.conf:
+
+context vm-include {
+ includes {
+ vm-direct;
+ vm-extension;
+ vm-directory;
+ };
+};
+
+context vm-direct {
+ s => {
+ Dial(SIP/5555@svm1.shsu.edu,20);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Playback(extra/pls-try-call-later);
+ Congestion(10);
+ Hangup;
+ };
+};
+
+context vm-extension {
+ s => {
+ Dial(SIP/62100@svm1.shsu.edu,20);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Playback(extra/pls-try-call-later);
+ Congestion(10);
+ Hangup;
+ };
+};
+
+context vm-directory {
+ 5556 => {
+ Dial(SIP/5556@svm1.shsu.edu);
+ Playback(im-sorry);
+ Playback(voice-mail-system);
+ Playback(down);
+ Playback(extra/pls-try-call-later);
+ Congestion(10);
+ Hangup;
+ };
+};
diff --git a/trunk/pbx/ael/ael-test/ael-test7/extensions.ael b/trunk/pbx/ael/ael-test/ael-test7/extensions.ael
new file mode 100644
index 000000000..27ed374f5
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test7/extensions.ael
@@ -0,0 +1,460 @@
+//
+// Example AEL config file
+//
+
+globals {
+ CONSOLE=Console/dsp;
+ TRUNKMSD=0; //MSD digits to strip (usually 1 or 0)
+ TRUNCPROTO=SIP;
+ TRUNK=sunrocket;
+ PSTN=pstn-spa3k;
+ PSTNPROTO=SIP;
+ TARIOPROTO=SIP;
+ TARIO=tario;
+ CPPROTO=SIP;
+ CPACKET1=callpacket1;
+ CPACKET2=callpacket2;
+ SELLVOIP=1577040314;
+ SVPROTO=IAX2;
+};
+
+
+macro stdexten (ext , dev ) {
+ PrivacyManager(3,10);
+ if("${PRIVACYMGRSTATUS}" = "FAILED") {
+ Playback(vm-goodbye);
+ Hangup();
+ };
+
+ AGI(calleridnamelookup.agi);
+ Dial(${dev}/${ext},30,t);
+ switch(${DIALSTATUS}) {
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ };
+ catch a {
+ VoiceMailMain(${ext});
+ return;
+ };
+};
+
+macro announce_minutes(minutes) {
+ Playback(vm-youhave);
+ SayNumber(${minutes});
+ Playback(vm-minutes);
+ Wait(1);
+};
+
+// Check if given provider allows only some free minutes per month
+// and announce number of free minutes remaining.
+// The limit will be reset monthly by cron job.
+// The macro sets the following variables:
+// MINUTES_LIMIT - number of free minutes per month
+// MINUTES_USED - number of free minutes used in the current month
+// PROVIDER - provider name
+
+macro checkanddial(prov,proto,ext,arg1,arg2,arg3,arg4) {
+ Set(MINUTES_LIMIT=0);
+ Set(MINUTES_USED=0);
+ Set(PROVIDER=${prov});
+
+ if(${DB_EXISTS(Provider/${prov}/used)})
+ Set(MINUTES_USED=${DB_RESULT});
+
+ country_c = 0;
+ switch(${LEN(${ext})}) { //assuming all international numbers are 11 digits long.
+ case 10: //NXXNXXXXXX
+ country_c=1;
+ break;
+ case 11: //XNXXNXXXXXX
+ country_c = ${ext:0:1};
+ break;
+ default: //011XNXXNXXXXXX
+ country_c = ${ext:3:1};
+ break;
+ };
+
+ if("${prov}" = "${TRUNK}" & ${country_c} != 1) { // SunRocket international calls
+ Set(MINUTES_LIMIT=${DB(Provider/${prov}/limit)});
+ &announce_minutes($[${MINUTES_LIMIT} - ${MINUTES_USED}]);
+ };
+ if("${prov}" = "${CPACKET1}" | "${prov}" = "${CPACKET2}") { // Callpacket has a limit on domestic calls
+ Set(MINUTES_LIMIT=${DB(Provider/${prov}/limit)});
+ &announce_minutes($[${MINUTES_LIMIT} - ${MINUTES_USED}]);
+ };
+ DeadAGI(dial.agi,${proto}/${ext}@${prov},${arg1},${arg2},${arg3},${arg4});
+};
+
+macro trunkdial(ext) { // Dial sunrocket and set correct collerid
+ if("${CALLERID(num)}" = "1") {
+ Set(CALLERID(num)=7322271653);
+ } else {
+ Set(CALLERID(num)=7326260100);
+ };
+ Set(CALLERID(name)=Sergey Okhapkin);
+ &checkanddial(${TRUNK},${TRUNCPROTO},${ext},60,T);
+ Hangup;
+};
+
+macro checklocal(ext) { // lookup the number in DB and call the number via pstn or sunrocket
+ Set(AREACODE=${ext:0:3});
+ Set(EXCHANGE=${ext:3:3});
+ Set(IS_LOCAL=${DB_EXISTS(localnum/${AREACODE}/${EXCHANGE})});
+ if(${IS_LOCAL}) {
+ &checkanddial(${PSTN},${PSTNPROTO},${ext},60,T);
+ if ("${DIALSTATUS}" = "BUSY")
+ &trunkdial(${ext});
+ } else
+ &trunkdial(${ext});
+};
+
+macro autodial(ext) { // Find Least Cost Route
+ LCDial(${ext},60,T);
+ if("${DIALSTATUS}" = "NOPROVIDER")
+ Playback(invalid);
+ Hangup();
+};
+
+context default { // Calls to us
+ s => {
+ Wait(1);
+ Answer;
+start:
+ Set(TIMEOUT(digit)=3);
+ Set(TIMEOUT(response)=10);
+repeat:
+ for (x=0; ${x} < 5; x=${x} + 1) {
+ Background(home/greeting);
+ WaitExten();
+ };
+ };
+ t => jump *;
+ i => { // invalid extension
+ Playback(invalid);
+ goto s|repeat;
+ };
+ _* => {
+ Playback(vm-goodbye);
+ Wait(1);
+ Hangup;
+ };
+ 1 => &stdexten(1,SIP/1);
+ 2 => &stdexten(2,SIP/2);
+ 3 => &stdexten(3,SIP/3);
+
+ 2271653 => jump 1;
+ 7322271653 => jump 1;
+ 17322271653 => jump 1;
+
+ 6260100 => jump 2;
+ 7326260100 => jump 2;
+ 17326260100 => jump 2;
+ 8058701100 => jump 2;
+ 3103622835 => jump 2;
+ sos => jump 2;
+ 1400898 => jump 2;
+
+ 6260101 => jump s;
+ 7326260101 => jump s;
+ 17326260101 => jump s;
+
+ 2271677 => jump 3;
+ 7322271677 => jump 3;
+ 17322271677 => jump 3;
+ galka => jump 3;
+ 911 => Dial(${PSTNPROTO}/911@${PSTN},60,);
+ 380 => Dial(SIP/topspeen@212.40.38.70,60,T);
+
+ // Fun stuff
+ 100 => {
+ SayUnixTime();
+ goto s|start;
+ };
+ 101 => { // Voicemail
+ VoicemailMain(${CALLERID(num)});
+ Hangup;
+ };
+ 102 => MusicOnHold();
+// 103 => {
+// Wait(1);
+//start:
+// Read(NUMBER,vm-enter-num-to-call);
+// LCDial(${NUMBER},T);
+// goto start;
+// };
+ 105 => jump s@phrase-menu;
+ 7312 => {
+ ForkCDR;
+ Set(CALLERID(name)=Sergey Okhapkin);
+ Set(CALLERID(num)=7326260100);
+ DISA(1111|home);
+ };
+};
+
+context goiax {
+ s => {
+ Answer();
+ Ringing();
+ Wait(1);
+start:
+ Read(NUMBER,vm-enter-num-to-call);
+ Set(CALLERID(name)=Central NJ);
+ Dial(IAX2/14301@fwdOUT/q${NUMBER},60,T);
+ goto start;
+ };
+
+};
+
+context phrase-menu {
+
+ s => {
+ Answer; // Answer the line
+ TIMEOUT(digit)=2; // Set Digit Timeout to 5 seconds
+ TIMEOUT(response)=10; // Set Response Timeout to 10 seconds
+ BackGround(custom/phrase-menu); // Play main menu.
+ };
+ 1 => { // Phrase Recording
+ Wait(1);
+ Read(PHRASEID|custom/enter-phrase-num);
+ Wait(2); // give yourself 2 secs to take a breath and wait for beep
+ Record(custom/${PHRASEID}:gsm);
+ Wait(2);
+ Playback(custom/${PHRASEID});
+ Wait(1);
+ jump s;
+ };
+ 2 => { // Phrase review
+ Wait(1);
+ Read(PHRASEID|custom/enter-phrase-num);
+ Wait(1);
+ Playback(custom/${PHRASEID});
+ Wait(1);
+ jump s;
+ };
+ t => Hangup;
+ i => {
+ Playback(custom/invalid-option);
+ jump s;
+ };
+};
+
+context outbound {
+ // North America seven-, ten- and eleven digits
+ _NXXXXXX => &autodial(1732${EXTEN});
+ _NXXNXXXXXX => &autodial(1${EXTEN});
+ _ZNXXNXXXXX. => &autodial(${EXTEN});
+ // Toll free numbers via PSTN
+// _1800NXXXXXX => &checkanddial(${PSTN},${PSTNPROTO},${EXTEN},60,T);
+// _1888NXXXXXX => &checkanddial(${PSTN},${PSTNPROTO},${EXTEN},60,T);
+// _1877NXXXXXX => &checkanddial(${PSTN},${PSTNPROTO},${EXTEN},60,T);
+// _1866NXXXXXX => &checkanddial(${PSTN},${PSTNPROTO},${EXTEN},60,T);
+
+ _011. => { //International context accessed through trunk
+ &trunkdial(${EXTEN});
+ };
+ _012. => { //fwdOUT
+ Set(CALLERID(name)=Central NJ);
+ Dial(IAX2/14301@fwdOUT/q${EXTEN:3},60,T);
+ };
+ _013X. => { //NECC
+ Dial(${PSTNPROTO}/011${EXTEN:3}@${PSTN},60,T);
+ };
+ _0131. => { //NECC to US
+ Dial(${PSTNPROTO}/${EXTEN:3}@${PSTN},60,T);
+ };
+ _014. => { //TARIO by SIP ID
+ Set(CALLERID(name)=Sergey Okhapkin);
+ Set(CALLERID(num)=1400898);
+ Dial(${TARIOPROTO}/${EXTEN:3}@${TARIO},60,T);
+ };
+ _0157. => { //TARIO outbound Russia
+ Set(CALLERID(name)=Sergey Okhapkin);
+ Set(CALLERID(num)=1400898);
+ Dial(${TARIOPROTO}/8${EXTEN:4}@${TARIO},60,T);
+ };
+// _015. => { //TARIO outbound international
+// CALLERID(name)="Sergey Okhapkin";
+// CALLERID(num)=1400898;
+// Dial(${TARIOPROTO}/810${EXTEN:3}@${TARIO},60,T);
+// };
+ _0161NXXNXXXXXX => { //Callpacket outbound USA/Canada
+ &checkanddial(${CPACKET1},${CPPROTO},${EXTEN:3},60,T);
+ };
+ _0171NXXNXXXXXX => { //Callpacket outbound USA/Canada
+ &checkanddial(${CPACKET2},${CPPROTO},${EXTEN:3},60,T);
+ };
+ _0181NXXNXXXXXX => { //sellvoip outbound USA/Canada
+ Dial(${SVPROTO}/${SELLVOIP}@${SELLVOIP}/${EXTEN:3},60,T);
+ };
+ _019. => { //Voipbuster
+ Dial(IAX2/sokhapkin@voipbuster/00${EXTEN:3},60,T);
+ };
+};
+
+context home { //calls from us
+ includes {
+ default;
+ outbound;
+ };
+};
+
+context sunrocket-in {
+ 7322271653 => jump s;
+ 7326260100 => jump 2@default;
+ s => {
+ if("${CALLERID(num)}" = "sunrocketcom")
+ Set(CALLERID(num)=);
+ switch(${CALLERID(RDNIS)}) {
+ case 7326260100:
+ jump 2@default;
+ break;
+ case 7326260101:
+ jump s@default;
+ break;
+ default:
+ jump 1@default;
+ break;
+ };
+ };
+};
+
+context pstn-in {
+ 3 => {
+ if ("${CALLERID(num)}" = "7322271677")
+ Set(CALLERID(num)=);
+ jump 3@default;
+ };
+};
+
+context tario.net-in {
+ _X. => {
+ Set(CALLERID(name)=);
+ if("${CALLERID(num):-11:1}" = "8")
+ Set(CALLERID(num)=7${CALLERID(num):1});
+ if("${SIP_HEADER(To)}" = "<sip:2271677@sipnet.ru>") {
+ jump 3@default;
+ } else if("${SIP_HEADER(To)}" = "<sip:2271653@sipnet.ru>") {
+ jump 1@default;
+ } else
+ jump 2@default;
+ };
+};
+
+context from-callpacket {
+ 8058701100 => jump 2@default;
+ 3103622835 => {
+ Answer;
+ Ringing;
+ Wait(10);
+ Voicemail(b3103622835);
+ Hangup;
+ };
+ a => Hangup;
+};
+
+context fromfwdOUT { // make sure we only accept US and Canada calls, limit to 30 minutes
+ includes {
+ fromfwdOUT-catchbad;
+ fromfwdOUT-isgood;
+ fromfwdOUT-catchall;
+ };
+};
+
+context fromfwdOUT-isgood {
+ _17326260100 => jump 2@default;
+ _17326260101 => jump s@default;
+ _17322271653 => jump 1@default;
+ _17322271677 => jump 3@default;
+ _1NXXNXXXXXX => {
+ Set(CALLERID(name)=Sergey Okhapkin);
+// Set(CALLERID(num)=7326260100);
+// Dial(${TRUNCPROTO}/*67${EXTEN:${TRUNKMSD}}@${TRUNK},60,,L(1800000:60000));
+ Dial(${CPPROTO}/${EXTEN}@${CPACKET2},60,,L(1800000:60000));
+ };
+};
+
+context fromfwdOUT-catchbad { //block bahamas, etc
+ _1900. => congestion ; //N11
+ _1XXX976. => congestion ; //N11
+ _1XXX555. => congestion ; //N11
+ _1X11. => congestion ; //N11
+ _1867. => congestion ; //Yukon (sorry mike)
+
+ // exten => _1NPA Country
+ _1242. => congestion; //BAHAMAS
+ _1246. => congestion; //BARBADOS
+ _1264. => congestion; //ANGUILLA
+ _1268. => congestion; //ANTIGUA/BARBUDA
+ _1284. => congestion; //BRITISH VIRGIN ISLANDS
+ _1345. => congestion; //CAYMAN ISLANDS
+ _1441. => congestion; //BERMUDA
+ _1473. => congestion; //GRENADA
+ _1649. => congestion; //TURKS & CAICOS ISLANDS
+ _1664. => congestion; //MONTSERRAT
+ _1758. => congestion; //ST. LUCIA
+ _1767. => congestion; //DOMINICA
+ _1784. => congestion; //ST. VINCENT & GRENADINES
+ _1809. => congestion; //DOMINICAN REPUBLIC
+ _1829. => congestion; //DOMINICAN REPUBLIC
+ _1868. => congestion; //TRINIDAD AND TOBAGO
+ _1869. => congestion; //ST. KITTS AND NEVIS
+ _1876. => congestion; //JAMAICA
+ _1787. => congestion; //Puerto Rico 787, 939 $0.07
+ _1939. => congestion; //Puerto Rico 787, 939 $0.07
+ _1671. => congestion; //Guam 671 $0.08
+ _1340. => congestion; //U.S. Virgin Islands 340 $0.06
+};
+
+context fromfwdOUT-catchall {
+ _X. => Congestion;
+ h => Hangup ; //hangup event
+ i => Hangup ; //invalid event
+ t => Hangup ; //timeout event
+};
+
+context ael-demo {
+ s => {
+ Wait(1);
+ Answer();
+ TIMEOUT(digit)=5;
+ TIMEOUT(response)=10;
+restart:
+ Background(demo-congrats);
+instructions:
+ for (x=0; ${x} < 3; x=${x} + 1) {
+ Background(demo-instruct);
+ WaitExten();
+ };
+ };
+ 2 => {
+ Background(demo-moreinfo);
+ goto s|instructions;
+ };
+ 3 => {
+ LANGUAGE()=fr;
+ goto s|restart;
+ };
+ 500 => {
+ Playback(demo-abouttotry);
+ Dial(IAX2/guest@misery.digium.com);
+ Playback(demo-nogo);
+ goto s|instructions;
+ };
+ 600 => {
+ Playback(demo-echotest);
+ Echo();
+ Playback(demo-echodone);
+ goto s|instructions;
+ };
+ _1234 => &std-exten-ael(${EXTEN}, "IAX2");
+ # => {
+ Playback(demo-thanks);
+ Hangup();
+ };
+ t => jump #;
+ i => Playback(invalid);
+};
+
diff --git a/trunk/pbx/ael/ael-test/ael-test8/extensions.ael b/trunk/pbx/ael/ael-test/ael-test8/extensions.ael
new file mode 100644
index 000000000..17bc74e6f
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-test8/extensions.ael
@@ -0,0 +1,27 @@
+context default
+{
+
+706/3077610011 => {
+ JabberStatus(asterisk|jmls@mike,StatusCode);
+
+ switch(${StatusCode}) {
+ case 1:
+ Dial(SIP/706,12);
+ switch(${DIALSTATUS}) {
+ case BUSY:
+ Voicemail(b706);
+ break;
+ default:
+ Voicemail(u706);
+ };
+ BackGround(hello);
+ break;
+ default:
+ Voicemail(u706);
+ };
+
+ Hangup();
+ };
+
+}
+
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/extensions.ael b/trunk/pbx/ael/ael-test/ael-vtest13/extensions.ael
new file mode 100755
index 000000000..b7e953e62
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/extensions.ael
@@ -0,0 +1,3183 @@
+globals
+{
+ static=yes;
+ writeprotect=yes;
+ CONSOLE=Console/dsp; // Console interface for demo
+ IAXINFO=murf:tlhfckoct; // IAXtel username/password
+ FWDNUMBER=544788 ; // your calling number
+ FWDCIDNAME="Joe-Worker"; // your caller id
+ FWDPASSWORD=zingledoodle ; // your password
+ FWDRINGS=Zap/6 ; // the phone to ring
+ FWDVMBOX=1 ; // the VM box for this user
+}
+
+macro std-exten( ext , dev )
+{
+ Dial(${dev}/${ext},20);
+ switch(${DIALSTATUS})
+ {
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ case ANSWER:
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+ catch a {
+ VoiceMailMain(${ext});
+ }
+}
+
+macro std-priv-exten_1( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_2( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_3( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_4( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_5( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_6( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_7( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_8( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_9( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_10( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_11( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_12( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_13( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_14( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_15( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_16( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_17( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_18( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_19( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_20( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_21( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_22( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_23( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_24( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_25( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_26( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_27( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_28( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_29( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_30( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_31( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_32( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_33( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_34( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_35( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_36( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_37( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_38( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_39( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_40( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_41( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_42( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_43( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_44( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_45( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_46( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_47( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_48( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_49( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_50( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_51( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_52( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_53( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_54( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_55( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_56( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_57( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_58( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_59( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_60( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_61( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_62( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_63( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_64( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_65( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_66( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_67( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_68( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_69( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_70( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_71( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_72( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten_73( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+
+macro std-priv-exten( dev, ext , timeout, opts, torcont, dontcont )
+{
+ Dial(${dev},${timeout},${opts});
+ NoOp(${DIALSTATUS} was chosen);
+ switch(${DIALSTATUS})
+ {
+ case TORTURE:
+ goto ${torcont}|s|begin;
+ break;
+ case DONTCALL:
+ goto ${dontcont}|s|begin;
+ break;
+ case BUSY:
+ Voicemail(b${ext});
+ break;
+ case ANSWER:
+ break;
+ case NOANSWER:
+ Voicemail(u${ext});
+ break;
+ default:
+ Voicemail(u${ext});
+ }
+}
+
+macro fillcidname()
+{
+ if( "${CALLERID(num)}" = "" ) // nothing to work with, quit!!!
+ return;
+ Set(cidn=${DB(cidname/${CALLERID(num)})});
+ if( "${CALLERID(name)}" != "" )
+ {
+ if( ("${cidn}" = "Privacy Manager" & "${CALLERID(name)}" != "Privacy Manager") | "${cidn}" = "" ) // if the entry isn't in the database,
+ // or if an entry exists, and it's "Privacy Manager", empty, (or add other useless possibilities).
+ {
+ Set(DB(cidname/${CALLERID(num)})=${CALLERID(name)}); // then set or override what's in the DB
+ }
+ }
+ // Now, we fill in the callerid info from the incoming entry, if it's stuff worth using
+ // Ignore fundamentally semi-anonymous information from local cell phones
+ // if the db has an entry for this number, and it's not a canned string from a cell phone company
+ if( ( "${cidn}" != "" ) & ( "${CALLERID(name)}" = ""
+ | "${CALLERID(name)}" = "CODY,WY "
+ | "${CALLERID(name)}" = "POWELL,WY "
+ | "${CALLERID(name)}" = "WIRELESS CALLER"
+ | "${CALLERID(name)}" = "SUBSCRIBER,WIRE"
+ | "${CALLERID(name)}" = "CELLULAR ONE"
+ | "${CALLERID(name)}" = "Cellular One Customer"
+ | "${CALLERID(name)}" = "CELLULAR ONE "
+ | "${CALLERID(name)}" = "Privacy Manager"
+ | "${CALLERID(name)}" = "RIVERTON,WY "
+ | "${CALLERID(name)}" = "BASIN,WY "
+ | "${CALLERID(name)}" = "BILLINGS,MT "
+ | "${CALLERID(name)}" = "PROVO,UT "
+ | "${CALLERID(name)}" = "TOLL FREE " ) ) // put stuff in the above, that the phone company tends to put in your callerid,
+ // that you would rather override with DB info
+ // there's no way to guess them all, but you can get the most popular ones...
+ // why cell phones can't do CID like everybody else, ....?
+ {
+ Set(CALLERID(name)=${cidn}); // Override what the phone company provides with what's in the DB for this number.
+ }
+}
+
+macro ciddial(dialnum, lookup, waittime, dialopts, ddev)
+{
+ Set(cidnu=${CALLERID(num)});
+ Set(cidn=${DB(cidname/${lookup})});
+ Set(CALLERID(name)=${cidn});
+ Dial(${ddev}/${dialnum}|${waittime}|${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_voip);
+ CALLERID(num)=7075679201;
+ Dial(SIP/1${lookup}@tctwest,${waittime},${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_cell);
+ CALLERID(num)=${cidnu}; // put the original number back
+ Dial(Zap/2/${lookup},${waittime},${dialopts});
+ }
+ }
+}
+
+macro ciddial3(dialnum, lookup, waittime, dialopts, ddev)
+{
+ Set(cidnu=${CALLERID(num)});
+ Set(cidn=${DB(cidname/${lookup})});
+ Set(CALLERID(name)=${cidn});
+ Dial(${ddev}/${dialnum}|${waittime}|${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_cell);
+ Dial(Zap/2/${lookup},${waittime},${dialopts});
+ }
+}
+
+macro ciddial2(dialnum, lookup, waittime, dialopts, ddev) // give priority to tctwest, then the ZAP in emergencies
+{
+ Set(cidn=${DB(cidname/${lookup})});
+ Set(cidnu=${CALLERID(num)});
+ Set(CALLERID(name)=${cidn});
+ Set(CALLERID(num)=7075679201);
+ Dial(SIP/1${lookup}@tctwest,${waittime},${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ Set(CALLERID(num)=${cidnu}); // put the original number back
+ BackGround(try_zap);
+ Dial(${ddev}/${dialnum},${waittime}|${dialopts});
+ if( "${DIALSTATUS}" = "CHANUNAVAIL" )
+ {
+ BackGround(try_cell);
+ Dial(Zap/2/${lookup},${waittime},${dialopts});
+ }
+ }
+}
+
+macro callerid-liar()
+{
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/priv-callerintros/LIAR.gsm&);
+ Background(priv-liar); // Script: OOOps! Sorry! I don't allow men with ski masks pulled over their
+ // faces to get in the front door, and unidentified callers won't fair
+ // any better. You entered *MY* phone number. That won't work.
+ // If you are telemarketing, cross me off the list, and don't call again.
+ // If you did this by mistake, forgive my defenses, and call again.
+ // Alternate: (priv-liar2)
+ // Script: You have chosen to try to deceive my system and withold your CallerID,
+ // by entering my own phone number as YOUR CallerID. I find this
+ // offensive because you are being dishonest. I will not do business nor
+ // waste my time talking to anyone who is less than honest and forthcoming.
+ // Take me off your call list and do not call me again.
+ Hangup();
+}
+
+macro callerid-bad()
+{
+ mycid=${CALLERID(num)}:"1([0-9]+)";
+ Set(CALLERID(num)=${mycid});
+ Wait(0);
+}
+
+context privacyManagerFailed {
+ s => {
+ begin:
+ Background(PrivManInstructions); // Script: OOps, that didn't go well. You need to enter *your* area code, and *your* 7 digit
+ // phone number, for a total of 10 digits, or you'll be handed over to the monkeys. Let's
+ // try this again, and hopefully you can get past our front-line defenses!
+ PrivacyManager();
+ if( "${PRIVACYMGRSTATUS}" = "FAILED" )
+ {
+ Background(tt-allbusy);
+ Background(tt-somethingwrong);
+ Background(tt-monkeysintro);
+ Background(tt-monkeys);
+ Background(tt-weasels);
+ Hangup();
+ }
+ else
+ {
+ goto homeline|s|postPriv;
+ }
+ }
+}
+
+// Some comments
+// Some more comments
+
+context homeline {
+ s => {
+ begin:
+ Answer();
+ Set(repeatcount=0);
+ Zapateller(nocallerid);
+ PrivacyManager();
+ if( "${PRIVACYMGRSTATUS}" = "FAILED" )
+ {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/privmanfailed.gsm);
+ &std-priv-exten(Zap/3r1&Zap/5r1,2,25,mtw,telemarket,telemarket);
+ Hangup();
+ return;
+// goto privacyManagerFailed|s|begin;
+ }
+ postPriv:
+ &fillcidname();
+ Set(CONFCIDNA=${CALLERID(name)});
+ Set(CONFCIDNU=${CALLERID(num)});
+ AGI(callall);
+ AGI(submit-announce.agi);
+ if( "${CALLERID(num)}" : "1" )
+ {
+ &callerid-bad();
+ }
+ if( "${CALLERID(num)}" = "7077577685" & "${CALLERID(name)}" : "Privacy Manager" )
+ {
+ &callerid-liar();
+ }
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ Set(lds=${DB(playlds/${CALLERID(num)})});
+ if( "${lds}" = "1" )
+ {
+ SetMusicOnHold(mohlds);
+ }
+ direct=${DB(DirectCall/${CALLERID(num)})};
+ if( "${direct}" != "" & ${direct} != 0 )
+ {
+ verbose(direct is XXX#${direct}XXXX);
+ Playback(greetings/direct); // Welcome to the Murphy residence. This system will automatically try to connect you to...
+ Playback(/var/spool/asterisk/voicemail/default/${direct}/greet);
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/${direct}/greet.wav&);
+ switch(${direct})
+ {
+ case 1: //Steve
+ &std-priv-exten(Zap/6r3&Sip/murf,1,25,mpA(beep)tw,telemarket,telemarket);
+ goto s|loopback;
+ case 2: //Sonya
+ &std-priv-exten(Zap/3r1&Zap/5r1,2,25,mtw,telemarket,telemarket);
+ goto s|loopback;
+ default: // all the kids
+ Set(z=${direct}-2);
+ goto homeline-kids|${z}|1;
+ }
+ }
+ loopback:
+ ifTime(*|*|20-25|dec)
+ {
+ Playback(greetings/christmas);
+ }
+ else ifTime(*|*|31|dec)
+ {
+ Playback(greetings/newyear);
+ }
+ else ifTime(*|*|1|jan)
+ {
+ Playback(greetings/newyear);
+ }
+ else ifTime(*|*|14|feb)
+ {
+ Playback(greetings/valentines);
+ }
+ else ifTime(*|*|17|mar)
+ {
+ Playback(greetings/stPat);
+ }
+ else ifTime(*|*|31|oct)
+ {
+ Playback(greetings/halloween);
+ }
+ else ifTime(*|mon|15-21|jan)
+ {
+ Playback(greetings/mlkDay);
+ }
+ else ifTime(*|thu|22-28|nov)
+ {
+ Playback(greetings/thanksgiving);
+ }
+ else ifTime(*|mon|25-31|may)
+ {
+ Playback(greetings/memorial);
+ }
+ else ifTime(*|mon|1-7|sep)
+ {
+ Playback(greetings/labor);
+ }
+ else ifTime(*|mon|15-21|feb)
+ {
+ Playback(greetings/president);
+ }
+ else ifTime(*|sun|8-14|may)
+ {
+ Playback(greetings/mothers);
+ }
+ else ifTime(*|sun|15-21|jun)
+ {
+ Playback(greetings/fathers);
+ }
+ else
+ {
+ Playback(greetings/hello); // None of the above? Just a plain hello will do
+ }
+ Background(murphy-homeline-intro1); // Script: Hello-- Welcome to the Murphy's! If you already know what
+ // option you want, you don't have to wait for this entire spiel-- just
+ // have at it.
+ // If you are calling because this number is on a list of some sort, dial 6.
+ // If you want Sonya, dial 1.
+ // If you want one of the kids, dial 2.
+ // If you want Steve, dial 3.
+ // to play with your introduction, dial 5.
+ // If we don't seem to be giving you the time of day, try 7.
+ // Have a good day!
+
+ }
+ 1 => { // Sonya
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/2/greet.wav&);
+ &std-priv-exten(Zap/3r1&Zap/5r1,2,25,mtw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 2 => { // Kids
+ goto homeline-kids|s|begin;
+ }
+ 21 => {
+ Dial(IAX2/seaniax,20,T);
+ }
+ 3 => { // Steve
+ &std-priv-exten(Zap/6r3&Sip/murf,1,25,mpA(beep)tw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 4 => { // Voicemail
+ VoicemailMain();
+ goto s|loopback;
+ }
+ 5 => { // play with intro
+ goto home-introduction|s|begin;
+ }
+ 6 => { // Telemarketers
+ goto telemarket|s|begin;
+ }
+ 7 => { // time of day, riddle
+ agi(tts-riddle.agi);
+ Background(gsm/what-time-it-is2);
+ SayUnixTime();
+ goto s|loopback;
+ }
+ 792 => { // Page All
+ goto pageall|s|begin;
+ }
+ 793 => { // check the tone recognition
+ Read(zz,,0,,1,0);
+ SayDigits(${zz});
+ }
+ t => {
+ Set(repeatcount=${repeatcount} + 1);
+ if( ${repeatcount} < 3 )
+ {
+ goto s|loopback; // just loopback isn't enough
+ }
+ Hangup();
+ }
+ i => {
+ Background(invalid);
+ goto s|loopback;
+ }
+ o => {
+ Congestion();
+ }
+ fax => {
+ Dial(Zap/4);
+ }
+}
+
+// Some comments
+// Some more comments
+
+context pageall {
+ s => {
+ begin:
+ AGI(callall);
+ MeetMe(5555,dtqp);
+ MeetMeAdmin(5555,K);
+ Hangup();
+ }
+
+ h => {
+ begin:
+ MeetMeAdmin(5555,K);
+ Background(conf-muted);
+ Hangup();
+ }
+}
+
+// Some comments
+// Some more comments
+
+context add-to-conference {
+ start => {
+ NoCDR();
+ MeetMe(5555,dmqp);
+ }
+ h => {
+ Hangup();
+ }
+}
+
+context home-introduction {
+ s => {
+ begin:
+ Background(intro-options); // Script: To hear your Introduction, dial 1.
+ // to record a new introduction, dial 2.
+ // to return to the main menu, dial 3.
+ // to hear what this is all about, dial 4.
+ }
+ 1 => {
+ Playback(priv-callerintros/${CALLERID(num)});
+ goto s|begin;
+ }
+ 2 => {
+ goto home-introduction-record|s|begin;
+ }
+ 3 => {
+ goto homeline|s|loopback;
+ }
+ 4 => {
+ Playback(intro-intro); // Script:
+ // This may seem a little strange, but it really is a neat
+ // thing, both for you and for us. I've taped a short introduction
+ // for many of the folks who normally call us. Using the Caller ID
+ // from each incoming call, the system plays the introduction
+ // for that phone number over a speaker, just as the call comes in.
+ // This helps the folks
+ // here in the house more quickly determine who is calling.
+ // and gets the right ones to gravitate to the phone.
+ // You can listen to, and record a new intro for your phone number
+ // using this menu.
+ goto s|begin;
+ }
+ t => {
+ goto s|begin;
+ }
+ i => {
+ Background(invalid);
+ goto s|begin;
+ }
+ o => {
+ goto s|begin;
+ }
+}
+
+context home-introduction-record {
+ s => {
+ begin:
+ Background(intro-record-choices); // Script:
+ // If you want some advice about recording your
+ // introduction, dial 1.
+ // otherwise, dial 2, and introduce yourself after
+ // the beep.
+ }
+ 1 => {
+ Playback(intro-record);
+ // Your introduction should be short and sweet and crisp.
+ // Your introduction will be limited to 10 seconds.
+ // This is NOT meant to be a voice mail message, so
+ // please, don't say anything about why you are calling.
+ // After we are done making the recording, your introduction
+ // will be saved for playback.
+ // If you are the only person that would call from this number,
+ // please state your name. Otherwise, state your business
+ // or residence name instead. For instance, if you are
+ // friend of the family, say, Olie McPherson, and both
+ // you and your kids might call here a lot, you might
+ // say: "This is the distinguished Olie McPherson Residence!"
+ // If you are the only person calling, you might say this:
+ // "This is the illustrious Kermit McFrog! Pick up the Phone, someone!!"
+ // If you are calling from a business, you might pronounce a more sedate introduction,like,
+ // "Fritz from McDonalds calling.", or perhaps the more original introduction:
+ // "John, from the Park County Morgue. You stab 'em, we slab 'em!".
+ // Just one caution: the kids will hear what you record every time
+ // you call. So watch your language!
+ // I will begin recording after the tone.
+ // When you are done, hit the # key. Gather your thoughts and get
+ // ready. Remember, the # key will end the recording, and play back
+ // your intro. Good Luck, and Thank you!"
+ goto 2|begin;
+ }
+ 2 => {
+ begin:
+ Background(intro-start);
+ // OK, here we go! After the beep, please give your introduction.
+ Background(beep);
+ Record(priv-callerintros/${CALLERID(num)}:gsm,3);
+ Background(priv-callerintros/${CALLERID(num)});
+ goto home-introduction|s|begin;
+ }
+ t => {
+ goto s|begin;
+ }
+ i => {
+ Background(invalid);
+ goto s|begin;
+ }
+ o => {
+ goto s|begin;
+ }
+}
+
+context homeline-kids {
+ s => {
+ begin:
+ Background(murphy-homeline-kids); // Which Kid? 1=Sean, 2:Eric, 3:Ryan, 4:Kyle, 5:Amber, 6:Alex, 7:Neal
+ }
+ 1 => { // SEAN
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/3/greet.wav&);
+ // &std-priv-exten(Zap/3r2&Zap/5r2,3,35,mtw,telemarket,telemarket);
+ &std-priv-exten(IAX2/seaniax&Zap/5r2,3,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 2 => { // ERIC
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/4/greet.wav&);
+ Voicemail(u4);
+ goto homeline|s|loopback;
+
+ // SetMusicOnHold(erics);
+ // TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ // TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/4/greet.wav&);
+ // &std-priv-exten(Zap/3r2&Zap/5r2,4,35,mtw,telemarket,telemarket);
+ // goto homeline|s|loopback;
+ }
+ 3 => { // RYAN
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/5/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,5,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 4 => { // KYLE
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/6/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,6,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 5 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/7/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,7,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+
+ }
+ 6 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/8/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,8,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ 7 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/9/greet.wav&);
+ &std-priv-exten(Zap/3r2&Zap/5r2,9,35,mtw,telemarket,telemarket);
+ goto homeline|s|loopback;
+ }
+ t => {
+ goto s|begin;
+ }
+ i => {
+ Background(invalid);
+ goto s|begin;
+ }
+ o => {
+ goto s|begin;
+ }
+}
+
+context voipworkline {
+ s => {
+ begin:
+ Answer();
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ goto workline|s|loopback;
+ }
+ 7075679201 => {
+ Answer();
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ goto workline|s|loopback;
+ }
+}
+
+context workline {
+ s => {
+ begin:
+ Answer();
+ Wait(1);
+ Set(repeatcount=0);
+ Zapateller(nocallerid);
+// PrivacyManager();
+// if( "${PRIVACYMGRSTATUS}" = "FAILED" )
+// {
+// goto privacyManagerFailed|s|begin;
+// }
+ &fillcidname();
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ loopback:
+ Background(greetings/greeting); //script: Hello
+ Background(murphy-office-intro1); //script: welcome to Steve Murphy's office. If you are dialing
+ // this number because it was on a calling list of any sort, dial 6.
+ // Otherwise, dial 1, and hopefully, you will reach Steve.
+ }
+ 1 => {
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm);
+ TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/1/greet.wav&);
+
+ &std-priv-exten(Zap/6&Sip/murf,1,30,mtw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 4 => {
+ VoicemailMain();
+ goto s|loopback;
+ }
+ 6 => {
+ goto telemarket|s|begin;
+ }
+ 793 => { // check the tone recognition
+ Read(zz,,0,,1,0);
+ SayDigits(${zz});
+ }
+ t => {
+ repeatcount=${repeatcount} + 1;
+ if( ${repeatcount} < 3 )
+ {
+ goto s|loopback; // just loopback isn't enough
+ }
+ Hangup();
+ }
+ i => {
+ Background(invalid);
+ goto s|loopback;
+ }
+ o => {
+ Congestion();
+ }
+ fax => {
+ Answer();
+ Dial(Zap/4);
+ }
+}
+
+context dialFWD {
+ ignorepat => 8;
+ ignorepat => 9;
+ _83. => {
+ Set(CALLERID(name)=${FWDCIDNAME});
+ Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2},60,r);
+ Congestion();
+ }
+ _82NXX => {
+ Set(CALLERID(name)=${FWDCIDNAME});
+ Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2},60,r);
+ Congestion();
+ }
+ _92NXX => {
+ Set(CALLERID(name)=${FWDCIDNAME});
+ Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2},60,r);
+ Congestion();
+ }
+}
+
+context dialiaxtel {
+ ignorepat => 8;
+ ignorepat => 9;
+ _81700NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+ _81800NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+ _91700NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+ _91800NXXXXXX => {
+ Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel);
+ }
+
+}
+
+context dialgoiax {
+ ignorepat => 9;
+ _93. => {
+ Set(CALLERID(name)="Joe Worker");
+ Dial(IAX2/878201007658:stickyfinger295@server1.goiax.com/${EXTEN:2},60,r);
+ Congestion();
+ }
+
+}
+
+context homefirst {
+ ignorepat => 9;
+ _91NXXNXXXXXX => {
+ &ciddial(${EXTEN:1},${EXTEN:2},30,TW,Zap/1);
+ }
+ _9754XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9574XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9202XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9219XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9254XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9716XXXX => {
+ &ciddial(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9NXXXXXX => {
+ &ciddial(1707${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9011. => {
+ &ciddial(${EXTEN:1},${EXTEN:1},30,TW,Zap/1);
+ }
+ _9911 => {
+ Dial(Zap/1/911,30,T);
+ }
+ _9411 => {
+ Dial(Zap/1/411,30,T);
+ }
+}
+
+context workfirst {
+ ignorepat => 9;
+ _91NXXNXXXXXX => {
+ &ciddial2(${EXTEN:1},${EXTEN:2},30,TW,Zap/1);
+ }
+ _9754XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9574XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9202XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9219XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9254XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9716XXXX => {
+ &ciddial2(${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9NXXXXXX => {
+ &ciddial2(1707${EXTEN:1},707${EXTEN:1},30,TW,Zap/1);
+ }
+ _9911 => {
+ Dial(Zap/1/911,30,T);
+ }
+ _9411 => {
+ Dial(Zap/1/411,30,T);
+ }
+}
+
+context force_cell {
+ ignorepat => 8;
+ _81NXXNXXXXXX => {
+ &ciddial(${EXTEN:1}#,${EXTEN:2},30,TW,Zap/2);
+ }
+ _8754XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8574XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8202XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8219XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8254XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8716XXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8NXXXXXX => {
+ &ciddial(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/2);
+ }
+ _8911 => {
+ Dial(Zap/1/911|30|T);
+ }
+ _8411 => {
+ Dial(Zap/1/411|30|T);
+ }
+}
+
+context force_home {
+ ignorepat => 8;
+ _81NXXNXXXXXX => {
+ &ciddial3(${EXTEN:1}#,${EXTEN:2},30,TW,Zap/1);
+ }
+ _8754XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8574XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8202XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8219XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8254XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8716XXXX => {
+ &ciddial3(${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8NXXXXXX => {
+ &ciddial3(1707${EXTEN:1}#,707${EXTEN:1},30,TW,Zap/1);
+ }
+ _8911 => {
+ Dial(Zap/1/911|30|T);
+ }
+ _8411 => {
+ Dial(Zap/1/411|30|T);
+ }
+}
+
+context homeext {
+ ignorepat => 8;
+ ignorepat => 9;
+ includes {
+ parkedcalls;
+ homefirst;
+ force_cell;
+ }
+ s => {
+ loopback:
+ Wait(0);
+ }
+ 1 => {
+ &std-priv-exten(Zap/3&Zap/5,2,35,mtw,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 2 => {
+ &std-priv-exten(Zap/6&Zap/5,1,35,mpA(beep3)Tt,telemarket,telemarket);
+ goto s|loopback;
+ }
+ 4 => {
+ VoicemailMain();
+ }
+ 5 => {
+ Record(recording:gsm);
+ Background(recording);
+ }
+ 6 => {
+ Background(recording);
+ }
+ 760 => {
+ DateTime();
+ goto s|loopback;
+ }
+ 761 => {
+ Record(announcement:gsm);
+ TrySystem(/usr/bin/play /var/lib/asterisk/sounds/announcement.gsm&);
+ goto s|loopback;
+ }
+ 762 => {
+ agi(tts-riddle.agi);
+ Background(gsm/what-time-it-is2);
+ SayUnixTime();
+ goto s|loopback;
+ }
+ 763 => {
+ Set(CALLERID(num)=);
+ Dial(Zap/6r3,35,mptA(beep3)); //results: it should ALWAYS ask for an intro; the intro should not be left behind
+ Hangup();
+ }
+ 764 => {
+ Set(CALLERID(num)=);
+ Dial(Zap/6r3,35,mptnA(beep3)); //results: Don't save the intro; shouldn't anyway if no callerid
+ Hangup();
+ }
+ 765 => {
+ Set(CALLERID(num)=);
+ Dial(Zap/6r3,35,mptNA(beep3)); //results: Don't screen if there's CALLERID; it should screen the call.
+ Hangup();
+ }
+ 766 => {
+ Dial(Zap/6r3,35,mptNA(beep3)); //results: Don't screen if there's CALLERID; it should screen the call.
+ Hangup();
+ }
+ 767 => {
+ Dial(Zap/6r3,35,mptnA(beep3)); //results: Don't save the intro; the interesting case, because callerID should be present.
+ Hangup();
+ }
+ 769 => {
+ Playtones(dial);
+ Wait(2);
+ Playtones(busy);
+ Wait(2);
+ Playtones(ring);
+ Wait(2);
+ Playtones(congestion);
+ Wait(2);
+ Playtones(callwaiting);
+ Wait(2);
+ Playtones(dialrecall);
+ Wait(2);
+ Playtones(record);
+ Wait(2);
+ Playtones(info);
+ Wait(5);
+ Hangup();
+ }
+ 790 => {
+ MeetMe(790,p);
+ }
+ 792 => {
+ goto pageall|s|begin;
+ }
+ 795 => {
+ AGI(wakeup.agi);Congestion();
+ }
+ 544716 => { // Incoming call from FWD
+ TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&);
+ goto s|loopback;
+ }
+
+ i => {
+ Background(invalid);
+ goto s|loopback;
+ }
+ o => {
+ goto s|loopback;
+ }
+ t => {
+ Congestion();
+ }
+}
+
+context fromvmhome {
+ 1 => {
+ Dial(Zap/6&Sip/murf|20|Tt);
+ }
+ 2 => {
+ Dial(Zap/3&Zap/5|20|Tt);
+ }
+ _707202XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707219XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707254XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707716XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707754XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707574XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _NXXNXXXXXX => {
+ &ciddial(1${EXTEN},${EXTEN},30,TW,Zap/1);
+ }
+ _1NXXNXXXXXX => { // HAND DIALING
+ &ciddial(${EXTEN},${EXTEN:1},30,TW,Zap/1);
+ }
+ _754XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _574XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _NXXXXXX => {
+ &ciddial(1707${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _911 => {
+ &ciddial(911,911,30,TW,Zap/1);
+ }
+ _411 => {
+ &ciddial(411,411,30,TW,Zap/1);
+ }
+}
+
+context fromvmwork {
+ 1 => {
+ Dial(Zap/6&Sip/murf|20|Tt);
+ }
+ 2 => {
+ Dial(Zap/3&Zap/5|20|Tt);
+ }
+ _707202XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707219XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707254XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707716XXXX => {
+ &ciddial(1${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707754XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707574XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _NXXNXXXXXX => {
+ &ciddial(1${EXTEN},${EXTEN},30,TW,Zap/1);
+ }
+ _1NXXNXXXXXX => { // HAND DIALING
+ &ciddial(${EXTEN},${EXTEN:1},30,TW,Zap/1);
+ }
+ _754XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _574XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _NXXXXXX => {
+ &ciddial(1707${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ 911 => {
+ &ciddial(911,911,30,TW,Zap/1);
+ }
+ 411 => {
+ &ciddial(411,411,30,TW,Zap/1);
+ }
+}
+
+context fromSeanUniden {
+ includes
+ {
+ parkedcalls;
+ }
+ 21 => {
+ Dial(IAX2/seaniax,20,T);
+ }
+ _707202XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707219XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707254XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707716XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707754XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _707574XXXX => {
+ &ciddial(${EXTEN:3},${EXTEN},30,TW,Zap/1);
+ }
+ _NXXNXXXXXX => {
+ &ciddial(1${EXTEN},${EXTEN},30,TW,Zap/1);
+ }
+ _1NXXNXXXXXX => {
+ &ciddial(${EXTEN},${EXTEN:1},30,TW,Zap/1);
+ }
+ _754XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _574XXXX => {
+ &ciddial(${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ _NXXXXXX => {
+ &ciddial(1707${EXTEN},707${EXTEN},30,TW,Zap/1);
+ }
+ 911 => {
+ &ciddial(911,911,30,TW,Zap/1);
+ }
+ 411 => {
+ &ciddial(411,411,30,TW,Zap/1);
+ }
+}
+
+context workext {
+ ignorepat => 8;
+ ignorepat => 9;
+ includes {
+ parkedcalls;
+ workfirst;
+ force_home;
+ dialFWD;
+ dialiaxtel;
+ dialgoiax;
+ }
+ s => {
+ loopback:
+ Wait(0);
+ }
+ 1 => {
+ Dial(Zap/3&Zap/5,20,tT);
+ }
+ 2 => {
+ Dial(Zap/5&Zap/6,20,tT);
+ }
+ 21 => {
+ Dial(IAX2/seaniax,20,T);
+ }
+ 22 => {
+ Set(CALLERID(num)=1234567890);
+ Set(CALLERID(name)=TestCaller);
+ Dial(Zap/5,20,mP()A(beep)tw);
+ NoOp(here is dialstatus: ${DIALSTATUS}...);
+ goto s|loopback;
+ }
+ 4 => {
+ VoicemailMain();
+ goto s|loopback;
+ }
+ 5 => {
+ Record(recording:gsm);
+ Background(recording);
+ }
+ 6 => {
+ ZapBarge();
+ }
+ 760 => {
+ DateTime();
+ goto s|loopback;
+ }
+ 761 => {
+ ZapBarge();
+ goto s|loopback;
+ }
+ 765 => {
+ Playback(demo-echotest);
+ Echo();
+ Playback(demo-echodone);
+ goto s|loopback;
+ }
+ 766 => {
+ Festival(The other thing to watch is neuro-electronics: the ability to interface technology with our neural system: My wife: Sigrid: has had a cochlear implant since 1996. This once profoundly deaf person now uses the phone: recognizes accents: and listens to movies and recorded books.);
+ goto s|loopback;
+ }
+ 767 => {
+ agi(tts-riddle.agi);
+ Background(gsm/what-time-it-is2);
+ SayUnixTime();
+ goto s|loopback;
+ }
+ 768 => {
+ agi(tts-computer.agi);
+ }
+ 771 => {
+ eagi(eagi-test);
+ agi(my-agi-test);
+ }
+ 772 => {
+ agi(wakeup.agi);
+ }
+ 775 => {
+ if( ${EXTEN}=${EXTEN} )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ if( ${EXTEN}=${LANGUAGE} )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ BackGround(digits/2);
+ }
+ 776 => {
+ Set(TEST=00359889811777);
+ if( ${TEST}= 00359889811777 )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ if( ${TEST}= 00359889811888 )
+ {
+ BackGround(digits/1);
+ }
+ else
+ {
+ BackGround(digits/0);
+ }
+ Hangup();
+ }
+ 790 => {
+ MeetMe(790,p);
+ }
+ 792 => {
+ goto pageall|s|begin;
+ }
+ 793 => {
+ #include "include1.ael2"
+ }
+ 795 => {
+ AGI(wakeup.agi);
+ Congestion();
+ }
+ 797 => {
+ Set(CONFCIDNA=${CALLERID(name)});
+ Set(CONFCIDNU=${CALLERID(num)});
+ AGI(callall);
+ AGI(submit-announce.agi);
+ Hangup();
+ }
+}
+
+context wakeup {
+ 3 => {
+ Dial(Zap/3|30);
+ }
+ 4 => {
+ Dial(Zap/4|30);
+
+ }
+ 5 => {
+ Dial(Zap/5|30);
+
+ }
+ 6 => {
+ Dial(Zap/6|30);
+
+ }
+ 99 => {
+ Dial(IAX2/murfiaxphone|30);
+ }
+ 97 => {
+ Dial(IAX2/ryaniax|30);
+ }
+ 94 => {
+ Dial(IAX2/seaniax|30);
+ }
+}
+
+context announce-all {
+ s => {
+ begin:
+ MeetMe(5555,dtqp);
+ MeetMeAdmin(5555,K);
+ Hangup();
+ }
+ h => {
+ MeetMeAdmin(5555,K);
+ Hangup();
+ }
+}
+
+// now include the telemarketer torture scripts!
+
+#include "telemarket_torture.ael2"
+
+
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/include1.ael2 b/trunk/pbx/ael/ael-test/ael-vtest13/include1.ael2
new file mode 100644
index 000000000..80c562cb2
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/include1.ael2
@@ -0,0 +1,3 @@
+ NoOp(Hello, this is included from include1.ael2);
+ #include "include2.ael2"
+
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/include2.ael2 b/trunk/pbx/ael/ael-test/ael-vtest13/include2.ael2
new file mode 100644
index 000000000..8d892fb0c
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/include2.ael2
@@ -0,0 +1,4 @@
+ NoOp(This was included from include2.ael2);
+ #include "include3.ael2"
+ #include "include4.ael2"
+
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/include3.ael2 b/trunk/pbx/ael/ael-test/ael-vtest13/include3.ael2
new file mode 100644
index 000000000..3c6c1e3dd
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/include3.ael2
@@ -0,0 +1,2 @@
+ NoOp(This is include3.ael2!);
+ #include "include5.ael2"
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/include4.ael2 b/trunk/pbx/ael/ael-test/ael-vtest13/include4.ael2
new file mode 100644
index 000000000..7d3703a5e
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/include4.ael2
@@ -0,0 +1,2 @@
+ NoOp(This is include4.ael2! Isn't it cool!?!?!?!);
+ NoOp(4 doesn't include anything);
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/include5.ael2 b/trunk/pbx/ael/ael-test/ael-vtest13/include5.ael2
new file mode 100644
index 000000000..0e18983ef
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/include5.ael2
@@ -0,0 +1 @@
+ NoOp(Include5.ael2 doesn't include anything, either!);
diff --git a/trunk/pbx/ael/ael-test/ael-vtest13/telemarket_torture.ael2 b/trunk/pbx/ael/ael-test/ael-vtest13/telemarket_torture.ael2
new file mode 100755
index 000000000..ebd8e9f2f
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest13/telemarket_torture.ael2
@@ -0,0 +1,812 @@
+//
+// AN EXCERSIZE IN BAD DIALPLAN DESIGN
+// (What better testing ground than on telemarketers?)
+//
+
+
+// BAD DESIGN: long, boring introductions followed by long, drawn out menus of choices.
+// if they survive to the last option, how will they remember the choices?
+//
+
+// BAD DESIGN: Amateur Recording. Poor voice quality, too quiet.
+// Also, the announcer is definitely not vocally gifted.
+// Also, the long pauses and clicks between the intro
+// and menu choices might lead some to think that
+// the announcements are over, and hang up. Too bad!
+
+// WORSE DESIGN: Instead of using the Background application, the Playback
+// application is used. After taking so much time and trouble
+// to record this material, the caller must listen and enjoy
+// every syllable before they can make an option choice. None
+// of that interrupting with a choice. We want them to savour
+// every word!
+
+// GOOD/BAD, ER INSIDIOUS -- DANGLE A CARROT-- GIVE THE LISTENER A GOOD REASON TO
+// HANG ON AND VOLUNTARILY LISTEN TO THE TORTURE.
+// BUT, DON'T MAKE PROMISES YOU WON'T KEEP!
+
+
+context telemarket {
+ s => {
+ begin:
+ Playback(telemarketer-intro); // ; Script:
+ // Due to the extremely high volume of calls from everything from telemarketers
+ // to Septic System Bacteria vendors, we are asking all such organizations
+ // to remove this number from their call list, or as need be, to add this
+ // number to their No-Call list, whichever is relevent.
+
+ // [THE CARROT:]
+ // We HAVE made some exceptions, and if you wish to see if your organization
+ // has been exempted, please listen to and follow the following prompts.
+ //
+ // Otherwise, please Cease calling this number!
+ //
+ Playback(telemarketer-choices);
+ // if you represent a charitable organization, please dial 1,
+ // if you represent a political organization, please dial 2.
+ // if you represent a polling company, please dial 3,
+ // if you represent a market research organization, please dial 4.
+ // if you represent a magazine or newsletter, please dial 5.
+ // if you represent a commercial organization, please dial 6.
+ }
+ 1 => goto telemarket-charity|s|begin;
+ 2 => goto telemarket-political|s|begin;
+ 3 => goto telemarket-pollster|s|begin;
+ 4 => goto telemarket-research|s|begin;
+ 5 => goto telemarket-magazine|s|begin;
+ 6 => goto telemarket-commercial|s|begin;
+ 7 => goto telemarket-other|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-charity {
+ s => {
+ begin:
+ Playback(telemark-charity-intro);
+ // We have contributed generously to many worthy causes in the past, and will
+ // continue to do so in the future. But we suspect that such organizatons
+ // have sold our name and phone number to each other until we are now hounded
+ // day and night by literally hundreds of such organizations.
+ // Enough is Enough!
+ //
+ // If we have contributed to your cause in the past, we may, perhaps, be disposed to
+ // do so in the future, at our option,
+ // we give no pledges nor make any commitments here.
+ // Send us material via the post if you feel this necessary
+ // but do not even consider email. Any email or further phone calls from your organization
+ // in the future, will be considered an act of aggression, and we will
+ // blacklist your organization for the rest of our natural lives.
+ //
+ // To see if your organization is exempt from these prohibitions, please
+ // comply with the following options.
+ Playback(telemark-charity-choices);
+ // If your organization is disease or genetic defect related, dial 1,
+ // If your organization is handicap related, dial 2.
+ // If your organization is a police or fireman or other similar support entity, please dial 3.
+ // If your organization is a grade school to high school related
+ // fund raiser or other type of activity, please dial 4.
+ // If your organization is a college or univerity or alumnis organization, please dial 5.
+ // If your organization is animal rights or ecology related organization, please dial 6.
+ // If your organization is a political action or candidate support related, please dial 7.
+ // If your organization is a substance abuse related organization or cause, please dial 8.
+ // And any other charity or tax exempt organization should dial 9.
+ }
+ 1 => goto telemarket-char-disease|s|begin;
+ 2 => goto telemarket-char-handicap|s|begin;
+ 3 => goto telemarket-char-police|s|begin;
+ 4 => goto telemarket-char-school|s|begin;
+ 5 => goto telemarket-char-college|s|begin;
+ 6 => goto telemarket-char-animal|s|begin;
+ 7 => goto telemarket-char-candidate|s|begin;
+ 8 => goto telemarket-char-abuse|s|begin;
+ 9 => goto telemarket-char-other|s|begin;
+// BAD DESIGN: referring all timeouts,invalid choices, etc, back to the root of the menu tree will frustrate users no end!
+// WORSE DESIGN: How about having the user have to push a button to repeat the current menu? When a time out could just
+// automatically do it for the user?
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-char-disease {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-handicap {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-police {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-school {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-college {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-animal {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-candidate {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-abuse {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-char-other {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-sorry {
+ s => {
+ begin:
+ Playback(telemarket-sorry);
+ // Sorry -- your organization is not exempt. Please stop calling us.
+ // Thank you. goodbye.
+ Hangup();
+ }
+}
+
+
+// BAD DESIGN: Hanging up on your audience, no matter what the outcome, is not a nice thing to do!
+
+context telemarket-exception {
+ s => {
+ begin:
+ Playback(telemarket-success);
+ // Congratulations. Your organization IS exempt. Please call us back,
+ // but this time, just act like a normal caller. Thank you. Goodbye.
+ Hangup();
+ }
+}
+
+
+// BAD DESIGN: Making long cascading menu choices is a nasty thing to do to callers!
+// BAD DESIGN: Putting the most frequently encountered items at the end of a list is also a nasty thing to do!
+
+
+// GOOD DESIGN: All rejection notices use a single context. All Acceptance also. To change a rejection to an
+// acceptance, just change the reference from telemarket-sorry to telemarket-exception
+
+
+context telemarket-political {
+ s => {
+ begin:
+ Playback(telemark-polit-intro);
+ // To see if your organization is exempt from our prohibitions,
+ // please follow the following prompts.
+ // please note that they are not in alphabetical order, and you will have to
+ // give them your full attention.
+ Playback(telemark-polit-choices);
+ // if You represent the America First Party, dial 1.
+ // if You represent the American Party, dial 2.
+ // if You represent the American Heritage Party, dial 3.
+ // if You represent the American Independent Party, dial 4.
+ // if You represent the American Nazi Party, dial 5.
+ // if You represent the Pot Party, dial 6.
+ // if You represent the American Reform Party, dial 7.
+ // if You represent the Christian Falenqist Party of America, dial 8.
+ // all others, please dial 9.
+ }
+ 1 => goto telemarket-poli-Am1st|s|begin;
+ 2 => goto telemarket-poli-American|s|begin;
+ 3 => goto telemarket-poli-AmHer|s|begin;
+ 4 => goto telemarket-poli-AmInd|s|begin;
+ 5 => goto telemarket-poli-AmNaz|s|begin;
+ 6 => goto telemarket-poli-Pot|s|begin;
+ 7 => goto telemarket-poli-AmRef|s|begin;
+ 8 => goto telemarket-poli-CFP|s|begin;
+ 9 => goto telemarket-political2|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-political2 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ // Thank you for your patience, and I congratulate you for your persistence.
+ // Just a few more options!
+ //
+ Playback(telemark-polit2-choices);
+ // if You represent the Communist Party USA, dial 1.
+ // if You represent the Constitution Party, dial 2.
+ // if You represent the Family Values Party, dial 3.
+ // if You represent the Freedom Socialist Party, dial 4.
+ // if You represent the Grass Roots Party, dial 5.
+ // if You represent the Green Party, dial 6.
+ // if You represent the Greens Party, dial 7.
+ // if You represent the Independence Party, dial 8.
+ // all others, goto 9.
+ }
+ 1 => goto telemarket-poli-Communist|s|begin;
+ 2 => goto telemarket-poli-Constit|s|begin;
+ 3 => goto telemarket-poli-FamVal|s|begin;
+ 4 => goto telemarket-poli-FreedSoc|s|begin;
+ 5 => goto telemarket-poli-Grassroot|s|begin;
+ 6 => goto telemarket-poli-Green|s|begin;
+ 7 => goto telemarket-poli-Greens|s|begin;
+ 8 => goto telemarket-poli-Independence|s|begin;
+ 9 => goto telemarket-political3|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+context telemarket-political3 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ Playback(telemark-polit3-choices);
+ // if You represent the Independant American Party, dial 1.
+ // if You represent the Labor Party, dial 2.
+ // if You represent the Libertarian Party, dial 3.
+ // if You represent the Light Party, dial 4.
+ // if You represent the Natural Law Party, dial 5.
+ // if You represent the New Party, dial 6.
+ // if You represent the New Union Party, dial 7.
+ // if You represent the Peace and Freedom Party, dial 8.
+ // all others, hang on, dial 9.
+ }
+ 1 => goto telemarket-poli-IndAm|s|begin;
+ 2 => goto telemarket-poli-Labor|s|begin;
+ 3 => goto telemarket-poli-Liber|s|begin;
+ 4 => goto telemarket-poli-Light|s|begin;
+ 5 => goto telemarket-poli-NatLaw|s|begin;
+ 6 => goto telemarket-poli-New|s|begin;
+ 7 => goto telemarket-poli-NewUn|s|begin;
+ 8 => goto telemarket-poli-PeaceFree|s|begin;
+ 9 => goto telemarket-political4|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-political4 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ Playback(telemark-polit4-choices);
+ // if You represent the Prohibition Party, dial 1.
+ // if You represent the Reform Party, dial 2.
+ // if You represent the Revolution , dial 3.
+ // if You represent the Socialist Party USA, dial 4.
+ // if You represent the Socialist Action Party, dial 5.
+ // if You represent the Socialist Equality Party, dial 6.
+ // if You represent the Socialist Labor Party, dial 7.
+ // if You represent the Socialist Workers Party, dial 8.
+ // all others, hang on, and dial 9.
+ }
+ 1 => goto telemarket-poli-Prohib|s|begin;
+ 2 => goto telemarket-poli-Ref|s|begin;
+ 3 => goto telemarket-poli-Revol|s|begin;
+ 4 => goto telemarket-poli-SocPart|s|begin;
+ 5 => goto telemarket-poli-SocAct|s|begin;
+ 6 => goto telemarket-poli-SocEq|s|begin;
+ 7 => goto telemarket-poli-SocLab|s|begin;
+ 8 => goto telemarket-poli-SocWork|s|begin;
+ 9 => goto telemarket-political5|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-political5 {
+ s => {
+ begin:
+ Playback(telemark-politx-intro);
+ Playback(telemark-polit5-choices);
+ // if You represent the Southern Party, dial 1.
+ // if You represent the Southern Independence Party, dial 2.
+ // if You represent the US Pacifist Party, dial 3.
+ // if You represent the We the People Party, dial 4.
+ // if You represent the Workers World Party, dial 5.
+ // if You represent the Democratic Party, dial 6.
+ // if You represent the Republican Party, dial 7.
+ // all others, may dial 8.
+ }
+ 1 => goto telemarket-poli-South|s|begin;
+ 2 => goto telemarket-poli-SoInd|s|begin;
+ 3 => goto telemarket-poli-USPac|s|begin;
+ 4 => goto telemarket-poli-WTP|s|begin;
+ 5 => goto telemarket-poli-WWP|s|begin;
+ 6 => goto telemarket-poli-Democrat|s|begin;
+ 7 => goto telemarket-poli-Repub|s|begin;
+ 8 => goto telemarket-poli-other|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-poli-other {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Repub {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Democrat {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-WWP {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-WTP {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-USPac {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SoInd {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-South {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocWork {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocLab {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocEq {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocAct {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-SocPart {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Revol {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Ref {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Prohib {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-PeaceFree {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-NewUn {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-New {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-NatLaw {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Light {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Liber {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Labor {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-IndAm {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Independence {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Greens {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Green {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Grassroot {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-FreedSoc {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-FamVal {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Constit {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Communist {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-CFP {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-AmRef {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+// BAD DESIGN: Putting in infinite loops in the menus, whether by design or mistake is not nice!
+context telemarket-poli-Pot {
+ s => {
+ begin:
+ goto telemarket-political|s|begin; // will the Pot Party Guys even notice an infinite loop?
+ }
+}
+
+context telemarket-poli-AmNaz {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-AmInd {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-AmHer {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-American {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+context telemarket-poli-Am1st {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+
+context telemarket-pollster {
+ s => {
+ begin:
+ Playback(telemark-poll-intro);
+ // I'm sorry-- We are just not available for doing any polling at the moment. So,
+ // please remove us from your list.
+ goto telemarket-sorry|s|begin;
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-research {
+ s => {
+ begin:
+ Playback(telemark-research-intro);
+ // I'd like to say I'd love to help you with your market survey, but that would be a complete
+ // and total lie. I am not interested in helping you with Market Surveys.
+ //
+ // Please remove me from your call list. It just doesn't pay enough. But Thank you.
+ goto telemarket-sorry|s|begin;
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-magazine {
+ s => {
+ begin:
+ Playback(telemark-mag-choices);
+ // If you are calling to see if I would like a NEW free subscription
+ // to your magazine or newsletter, please dial 1.
+ // If you are calling to see if I want to Renew an existing subscription, please dial 2.
+ // If you are representing some publisher, and want my opinion about something, or are doing
+ // some kind of survey, please dial 3.
+ // If you are calling to verify that some previous caller actually called me, and the
+ // verification information is correct, please dial 4.
+ // and if your call purpose doesn't match any of the above, please dial 5.
+ }
+ 1 => goto telemark-mag-new|s|begin;
+ 2 => goto telemark-mag-renew|s|begin;
+ 3 => goto telemark-mag-survey|s|begin;
+ 4 => goto telemark-mag-verify|s|begin;
+ 5 => goto telemark-mag-other|s|begin;
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-new {
+ s => {
+ begin:
+ Playback(telemark-mag-new);
+ // I'm sorry, I'm maxed out, and the answer is NO.
+ // If you really think I'd LOVE to add your publication to the pile I already get,
+ // Send something via the post. Don't call me.
+ // Thank you. bye.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-renew {
+ s => {
+ begin:
+ Playback(telemark-mag-renew);
+ // So, you want to see if I want to Renew, do you? The answer is most likely "YES".
+ //
+ // But, I will not answer a long list of questions over the phone. Send such
+ // categorization info via the post, and stop bothering me over the phone,
+ // if this is what you want.
+ // Do you need verification information? Normally I opt out of such nonsense, if possible.
+ // If not, use whatever of the following you can:
+ // My birth month is October.
+ // My birthplace is Kigali, in Rwanda, in Afica.
+ // My eye color is orange.
+ // All of these are wonderfully false, but I use them regularly for such purposes. Thank you.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-survey {
+ s => {
+ begin:
+ Playback(telemark-mag-survey);
+ // Sorry, I don't have time to answer survey or opinion questions. Find someone
+ // else to help build your marketing database, I guess. Good Luck.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-verify {
+ s => {
+ begin:
+ Playback(telemark-mag-verify);
+ // If you are calling to verify that your own agents aren't ripping you off,
+ // sorry, I can't help you. I opt out whenever I can, mainly because I'm not
+ // paid enough for this kind of thing. I always lie, and I can't remember
+ // what I might have said. Sorry. Goodbye.
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemark-mag-other {
+ s => {
+ begin:
+ goto telemarket-sorry|s|begin;
+ }
+}
+
+
+
+// BAD DESIGN: Is it entrapment, when you lure telemarketers to reveal their contact information,
+// Just so you can report them to the FTC/FCC? If it is, isn't it unethical for them
+// to hide their CID (via Anonymous, usually), to hide their identities from the public?
+
+// BTW -- What telemarketer would be stupid enough to fall for this? I'll bet not a single one!
+// For that matter, what telemarketer will be stupid enough to even enter any of this? I'll bet not a single one!
+// (but it was fun messing around).
+
+context telemarket-commercial {
+ s => {
+ begin:
+ Playback(telemark-comm-intro); // Script: Please leave your name, organization, and phone number, plus
+ // a short description of the purpose of your call, at the prompt.
+ // We will do our best to respond to your call! And, in the mean time,
+ // do not forget to add us to your no-call list!
+ Voicemail(u82);
+ goto telemarket-sorry|s|begin;
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
+
+
+context telemarket-other {
+ s => {
+ begin:
+ Playback(telemark-other-intro);
+ // Please review the previous menu options, and see if you really don't
+ // fit in one of the previous categories.
+ // If you do not, go ahead, and call me again, and let me know what category
+ // I should have included in the above list. I appreciate this. Thank you much!
+ Hangup();
+ }
+ t => goto telemarket|s|begin;
+ i => goto telemarket|s|begin;
+ o => goto telemarket|s|begin;
+}
diff --git a/trunk/pbx/ael/ael-test/ael-vtest17/extensions.ael b/trunk/pbx/ael/ael-test/ael-vtest17/extensions.ael
new file mode 100644
index 000000000..d13fe99d7
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest17/extensions.ael
@@ -0,0 +1,116 @@
+context dialextens
+{
+ /*
+ 101 thru 123, 149 thru 152
+ */
+ _10X => Dial(Zap/${EXTEN:2},30,tw);
+ _1ZX => Dial(Zap/${EXTEN:1},30,tw);
+}
+/*
+ Due to extenal wiring:
+
+ dialing 125 will ring 101
+ dialing 126 will ring 102
+ and so on until
+ dialing 147 will ring 123
+
+We can dial out on zap 69 thru 72; and 25-47
+
+*/
+
+context dialthrus
+{
+ /* 369-372; 325-347 */
+ _3XX => Dial(Zap/${EXTEN:1},30,tw);
+}
+
+context t1incoming
+{
+ includes
+ {
+ dialextens;
+ parkedcalls;
+ }
+ s => {
+ Answer();
+ Background(welcome-to-test-machine);
+ }
+
+}
+
+context t1extension
+{
+ includes
+ {
+ dialextens;
+ dialthrus;
+ }
+
+}
+
+context incoming
+{
+ includes
+ {
+ dialextens;
+ parkedcalls;
+ }
+ s => {
+ Answer();
+ Background(welcome-to-test-machine);
+ }
+}
+
+context extension
+{
+ includes
+ {
+ dialextens;
+ dialthrus;
+ }
+ 5 => {
+ Record(recording:gsm);
+ Background(recording);
+ }
+
+ 81 => {
+ iterations=1000000;
+ Set(time1=${EPOCH});
+ for(i=1; ${i}<${iterations}; i=${i}+1)
+ {
+ NoOp(Hello);
+ }
+ Set(time2=${EPOCH});
+ Verbose(The time diff is $[${time2} - ${time1} ] seconds);
+ Verbose(Which means that the priorities/sec = $[4* ${iterations} / (${time2} - ${time1}) ]);
+ SayNumber($[4 * ${iterations} / (${time2} - ${time1}) ]);
+ }
+ 82 => {
+ &ndeep(100000);
+ Verbose(Finished 100000 levels deep call!);
+ }
+ 83 => {
+ switch (${EXTEN})
+ {
+ pattern 8X:
+ Verbose(do something to prepare it);
+ pattern 9X:
+ Verbose(handle both 8x and 9x calls);
+ pattern [4-7]X:
+ Verbose(and this too!);
+
+ }
+
+ }
+}
+
+macro ndeep(level)
+{
+ if( ${level} == 0)
+ {
+ Verbose(2|Got to Level 0);
+ return;
+ }
+ &ndeep($[${level}-1]);
+ return;
+}
diff --git a/trunk/pbx/ael/ael-test/ael-vtest21/extensions.ael b/trunk/pbx/ael/ael-test/ael-vtest21/extensions.ael
new file mode 100644
index 000000000..95f25302a
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ael-vtest21/extensions.ael
@@ -0,0 +1,14 @@
+globals {
+ AXLHAFT=wow-to-the-tenth-power;
+ JibberWorthy=zinger3;
+ OFFICE_CODE=503;
+}
+
+context from-enum {
+
+ _${OFFICE_CODE}XXXX => {
+ Answer();
+ goto ${EXTEN:3}|1;
+ }
+}
+
diff --git a/trunk/pbx/ael/ael-test/ref.ael-ntest10 b/trunk/pbx/ael/ael-test/ref.ael-ntest10
new file mode 100644
index 000000000..9eb8ac989
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-ntest10
@@ -0,0 +1,171 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)
+
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1-4: The macro endsess does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 6-9: The macro nullchk does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 11-26: The macro endcall does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 13-13: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 28-44: The macro endcall2 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 36-36: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 46-68: The macro endcall3 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 48-48: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 60-60: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 70-96: The macro endcall4 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 72-72: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 84-84: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 87-87: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 98-131: The macro endcall5 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 106-106: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 119-119: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 122-122: A default case was automatically added to the switch.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+Executed ast_context_create(conts, name=endsess, registrar=pbx_ael);
+Executed ast_context_create(conts, name=nullchk, registrar=pbx_ael);
+Executed ast_context_create(conts, name=endcall, registrar=pbx_ael);
+Executed ast_context_create(conts, name=endcall2, registrar=pbx_ael);
+Executed ast_context_create(conts, name=endcall3, registrar=pbx_ael);
+Executed ast_context_create(conts, name=endcall4, registrar=pbx_ael);
+Executed ast_context_create(conts, name=endcall5, registrar=pbx_ael);
+Executed ast_add_extension2(context=endsess, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=NoOp, data=hithere, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endsess, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=nullchk, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=Set, data=LOCAL(type)=${ARG1}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=nullchk, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=NoOp, data=${type} is this, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=nullchk, rep=0, exten=s, priority=3, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=Set, data=LOCAL(type)=${ARG1}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=Goto, data=sw-1-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=s, priority=3, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall-1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=s, priority=4, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=_sw-1-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-1-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=10, label=(null), callerid=(null), appl=Gosub, data=nullchk,s,1(callid), FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=11, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?12:15, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=12, label=(null), callerid=(null), appl=Gosub, data=endsess,s,1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-1-out,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=14, label=(null), callerid=(null), appl=Goto, data=17, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=15, label=ptr1, callerid=(null), appl=Softhangup, data=${CHANNEL}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=16, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=17, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall-out-1-2, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=18, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall, rep=0, exten=sw-1-out, priority=19, label=(null), callerid=(null), appl=Goto, data=sw-1-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=Set, data=LOCAL(type)=${ARG1}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=Goto, data=sw-3-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=s, priority=3, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall2-3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=s, priority=4, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=_sw-3-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-3-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out2, priority=10, label=ptr1, callerid=(null), appl=Softhangup, data=${CHANNEL}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out2, priority=11, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out2, priority=12, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out2, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-3-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out, priority=10, label=(null), callerid=(null), appl=Gosub, data=nullchk,s,1(callid), FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out, priority=11, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?12:14, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out, priority=12, label=(null), callerid=(null), appl=Gosub, data=endsess,s,1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-3-out2,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out, priority=14, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall2-out-3-4, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall2, rep=0, exten=sw-3-out, priority=15, label=(null), callerid=(null), appl=Goto, data=sw-3-out2,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=Set, data=LOCAL(type)=${ARG1}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=Goto, data=sw-5-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=3, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall3-5, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=4, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?5:6, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=5, label=(null), callerid=(null), appl=Goto, data=sw-8-out,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=6, label=(null), callerid=(null), appl=NoOp, data=Finish if-endcall3-7, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=7, label=(null), callerid=(null), appl=Goto, data=sw-8-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=8, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall3-8, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=s, priority=9, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=_sw-8-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,8, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-8-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-out, priority=10, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?11:13, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-out, priority=11, label=ptr1, callerid=(null), appl=Softhangup, data=${CHANNEL}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-out, priority=12, label=(null), callerid=(null), appl=Goto, data=s,8, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-out, priority=13, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall3-out-8-9, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-out, priority=14, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-8-out, priority=15, label=(null), callerid=(null), appl=Goto, data=sw-8-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=_sw-5-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-5-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=10, label=(null), callerid=(null), appl=Gosub, data=nullchk,s,1(callid), FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=11, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?12:14, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=12, label=(null), callerid=(null), appl=Gosub, data=endsess,s,1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-8-out,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=14, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall3-out-5-6, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=15, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall3, rep=0, exten=sw-5-out, priority=16, label=(null), callerid=(null), appl=Goto, data=sw-5-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=Set, data=LOCAL(type)=${ARG1}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=Goto, data=sw-10-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=3, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall4-10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=4, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?5:6, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=5, label=(null), callerid=(null), appl=Goto, data=sw-14-in,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=6, label=(null), callerid=(null), appl=NoOp, data=Finish if-endcall4-12, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=7, label=(null), callerid=(null), appl=Goto, data=sw-13-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=8, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall4-13, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=s, priority=9, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=_sw-13-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,8, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-13-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-13-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-13-out, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-14-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-13-out, priority=11, label=(null), callerid=(null), appl=NoOp, data=Finish switch-sw-endcall4-out-13-14, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-13-out, priority=12, label=(null), callerid=(null), appl=Goto, data=sw-13-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=_sw-14-., priority=10, label=(null), callerid=(null), appl=Goto, data=sw-13-out,11, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-14-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-in, priority=10, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?11:13, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-in, priority=11, label=ptr1, callerid=(null), appl=Softhangup, data=${CHANNEL}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-in, priority=12, label=(null), callerid=(null), appl=Goto, data=sw-13-out,11, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-in, priority=13, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-sw-endcall4-out-13-in-14-15, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-in, priority=14, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-14-in, priority=15, label=(null), callerid=(null), appl=Goto, data=sw-14-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=_sw-10-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-10-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=10, label=(null), callerid=(null), appl=Gosub, data=nullchk,s,1(callid), FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=11, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?12:14, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=12, label=(null), callerid=(null), appl=Gosub, data=endsess,s,1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-14-in,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=14, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall4-out-10-11, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=15, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall4, rep=0, exten=sw-10-out, priority=16, label=(null), callerid=(null), appl=Goto, data=sw-10-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=1, label=(null), callerid=(null), appl=Set, data=LOCAL(type)=${ARG1}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=2, label=(null), callerid=(null), appl=Goto, data=sw-16-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=3, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall5-16, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=4, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?5:6, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=5, label=(null), callerid=(null), appl=Goto, data=sw-21-in,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=6, label=(null), callerid=(null), appl=NoOp, data=Finish if-endcall5-19, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=7, label=(null), callerid=(null), appl=Goto, data=sw-20-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=8, label=(null), callerid=(null), appl=NoOp, data=Finish switch-endcall5-20, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=s, priority=9, label=(null), callerid=(null), appl=Return, data=, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=_sw-20-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,8, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-20-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-20-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-20-out, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-21-${type},10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-20-out, priority=11, label=(null), callerid=(null), appl=NoOp, data=Finish switch-sw-endcall5-out-20-21, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-20-out, priority=12, label=(null), callerid=(null), appl=Goto, data=sw-20-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=_sw-21-., priority=10, label=(null), callerid=(null), appl=Goto, data=sw-20-out,11, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-21-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-in, priority=10, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?11:13, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-in, priority=11, label=ptr1, callerid=(null), appl=Softhangup, data=${CHANNEL}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-in, priority=12, label=(null), callerid=(null), appl=Goto, data=sw-20-out,11, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-in, priority=13, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-sw-endcall5-out-20-in-21-22, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-in, priority=14, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-21-in, priority=15, label=(null), callerid=(null), appl=Goto, data=sw-21-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=_sw-16-., priority=10, label=(null), callerid=(null), appl=Goto, data=s,3, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-, priority=10, label=(null), callerid=(null), appl=Goto, data=sw-16-.|10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=10, label=(null), callerid=(null), appl=Gosub, data=nullchk,s,1(callid), FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=11, label=ptr2, callerid=(null), appl=GotoIf, data=$[${testnotnull}]?12:14, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=12, label=(null), callerid=(null), appl=Gosub, data=endsess,s,1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-21-in,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=14, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall5-in-16-18, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=15, label=(null), callerid=(null), appl=Noop, data=esac, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-in, priority=16, label=(null), callerid=(null), appl=Goto, data=sw-16-.,10, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-out, priority=10, label=(null), callerid=(null), appl=Gosub, data=nullchk,s,1(callid), FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-out, priority=11, label=(null), callerid=(null), appl=GotoIf, data=$[${testnotnull}]?12:14, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-out, priority=12, label=(null), callerid=(null), appl=Gosub, data=endsess,s,1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-out, priority=13, label=(null), callerid=(null), appl=Goto, data=sw-21-in,ptr1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-out, priority=14, label=(null), callerid=(null), appl=NoOp, data=Finish if-sw-endcall5-out-16-17, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=endcall5, rep=0, exten=sw-16-out, priority=15, label=(null), callerid=(null), appl=Goto, data=sw-16-in,10, FREE, registrar=pbx_ael);
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+Executed ast_merge_contexts_and_delete();
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+Executed ast_walk_contexts();
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 7 contexts, 37 extensions, 131 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-ntest12 b/trunk/pbx/ael/ael-test/ref.ael-ntest12
new file mode 100644
index 000000000..184ce2d6c
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-ntest12
@@ -0,0 +1,30 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)
+
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+Executed ast_context_find_or_create(conts, name=test1, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=771, priority=1, label=(null), callerid=(null), appl=Set, data=i=$[0], FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=771, priority=2, label=(null), callerid=(null), appl=GotoIf, data=$[
+ ${i} <= 3]?3:6, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=771, priority=3, label=(null), callerid=(null), appl=NoOp, data=i is '${i}', FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=771, priority=4, label=(null), callerid=(null), appl=Set, data=i=$[ ${i} + 1 ], FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=771, priority=5, label=(null), callerid=(null), appl=Goto, data=2, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=771, priority=6, label=(null), callerid=(null), appl=NoOp, data=Finish for-test1-1, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=772, priority=1, label=(null), callerid=(null), appl=Set, data=i=$[0], FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=772, priority=2, label=(null), callerid=(null), appl=GotoIf, data=$[ ${i} <= 3]?3:6, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=772, priority=3, label=(null), callerid=(null), appl=NoOp, data=i is '${i}', FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=772, priority=4, label=(null), callerid=(null), appl=Set, data=i=$[ ${i} + 1 ], FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=772, priority=5, label=(null), callerid=(null), appl=Goto, data=2, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=test1, rep=0, exten=772, priority=6, label=(null), callerid=(null), appl=NoOp, data=Finish for-test1-2, FREE, registrar=pbx_ael);
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+Executed ast_merge_contexts_and_delete();
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+Executed ast_walk_contexts();
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 2 extensions, 12 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-ntest22 b/trunk/pbx/ael/ael-test/ref.ael-ntest22
new file mode 100644
index 000000000..c9317f64e
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-ntest22
@@ -0,0 +1,54 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)
+
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t1/a.ael, 41 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t1/b.ael, 42 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t1/c.ael, 106 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t2/d.ael, 41 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t2/e.ael, 42 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t2/f.ael, 82 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././qq.ael, 45 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t3/g.ael, 41 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t3/h.ael, 42 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t3/i.ael, 41 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././t3/j.ael, 43 chars
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+Executed ast_context_find_or_create(conts, name=a, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=b, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=c, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=d, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=e, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=qq, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=f, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=g, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=h, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=i, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=j, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=w, registrar=pbx_ael);
+Executed ast_context_find_or_create(conts, name=z, registrar=pbx_ael);
+Executed ast_add_extension2(context=a, rep=0, exten=134, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, a, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=b, rep=0, exten=456, priority=1, label=(null), callerid=(null), appl=NoOp, data=hithere, b, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=c, rep=0, exten=567, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, c, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=d, rep=0, exten=134, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, d, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=e, rep=0, exten=456, priority=1, label=(null), callerid=(null), appl=NoOp, data=hithere, e, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=qq, rep=0, exten=567, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, qq, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=f, rep=0, exten=567, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, f, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=g, rep=0, exten=134, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, g, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=h, rep=0, exten=456, priority=1, label=(null), callerid=(null), appl=NoOp, data=hithere, h, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=i, rep=0, exten=134, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, i, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=j, rep=0, exten=567, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, j, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=w, rep=0, exten=890, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, w, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=z, rep=0, exten=123, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, z, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=z, rep=0, exten=124, priority=1, label=(null), callerid=(null), appl=NoOp, data=hi there, z, FREE, registrar=pbx_ael);
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+Executed ast_merge_contexts_and_delete();
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+Executed ast_walk_contexts();
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 13 contexts, 13 extensions, 14 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-ntest9 b/trunk/pbx/ael/ael-test/ref.ael-ntest9
new file mode 100644
index 000000000..e40790e59
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-ntest9
@@ -0,0 +1,23 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)
+
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+Executed ast_context_find_or_create(conts, name=workext, registrar=pbx_ael);
+Executed ast_context_add_ignorepat2(con, value=8, registrar=pbx_ael);
+Executed ast_context_add_ignorepat2(con, value=9, registrar=pbx_ael);
+Executed ast_add_extension2(context=workext, rep=0, exten=793, priority=1, label=(null), callerid=(null), appl=Set, data=QUERYSTRING=SELECT\ foo\,\ bar\ FROM\ foobar, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=workext, rep=0, exten=793, priority=2, label=(null), callerid=(null), appl=Verbose, data=2|${QUERYSTRING}, FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=workext, rep=0, exten=793, priority=3, label=(null), callerid=(null), appl=Set, data=query=$["SELECT foo\, bar FROM foobar" ], FREE, registrar=pbx_ael);
+Executed ast_add_extension2(context=workext, rep=0, exten=793, priority=4, label=(null), callerid=(null), appl=Verbose, data=2|${query}, FREE, registrar=pbx_ael);
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+Executed ast_merge_contexts_and_delete();
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+Executed ast_walk_contexts();
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 1 extensions, 4 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test1 b/trunk/pbx/ael/ael-test/ref.ael-test1
new file mode 100644
index 000000000..5538514fe
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test1
@@ -0,0 +1,18 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 2-16: The macro testdial does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 18-25: The macro exten-gen does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:1362 func: check_goto Warning: file ./extensions.ael, line 21-21: It's bad form to have a goto in a macro to a target outside the macro!
+LOG: lev:3 file:pval.c line:1362 func: check_goto Warning: file ./extensions.ael, line 23-23: It's bad form to have a goto in a macro to a target outside the macro!
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 58-58: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:922 func: check_dow Warning: file ./extensions.ael, line 67-67: The day (m0n) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!
+LOG: lev:3 file:pval.c line:880 func: check_timerange Warning: file ./extensions.ael, line 78-78: The end time (25:00) is out of range!
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 5 contexts, 16 extensions, 157 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test11 b/trunk/pbx/ael/ael-test/ref.ael-test11
new file mode 100644
index 000000000..c47f2b8bf
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test11
@@ -0,0 +1,13 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:4 file:pval.c line:1147 func: check_label Error: file ./extensions.ael, line 13-13: Duplicate label lab1! Previously defined at file ./extensions.ael, line 8.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 32-32: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 44-44: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 47-47: A default case was automatically added to the switch.
+LOG: lev:4 file:pval.c line:1147 func: check_label Error: file ./extensions.ael, line 49-49: Duplicate label ptr1! Previously defined at file ./extensions.ael, line 33.
+LOG: lev:4 file:pbx_ael.c line:139 func: pbx_load_module Sorry, but 0 syntax errors and 2 semantic errors were detected. It doesn't make sense to compile.
+LOG: lev:4 file:ael2_parse line:531 func: main 0 contexts, 0 extensions, 0 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test14 b/trunk/pbx/ael/ael-test/ref.ael-test14
new file mode 100644
index 000000000..2cd4ed1b1
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test14
@@ -0,0 +1,11 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 13-13: A default case was automatically added to the switch.
+LOG: lev:4 file:pval.c line:1071 func: check_continue Error: file ./extensions.ael, line 15-15: 'continue' not in 'for' or 'while' statement!
+LOG: lev:4 file:pval.c line:1052 func: check_break Error: file ./extensions.ael, line 17-17: 'break' not in switch, for, or while statement!
+LOG: lev:4 file:pbx_ael.c line:139 func: pbx_load_module Sorry, but 0 syntax errors and 2 semantic errors were detected. It doesn't make sense to compile.
+LOG: lev:4 file:ael2_parse line:531 func: main 0 contexts, 0 extensions, 0 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test15 b/trunk/pbx/ael/ael-test/ref.ael-test15
new file mode 100644
index 000000000..995068563
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test15
@@ -0,0 +1,12 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:4070 func: ast_compile_ael2 Warning: file ./extensions.ael, line 8-13: Empty Extension!
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 0 extensions, 0 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test16 b/trunk/pbx/ael/ael-test/ref.ael-test16
new file mode 100644
index 000000000..f43257d46
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test16
@@ -0,0 +1,12 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:3786 func: add_extensions This file is Empty!
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 0 extensions, 0 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test18 b/trunk/pbx/ael/ael-test/ref.ael-test18
new file mode 100644
index 000000000..072135ef2
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test18
@@ -0,0 +1,11 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 7 extensions, 27 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test19 b/trunk/pbx/ael/ael-test/ref.ael-test19
new file mode 100644
index 000000000..e093d75e5
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test19
@@ -0,0 +1,18 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:2300 func: check_context_names Warning: file ./extensions.ael, line 49-62: The context name (incoming) is also declared in file ./extensions.ael, line 62-69! (and neither is marked 'extend')
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 71-175: The macro std-priv-exten does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:2284 func: check_switch_expr Warning: file ./extensions.ael, line 245-246: A default case was automatically added to the switch.
+LOG: lev:3 file:pval.c line:2426 func: check_pval_item Warning: file ./extensions.ael, line 312-312: macro call to non-existent funcA! (Not even in the extensions.conf stuff!)
+LOG: lev:3 file:pval.c line:2426 func: check_pval_item Warning: file ./extensions.ael, line 313-313: macro call to non-existent funcD! (Not even in the extensions.conf stuff!)
+LOG: lev:3 file:pval.c line:1346 func: check_goto Warning: file ./extensions.ael, line 319-319: goto: Couldn't find goto target test5|s|1, not even in extensions.conf!
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 363-366: The macro dialoutpstn does not end with a return; I will insert one.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 13 contexts, 57 extensions, 188 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test2 b/trunk/pbx/ael/ael-test/ref.ael-test2
new file mode 100644
index 000000000..892b63464
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test2
@@ -0,0 +1,28 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././apptest.ael2, 3474 chars
+LOG: lev:3 file:ael.y line:546 func: ael_yyparse ==== File: ././apptest.ael2, Line 46, Cols: 8-11: Suggestion: Use the goto statement instead of the Goto() application call in AEL.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 35-35: application call to EndWhile affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 37-37: application call to ExecIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 38-38: application call to ExecIfTime affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 44-44: application call to Gosub affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 45-45: application call to GosubIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:1346 func: check_goto Warning: file ././apptest.ael2, line 46-46: goto: Couldn't find goto target cont|exten|prior, not even in extensions.conf!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 47-47: application call to GotoIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 48-48: application call to GotoIfTime affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 58-58: application call to Macro affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2512 func: check_pval_item Warning: file ././apptest.ael2, line 59-59: I am converting the MacroExit call here to a return statement.
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 60-60: application call to MacroIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 85-85: application call to Random affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 94-94: application call to Return affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 119-119: application call to StackPop affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 141-141: application call to While affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 1 extensions, 142 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test20 b/trunk/pbx/ael/ael-test/ref.ael-test20
new file mode 100644
index 000000000..065281f94
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test20
@@ -0,0 +1,11 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 1 extensions, 1 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test3 b/trunk/pbx/ael/ael-test/ref.ael-test3
new file mode 100644
index 000000000..5ff89ef8b
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test3
@@ -0,0 +1,99 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././include1.ael2, 78 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././include2.ael2, 98 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././include3.ael2, 57 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././include5.ael2, 56 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././include4.ael2, 87 chars
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././telemarket_torture.ael2, 28036 chars
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 14-34: The macro std-exten does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:1362 func: check_goto Warning: file ./extensions.ael, line 17-17: It's bad form to have a goto in a macro to a target outside the macro!
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 36-59: The macro std-priv-exten_1 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 62-85: The macro std-priv-exten_2 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 88-111: The macro std-priv-exten_3 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 114-137: The macro std-priv-exten_4 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 140-163: The macro std-priv-exten_5 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 166-189: The macro std-priv-exten_6 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 192-215: The macro std-priv-exten_7 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 218-241: The macro std-priv-exten_8 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 244-267: The macro std-priv-exten_9 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 270-293: The macro std-priv-exten_10 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 296-319: The macro std-priv-exten_11 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 322-345: The macro std-priv-exten_12 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 348-371: The macro std-priv-exten_13 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 374-397: The macro std-priv-exten_14 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 400-423: The macro std-priv-exten_15 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 426-449: The macro std-priv-exten_16 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 452-475: The macro std-priv-exten_17 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 478-501: The macro std-priv-exten_18 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 504-527: The macro std-priv-exten_19 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 530-553: The macro std-priv-exten_20 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 556-579: The macro std-priv-exten_21 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 582-605: The macro std-priv-exten_22 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 608-631: The macro std-priv-exten_23 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 634-657: The macro std-priv-exten_24 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 660-683: The macro std-priv-exten_25 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 686-709: The macro std-priv-exten_26 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 712-735: The macro std-priv-exten_27 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 738-761: The macro std-priv-exten_28 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 764-787: The macro std-priv-exten_29 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 790-813: The macro std-priv-exten_30 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 816-839: The macro std-priv-exten_31 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 842-865: The macro std-priv-exten_32 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 868-891: The macro std-priv-exten_33 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 894-917: The macro std-priv-exten_34 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 920-943: The macro std-priv-exten_35 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 946-969: The macro std-priv-exten_36 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 972-995: The macro std-priv-exten_37 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 998-1021: The macro std-priv-exten_38 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1024-1047: The macro std-priv-exten_39 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1050-1073: The macro std-priv-exten_40 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1076-1099: The macro std-priv-exten_41 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1102-1125: The macro std-priv-exten_42 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1128-1151: The macro std-priv-exten_43 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1154-1177: The macro std-priv-exten_44 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1180-1203: The macro std-priv-exten_45 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1206-1229: The macro std-priv-exten_46 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1232-1255: The macro std-priv-exten_47 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1258-1281: The macro std-priv-exten_48 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1284-1307: The macro std-priv-exten_49 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1310-1333: The macro std-priv-exten_50 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1336-1359: The macro std-priv-exten_51 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1362-1385: The macro std-priv-exten_52 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1388-1411: The macro std-priv-exten_53 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1414-1437: The macro std-priv-exten_54 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1440-1463: The macro std-priv-exten_55 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1466-1489: The macro std-priv-exten_56 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1492-1515: The macro std-priv-exten_57 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1518-1541: The macro std-priv-exten_58 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1544-1567: The macro std-priv-exten_59 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1570-1593: The macro std-priv-exten_60 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1596-1619: The macro std-priv-exten_61 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1622-1645: The macro std-priv-exten_62 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1648-1671: The macro std-priv-exten_63 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1674-1697: The macro std-priv-exten_64 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1700-1723: The macro std-priv-exten_65 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1726-1749: The macro std-priv-exten_66 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1752-1775: The macro std-priv-exten_67 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1778-1801: The macro std-priv-exten_68 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1804-1827: The macro std-priv-exten_69 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1830-1853: The macro std-priv-exten_70 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1856-1879: The macro std-priv-exten_71 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1882-1905: The macro std-priv-exten_72 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1908-1931: The macro std-priv-exten_73 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1934-1957: The macro std-priv-exten does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1959-1995: The macro fillcidname does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 1997-2015: The macro ciddial does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 2017-2028: The macro ciddial3 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 2030-2048: The macro ciddial2 does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 2050-2065: The macro callerid-liar does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 2067-2072: The macro callerid-bad does not end with a return; I will insert one.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 172 contexts, 934 extensions, 2482 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test4 b/trunk/pbx/ael/ael-test/ref.ael-test4
new file mode 100644
index 000000000..892b63464
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test4
@@ -0,0 +1,28 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:ael.flex line:662 func: setup_filestack --Read in included file ././apptest.ael2, 3474 chars
+LOG: lev:3 file:ael.y line:546 func: ael_yyparse ==== File: ././apptest.ael2, Line 46, Cols: 8-11: Suggestion: Use the goto statement instead of the Goto() application call in AEL.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 35-35: application call to EndWhile affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 37-37: application call to ExecIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 38-38: application call to ExecIfTime affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 44-44: application call to Gosub affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 45-45: application call to GosubIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:1346 func: check_goto Warning: file ././apptest.ael2, line 46-46: goto: Couldn't find goto target cont|exten|prior, not even in extensions.conf!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 47-47: application call to GotoIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 48-48: application call to GotoIfTime affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 58-58: application call to Macro affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2512 func: check_pval_item Warning: file ././apptest.ael2, line 59-59: I am converting the MacroExit call here to a return statement.
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 60-60: application call to MacroIf affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 85-85: application call to Random affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 94-94: application call to Return affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 119-119: application call to StackPop affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:3 file:pval.c line:2507 func: check_pval_item Warning: file ././apptest.ael2, line 141-141: application call to While affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 1 extensions, 142 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test5 b/trunk/pbx/ael/ael-test/ref.ael-test5
new file mode 100644
index 000000000..79c327413
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test5
@@ -0,0 +1,14 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 130-183: The macro stdexten does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 185-192: The macro uvm does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 194-201: The macro bvm does not end with a return; I will insert one.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 38 contexts, 91 extensions, 493 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test6 b/trunk/pbx/ael/ael-test/ref.ael-test6
new file mode 100644
index 000000000..968c7c71e
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test6
@@ -0,0 +1,24 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:4 file:ael.flex line:288 func: ael_yylex File=./extensions.ael, line=165, column=49: Mismatched '}' in expression!
+LOG: lev:4 file:ael.y line:772 func: ael_yyerror ==== File: ./extensions.ael, Line 165, Cols: 51-51: Error: syntax error, unexpected '=', expecting ')'
+LOG: lev:4 file:ael.flex line:288 func: ael_yylex File=./extensions.ael, line=174, column=49: Mismatched '}' in expression!
+LOG: lev:4 file:ael.y line:772 func: ael_yyerror ==== File: ./extensions.ael, Line 174, Cols: 51-51: Error: syntax error, unexpected '=', expecting ')'
+LOG: lev:4 file:ael.flex line:288 func: ael_yylex File=./extensions.ael, line=222, column=41: Mismatched '}' in expression!
+LOG: lev:4 file:ael.y line:772 func: ael_yyerror ==== File: ./extensions.ael, Line 222, Cols: 43-43: Error: syntax error, unexpected '=', expecting ')'
+LOG: lev:4 file:ael.y line:772 func: ael_yyerror ==== File: ./extensions.ael, Line 291, Cols: 21-28: Error: syntax error, unexpected word, expecting '(' or ';' or '=' or ':'
+LOG: lev:4 file:ael.y line:772 func: ael_yyerror ==== File: ./extensions.ael, Line 291, Cols: 32-32: Error: syntax error, unexpected '|', expecting '(' or ';' or '=' or ':'
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 116-125: The macro dialout does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 129-182: The macro stdexten does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 184-191: The macro uvm does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 193-200: The macro bvm does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 202-207: The macro checkdnd does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 209-216: The macro checkcf does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 218-230: The macro checkcfb does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 688-694: The macro check-psd-exists does not end with a return; I will insert one.
+LOG: lev:4 file:pbx_ael.c line:139 func: pbx_load_module Sorry, but 5 syntax errors and 0 semantic errors were detected. It doesn't make sense to compile.
+LOG: lev:4 file:ael2_parse line:531 func: main 0 contexts, 0 extensions, 0 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test7 b/trunk/pbx/ael/ael-test/ref.ael-test7
new file mode 100644
index 000000000..69f0c9f91
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test7
@@ -0,0 +1,19 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 22-42: The macro stdexten does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 44-49: The macro announce_minutes does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 59-89: The macro checkanddial does not end with a return; I will insert one.
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 91-100: The macro trunkdial does not end with a return; I will insert one.
+LOG: lev:4 file:pval.c line:2468 func: check_pval_item Error: file ./extensions.ael, line 98-98: The macro call to checkanddial has 5 arguments, but the macro definition has 7 arguments
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 102-112: The macro checklocal does not end with a return; I will insert one.
+LOG: lev:4 file:pval.c line:2468 func: check_pval_item Error: file ./extensions.ael, line 107-107: The macro call to checkanddial has 5 arguments, but the macro definition has 7 arguments
+LOG: lev:3 file:pval.c line:671 func: check_macro_returns Warning: file ./extensions.ael, line 114-119: The macro autodial does not end with a return; I will insert one.
+LOG: lev:4 file:pval.c line:2468 func: check_pval_item Error: file ./extensions.ael, line 284-284: The macro call to checkanddial has 5 arguments, but the macro definition has 7 arguments
+LOG: lev:4 file:pval.c line:2468 func: check_pval_item Error: file ./extensions.ael, line 287-287: The macro call to checkanddial has 5 arguments, but the macro definition has 7 arguments
+LOG: lev:3 file:pval.c line:2426 func: check_pval_item Warning: file ./extensions.ael, line 452-452: macro call to non-existent std-exten-ael! (Not even in the extensions.conf stuff!)
+LOG: lev:4 file:pbx_ael.c line:139 func: pbx_load_module Sorry, but 0 syntax errors and 4 semantic errors were detected. It doesn't make sense to compile.
+LOG: lev:4 file:ael2_parse line:531 func: main 0 contexts, 0 extensions, 0 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-test8 b/trunk/pbx/ael/ael-test/ref.ael-test8
new file mode 100644
index 000000000..4e5d0aa37
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-test8
@@ -0,0 +1,11 @@
+
+(If you find progress and other non-error messages irritating, you can use -q to suppress them)
+
+(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)
+LOG: lev:2 file:pbx_ael.c line:113 func: pbx_load_module Starting AEL load process.
+LOG: lev:2 file:pbx_ael.c line:126 func: pbx_load_module AEL load process: parsed config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:129 func: pbx_load_module AEL load process: checked config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:131 func: pbx_load_module AEL load process: compiled config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:134 func: pbx_load_module AEL load process: merged config file name './extensions.ael'.
+LOG: lev:2 file:pbx_ael.c line:137 func: pbx_load_module AEL load process: verified config file name './extensions.ael'.
+LOG: lev:4 file:ael2_parse line:531 func: main 1 contexts, 7 extensions, 17 priorities
diff --git a/trunk/pbx/ael/ael-test/ref.ael-vtest13 b/trunk/pbx/ael/ael-test/ref.ael-vtest13
new file mode 100644
index 000000000..989a18258
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-vtest13
@@ -0,0 +1,3030 @@
+[globals]
+static=yes
+writeprotect=yes
+CONSOLE=Console/dsp
+IAXINFO=murf:tlhfckoct
+FWDNUMBER=544788
+FWDCIDNAME="Joe-Worker"
+FWDPASSWORD=zingledoodle
+FWDRINGS=Zap/6
+FWDVMBOX=1
+
+
+[std-exten]
+exten => s,1,Set(LOCAL(ext)=${ARG1})
+exten => s,2,Set(LOCAL(dev)=${ARG2})
+exten => s,3,Dial(${dev}/${ext}\,20)
+exten => s,4,Goto(sw-1-${DIALSTATUS}\,10)
+exten => s,5,NoOp(Finish switch-std-exten-1)
+exten => s,6,Return()
+exten => a,1,VoiceMailMain(${ext})
+exten => _sw-1-.,10,Voicemail(u${ext})
+exten => _sw-1-.,11,Goto(s\,5)
+exten => sw-1-,10,Goto(sw-1-.|10)
+exten => sw-1-ANSWER,10,Goto(s\,5)
+exten => sw-1-NOANSWER,10,Voicemail(u${ext})
+exten => sw-1-NOANSWER,11,Goto(s\,5)
+exten => sw-1-BUSY,10,Voicemail(b${ext})
+exten => sw-1-BUSY,11,Goto(s\,5)
+
+
+[std-priv-exten_1]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-3-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_1-3)
+exten => s,11,Return()
+exten => _sw-3-.,10,Voicemail(u${ext})
+exten => _sw-3-.,11,Goto(s\,10)
+exten => sw-3-,10,Goto(sw-3-.|10)
+exten => sw-3-NOANSWER,10,Voicemail(u${ext})
+exten => sw-3-NOANSWER,11,Goto(s\,10)
+exten => sw-3-ANSWER,10,Goto(s\,10)
+exten => sw-3-BUSY,10,Voicemail(b${ext})
+exten => sw-3-BUSY,11,Goto(s\,10)
+exten => sw-3-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-3-DONTCALL,11,Goto(s\,10)
+exten => sw-3-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-3-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_2]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-4-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_2-4)
+exten => s,11,Return()
+exten => _sw-4-.,10,Voicemail(u${ext})
+exten => _sw-4-.,11,Goto(s\,10)
+exten => sw-4-,10,Goto(sw-4-.|10)
+exten => sw-4-NOANSWER,10,Voicemail(u${ext})
+exten => sw-4-NOANSWER,11,Goto(s\,10)
+exten => sw-4-ANSWER,10,Goto(s\,10)
+exten => sw-4-BUSY,10,Voicemail(b${ext})
+exten => sw-4-BUSY,11,Goto(s\,10)
+exten => sw-4-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-4-DONTCALL,11,Goto(s\,10)
+exten => sw-4-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-4-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_3]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-5-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_3-5)
+exten => s,11,Return()
+exten => _sw-5-.,10,Voicemail(u${ext})
+exten => _sw-5-.,11,Goto(s\,10)
+exten => sw-5-,10,Goto(sw-5-.|10)
+exten => sw-5-NOANSWER,10,Voicemail(u${ext})
+exten => sw-5-NOANSWER,11,Goto(s\,10)
+exten => sw-5-ANSWER,10,Goto(s\,10)
+exten => sw-5-BUSY,10,Voicemail(b${ext})
+exten => sw-5-BUSY,11,Goto(s\,10)
+exten => sw-5-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-5-DONTCALL,11,Goto(s\,10)
+exten => sw-5-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-5-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_4]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-6-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_4-6)
+exten => s,11,Return()
+exten => _sw-6-.,10,Voicemail(u${ext})
+exten => _sw-6-.,11,Goto(s\,10)
+exten => sw-6-,10,Goto(sw-6-.|10)
+exten => sw-6-NOANSWER,10,Voicemail(u${ext})
+exten => sw-6-NOANSWER,11,Goto(s\,10)
+exten => sw-6-ANSWER,10,Goto(s\,10)
+exten => sw-6-BUSY,10,Voicemail(b${ext})
+exten => sw-6-BUSY,11,Goto(s\,10)
+exten => sw-6-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-6-DONTCALL,11,Goto(s\,10)
+exten => sw-6-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-6-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_5]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-7-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_5-7)
+exten => s,11,Return()
+exten => _sw-7-.,10,Voicemail(u${ext})
+exten => _sw-7-.,11,Goto(s\,10)
+exten => sw-7-,10,Goto(sw-7-.|10)
+exten => sw-7-NOANSWER,10,Voicemail(u${ext})
+exten => sw-7-NOANSWER,11,Goto(s\,10)
+exten => sw-7-ANSWER,10,Goto(s\,10)
+exten => sw-7-BUSY,10,Voicemail(b${ext})
+exten => sw-7-BUSY,11,Goto(s\,10)
+exten => sw-7-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-7-DONTCALL,11,Goto(s\,10)
+exten => sw-7-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-7-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_6]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-8-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_6-8)
+exten => s,11,Return()
+exten => _sw-8-.,10,Voicemail(u${ext})
+exten => _sw-8-.,11,Goto(s\,10)
+exten => sw-8-,10,Goto(sw-8-.|10)
+exten => sw-8-NOANSWER,10,Voicemail(u${ext})
+exten => sw-8-NOANSWER,11,Goto(s\,10)
+exten => sw-8-ANSWER,10,Goto(s\,10)
+exten => sw-8-BUSY,10,Voicemail(b${ext})
+exten => sw-8-BUSY,11,Goto(s\,10)
+exten => sw-8-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-8-DONTCALL,11,Goto(s\,10)
+exten => sw-8-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-8-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_7]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-9-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_7-9)
+exten => s,11,Return()
+exten => _sw-9-.,10,Voicemail(u${ext})
+exten => _sw-9-.,11,Goto(s\,10)
+exten => sw-9-,10,Goto(sw-9-.|10)
+exten => sw-9-NOANSWER,10,Voicemail(u${ext})
+exten => sw-9-NOANSWER,11,Goto(s\,10)
+exten => sw-9-ANSWER,10,Goto(s\,10)
+exten => sw-9-BUSY,10,Voicemail(b${ext})
+exten => sw-9-BUSY,11,Goto(s\,10)
+exten => sw-9-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-9-DONTCALL,11,Goto(s\,10)
+exten => sw-9-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-9-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_8]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-10-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_8-10)
+exten => s,11,Return()
+exten => _sw-10-.,10,Voicemail(u${ext})
+exten => _sw-10-.,11,Goto(s\,10)
+exten => sw-10-,10,Goto(sw-10-.|10)
+exten => sw-10-NOANSWER,10,Voicemail(u${ext})
+exten => sw-10-NOANSWER,11,Goto(s\,10)
+exten => sw-10-ANSWER,10,Goto(s\,10)
+exten => sw-10-BUSY,10,Voicemail(b${ext})
+exten => sw-10-BUSY,11,Goto(s\,10)
+exten => sw-10-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-10-DONTCALL,11,Goto(s\,10)
+exten => sw-10-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-10-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_9]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-11-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_9-11)
+exten => s,11,Return()
+exten => _sw-11-.,10,Voicemail(u${ext})
+exten => _sw-11-.,11,Goto(s\,10)
+exten => sw-11-,10,Goto(sw-11-.|10)
+exten => sw-11-NOANSWER,10,Voicemail(u${ext})
+exten => sw-11-NOANSWER,11,Goto(s\,10)
+exten => sw-11-ANSWER,10,Goto(s\,10)
+exten => sw-11-BUSY,10,Voicemail(b${ext})
+exten => sw-11-BUSY,11,Goto(s\,10)
+exten => sw-11-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-11-DONTCALL,11,Goto(s\,10)
+exten => sw-11-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-11-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_10]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-12-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_10-12)
+exten => s,11,Return()
+exten => _sw-12-.,10,Voicemail(u${ext})
+exten => _sw-12-.,11,Goto(s\,10)
+exten => sw-12-,10,Goto(sw-12-.|10)
+exten => sw-12-NOANSWER,10,Voicemail(u${ext})
+exten => sw-12-NOANSWER,11,Goto(s\,10)
+exten => sw-12-ANSWER,10,Goto(s\,10)
+exten => sw-12-BUSY,10,Voicemail(b${ext})
+exten => sw-12-BUSY,11,Goto(s\,10)
+exten => sw-12-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-12-DONTCALL,11,Goto(s\,10)
+exten => sw-12-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-12-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_11]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-13-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_11-13)
+exten => s,11,Return()
+exten => _sw-13-.,10,Voicemail(u${ext})
+exten => _sw-13-.,11,Goto(s\,10)
+exten => sw-13-,10,Goto(sw-13-.|10)
+exten => sw-13-NOANSWER,10,Voicemail(u${ext})
+exten => sw-13-NOANSWER,11,Goto(s\,10)
+exten => sw-13-ANSWER,10,Goto(s\,10)
+exten => sw-13-BUSY,10,Voicemail(b${ext})
+exten => sw-13-BUSY,11,Goto(s\,10)
+exten => sw-13-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-13-DONTCALL,11,Goto(s\,10)
+exten => sw-13-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-13-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_12]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-14-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_12-14)
+exten => s,11,Return()
+exten => _sw-14-.,10,Voicemail(u${ext})
+exten => _sw-14-.,11,Goto(s\,10)
+exten => sw-14-,10,Goto(sw-14-.|10)
+exten => sw-14-NOANSWER,10,Voicemail(u${ext})
+exten => sw-14-NOANSWER,11,Goto(s\,10)
+exten => sw-14-ANSWER,10,Goto(s\,10)
+exten => sw-14-BUSY,10,Voicemail(b${ext})
+exten => sw-14-BUSY,11,Goto(s\,10)
+exten => sw-14-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-14-DONTCALL,11,Goto(s\,10)
+exten => sw-14-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-14-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_13]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-15-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_13-15)
+exten => s,11,Return()
+exten => _sw-15-.,10,Voicemail(u${ext})
+exten => _sw-15-.,11,Goto(s\,10)
+exten => sw-15-,10,Goto(sw-15-.|10)
+exten => sw-15-NOANSWER,10,Voicemail(u${ext})
+exten => sw-15-NOANSWER,11,Goto(s\,10)
+exten => sw-15-ANSWER,10,Goto(s\,10)
+exten => sw-15-BUSY,10,Voicemail(b${ext})
+exten => sw-15-BUSY,11,Goto(s\,10)
+exten => sw-15-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-15-DONTCALL,11,Goto(s\,10)
+exten => sw-15-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-15-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_14]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-16-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_14-16)
+exten => s,11,Return()
+exten => _sw-16-.,10,Voicemail(u${ext})
+exten => _sw-16-.,11,Goto(s\,10)
+exten => sw-16-,10,Goto(sw-16-.|10)
+exten => sw-16-NOANSWER,10,Voicemail(u${ext})
+exten => sw-16-NOANSWER,11,Goto(s\,10)
+exten => sw-16-ANSWER,10,Goto(s\,10)
+exten => sw-16-BUSY,10,Voicemail(b${ext})
+exten => sw-16-BUSY,11,Goto(s\,10)
+exten => sw-16-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-16-DONTCALL,11,Goto(s\,10)
+exten => sw-16-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-16-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_15]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-17-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_15-17)
+exten => s,11,Return()
+exten => _sw-17-.,10,Voicemail(u${ext})
+exten => _sw-17-.,11,Goto(s\,10)
+exten => sw-17-,10,Goto(sw-17-.|10)
+exten => sw-17-NOANSWER,10,Voicemail(u${ext})
+exten => sw-17-NOANSWER,11,Goto(s\,10)
+exten => sw-17-ANSWER,10,Goto(s\,10)
+exten => sw-17-BUSY,10,Voicemail(b${ext})
+exten => sw-17-BUSY,11,Goto(s\,10)
+exten => sw-17-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-17-DONTCALL,11,Goto(s\,10)
+exten => sw-17-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-17-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_16]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-18-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_16-18)
+exten => s,11,Return()
+exten => _sw-18-.,10,Voicemail(u${ext})
+exten => _sw-18-.,11,Goto(s\,10)
+exten => sw-18-,10,Goto(sw-18-.|10)
+exten => sw-18-NOANSWER,10,Voicemail(u${ext})
+exten => sw-18-NOANSWER,11,Goto(s\,10)
+exten => sw-18-ANSWER,10,Goto(s\,10)
+exten => sw-18-BUSY,10,Voicemail(b${ext})
+exten => sw-18-BUSY,11,Goto(s\,10)
+exten => sw-18-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-18-DONTCALL,11,Goto(s\,10)
+exten => sw-18-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-18-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_17]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-19-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_17-19)
+exten => s,11,Return()
+exten => _sw-19-.,10,Voicemail(u${ext})
+exten => _sw-19-.,11,Goto(s\,10)
+exten => sw-19-,10,Goto(sw-19-.|10)
+exten => sw-19-NOANSWER,10,Voicemail(u${ext})
+exten => sw-19-NOANSWER,11,Goto(s\,10)
+exten => sw-19-ANSWER,10,Goto(s\,10)
+exten => sw-19-BUSY,10,Voicemail(b${ext})
+exten => sw-19-BUSY,11,Goto(s\,10)
+exten => sw-19-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-19-DONTCALL,11,Goto(s\,10)
+exten => sw-19-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-19-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_18]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-20-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_18-20)
+exten => s,11,Return()
+exten => _sw-20-.,10,Voicemail(u${ext})
+exten => _sw-20-.,11,Goto(s\,10)
+exten => sw-20-,10,Goto(sw-20-.|10)
+exten => sw-20-NOANSWER,10,Voicemail(u${ext})
+exten => sw-20-NOANSWER,11,Goto(s\,10)
+exten => sw-20-ANSWER,10,Goto(s\,10)
+exten => sw-20-BUSY,10,Voicemail(b${ext})
+exten => sw-20-BUSY,11,Goto(s\,10)
+exten => sw-20-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-20-DONTCALL,11,Goto(s\,10)
+exten => sw-20-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-20-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_19]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-21-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_19-21)
+exten => s,11,Return()
+exten => _sw-21-.,10,Voicemail(u${ext})
+exten => _sw-21-.,11,Goto(s\,10)
+exten => sw-21-,10,Goto(sw-21-.|10)
+exten => sw-21-NOANSWER,10,Voicemail(u${ext})
+exten => sw-21-NOANSWER,11,Goto(s\,10)
+exten => sw-21-ANSWER,10,Goto(s\,10)
+exten => sw-21-BUSY,10,Voicemail(b${ext})
+exten => sw-21-BUSY,11,Goto(s\,10)
+exten => sw-21-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-21-DONTCALL,11,Goto(s\,10)
+exten => sw-21-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-21-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_20]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-22-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_20-22)
+exten => s,11,Return()
+exten => _sw-22-.,10,Voicemail(u${ext})
+exten => _sw-22-.,11,Goto(s\,10)
+exten => sw-22-,10,Goto(sw-22-.|10)
+exten => sw-22-NOANSWER,10,Voicemail(u${ext})
+exten => sw-22-NOANSWER,11,Goto(s\,10)
+exten => sw-22-ANSWER,10,Goto(s\,10)
+exten => sw-22-BUSY,10,Voicemail(b${ext})
+exten => sw-22-BUSY,11,Goto(s\,10)
+exten => sw-22-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-22-DONTCALL,11,Goto(s\,10)
+exten => sw-22-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-22-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_21]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-23-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_21-23)
+exten => s,11,Return()
+exten => _sw-23-.,10,Voicemail(u${ext})
+exten => _sw-23-.,11,Goto(s\,10)
+exten => sw-23-,10,Goto(sw-23-.|10)
+exten => sw-23-NOANSWER,10,Voicemail(u${ext})
+exten => sw-23-NOANSWER,11,Goto(s\,10)
+exten => sw-23-ANSWER,10,Goto(s\,10)
+exten => sw-23-BUSY,10,Voicemail(b${ext})
+exten => sw-23-BUSY,11,Goto(s\,10)
+exten => sw-23-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-23-DONTCALL,11,Goto(s\,10)
+exten => sw-23-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-23-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_22]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-24-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_22-24)
+exten => s,11,Return()
+exten => _sw-24-.,10,Voicemail(u${ext})
+exten => _sw-24-.,11,Goto(s\,10)
+exten => sw-24-,10,Goto(sw-24-.|10)
+exten => sw-24-NOANSWER,10,Voicemail(u${ext})
+exten => sw-24-NOANSWER,11,Goto(s\,10)
+exten => sw-24-ANSWER,10,Goto(s\,10)
+exten => sw-24-BUSY,10,Voicemail(b${ext})
+exten => sw-24-BUSY,11,Goto(s\,10)
+exten => sw-24-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-24-DONTCALL,11,Goto(s\,10)
+exten => sw-24-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-24-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_23]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-25-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_23-25)
+exten => s,11,Return()
+exten => _sw-25-.,10,Voicemail(u${ext})
+exten => _sw-25-.,11,Goto(s\,10)
+exten => sw-25-,10,Goto(sw-25-.|10)
+exten => sw-25-NOANSWER,10,Voicemail(u${ext})
+exten => sw-25-NOANSWER,11,Goto(s\,10)
+exten => sw-25-ANSWER,10,Goto(s\,10)
+exten => sw-25-BUSY,10,Voicemail(b${ext})
+exten => sw-25-BUSY,11,Goto(s\,10)
+exten => sw-25-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-25-DONTCALL,11,Goto(s\,10)
+exten => sw-25-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-25-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_24]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-26-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_24-26)
+exten => s,11,Return()
+exten => _sw-26-.,10,Voicemail(u${ext})
+exten => _sw-26-.,11,Goto(s\,10)
+exten => sw-26-,10,Goto(sw-26-.|10)
+exten => sw-26-NOANSWER,10,Voicemail(u${ext})
+exten => sw-26-NOANSWER,11,Goto(s\,10)
+exten => sw-26-ANSWER,10,Goto(s\,10)
+exten => sw-26-BUSY,10,Voicemail(b${ext})
+exten => sw-26-BUSY,11,Goto(s\,10)
+exten => sw-26-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-26-DONTCALL,11,Goto(s\,10)
+exten => sw-26-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-26-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_25]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-27-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_25-27)
+exten => s,11,Return()
+exten => _sw-27-.,10,Voicemail(u${ext})
+exten => _sw-27-.,11,Goto(s\,10)
+exten => sw-27-,10,Goto(sw-27-.|10)
+exten => sw-27-NOANSWER,10,Voicemail(u${ext})
+exten => sw-27-NOANSWER,11,Goto(s\,10)
+exten => sw-27-ANSWER,10,Goto(s\,10)
+exten => sw-27-BUSY,10,Voicemail(b${ext})
+exten => sw-27-BUSY,11,Goto(s\,10)
+exten => sw-27-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-27-DONTCALL,11,Goto(s\,10)
+exten => sw-27-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-27-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_26]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-28-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_26-28)
+exten => s,11,Return()
+exten => _sw-28-.,10,Voicemail(u${ext})
+exten => _sw-28-.,11,Goto(s\,10)
+exten => sw-28-,10,Goto(sw-28-.|10)
+exten => sw-28-NOANSWER,10,Voicemail(u${ext})
+exten => sw-28-NOANSWER,11,Goto(s\,10)
+exten => sw-28-ANSWER,10,Goto(s\,10)
+exten => sw-28-BUSY,10,Voicemail(b${ext})
+exten => sw-28-BUSY,11,Goto(s\,10)
+exten => sw-28-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-28-DONTCALL,11,Goto(s\,10)
+exten => sw-28-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-28-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_27]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-29-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_27-29)
+exten => s,11,Return()
+exten => _sw-29-.,10,Voicemail(u${ext})
+exten => _sw-29-.,11,Goto(s\,10)
+exten => sw-29-,10,Goto(sw-29-.|10)
+exten => sw-29-NOANSWER,10,Voicemail(u${ext})
+exten => sw-29-NOANSWER,11,Goto(s\,10)
+exten => sw-29-ANSWER,10,Goto(s\,10)
+exten => sw-29-BUSY,10,Voicemail(b${ext})
+exten => sw-29-BUSY,11,Goto(s\,10)
+exten => sw-29-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-29-DONTCALL,11,Goto(s\,10)
+exten => sw-29-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-29-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_28]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-30-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_28-30)
+exten => s,11,Return()
+exten => _sw-30-.,10,Voicemail(u${ext})
+exten => _sw-30-.,11,Goto(s\,10)
+exten => sw-30-,10,Goto(sw-30-.|10)
+exten => sw-30-NOANSWER,10,Voicemail(u${ext})
+exten => sw-30-NOANSWER,11,Goto(s\,10)
+exten => sw-30-ANSWER,10,Goto(s\,10)
+exten => sw-30-BUSY,10,Voicemail(b${ext})
+exten => sw-30-BUSY,11,Goto(s\,10)
+exten => sw-30-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-30-DONTCALL,11,Goto(s\,10)
+exten => sw-30-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-30-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_29]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-31-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_29-31)
+exten => s,11,Return()
+exten => _sw-31-.,10,Voicemail(u${ext})
+exten => _sw-31-.,11,Goto(s\,10)
+exten => sw-31-,10,Goto(sw-31-.|10)
+exten => sw-31-NOANSWER,10,Voicemail(u${ext})
+exten => sw-31-NOANSWER,11,Goto(s\,10)
+exten => sw-31-ANSWER,10,Goto(s\,10)
+exten => sw-31-BUSY,10,Voicemail(b${ext})
+exten => sw-31-BUSY,11,Goto(s\,10)
+exten => sw-31-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-31-DONTCALL,11,Goto(s\,10)
+exten => sw-31-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-31-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_30]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-32-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_30-32)
+exten => s,11,Return()
+exten => _sw-32-.,10,Voicemail(u${ext})
+exten => _sw-32-.,11,Goto(s\,10)
+exten => sw-32-,10,Goto(sw-32-.|10)
+exten => sw-32-NOANSWER,10,Voicemail(u${ext})
+exten => sw-32-NOANSWER,11,Goto(s\,10)
+exten => sw-32-ANSWER,10,Goto(s\,10)
+exten => sw-32-BUSY,10,Voicemail(b${ext})
+exten => sw-32-BUSY,11,Goto(s\,10)
+exten => sw-32-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-32-DONTCALL,11,Goto(s\,10)
+exten => sw-32-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-32-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_31]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-33-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_31-33)
+exten => s,11,Return()
+exten => _sw-33-.,10,Voicemail(u${ext})
+exten => _sw-33-.,11,Goto(s\,10)
+exten => sw-33-,10,Goto(sw-33-.|10)
+exten => sw-33-NOANSWER,10,Voicemail(u${ext})
+exten => sw-33-NOANSWER,11,Goto(s\,10)
+exten => sw-33-ANSWER,10,Goto(s\,10)
+exten => sw-33-BUSY,10,Voicemail(b${ext})
+exten => sw-33-BUSY,11,Goto(s\,10)
+exten => sw-33-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-33-DONTCALL,11,Goto(s\,10)
+exten => sw-33-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-33-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_32]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-34-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_32-34)
+exten => s,11,Return()
+exten => _sw-34-.,10,Voicemail(u${ext})
+exten => _sw-34-.,11,Goto(s\,10)
+exten => sw-34-,10,Goto(sw-34-.|10)
+exten => sw-34-NOANSWER,10,Voicemail(u${ext})
+exten => sw-34-NOANSWER,11,Goto(s\,10)
+exten => sw-34-ANSWER,10,Goto(s\,10)
+exten => sw-34-BUSY,10,Voicemail(b${ext})
+exten => sw-34-BUSY,11,Goto(s\,10)
+exten => sw-34-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-34-DONTCALL,11,Goto(s\,10)
+exten => sw-34-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-34-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_33]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-35-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_33-35)
+exten => s,11,Return()
+exten => _sw-35-.,10,Voicemail(u${ext})
+exten => _sw-35-.,11,Goto(s\,10)
+exten => sw-35-,10,Goto(sw-35-.|10)
+exten => sw-35-NOANSWER,10,Voicemail(u${ext})
+exten => sw-35-NOANSWER,11,Goto(s\,10)
+exten => sw-35-ANSWER,10,Goto(s\,10)
+exten => sw-35-BUSY,10,Voicemail(b${ext})
+exten => sw-35-BUSY,11,Goto(s\,10)
+exten => sw-35-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-35-DONTCALL,11,Goto(s\,10)
+exten => sw-35-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-35-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_34]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-36-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_34-36)
+exten => s,11,Return()
+exten => _sw-36-.,10,Voicemail(u${ext})
+exten => _sw-36-.,11,Goto(s\,10)
+exten => sw-36-,10,Goto(sw-36-.|10)
+exten => sw-36-NOANSWER,10,Voicemail(u${ext})
+exten => sw-36-NOANSWER,11,Goto(s\,10)
+exten => sw-36-ANSWER,10,Goto(s\,10)
+exten => sw-36-BUSY,10,Voicemail(b${ext})
+exten => sw-36-BUSY,11,Goto(s\,10)
+exten => sw-36-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-36-DONTCALL,11,Goto(s\,10)
+exten => sw-36-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-36-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_35]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-37-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_35-37)
+exten => s,11,Return()
+exten => _sw-37-.,10,Voicemail(u${ext})
+exten => _sw-37-.,11,Goto(s\,10)
+exten => sw-37-,10,Goto(sw-37-.|10)
+exten => sw-37-NOANSWER,10,Voicemail(u${ext})
+exten => sw-37-NOANSWER,11,Goto(s\,10)
+exten => sw-37-ANSWER,10,Goto(s\,10)
+exten => sw-37-BUSY,10,Voicemail(b${ext})
+exten => sw-37-BUSY,11,Goto(s\,10)
+exten => sw-37-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-37-DONTCALL,11,Goto(s\,10)
+exten => sw-37-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-37-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_36]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-38-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_36-38)
+exten => s,11,Return()
+exten => _sw-38-.,10,Voicemail(u${ext})
+exten => _sw-38-.,11,Goto(s\,10)
+exten => sw-38-,10,Goto(sw-38-.|10)
+exten => sw-38-NOANSWER,10,Voicemail(u${ext})
+exten => sw-38-NOANSWER,11,Goto(s\,10)
+exten => sw-38-ANSWER,10,Goto(s\,10)
+exten => sw-38-BUSY,10,Voicemail(b${ext})
+exten => sw-38-BUSY,11,Goto(s\,10)
+exten => sw-38-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-38-DONTCALL,11,Goto(s\,10)
+exten => sw-38-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-38-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_37]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-39-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_37-39)
+exten => s,11,Return()
+exten => _sw-39-.,10,Voicemail(u${ext})
+exten => _sw-39-.,11,Goto(s\,10)
+exten => sw-39-,10,Goto(sw-39-.|10)
+exten => sw-39-NOANSWER,10,Voicemail(u${ext})
+exten => sw-39-NOANSWER,11,Goto(s\,10)
+exten => sw-39-ANSWER,10,Goto(s\,10)
+exten => sw-39-BUSY,10,Voicemail(b${ext})
+exten => sw-39-BUSY,11,Goto(s\,10)
+exten => sw-39-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-39-DONTCALL,11,Goto(s\,10)
+exten => sw-39-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-39-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_38]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-40-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_38-40)
+exten => s,11,Return()
+exten => _sw-40-.,10,Voicemail(u${ext})
+exten => _sw-40-.,11,Goto(s\,10)
+exten => sw-40-,10,Goto(sw-40-.|10)
+exten => sw-40-NOANSWER,10,Voicemail(u${ext})
+exten => sw-40-NOANSWER,11,Goto(s\,10)
+exten => sw-40-ANSWER,10,Goto(s\,10)
+exten => sw-40-BUSY,10,Voicemail(b${ext})
+exten => sw-40-BUSY,11,Goto(s\,10)
+exten => sw-40-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-40-DONTCALL,11,Goto(s\,10)
+exten => sw-40-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-40-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_39]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-41-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_39-41)
+exten => s,11,Return()
+exten => _sw-41-.,10,Voicemail(u${ext})
+exten => _sw-41-.,11,Goto(s\,10)
+exten => sw-41-,10,Goto(sw-41-.|10)
+exten => sw-41-NOANSWER,10,Voicemail(u${ext})
+exten => sw-41-NOANSWER,11,Goto(s\,10)
+exten => sw-41-ANSWER,10,Goto(s\,10)
+exten => sw-41-BUSY,10,Voicemail(b${ext})
+exten => sw-41-BUSY,11,Goto(s\,10)
+exten => sw-41-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-41-DONTCALL,11,Goto(s\,10)
+exten => sw-41-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-41-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_40]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-42-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_40-42)
+exten => s,11,Return()
+exten => _sw-42-.,10,Voicemail(u${ext})
+exten => _sw-42-.,11,Goto(s\,10)
+exten => sw-42-,10,Goto(sw-42-.|10)
+exten => sw-42-NOANSWER,10,Voicemail(u${ext})
+exten => sw-42-NOANSWER,11,Goto(s\,10)
+exten => sw-42-ANSWER,10,Goto(s\,10)
+exten => sw-42-BUSY,10,Voicemail(b${ext})
+exten => sw-42-BUSY,11,Goto(s\,10)
+exten => sw-42-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-42-DONTCALL,11,Goto(s\,10)
+exten => sw-42-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-42-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_41]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-43-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_41-43)
+exten => s,11,Return()
+exten => _sw-43-.,10,Voicemail(u${ext})
+exten => _sw-43-.,11,Goto(s\,10)
+exten => sw-43-,10,Goto(sw-43-.|10)
+exten => sw-43-NOANSWER,10,Voicemail(u${ext})
+exten => sw-43-NOANSWER,11,Goto(s\,10)
+exten => sw-43-ANSWER,10,Goto(s\,10)
+exten => sw-43-BUSY,10,Voicemail(b${ext})
+exten => sw-43-BUSY,11,Goto(s\,10)
+exten => sw-43-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-43-DONTCALL,11,Goto(s\,10)
+exten => sw-43-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-43-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_42]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-44-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_42-44)
+exten => s,11,Return()
+exten => _sw-44-.,10,Voicemail(u${ext})
+exten => _sw-44-.,11,Goto(s\,10)
+exten => sw-44-,10,Goto(sw-44-.|10)
+exten => sw-44-NOANSWER,10,Voicemail(u${ext})
+exten => sw-44-NOANSWER,11,Goto(s\,10)
+exten => sw-44-ANSWER,10,Goto(s\,10)
+exten => sw-44-BUSY,10,Voicemail(b${ext})
+exten => sw-44-BUSY,11,Goto(s\,10)
+exten => sw-44-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-44-DONTCALL,11,Goto(s\,10)
+exten => sw-44-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-44-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_43]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-45-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_43-45)
+exten => s,11,Return()
+exten => _sw-45-.,10,Voicemail(u${ext})
+exten => _sw-45-.,11,Goto(s\,10)
+exten => sw-45-,10,Goto(sw-45-.|10)
+exten => sw-45-NOANSWER,10,Voicemail(u${ext})
+exten => sw-45-NOANSWER,11,Goto(s\,10)
+exten => sw-45-ANSWER,10,Goto(s\,10)
+exten => sw-45-BUSY,10,Voicemail(b${ext})
+exten => sw-45-BUSY,11,Goto(s\,10)
+exten => sw-45-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-45-DONTCALL,11,Goto(s\,10)
+exten => sw-45-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-45-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_44]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-46-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_44-46)
+exten => s,11,Return()
+exten => _sw-46-.,10,Voicemail(u${ext})
+exten => _sw-46-.,11,Goto(s\,10)
+exten => sw-46-,10,Goto(sw-46-.|10)
+exten => sw-46-NOANSWER,10,Voicemail(u${ext})
+exten => sw-46-NOANSWER,11,Goto(s\,10)
+exten => sw-46-ANSWER,10,Goto(s\,10)
+exten => sw-46-BUSY,10,Voicemail(b${ext})
+exten => sw-46-BUSY,11,Goto(s\,10)
+exten => sw-46-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-46-DONTCALL,11,Goto(s\,10)
+exten => sw-46-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-46-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_45]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-47-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_45-47)
+exten => s,11,Return()
+exten => _sw-47-.,10,Voicemail(u${ext})
+exten => _sw-47-.,11,Goto(s\,10)
+exten => sw-47-,10,Goto(sw-47-.|10)
+exten => sw-47-NOANSWER,10,Voicemail(u${ext})
+exten => sw-47-NOANSWER,11,Goto(s\,10)
+exten => sw-47-ANSWER,10,Goto(s\,10)
+exten => sw-47-BUSY,10,Voicemail(b${ext})
+exten => sw-47-BUSY,11,Goto(s\,10)
+exten => sw-47-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-47-DONTCALL,11,Goto(s\,10)
+exten => sw-47-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-47-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_46]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-48-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_46-48)
+exten => s,11,Return()
+exten => _sw-48-.,10,Voicemail(u${ext})
+exten => _sw-48-.,11,Goto(s\,10)
+exten => sw-48-,10,Goto(sw-48-.|10)
+exten => sw-48-NOANSWER,10,Voicemail(u${ext})
+exten => sw-48-NOANSWER,11,Goto(s\,10)
+exten => sw-48-ANSWER,10,Goto(s\,10)
+exten => sw-48-BUSY,10,Voicemail(b${ext})
+exten => sw-48-BUSY,11,Goto(s\,10)
+exten => sw-48-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-48-DONTCALL,11,Goto(s\,10)
+exten => sw-48-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-48-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_47]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-49-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_47-49)
+exten => s,11,Return()
+exten => _sw-49-.,10,Voicemail(u${ext})
+exten => _sw-49-.,11,Goto(s\,10)
+exten => sw-49-,10,Goto(sw-49-.|10)
+exten => sw-49-NOANSWER,10,Voicemail(u${ext})
+exten => sw-49-NOANSWER,11,Goto(s\,10)
+exten => sw-49-ANSWER,10,Goto(s\,10)
+exten => sw-49-BUSY,10,Voicemail(b${ext})
+exten => sw-49-BUSY,11,Goto(s\,10)
+exten => sw-49-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-49-DONTCALL,11,Goto(s\,10)
+exten => sw-49-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-49-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_48]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-50-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_48-50)
+exten => s,11,Return()
+exten => _sw-50-.,10,Voicemail(u${ext})
+exten => _sw-50-.,11,Goto(s\,10)
+exten => sw-50-,10,Goto(sw-50-.|10)
+exten => sw-50-NOANSWER,10,Voicemail(u${ext})
+exten => sw-50-NOANSWER,11,Goto(s\,10)
+exten => sw-50-ANSWER,10,Goto(s\,10)
+exten => sw-50-BUSY,10,Voicemail(b${ext})
+exten => sw-50-BUSY,11,Goto(s\,10)
+exten => sw-50-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-50-DONTCALL,11,Goto(s\,10)
+exten => sw-50-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-50-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_49]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-51-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_49-51)
+exten => s,11,Return()
+exten => _sw-51-.,10,Voicemail(u${ext})
+exten => _sw-51-.,11,Goto(s\,10)
+exten => sw-51-,10,Goto(sw-51-.|10)
+exten => sw-51-NOANSWER,10,Voicemail(u${ext})
+exten => sw-51-NOANSWER,11,Goto(s\,10)
+exten => sw-51-ANSWER,10,Goto(s\,10)
+exten => sw-51-BUSY,10,Voicemail(b${ext})
+exten => sw-51-BUSY,11,Goto(s\,10)
+exten => sw-51-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-51-DONTCALL,11,Goto(s\,10)
+exten => sw-51-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-51-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_50]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-52-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_50-52)
+exten => s,11,Return()
+exten => _sw-52-.,10,Voicemail(u${ext})
+exten => _sw-52-.,11,Goto(s\,10)
+exten => sw-52-,10,Goto(sw-52-.|10)
+exten => sw-52-NOANSWER,10,Voicemail(u${ext})
+exten => sw-52-NOANSWER,11,Goto(s\,10)
+exten => sw-52-ANSWER,10,Goto(s\,10)
+exten => sw-52-BUSY,10,Voicemail(b${ext})
+exten => sw-52-BUSY,11,Goto(s\,10)
+exten => sw-52-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-52-DONTCALL,11,Goto(s\,10)
+exten => sw-52-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-52-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_51]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-53-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_51-53)
+exten => s,11,Return()
+exten => _sw-53-.,10,Voicemail(u${ext})
+exten => _sw-53-.,11,Goto(s\,10)
+exten => sw-53-,10,Goto(sw-53-.|10)
+exten => sw-53-NOANSWER,10,Voicemail(u${ext})
+exten => sw-53-NOANSWER,11,Goto(s\,10)
+exten => sw-53-ANSWER,10,Goto(s\,10)
+exten => sw-53-BUSY,10,Voicemail(b${ext})
+exten => sw-53-BUSY,11,Goto(s\,10)
+exten => sw-53-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-53-DONTCALL,11,Goto(s\,10)
+exten => sw-53-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-53-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_52]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-54-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_52-54)
+exten => s,11,Return()
+exten => _sw-54-.,10,Voicemail(u${ext})
+exten => _sw-54-.,11,Goto(s\,10)
+exten => sw-54-,10,Goto(sw-54-.|10)
+exten => sw-54-NOANSWER,10,Voicemail(u${ext})
+exten => sw-54-NOANSWER,11,Goto(s\,10)
+exten => sw-54-ANSWER,10,Goto(s\,10)
+exten => sw-54-BUSY,10,Voicemail(b${ext})
+exten => sw-54-BUSY,11,Goto(s\,10)
+exten => sw-54-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-54-DONTCALL,11,Goto(s\,10)
+exten => sw-54-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-54-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_53]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-55-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_53-55)
+exten => s,11,Return()
+exten => _sw-55-.,10,Voicemail(u${ext})
+exten => _sw-55-.,11,Goto(s\,10)
+exten => sw-55-,10,Goto(sw-55-.|10)
+exten => sw-55-NOANSWER,10,Voicemail(u${ext})
+exten => sw-55-NOANSWER,11,Goto(s\,10)
+exten => sw-55-ANSWER,10,Goto(s\,10)
+exten => sw-55-BUSY,10,Voicemail(b${ext})
+exten => sw-55-BUSY,11,Goto(s\,10)
+exten => sw-55-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-55-DONTCALL,11,Goto(s\,10)
+exten => sw-55-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-55-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_54]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-56-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_54-56)
+exten => s,11,Return()
+exten => _sw-56-.,10,Voicemail(u${ext})
+exten => _sw-56-.,11,Goto(s\,10)
+exten => sw-56-,10,Goto(sw-56-.|10)
+exten => sw-56-NOANSWER,10,Voicemail(u${ext})
+exten => sw-56-NOANSWER,11,Goto(s\,10)
+exten => sw-56-ANSWER,10,Goto(s\,10)
+exten => sw-56-BUSY,10,Voicemail(b${ext})
+exten => sw-56-BUSY,11,Goto(s\,10)
+exten => sw-56-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-56-DONTCALL,11,Goto(s\,10)
+exten => sw-56-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-56-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_55]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-57-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_55-57)
+exten => s,11,Return()
+exten => _sw-57-.,10,Voicemail(u${ext})
+exten => _sw-57-.,11,Goto(s\,10)
+exten => sw-57-,10,Goto(sw-57-.|10)
+exten => sw-57-NOANSWER,10,Voicemail(u${ext})
+exten => sw-57-NOANSWER,11,Goto(s\,10)
+exten => sw-57-ANSWER,10,Goto(s\,10)
+exten => sw-57-BUSY,10,Voicemail(b${ext})
+exten => sw-57-BUSY,11,Goto(s\,10)
+exten => sw-57-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-57-DONTCALL,11,Goto(s\,10)
+exten => sw-57-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-57-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_56]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-58-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_56-58)
+exten => s,11,Return()
+exten => _sw-58-.,10,Voicemail(u${ext})
+exten => _sw-58-.,11,Goto(s\,10)
+exten => sw-58-,10,Goto(sw-58-.|10)
+exten => sw-58-NOANSWER,10,Voicemail(u${ext})
+exten => sw-58-NOANSWER,11,Goto(s\,10)
+exten => sw-58-ANSWER,10,Goto(s\,10)
+exten => sw-58-BUSY,10,Voicemail(b${ext})
+exten => sw-58-BUSY,11,Goto(s\,10)
+exten => sw-58-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-58-DONTCALL,11,Goto(s\,10)
+exten => sw-58-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-58-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_57]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-59-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_57-59)
+exten => s,11,Return()
+exten => _sw-59-.,10,Voicemail(u${ext})
+exten => _sw-59-.,11,Goto(s\,10)
+exten => sw-59-,10,Goto(sw-59-.|10)
+exten => sw-59-NOANSWER,10,Voicemail(u${ext})
+exten => sw-59-NOANSWER,11,Goto(s\,10)
+exten => sw-59-ANSWER,10,Goto(s\,10)
+exten => sw-59-BUSY,10,Voicemail(b${ext})
+exten => sw-59-BUSY,11,Goto(s\,10)
+exten => sw-59-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-59-DONTCALL,11,Goto(s\,10)
+exten => sw-59-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-59-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_58]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-60-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_58-60)
+exten => s,11,Return()
+exten => _sw-60-.,10,Voicemail(u${ext})
+exten => _sw-60-.,11,Goto(s\,10)
+exten => sw-60-,10,Goto(sw-60-.|10)
+exten => sw-60-NOANSWER,10,Voicemail(u${ext})
+exten => sw-60-NOANSWER,11,Goto(s\,10)
+exten => sw-60-ANSWER,10,Goto(s\,10)
+exten => sw-60-BUSY,10,Voicemail(b${ext})
+exten => sw-60-BUSY,11,Goto(s\,10)
+exten => sw-60-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-60-DONTCALL,11,Goto(s\,10)
+exten => sw-60-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-60-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_59]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-61-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_59-61)
+exten => s,11,Return()
+exten => _sw-61-.,10,Voicemail(u${ext})
+exten => _sw-61-.,11,Goto(s\,10)
+exten => sw-61-,10,Goto(sw-61-.|10)
+exten => sw-61-NOANSWER,10,Voicemail(u${ext})
+exten => sw-61-NOANSWER,11,Goto(s\,10)
+exten => sw-61-ANSWER,10,Goto(s\,10)
+exten => sw-61-BUSY,10,Voicemail(b${ext})
+exten => sw-61-BUSY,11,Goto(s\,10)
+exten => sw-61-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-61-DONTCALL,11,Goto(s\,10)
+exten => sw-61-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-61-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_60]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-62-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_60-62)
+exten => s,11,Return()
+exten => _sw-62-.,10,Voicemail(u${ext})
+exten => _sw-62-.,11,Goto(s\,10)
+exten => sw-62-,10,Goto(sw-62-.|10)
+exten => sw-62-NOANSWER,10,Voicemail(u${ext})
+exten => sw-62-NOANSWER,11,Goto(s\,10)
+exten => sw-62-ANSWER,10,Goto(s\,10)
+exten => sw-62-BUSY,10,Voicemail(b${ext})
+exten => sw-62-BUSY,11,Goto(s\,10)
+exten => sw-62-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-62-DONTCALL,11,Goto(s\,10)
+exten => sw-62-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-62-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_61]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-63-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_61-63)
+exten => s,11,Return()
+exten => _sw-63-.,10,Voicemail(u${ext})
+exten => _sw-63-.,11,Goto(s\,10)
+exten => sw-63-,10,Goto(sw-63-.|10)
+exten => sw-63-NOANSWER,10,Voicemail(u${ext})
+exten => sw-63-NOANSWER,11,Goto(s\,10)
+exten => sw-63-ANSWER,10,Goto(s\,10)
+exten => sw-63-BUSY,10,Voicemail(b${ext})
+exten => sw-63-BUSY,11,Goto(s\,10)
+exten => sw-63-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-63-DONTCALL,11,Goto(s\,10)
+exten => sw-63-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-63-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_62]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-64-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_62-64)
+exten => s,11,Return()
+exten => _sw-64-.,10,Voicemail(u${ext})
+exten => _sw-64-.,11,Goto(s\,10)
+exten => sw-64-,10,Goto(sw-64-.|10)
+exten => sw-64-NOANSWER,10,Voicemail(u${ext})
+exten => sw-64-NOANSWER,11,Goto(s\,10)
+exten => sw-64-ANSWER,10,Goto(s\,10)
+exten => sw-64-BUSY,10,Voicemail(b${ext})
+exten => sw-64-BUSY,11,Goto(s\,10)
+exten => sw-64-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-64-DONTCALL,11,Goto(s\,10)
+exten => sw-64-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-64-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_63]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-65-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_63-65)
+exten => s,11,Return()
+exten => _sw-65-.,10,Voicemail(u${ext})
+exten => _sw-65-.,11,Goto(s\,10)
+exten => sw-65-,10,Goto(sw-65-.|10)
+exten => sw-65-NOANSWER,10,Voicemail(u${ext})
+exten => sw-65-NOANSWER,11,Goto(s\,10)
+exten => sw-65-ANSWER,10,Goto(s\,10)
+exten => sw-65-BUSY,10,Voicemail(b${ext})
+exten => sw-65-BUSY,11,Goto(s\,10)
+exten => sw-65-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-65-DONTCALL,11,Goto(s\,10)
+exten => sw-65-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-65-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_64]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-66-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_64-66)
+exten => s,11,Return()
+exten => _sw-66-.,10,Voicemail(u${ext})
+exten => _sw-66-.,11,Goto(s\,10)
+exten => sw-66-,10,Goto(sw-66-.|10)
+exten => sw-66-NOANSWER,10,Voicemail(u${ext})
+exten => sw-66-NOANSWER,11,Goto(s\,10)
+exten => sw-66-ANSWER,10,Goto(s\,10)
+exten => sw-66-BUSY,10,Voicemail(b${ext})
+exten => sw-66-BUSY,11,Goto(s\,10)
+exten => sw-66-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-66-DONTCALL,11,Goto(s\,10)
+exten => sw-66-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-66-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_65]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-67-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_65-67)
+exten => s,11,Return()
+exten => _sw-67-.,10,Voicemail(u${ext})
+exten => _sw-67-.,11,Goto(s\,10)
+exten => sw-67-,10,Goto(sw-67-.|10)
+exten => sw-67-NOANSWER,10,Voicemail(u${ext})
+exten => sw-67-NOANSWER,11,Goto(s\,10)
+exten => sw-67-ANSWER,10,Goto(s\,10)
+exten => sw-67-BUSY,10,Voicemail(b${ext})
+exten => sw-67-BUSY,11,Goto(s\,10)
+exten => sw-67-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-67-DONTCALL,11,Goto(s\,10)
+exten => sw-67-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-67-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_66]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-68-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_66-68)
+exten => s,11,Return()
+exten => _sw-68-.,10,Voicemail(u${ext})
+exten => _sw-68-.,11,Goto(s\,10)
+exten => sw-68-,10,Goto(sw-68-.|10)
+exten => sw-68-NOANSWER,10,Voicemail(u${ext})
+exten => sw-68-NOANSWER,11,Goto(s\,10)
+exten => sw-68-ANSWER,10,Goto(s\,10)
+exten => sw-68-BUSY,10,Voicemail(b${ext})
+exten => sw-68-BUSY,11,Goto(s\,10)
+exten => sw-68-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-68-DONTCALL,11,Goto(s\,10)
+exten => sw-68-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-68-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_67]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-69-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_67-69)
+exten => s,11,Return()
+exten => _sw-69-.,10,Voicemail(u${ext})
+exten => _sw-69-.,11,Goto(s\,10)
+exten => sw-69-,10,Goto(sw-69-.|10)
+exten => sw-69-NOANSWER,10,Voicemail(u${ext})
+exten => sw-69-NOANSWER,11,Goto(s\,10)
+exten => sw-69-ANSWER,10,Goto(s\,10)
+exten => sw-69-BUSY,10,Voicemail(b${ext})
+exten => sw-69-BUSY,11,Goto(s\,10)
+exten => sw-69-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-69-DONTCALL,11,Goto(s\,10)
+exten => sw-69-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-69-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_68]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-70-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_68-70)
+exten => s,11,Return()
+exten => _sw-70-.,10,Voicemail(u${ext})
+exten => _sw-70-.,11,Goto(s\,10)
+exten => sw-70-,10,Goto(sw-70-.|10)
+exten => sw-70-NOANSWER,10,Voicemail(u${ext})
+exten => sw-70-NOANSWER,11,Goto(s\,10)
+exten => sw-70-ANSWER,10,Goto(s\,10)
+exten => sw-70-BUSY,10,Voicemail(b${ext})
+exten => sw-70-BUSY,11,Goto(s\,10)
+exten => sw-70-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-70-DONTCALL,11,Goto(s\,10)
+exten => sw-70-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-70-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_69]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-71-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_69-71)
+exten => s,11,Return()
+exten => _sw-71-.,10,Voicemail(u${ext})
+exten => _sw-71-.,11,Goto(s\,10)
+exten => sw-71-,10,Goto(sw-71-.|10)
+exten => sw-71-NOANSWER,10,Voicemail(u${ext})
+exten => sw-71-NOANSWER,11,Goto(s\,10)
+exten => sw-71-ANSWER,10,Goto(s\,10)
+exten => sw-71-BUSY,10,Voicemail(b${ext})
+exten => sw-71-BUSY,11,Goto(s\,10)
+exten => sw-71-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-71-DONTCALL,11,Goto(s\,10)
+exten => sw-71-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-71-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_70]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-72-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_70-72)
+exten => s,11,Return()
+exten => _sw-72-.,10,Voicemail(u${ext})
+exten => _sw-72-.,11,Goto(s\,10)
+exten => sw-72-,10,Goto(sw-72-.|10)
+exten => sw-72-NOANSWER,10,Voicemail(u${ext})
+exten => sw-72-NOANSWER,11,Goto(s\,10)
+exten => sw-72-ANSWER,10,Goto(s\,10)
+exten => sw-72-BUSY,10,Voicemail(b${ext})
+exten => sw-72-BUSY,11,Goto(s\,10)
+exten => sw-72-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-72-DONTCALL,11,Goto(s\,10)
+exten => sw-72-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-72-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_71]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-73-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_71-73)
+exten => s,11,Return()
+exten => _sw-73-.,10,Voicemail(u${ext})
+exten => _sw-73-.,11,Goto(s\,10)
+exten => sw-73-,10,Goto(sw-73-.|10)
+exten => sw-73-NOANSWER,10,Voicemail(u${ext})
+exten => sw-73-NOANSWER,11,Goto(s\,10)
+exten => sw-73-ANSWER,10,Goto(s\,10)
+exten => sw-73-BUSY,10,Voicemail(b${ext})
+exten => sw-73-BUSY,11,Goto(s\,10)
+exten => sw-73-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-73-DONTCALL,11,Goto(s\,10)
+exten => sw-73-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-73-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_72]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-74-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_72-74)
+exten => s,11,Return()
+exten => _sw-74-.,10,Voicemail(u${ext})
+exten => _sw-74-.,11,Goto(s\,10)
+exten => sw-74-,10,Goto(sw-74-.|10)
+exten => sw-74-NOANSWER,10,Voicemail(u${ext})
+exten => sw-74-NOANSWER,11,Goto(s\,10)
+exten => sw-74-ANSWER,10,Goto(s\,10)
+exten => sw-74-BUSY,10,Voicemail(b${ext})
+exten => sw-74-BUSY,11,Goto(s\,10)
+exten => sw-74-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-74-DONTCALL,11,Goto(s\,10)
+exten => sw-74-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-74-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten_73]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-75-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten_73-75)
+exten => s,11,Return()
+exten => _sw-75-.,10,Voicemail(u${ext})
+exten => _sw-75-.,11,Goto(s\,10)
+exten => sw-75-,10,Goto(sw-75-.|10)
+exten => sw-75-NOANSWER,10,Voicemail(u${ext})
+exten => sw-75-NOANSWER,11,Goto(s\,10)
+exten => sw-75-ANSWER,10,Goto(s\,10)
+exten => sw-75-BUSY,10,Voicemail(b${ext})
+exten => sw-75-BUSY,11,Goto(s\,10)
+exten => sw-75-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-75-DONTCALL,11,Goto(s\,10)
+exten => sw-75-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-75-TORTURE,11,Goto(s\,10)
+
+
+[std-priv-exten]
+exten => s,1,Set(LOCAL(dev)=${ARG1})
+exten => s,2,Set(LOCAL(ext)=${ARG2})
+exten => s,3,Set(LOCAL(timeout)=${ARG3})
+exten => s,4,Set(LOCAL(opts)=${ARG4})
+exten => s,5,Set(LOCAL(torcont)=${ARG5})
+exten => s,6,Set(LOCAL(dontcont)=${ARG6})
+exten => s,7,Dial(${dev}\,${timeout}\,${opts})
+exten => s,8,NoOp(${DIALSTATUS} was chosen)
+exten => s,9,Goto(sw-76-${DIALSTATUS}\,10)
+exten => s,10,NoOp(Finish switch-std-priv-exten-76)
+exten => s,11,Return()
+exten => _sw-76-.,10,Voicemail(u${ext})
+exten => _sw-76-.,11,Goto(s\,10)
+exten => sw-76-,10,Goto(sw-76-.|10)
+exten => sw-76-NOANSWER,10,Voicemail(u${ext})
+exten => sw-76-NOANSWER,11,Goto(s\,10)
+exten => sw-76-ANSWER,10,Goto(s\,10)
+exten => sw-76-BUSY,10,Voicemail(b${ext})
+exten => sw-76-BUSY,11,Goto(s\,10)
+exten => sw-76-DONTCALL,10,Goto(${dontcont}\,s\,begin)
+exten => sw-76-DONTCALL,11,Goto(s\,10)
+exten => sw-76-TORTURE,10,Goto(${torcont}\,s\,begin)
+exten => sw-76-TORTURE,11,Goto(s\,10)
+
+
+[fillcidname]
+exten => s,1,GotoIf($["${CALLERID(num)}" = "" ]?2:3)
+exten => s,2,Return()
+exten => s,3,NoOp(Finish if-fillcidname-77)
+exten => s,4,Set(cidn=${DB(cidname/${CALLERID(num)})})
+exten => s,5,GotoIf($["${CALLERID(name)}" != "" ]?6:9)
+exten => s,6,GotoIf($[("${cidn}" = "Privacy Manager" & "${CALLERID(name)}" != "Privacy Manager") | "${cidn}" = "" ]?7:8)
+exten => s,7,Set(DB(cidname/${CALLERID(num)})=${CALLERID(name)})
+exten => s,8,NoOp(Finish if-if-fillcidname-78-79)
+exten => s,9,NoOp(Finish if-fillcidname-78)
+exten => s,10,GotoIf($[( "${cidn}" != "" ) & ( "${CALLERID(name)}" = "" | "${CALLERID(name)}" = "CODY\,WY " | "${CALLERID(name)}" = "POWELL\,WY " | "${CALLERID(name)}" = "WIRELESS CALLER" | "${CALLERID(name)}" = "SUBSCRIBER\,WIRE" | "${CALLERID(name)}" = "CELLULAR ONE" | "${CALLERID(name)}" = "Cellular One Customer" | "${CALLERID(name)}" = "CELLULAR ONE " | "${CALLERID(name)}" = "Privacy Manager" | "${CALLERID(name)}" = "RIVERTON\,WY " | "${CALLERID(name)}" = "BASIN\,WY " | "${CALLERID(name)}" = "BILLINGS\,MT " | "${CALLERID(name)}" = "PROVO\,UT " | "${CALLERID(name)}" = "TOLL FREE " ) ]?11:12)
+exten => s,11,Set(CALLERID(name)=${cidn})
+exten => s,12,NoOp(Finish if-fillcidname-80)
+exten => s,13,Return()
+
+
+[ciddial]
+exten => s,1,Set(LOCAL(dialnum)=${ARG1})
+exten => s,2,Set(LOCAL(lookup)=${ARG2})
+exten => s,3,Set(LOCAL(waittime)=${ARG3})
+exten => s,4,Set(LOCAL(dialopts)=${ARG4})
+exten => s,5,Set(LOCAL(ddev)=${ARG5})
+exten => s,6,Set(cidnu=${CALLERID(num)})
+exten => s,7,Set(cidn=${DB(cidname/${lookup})})
+exten => s,8,Set(CALLERID(name)=${cidn})
+exten => s,9,Dial(${ddev}/${dialnum}|${waittime}|${dialopts})
+exten => s,10,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL" ]?11:19)
+exten => s,11,BackGround(try_voip)
+exten => s,12,Set(CALLERID(num)=$[7075679201])
+exten => s,13,Dial(SIP/1${lookup}@tctwest\,${waittime}\,${dialopts})
+exten => s,14,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL" ]?15:18)
+exten => s,15,BackGround(try_cell)
+exten => s,16,Set(CALLERID(num)=$[${cidnu}])
+exten => s,17,Dial(Zap/2/${lookup}\,${waittime}\,${dialopts})
+exten => s,18,NoOp(Finish if-if-ciddial-81-82)
+exten => s,19,NoOp(Finish if-ciddial-81)
+exten => s,20,Return()
+
+
+[ciddial3]
+exten => s,1,Set(LOCAL(dialnum)=${ARG1})
+exten => s,2,Set(LOCAL(lookup)=${ARG2})
+exten => s,3,Set(LOCAL(waittime)=${ARG3})
+exten => s,4,Set(LOCAL(dialopts)=${ARG4})
+exten => s,5,Set(LOCAL(ddev)=${ARG5})
+exten => s,6,Set(cidnu=${CALLERID(num)})
+exten => s,7,Set(cidn=${DB(cidname/${lookup})})
+exten => s,8,Set(CALLERID(name)=${cidn})
+exten => s,9,Dial(${ddev}/${dialnum}|${waittime}|${dialopts})
+exten => s,10,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL" ]?11:13)
+exten => s,11,BackGround(try_cell)
+exten => s,12,Dial(Zap/2/${lookup}\,${waittime}\,${dialopts})
+exten => s,13,NoOp(Finish if-ciddial3-83)
+exten => s,14,Return()
+
+
+[ciddial2]
+exten => s,1,Set(LOCAL(dialnum)=${ARG1})
+exten => s,2,Set(LOCAL(lookup)=${ARG2})
+exten => s,3,Set(LOCAL(waittime)=${ARG3})
+exten => s,4,Set(LOCAL(dialopts)=${ARG4})
+exten => s,5,Set(LOCAL(ddev)=${ARG5})
+exten => s,6,Set(cidn=${DB(cidname/${lookup})})
+exten => s,7,Set(cidnu=${CALLERID(num)})
+exten => s,8,Set(CALLERID(name)=${cidn})
+exten => s,9,Set(CALLERID(num)=7075679201)
+exten => s,10,Dial(SIP/1${lookup}@tctwest\,${waittime}\,${dialopts})
+exten => s,11,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL" ]?12:19)
+exten => s,12,Set(CALLERID(num)=${cidnu})
+exten => s,13,BackGround(try_zap)
+exten => s,14,Dial(${ddev}/${dialnum}\,${waittime}|${dialopts})
+exten => s,15,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL" ]?16:18)
+exten => s,16,BackGround(try_cell)
+exten => s,17,Dial(Zap/2/${lookup}\,${waittime}\,${dialopts})
+exten => s,18,NoOp(Finish if-if-ciddial2-84-85)
+exten => s,19,NoOp(Finish if-ciddial2-84)
+exten => s,20,Return()
+
+
+[callerid-liar]
+exten => s,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/priv-callerintros/LIAR.gsm&)
+exten => s,2,Background(priv-liar)
+exten => s,3,Hangup()
+exten => s,4,Return()
+
+
+[callerid-bad]
+exten => s,1,Set(mycid=$[${CALLERID(num)}:"1([0-9]+)"])
+exten => s,2,Set(CALLERID(num)=${mycid})
+exten => s,3,Wait(0)
+exten => s,4,Return()
+
+
+[privacyManagerFailed]
+exten => s,1(begin),Background(PrivManInstructions)
+exten => s,2,PrivacyManager()
+exten => s,3,GotoIf($["${PRIVACYMGRSTATUS}" = "FAILED" ]?4:11)
+exten => s,4,Background(tt-allbusy)
+exten => s,5,Background(tt-somethingwrong)
+exten => s,6,Background(tt-monkeysintro)
+exten => s,7,Background(tt-monkeys)
+exten => s,8,Background(tt-weasels)
+exten => s,9,Hangup()
+exten => s,10,Goto(12)
+exten => s,11,Goto(homeline\,s\,postPriv)
+exten => s,12,NoOp(Finish if-privacyManagerFailed-86)
+
+
+[homeline]
+exten => s,1(begin),Answer()
+exten => s,2,Set(repeatcount=0)
+exten => s,3,Zapateller(nocallerid)
+exten => s,4,PrivacyManager()
+exten => s,5,GotoIf($["${PRIVACYMGRSTATUS}" = "FAILED" ]?6:10)
+exten => s,6,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/privmanfailed.gsm)
+exten => s,7,Gosub(std-priv-exten\,s\,1(Zap/3r1&Zap/5r1\,2\,25\,mtw\,telemarket\,telemarket))
+exten => s,8,Hangup()
+exten => s,9,Return()
+exten => s,10,NoOp(Finish if-homeline-87)
+exten => s,11(postPriv),Gosub(fillcidname\,s\,1)
+exten => s,12,Set(CONFCIDNA=${CALLERID(name)})
+exten => s,13,Set(CONFCIDNU=${CALLERID(num)})
+exten => s,14,AGI(callall)
+exten => s,15,AGI(submit-announce.agi)
+exten => s,16,GotoIf($["${CALLERID(num)}" : "1" ]?17:18)
+exten => s,17,Gosub(callerid-bad\,s\,1)
+exten => s,18,NoOp(Finish if-homeline-88)
+exten => s,19,GotoIf($["${CALLERID(num)}" = "7077577685" & "${CALLERID(name)}" : "Privacy Manager" ]?20:21)
+exten => s,20,Gosub(callerid-liar\,s\,1)
+exten => s,21,NoOp(Finish if-homeline-89)
+exten => s,22,TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&)
+exten => s,23,Set(lds=${DB(playlds/${CALLERID(num)})})
+exten => s,24,GotoIf($["${lds}" = "1" ]?25:26)
+exten => s,25,SetMusicOnHold(mohlds)
+exten => s,26,NoOp(Finish if-homeline-90)
+exten => s,27,Set(direct=$[${DB(DirectCall/${CALLERID(num)})}])
+exten => s,28,GotoIf($["${direct}" != "" & ${direct} != 0 ]?29:36)
+exten => s,29,verbose(direct is XXX#${direct}XXXX)
+exten => s,30,Playback(greetings/direct)
+exten => s,31,Playback(/var/spool/asterisk/voicemail/default/${direct}/greet)
+exten => s,32,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => s,33,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/${direct}/greet.wav&)
+exten => s,34,Goto(sw-92-${direct}\,10)
+exten => s,35,NoOp(Finish switch-if-homeline-91-92)
+exten => s,36,NoOp(Finish if-homeline-91)
+exten => s,37(loopback),GotoIfTime(*\,*\,20-25\,dec?39)
+exten => s,38,Goto(41)
+exten => s,39,Playback(greetings/christmas)
+exten => s,40,Goto(102)
+exten => s,41,GotoIfTime(*\,*\,31\,dec?43)
+exten => s,42,Goto(45)
+exten => s,43,Playback(greetings/newyear)
+exten => s,44,Goto(101)
+exten => s,45,GotoIfTime(*\,*\,1\,jan?47)
+exten => s,46,Goto(49)
+exten => s,47,Playback(greetings/newyear)
+exten => s,48,Goto(100)
+exten => s,49,GotoIfTime(*\,*\,14\,feb?51)
+exten => s,50,Goto(53)
+exten => s,51,Playback(greetings/valentines)
+exten => s,52,Goto(99)
+exten => s,53,GotoIfTime(*\,*\,17\,mar?55)
+exten => s,54,Goto(57)
+exten => s,55,Playback(greetings/stPat)
+exten => s,56,Goto(98)
+exten => s,57,GotoIfTime(*\,*\,31\,oct?59)
+exten => s,58,Goto(61)
+exten => s,59,Playback(greetings/halloween)
+exten => s,60,Goto(97)
+exten => s,61,GotoIfTime(*\,mon\,15-21\,jan?63)
+exten => s,62,Goto(65)
+exten => s,63,Playback(greetings/mlkDay)
+exten => s,64,Goto(96)
+exten => s,65,GotoIfTime(*\,thu\,22-28\,nov?67)
+exten => s,66,Goto(69)
+exten => s,67,Playback(greetings/thanksgiving)
+exten => s,68,Goto(95)
+exten => s,69,GotoIfTime(*\,mon\,25-31\,may?71)
+exten => s,70,Goto(73)
+exten => s,71,Playback(greetings/memorial)
+exten => s,72,Goto(94)
+exten => s,73,GotoIfTime(*\,mon\,1-7\,sep?75)
+exten => s,74,Goto(77)
+exten => s,75,Playback(greetings/labor)
+exten => s,76,Goto(93)
+exten => s,77,GotoIfTime(*\,mon\,15-21\,feb?79)
+exten => s,78,Goto(81)
+exten => s,79,Playback(greetings/president)
+exten => s,80,Goto(92)
+exten => s,81,GotoIfTime(*\,sun\,8-14\,may?83)
+exten => s,82,Goto(85)
+exten => s,83,Playback(greetings/mothers)
+exten => s,84,Goto(91)
+exten => s,85,GotoIfTime(*\,sun\,15-21\,jun?87)
+exten => s,86,Goto(89)
+exten => s,87,Playback(greetings/fathers)
+exten => s,88,Goto(90)
+exten => s,89,Playback(greetings/hello)
+exten => s,90,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99-100-101-102-103-104-105)
+exten => s,91,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99-100-101-102-103-104)
+exten => s,92,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99-100-101-102-103)
+exten => s,93,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99-100-101-102)
+exten => s,94,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99-100-101)
+exten => s,95,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99-100)
+exten => s,96,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98-99)
+exten => s,97,NoOp(Finish iftime-iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97-98)
+exten => s,98,NoOp(Finish iftime-iftime-iftime-iftime-iftime-homeline-93-94-95-96-97)
+exten => s,99,NoOp(Finish iftime-iftime-iftime-iftime-homeline-93-94-95-96)
+exten => s,100,NoOp(Finish iftime-iftime-iftime-homeline-93-94-95)
+exten => s,101,NoOp(Finish iftime-iftime-homeline-93-94)
+exten => s,102,NoOp(Finish iftime-homeline-93)
+exten => s,103,Background(murphy-homeline-intro1)
+exten => _sw-92-.,10,Set(z=${direct}-2)
+exten => _sw-92-.,11,Goto(homeline-kids\,${z}\,1)
+exten => sw-92-,10,Goto(sw-92-.|10)
+exten => sw-92-2,10,Gosub(std-priv-exten\,s\,1(Zap/3r1&Zap/5r1\,2\,25\,mtw\,telemarket\,telemarket))
+exten => sw-92-2,11,Goto(s\,loopback)
+exten => sw-92-1,10,Gosub(std-priv-exten\,s\,1(Zap/6r3&Sip/murf\,1\,25\,mpA(beep)tw\,telemarket\,telemarket))
+exten => sw-92-1,11,Goto(s\,loopback)
+exten => 1,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 1,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/2/greet.wav&)
+exten => 1,3,Gosub(std-priv-exten\,s\,1(Zap/3r1&Zap/5r1\,2\,25\,mtw\,telemarket\,telemarket))
+exten => 1,4,Goto(s\,loopback)
+exten => 2,1,Goto(homeline-kids\,s\,begin)
+exten => 21,1,Dial(IAX2/seaniax\,20\,T)
+exten => 3,1,Gosub(std-priv-exten\,s\,1(Zap/6r3&Sip/murf\,1\,25\,mpA(beep)tw\,telemarket\,telemarket))
+exten => 3,2,Goto(s\,loopback)
+exten => 4,1,VoicemailMain()
+exten => 4,2,Goto(s\,loopback)
+exten => 5,1,Goto(home-introduction\,s\,begin)
+exten => 6,1,Goto(telemarket\,s\,begin)
+exten => 7,1,agi(tts-riddle.agi)
+exten => 7,2,Background(gsm/what-time-it-is2)
+exten => 7,3,SayUnixTime()
+exten => 7,4,Goto(s\,loopback)
+exten => 792,1,Goto(pageall\,s\,begin)
+exten => 793,1,Read(zz\,\,0\,\,1\,0)
+exten => 793,2,SayDigits(${zz})
+exten => t,1,Set(repeatcount=${repeatcount} + 1)
+exten => t,2,GotoIf($[${repeatcount} < 3 ]?3:4)
+exten => t,3,Goto(s\,loopback)
+exten => t,4,NoOp(Finish if-homeline-106)
+exten => t,5,Hangup()
+exten => i,1,Background(invalid)
+exten => i,2,Goto(s\,loopback)
+exten => o,1,Congestion()
+exten => fax,1,Dial(Zap/4)
+
+
+[pageall]
+exten => s,1(begin),AGI(callall)
+exten => s,2,MeetMe(5555\,dtqp)
+exten => s,3,MeetMeAdmin(5555\,K)
+exten => s,4,Hangup()
+exten => h,1(begin),MeetMeAdmin(5555\,K)
+exten => h,2,Background(conf-muted)
+exten => h,3,Hangup()
+
+
+[add-to-conference]
+exten => start,1,NoCDR()
+exten => start,2,MeetMe(5555\,dmqp)
+exten => h,1,Hangup()
+
+
+[home-introduction]
+exten => s,1(begin),Background(intro-options)
+exten => 1,1,Playback(priv-callerintros/${CALLERID(num)})
+exten => 1,2,Goto(s\,begin)
+exten => 2,1,Goto(home-introduction-record\,s\,begin)
+exten => 3,1,Goto(homeline\,s\,loopback)
+exten => 4,1,Playback(intro-intro)
+exten => 4,2,Goto(s\,begin)
+exten => t,1,Goto(s\,begin)
+exten => i,1,Background(invalid)
+exten => i,2,Goto(s\,begin)
+exten => o,1,Goto(s\,begin)
+
+
+[home-introduction-record]
+exten => s,1(begin),Background(intro-record-choices)
+exten => 1,1,Playback(intro-record)
+exten => 1,2,Goto(2\,begin)
+exten => 2,1(begin),Background(intro-start)
+exten => 2,2,Background(beep)
+exten => 2,3,Record(priv-callerintros/${CALLERID(num)}:gsm\,3)
+exten => 2,4,Background(priv-callerintros/${CALLERID(num)})
+exten => 2,5,Goto(home-introduction\,s\,begin)
+exten => t,1,Goto(s\,begin)
+exten => i,1,Background(invalid)
+exten => i,2,Goto(s\,begin)
+exten => o,1,Goto(s\,begin)
+
+
+[homeline-kids]
+exten => s,1(begin),Background(murphy-homeline-kids)
+exten => 1,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 1,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/3/greet.wav&)
+exten => 1,3,Gosub(std-priv-exten\,s\,1(IAX2/seaniax&Zap/5r2\,3\,35\,mtw\,telemarket\,telemarket))
+exten => 1,4,Goto(homeline\,s\,loopback)
+exten => 2,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 2,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/4/greet.wav&)
+exten => 2,3,Voicemail(u4)
+exten => 2,4,Goto(homeline\,s\,loopback)
+exten => 3,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 3,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/5/greet.wav&)
+exten => 3,3,Gosub(std-priv-exten\,s\,1(Zap/3r2&Zap/5r2\,5\,35\,mtw\,telemarket\,telemarket))
+exten => 3,4,Goto(homeline\,s\,loopback)
+exten => 4,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 4,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/6/greet.wav&)
+exten => 4,3,Gosub(std-priv-exten\,s\,1(Zap/3r2&Zap/5r2\,6\,35\,mtw\,telemarket\,telemarket))
+exten => 4,4,Goto(homeline\,s\,loopback)
+exten => 5,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 5,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/7/greet.wav&)
+exten => 5,3,Gosub(std-priv-exten\,s\,1(Zap/3r2&Zap/5r2\,7\,35\,mtw\,telemarket\,telemarket))
+exten => 5,4,Goto(homeline\,s\,loopback)
+exten => 6,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 6,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/8/greet.wav&)
+exten => 6,3,Gosub(std-priv-exten\,s\,1(Zap/3r2&Zap/5r2\,8\,35\,mtw\,telemarket\,telemarket))
+exten => 6,4,Goto(homeline\,s\,loopback)
+exten => 7,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 7,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/9/greet.wav&)
+exten => 7,3,Gosub(std-priv-exten\,s\,1(Zap/3r2&Zap/5r2\,9\,35\,mtw\,telemarket\,telemarket))
+exten => 7,4,Goto(homeline\,s\,loopback)
+exten => t,1,Goto(s\,begin)
+exten => i,1,Background(invalid)
+exten => i,2,Goto(s\,begin)
+exten => o,1,Goto(s\,begin)
+
+
+[voipworkline]
+exten => s,1(begin),Answer()
+exten => s,2,TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&)
+exten => s,3,Goto(workline\,s\,loopback)
+exten => 7075679201,1,Answer()
+exten => 7075679201,2,TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&)
+exten => 7075679201,3,Goto(workline\,s\,loopback)
+
+
+[workline]
+exten => s,1(begin),Answer()
+exten => s,2,Wait(1)
+exten => s,3,Set(repeatcount=0)
+exten => s,4,Zapateller(nocallerid)
+exten => s,5,Gosub(fillcidname\,s\,1)
+exten => s,6,TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&)
+exten => s,7(loopback),Background(greetings/greeting)
+exten => s,8,Background(murphy-office-intro1)
+exten => 1,1,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/call-for.gsm)
+exten => 1,2,TrySystem(/usr/bin/play /var/spool/asterisk/voicemail/default/1/greet.wav&)
+exten => 1,3,Gosub(std-priv-exten\,s\,1(Zap/6&Sip/murf\,1\,30\,mtw\,telemarket\,telemarket))
+exten => 1,4,Goto(s\,loopback)
+exten => 4,1,VoicemailMain()
+exten => 4,2,Goto(s\,loopback)
+exten => 6,1,Goto(telemarket\,s\,begin)
+exten => 793,1,Read(zz\,\,0\,\,1\,0)
+exten => 793,2,SayDigits(${zz})
+exten => t,1,Set(repeatcount=$[${repeatcount} + 1])
+exten => t,2,GotoIf($[${repeatcount} < 3 ]?3:4)
+exten => t,3,Goto(s\,loopback)
+exten => t,4,NoOp(Finish if-workline-107)
+exten => t,5,Hangup()
+exten => i,1,Background(invalid)
+exten => i,2,Goto(s\,loopback)
+exten => o,1,Congestion()
+exten => fax,1,Answer()
+exten => fax,2,Dial(Zap/4)
+
+
+[dialFWD]
+ignorepat => 8
+ignorepat => 9
+exten => _83.,1,Set(CALLERID(name)=${FWDCIDNAME})
+exten => _83.,2,Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2}\,60\,r)
+exten => _83.,3,Congestion()
+exten => _82NXX,1,Set(CALLERID(name)=${FWDCIDNAME})
+exten => _82NXX,2,Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2}\,60\,r)
+exten => _82NXX,3,Congestion()
+exten => _92NXX,1,Set(CALLERID(name)=${FWDCIDNAME})
+exten => _92NXX,2,Dial(IAX2/${FWDNUMBER}:${FWDPASSWORD}@iax2.fwdnet.net/${EXTEN:2}\,60\,r)
+exten => _92NXX,3,Congestion()
+
+
+[dialiaxtel]
+ignorepat => 8
+ignorepat => 9
+exten => _81700NXXXXXX,1,Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel)
+exten => _81800NXXXXXX,1,Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel)
+exten => _91700NXXXXXX,1,Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel)
+exten => _91800NXXXXXX,1,Dial(IAX2/zorch:zilchnoodle@iaxtel.com/${EXTEN:1}@iaxtel)
+
+
+[dialgoiax]
+ignorepat => 9
+exten => _93.,1,Set(CALLERID(name)="Joe Worker")
+exten => _93.,2,Dial(IAX2/878201007658:stickyfinger295@server1.goiax.com/${EXTEN:2}\,60\,r)
+exten => _93.,3,Congestion()
+
+
+[homefirst]
+ignorepat => 9
+exten => _91NXXNXXXXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,${EXTEN:2}\,30\,TW\,Zap/1))
+exten => _9754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9202XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9219XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9254XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9716XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9NXXXXXX,1,Gosub(ciddial\,s\,1(1707${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9011.,1,Gosub(ciddial\,s\,1(${EXTEN:1}\,${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9911,1,Dial(Zap/1/911\,30\,T)
+exten => _9411,1,Dial(Zap/1/411\,30\,T)
+
+
+[workfirst]
+ignorepat => 9
+exten => _91NXXNXXXXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,${EXTEN:2}\,30\,TW\,Zap/1))
+exten => _9754XXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9574XXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9202XXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9219XXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9254XXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9716XXXX,1,Gosub(ciddial2\,s\,1(${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9NXXXXXX,1,Gosub(ciddial2\,s\,1(1707${EXTEN:1}\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _9911,1,Dial(Zap/1/911\,30\,T)
+exten => _9411,1,Dial(Zap/1/411\,30\,T)
+
+
+[force_cell]
+ignorepat => 8
+exten => _81NXXNXXXXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,${EXTEN:2}\,30\,TW\,Zap/2))
+exten => _8754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8202XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8219XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8254XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8716XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8NXXXXXX,1,Gosub(ciddial\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/2))
+exten => _8911,1,Dial(Zap/1/911|30|T)
+exten => _8411,1,Dial(Zap/1/411|30|T)
+
+
+[force_home]
+ignorepat => 8
+exten => _81NXXNXXXXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,${EXTEN:2}\,30\,TW\,Zap/1))
+exten => _8754XXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8574XXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8202XXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8219XXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8254XXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8716XXXX,1,Gosub(ciddial3\,s\,1(${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8NXXXXXX,1,Gosub(ciddial3\,s\,1(1707${EXTEN:1}#\,707${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _8911,1,Dial(Zap/1/911|30|T)
+exten => _8411,1,Dial(Zap/1/411|30|T)
+
+
+[homeext]
+ignorepat => 8
+ignorepat => 9
+include => parkedcalls
+include => homefirst
+include => force_cell
+exten => s,1(loopback),Wait(0)
+exten => 1,1,Gosub(std-priv-exten\,s\,1(Zap/3&Zap/5\,2\,35\,mtw\,telemarket\,telemarket))
+exten => 1,2,Goto(s\,loopback)
+exten => 2,1,Gosub(std-priv-exten\,s\,1(Zap/6&Zap/5\,1\,35\,mpA(beep3)Tt\,telemarket\,telemarket))
+exten => 2,2,Goto(s\,loopback)
+exten => 4,1,VoicemailMain()
+exten => 5,1,Record(recording:gsm)
+exten => 5,2,Background(recording)
+exten => 6,1,Background(recording)
+exten => 760,1,DateTime()
+exten => 760,2,Goto(s\,loopback)
+exten => 761,1,Record(announcement:gsm)
+exten => 761,2,TrySystem(/usr/bin/play /var/lib/asterisk/sounds/announcement.gsm&)
+exten => 761,3,Goto(s\,loopback)
+exten => 762,1,agi(tts-riddle.agi)
+exten => 762,2,Background(gsm/what-time-it-is2)
+exten => 762,3,SayUnixTime()
+exten => 762,4,Goto(s\,loopback)
+exten => 763,1,Set(CALLERID(num)=)
+exten => 763,2,Dial(Zap/6r3\,35\,mptA(beep3))
+exten => 763,3,Hangup()
+exten => 764,1,Set(CALLERID(num)=)
+exten => 764,2,Dial(Zap/6r3\,35\,mptnA(beep3))
+exten => 764,3,Hangup()
+exten => 765,1,Set(CALLERID(num)=)
+exten => 765,2,Dial(Zap/6r3\,35\,mptNA(beep3))
+exten => 765,3,Hangup()
+exten => 766,1,Dial(Zap/6r3\,35\,mptNA(beep3))
+exten => 766,2,Hangup()
+exten => 767,1,Dial(Zap/6r3\,35\,mptnA(beep3))
+exten => 767,2,Hangup()
+exten => 769,1,Playtones(dial)
+exten => 769,2,Wait(2)
+exten => 769,3,Playtones(busy)
+exten => 769,4,Wait(2)
+exten => 769,5,Playtones(ring)
+exten => 769,6,Wait(2)
+exten => 769,7,Playtones(congestion)
+exten => 769,8,Wait(2)
+exten => 769,9,Playtones(callwaiting)
+exten => 769,10,Wait(2)
+exten => 769,11,Playtones(dialrecall)
+exten => 769,12,Wait(2)
+exten => 769,13,Playtones(record)
+exten => 769,14,Wait(2)
+exten => 769,15,Playtones(info)
+exten => 769,16,Wait(5)
+exten => 769,17,Hangup()
+exten => 790,1,MeetMe(790\,p)
+exten => 792,1,Goto(pageall\,s\,begin)
+exten => 795,1,AGI(wakeup.agi)
+exten => 795,2,Congestion()
+exten => 544716,1,TrySystem(/usr/local/bin/who-is-it ${CALLERID(num)} "${CALLERID(name)}"&)
+exten => 544716,2,Goto(s\,loopback)
+exten => i,1,Background(invalid)
+exten => i,2,Goto(s\,loopback)
+exten => o,1,Goto(s\,loopback)
+exten => t,1,Congestion()
+
+
+[fromvmhome]
+exten => 1,1,Dial(Zap/6&Sip/murf|20|Tt)
+exten => 2,1,Dial(Zap/3&Zap/5|20|Tt)
+exten => _707202XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707219XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707254XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707716XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _NXXNXXXXXX,1,Gosub(ciddial\,s\,1(1${EXTEN}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _1NXXNXXXXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _NXXXXXX,1,Gosub(ciddial\,s\,1(1707${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _911,1,Gosub(ciddial\,s\,1(911\,911\,30\,TW\,Zap/1))
+exten => _411,1,Gosub(ciddial\,s\,1(411\,411\,30\,TW\,Zap/1))
+
+
+[fromvmwork]
+exten => 1,1,Dial(Zap/6&Sip/murf|20|Tt)
+exten => 2,1,Dial(Zap/3&Zap/5|20|Tt)
+exten => _707202XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707219XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707254XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707716XXXX,1,Gosub(ciddial\,s\,1(1${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _NXXNXXXXXX,1,Gosub(ciddial\,s\,1(1${EXTEN}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _1NXXNXXXXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _NXXXXXX,1,Gosub(ciddial\,s\,1(1707${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => 911,1,Gosub(ciddial\,s\,1(911\,911\,30\,TW\,Zap/1))
+exten => 411,1,Gosub(ciddial\,s\,1(411\,411\,30\,TW\,Zap/1))
+
+
+[fromSeanUniden]
+include => parkedcalls
+exten => 21,1,Dial(IAX2/seaniax\,20\,T)
+exten => _707202XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707219XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707254XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707716XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _707574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN:3}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _NXXNXXXXXX,1,Gosub(ciddial\,s\,1(1${EXTEN}\,${EXTEN}\,30\,TW\,Zap/1))
+exten => _1NXXNXXXXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,${EXTEN:1}\,30\,TW\,Zap/1))
+exten => _754XXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _574XXXX,1,Gosub(ciddial\,s\,1(${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => _NXXXXXX,1,Gosub(ciddial\,s\,1(1707${EXTEN}\,707${EXTEN}\,30\,TW\,Zap/1))
+exten => 911,1,Gosub(ciddial\,s\,1(911\,911\,30\,TW\,Zap/1))
+exten => 411,1,Gosub(ciddial\,s\,1(411\,411\,30\,TW\,Zap/1))
+
+
+[workext]
+ignorepat => 8
+ignorepat => 9
+include => parkedcalls
+include => workfirst
+include => force_home
+include => dialFWD
+include => dialiaxtel
+include => dialgoiax
+exten => s,1(loopback),Wait(0)
+exten => 1,1,Dial(Zap/3&Zap/5\,20\,tT)
+exten => 2,1,Dial(Zap/5&Zap/6\,20\,tT)
+exten => 21,1,Dial(IAX2/seaniax\,20\,T)
+exten => 22,1,Set(CALLERID(num)=1234567890)
+exten => 22,2,Set(CALLERID(name)=TestCaller)
+exten => 22,3,Dial(Zap/5\,20\,mP()A(beep)tw)
+exten => 22,4,NoOp(here is dialstatus: ${DIALSTATUS}...)
+exten => 22,5,Goto(s\,loopback)
+exten => 4,1,VoicemailMain()
+exten => 4,2,Goto(s\,loopback)
+exten => 5,1,Record(recording:gsm)
+exten => 5,2,Background(recording)
+exten => 6,1,ZapBarge()
+exten => 760,1,DateTime()
+exten => 760,2,Goto(s\,loopback)
+exten => 761,1,ZapBarge()
+exten => 761,2,Goto(s\,loopback)
+exten => 765,1,Playback(demo-echotest)
+exten => 765,2,Echo()
+exten => 765,3,Playback(demo-echodone)
+exten => 765,4,Goto(s\,loopback)
+exten => 766,1,Festival(The other thing to watch is neuro-electronics: the ability to interface technology with our neural system: My wife: Sigrid: has had a cochlear implant since 1996. This once profoundly deaf person now uses the phone: recognizes accents: and listens to movies and recorded books.)
+exten => 766,2,Goto(s\,loopback)
+exten => 767,1,agi(tts-riddle.agi)
+exten => 767,2,Background(gsm/what-time-it-is2)
+exten => 767,3,SayUnixTime()
+exten => 767,4,Goto(s\,loopback)
+exten => 768,1,agi(tts-computer.agi)
+exten => 771,1,eagi(eagi-test)
+exten => 771,2,agi(my-agi-test)
+exten => 772,1,agi(wakeup.agi)
+exten => 775,1,GotoIf($[${EXTEN}=${EXTEN} ]?2:4)
+exten => 775,2,BackGround(digits/1)
+exten => 775,3,Goto(5)
+exten => 775,4,BackGround(digits/0)
+exten => 775,5,NoOp(Finish if-workext-108)
+exten => 775,6,GotoIf($[${EXTEN}=${LANGUAGE} ]?7:9)
+exten => 775,7,BackGround(digits/1)
+exten => 775,8,Goto(10)
+exten => 775,9,BackGround(digits/0)
+exten => 775,10,NoOp(Finish if-workext-109)
+exten => 775,11,BackGround(digits/2)
+exten => 776,1,Set(TEST=00359889811777)
+exten => 776,2,GotoIf($[${TEST}= 00359889811777 ]?3:5)
+exten => 776,3,BackGround(digits/1)
+exten => 776,4,Goto(6)
+exten => 776,5,BackGround(digits/0)
+exten => 776,6,NoOp(Finish if-workext-110)
+exten => 776,7,GotoIf($[${TEST}= 00359889811888 ]?8:10)
+exten => 776,8,BackGround(digits/1)
+exten => 776,9,Goto(11)
+exten => 776,10,BackGround(digits/0)
+exten => 776,11,NoOp(Finish if-workext-111)
+exten => 776,12,Hangup()
+exten => 790,1,MeetMe(790\,p)
+exten => 792,1,Goto(pageall\,s\,begin)
+exten => 793,1,NoOp(Hello\, this is included from include1.ael2)
+exten => 793,2,NoOp(This was included from include2.ael2)
+exten => 793,3,NoOp(This is include3.ael2!)
+exten => 793,4,NoOp(Include5.ael2 doesn't include anything\, either!)
+exten => 793,5,NoOp(This is include4.ael2! Isn't it cool!?!?!?!)
+exten => 793,6,NoOp(4 doesn't include anything)
+exten => 795,1,AGI(wakeup.agi)
+exten => 795,2,Congestion()
+exten => 797,1,Set(CONFCIDNA=${CALLERID(name)})
+exten => 797,2,Set(CONFCIDNU=${CALLERID(num)})
+exten => 797,3,AGI(callall)
+exten => 797,4,AGI(submit-announce.agi)
+exten => 797,5,Hangup()
+
+
+[wakeup]
+exten => 3,1,Dial(Zap/3|30)
+exten => 4,1,Dial(Zap/4|30)
+exten => 5,1,Dial(Zap/5|30)
+exten => 6,1,Dial(Zap/6|30)
+exten => 99,1,Dial(IAX2/murfiaxphone|30)
+exten => 97,1,Dial(IAX2/ryaniax|30)
+exten => 94,1,Dial(IAX2/seaniax|30)
+
+
+[announce-all]
+exten => s,1(begin),MeetMe(5555\,dtqp)
+exten => s,2,MeetMeAdmin(5555\,K)
+exten => s,3,Hangup()
+exten => h,1,MeetMeAdmin(5555\,K)
+exten => h,2,Hangup()
+
+
+[telemarket]
+exten => s,1(begin),Playback(telemarketer-intro)
+exten => s,2,Playback(telemarketer-choices)
+exten => 1,1,Goto(telemarket-charity\,s\,begin)
+exten => 2,1,Goto(telemarket-political\,s\,begin)
+exten => 3,1,Goto(telemarket-pollster\,s\,begin)
+exten => 4,1,Goto(telemarket-research\,s\,begin)
+exten => 5,1,Goto(telemarket-magazine\,s\,begin)
+exten => 6,1,Goto(telemarket-commercial\,s\,begin)
+exten => 7,1,Goto(telemarket-other\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-charity]
+exten => s,1(begin),Playback(telemark-charity-intro)
+exten => s,2,Playback(telemark-charity-choices)
+exten => 1,1,Goto(telemarket-char-disease\,s\,begin)
+exten => 2,1,Goto(telemarket-char-handicap\,s\,begin)
+exten => 3,1,Goto(telemarket-char-police\,s\,begin)
+exten => 4,1,Goto(telemarket-char-school\,s\,begin)
+exten => 5,1,Goto(telemarket-char-college\,s\,begin)
+exten => 6,1,Goto(telemarket-char-animal\,s\,begin)
+exten => 7,1,Goto(telemarket-char-candidate\,s\,begin)
+exten => 8,1,Goto(telemarket-char-abuse\,s\,begin)
+exten => 9,1,Goto(telemarket-char-other\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-char-disease]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-handicap]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-police]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-school]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-college]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-animal]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-candidate]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-abuse]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-char-other]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-sorry]
+exten => s,1(begin),Playback(telemarket-sorry)
+exten => s,2,Hangup()
+
+
+[telemarket-exception]
+exten => s,1(begin),Playback(telemarket-success)
+exten => s,2,Hangup()
+
+
+[telemarket-political]
+exten => s,1(begin),Playback(telemark-polit-intro)
+exten => s,2,Playback(telemark-polit-choices)
+exten => 1,1,Goto(telemarket-poli-Am1st\,s\,begin)
+exten => 2,1,Goto(telemarket-poli-American\,s\,begin)
+exten => 3,1,Goto(telemarket-poli-AmHer\,s\,begin)
+exten => 4,1,Goto(telemarket-poli-AmInd\,s\,begin)
+exten => 5,1,Goto(telemarket-poli-AmNaz\,s\,begin)
+exten => 6,1,Goto(telemarket-poli-Pot\,s\,begin)
+exten => 7,1,Goto(telemarket-poli-AmRef\,s\,begin)
+exten => 8,1,Goto(telemarket-poli-CFP\,s\,begin)
+exten => 9,1,Goto(telemarket-political2\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-political2]
+exten => s,1(begin),Playback(telemark-politx-intro)
+exten => s,2,Playback(telemark-polit2-choices)
+exten => 1,1,Goto(telemarket-poli-Communist\,s\,begin)
+exten => 2,1,Goto(telemarket-poli-Constit\,s\,begin)
+exten => 3,1,Goto(telemarket-poli-FamVal\,s\,begin)
+exten => 4,1,Goto(telemarket-poli-FreedSoc\,s\,begin)
+exten => 5,1,Goto(telemarket-poli-Grassroot\,s\,begin)
+exten => 6,1,Goto(telemarket-poli-Green\,s\,begin)
+exten => 7,1,Goto(telemarket-poli-Greens\,s\,begin)
+exten => 8,1,Goto(telemarket-poli-Independence\,s\,begin)
+exten => 9,1,Goto(telemarket-political3\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-political3]
+exten => s,1(begin),Playback(telemark-politx-intro)
+exten => s,2,Playback(telemark-polit3-choices)
+exten => 1,1,Goto(telemarket-poli-IndAm\,s\,begin)
+exten => 2,1,Goto(telemarket-poli-Labor\,s\,begin)
+exten => 3,1,Goto(telemarket-poli-Liber\,s\,begin)
+exten => 4,1,Goto(telemarket-poli-Light\,s\,begin)
+exten => 5,1,Goto(telemarket-poli-NatLaw\,s\,begin)
+exten => 6,1,Goto(telemarket-poli-New\,s\,begin)
+exten => 7,1,Goto(telemarket-poli-NewUn\,s\,begin)
+exten => 8,1,Goto(telemarket-poli-PeaceFree\,s\,begin)
+exten => 9,1,Goto(telemarket-political4\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-political4]
+exten => s,1(begin),Playback(telemark-politx-intro)
+exten => s,2,Playback(telemark-polit4-choices)
+exten => 1,1,Goto(telemarket-poli-Prohib\,s\,begin)
+exten => 2,1,Goto(telemarket-poli-Ref\,s\,begin)
+exten => 3,1,Goto(telemarket-poli-Revol\,s\,begin)
+exten => 4,1,Goto(telemarket-poli-SocPart\,s\,begin)
+exten => 5,1,Goto(telemarket-poli-SocAct\,s\,begin)
+exten => 6,1,Goto(telemarket-poli-SocEq\,s\,begin)
+exten => 7,1,Goto(telemarket-poli-SocLab\,s\,begin)
+exten => 8,1,Goto(telemarket-poli-SocWork\,s\,begin)
+exten => 9,1,Goto(telemarket-political5\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-political5]
+exten => s,1(begin),Playback(telemark-politx-intro)
+exten => s,2,Playback(telemark-polit5-choices)
+exten => 1,1,Goto(telemarket-poli-South\,s\,begin)
+exten => 2,1,Goto(telemarket-poli-SoInd\,s\,begin)
+exten => 3,1,Goto(telemarket-poli-USPac\,s\,begin)
+exten => 4,1,Goto(telemarket-poli-WTP\,s\,begin)
+exten => 5,1,Goto(telemarket-poli-WWP\,s\,begin)
+exten => 6,1,Goto(telemarket-poli-Democrat\,s\,begin)
+exten => 7,1,Goto(telemarket-poli-Repub\,s\,begin)
+exten => 8,1,Goto(telemarket-poli-other\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-poli-other]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Repub]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Democrat]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-WWP]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-WTP]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-USPac]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-SoInd]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-South]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-SocWork]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-SocLab]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-SocEq]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-SocAct]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-SocPart]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Revol]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Ref]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Prohib]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-PeaceFree]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-NewUn]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-New]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-NatLaw]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Light]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Liber]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Labor]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-IndAm]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Independence]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Greens]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Green]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Grassroot]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-FreedSoc]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-FamVal]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Constit]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Communist]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-CFP]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-AmRef]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Pot]
+exten => s,1(begin),Goto(telemarket-political\,s\,begin)
+
+
+[telemarket-poli-AmNaz]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-AmInd]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-AmHer]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-American]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-poli-Am1st]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-pollster]
+exten => s,1(begin),Playback(telemark-poll-intro)
+exten => s,2,Goto(telemarket-sorry\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-research]
+exten => s,1(begin),Playback(telemark-research-intro)
+exten => s,2,Goto(telemarket-sorry\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-magazine]
+exten => s,1(begin),Playback(telemark-mag-choices)
+exten => 1,1,Goto(telemark-mag-new\,s\,begin)
+exten => 2,1,Goto(telemark-mag-renew\,s\,begin)
+exten => 3,1,Goto(telemark-mag-survey\,s\,begin)
+exten => 4,1,Goto(telemark-mag-verify\,s\,begin)
+exten => 5,1,Goto(telemark-mag-other\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemark-mag-new]
+exten => s,1(begin),Playback(telemark-mag-new)
+exten => s,2,Hangup()
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemark-mag-renew]
+exten => s,1(begin),Playback(telemark-mag-renew)
+exten => s,2,Hangup()
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemark-mag-survey]
+exten => s,1(begin),Playback(telemark-mag-survey)
+exten => s,2,Hangup()
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemark-mag-verify]
+exten => s,1(begin),Playback(telemark-mag-verify)
+exten => s,2,Hangup()
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemark-mag-other]
+exten => s,1(begin),Goto(telemarket-sorry\,s\,begin)
+
+
+[telemarket-commercial]
+exten => s,1(begin),Playback(telemark-comm-intro)
+exten => s,2,Voicemail(u82)
+exten => s,3,Goto(telemarket-sorry\,s\,begin)
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
+
+
+[telemarket-other]
+exten => s,1(begin),Playback(telemark-other-intro)
+exten => s,2,Hangup()
+exten => t,1,Goto(telemarket\,s\,begin)
+exten => i,1,Goto(telemarket\,s\,begin)
+exten => o,1,Goto(telemarket\,s\,begin)
diff --git a/trunk/pbx/ael/ael-test/ref.ael-vtest17 b/trunk/pbx/ael/ael-test/ref.ael-vtest17
new file mode 100644
index 000000000..bb4204caa
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-vtest17
@@ -0,0 +1,69 @@
+
+
+[dialextens]
+exten => _10X,1,Dial(Zap/${EXTEN:2}\,30\,tw)
+exten => _1ZX,1,Dial(Zap/${EXTEN:1}\,30\,tw)
+
+
+[dialthrus]
+exten => _3XX,1,Dial(Zap/${EXTEN:1}\,30\,tw)
+
+
+[t1incoming]
+include => dialextens
+include => parkedcalls
+exten => s,1,Answer()
+exten => s,2,Background(welcome-to-test-machine)
+
+
+[incoming]
+include => dialextens
+include => parkedcalls
+exten => s,1,Answer()
+exten => s,2,Background(welcome-to-test-machine)
+
+
+[extension]
+include => dialextens
+include => dialthrus
+exten => 5,1,Record(recording:gsm)
+exten => 5,2,Background(recording)
+exten => 81,1,Set(iterations=$[1000000])
+exten => 81,2,Set(time1=${EPOCH})
+exten => 81,3,Set(i=$[1])
+exten => 81,4,GotoIf($[${i}<${iterations}]?5:8)
+exten => 81,5,NoOp(Hello)
+exten => 81,6,Set(i=$[${i}+1])
+exten => 81,7,Goto(4)
+exten => 81,8,NoOp(Finish for-extension-1)
+exten => 81,9,Set(time2=${EPOCH})
+exten => 81,10,Verbose(The time diff is $[${time2} - ${time1} ] seconds)
+exten => 81,11,Verbose(Which means that the priorities/sec = $[4* ${iterations} / (${time2} - ${time1}) ])
+exten => 81,12,SayNumber($[4 * ${iterations} / (${time2} - ${time1}) ])
+exten => 82,1,Gosub(ndeep\,s\,1(100000))
+exten => 82,2,Verbose(Finished 100000 levels deep call!)
+exten => 83,1,Goto(sw-2-${EXTEN}\,10)
+exten => 83,2,NoOp(Finish switch-extension-2)
+exten => _sw-2-.,10,Goto(83\,2)
+exten => sw-2-,10,Goto(sw-2-.|10)
+exten => _sw-2-[4-7]X,10,Verbose(and this too!)
+exten => _sw-2-[4-7]X,11,Goto(sw-2-.\,10)
+exten => _sw-2-9X,10,Verbose(handle both 8x and 9x calls)
+exten => _sw-2-9X,11,Goto(sw-2-49\,10)
+exten => _sw-2-8X,10,Verbose(do something to prepare it)
+exten => _sw-2-8X,11,Goto(sw-2-99\,10)
+
+
+[ndeep]
+exten => s,1,Set(LOCAL(level)=${ARG1})
+exten => s,2,GotoIf($[${level} == 0]?3:5)
+exten => s,3,Verbose(2|Got to Level 0)
+exten => s,4,Return()
+exten => s,5,NoOp(Finish if-ndeep-3)
+exten => s,6,Gosub(ndeep\,s\,1($[${level}-1]))
+exten => s,7,Return()
+
+
+[t1extension]
+include => dialextens
+include => dialthrus
diff --git a/trunk/pbx/ael/ael-test/ref.ael-vtest21 b/trunk/pbx/ael/ael-test/ref.ael-vtest21
new file mode 100644
index 000000000..711540aa3
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/ref.ael-vtest21
@@ -0,0 +1,9 @@
+[globals]
+AXLHAFT=wow-to-the-tenth-power
+JibberWorthy=zinger3
+OFFICE_CODE=503
+
+
+[from-enum]
+exten => _${OFFICE_CODE}XXXX,1,Answer()
+exten => _${OFFICE_CODE}XXXX,2,Goto(${EXTEN:3}\,1)
diff --git a/trunk/pbx/ael/ael-test/runtests b/trunk/pbx/ael/ael-test/runtests
new file mode 100755
index 000000000..9209f0a54
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/runtests
@@ -0,0 +1,56 @@
+#!/bin/bash
+ORIG=`mktemp /tmp/mytest.XXXXXX`
+NEW=`mktemp /tmp/mytest.XXXXXX`
+
+do_filter() {
+ sed 's/line:[0-9]*//; /^Executed.*/d; s/column=[0-9]*/ /; s/Cols: [0-9]*-[0-9]*/___/'
+}
+
+for i in ael-test*; do
+ echo -n Test: $i..................
+ (cd $i; ../../../../utils/aelparse -n -d | grep -v -i 'seconds' > ../res.$i)
+ do_filter < res.$i > $NEW
+ do_filter < ref.$i > $ORIG
+ if (diff -q $NEW $ORIG > /dev/null 2>&1 ) then
+ echo PASSED
+ rm res.$i
+ else
+ echo %%%%%%FAILED%%%%%%
+ # diff -u ref.$i res.$i
+ diff -u $ORIG $NEW
+ fi
+
+done
+
+for i in ael-ntest*; do
+ echo -n Test: $i.................
+ (cd $i; ../../../../utils/aelparse -d | grep -v -i 'seconds' > ../res.$i)
+ do_filter < res.$i > $NEW
+ do_filter < ref.$i > $ORIG
+ if (diff -q $NEW $ORIG > /dev/null 2>&1 ) then
+ echo PASSED
+ rm res.$i
+ else
+ echo %%%%%%FAILED%%%%%%
+ # diff -u ref.$i res.$i
+ diff -u $ORIG $NEW
+ fi
+
+done
+
+for i in ael-vtest*; do
+ echo -n Test: $i.................
+ (cd $i; ../../../../utils/aelparse -d -w -n | grep -v -i 'seconds' > ../res2.$i)
+
+ if (diff -q ref.$i $i/extensions.conf.aeldump > /dev/null 2>&1 ) then
+ echo PASSED
+ rm res2.$i
+ rm $i/extensions.conf.aeldump
+ else
+ echo %%%%%%FAILED%%%%%%
+ # diff -u ref.$i res.$i
+ diff -u ref.$i $i/extensions.conf.aeldump
+ fi
+
+done
+rm $NEW $ORIG
diff --git a/trunk/pbx/ael/ael-test/setref b/trunk/pbx/ael/ael-test/setref
new file mode 100755
index 000000000..b483f05ae
--- /dev/null
+++ b/trunk/pbx/ael/ael-test/setref
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+for i in res.*; do
+ refname=`echo $i | sed 's/^res/ref/'`
+ echo $refname
+ mv $i $refname
+done
diff --git a/trunk/pbx/dundi-parser.c b/trunk/pbx/dundi-parser.c
new file mode 100644
index 000000000..bab1bfc91
--- /dev/null
+++ b/trunk/pbx/dundi-parser.c
@@ -0,0 +1,846 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Distributed Universal Number Discovery (DUNDi)
+ *
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "asterisk/frame.h"
+#include "asterisk/utils.h"
+#include "asterisk/dundi.h"
+#include "dundi-parser.h"
+
+static void internaloutput(const char *str)
+{
+ fputs(str, stdout);
+}
+
+static void internalerror(const char *str)
+{
+ fprintf(stderr, "WARNING: %s", str);
+}
+
+static void (*outputf)(const char *str) = internaloutput;
+static void (*errorf)(const char *str) = internalerror;
+
+char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid)
+{
+ int x;
+ char *os = s;
+ if (maxlen < 18) {
+ if (s && (maxlen > 0))
+ *s = '\0';
+ } else {
+ for (x=0;x<5;x++) {
+ sprintf(s, "%02x:", eid->eid[x]);
+ s += 3;
+ }
+ sprintf(s, "%02x", eid->eid[5]);
+ }
+ return os;
+}
+
+char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid)
+{
+ int x;
+ char *os = s;
+ if (maxlen < 13) {
+ if (s && (maxlen > 0))
+ *s = '\0';
+ } else {
+ for (x=0;x<6;x++) {
+ sprintf(s, "%02X", eid->eid[x]);
+ s += 2;
+ }
+ }
+ return os;
+}
+
+int dundi_str_to_eid(dundi_eid *eid, const char *s)
+{
+ unsigned int eid_int[6];
+ int x;
+ if (sscanf(s, "%x:%x:%x:%x:%x:%x", &eid_int[0], &eid_int[1], &eid_int[2],
+ &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
+ return -1;
+ for (x=0;x<6;x++)
+ eid->eid[x] = eid_int[x];
+ return 0;
+}
+
+int dundi_str_short_to_eid(dundi_eid *eid, const char *s)
+{
+ unsigned int eid_int[6];
+ int x;
+ if (sscanf(s, "%2x%2x%2x%2x%2x%2x", &eid_int[0], &eid_int[1], &eid_int[2],
+ &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
+ return -1;
+ for (x=0;x<6;x++)
+ eid->eid[x] = eid_int[x];
+ return 0;
+}
+
+int dundi_eid_zero(dundi_eid *eid)
+{
+ int x;
+ for (x=0;x<sizeof(eid->eid) / sizeof(eid->eid[0]);x++)
+ if (eid->eid[x]) return 0;
+ return 1;
+}
+
+int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2)
+{
+ return memcmp(eid1, eid2, sizeof(dundi_eid));
+}
+
+static void dump_string(char *output, int maxlen, void *value, int len)
+{
+ if (maxlen > len + 1)
+ maxlen = len + 1;
+
+ snprintf(output, maxlen, "%s", (char *) value);
+}
+
+static void dump_cbypass(char *output, int maxlen, void *value, int len)
+{
+ snprintf(output, maxlen, "Bypass Caches");
+}
+
+static void dump_eid(char *output, int maxlen, void *value, int len)
+{
+ if (len == 6)
+ dundi_eid_to_str(output, maxlen, (dundi_eid *)value);
+ else
+ snprintf(output, maxlen, "Invalid EID len %d", len);
+}
+
+char *dundi_hint2str(char *buf, int bufsiz, int flags)
+{
+ strcpy(buf, "");
+ buf[bufsiz-1] = '\0';
+ if (flags & DUNDI_HINT_TTL_EXPIRED) {
+ strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_HINT_DONT_ASK) {
+ strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_HINT_UNAFFECTED) {
+ strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1);
+ }
+ /* Get rid of trailing | */
+ if (ast_strlen_zero(buf))
+ strcpy(buf, "NONE|");
+ buf[strlen(buf)-1] = '\0';
+ return buf;
+}
+
+static void dump_hint(char *output, int maxlen, void *value, int len)
+{
+ char tmp2[256];
+ char tmp3[256];
+ int datalen;
+ struct dundi_hint *hint;
+ if (len < sizeof(*hint)) {
+ snprintf(output, maxlen, "<invalid contents>");
+ return;
+ }
+
+ hint = (struct dundi_hint *) value;;
+
+ datalen = len - offsetof(struct dundi_hint, data);
+ if (datalen > sizeof(tmp3) - 1)
+ datalen = sizeof(tmp3) - 1;
+
+ memcpy(tmp3, hint->data, datalen);
+ tmp3[datalen] = '\0';
+
+ dundi_hint2str(tmp2, sizeof(tmp2), ntohs(hint->flags));
+
+ if (ast_strlen_zero(tmp3))
+ snprintf(output, maxlen, "[%s]", tmp2);
+ else
+ snprintf(output, maxlen, "[%s] %s", tmp2, tmp3);
+}
+
+static void dump_cause(char *output, int maxlen, void *value, int len)
+{
+ static char *causes[] = {
+ "SUCCESS",
+ "GENERAL",
+ "DYNAMIC",
+ "NOAUTH" ,
+ };
+ char tmp2[256];
+ struct dundi_cause *cause;
+ int datalen;
+ int causecode;
+
+ if (len < sizeof(*cause)) {
+ snprintf(output, maxlen, "<invalid contents>");
+ return;
+ }
+
+ cause = (struct dundi_cause*) value;
+ causecode = cause->causecode;
+
+ datalen = len - offsetof(struct dundi_cause, desc);
+ if (datalen > sizeof(tmp2) - 1)
+ datalen = sizeof(tmp2) - 1;
+
+ memcpy(tmp2, cause->desc, datalen);
+ tmp2[datalen] = '\0';
+
+ if (causecode < sizeof(causes) / sizeof(causes[0])) {
+ if (ast_strlen_zero(tmp2))
+ snprintf(output, maxlen, "%s", causes[causecode]);
+ else
+ snprintf(output, maxlen, "%s: %s", causes[causecode], tmp2);
+ } else {
+ if (ast_strlen_zero(tmp2))
+ snprintf(output, maxlen, "%d", causecode);
+ else
+ snprintf(output, maxlen, "%d: %s", causecode, tmp2);
+ }
+}
+
+static void dump_int(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned int))
+ snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value)));
+ else
+ ast_copy_string(output, "Invalid INT", maxlen);
+}
+
+static void dump_short(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned short))
+ snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
+ else
+ ast_copy_string(output, "Invalid SHORT", maxlen);
+}
+
+static void dump_byte(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned char))
+ snprintf(output, maxlen, "%d", *((unsigned char *)value));
+ else
+ ast_copy_string(output, "Invalid BYTE", maxlen);
+}
+
+static char *proto2str(int proto, char *buf, int bufsiz)
+{
+ switch(proto) {
+ case DUNDI_PROTO_NONE:
+ strncpy(buf, "None", bufsiz - 1);
+ break;
+ case DUNDI_PROTO_IAX:
+ strncpy(buf, "IAX", bufsiz - 1);
+ break;
+ case DUNDI_PROTO_SIP:
+ strncpy(buf, "SIP", bufsiz - 1);
+ break;
+ case DUNDI_PROTO_H323:
+ strncpy(buf, "H.323", bufsiz - 1);
+ break;
+ default:
+ snprintf(buf, bufsiz, "Unknown Proto(%d)", proto);
+ }
+ buf[bufsiz-1] = '\0';
+ return buf;
+}
+
+char *dundi_flags2str(char *buf, int bufsiz, int flags)
+{
+ strcpy(buf, "");
+ buf[bufsiz-1] = '\0';
+ if (flags & DUNDI_FLAG_EXISTS) {
+ strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_MATCHMORE) {
+ strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_CANMATCH) {
+ strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_IGNOREPAT) {
+ strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_RESIDENTIAL) {
+ strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_COMMERCIAL) {
+ strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_MOBILE) {
+ strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_NOUNSOLICITED) {
+ strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1);
+ }
+ if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) {
+ strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1);
+ }
+ /* Get rid of trailing | */
+ if (ast_strlen_zero(buf))
+ strcpy(buf, "NONE|");
+ buf[strlen(buf)-1] = '\0';
+ return buf;
+}
+
+static void dump_answer(char *output, int maxlen, void *value, int len)
+{
+ struct dundi_answer *answer;
+ char proto[40];
+ char flags[40];
+ char eid_str[40];
+ char tmp[512]="";
+ int datalen;
+
+ if (len < sizeof(*answer)) {
+ snprintf(output, maxlen, "Invalid Answer");
+ return;
+ }
+
+ answer = (struct dundi_answer *)(value);
+
+ datalen = len - offsetof(struct dundi_answer, data);
+ if (datalen > sizeof(tmp) - 1)
+ datalen = sizeof(tmp) - 1;
+
+ memcpy(tmp, answer->data, datalen);
+ tmp[datalen] = '\0';
+
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &answer->eid);
+ snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]",
+ dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)),
+ ntohs(answer->weight),
+ proto2str(answer->protocol, proto, sizeof(proto)),
+ tmp, eid_str);
+}
+
+static void dump_encrypted(char *output, int maxlen, void *value, int len)
+{
+ char iv[33];
+ int x;
+ if ((len > 16) && !(len % 16)) {
+ /* Build up IV */
+ for (x=0;x<16;x++) {
+ snprintf(iv + (x << 1), 3, "%02x", ((unsigned char *)value)[x]);
+ }
+ snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16);
+ } else
+ snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len);
+}
+
+static void dump_raw(char *output, int maxlen, void *value, int len)
+{
+ int x;
+ unsigned char *u = value;
+ output[maxlen - 1] = '\0';
+ strcpy(output, "[ ");
+ for (x=0;x<len;x++) {
+ snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", u[x]);
+ }
+ strncat(output + strlen(output), "]", maxlen - strlen(output) - 1);
+}
+
+static struct dundi_ie {
+ int ie;
+ char *name;
+ void (*dump)(char *output, int maxlen, void *value, int len);
+} ies[] = {
+ { DUNDI_IE_EID, "ENTITY IDENT", dump_eid },
+ { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
+ { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
+ { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid },
+ { DUNDI_IE_ANSWER, "ANSWER", dump_answer },
+ { DUNDI_IE_TTL, "TTL", dump_short },
+ { DUNDI_IE_VERSION, "VERSION", dump_short },
+ { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short },
+ { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte },
+ { DUNDI_IE_CAUSE, "CAUSE", dump_cause },
+ { DUNDI_IE_REQEID, "REQUEST EID", dump_eid },
+ { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted },
+ { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw },
+ { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw },
+ { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int },
+ { DUNDI_IE_HINT, "HINT", dump_hint },
+ { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string },
+ { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string },
+ { DUNDI_IE_LOCALITY, "LOCALITY", dump_string },
+ { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string },
+ { DUNDI_IE_COUNTRY, "COUNTRY", dump_string },
+ { DUNDI_IE_EMAIL, "EMAIL", dump_string },
+ { DUNDI_IE_PHONE, "PHONE", dump_string },
+ { DUNDI_IE_IPADDR, "ADDRESS", dump_string },
+ { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass },
+};
+
+const char *dundi_ie2str(int ie)
+{
+ int x;
+ for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
+ if (ies[x].ie == ie)
+ return ies[x].name;
+ }
+ return "Unknown IE";
+}
+
+static void dump_ies(unsigned char *iedata, int spaces, int len)
+{
+ int ielen;
+ int ie;
+ int x;
+ int found;
+ char interp[1024];
+ char tmp[1024];
+ if (len < 2)
+ return;
+ while(len >= 2) {
+ ie = iedata[0];
+ ielen = iedata[1];
+ /* Encrypted data is the remainder */
+ if (ie == DUNDI_IE_ENCDATA)
+ ielen = len - 2;
+ if (ielen + 2> len) {
+ snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
+ outputf(tmp);
+ return;
+ }
+ found = 0;
+ for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
+ if (ies[x].ie == ie) {
+ if (ies[x].dump) {
+ ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
+ snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp);
+ outputf(tmp);
+ } else {
+ if (ielen)
+ snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
+ else
+ strcpy(interp, "Present");
+ snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp);
+ outputf(tmp);
+ }
+ found++;
+ }
+ }
+ if (!found) {
+ snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie);
+ outputf(tmp);
+ }
+ iedata += (2 + ielen);
+ len -= (2 + ielen);
+ }
+ outputf("\n");
+}
+
+void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
+{
+ char *pref[] = {
+ "Tx",
+ "Rx",
+ " ETx",
+ " Erx" };
+ char *commands[] = {
+ "ACK ",
+ "DPDISCOVER ",
+ "DPRESPONSE ",
+ "EIDQUERY ",
+ "EIDRESPONSE ",
+ "PRECACHERQ ",
+ "PRECACHERP ",
+ "INVALID ",
+ "UNKNOWN CMD ",
+ "NULL ",
+ "REQREQ ",
+ "REGRESPONSE ",
+ "CANCEL ",
+ "ENCRYPT ",
+ "ENCREJ " };
+ char class2[20];
+ char *class;
+ char subclass2[20];
+ char *subclass;
+ char tmp[256];
+ char retries[20];
+ if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS)
+ strcpy(retries, "Yes");
+ else
+ strcpy(retries, "No");
+ if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) {
+ /* Ignore frames with high bit set to 1 */
+ return;
+ }
+ if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) {
+ snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp);
+ class = class2;
+ } else {
+ class = commands[(int)(fhi->cmdresp & 0x3f)];
+ }
+ snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags);
+ subclass = subclass2;
+ snprintf(tmp, (int)sizeof(tmp),
+ "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n",
+ pref[rx],
+ retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");
+ outputf(tmp);
+ snprintf(tmp, (int)sizeof(tmp),
+ "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "",
+ subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,
+ ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
+ fhi->cmdresp & 0x80 ? " (Final)" : "");
+ outputf(tmp);
+ dump_ies(fhi->ies, rx > 1, datalen);
+}
+
+int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen)
+{
+ char tmp[256];
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
+ errorf(tmp);
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ memcpy(ied->buf + ied->pos, data, datalen);
+ ied->pos += datalen;
+ return 0;
+}
+
+int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data)
+{
+ char tmp[256];
+ int datalen = data ? strlen(data) + 1 : 1;
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
+ errorf(tmp);
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ ied->buf[ied->pos++] = cause;
+ memcpy(ied->buf + ied->pos, data, datalen-1);
+ ied->pos += datalen-1;
+ return 0;
+}
+
+int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data)
+{
+ char tmp[256];
+ int datalen = data ? strlen(data) + 2 : 2;
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
+ errorf(tmp);
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ flags = htons(flags);
+ memcpy(ied->buf + ied->pos, &flags, sizeof(flags));
+ ied->pos += 2;
+ memcpy(ied->buf + ied->pos, data, datalen-1);
+ ied->pos += datalen-2;
+ return 0;
+}
+
+int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen)
+{
+ char tmp[256];
+ datalen += 16;
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
+ errorf(tmp);
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ memcpy(ied->buf + ied->pos, iv, 16);
+ ied->pos += 16;
+ if (data) {
+ memcpy(ied->buf + ied->pos, data, datalen-16);
+ ied->pos += datalen-16;
+ }
+ return 0;
+}
+
+int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *data)
+{
+ char tmp[256];
+ int datalen = data ? strlen(data) + 11 : 11;
+ int x;
+ unsigned short myw;
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
+ errorf(tmp);
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ for (x=0;x<6;x++)
+ ied->buf[ied->pos++] = eid->eid[x];
+ ied->buf[ied->pos++] = protocol;
+ myw = htons(flags);
+ memcpy(ied->buf + ied->pos, &myw, 2);
+ ied->pos += 2;
+ myw = htons(weight);
+ memcpy(ied->buf + ied->pos, &myw, 2);
+ ied->pos += 2;
+ memcpy(ied->buf + ied->pos, data, datalen-11);
+ ied->pos += datalen-11;
+ return 0;
+}
+
+int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
+{
+ return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
+}
+
+int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value)
+{
+ unsigned int newval;
+ newval = htonl(value);
+ return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
+}
+
+int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value)
+{
+ unsigned short newval;
+ newval = htons(value);
+ return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
+}
+
+int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str)
+{
+ return dundi_ie_append_raw(ied, ie, str, strlen(str));
+}
+
+int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid)
+{
+ return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid));
+}
+
+int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat)
+{
+ return dundi_ie_append_raw(ied, ie, &dat, 1);
+}
+
+int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie)
+{
+ return dundi_ie_append_raw(ied, ie, NULL, 0);
+}
+
+void dundi_set_output(void (*func)(const char *))
+{
+ outputf = func;
+}
+
+void dundi_set_error(void (*func)(const char *))
+{
+ errorf = func;
+}
+
+int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen)
+{
+ /* Parse data into information elements */
+ int len;
+ int ie;
+ char tmp[256];
+ memset(ies, 0, (int)sizeof(struct dundi_ies));
+ ies->ttl = -1;
+ ies->expiration = -1;
+ ies->unknowncmd = -1;
+ ies->cause = -1;
+ while(datalen >= 2) {
+ ie = data[0];
+ len = data[1];
+ if (len > datalen - 2) {
+ errorf("Information element length exceeds message size\n");
+ return -1;
+ }
+ switch(ie) {
+ case DUNDI_IE_EID:
+ case DUNDI_IE_EID_DIRECT:
+ if (len != (int)sizeof(dundi_eid)) {
+ errorf("Improper entity identifer, expecting 6 bytes!\n");
+ } else if (ies->eidcount < DUNDI_MAX_STACK) {
+ ies->eids[ies->eidcount] = (dundi_eid *)(data + 2);
+ ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT);
+ ies->eidcount++;
+ } else
+ errorf("Too many entities in stack!\n");
+ break;
+ case DUNDI_IE_REQEID:
+ if (len != (int)sizeof(dundi_eid)) {
+ errorf("Improper requested entity identifer, expecting 6 bytes!\n");
+ } else
+ ies->reqeid = (dundi_eid *)(data + 2);
+ break;
+ case DUNDI_IE_CALLED_CONTEXT:
+ ies->called_context = (char *)data + 2;
+ break;
+ case DUNDI_IE_CALLED_NUMBER:
+ ies->called_number = (char *)data + 2;
+ break;
+ case DUNDI_IE_ANSWER:
+ if (len < sizeof(struct dundi_answer)) {
+ snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len);
+ errorf(tmp);
+ } else {
+ if (ies->anscount < DUNDI_MAX_ANSWERS)
+ ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2);
+ else
+ errorf("Ignoring extra answers!\n");
+ }
+ break;
+ case DUNDI_IE_TTL:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->ttl = ntohs(*((unsigned short *)(data + 2)));
+ break;
+ case DUNDI_IE_VERSION:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->version = ntohs(*((unsigned short *)(data + 2)));
+ break;
+ case DUNDI_IE_EXPIRATION:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->expiration = ntohs(*((unsigned short *)(data + 2)));
+ break;
+ case DUNDI_IE_KEYCRC32:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else
+ ies->keycrc32 = ntohl(*((unsigned int *)(data + 2)));
+ break;
+ case DUNDI_IE_UNKNOWN:
+ if (len == 1)
+ ies->unknowncmd = data[2];
+ else {
+ snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
+ errorf(tmp);
+ }
+ break;
+ case DUNDI_IE_CAUSE:
+ if (len >= 1) {
+ ies->cause = data[2];
+ ies->causestr = (char *)data + 3;
+ } else {
+ snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len);
+ errorf(tmp);
+ }
+ break;
+ case DUNDI_IE_HINT:
+ if (len >= 2) {
+ ies->hint = (struct dundi_hint *)(data + 2);
+ } else {
+ snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len);
+ errorf(tmp);
+ }
+ break;
+ case DUNDI_IE_DEPARTMENT:
+ ies->q_dept = (char *)data + 2;
+ break;
+ case DUNDI_IE_ORGANIZATION:
+ ies->q_org = (char *)data + 2;
+ break;
+ case DUNDI_IE_LOCALITY:
+ ies->q_locality = (char *)data + 2;
+ break;
+ case DUNDI_IE_STATE_PROV:
+ ies->q_stateprov = (char *)data + 2;
+ break;
+ case DUNDI_IE_COUNTRY:
+ ies->q_country = (char *)data + 2;
+ break;
+ case DUNDI_IE_EMAIL:
+ ies->q_email = (char *)data + 2;
+ break;
+ case DUNDI_IE_PHONE:
+ ies->q_phone = (char *)data + 2;
+ break;
+ case DUNDI_IE_IPADDR:
+ ies->q_ipaddr = (char *)data + 2;
+ break;
+ case DUNDI_IE_ENCDATA:
+ /* Recalculate len as the remainder of the message, regardless of
+ theoretical length */
+ len = datalen - 2;
+ if ((len > 16) && !(len % 16)) {
+ ies->encblock = (struct dundi_encblock *)(data + 2);
+ ies->enclen = len - 16;
+ } else {
+ snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len);
+ errorf(tmp);
+ }
+ break;
+ case DUNDI_IE_SHAREDKEY:
+ if (len == 128) {
+ ies->encsharedkey = (unsigned char *)(data + 2);
+ } else {
+ snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len);
+ errorf(tmp);
+ }
+ break;
+ case DUNDI_IE_SIGNATURE:
+ if (len == 128) {
+ ies->encsig = (unsigned char *)(data + 2);
+ } else {
+ snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len);
+ errorf(tmp);
+ }
+ break;
+ case DUNDI_IE_CACHEBYPASS:
+ ies->cbypass = 1;
+ break;
+ default:
+ snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len);
+ outputf(tmp);
+ }
+ /* Overwrite information element with 0, to null terminate previous portion */
+ data[0] = 0;
+ datalen -= (len + 2);
+ data += (len + 2);
+ }
+ /* Null-terminate last field */
+ *data = '\0';
+ if (datalen) {
+ errorf("Invalid information element contents, strange boundary\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/trunk/pbx/dundi-parser.h b/trunk/pbx/dundi-parser.h
new file mode 100644
index 000000000..8ff772347
--- /dev/null
+++ b/trunk/pbx/dundi-parser.h
@@ -0,0 +1,88 @@
+/*
+ * Distributed Universal Number Discovery (DUNDi)
+ *
+ * Copyright (C) 2004 - 2005, Digium Inc.
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ *
+ * This program is Free Software distributed under the terms of
+ * of the GNU General Public License.
+ */
+
+#ifndef _DUNDI_PARSER_H
+#define _DUNDI_PARSER_H
+
+#include "asterisk/dundi.h"
+#include "asterisk/aes.h"
+
+#define DUNDI_MAX_STACK 512
+#define DUNDI_MAX_ANSWERS 100
+
+struct dundi_ies {
+ dundi_eid *eids[DUNDI_MAX_STACK + 1];
+ int eid_direct[DUNDI_MAX_STACK + 1];
+ dundi_eid *reqeid;
+ int eidcount;
+ char *called_context;
+ char *called_number;
+ struct dundi_answer *answers[DUNDI_MAX_ANSWERS + 1];
+ struct dundi_hint *hint;
+ int anscount;
+ int ttl;
+ int version;
+ int expiration;
+ int unknowncmd;
+ unsigned char *pubkey;
+ int cause;
+ char *q_dept;
+ char *q_org;
+ char *q_locality;
+ char *q_stateprov;
+ char *q_country;
+ char *q_email;
+ char *q_phone;
+ char *q_ipaddr;
+ char *causestr;
+ unsigned char *encsharedkey;
+ unsigned char *encsig;
+ unsigned long keycrc32;
+ struct dundi_encblock *encblock;
+ int enclen;
+ int cbypass;
+};
+
+struct dundi_ie_data {
+ int pos;
+ unsigned char buf[8192];
+};
+
+/* Choose a different function for output */
+extern void dundi_set_output(void (*output)(const char *data));
+/* Choose a different function for errors */
+extern void dundi_set_error(void (*output)(const char *data));
+extern void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
+
+extern const char *dundi_ie2str(int ie);
+
+extern int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen);
+extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin);
+extern int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value);
+extern int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value);
+extern int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str);
+extern int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid);
+extern int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *desc);
+extern int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data);
+extern int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *desc);
+extern int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen);
+extern int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat);
+extern int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie);
+extern int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen);
+extern char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid);
+extern char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid);
+extern int dundi_str_to_eid(dundi_eid *eid, const char *s);
+extern int dundi_str_short_to_eid(dundi_eid *eid, const char *s);
+extern int dundi_eid_zero(dundi_eid *eid);
+extern int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2);
+extern char *dundi_flags2str(char *s, int maxlen, int flags);
+extern char *dundi_hint2str(char *s, int maxlen, int flags);
+#endif
diff --git a/trunk/pbx/pbx_ael.c b/trunk/pbx/pbx_ael.c
new file mode 100644
index 000000000..cffa65f40
--- /dev/null
+++ b/trunk/pbx/pbx_ael.c
@@ -0,0 +1,313 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Digium, Inc.
+ *
+ * Steve Murphy <murf@parsetree.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
+ *
+ */
+
+/*** MODULEINFO
+ <depend>res_ael_share</depend>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <ctype.h>
+#include <regex.h>
+#include <sys/stat.h>
+
+#include "asterisk/pbx.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/callerid.h"
+#include "asterisk/ael_structs.h"
+#include "asterisk/pval.h"
+#ifdef AAL_ARGCHECK
+#include "asterisk/argdesc.h"
+#endif
+
+/* these functions are in ../ast_expr2.fl */
+
+#define DEBUG_READ (1 << 0)
+#define DEBUG_TOKENS (1 << 1)
+#define DEBUG_MACROS (1 << 2)
+#define DEBUG_CONTEXTS (1 << 3)
+
+static char *config = "extensions.ael";
+static char *registrar = "pbx_ael";
+static int pbx_load_module(void);
+
+#ifndef AAL_ARGCHECK
+/* for the time being, short circuit all the AAL related structures
+ without permanently removing the code; after/during the AAL
+ development, this code can be properly re-instated
+*/
+
+#endif
+
+#ifdef AAL_ARGCHECK
+int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
+int option_matches( struct argdesc *should, pval *is, struct argapp *app);
+int ael_is_funcname(char *name);
+#endif
+
+int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
+void check_pval(pval *item, struct argapp *apps, int in_globals);
+void check_pval_item(pval *item, struct argapp *apps, int in_globals);
+void check_switch_expr(pval *item, struct argapp *apps);
+void ast_expr_register_extra_error_info(char *errmsg);
+void ast_expr_clear_extra_error_info(void);
+struct pval *find_macro(char *name);
+struct pval *find_context(char *name);
+struct pval *find_context(char *name);
+struct pval *find_macro(char *name);
+struct ael_priority *new_prio(void);
+struct ael_extension *new_exten(void);
+void linkprio(struct ael_extension *exten, struct ael_priority *prio);
+void destroy_extensions(struct ael_extension *exten);
+void set_priorities(struct ael_extension *exten);
+void add_extensions(struct ael_extension *exten);
+void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void destroy_pval(pval *item);
+void destroy_pval_item(pval *item);
+int is_float(char *arg );
+int is_int(char *arg );
+int is_empty(char *arg);
+
+/* static void substitute_commas(char *str); */
+
+static int aeldebug = 0;
+
+/* interface stuff */
+
+/* if all the below are static, who cares if they are present? */
+
+static int pbx_load_module(void)
+{
+ int errs=0, sem_err=0, sem_warn=0, sem_note=0;
+ char *rfilename;
+ struct ast_context *local_contexts=NULL, *con;
+ struct pval *parse_tree;
+
+ ast_log(LOG_NOTICE, "Starting AEL load process.\n");
+ if (config[0] == '/')
+ rfilename = (char *)config;
+ else {
+ rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
+ sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
+ }
+ if (access(rfilename,R_OK) != 0) {
+ ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ parse_tree = ael2_parse(rfilename, &errs);
+ ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
+ ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
+ if (errs == 0 && sem_err == 0) {
+ ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
+ ast_compile_ael2(&local_contexts, parse_tree);
+ ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
+
+ ast_merge_contexts_and_delete(&local_contexts, registrar);
+ ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
+ for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
+ ast_context_verify_includes(con);
+ ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
+ } else {
+ ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
+ destroy_pval(parse_tree); /* free up the memory */
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ destroy_pval(parse_tree); /* free up the memory */
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+/* CLI interface */
+static char *handle_cli_ael_debug_multiple(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ael debug [read|tokens|macros|contexts|off]";
+ e->usage =
+ "Usage: ael debug [read|tokens|macros|contexts|off]\n"
+ " Enable AEL read, token, macro, or context debugging,\n"
+ " or disable all AEL debugging messages. Note: this\n"
+ " currently does nothing.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ if (!strcasecmp(a->argv[2], "read"))
+ aeldebug |= DEBUG_READ;
+ else if (!strcasecmp(a->argv[2], "tokens"))
+ aeldebug |= DEBUG_TOKENS;
+ else if (!strcasecmp(a->argv[2], "macros"))
+ aeldebug |= DEBUG_MACROS;
+ else if (!strcasecmp(a->argv[2], "contexts"))
+ aeldebug |= DEBUG_CONTEXTS;
+ else if (!strcasecmp(a->argv[2], "off"))
+ aeldebug = 0;
+ else
+ return CLI_SHOWUSAGE;
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ael reload";
+ e->usage =
+ "Usage: ael reload\n"
+ " Reloads AEL configuration.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 2)
+ return CLI_SHOWUSAGE;
+
+ return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
+}
+
+static struct ast_cli_entry cli_ael[] = {
+ AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
+ AST_CLI_DEFINE(handle_cli_ael_debug_multiple, "Enable AEL debugging flags")
+};
+
+static int unload_module(void)
+{
+ ast_context_destroy(NULL, registrar);
+ ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
+ return 0;
+}
+
+static int load_module(void)
+{
+ ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
+ return (pbx_load_module());
+}
+
+static int reload(void)
+{
+ return pbx_load_module();
+}
+
+#ifdef STANDALONE_AEL
+#define AST_MODULE "ael"
+int ael_external_load_module(void);
+int ael_external_load_module(void)
+{
+ pbx_load_module();
+ return 1;
+}
+#endif
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
+
+#ifdef AAL_ARGCHECK
+static char *ael_funclist[] =
+{
+ "AGENT",
+ "ARRAY",
+ "BASE64_DECODE",
+ "BASE64_ENCODE",
+ "CALLERID",
+ "CDR",
+ "CHANNEL",
+ "CHECKSIPDOMAIN",
+ "CHECK_MD5",
+ "CURL",
+ "CUT",
+ "DB",
+ "DB_EXISTS",
+ "DUNDILOOKUP",
+ "ENUMLOOKUP",
+ "ENV",
+ "EVAL",
+ "EXISTS",
+ "FIELDQTY",
+ "FILTER",
+ "GROUP",
+ "GROUP_COUNT",
+ "GROUP_LIST",
+ "GROUP_MATCH_COUNT",
+ "IAXPEER",
+ "IF",
+ "IFTIME",
+ "ISNULL",
+ "KEYPADHASH",
+ "LANGUAGE",
+ "LEN",
+ "MATH",
+ "MD5",
+ "MUSICCLASS",
+ "QUEUEAGENTCOUNT",
+ "QUEUE_MEMBER_COUNT",
+ "QUEUE_MEMBER_LIST",
+ "QUOTE",
+ "RAND",
+ "REGEX",
+ "SET",
+ "SHA1",
+ "SIPCHANINFO",
+ "SIPPEER",
+ "SIP_HEADER",
+ "SORT",
+ "STAT",
+ "STRFTIME",
+ "STRPTIME",
+ "TIMEOUT",
+ "TXTCIDNAME",
+ "URIDECODE",
+ "URIENCODE",
+ "VMCOUNT"
+};
+
+
+int ael_is_funcname(char *name)
+{
+ int s,t;
+ t = sizeof(ael_funclist)/sizeof(char*);
+ s = 0;
+ while ((s < t) && strcasecmp(name, ael_funclist[s]))
+ s++;
+ if ( s < t )
+ return 1;
+ else
+ return 0;
+}
+#endif
diff --git a/trunk/pbx/pbx_config.c b/trunk/pbx/pbx_config.c
new file mode 100644
index 000000000..4a7a3d368
--- /dev/null
+++ b/trunk/pbx/pbx_config.c
@@ -0,0 +1,1668 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Populate and remember extensions from static config file
+ *
+ *
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <ctype.h>
+
+#include "asterisk/paths.h" /* ast_config_AST_CONFIG_DIR */
+#include "asterisk/pbx.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/cli.h"
+#include "asterisk/channel.h" /* AST_MAX_EXTENSION */
+#include "asterisk/callerid.h"
+
+static char *config = "extensions.conf";
+static char *registrar = "pbx_config";
+static char userscontext[AST_MAX_EXTENSION] = "default";
+
+static int static_config = 0;
+static int write_protect_config = 1;
+static int autofallthrough_config = 1;
+static int clearglobalvars_config = 0;
+static int extenpatternmatchnew_config = 0;
+
+AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
+
+static struct ast_context *local_contexts = NULL;
+
+/*
+ * Prototypes for our completion functions
+ */
+static char *complete_dialplan_remove_include(struct ast_cli_args *);
+static char *complete_dialplan_add_include(struct ast_cli_args *);
+static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *);
+static char *complete_dialplan_add_ignorepat(struct ast_cli_args *);
+static char *complete_dialplan_remove_extension(struct ast_cli_args *);
+static char *complete_dialplan_add_extension(struct ast_cli_args *);
+
+/*
+ * Implementation of functions provided by this module
+ */
+
+/*!
+ * REMOVE INCLUDE command stuff
+ */
+static char *handle_cli_dialplan_remove_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan remove include";
+ e->usage =
+ "Usage: dialplan remove include <context> from <context>\n"
+ " Remove an included context from another context.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_dialplan_remove_include(a);
+ }
+
+ if (strcmp(a->argv[4], "from"))
+ return CLI_SHOWUSAGE;
+
+ if (!ast_context_remove_include(a->argv[5], a->argv[3], registrar)) {
+ ast_cli(a->fd, "We are not including '%s' into '%s' now\n",
+ a->argv[3], a->argv[5]);
+ return CLI_SUCCESS;
+ }
+
+ ast_cli(a->fd, "Failed to remove '%s' include from '%s' context\n",
+ a->argv[3], a->argv[5]);
+ return CLI_FAILURE;
+}
+
+/*! \brief return true if 'name' is included by context c */
+static int lookup_ci(struct ast_context *c, const char *name)
+{
+ struct ast_include *i = NULL;
+
+ if (ast_rdlock_context(c)) /* error, skip */
+ return 0;
+ while ( (i = ast_walk_context_includes(c, i)) )
+ if (!strcmp(name, ast_get_include_name(i)))
+ break;
+ ast_unlock_context(c);
+ return i ? -1 /* success */ : 0;
+}
+
+/*! \brief return true if 'name' is in the ignorepats for context c */
+static int lookup_c_ip(struct ast_context *c, const char *name)
+{
+ struct ast_ignorepat *ip = NULL;
+
+ if (ast_rdlock_context(c)) /* error, skip */
+ return 0;
+ while ( (ip = ast_walk_context_ignorepats(c, ip)) )
+ if (!strcmp(name, ast_get_ignorepat_name(ip)))
+ break;
+ ast_unlock_context(c);
+ return ip ? -1 /* success */ : 0;
+}
+
+/*! \brief moves to the n-th word in the string, or empty string if none */
+static const char *skip_words(const char *p, int n)
+{
+ int in_blank = 0;
+ for (;n && *p; p++) {
+ if (isblank(*p) /* XXX order is important */ && !in_blank) {
+ n--; /* one word is gone */
+ in_blank = 1;
+ } else if (/* !is_blank(*p), we know already, && */ in_blank) {
+ in_blank = 0;
+ }
+ }
+ return p;
+}
+
+/*! \brief match the first 'len' chars of word. len==0 always succeeds */
+static int partial_match(const char *s, const char *word, int len)
+{
+ return (len == 0 || !strncmp(s, word, len));
+}
+
+/*! \brief split extension\@context in two parts, return -1 on error.
+ * The return string is malloc'ed and pointed by *ext
+ */
+static int split_ec(const char *src, char **ext, char ** const ctx)
+{
+ char *c, *e = ast_strdup(src); /* now src is not used anymore */
+
+ if (e == NULL)
+ return -1; /* malloc error */
+ /* now, parse values from 'exten@context' */
+ *ext = e;
+ c = strchr(e, '@');
+ if (c == NULL) /* no context part */
+ *ctx = ""; /* it is not overwritten, anyways */
+ else { /* found context, check for duplicity ... */
+ *c++ = '\0';
+ *ctx = c;
+ if (strchr(c, '@')) { /* two @, not allowed */
+ free(e);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* _X_ is the string we need to complete */
+static char *complete_dialplan_remove_include(struct ast_cli_args *a)
+{
+ int which = 0;
+ char *res = NULL;
+ int len = strlen(a->word); /* how many bytes to match */
+ struct ast_context *c = NULL;
+
+ if (a->pos == 3) { /* "dialplan remove include _X_" */
+ if (ast_wrlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ return NULL;
+ }
+ /* walk contexts and their includes, return the n-th match */
+ while (!res && (c = ast_walk_contexts(c))) {
+ struct ast_include *i = NULL;
+
+ if (ast_rdlock_context(c)) /* error ? skip this one */
+ continue;
+
+ while ( !res && (i = ast_walk_context_includes(c, i)) ) {
+ const char *i_name = ast_get_include_name(i);
+ struct ast_context *nc = NULL;
+ int already_served = 0;
+
+ if (!partial_match(i_name, a->word, len))
+ continue; /* not matched */
+
+ /* check if this include is already served or not */
+
+ /* go through all contexts again till we reach actual
+ * context or already_served = 1
+ */
+ while ( (nc = ast_walk_contexts(nc)) && nc != c && !already_served)
+ already_served = lookup_ci(nc, i_name);
+
+ if (!already_served && ++which > a->n)
+ res = strdup(i_name);
+ }
+ ast_unlock_context(c);
+ }
+
+ ast_unlock_contexts();
+ return res;
+ } else if (a->pos == 4) { /* "dialplan remove include CTX _X_" */
+ /*
+ * complete as 'from', but only if previous context is really
+ * included somewhere
+ */
+ char *context, *dupline;
+ const char *s = skip_words(a->line, 3); /* skip 'dialplan' 'remove' 'include' */
+
+ if (a->n > 0)
+ return NULL;
+ context = dupline = strdup(s);
+ if (!dupline) {
+ ast_log(LOG_ERROR, "Out of free memory\n");
+ return NULL;
+ }
+ strsep(&dupline, " ");
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock contexts list\n");
+ free(context);
+ return NULL;
+ }
+
+ /* go through all contexts and check if is included ... */
+ while (!res && (c = ast_walk_contexts(c)))
+ if (lookup_ci(c, context)) /* context is really included, complete "from" command */
+ res = strdup("from");
+ ast_unlock_contexts();
+ if (!res)
+ ast_log(LOG_WARNING, "%s not included anywhere\n", context);
+ free(context);
+ return res;
+ } else if (a->pos == 5) { /* "dialplan remove include CTX from _X_" */
+ /*
+ * Context from which we removing include ...
+ */
+ char *context, *dupline, *from;
+ const char *s = skip_words(a->line, 3); /* skip 'dialplan' 'remove' 'include' */
+ context = dupline = strdup(s);
+ if (!dupline) {
+ ast_log(LOG_ERROR, "Out of free memory\n");
+ return NULL;
+ }
+
+ strsep(&dupline, " "); /* skip context */
+
+ /* fourth word must be 'from' */
+ from = strsep(&dupline, " ");
+ if (!from || strcmp(from, "from")) {
+ free(context);
+ return NULL;
+ }
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ free(context);
+ return NULL;
+ }
+
+ /* walk through all contexts ... */
+ c = NULL;
+ while ( !res && (c = ast_walk_contexts(c))) {
+ const char *c_name = ast_get_context_name(c);
+ if (!partial_match(c_name, a->word, len)) /* not a good target */
+ continue;
+ /* walk through all includes and check if it is our context */
+ if (lookup_ci(c, context) && ++which > a->n)
+ res = strdup(c_name);
+ }
+ ast_unlock_contexts();
+ free(context);
+ return res;
+ }
+
+ return NULL;
+}
+
+/*!
+ * REMOVE EXTENSION command stuff
+ */
+static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int removing_priority = 0;
+ char *exten, *context;
+ char *ret = CLI_FAILURE;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan remove extension";
+ e->usage =
+ "Usage: dialplan remove extension exten@context [priority]\n"
+ " Remove an extension from a given context. If a priority\n"
+ " is given, only that specific priority from the given extension\n"
+ " will be removed.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_dialplan_remove_extension(a);
+ }
+
+ if (a->argc != 5 && a->argc != 4)
+ return CLI_SHOWUSAGE;
+
+ /*
+ * Priority input checking ...
+ */
+ if (a->argc == 5) {
+ char *c = a->argv[4];
+
+ /* check for digits in whole parameter for right priority ...
+ * why? because atoi (strtol) returns 0 if any characters in
+ * string and whole extension will be removed, it's not good
+ */
+ if (!strcmp("hint", c))
+ removing_priority = PRIORITY_HINT;
+ else {
+ while (*c && isdigit(*c))
+ c++;
+ if (*c) { /* non-digit in string */
+ ast_cli(a->fd, "Invalid priority '%s'\n", a->argv[4]);
+ return CLI_FAILURE;
+ }
+ removing_priority = atoi(a->argv[4]);
+ }
+
+ if (removing_priority == 0) {
+ ast_cli(a->fd, "If you want to remove whole extension, please " \
+ "omit priority argument\n");
+ return CLI_FAILURE;
+ }
+ }
+
+ /* XXX original overwrote argv[3] */
+ /*
+ * Format exten@context checking ...
+ */
+ if (split_ec(a->argv[3], &exten, &context))
+ return CLI_FAILURE; /* XXX malloc failure */
+ if ((!strlen(exten)) || (!(strlen(context)))) {
+ ast_cli(a->fd, "Missing extension or context name in third argument '%s'\n",
+ a->argv[3]);
+ free(exten);
+ return CLI_FAILURE;
+ }
+
+ if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) {
+ if (!removing_priority)
+ ast_cli(a->fd, "Whole extension %s@%s removed\n",
+ exten, context);
+ else
+ ast_cli(a->fd, "Extension %s@%s with priority %d removed\n",
+ exten, context, removing_priority);
+
+ ret = CLI_SUCCESS;
+ } else {
+ ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context);
+ ret = CLI_FAILURE;
+ }
+ free(exten);
+ return ret;
+}
+
+#define BROKEN_READLINE 1
+
+#ifdef BROKEN_READLINE
+/*
+ * There is one funny thing, when you have word like 300@ and you hit
+ * <tab>, you arguments will like as your word is '300 ', so it '@'
+ * characters acts sometimes as word delimiter and sometimes as a part
+ * of word
+ *
+ * This fix function, allocates new word variable and store here every
+ * time xxx@yyy always as one word and correct pos is set too
+ *
+ * It's ugly, I know, but I'm waiting for Mark suggestion if upper is
+ * bug or feature ...
+ */
+static int fix_complete_args(const char *line, char **word, int *pos)
+{
+ char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL;
+ int words = 0;
+
+ _line = strdup(line);
+
+ _strsep_line = _line;
+ while (_strsep_line) {
+ _previous_word = _word;
+ _word = strsep(&_strsep_line, " ");
+
+ if (_word && strlen(_word)) words++;
+ }
+
+
+ if (_word || _previous_word) {
+ if (_word) {
+ if (!strlen(_word)) words++;
+ *word = strdup(_word);
+ } else
+ *word = strdup(_previous_word);
+ *pos = words - 1;
+ free(_line);
+ return 0;
+ }
+
+ free(_line);
+ return -1;
+}
+#endif /* BROKEN_READLINE */
+
+static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
+{
+ char *ret = NULL;
+ int which = 0;
+
+#ifdef BROKEN_READLINE
+ char *word2;
+ /*
+ * Fix arguments, *word is a new allocated structure, REMEMBER to
+ * free *word when you want to return from this function ...
+ */
+ if (fix_complete_args(a->line, &word2, &a->pos)) {
+ ast_log(LOG_ERROR, "Out of free memory\n");
+ return NULL;
+ }
+ a->word = word2;
+#endif
+
+ if (a->pos == 3) { /* 'dialplan remove extension _X_' (exten@context ... */
+ struct ast_context *c = NULL;
+ char *context = NULL, *exten = NULL;
+ int le = 0; /* length of extension */
+ int lc = 0; /* length of context */
+
+ lc = split_ec(a->word, &exten, &context);
+#ifdef BROKEN_READLINE
+ free(word2);
+#endif
+ if (lc) /* error */
+ return NULL;
+ le = strlen(exten);
+ lc = strlen(context);
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ goto error2;
+ }
+
+ /* find our context ... */
+ while ( (c = ast_walk_contexts(c)) ) { /* match our context if any */
+ struct ast_exten *e = NULL;
+ /* XXX locking ? */
+ if (!partial_match(ast_get_context_name(c), context, lc))
+ continue; /* context not matched */
+ while ( (e = ast_walk_context_extensions(c, e)) ) { /* try to complete extensions ... */
+ if ( partial_match(ast_get_extension_name(e), exten, le) && ++which > a->n) { /* n-th match */
+ /* If there is an extension then return exten@context. XXX otherwise ? */
+ if (exten)
+ asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
+ break;
+ }
+ }
+ if (e) /* got a match */
+ break;
+ }
+
+ ast_unlock_contexts();
+ error2:
+ if (exten)
+ free(exten);
+ } else if (a->pos == 4) { /* 'dialplan remove extension EXT _X_' (priority) */
+ char *exten = NULL, *context, *p;
+ struct ast_context *c;
+ int le, lc, len;
+ const char *s = skip_words(a->line, 3); /* skip 'dialplan' 'remove' 'extension' */
+ int i = split_ec(s, &exten, &context); /* parse ext@context */
+
+ if (i) /* error */
+ goto error3;
+ if ( (p = strchr(exten, ' ')) ) /* remove space after extension */
+ *p = '\0';
+ if ( (p = strchr(context, ' ')) ) /* remove space after context */
+ *p = '\0';
+ le = strlen(exten);
+ lc = strlen(context);
+ len = strlen(a->word);
+ if (le == 0 || lc == 0)
+ goto error3;
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ goto error3;
+ }
+
+ /* walk contexts */
+ c = NULL;
+ while ( (c = ast_walk_contexts(c)) ) {
+ /* XXX locking on c ? */
+ struct ast_exten *e;
+ if (strcmp(ast_get_context_name(c), context) != 0)
+ continue;
+ /* got it, we must match here */
+ e = NULL;
+ while ( (e = ast_walk_context_extensions(c, e)) ) {
+ struct ast_exten *priority;
+ char buffer[10];
+
+ if (strcmp(ast_get_extension_name(e), exten) != 0)
+ continue;
+ /* XXX lock e ? */
+ priority = NULL;
+ while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
+ snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority));
+ if (partial_match(buffer, a->word, len) && ++which > a->n) /* n-th match */
+ ret = strdup(buffer);
+ }
+ break;
+ }
+ break;
+ }
+ ast_unlock_contexts();
+ error3:
+ if (exten)
+ free(exten);
+#ifdef BROKEN_READLINE
+ free(word2);
+#endif
+ }
+ return ret;
+}
+
+/*!
+ * Include context ...
+ */
+static char *handle_cli_dialplan_add_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan add include";
+ e->usage =
+ "Usage: dialplan add include <context> into <context>\n"
+ " Include a context in another context.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_dialplan_add_include(a);
+ }
+
+ if (a->argc != 6) /* dialplan add include CTX in CTX */
+ return CLI_SHOWUSAGE;
+
+ /* fifth arg must be 'into' ... */
+ if (strcmp(a->argv[4], "into"))
+ return CLI_SHOWUSAGE;
+
+ if (ast_context_add_include(a->argv[5], a->argv[3], registrar)) {
+ switch (errno) {
+ case ENOMEM:
+ ast_cli(a->fd, "Out of memory for context addition\n");
+ break;
+
+ case EBUSY:
+ ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
+ break;
+
+ case EEXIST:
+ ast_cli(a->fd, "Context '%s' already included in '%s' context\n",
+ a->argv[3], a->argv[5]);
+ break;
+
+ case ENOENT:
+ case EINVAL:
+ ast_cli(a->fd, "There is no existence of context '%s'\n",
+ errno == ENOENT ? a->argv[5] : a->argv[3]);
+ break;
+
+ default:
+ ast_cli(a->fd, "Failed to include '%s' in '%s' context\n",
+ a->argv[3], a->argv[5]);
+ break;
+ }
+ return CLI_FAILURE;
+ }
+
+ /* show some info ... */
+ ast_cli(a->fd, "Context '%s' included in '%s' context\n",
+ a->argv[3], a->argv[5]);
+
+ return CLI_SUCCESS;
+}
+
+static char *complete_dialplan_add_include(struct ast_cli_args *a)
+{
+ struct ast_context *c;
+ int which = 0;
+ char *ret = NULL;
+ int len = strlen(a->word);
+
+ if (a->pos == 3) { /* 'dialplan add include _X_' (context) ... */
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ return NULL;
+ }
+ for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
+ if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n)
+ ret = strdup(ast_get_context_name(c));
+ ast_unlock_contexts();
+ return ret;
+ } else if (a->pos == 4) { /* dialplan add include CTX _X_ */
+ /* complete as 'into' if context exists or we are unable to check */
+ char *context, *dupline;
+ struct ast_context *c;
+ const char *s = skip_words(a->line, 3); /* should not fail */
+
+ if (a->n != 0) /* only once */
+ return NULL;
+
+ /* parse context from line ... */
+ context = dupline = strdup(s);
+ if (!context) {
+ ast_log(LOG_ERROR, "Out of free memory\n");
+ return strdup("into");
+ }
+ strsep(&dupline, " ");
+
+ /* check for context existence ... */
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ /* our fault, we can't check, so complete 'into' ... */
+ ret = strdup("into");
+ } else {
+ for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
+ if (!strcmp(context, ast_get_context_name(c)))
+ ret = strdup("into"); /* found */
+ ast_unlock_contexts();
+ }
+ free(context);
+ return ret;
+ } else if (a->pos == 5) { /* 'dialplan add include CTX into _X_' (dst context) */
+ char *context, *dupline, *into;
+ const char *s = skip_words(a->line, 3); /* should not fail */
+ context = dupline = strdup(s);
+ if (!dupline) {
+ ast_log(LOG_ERROR, "Out of free memory\n");
+ return NULL;
+ }
+ strsep(&dupline, " "); /* skip context */
+ into = strsep(&dupline, " ");
+ /* error if missing context or fifth word is not 'into' */
+ if (!strlen(context) || strcmp(into, "into")) {
+ ast_log(LOG_ERROR, "bad context %s or missing into %s\n",
+ context, into);
+ goto error3;
+ }
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock context list\n");
+ goto error3;
+ }
+
+ for (c = NULL; (c = ast_walk_contexts(c)); )
+ if (!strcmp(context, ast_get_context_name(c)))
+ break;
+ if (c) { /* first context exists, go on... */
+ /* go through all contexts ... */
+ for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
+ if (!strcmp(context, ast_get_context_name(c)))
+ continue; /* skip ourselves */
+ if (partial_match(ast_get_context_name(c), a->word, len) &&
+ !lookup_ci(c, context) /* not included yet */ &&
+ ++which > a->n)
+ ret = strdup(ast_get_context_name(c));
+ }
+ } else {
+ ast_log(LOG_ERROR, "context %s not found\n", context);
+ }
+ ast_unlock_contexts();
+ error3:
+ free(context);
+ return ret;
+ }
+
+ return NULL;
+}
+
+/*!
+ * \brief 'save dialplan' CLI command implementation functions ...
+ */
+static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char filename[256];
+ struct ast_context *c;
+ struct ast_config *cfg;
+ struct ast_variable *v;
+ int incomplete = 0; /* incomplete config write? */
+ FILE *output;
+ struct ast_flags config_flags = { 0 };
+ const char *base, *slash, *file;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan save";
+ e->usage =
+ "Usage: dialplan save [/path/to/extension/file]\n"
+ " Save dialplan created by pbx_config module.\n"
+ "\n"
+ "Example: dialplan save (/etc/asterisk/extensions.conf)\n"
+ " dialplan save /home/markster (/home/markster/extensions.conf)\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (! (static_config && !write_protect_config)) {
+ ast_cli(a->fd,
+ "I can't save dialplan now, see '%s' example file.\n",
+ config);
+ return CLI_FAILURE;
+ }
+
+ if (a->argc != 2 && a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ if (ast_mutex_lock(&save_dialplan_lock)) {
+ ast_cli(a->fd,
+ "Failed to lock dialplan saving (another proccess saving?)\n");
+ return CLI_FAILURE;
+ }
+ /* XXX the code here is quite loose, a pathname with .conf in it
+ * is assumed to be a complete pathname
+ */
+ if (a->argc == 3) { /* have config path. Look for *.conf */
+ base = a->argv[2];
+ if (!strstr(a->argv[2], ".conf")) { /*no, this is assumed to be a pathname */
+ /* if filename ends with '/', do not add one */
+ slash = (*(a->argv[2] + strlen(a->argv[2]) -1) == '/') ? "/" : "";
+ file = config; /* default: 'extensions.conf' */
+ } else { /* yes, complete file name */
+ slash = "";
+ file = "";
+ }
+ } else {
+ /* no config file, default one */
+ base = ast_config_AST_CONFIG_DIR;
+ slash = "/";
+ file = config;
+ }
+ snprintf(filename, sizeof(filename), "%s%s%s", base, slash, config);
+
+ cfg = ast_config_load("extensions.conf", config_flags);
+
+ /* try to lock contexts list */
+ if (ast_rdlock_contexts()) {
+ ast_cli(a->fd, "Failed to lock contexts list\n");
+ ast_mutex_unlock(&save_dialplan_lock);
+ ast_config_destroy(cfg);
+ return CLI_FAILURE;
+ }
+
+ /* create new file ... */
+ if (!(output = fopen(filename, "wt"))) {
+ ast_cli(a->fd, "Failed to create file '%s'\n",
+ filename);
+ ast_unlock_contexts();
+ ast_mutex_unlock(&save_dialplan_lock);
+ ast_config_destroy(cfg);
+ return CLI_FAILURE;
+ }
+
+ /* fireout general info */
+ fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\nextenpatternmatchnew=%s\n\n",
+ static_config ? "yes" : "no",
+ write_protect_config ? "yes" : "no",
+ autofallthrough_config ? "yes" : "no",
+ clearglobalvars_config ? "yes" : "no",
+ extenpatternmatchnew_config ? "yes" : "no");
+
+ if ((v = ast_variable_browse(cfg, "globals"))) {
+ fprintf(output, "[globals]\n");
+ while(v) {
+ fprintf(output, "%s => %s\n", v->name, v->value);
+ v = v->next;
+ }
+ fprintf(output, "\n");
+ }
+
+ ast_config_destroy(cfg);
+
+#define PUT_CTX_HDR do { \
+ if (!context_header_written) { \
+ fprintf(output, "[%s]\n", ast_get_context_name(c)); \
+ context_header_written = 1; \
+ } \
+ } while (0)
+
+ /* walk all contexts */
+ for (c = NULL; (c = ast_walk_contexts(c)); ) {
+ int context_header_written = 0;
+ struct ast_exten *e, *last_written_e = NULL;
+ struct ast_include *i;
+ struct ast_ignorepat *ip;
+ struct ast_sw *sw;
+
+ /* try to lock context and fireout all info */
+ if (ast_rdlock_context(c)) { /* lock failure */
+ incomplete = 1;
+ continue;
+ }
+ /* registered by this module? */
+ /* XXX do we need this ? */
+ if (!strcmp(ast_get_context_registrar(c), registrar)) {
+ fprintf(output, "[%s]\n", ast_get_context_name(c));
+ context_header_written = 1;
+ }
+
+ /* walk extensions ... */
+ for (e = NULL; (e = ast_walk_context_extensions(c, e)); ) {
+ struct ast_exten *p = NULL;
+
+ /* fireout priorities */
+ while ( (p = ast_walk_extension_priorities(e, p)) ) {
+ if (strcmp(ast_get_extension_registrar(p), registrar) != 0) /* not this source */
+ continue;
+
+ /* make empty line between different extensions */
+ if (last_written_e != NULL &&
+ strcmp(ast_get_extension_name(last_written_e),
+ ast_get_extension_name(p)))
+ fprintf(output, "\n");
+ last_written_e = p;
+
+ PUT_CTX_HDR;
+
+ if (ast_get_extension_priority(p) == PRIORITY_HINT) { /* easy */
+ fprintf(output, "exten => %s,hint,%s\n",
+ ast_get_extension_name(p),
+ ast_get_extension_app(p));
+ } else {
+ const char *sep, *cid;
+ const char *el = ast_get_extension_label(p);
+ char label[128] = "";
+
+ if (ast_get_extension_matchcid(p)) {
+ sep = "/";
+ cid = ast_get_extension_cidmatch(p);
+ } else
+ sep = cid = "";
+
+ if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
+ incomplete = 1; /* error encountered or label > 125 chars */
+
+ fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
+ ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
+ ast_get_extension_priority(p), label,
+ ast_get_extension_app(p), (ast_strlen_zero(ast_get_extension_app_data(p)) ? "" : (const char *)ast_get_extension_app_data(p)));
+ }
+ }
+ }
+
+ /* written any extensions? ok, write space between exten & inc */
+ if (last_written_e)
+ fprintf(output, "\n");
+
+ /* walk through includes */
+ for (i = NULL; (i = ast_walk_context_includes(c, i)) ; ) {
+ if (strcmp(ast_get_include_registrar(i), registrar) != 0)
+ continue; /* not mine */
+ PUT_CTX_HDR;
+ fprintf(output, "include => %s\n", ast_get_include_name(i));
+ }
+ if (ast_walk_context_includes(c, NULL))
+ fprintf(output, "\n");
+
+ /* walk through switches */
+ for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) {
+ if (strcmp(ast_get_switch_registrar(sw), registrar) != 0)
+ continue; /* not mine */
+ PUT_CTX_HDR;
+ fprintf(output, "switch => %s/%s\n",
+ ast_get_switch_name(sw), ast_get_switch_data(sw));
+ }
+
+ if (ast_walk_context_switches(c, NULL))
+ fprintf(output, "\n");
+
+ /* fireout ignorepats ... */
+ for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) {
+ if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0)
+ continue; /* not mine */
+ PUT_CTX_HDR;
+ fprintf(output, "ignorepat => %s\n",
+ ast_get_ignorepat_name(ip));
+ }
+
+ ast_unlock_context(c);
+ }
+
+ ast_unlock_contexts();
+ ast_mutex_unlock(&save_dialplan_lock);
+ fclose(output);
+
+ if (incomplete) {
+ ast_cli(a->fd, "Saved dialplan is incomplete\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "Dialplan successfully saved into '%s'\n",
+ filename);
+ return CLI_SUCCESS;
+}
+
+/*!
+ * \brief ADD EXTENSION command stuff
+ */
+static char *handle_cli_dialplan_add_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char *whole_exten;
+ char *exten, *prior;
+ int iprior = -2;
+ char *cidmatch, *app, *app_data;
+ char *start, *end;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan add extension";
+ e->usage =
+ "Usage: dialplan add extension <exten>,<priority>,<app>,<app-data>\n"
+ " into <context> [replace]\n\n"
+ " This command will add new extension into <context>. If there is an\n"
+ " existence of extension with the same priority and last 'replace'\n"
+ " arguments is given here we simply replace this extension.\n"
+ "\n"
+ "Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
+ " Now, you can dial 6123 and talk to Markster :)\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_dialplan_add_extension(a);
+ }
+
+ /* check for arguments at first */
+ if (a->argc != 6 && a->argc != 7)
+ return CLI_SHOWUSAGE;
+ if (strcmp(a->argv[4], "into"))
+ return CLI_SHOWUSAGE;
+ if (a->argc == 7)
+ if (strcmp(a->argv[6], "replace"))
+ return CLI_SHOWUSAGE;
+
+ /* XXX overwrite argv[3] */
+ whole_exten = a->argv[3];
+ exten = strsep(&whole_exten,",");
+ if (strchr(exten, '/')) {
+ cidmatch = exten;
+ strsep(&cidmatch,"/");
+ } else {
+ cidmatch = NULL;
+ }
+ prior = strsep(&whole_exten,",");
+ if (prior) {
+ if (!strcmp(prior, "hint")) {
+ iprior = PRIORITY_HINT;
+ } else {
+ if (sscanf(prior, "%d", &iprior) != 1) {
+ ast_cli(a->fd, "'%s' is not a valid priority\n", prior);
+ prior = NULL;
+ }
+ }
+ }
+ app = whole_exten;
+ if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
+ *start = *end = '\0';
+ app_data = start + 1;
+ } else {
+ if (app) {
+ app_data = strchr(app, ',');
+ if (app_data) {
+ *app_data = '\0';
+ app_data++;
+ }
+ } else
+ app_data = NULL;
+ }
+
+ if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT))
+ return CLI_SHOWUSAGE;
+
+ if (!app_data)
+ app_data="";
+ if (ast_add_extension(a->argv[5], a->argc == 7 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
+ (void *)strdup(app_data), ast_free_ptr, registrar)) {
+ switch (errno) {
+ case ENOMEM:
+ ast_cli(a->fd, "Out of free memory\n");
+ break;
+
+ case EBUSY:
+ ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
+ break;
+
+ case ENOENT:
+ ast_cli(a->fd, "No existence of '%s' context\n", a->argv[5]);
+ break;
+
+ case EEXIST:
+ ast_cli(a->fd, "Extension %s@%s with priority %s already exists\n",
+ exten, a->argv[5], prior);
+ break;
+
+ default:
+ ast_cli(a->fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
+ exten, prior, app, app_data, a->argv[5]);
+ break;
+ }
+ return CLI_FAILURE;
+ }
+
+ if (a->argc == 7)
+ ast_cli(a->fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
+ exten, a->argv[5], prior, exten, prior, app, app_data);
+ else
+ ast_cli(a->fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
+ exten, prior, app, app_data, a->argv[5]);
+
+ return CLI_SUCCESS;
+}
+
+/*! dialplan add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
+static char *complete_dialplan_add_extension(struct ast_cli_args *a)
+{
+ int which = 0;
+
+ if (a->pos == 4) { /* complete 'into' word ... */
+ return (a->n == 0) ? strdup("into") : NULL;
+ } else if (a->pos == 5) { /* complete context */
+ struct ast_context *c = NULL;
+ int len = strlen(a->word);
+ char *res = NULL;
+
+ /* try to lock contexts list ... */
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_WARNING, "Failed to lock contexts list\n");
+ return NULL;
+ }
+
+ /* walk through all contexts */
+ while ( !res && (c = ast_walk_contexts(c)) )
+ if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n)
+ res = strdup(ast_get_context_name(c));
+ ast_unlock_contexts();
+ return res;
+ } else if (a->pos == 6) {
+ return a->n == 0 ? strdup("replace") : NULL;
+ }
+ return NULL;
+}
+
+/*!
+ * IGNOREPAT CLI stuff
+ */
+static char *handle_cli_dialplan_add_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan add ignorepat";
+ e->usage =
+ "Usage: dialplan add ignorepat <pattern> into <context>\n"
+ " This command adds a new ignore pattern into context <context>\n"
+ "\n"
+ "Example: dialplan add ignorepat _3XX into local\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_dialplan_add_ignorepat(a);
+ }
+
+ if (a->argc != 6)
+ return CLI_SHOWUSAGE;
+
+ if (strcmp(a->argv[4], "into"))
+ return CLI_SHOWUSAGE;
+
+ if (ast_context_add_ignorepat(a->argv[5], a->argv[3], registrar)) {
+ switch (errno) {
+ case ENOMEM:
+ ast_cli(a->fd, "Out of free memory\n");
+ break;
+
+ case ENOENT:
+ ast_cli(a->fd, "There is no existence of '%s' context\n", a->argv[5]);
+ break;
+
+ case EEXIST:
+ ast_cli(a->fd, "Ignore pattern '%s' already included in '%s' context\n",
+ a->argv[3], a->argv[5]);
+ break;
+
+ case EBUSY:
+ ast_cli(a->fd, "Failed to lock context(s) list, please, try again later\n");
+ break;
+
+ default:
+ ast_cli(a->fd, "Failed to add ingore pattern '%s' into '%s' context\n",
+ a->argv[3], a->argv[5]);
+ break;
+ }
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "Ignore pattern '%s' added into '%s' context\n",
+ a->argv[3], a->argv[5]);
+
+ return CLI_SUCCESS;
+}
+
+static char *complete_dialplan_add_ignorepat(struct ast_cli_args *a)
+{
+ if (a->pos == 4)
+ return a->n == 0 ? strdup("into") : NULL;
+ else if (a->pos == 5) {
+ struct ast_context *c;
+ int which = 0;
+ char *dupline, *ignorepat = NULL;
+ const char *s;
+ char *ret = NULL;
+ int len = strlen(a->word);
+
+ /* XXX skip first three words 'dialplan' 'add' 'ignorepat' */
+ s = skip_words(a->line, 3);
+ if (s == NULL)
+ return NULL;
+ dupline = strdup(s);
+ if (!dupline) {
+ ast_log(LOG_ERROR, "Malloc failure\n");
+ return NULL;
+ }
+ ignorepat = strsep(&dupline, " ");
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_ERROR, "Failed to lock contexts list\n");
+ return NULL;
+ }
+
+ for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
+ int found = 0;
+
+ if (!partial_match(ast_get_context_name(c), a->word, len))
+ continue; /* not mine */
+ if (ignorepat) /* there must be one, right ? */
+ found = lookup_c_ip(c, ignorepat);
+ if (!found && ++which > a->n)
+ ret = strdup(ast_get_context_name(c));
+ }
+
+ if (ignorepat)
+ free(ignorepat);
+ ast_unlock_contexts();
+ return ret;
+ }
+
+ return NULL;
+}
+
+static char *handle_cli_dialplan_remove_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan remove ignorepat";
+ e->usage =
+ "Usage: dialplan remove ignorepat <pattern> from <context>\n"
+ " This command removes an ignore pattern from context <context>\n"
+ "\n"
+ "Example: dialplan remove ignorepat _3XX from local\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_dialplan_remove_ignorepat(a);
+ }
+
+ if (a->argc != 6)
+ return CLI_SHOWUSAGE;
+
+ if (strcmp(a->argv[4], "from"))
+ return CLI_SHOWUSAGE;
+
+ if (ast_context_remove_ignorepat(a->argv[5], a->argv[3], registrar)) {
+ switch (errno) {
+ case EBUSY:
+ ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
+ break;
+
+ case ENOENT:
+ ast_cli(a->fd, "There is no existence of '%s' context\n", a->argv[5]);
+ break;
+
+ case EINVAL:
+ ast_cli(a->fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
+ a->argv[3], a->argv[5]);
+ break;
+
+ default:
+ ast_cli(a->fd, "Failed to remove ignore pattern '%s' from '%s' context\n",
+ a->argv[3], a->argv[5]);
+ break;
+ }
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "Ignore pattern '%s' removed from '%s' context\n",
+ a->argv[3], a->argv[5]);
+ return CLI_SUCCESS;
+}
+
+static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *a)
+{
+ struct ast_context *c;
+ int which = 0;
+ char *ret = NULL;
+
+ if (a->pos == 3) {
+ int len = strlen(a->word);
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_WARNING, "Failed to lock contexts list\n");
+ return NULL;
+ }
+
+ for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
+ struct ast_ignorepat *ip;
+
+ if (ast_rdlock_context(c)) /* error, skip it */
+ continue;
+
+ for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) {
+ if (partial_match(ast_get_ignorepat_name(ip), a->word, len) && ++which > a->n) {
+ /* n-th match */
+ struct ast_context *cw = NULL;
+ int found = 0;
+ while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
+ /* XXX do i stop on c, or skip it ? */
+ found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
+ }
+ if (!found)
+ ret = strdup(ast_get_ignorepat_name(ip));
+ }
+ }
+ ast_unlock_context(c);
+ }
+ ast_unlock_contexts();
+ return ret;
+ } else if (a->pos == 4) {
+ return a->n == 0 ? strdup("from") : NULL;
+ } else if (a->pos == 5) { /* XXX check this */
+ char *dupline, *duplinet, *ignorepat;
+ int len = strlen(a->word);
+
+ dupline = strdup(a->line);
+ if (!dupline) {
+ ast_log(LOG_WARNING, "Out of free memory\n");
+ return NULL;
+ }
+
+ duplinet = dupline;
+ strsep(&duplinet, " ");
+ strsep(&duplinet, " ");
+ ignorepat = strsep(&duplinet, " ");
+
+ if (!ignorepat) {
+ free(dupline);
+ return NULL;
+ }
+
+ if (ast_rdlock_contexts()) {
+ ast_log(LOG_WARNING, "Failed to lock contexts list\n");
+ free(dupline);
+ return NULL;
+ }
+
+ for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
+ if (ast_rdlock_context(c)) /* fail, skip it */
+ continue;
+ if (!partial_match(ast_get_context_name(c), a->word, len))
+ continue;
+ if (lookup_c_ip(c, ignorepat) && ++which > a->n)
+ ret = strdup(ast_get_context_name(c));
+ ast_unlock_context(c);
+ }
+ ast_unlock_contexts();
+ free(dupline);
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static int pbx_load_module(void);
+
+static char *handle_cli_dialplan_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dialplan reload";
+ e->usage =
+ "Usage: dialplan reload\n"
+ " Reload extensions.conf without reloading any other\n"
+ " modules. This command does not delete global variables\n"
+ " unless clearglobalvars is set to yes in extensions.conf\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 2)
+ return CLI_SHOWUSAGE;
+
+ if (clearglobalvars_config)
+ pbx_builtin_clear_globals();
+
+ pbx_load_module();
+
+ return CLI_SUCCESS;
+}
+
+/*!
+ * CLI entries for commands provided by this module
+ */
+static struct ast_cli_entry cli_pbx_config[] = {
+ AST_CLI_DEFINE(handle_cli_dialplan_add_extension, "Add new extension into context"),
+ AST_CLI_DEFINE(handle_cli_dialplan_remove_extension, "Remove a specified extension"),
+ AST_CLI_DEFINE(handle_cli_dialplan_add_ignorepat, "Add new ignore pattern"),
+ AST_CLI_DEFINE(handle_cli_dialplan_remove_ignorepat, "Remove ignore pattern from context"),
+ AST_CLI_DEFINE(handle_cli_dialplan_add_include, "Include context in other context"),
+ AST_CLI_DEFINE(handle_cli_dialplan_remove_include, "Remove a specified include from context"),
+ AST_CLI_DEFINE(handle_cli_dialplan_reload, "Reload extensions and *only* extensions")
+};
+
+static struct ast_cli_entry cli_dialplan_save =
+ AST_CLI_DEFINE(handle_cli_dialplan_save, "Save dialplan");
+
+/*!
+ * Standard module functions ...
+ */
+static int unload_module(void)
+{
+ if (static_config && !write_protect_config)
+ ast_cli_unregister(&cli_dialplan_save);
+ ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
+ ast_context_destroy(NULL, registrar);
+ return 0;
+}
+
+static int pbx_load_config(const char *config_file)
+{
+ struct ast_config *cfg;
+ char *end;
+ char *label;
+ char realvalue[256];
+ int lastpri = -2;
+ struct ast_context *con;
+ struct ast_variable *v;
+ const char *cxt;
+ const char *aft;
+ const char *newpm;
+ struct ast_flags config_flags = { 0 };
+
+ cfg = ast_config_load(config_file, config_flags);
+ if (!cfg)
+ return 0;
+
+ /* Use existing config to populate the PBX table */
+ static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
+ write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
+ if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
+ autofallthrough_config = ast_true(aft);
+ if ((newpm = ast_variable_retrieve(cfg, "general", "extenpatternmatchnew")))
+ extenpatternmatchnew_config = ast_true(newpm);
+ clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
+
+
+ if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
+ ast_copy_string(userscontext, cxt, sizeof(userscontext));
+ else
+ ast_copy_string(userscontext, "default", sizeof(userscontext));
+
+ for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
+ pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
+ pbx_builtin_setvar_helper(NULL, v->name, realvalue);
+ }
+ for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
+ /* All categories but "general" or "globals" are considered contexts */
+ if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
+ continue;
+ con=ast_context_find_or_create(&local_contexts,cxt, registrar);
+ if (con == NULL)
+ continue;
+
+ for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
+ if (!strcasecmp(v->name, "exten")) {
+ char *tc = ast_strdup(v->value);
+ if (tc) {
+ int ipri = -2;
+ char realext[256]="";
+ char *plus, *firstp;
+ char *pri, *appl, *data, *cidmatch;
+ char *stringp = tc;
+ char *ext = strsep(&stringp, ",");
+ if (!ext)
+ ext="";
+ pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
+ cidmatch = strchr(realext, '/');
+ if (cidmatch) {
+ *cidmatch++ = '\0';
+ ast_shrink_phone_number(cidmatch);
+ }
+ pri = strsep(&stringp, ",");
+ if (!pri)
+ pri="";
+ pri = ast_skip_blanks(pri);
+ pri = ast_trim_blanks(pri);
+ label = strchr(pri, '(');
+ if (label) {
+ *label++ = '\0';
+ end = strchr(label, ')');
+ if (end)
+ *end = '\0';
+ else
+ ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
+ }
+ plus = strchr(pri, '+');
+ if (plus)
+ *plus++ = '\0';
+ if (!strcmp(pri,"hint"))
+ ipri=PRIORITY_HINT;
+ else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
+ if (lastpri > -2)
+ ipri = lastpri + 1;
+ else
+ ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
+ } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
+ if (lastpri > -2)
+ ipri = lastpri;
+ else
+ ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
+ } else if (sscanf(pri, "%d", &ipri) != 1 &&
+ (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
+ ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
+ ipri = 0;
+ }
+ appl = S_OR(stringp, "");
+ /* Find the first occurrence of '(' */
+ firstp = strchr(appl, '(');
+ if (!firstp) {
+ /* No arguments */
+ data = "";
+ } else {
+ appl = strsep(&stringp, "(");
+ data = stringp;
+ end = strrchr(data, ')');
+ if ((end = strrchr(data, ')'))) {
+ *end = '\0';
+ } else {
+ ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
+ }
+ }
+
+ if (!data)
+ data = "";
+ appl = ast_skip_blanks(appl);
+ if (ipri) {
+ if (plus)
+ ipri += atoi(plus);
+ lastpri = ipri;
+ if (!ast_opt_dont_warn && !strcmp(realext, "_."))
+ ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno);
+ if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, registrar)) {
+ ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
+ }
+ }
+ free(tc);
+ }
+ } else if (!strcasecmp(v->name, "include")) {
+ pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
+ if (ast_context_add_include2(con, realvalue, registrar))
+ ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
+ } else if (!strcasecmp(v->name, "ignorepat")) {
+ pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
+ if (ast_context_add_ignorepat2(con, realvalue, registrar))
+ ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
+ } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
+ char *stringp = realvalue;
+ char *appl, *data;
+
+ if (!strcasecmp(v->name, "switch"))
+ pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
+ else
+ ast_copy_string(realvalue, v->value, sizeof(realvalue));
+ appl = strsep(&stringp, "/");
+ data = S_OR(stringp, "");
+ if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
+ ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
+ } else {
+ ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
+ }
+ }
+ }
+ ast_config_destroy(cfg);
+ return 1;
+}
+
+static void append_interface(char *iface, int maxlen, char *add)
+{
+ int len = strlen(iface);
+ if (strlen(add) + len < maxlen - 2) {
+ if (strlen(iface)) {
+ iface[len] = '&';
+ strcpy(iface + len + 1, add);
+ } else
+ strcpy(iface, add);
+ }
+}
+
+static void pbx_load_users(void)
+{
+ struct ast_config *cfg;
+ char *cat, *chan;
+ const char *zapchan;
+ const char *hasexten;
+ char tmp[256];
+ char iface[256];
+ char zapcopy[256];
+ char *c;
+ int len;
+ int hasvoicemail;
+ int start, finish, x;
+ struct ast_context *con = NULL;
+ struct ast_flags config_flags = { 0 };
+
+ cfg = ast_config_load("users.conf", config_flags);
+ if (!cfg)
+ return;
+
+ for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
+ if (!strcasecmp(cat, "general"))
+ continue;
+ iface[0] = '\0';
+ len = sizeof(iface);
+ if (ast_true(ast_config_option(cfg, cat, "hassip"))) {
+ snprintf(tmp, sizeof(tmp), "SIP/%s", cat);
+ append_interface(iface, sizeof(iface), tmp);
+ }
+ if (ast_true(ast_config_option(cfg, cat, "hasiax"))) {
+ snprintf(tmp, sizeof(tmp), "IAX2/%s", cat);
+ append_interface(iface, sizeof(iface), tmp);
+ }
+ if (ast_true(ast_config_option(cfg, cat, "hash323"))) {
+ snprintf(tmp, sizeof(tmp), "H323/%s", cat);
+ append_interface(iface, sizeof(iface), tmp);
+ }
+ hasexten = ast_config_option(cfg, cat, "hasexten");
+ if (hasexten && !ast_true(hasexten))
+ continue;
+ hasvoicemail = ast_true(ast_config_option(cfg, cat, "hasvoicemail"));
+ zapchan = ast_variable_retrieve(cfg, cat, "zapchan");
+ if (!zapchan)
+ zapchan = ast_variable_retrieve(cfg, "general", "zapchan");
+ if (!ast_strlen_zero(zapchan)) {
+ ast_copy_string(zapcopy, zapchan, sizeof(zapcopy));
+ c = zapcopy;
+ chan = strsep(&c, ",");
+ while (chan) {
+ if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
+ /* Range */
+ } else if (sscanf(chan, "%d", &start)) {
+ /* Just one */
+ finish = start;
+ } else {
+ start = 0; finish = 0;
+ }
+ if (finish < start) {
+ x = finish;
+ finish = start;
+ start = x;
+ }
+ for (x = start; x <= finish; x++) {
+ snprintf(tmp, sizeof(tmp), "Zap/%d", x);
+ append_interface(iface, sizeof(iface), tmp);
+ }
+ chan = strsep(&c, ",");
+ }
+ }
+ if (!ast_strlen_zero(iface)) {
+ /* Only create a context here when it is really needed. Otherwise default empty context
+ created by pbx_config may conflict with the one explicitly created by pbx_ael */
+ if (!con)
+ con = ast_context_find_or_create(&local_contexts, userscontext, registrar);
+
+ if (!con) {
+ ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
+ return;
+ }
+
+ /* Add hint */
+ ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar);
+ /* If voicemail, use "stdexten" else use plain old dial */
+ if (hasvoicemail) {
+ snprintf(tmp, sizeof(tmp), "stdexten,%s,${HINT}", cat);
+ ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", strdup(tmp), ast_free_ptr, registrar);
+ } else {
+ ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", strdup("${HINT}"), ast_free_ptr, registrar);
+ }
+ }
+ }
+ ast_config_destroy(cfg);
+}
+
+static int pbx_load_module(void)
+{
+ struct ast_context *con;
+
+ if(!pbx_load_config(config))
+ return AST_MODULE_LOAD_DECLINE;
+
+ pbx_load_users();
+
+ ast_merge_contexts_and_delete(&local_contexts, registrar);
+
+ for (con = NULL; (con = ast_walk_contexts(con));)
+ ast_context_verify_includes(con);
+
+ pbx_set_autofallthrough(autofallthrough_config);
+ pbx_set_extenpatternmatchnew(extenpatternmatchnew_config);
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int load_module(void)
+{
+ if (pbx_load_module())
+ return AST_MODULE_LOAD_DECLINE;
+
+ if (static_config && !write_protect_config)
+ ast_cli_register(&cli_dialplan_save);
+ ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload(void)
+{
+ if (clearglobalvars_config)
+ pbx_builtin_clear_globals();
+ return pbx_load_module();
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Text Extension Configuration",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
diff --git a/trunk/pbx/pbx_dundi.c b/trunk/pbx/pbx_dundi.c
new file mode 100644
index 000000000..26a3e51a2
--- /dev/null
+++ b/trunk/pbx/pbx_dundi.c
@@ -0,0 +1,4847 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Distributed Universal Number Discovery (DUNDi)
+ */
+
+/*** MODULEINFO
+ <depend>zlib</depend>
+ <use>crypto</use>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/network.h"
+#include <sys/ioctl.h>
+#include <zlib.h>
+#include <sys/signal.h>
+#include <pthread.h>
+#include <net/if.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Darwin__)
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#endif
+
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/frame.h"
+#include "asterisk/cli.h"
+#include "asterisk/lock.h"
+#include "asterisk/md5.h"
+#include "asterisk/dundi.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/utils.h"
+#include "asterisk/netsock.h"
+#include "asterisk/crypto.h"
+#include "asterisk/astdb.h"
+#include "asterisk/acl.h"
+#include "asterisk/aes.h"
+#include "asterisk/app.h"
+
+#include "dundi-parser.h"
+
+#define MAX_RESULTS 64
+
+#define MAX_PACKET_SIZE 8192
+
+#define MAX_WEIGHT 59999
+
+#define DUNDI_MODEL_INBOUND (1 << 0)
+#define DUNDI_MODEL_OUTBOUND (1 << 1)
+#define DUNDI_MODEL_SYMMETRIC (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND)
+
+/*! Keep times of last 10 lookups */
+#define DUNDI_TIMING_HISTORY 10
+
+enum {
+ FLAG_ISREG = (1 << 0), /*!< Transaction is register request */
+ FLAG_DEAD = (1 << 1), /*!< Transaction is dead */
+ FLAG_FINAL = (1 << 2), /*!< Transaction has final message sent */
+ FLAG_ISQUAL = (1 << 3), /*!< Transaction is a qualification */
+ FLAG_ENCRYPT = (1 << 4), /*!< Transaction is encrypted wiht ECX/DCX */
+ FLAG_SENDFULLKEY = (1 << 5), /*!< Send full key on transaction */
+ FLAG_STOREHIST = (1 << 6), /*!< Record historic performance */
+};
+
+#define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17)
+
+#if 0
+#define DUNDI_SECRET_TIME 15 /* Testing only */
+#else
+#define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME
+#endif
+
+static struct io_context *io;
+static struct sched_context *sched;
+static int netsocket = -1;
+static pthread_t netthreadid = AST_PTHREADT_NULL;
+static pthread_t precachethreadid = AST_PTHREADT_NULL;
+static unsigned int tos = 0;
+static int dundidebug = 0;
+static int authdebug = 0;
+static int dundi_ttl = DUNDI_DEFAULT_TTL;
+static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE;
+static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
+static int global_autokilltimeout = 0;
+static dundi_eid global_eid;
+static int default_expiration = 60;
+static int global_storehistory = 0;
+static char dept[80];
+static char org[80];
+static char locality[80];
+static char stateprov[80];
+static char country[80];
+static char email[80];
+static char phone[80];
+static char secretpath[80];
+static char cursecret[80];
+static char ipaddr[80];
+static time_t rotatetime;
+static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } };
+static int dundi_shutdown = 0;
+
+struct permission {
+ AST_LIST_ENTRY(permission) list;
+ int allow;
+ char name[0];
+};
+
+struct dundi_packet {
+ AST_LIST_ENTRY(dundi_packet) list;
+ struct dundi_hdr *h;
+ int datalen;
+ struct dundi_transaction *parent;
+ int retransid;
+ int retrans;
+ unsigned char data[0];
+};
+
+struct dundi_hint_metadata {
+ unsigned short flags;
+ char exten[AST_MAX_EXTENSION];
+};
+
+struct dundi_precache_queue {
+ AST_LIST_ENTRY(dundi_precache_queue) list;
+ char *context;
+ time_t expiration;
+ char number[0];
+};
+
+struct dundi_request;
+
+struct dundi_transaction {
+ struct sockaddr_in addr; /*!< Other end of transaction */
+ struct timeval start; /*!< When this transaction was created */
+ dundi_eid eids[DUNDI_MAX_STACK + 1];
+ int eidcount; /*!< Number of eids in eids */
+ dundi_eid us_eid; /*!< Our EID, to them */
+ dundi_eid them_eid; /*!< Their EID, to us */
+ ast_aes_encrypt_key ecx; /*!< AES 128 Encryption context */
+ ast_aes_decrypt_key dcx; /*!< AES 128 Decryption context */
+ unsigned int flags; /*!< Has final packet been sent */
+ int ttl; /*!< Remaining TTL for queries on this one */
+ int thread; /*!< We have a calling thread */
+ int retranstimer; /*!< How long to wait before retransmissions */
+ int autokillid; /*!< ID to kill connection if answer doesn't come back fast enough */
+ int autokilltimeout; /*!< Recommended timeout for autokill */
+ unsigned short strans; /*!< Our transaction identifier */
+ unsigned short dtrans; /*!< Their transaction identifer */
+ unsigned char iseqno; /*!< Next expected received seqno */
+ unsigned char oiseqno; /*!< Last received incoming seqno */
+ unsigned char oseqno; /*!< Next transmitted seqno */
+ unsigned char aseqno; /*!< Last acknowledge seqno */
+ AST_LIST_HEAD_NOLOCK(packetlist, dundi_packet) packets; /*!< Packets to be retransmitted */
+ struct packetlist lasttrans; /*!< Last transmitted / ACK'd packet */
+ struct dundi_request *parent; /*!< Parent request (if there is one) */
+ AST_LIST_ENTRY(dundi_transaction) parentlist; /*!< Next with respect to the parent */
+ AST_LIST_ENTRY(dundi_transaction) all; /*!< Next with respect to all DUNDi transactions */
+};
+
+struct dundi_request {
+ char dcontext[AST_MAX_EXTENSION];
+ char number[AST_MAX_EXTENSION];
+ dundi_eid query_eid;
+ dundi_eid root_eid;
+ struct dundi_result *dr;
+ struct dundi_entity_info *dei;
+ struct dundi_hint_metadata *hmd;
+ int maxcount;
+ int respcount;
+ int expiration;
+ int cbypass;
+ int pfds[2];
+ unsigned long crc32; /*!< CRC-32 of all but root EID's in avoid list */
+ AST_LIST_HEAD_NOLOCK(, dundi_transaction) trans; /*!< Transactions */
+ AST_LIST_ENTRY(dundi_request) list;
+};
+
+struct dundi_mapping {
+ char dcontext[AST_MAX_EXTENSION];
+ char lcontext[AST_MAX_EXTENSION];
+ int _weight;
+ char *weightstr;
+ int options;
+ int tech;
+ int dead;
+ char dest[AST_MAX_EXTENSION];
+ AST_LIST_ENTRY(dundi_mapping) list;
+};
+
+struct dundi_peer {
+ dundi_eid eid;
+ struct sockaddr_in addr; /*!< Address of DUNDi peer */
+ AST_LIST_HEAD_NOLOCK(permissionlist, permission) permit;
+ struct permissionlist include;
+ dundi_eid us_eid;
+ char inkey[80];
+ char outkey[80];
+ int dead;
+ int registerid;
+ int qualifyid;
+ int sentfullkey;
+ int order;
+ unsigned char txenckey[256]; /*!< Transmitted encrypted key + sig */
+ unsigned char rxenckey[256]; /*!< Cache received encrypted key + sig */
+ unsigned long us_keycrc32; /*!< CRC-32 of our key */
+ ast_aes_encrypt_key us_ecx; /*!< Cached AES 128 Encryption context */
+ ast_aes_decrypt_key us_dcx; /*!< Cached AES 128 Decryption context */
+ unsigned long them_keycrc32; /*!< CRC-32 of our key */
+ ast_aes_encrypt_key them_ecx; /*!< Cached AES 128 Encryption context */
+ ast_aes_decrypt_key them_dcx; /*!< Cached AES 128 Decryption context */
+ time_t keyexpire; /*!< When to expire/recreate key */
+ int registerexpire;
+ int lookuptimes[DUNDI_TIMING_HISTORY];
+ char *lookups[DUNDI_TIMING_HISTORY];
+ int avgms;
+ struct dundi_transaction *regtrans; /*!< Registration transaction */
+ struct dundi_transaction *qualtrans; /*!< Qualify transaction */
+ int model; /*!< Pull model */
+ int pcmodel; /*!< Push/precache model */
+ /*! Dynamic peers register with us */
+ unsigned int dynamic:1;
+ int lastms; /*!< Last measured latency */
+ int maxms; /*!< Max permissible latency */
+ struct timeval qualtx; /*!< Time of transmit */
+ AST_LIST_ENTRY(dundi_peer) list;
+};
+
+static AST_LIST_HEAD_STATIC(peers, dundi_peer);
+static AST_LIST_HEAD_STATIC(pcq, dundi_precache_queue);
+static AST_LIST_HEAD_NOLOCK_STATIC(mappings, dundi_mapping);
+static AST_LIST_HEAD_NOLOCK_STATIC(requests, dundi_request);
+static AST_LIST_HEAD_NOLOCK_STATIC(alltrans, dundi_transaction);
+
+/*!
+ * \brief Wildcard peer
+ *
+ * This peer is created if the [*] entry is specified in dundi.conf
+ */
+static struct dundi_peer *any_peer;
+
+static int dundi_xmit(struct dundi_packet *pack);
+
+static void dundi_debug_output(const char *data)
+{
+ if (dundidebug)
+ ast_verbose("%s", data);
+}
+
+static void dundi_error_output(const char *data)
+{
+ ast_log(LOG_WARNING, "%s", data);
+}
+
+static int has_permission(struct permissionlist *permlist, char *cont)
+{
+ struct permission *perm;
+ int res = 0;
+
+ AST_LIST_TRAVERSE(permlist, perm, list) {
+ if (!strcasecmp(perm->name, "all") || !strcasecmp(perm->name, cont))
+ res = perm->allow;
+ }
+
+ return res;
+}
+
+static char *tech2str(int tech)
+{
+ switch(tech) {
+ case DUNDI_PROTO_NONE:
+ return "None";
+ case DUNDI_PROTO_IAX:
+ return "IAX2";
+ case DUNDI_PROTO_SIP:
+ return "SIP";
+ case DUNDI_PROTO_H323:
+ return "H323";
+ default:
+ return "Unknown";
+ }
+}
+
+static int str2tech(char *str)
+{
+ if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2"))
+ return DUNDI_PROTO_IAX;
+ else if (!strcasecmp(str, "SIP"))
+ return DUNDI_PROTO_SIP;
+ else if (!strcasecmp(str, "H323"))
+ return DUNDI_PROTO_H323;
+ else
+ return -1;
+}
+
+static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]);
+static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]);
+static struct dundi_transaction *create_transaction(struct dundi_peer *p);
+static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct sockaddr_in *sin)
+{
+ struct dundi_transaction *trans;
+
+ /* Look for an exact match first */
+ AST_LIST_TRAVERSE(&alltrans, trans, all) {
+ if (!inaddrcmp(&trans->addr, sin) &&
+ ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||
+ ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {
+ if (hdr->strans)
+ trans->dtrans = ntohs(hdr->strans) & 32767;
+ return trans;
+ }
+ }
+
+ switch(hdr->cmdresp & 0x7f) {
+ case DUNDI_COMMAND_DPDISCOVER:
+ case DUNDI_COMMAND_EIDQUERY:
+ case DUNDI_COMMAND_PRECACHERQ:
+ case DUNDI_COMMAND_REGREQ:
+ case DUNDI_COMMAND_NULL:
+ case DUNDI_COMMAND_ENCRYPT:
+ if (!hdr->strans)
+ break;
+ /* Create new transaction */
+ if (!(trans = create_transaction(NULL)))
+ break;
+ memcpy(&trans->addr, sin, sizeof(trans->addr));
+ trans->dtrans = ntohs(hdr->strans) & 32767;
+ default:
+ break;
+ }
+
+ return trans;
+}
+
+static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied);
+
+static int dundi_ack(struct dundi_transaction *trans, int final)
+{
+ return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);
+}
+static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin)
+{
+ struct {
+ struct dundi_packet pack;
+ struct dundi_hdr hdr;
+ } tmp;
+ struct dundi_transaction trans;
+ /* Never respond to an INVALID with another INVALID */
+ if (h->cmdresp == DUNDI_COMMAND_INVALID)
+ return;
+ memset(&tmp, 0, sizeof(tmp));
+ memset(&trans, 0, sizeof(trans));
+ memcpy(&trans.addr, sin, sizeof(trans.addr));
+ tmp.hdr.strans = h->dtrans;
+ tmp.hdr.dtrans = h->strans;
+ tmp.hdr.iseqno = h->oseqno;
+ tmp.hdr.oseqno = h->iseqno;
+ tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID;
+ tmp.hdr.cmdflags = 0;
+ tmp.pack.h = (struct dundi_hdr *)tmp.pack.data;
+ tmp.pack.datalen = sizeof(struct dundi_hdr);
+ tmp.pack.parent = &trans;
+ dundi_xmit(&tmp.pack);
+}
+
+static void reset_global_eid(void)
+{
+#if defined(SIOCGIFHWADDR)
+ int s, x = 0;
+ char eid_str[20];
+ struct ifreq ifr;
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return;
+ for (x = 0; x < 10; x++) {
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x);
+ if (ioctl(s, SIOCGIFHWADDR, &ifr))
+ continue;
+ memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid));
+ ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name);
+ close(s);
+ return;
+ }
+ close(s);
+#else
+#if defined(ifa_broadaddr) && !defined(SOLARIS)
+ char eid_str[20];
+ struct ifaddrs *ifap;
+
+ if (getifaddrs(&ifap) == 0) {
+ struct ifaddrs *p;
+ for (p = ifap; p; p = p->ifa_next) {
+ if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
+ struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
+ memcpy(&(global_eid.eid), sdp->sdl_data + sdp->sdl_nlen, 6);
+ ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), p->ifa_name);
+ freeifaddrs(ifap);
+ return;
+ }
+ }
+ freeifaddrs(ifap);
+ }
+#endif
+#endif
+ ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
+}
+
+static int get_trans_id(void)
+{
+ struct dundi_transaction *t;
+ int stid = (ast_random() % 32766) + 1;
+ int tid = stid;
+
+ do {
+ AST_LIST_TRAVERSE(&alltrans, t, all) {
+ if (t->strans == tid)
+ break;
+ }
+ if (!t)
+ return tid;
+ tid = (tid % 32766) + 1;
+ } while (tid != stid);
+
+ return 0;
+}
+
+static int reset_transaction(struct dundi_transaction *trans)
+{
+ int tid;
+ tid = get_trans_id();
+ if (tid < 1)
+ return -1;
+ trans->strans = tid;
+ trans->dtrans = 0;
+ trans->iseqno = 0;
+ trans->oiseqno = 0;
+ trans->oseqno = 0;
+ trans->aseqno = 0;
+ ast_clear_flag(trans, FLAG_FINAL);
+ return 0;
+}
+
+static struct dundi_peer *find_peer(dundi_eid *eid)
+{
+ struct dundi_peer *cur = NULL;
+
+ if (!eid)
+ eid = &empty_eid;
+
+ AST_LIST_TRAVERSE(&peers, cur, list) {
+ if (!dundi_eid_cmp(&cur->eid,eid))
+ break;
+ }
+
+ if (!cur && any_peer)
+ cur = any_peer;
+
+ return cur;
+}
+
+static void build_iv(unsigned char *iv)
+{
+ /* XXX Would be nice to be more random XXX */
+ unsigned int *fluffy;
+ int x;
+ fluffy = (unsigned int *)(iv);
+ for (x=0;x<4;x++)
+ fluffy[x] = ast_random();
+}
+
+struct dundi_query_state {
+ dundi_eid *eids[DUNDI_MAX_STACK + 1];
+ int directs[DUNDI_MAX_STACK + 1];
+ dundi_eid reqeid;
+ char called_context[AST_MAX_EXTENSION];
+ char called_number[AST_MAX_EXTENSION];
+ struct dundi_mapping *maps;
+ int nummaps;
+ int nocache;
+ struct dundi_transaction *trans;
+ void *chal;
+ int challen;
+ int ttl;
+ char fluffy[0];
+};
+
+static int get_mapping_weight(struct dundi_mapping *map)
+{
+ char buf[32];
+
+ buf[0] = 0;
+ if (map->weightstr) {
+ pbx_substitute_variables_helper(NULL, map->weightstr, buf, sizeof(buf) - 1);
+ if (sscanf(buf, "%d", &map->_weight) != 1)
+ map->_weight = MAX_WEIGHT;
+ }
+
+ return map->_weight;
+}
+
+static int dundi_lookup_local(struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd)
+{
+ struct ast_flags flags = {0};
+ int x;
+ if (!ast_strlen_zero(map->lcontext)) {
+ if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL))
+ ast_set_flag(&flags, DUNDI_FLAG_EXISTS);
+ if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL))
+ ast_set_flag(&flags, DUNDI_FLAG_CANMATCH);
+ if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL))
+ ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE);
+ if (ast_ignore_pattern(map->lcontext, called_number))
+ ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT);
+
+ /* Clearly we can't say 'don't ask' anymore if we found anything... */
+ if (ast_test_flag(&flags, AST_FLAGS_ALL))
+ ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK);
+
+ if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) {
+ /* Skip partial answers */
+ ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH);
+ }
+ if (ast_test_flag(&flags, AST_FLAGS_ALL)) {
+ struct varshead headp;
+ struct ast_var_t *newvariable;
+ ast_set_flag(&flags, map->options & 0xffff);
+ ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL);
+ dr[anscnt].techint = map->tech;
+ dr[anscnt].weight = get_mapping_weight(map);
+ dr[anscnt].expiration = dundi_cache_time;
+ ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech));
+ dr[anscnt].eid = *us_eid;
+ dundi_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid);
+ if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) {
+ AST_LIST_HEAD_INIT_NOLOCK(&headp);
+ newvariable = ast_var_assign("NUMBER", called_number);
+ AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
+ newvariable = ast_var_assign("EID", dr[anscnt].eid_str);
+ AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
+ newvariable = ast_var_assign("SECRET", cursecret);
+ AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
+ newvariable = ast_var_assign("IPADDR", ipaddr);
+ AST_LIST_INSERT_HEAD(&headp, newvariable, entries);
+ pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest));
+ while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
+ ast_var_delete(newvariable);
+ } else
+ dr[anscnt].dest[0] = '\0';
+ anscnt++;
+ } else {
+ /* No answers... Find the fewest number of digits from the
+ number for which we have no answer. */
+ char tmp[AST_MAX_EXTENSION + 1] = "";
+ for (x = 0; x < (sizeof(tmp) - 1); x++) {
+ tmp[x] = called_number[x];
+ if (!tmp[x])
+ break;
+ if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) {
+ /* Oops found something we can't match. If this is longer
+ than the running hint, we have to consider it */
+ if (strlen(tmp) > strlen(hmd->exten)) {
+ ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten));
+ }
+ break;
+ }
+ }
+ }
+ }
+ return anscnt;
+}
+
+static void destroy_trans(struct dundi_transaction *trans, int fromtimeout);
+
+static void *dundi_lookup_thread(void *data)
+{
+ struct dundi_query_state *st = data;
+ struct dundi_result dr[MAX_RESULTS];
+ struct dundi_ie_data ied;
+ struct dundi_hint_metadata hmd;
+ char eid_str[20];
+ int res, x;
+ int ouranswers=0;
+ int max = 999999;
+ int expiration = dundi_cache_time;
+
+ ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
+ st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves");
+ memset(&ied, 0, sizeof(ied));
+ memset(&dr, 0, sizeof(dr));
+ memset(&hmd, 0, sizeof(hmd));
+ /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */
+ hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
+ for (x=0;x<st->nummaps;x++)
+ ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd);
+ if (ouranswers < 0)
+ ouranswers = 0;
+ for (x=0;x<ouranswers;x++) {
+ if (dr[x].weight < max)
+ max = dr[x].weight;
+ }
+
+ if (max) {
+ /* If we do not have a canonical result, keep looking */
+ res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, st->called_context, st->called_number, st->ttl, 1, &hmd, &expiration, st->nocache, 0, NULL, st->eids, st->directs);
+ if (res > 0) {
+ /* Append answer in result */
+ ouranswers += res;
+ } else {
+ if ((res < -1) && (!ouranswers))
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending");
+ }
+ }
+ AST_LIST_LOCK(&peers);
+ /* Truncate if "don't ask" isn't present */
+ if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
+ hmd.exten[0] = '\0';
+ if (ast_test_flag(st->trans, FLAG_DEAD)) {
+ ast_debug(1, "Our transaction went away!\n");
+ st->trans->thread = 0;
+ destroy_trans(st->trans, 0);
+ } else {
+ for (x=0;x<ouranswers;x++) {
+ /* Add answers */
+ if (dr[x].expiration && (expiration > dr[x].expiration))
+ expiration = dr[x].expiration;
+ dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
+ }
+ dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
+ dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
+ dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
+ st->trans->thread = 0;
+ }
+ AST_LIST_UNLOCK(&peers);
+ ast_free(st);
+ return NULL;
+}
+
+static void *dundi_precache_thread(void *data)
+{
+ struct dundi_query_state *st = data;
+ struct dundi_ie_data ied;
+ struct dundi_hint_metadata hmd;
+ char eid_str[20];
+
+ ast_debug(1, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context,
+ st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves");
+ memset(&ied, 0, sizeof(ied));
+
+ /* Now produce precache */
+ dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids);
+
+ AST_LIST_LOCK(&peers);
+ /* Truncate if "don't ask" isn't present */
+ if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK))
+ hmd.exten[0] = '\0';
+ if (ast_test_flag(st->trans, FLAG_DEAD)) {
+ ast_debug(1, "Our transaction went away!\n");
+ st->trans->thread = 0;
+ destroy_trans(st->trans, 0);
+ } else {
+ dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
+ st->trans->thread = 0;
+ }
+ AST_LIST_UNLOCK(&peers);
+ ast_free(st);
+ return NULL;
+}
+
+static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]);
+
+static void *dundi_query_thread(void *data)
+{
+ struct dundi_query_state *st = data;
+ struct dundi_entity_info dei;
+ struct dundi_ie_data ied;
+ struct dundi_hint_metadata hmd;
+ char eid_str[20];
+ int res;
+
+ ast_debug(1, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context,
+ st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves");
+ memset(&ied, 0, sizeof(ied));
+ memset(&dei, 0, sizeof(dei));
+ memset(&hmd, 0, sizeof(hmd));
+ if (!dundi_eid_cmp(&st->trans->us_eid, &st->reqeid)) {
+ /* Ooh, it's us! */
+ ast_debug(1, "Neat, someone look for us!\n");
+ ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit));
+ ast_copy_string(dei.org, org, sizeof(dei.org));
+ ast_copy_string(dei.locality, locality, sizeof(dei.locality));
+ ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov));
+ ast_copy_string(dei.country, country, sizeof(dei.country));
+ ast_copy_string(dei.email, email, sizeof(dei.email));
+ ast_copy_string(dei.phone, phone, sizeof(dei.phone));
+ res = 1;
+ } else {
+ /* If we do not have a canonical result, keep looking */
+ res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids);
+ }
+ AST_LIST_LOCK(&peers);
+ if (ast_test_flag(st->trans, FLAG_DEAD)) {
+ ast_debug(1, "Our transaction went away!\n");
+ st->trans->thread = 0;
+ destroy_trans(st->trans, 0);
+ } else {
+ if (res) {
+ dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit);
+ dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org);
+ dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality);
+ dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov);
+ dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country);
+ dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email);
+ dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone);
+ if (!ast_strlen_zero(dei.ipaddr))
+ dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr);
+ }
+ dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
+ dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
+ st->trans->thread = 0;
+ }
+ AST_LIST_UNLOCK(&peers);
+ ast_free(st);
+ return NULL;
+}
+
+static int dundi_answer_entity(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
+{
+ struct dundi_query_state *st;
+ int totallen;
+ int x;
+ int skipfirst=0;
+ char eid_str[20];
+ char *s;
+ pthread_t lookupthread;
+
+ if (ies->eidcount > 1) {
+ /* Since it is a requirement that the first EID is the authenticating host
+ and the last EID is the root, it is permissible that the first and last EID
+ could be the same. In that case, we should go ahead copy only the "root" section
+ since we will not need it for authentication. */
+ if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
+ skipfirst = 1;
+ }
+ totallen = sizeof(struct dundi_query_state);
+ totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
+ st = ast_calloc(1, totallen);
+ if (st) {
+ ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
+ memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid));
+ st->trans = trans;
+ st->ttl = ies->ttl - 1;
+ if (st->ttl < 0)
+ st->ttl = 0;
+ s = st->fluffy;
+ for (x=skipfirst;ies->eids[x];x++) {
+ st->eids[x-skipfirst] = (dundi_eid *)s;
+ *st->eids[x-skipfirst] = *ies->eids[x];
+ s += sizeof(dundi_eid);
+ }
+ ast_debug(1, "Answering EID query for '%s@%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context);
+
+ trans->thread = 1;
+ if (ast_pthread_create_detached(&lookupthread, NULL, dundi_query_thread, st)) {
+ struct dundi_ie_data ied = { 0, };
+ trans->thread = 0;
+ ast_log(LOG_WARNING, "Unable to create thread!\n");
+ ast_free(st);
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
+ dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
+ return -1;
+ }
+ } else {
+ struct dundi_ie_data ied = { 0, };
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
+ dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied);
+ return -1;
+ }
+ return 0;
+}
+
+static int cache_save_hint(dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration)
+{
+ int unaffected;
+ char key1[256];
+ char key2[256];
+ char eidpeer_str[20];
+ char eidroot_str[20];
+ char data[80];
+ time_t timeout;
+
+ if (expiration < 0)
+ expiration = dundi_cache_time;
+
+ /* Only cache hint if "don't ask" is there... */
+ if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK)))
+ return 0;
+
+ unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED));
+
+ dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
+ dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
+ snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08lx", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32);
+ snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str);
+
+ time(&timeout);
+ timeout += expiration;
+ snprintf(data, sizeof(data), "%ld|", (long)(timeout));
+
+ ast_db_put("dundi/cache", key1, data);
+ ast_debug(1, "Caching hint at '%s'\n", key1);
+ ast_db_put("dundi/cache", key2, data);
+ ast_debug(1, "Caching hint at '%s'\n", key2);
+ return 0;
+}
+
+static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push)
+{
+ int x;
+ char key1[256];
+ char key2[256];
+ char data[1024];
+ char eidpeer_str[20];
+ char eidroot_str[20];
+ time_t timeout;
+
+ if (expiration < 1)
+ expiration = dundi_cache_time;
+
+ /* Keep pushes a little longer, cut pulls a little short */
+ if (push)
+ expiration += 10;
+ else
+ expiration -= 10;
+ if (expiration < 1)
+ expiration = 1;
+ dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer);
+ dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
+ snprintf(key1, sizeof(key1), "%s/%s/%s/e%08lx", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32);
+ snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str);
+ /* Build request string */
+ time(&timeout);
+ timeout += expiration;
+ snprintf(data, sizeof(data), "%ld|", (long)(timeout));
+ for (x=start;x<req->respcount;x++) {
+ /* Skip anything with an illegal pipe in it */
+ if (strchr(req->dr[x].dest, '|'))
+ continue;
+ snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|",
+ req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest,
+ dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid));
+ }
+ ast_db_put("dundi/cache", key1, data);
+ ast_db_put("dundi/cache", key2, data);
+ return 0;
+}
+
+static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
+{
+ struct dundi_query_state *st;
+ int totallen;
+ int x,z;
+ struct dundi_ie_data ied;
+ char *s;
+ struct dundi_result dr2[MAX_RESULTS];
+ struct dundi_request dr;
+ struct dundi_hint_metadata hmd;
+
+ struct dundi_mapping *cur;
+ int mapcount;
+ int skipfirst = 0;
+
+ pthread_t lookupthread;
+
+ memset(&dr2, 0, sizeof(dr2));
+ memset(&dr, 0, sizeof(dr));
+ memset(&hmd, 0, sizeof(hmd));
+
+ /* Forge request structure to hold answers for cache */
+ hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
+ dr.dr = dr2;
+ dr.maxcount = MAX_RESULTS;
+ dr.expiration = dundi_cache_time;
+ dr.hmd = &hmd;
+ dr.pfds[0] = dr.pfds[1] = -1;
+ trans->parent = &dr;
+ ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext));
+ ast_copy_string(dr.number, ies->called_number, sizeof(dr.number));
+
+ for (x=0;x<ies->anscount;x++) {
+ if (trans->parent->respcount < trans->parent->maxcount) {
+ /* Make sure it's not already there */
+ for (z=0;z<trans->parent->respcount;z++) {
+ if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) &&
+ !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data))
+ break;
+ }
+ if (z == trans->parent->respcount) {
+ /* Copy into parent responses */
+ trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags);
+ trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol;
+ trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight);
+ trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid;
+ if (ies->expiration > 0)
+ trans->parent->dr[trans->parent->respcount].expiration = ies->expiration;
+ else
+ trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
+ dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
+ sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
+ &ies->answers[x]->eid);
+ ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data,
+ sizeof(trans->parent->dr[trans->parent->respcount].dest));
+ ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol),
+ sizeof(trans->parent->dr[trans->parent->respcount].tech));
+ trans->parent->respcount++;
+ ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
+ } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) {
+ /* Update weight if appropriate */
+ trans->parent->dr[z].weight = ies->answers[x]->weight;
+ }
+ } else
+ ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n",
+ trans->parent->number, trans->parent->dcontext);
+
+ }
+ /* Save all the results (if any) we had. Even if no results, still cache lookup. */
+ cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1);
+ if (ies->hint)
+ cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration);
+
+ totallen = sizeof(struct dundi_query_state);
+ /* Count matching map entries */
+ mapcount = 0;
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ if (!strcasecmp(cur->dcontext, ccontext))
+ mapcount++;
+ }
+
+ /* If no maps, return -1 immediately */
+ if (!mapcount)
+ return -1;
+
+ if (ies->eidcount > 1) {
+ /* Since it is a requirement that the first EID is the authenticating host
+ and the last EID is the root, it is permissible that the first and last EID
+ could be the same. In that case, we should go ahead copy only the "root" section
+ since we will not need it for authentication. */
+ if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
+ skipfirst = 1;
+ }
+
+ /* Prepare to run a query and then propagate that as necessary */
+ totallen += mapcount * sizeof(struct dundi_mapping);
+ totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
+ st = ast_calloc(1, totallen);
+ if (st) {
+ ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
+ ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
+ st->trans = trans;
+ st->ttl = ies->ttl - 1;
+ st->nocache = ies->cbypass;
+ if (st->ttl < 0)
+ st->ttl = 0;
+ s = st->fluffy;
+ for (x=skipfirst;ies->eids[x];x++) {
+ st->eids[x-skipfirst] = (dundi_eid *)s;
+ *st->eids[x-skipfirst] = *ies->eids[x];
+ st->directs[x-skipfirst] = ies->eid_direct[x];
+ s += sizeof(dundi_eid);
+ }
+ /* Append mappings */
+ x = 0;
+ st->maps = (struct dundi_mapping *)s;
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ if (!strcasecmp(cur->dcontext, ccontext)) {
+ if (x < mapcount) {
+ st->maps[x] = *cur;
+ st->maps[x].list.next = NULL;
+ x++;
+ }
+ }
+ }
+ st->nummaps = mapcount;
+ ast_debug(1, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context);
+ trans->thread = 1;
+ if (ast_pthread_create_detached(&lookupthread, NULL, dundi_precache_thread, st)) {
+ trans->thread = 0;
+ ast_log(LOG_WARNING, "Unable to create thread!\n");
+ ast_free(st);
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
+ dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
+ return -1;
+ }
+ } else {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
+ dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied);
+ return -1;
+ }
+ return 0;
+}
+
+static int dundi_answer_query(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext)
+{
+ struct dundi_query_state *st;
+ int totallen;
+ int x;
+ struct dundi_ie_data ied;
+ char *s;
+ struct dundi_mapping *cur;
+ int mapcount = 0;
+ int skipfirst = 0;
+
+ pthread_t lookupthread;
+ totallen = sizeof(struct dundi_query_state);
+ /* Count matching map entries */
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ if (!strcasecmp(cur->dcontext, ccontext))
+ mapcount++;
+ }
+ /* If no maps, return -1 immediately */
+ if (!mapcount)
+ return -1;
+
+ if (ies->eidcount > 1) {
+ /* Since it is a requirement that the first EID is the authenticating host
+ and the last EID is the root, it is permissible that the first and last EID
+ could be the same. In that case, we should go ahead copy only the "root" section
+ since we will not need it for authentication. */
+ if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1]))
+ skipfirst = 1;
+ }
+
+ totallen += mapcount * sizeof(struct dundi_mapping);
+ totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid);
+ st = ast_calloc(1, totallen);
+ if (st) {
+ ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context));
+ ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number));
+ st->trans = trans;
+ st->ttl = ies->ttl - 1;
+ st->nocache = ies->cbypass;
+ if (st->ttl < 0)
+ st->ttl = 0;
+ s = st->fluffy;
+ for (x=skipfirst;ies->eids[x];x++) {
+ st->eids[x-skipfirst] = (dundi_eid *)s;
+ *st->eids[x-skipfirst] = *ies->eids[x];
+ st->directs[x-skipfirst] = ies->eid_direct[x];
+ s += sizeof(dundi_eid);
+ }
+ /* Append mappings */
+ x = 0;
+ st->maps = (struct dundi_mapping *)s;
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ if (!strcasecmp(cur->dcontext, ccontext)) {
+ if (x < mapcount) {
+ st->maps[x] = *cur;
+ st->maps[x].list.next = NULL;
+ x++;
+ }
+ }
+ }
+ st->nummaps = mapcount;
+ ast_debug(1, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context);
+ trans->thread = 1;
+ if (ast_pthread_create_detached(&lookupthread, NULL, dundi_lookup_thread, st)) {
+ trans->thread = 0;
+ ast_log(LOG_WARNING, "Unable to create thread!\n");
+ ast_free(st);
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads");
+ dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
+ return -1;
+ }
+ } else {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory");
+ dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied);
+ return -1;
+ }
+ return 0;
+}
+
+static int cache_lookup_internal(time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration)
+{
+ char data[1024];
+ char *ptr, *term, *src;
+ int tech;
+ struct ast_flags flags;
+ int weight;
+ int length;
+ int z;
+ char fs[256];
+
+ /* Build request string */
+ if (!ast_db_get("dundi/cache", key, data, sizeof(data))) {
+ time_t timeout;
+ ptr = data;
+ if (!ast_get_time_t(ptr, &timeout, 0, &length)) {
+ int expiration = timeout - now;
+ if (expiration > 0) {
+ ast_debug(1, "Found cache expiring in %d seconds!\n", expiration);
+ ptr += length + 1;
+ while((sscanf(ptr, "%d/%d/%d/%n", &(flags.flags), &weight, &tech, &length) == 3)) {
+ ptr += length;
+ term = strchr(ptr, '|');
+ if (term) {
+ *term = '\0';
+ src = strrchr(ptr, '/');
+ if (src) {
+ *src = '\0';
+ src++;
+ } else
+ src = "";
+ ast_debug(1, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n",
+ tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full);
+ /* Make sure it's not already there */
+ for (z=0;z<req->respcount;z++) {
+ if ((req->dr[z].techint == tech) &&
+ !strcmp(req->dr[z].dest, ptr))
+ break;
+ }
+ if (z == req->respcount) {
+ /* Copy into parent responses */
+ ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL);
+ req->dr[req->respcount].weight = weight;
+ req->dr[req->respcount].techint = tech;
+ req->dr[req->respcount].expiration = expiration;
+ dundi_str_short_to_eid(&req->dr[req->respcount].eid, src);
+ dundi_eid_to_str(req->dr[req->respcount].eid_str,
+ sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid);
+ ast_copy_string(req->dr[req->respcount].dest, ptr,
+ sizeof(req->dr[req->respcount].dest));
+ ast_copy_string(req->dr[req->respcount].tech, tech2str(tech),
+ sizeof(req->dr[req->respcount].tech));
+ req->respcount++;
+ ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK);
+ } else if (req->dr[z].weight > weight)
+ req->dr[z].weight = weight;
+ ptr = term + 1;
+ }
+ }
+ /* We found *something* cached */
+ if (expiration < *lowexpiration)
+ *lowexpiration = expiration;
+ return 1;
+ } else
+ ast_db_del("dundi/cache", key);
+ } else
+ ast_db_del("dundi/cache", key);
+ }
+
+ return 0;
+}
+
+static int cache_lookup(struct dundi_request *req, dundi_eid *peer_eid, unsigned long crc32, int *lowexpiration)
+{
+ char key[256];
+ char eid_str[20];
+ char eidroot_str[20];
+ time_t now;
+ int res=0;
+ int res2=0;
+ char eid_str_full[20];
+ char tmp[256]="";
+ int x;
+
+ time(&now);
+ dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid);
+ dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid);
+ dundi_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid);
+ snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, crc32);
+ res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
+ snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, 0L);
+ res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
+ snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str);
+ res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
+ x = 0;
+ if (!req->respcount) {
+ while(!res2) {
+ /* Look and see if we have a hint that would preclude us from looking at this
+ peer for this number. */
+ if (!(tmp[x] = req->number[x]))
+ break;
+ x++;
+ /* Check for hints */
+ snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, crc32);
+ res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
+ snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, 0L);
+ res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
+ snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str);
+ res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration);
+ if (res2) {
+ if (strlen(tmp) > strlen(req->hmd->exten)) {
+ /* Update meta data if appropriate */
+ ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten));
+ }
+ }
+ }
+ res |= res2;
+ }
+
+ return res;
+}
+
+static void qualify_peer(struct dundi_peer *peer, int schedonly);
+
+static void apply_peer(struct dundi_transaction *trans, struct dundi_peer *p)
+{
+ if (!trans->addr.sin_addr.s_addr)
+ memcpy(&trans->addr, &p->addr, sizeof(trans->addr));
+ trans->us_eid = p->us_eid;
+ trans->them_eid = p->eid;
+ /* Enable encryption if appropriate */
+ if (!ast_strlen_zero(p->inkey))
+ ast_set_flag(trans, FLAG_ENCRYPT);
+ if (p->maxms) {
+ trans->autokilltimeout = p->maxms;
+ trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
+ if (p->lastms > 1) {
+ trans->retranstimer = p->lastms * 2;
+ /* Keep it from being silly */
+ if (trans->retranstimer < 150)
+ trans->retranstimer = 150;
+ }
+ if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER)
+ trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
+ } else
+ trans->autokilltimeout = global_autokilltimeout;
+}
+
+/*! \note Called with the peers list already locked */
+static int do_register_expire(const void *data)
+{
+ struct dundi_peer *peer = (struct dundi_peer *)data;
+ char eid_str[20];
+ ast_debug(1, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ peer->registerexpire = -1;
+ peer->lastms = 0;
+ memset(&peer->addr, 0, sizeof(peer->addr));
+ return 0;
+}
+
+static int update_key(struct dundi_peer *peer)
+{
+ unsigned char key[16];
+ struct ast_key *ekey, *skey;
+ char eid_str[20];
+ int res;
+ if (!peer->keyexpire || (peer->keyexpire < time(NULL))) {
+ build_iv(key);
+ ast_aes_encrypt_key(key, &peer->us_ecx);
+ ast_aes_decrypt_key(key, &peer->us_dcx);
+ ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
+ if (!ekey) {
+ ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
+ peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ return -1;
+ }
+ skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
+ if (!skey) {
+ ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
+ peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ return -1;
+ }
+ if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
+ ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
+ return -1;
+ }
+ if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) {
+ ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
+ return -1;
+ }
+ peer->us_keycrc32 = crc32(0L, peer->txenckey, 128);
+ peer->sentfullkey = 0;
+ /* Looks good */
+ time(&peer->keyexpire);
+ peer->keyexpire += dundi_key_ttl;
+ }
+ return 0;
+}
+
+static int encrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_encrypt_key *ecx)
+{
+ unsigned char curblock[16];
+ int x;
+ memcpy(curblock, iv, sizeof(curblock));
+ while(len > 0) {
+ for (x=0;x<16;x++)
+ curblock[x] ^= src[x];
+ ast_aes_encrypt(curblock, dst, ecx);
+ memcpy(curblock, dst, sizeof(curblock));
+ dst += 16;
+ src += 16;
+ len -= 16;
+ }
+ return 0;
+}
+static int decrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, ast_aes_decrypt_key *dcx)
+{
+ unsigned char lastblock[16];
+ int x;
+ memcpy(lastblock, iv, sizeof(lastblock));
+ while(len > 0) {
+ ast_aes_decrypt(src, dst, dcx);
+ for (x=0;x<16;x++)
+ dst[x] ^= lastblock[x];
+ memcpy(lastblock, src, sizeof(lastblock));
+ dst += 16;
+ src += 16;
+ len -= 16;
+ }
+ return 0;
+}
+
+static struct dundi_hdr *dundi_decrypt(struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen)
+{
+ int space = *dstlen;
+ unsigned long bytes;
+ struct dundi_hdr *h;
+ unsigned char *decrypt_space;
+ decrypt_space = alloca(srclen);
+ if (!decrypt_space)
+ return NULL;
+ decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx);
+ /* Setup header */
+ h = (struct dundi_hdr *)dst;
+ *h = *ohdr;
+ bytes = space - 6;
+ if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) {
+ ast_debug(1, "Ouch, uncompress failed :(\n");
+ return NULL;
+ }
+ /* Update length */
+ *dstlen = bytes + 6;
+ /* Return new header */
+ return h;
+}
+
+static int dundi_encrypt(struct dundi_transaction *trans, struct dundi_packet *pack)
+{
+ unsigned char *compress_space;
+ int len;
+ int res;
+ unsigned long bytes;
+ struct dundi_ie_data ied;
+ struct dundi_peer *peer;
+ unsigned char iv[16];
+ len = pack->datalen + pack->datalen / 100 + 42;
+ compress_space = alloca(len);
+ if (compress_space) {
+ memset(compress_space, 0, len);
+ /* We care about everthing save the first 6 bytes of header */
+ bytes = len;
+ res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6);
+ if (res != Z_OK) {
+ ast_debug(1, "Ouch, compression failed!\n");
+ return -1;
+ }
+ memset(&ied, 0, sizeof(ied));
+ /* Say who we are */
+ if (!pack->h->iseqno && !pack->h->oseqno) {
+ /* Need the key in the first copy */
+ if (!(peer = find_peer(&trans->them_eid)))
+ return -1;
+ if (update_key(peer))
+ return -1;
+ if (!peer->sentfullkey)
+ ast_set_flag(trans, FLAG_SENDFULLKEY);
+ /* Append key data */
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
+ if (ast_test_flag(trans, FLAG_SENDFULLKEY)) {
+ dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
+ dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
+ } else {
+ dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32);
+ }
+ /* Setup contexts */
+ trans->ecx = peer->us_ecx;
+ trans->dcx = peer->us_dcx;
+
+ /* We've sent the full key */
+ peer->sentfullkey = 1;
+ }
+ /* Build initialization vector */
+ build_iv(iv);
+ /* Add the field, rounded up to 16 bytes */
+ dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16);
+ /* Copy the data */
+ if ((ied.pos + bytes) >= sizeof(ied.buf)) {
+ ast_log(LOG_NOTICE, "Final packet too large!\n");
+ return -1;
+ }
+ encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx);
+ ied.pos += ((bytes + 15) / 16) * 16;
+ /* Reconstruct header */
+ pack->datalen = sizeof(struct dundi_hdr);
+ pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT;
+ pack->h->cmdflags = 0;
+ memcpy(pack->h->ies, ied.buf, ied.pos);
+ pack->datalen += ied.pos;
+ return 0;
+ }
+ return -1;
+}
+
+static int check_key(struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, unsigned long keycrc32)
+{
+ unsigned char dst[128];
+ int res;
+ struct ast_key *key, *skey;
+ char eid_str[20];
+ ast_debug(1, "Expected '%08lx' got '%08lx'\n", peer->them_keycrc32, keycrc32);
+ if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) {
+ /* A match */
+ return 1;
+ } else if (!newkey || !newsig)
+ return 0;
+ if (!memcmp(peer->rxenckey, newkey, 128) &&
+ !memcmp(peer->rxenckey + 128, newsig, 128)) {
+ /* By definition, a match */
+ return 1;
+ }
+ /* Decrypt key */
+ key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
+ if (!key) {
+ ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
+ peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ return -1;
+ }
+
+ skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
+ if (!skey) {
+ ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
+ peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ return -1;
+ }
+
+ /* First check signature */
+ res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig);
+ if (res)
+ return 0;
+
+ res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
+ if (res != 16) {
+ if (res >= 0)
+ ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
+ return 0;
+ }
+ /* Decrypted, passes signature */
+ ast_debug(1, "Wow, new key combo passed signature and decrypt!\n");
+ memcpy(peer->rxenckey, newkey, 128);
+ memcpy(peer->rxenckey + 128, newsig, 128);
+ peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128);
+ ast_aes_decrypt_key(dst, &peer->them_dcx);
+ ast_aes_encrypt_key(dst, &peer->them_ecx);
+ return 1;
+}
+
+static void deep_copy_peer(struct dundi_peer *peer_dst, const struct dundi_peer *peer_src)
+{
+ struct permission *cur, *perm;
+
+ memcpy(peer_dst, peer_src, sizeof(*peer_dst));
+
+ memset(&peer_dst->permit, 0, sizeof(peer_dst->permit));
+ memset(&peer_dst->include, 0, sizeof(peer_dst->permit));
+
+ AST_LIST_TRAVERSE(&peer_src->permit, cur, list) {
+ if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
+ continue;
+
+ perm->allow = cur->allow;
+ strcpy(perm->name, cur->name);
+
+ AST_LIST_INSERT_HEAD(&peer_dst->permit, perm, list);
+ }
+
+ AST_LIST_TRAVERSE(&peer_src->include, cur, list) {
+ if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(cur->name) + 1)))
+ continue;
+
+ perm->allow = cur->allow;
+ strcpy(perm->name, cur->name);
+
+ AST_LIST_INSERT_HEAD(&peer_dst->include, perm, list);
+ }
+}
+
+static int handle_command_response(struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted)
+{
+ /* Handle canonical command / response */
+ int final = hdr->cmdresp & 0x80;
+ int cmd = hdr->cmdresp & 0x7f;
+ int x,y,z;
+ int resp;
+ int res;
+ int authpass=0;
+ unsigned char *bufcpy;
+ struct dundi_ie_data ied;
+ struct dundi_ies ies;
+ struct dundi_peer *peer = NULL;
+ char eid_str[20];
+ char eid_str2[20];
+ memset(&ied, 0, sizeof(ied));
+ memset(&ies, 0, sizeof(ies));
+ if (datalen) {
+ bufcpy = alloca(datalen);
+ if (!bufcpy)
+ return -1;
+ /* Make a copy for parsing */
+ memcpy(bufcpy, hdr->ies, datalen);
+ ast_debug(1, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : "");
+ if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) {
+ ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n");
+ return -1;
+ }
+ }
+ switch(cmd) {
+ case DUNDI_COMMAND_DPDISCOVER:
+ case DUNDI_COMMAND_EIDQUERY:
+ case DUNDI_COMMAND_PRECACHERQ:
+ if (cmd == DUNDI_COMMAND_EIDQUERY)
+ resp = DUNDI_COMMAND_EIDRESPONSE;
+ else if (cmd == DUNDI_COMMAND_PRECACHERQ)
+ resp = DUNDI_COMMAND_PRECACHERP;
+ else
+ resp = DUNDI_COMMAND_DPRESPONSE;
+ /* A dialplan or entity discover -- qualify by highest level entity */
+ peer = find_peer(ies.eids[0]);
+ if (!peer) {
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
+ dundi_send(trans, resp, 0, 1, &ied);
+ } else {
+ int hasauth = 0;
+ trans->us_eid = peer->us_eid;
+ if (strlen(peer->inkey)) {
+ hasauth = encrypted;
+ } else
+ hasauth = 1;
+ if (hasauth) {
+ /* Okay we're authentiated and all, now we check if they're authorized */
+ if (!ies.called_context)
+ ies.called_context = "e164";
+ if (cmd == DUNDI_COMMAND_EIDQUERY) {
+ res = dundi_answer_entity(trans, &ies, ies.called_context);
+ } else {
+ if (ast_strlen_zero(ies.called_number)) {
+ /* They're not permitted to access that context */
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity");
+ dundi_send(trans, resp, 0, 1, &ied);
+ } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) &&
+ (peer->model & DUNDI_MODEL_INBOUND) &&
+ has_permission(&peer->permit, ies.called_context)) {
+ res = dundi_answer_query(trans, &ies, ies.called_context);
+ if (res < 0) {
+ /* There is no such dundi context */
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
+ dundi_send(trans, resp, 0, 1, &ied);
+ }
+ } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) &&
+ (peer->pcmodel & DUNDI_MODEL_INBOUND) &&
+ has_permission(&peer->include, ies.called_context)) {
+ res = dundi_prop_precache(trans, &ies, ies.called_context);
+ if (res < 0) {
+ /* There is no such dundi context */
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context");
+ dundi_send(trans, resp, 0, 1, &ied);
+ }
+ } else {
+ /* They're not permitted to access that context */
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied");
+ dundi_send(trans, resp, 0, 1, &ied);
+ }
+ }
+ } else {
+ /* They're not permitted to access that context */
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted");
+ dundi_send(trans, resp, 0, 1, &ied);
+ }
+ }
+ break;
+ case DUNDI_COMMAND_REGREQ:
+ /* A register request -- should only have one entity */
+ peer = find_peer(ies.eids[0]);
+
+ /* if the peer is not found and we have a valid 'any_peer' setting */
+ if (any_peer && peer == any_peer) {
+ /* copy any_peer into a new peer object */
+ peer = ast_calloc(1, sizeof(*peer));
+ if (peer) {
+ deep_copy_peer(peer, any_peer);
+
+ /* set EID to remote EID */
+ peer->eid = *ies.eids[0];
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_INSERT_HEAD(&peers, peer, list);
+ AST_LIST_UNLOCK(&peers);
+ }
+ }
+
+ if (!peer || !peer->dynamic) {
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL);
+ dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, &ied);
+ } else {
+ int hasauth = 0;
+ trans->us_eid = peer->us_eid;
+ if (!ast_strlen_zero(peer->inkey)) {
+ hasauth = encrypted;
+ } else
+ hasauth = 1;
+ if (hasauth) {
+ int expire = default_expiration;
+ char data[256];
+ int needqual = 0;
+ if (peer->registerexpire > -1)
+ ast_sched_del(sched, peer->registerexpire);
+ peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
+ snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.sin_addr),
+ ntohs(trans->addr.sin_port), expire);
+ ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data);
+ if (inaddrcmp(&peer->addr, &trans->addr)) {
+ ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
+ ast_inet_ntoa(trans->addr.sin_addr), ntohs(trans->addr.sin_port));
+ needqual = 1;
+ }
+
+ memcpy(&peer->addr, &trans->addr, sizeof(peer->addr));
+ dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
+ dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, &ied);
+ if (needqual)
+ qualify_peer(peer, 1);
+ }
+ }
+ break;
+ case DUNDI_COMMAND_DPRESPONSE:
+ /* A dialplan response, lets see what we got... */
+ if (ies.cause < 1) {
+ /* Success of some sort */
+ ast_debug(1, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount);
+ if (ast_test_flag(trans, FLAG_ENCRYPT)) {
+ authpass = encrypted;
+ } else
+ authpass = 1;
+ if (authpass) {
+ /* Pass back up answers */
+ if (trans->parent && trans->parent->dr) {
+ y = trans->parent->respcount;
+ for (x=0;x<ies.anscount;x++) {
+ if (trans->parent->respcount < trans->parent->maxcount) {
+ /* Make sure it's not already there */
+ for (z=0;z<trans->parent->respcount;z++) {
+ if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) &&
+ !strcmp(trans->parent->dr[z].dest, (char *)ies.answers[x]->data))
+ break;
+ }
+ if (z == trans->parent->respcount) {
+ /* Copy into parent responses */
+ trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags);
+ trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol;
+ trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight);
+ trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid;
+ if (ies.expiration > 0)
+ trans->parent->dr[trans->parent->respcount].expiration = ies.expiration;
+ else
+ trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time;
+ dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str,
+ sizeof(trans->parent->dr[trans->parent->respcount].eid_str),
+ &ies.answers[x]->eid);
+ ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies.answers[x]->data,
+ sizeof(trans->parent->dr[trans->parent->respcount].dest));
+ ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol),
+ sizeof(trans->parent->dr[trans->parent->respcount].tech));
+ trans->parent->respcount++;
+ ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
+ } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) {
+ /* Update weight if appropriate */
+ trans->parent->dr[z].weight = ies.answers[x]->weight;
+ }
+ } else
+ ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n",
+ trans->parent->number, trans->parent->dcontext);
+ }
+ /* Save all the results (if any) we had. Even if no results, still cache lookup. Let
+ the cache know if this request was unaffected by our entity list. */
+ cache_save(&trans->them_eid, trans->parent, y,
+ ies.hint ? ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_UNAFFECTED)) : 0, ies.expiration, 0);
+ if (ies.hint) {
+ cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration);
+ if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED)))
+ ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED);
+ if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_DONT_ASK))) {
+ if (strlen((char *)ies.hint->data) > strlen(trans->parent->hmd->exten)) {
+ ast_copy_string(trans->parent->hmd->exten, (char *)ies.hint->data,
+ sizeof(trans->parent->hmd->exten));
+ }
+ } else {
+ ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK);
+ }
+ }
+ if (ies.expiration > 0) {
+ if (trans->parent->expiration > ies.expiration) {
+ trans->parent->expiration = ies.expiration;
+ }
+ }
+ }
+ /* Close connection if not final */
+ if (!final)
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+
+ } else {
+ /* Auth failure, check for data */
+ if (!final) {
+ /* Cancel if they didn't already */
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+ }
+ break;
+ case DUNDI_COMMAND_EIDRESPONSE:
+ /* A dialplan response, lets see what we got... */
+ if (ies.cause < 1) {
+ /* Success of some sort */
+ ast_debug(1, "Looks like success of some sort (%d)\n", ies.cause);
+ if (ast_test_flag(trans, FLAG_ENCRYPT)) {
+ authpass = encrypted;
+ } else
+ authpass = 1;
+ if (authpass) {
+ /* Pass back up answers */
+ if (trans->parent && trans->parent->dei && ies.q_org) {
+ if (!trans->parent->respcount) {
+ trans->parent->respcount++;
+ if (ies.q_dept)
+ ast_copy_string(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit));
+ if (ies.q_org)
+ ast_copy_string(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org));
+ if (ies.q_locality)
+ ast_copy_string(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality));
+ if (ies.q_stateprov)
+ ast_copy_string(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov));
+ if (ies.q_country)
+ ast_copy_string(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country));
+ if (ies.q_email)
+ ast_copy_string(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email));
+ if (ies.q_phone)
+ ast_copy_string(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone));
+ if (ies.q_ipaddr)
+ ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr));
+ if (!dundi_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) {
+ /* If it's them, update our address */
+ ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.sin_addr), sizeof(trans->parent->dei->ipaddr));
+ }
+ }
+ if (ies.hint) {
+ if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED)))
+ ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED);
+ }
+ }
+ /* Close connection if not final */
+ if (!final)
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+
+ } else {
+ /* Auth failure, check for data */
+ if (!final) {
+ /* Cancel if they didn't already */
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+ }
+ break;
+ case DUNDI_COMMAND_REGRESPONSE:
+ /* A dialplan response, lets see what we got... */
+ if (ies.cause < 1) {
+ int hasauth;
+ /* Success of some sort */
+ if (ast_test_flag(trans, FLAG_ENCRYPT)) {
+ hasauth = encrypted;
+ } else
+ hasauth = 1;
+
+ if (!hasauth) {
+ ast_log(LOG_NOTICE, "Reponse to register not authorized!\n");
+ if (!final) {
+ dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer");
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, &ied);
+ }
+ } else {
+ ast_debug(1, "Yay, we've registered as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid),
+ dundi_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid));
+ /* Close connection if not final */
+ if (!final)
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+ } else {
+ /* Auth failure, cancel if they didn't for some reason */
+ if (!final) {
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+ }
+ break;
+ case DUNDI_COMMAND_INVALID:
+ case DUNDI_COMMAND_NULL:
+ case DUNDI_COMMAND_PRECACHERP:
+ /* Do nothing special */
+ if (!final)
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ break;
+ case DUNDI_COMMAND_ENCREJ:
+ if ((ast_test_flag(trans, FLAG_SENDFULLKEY)) || AST_LIST_EMPTY(&trans->lasttrans) || !(peer = find_peer(&trans->them_eid))) {
+ /* No really, it's over at this point */
+ if (!final)
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ } else {
+ /* Send with full key */
+ ast_set_flag(trans, FLAG_SENDFULLKEY);
+ if (final) {
+ /* Ooops, we got a final message, start by sending ACK... */
+ dundi_ack(trans, hdr->cmdresp & 0x80);
+ trans->aseqno = trans->iseqno;
+ /* Now, we gotta create a new transaction */
+ if (!reset_transaction(trans)) {
+ /* Make sure handle_frame doesn't destroy us */
+ hdr->cmdresp &= 0x7f;
+ /* Parse the message we transmitted */
+ memset(&ies, 0, sizeof(ies));
+ dundi_parse_ies(&ies, (AST_LIST_FIRST(&trans->lasttrans))->h->ies, (AST_LIST_FIRST(&trans->lasttrans))->datalen - sizeof(struct dundi_hdr));
+ /* Reconstruct outgoing encrypted packet */
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
+ dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128);
+ dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128);
+ if (ies.encblock)
+ dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen);
+ dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, (AST_LIST_FIRST(&trans->lasttrans))->h->cmdresp & 0x80, &ied);
+ peer->sentfullkey = 1;
+ }
+ }
+ }
+ break;
+ case DUNDI_COMMAND_ENCRYPT:
+ if (!encrypted) {
+ /* No nested encryption! */
+ if ((trans->iseqno == 1) && !trans->oseqno) {
+ if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) ||
+ ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) ||
+ (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) {
+ if (!final) {
+ dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
+ }
+ break;
+ }
+ apply_peer(trans, peer);
+ /* Key passed, use new contexts for this session */
+ trans->ecx = peer->them_ecx;
+ trans->dcx = peer->them_dcx;
+ }
+ if (ast_test_flag(trans, FLAG_ENCRYPT) && ies.encblock && ies.enclen) {
+ struct dundi_hdr *dhdr;
+ unsigned char decoded[MAX_PACKET_SIZE];
+ int ddatalen;
+ ddatalen = sizeof(decoded);
+ dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen);
+ if (dhdr) {
+ /* Handle decrypted response */
+ if (dundidebug)
+ dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr));
+ handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1);
+ /* Carry back final flag */
+ hdr->cmdresp |= dhdr->cmdresp & 0x80;
+ break;
+ } else {
+ ast_debug(1, "Ouch, decrypt failed :(\n");
+ }
+ }
+ }
+ if (!final) {
+ /* Turn off encryption */
+ ast_clear_flag(trans, FLAG_ENCRYPT);
+ dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL);
+ }
+ break;
+ default:
+ /* Send unknown command if we don't know it, with final flag IFF it's the
+ first command in the dialog and only if we haven't recieved final notification */
+ if (!final) {
+ dundi_ie_append_byte(&ied, DUNDI_IE_UNKNOWN, cmd);
+ dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, &ied);
+ }
+ }
+ return 0;
+}
+
+static void destroy_packet(struct dundi_packet *pack, int needfree);
+static void destroy_packets(struct packetlist *p)
+{
+ struct dundi_packet *pack;
+
+ while ((pack = AST_LIST_REMOVE_HEAD(p, list))) {
+ if (pack->retransid > -1)
+ ast_sched_del(sched, pack->retransid);
+ ast_free(pack);
+ }
+}
+
+
+static int ack_trans(struct dundi_transaction *trans, int iseqno)
+{
+ struct dundi_packet *pack;
+
+ /* Ack transmitted packet corresponding to iseqno */
+ AST_LIST_TRAVERSE(&trans->packets, pack, list) {
+ if ((pack->h->oseqno + 1) % 255 == iseqno) {
+ destroy_packet(pack, 0);
+ if (!AST_LIST_EMPTY(&trans->lasttrans)) {
+ ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n");
+ destroy_packets(&trans->lasttrans);
+ }
+ AST_LIST_INSERT_HEAD(&trans->lasttrans, pack, list);
+ if (trans->autokillid > -1)
+ ast_sched_del(sched, trans->autokillid);
+ trans->autokillid = -1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datalen)
+{
+ struct dundi_transaction *trans;
+ trans = find_transaction(h, sin);
+ if (!trans) {
+ dundi_reject(h, sin);
+ return 0;
+ }
+ /* Got a transaction, see where this header fits in */
+ if (h->oseqno == trans->iseqno) {
+ /* Just what we were looking for... Anything but ack increments iseqno */
+ if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) {
+ /* If final, we're done */
+ destroy_trans(trans, 0);
+ return 0;
+ }
+ if (h->cmdresp != DUNDI_COMMAND_ACK) {
+ trans->oiseqno = trans->iseqno;
+ trans->iseqno++;
+ handle_command_response(trans, h, datalen, 0);
+ }
+ if (trans->aseqno != trans->iseqno) {
+ dundi_ack(trans, h->cmdresp & 0x80);
+ trans->aseqno = trans->iseqno;
+ }
+ /* Delete any saved last transmissions */
+ destroy_packets(&trans->lasttrans);
+ if (h->cmdresp & 0x80) {
+ /* Final -- destroy now */
+ destroy_trans(trans, 0);
+ }
+ } else if (h->oseqno == trans->oiseqno) {
+ /* Last incoming sequence number -- send ACK without processing */
+ dundi_ack(trans, 0);
+ } else {
+ /* Out of window -- simply drop */
+ ast_debug(1, "Dropping packet out of window!\n");
+ }
+ return 0;
+}
+
+static int socket_read(int *id, int fd, short events, void *cbdata)
+{
+ struct sockaddr_in sin;
+ int res;
+ struct dundi_hdr *h;
+ char buf[MAX_PACKET_SIZE];
+ socklen_t len = sizeof(sin);
+
+ res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);
+ if (res < 0) {
+ if (errno != ECONNREFUSED)
+ ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
+ return 1;
+ }
+ if (res < sizeof(struct dundi_hdr)) {
+ ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr));
+ return 1;
+ }
+ buf[res] = '\0';
+ h = (struct dundi_hdr *) buf;
+ if (dundidebug)
+ dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr));
+ AST_LIST_LOCK(&peers);
+ handle_frame(h, &sin, res - sizeof(struct dundi_hdr));
+ AST_LIST_UNLOCK(&peers);
+ return 1;
+}
+
+static void build_secret(char *secret, int seclen)
+{
+ unsigned char tmp[16];
+ char *s;
+ build_iv(tmp);
+ secret[0] = '\0';
+ ast_base64encode(secret, tmp, sizeof(tmp), seclen);
+ /* Eliminate potential bad characters */
+ while((s = strchr(secret, ';'))) *s = '+';
+ while((s = strchr(secret, '/'))) *s = '+';
+ while((s = strchr(secret, ':'))) *s = '+';
+ while((s = strchr(secret, '@'))) *s = '+';
+}
+
+
+static void save_secret(const char *newkey, const char *oldkey)
+{
+ char tmp[256];
+ if (oldkey)
+ snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey);
+ else
+ snprintf(tmp, sizeof(tmp), "%s", newkey);
+ rotatetime = time(NULL) + DUNDI_SECRET_TIME;
+ ast_db_put(secretpath, "secret", tmp);
+ snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime);
+ ast_db_put(secretpath, "secretexpiry", tmp);
+}
+
+static void load_password(void)
+{
+ char *current=NULL;
+ char *last=NULL;
+ char tmp[256];
+ time_t expired;
+
+ ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp));
+ if (!ast_get_time_t(tmp, &expired, 0, NULL)) {
+ ast_db_get(secretpath, "secret", tmp, sizeof(tmp));
+ current = strchr(tmp, ';');
+ if (!current)
+ current = tmp;
+ else {
+ *current = '\0';
+ current++;
+ };
+ if ((time(NULL) - expired) < 0) {
+ if ((expired - time(NULL)) > DUNDI_SECRET_TIME)
+ expired = time(NULL) + DUNDI_SECRET_TIME;
+ } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) {
+ last = current;
+ current = NULL;
+ } else {
+ last = NULL;
+ current = NULL;
+ }
+ }
+ if (current) {
+ /* Current key is still valid, just setup rotatation properly */
+ ast_copy_string(cursecret, current, sizeof(cursecret));
+ rotatetime = expired;
+ } else {
+ /* Current key is out of date, rotate or eliminate all together */
+ build_secret(cursecret, sizeof(cursecret));
+ save_secret(cursecret, last);
+ }
+}
+
+static void check_password(void)
+{
+ char oldsecret[80];
+ time_t now;
+
+ time(&now);
+#if 0
+ printf("%ld/%ld\n", now, rotatetime);
+#endif
+ if ((now - rotatetime) >= 0) {
+ /* Time to rotate keys */
+ ast_copy_string(oldsecret, cursecret, sizeof(oldsecret));
+ build_secret(cursecret, sizeof(cursecret));
+ save_secret(cursecret, oldsecret);
+ }
+}
+
+static void *network_thread(void *ignore)
+{
+ /* Our job is simple: Send queued messages, retrying if necessary. Read frames
+ from the network, and queue them for delivery to the channels */
+ int res;
+ /* Establish I/O callback for socket read */
+ ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
+
+ while (!dundi_shutdown) {
+ res = ast_sched_wait(sched);
+ if ((res > 1000) || (res < 0))
+ res = 1000;
+ res = ast_io_wait(io, res);
+ if (res >= 0) {
+ AST_LIST_LOCK(&peers);
+ ast_sched_runq(sched);
+ AST_LIST_UNLOCK(&peers);
+ }
+ check_password();
+ }
+
+ netthreadid = AST_PTHREADT_NULL;
+
+ return NULL;
+}
+
+static void *process_precache(void *ign)
+{
+ struct dundi_precache_queue *qe;
+ time_t now;
+ char context[256];
+ char number[256];
+ int run;
+
+ while (!dundi_shutdown) {
+ time(&now);
+ run = 0;
+ AST_LIST_LOCK(&pcq);
+ if ((qe = AST_LIST_FIRST(&pcq))) {
+ if (!qe->expiration) {
+ /* Gone... Remove... */
+ AST_LIST_REMOVE_HEAD(&pcq, list);
+ ast_free(qe);
+ } else if (qe->expiration < now) {
+ /* Process this entry */
+ qe->expiration = 0;
+ ast_copy_string(context, qe->context, sizeof(context));
+ ast_copy_string(number, qe->number, sizeof(number));
+ run = 1;
+ }
+ }
+ AST_LIST_UNLOCK(&pcq);
+ if (run) {
+ dundi_precache(context, number);
+ } else
+ sleep(1);
+ }
+
+ precachethreadid = AST_PTHREADT_NULL;
+
+ return NULL;
+}
+
+static int start_network_thread(void)
+{
+ ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL);
+ ast_pthread_create_background(&precachethreadid, NULL, process_precache, NULL);
+ return 0;
+}
+
+static char *dundi_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi debug";
+ e->usage =
+ "Usage: dundi debug\n"
+ " Enables dumping of DUNDi packets for debugging purposes\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 2)
+ return CLI_SHOWUSAGE;
+ dundidebug = 1;
+ ast_cli(a->fd, "DUNDi Debugging Enabled\n");
+ return CLI_SUCCESS;
+}
+
+static char *dundi_do_store_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi store history";
+ e->usage =
+ "Usage: dundi store history\n"
+ " Enables storing of DUNDi requests and times for debugging\n"
+ "purposes\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ global_storehistory = 1;
+ ast_cli(a->fd, "DUNDi History Storage Enabled\n");
+ return CLI_SUCCESS;
+}
+
+static char *dundi_flush(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int stats = 0;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi flush [stats]";
+ e->usage =
+ "Usage: dundi flush [stats]\n"
+ " Flushes DUNDi answer cache, used primarily for debug. If\n"
+ "'stats' is present, clears timer statistics instead of normal\n"
+ "operation.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if ((a->argc < 2) || (a->argc > 3))
+ return CLI_SHOWUSAGE;
+ if (a->argc > 2) {
+ if (!strcasecmp(a->argv[2], "stats"))
+ stats = 1;
+ else
+ return CLI_SHOWUSAGE;
+ }
+ if (stats) {
+ /* Flush statistics */
+ struct dundi_peer *p;
+ int x;
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&peers, p, list) {
+ for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
+ if (p->lookups[x])
+ ast_free(p->lookups[x]);
+ p->lookups[x] = NULL;
+ p->lookuptimes[x] = 0;
+ }
+ p->avgms = 0;
+ }
+ AST_LIST_UNLOCK(&peers);
+ } else {
+ ast_db_deltree("dundi/cache", NULL);
+ ast_cli(a->fd, "DUNDi Cache Flushed\n");
+ }
+ return CLI_SUCCESS;
+}
+
+static char *dundi_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi no debug";
+ e->usage =
+ "Usage: dundi no debug\n"
+ " Disables dumping of DUNDi packets for debugging purposes\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ dundidebug = 0;
+ ast_cli(a->fd, "DUNDi Debugging Disabled\n");
+ return CLI_SUCCESS;
+}
+
+static char *dundi_no_store_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi no store history";
+ e->usage =
+ "Usage: dundi no store history\n"
+ " Disables storing of DUNDi requests and times for debugging\n"
+ "purposes\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 4)
+ return CLI_SHOWUSAGE;
+ global_storehistory = 0;
+ ast_cli(a->fd, "DUNDi History Storage Disabled\n");
+ return CLI_SUCCESS;
+}
+
+static char *model2str(int model)
+{
+ switch(model) {
+ case DUNDI_MODEL_INBOUND:
+ return "Inbound";
+ case DUNDI_MODEL_OUTBOUND:
+ return "Outbound";
+ case DUNDI_MODEL_SYMMETRIC:
+ return "Symmetric";
+ default:
+ return "Unknown";
+ }
+}
+
+static char *complete_peer_helper(const char *line, const char *word, int pos, int state, int rpos)
+{
+ int which=0, len;
+ char *ret = NULL;
+ struct dundi_peer *p;
+ char eid_str[20];
+
+ if (pos != rpos)
+ return NULL;
+ AST_LIST_LOCK(&peers);
+ len = strlen(word);
+ AST_LIST_TRAVERSE(&peers, p, list) {
+ const char *s = dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid);
+ if (!strncasecmp(word, s, len) && ++which > state) {
+ ret = ast_strdup(s);
+ break;
+ }
+ }
+ AST_LIST_UNLOCK(&peers);
+ return ret;
+}
+
+static int rescomp(const void *a, const void *b)
+{
+ const struct dundi_result *resa, *resb;
+ resa = a;
+ resb = b;
+ if (resa->weight < resb->weight)
+ return -1;
+ if (resa->weight > resb->weight)
+ return 1;
+ return 0;
+}
+
+static void sort_results(struct dundi_result *results, int count)
+{
+ qsort(results, count, sizeof(results[0]), rescomp);
+}
+
+static char *dundi_do_lookup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int res;
+ char tmp[256];
+ char fs[80] = "";
+ char *context;
+ int x;
+ int bypass = 0;
+ struct dundi_result dr[MAX_RESULTS];
+ struct timeval start;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi lookup";
+ e->usage =
+ "Usage: dundi lookup <number>[@context] [bypass]\n"
+ " Lookup the given number within the given DUNDi context\n"
+ "(or e164 if none is specified). Bypasses cache if 'bypass'\n"
+ "keyword is specified.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if ((a->argc < 3) || (a->argc > 4))
+ return CLI_SHOWUSAGE;
+ if (a->argc > 3) {
+ if (!strcasecmp(a->argv[3], "bypass"))
+ bypass=1;
+ else
+ return CLI_SHOWUSAGE;
+ }
+ ast_copy_string(tmp, a->argv[2], sizeof(tmp));
+ context = strchr(tmp, '@');
+ if (context) {
+ *context = '\0';
+ context++;
+ }
+ start = ast_tvnow();
+ res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
+
+ if (res < 0)
+ ast_cli(a->fd, "DUNDi lookup returned error.\n");
+ else if (!res)
+ ast_cli(a->fd, "DUNDi lookup returned no results.\n");
+ else
+ sort_results(dr, res);
+ for (x=0;x<res;x++) {
+ ast_cli(a->fd, "%3d. %5d %s/%s (%s)\n", x + 1, dr[x].weight, dr[x].tech, dr[x].dest, dundi_flags2str(fs, sizeof(fs), dr[x].flags));
+ ast_cli(a->fd, " from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
+ }
+ ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
+ return CLI_SUCCESS;
+}
+
+static char *dundi_do_precache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int res;
+ char tmp[256];
+ char *context;
+ struct timeval start;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi precache";
+ e->usage =
+ "Usage: dundi precache <number>[@context]\n"
+ " Lookup the given number within the given DUNDi context\n"
+ "(or e164 if none is specified) and precaches the results to any\n"
+ "upstream DUNDi push servers.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if ((a->argc < 3) || (a->argc > 3))
+ return CLI_SHOWUSAGE;
+ ast_copy_string(tmp, a->argv[2], sizeof(tmp));
+ context = strchr(tmp, '@');
+ if (context) {
+ *context = '\0';
+ context++;
+ }
+ start = ast_tvnow();
+ res = dundi_precache(context, tmp);
+
+ if (res < 0)
+ ast_cli(a->fd, "DUNDi precache returned error.\n");
+ else if (!res)
+ ast_cli(a->fd, "DUNDi precache returned no error.\n");
+ ast_cli(a->fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
+ return CLI_SUCCESS;
+}
+
+static char *dundi_do_query(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int res;
+ char tmp[256];
+ char *context;
+ dundi_eid eid;
+ struct dundi_entity_info dei;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi query";
+ e->usage =
+ "Usage: dundi query <entity>[@context]\n"
+ " Attempts to retrieve contact information for a specific\n"
+ "DUNDi entity identifier (EID) within a given DUNDi context (or\n"
+ "e164 if none is specified).\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if ((a->argc < 3) || (a->argc > 3))
+ return CLI_SHOWUSAGE;
+ if (dundi_str_to_eid(&eid, a->argv[2])) {
+ ast_cli(a->fd, "'%s' is not a valid EID!\n", a->argv[2]);
+ return CLI_SHOWUSAGE;
+ }
+ ast_copy_string(tmp, a->argv[2], sizeof(tmp));
+ context = strchr(tmp, '@');
+ if (context) {
+ *context = '\0';
+ context++;
+ }
+ res = dundi_query_eid(&dei, context, eid);
+ if (res < 0)
+ ast_cli(a->fd, "DUNDi Query EID returned error.\n");
+ else if (!res)
+ ast_cli(a->fd, "DUNDi Query EID returned no results.\n");
+ else {
+ ast_cli(a->fd, "DUNDi Query EID succeeded:\n");
+ ast_cli(a->fd, "Department: %s\n", dei.orgunit);
+ ast_cli(a->fd, "Organization: %s\n", dei.org);
+ ast_cli(a->fd, "City/Locality: %s\n", dei.locality);
+ ast_cli(a->fd, "State/Province: %s\n", dei.stateprov);
+ ast_cli(a->fd, "Country: %s\n", dei.country);
+ ast_cli(a->fd, "E-mail: %s\n", dei.email);
+ ast_cli(a->fd, "Phone: %s\n", dei.phone);
+ ast_cli(a->fd, "IP Address: %s\n", dei.ipaddr);
+ }
+ return CLI_SUCCESS;
+}
+
+static char *dundi_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct dundi_peer *peer;
+ struct permission *p;
+ char *order;
+ char eid_str[20];
+ int x, cnt;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show peer";
+ e->usage =
+ "Usage: dundi show peer [peer]\n"
+ " Provide a detailed description of a specifid DUNDi peer.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_peer_helper(a->line, a->word, a->pos, a->n, 3);
+ }
+ if (a->argc != 4)
+ return CLI_SHOWUSAGE;
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&peers, peer, list) {
+ if (!strcasecmp(dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), a->argv[3]))
+ break;
+ }
+ if (peer) {
+ switch(peer->order) {
+ case 0:
+ order = "Primary";
+ break;
+ case 1:
+ order = "Secondary";
+ break;
+ case 2:
+ order = "Tertiary";
+ break;
+ case 3:
+ order = "Quartiary";
+ break;
+ default:
+ order = "Unknown";
+ }
+ ast_cli(a->fd, "Peer: %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ ast_cli(a->fd, "Model: %s\n", model2str(peer->model));
+ ast_cli(a->fd, "Host: %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");
+ ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");
+ ast_cli(a->fd, "Reg: %s\n", peer->registerid < 0 ? "No" : "Yes");
+ ast_cli(a->fd, "In Key: %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);
+ ast_cli(a->fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey);
+ if (!AST_LIST_EMPTY(&peer->include))
+ ast_cli(a->fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)");
+ AST_LIST_TRAVERSE(&peer->include, p, list)
+ ast_cli(a->fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name);
+ if (!AST_LIST_EMPTY(&peer->permit))
+ ast_cli(a->fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)");
+ AST_LIST_TRAVERSE(&peer->permit, p, list)
+ ast_cli(a->fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name);
+ cnt = 0;
+ for (x = 0;x < DUNDI_TIMING_HISTORY; x++) {
+ if (peer->lookups[x]) {
+ if (!cnt)
+ ast_cli(a->fd, "Last few query times:\n");
+ ast_cli(a->fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]);
+ cnt++;
+ }
+ }
+ if (cnt)
+ ast_cli(a->fd, "Average query time: %d ms\n", peer->avgms);
+ } else
+ ast_cli(a->fd, "No such peer '%s'\n", a->argv[3]);
+ AST_LIST_UNLOCK(&peers);
+ return CLI_SUCCESS;
+}
+
+static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n"
+#define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n"
+ struct dundi_peer *peer;
+ int registeredonly=0;
+ char avgms[20];
+ char eid_str[20];
+ int online_peers = 0;
+ int offline_peers = 0;
+ int unmonitored_peers = 0;
+ int total_peers = 0;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show peers [registered|include|exclude|begin]";
+ e->usage =
+ "Usage: dundi show peers [registered|include|exclude|begin]\n"
+ " Lists all known DUNDi peers.\n"
+ " If 'registered' is present, only registered peers are shown.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if ((a->argc != 3) && (a->argc != 4) && (a->argc != 5))
+ return CLI_SHOWUSAGE;
+ if ((a->argc == 4)) {
+ if (!strcasecmp(a->argv[3], "registered")) {
+ registeredonly = 1;
+ } else
+ return CLI_SHOWUSAGE;
+ }
+ AST_LIST_LOCK(&peers);
+ ast_cli(a->fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status");
+ AST_LIST_TRAVERSE(&peers, peer, list) {
+ char status[20];
+ int print_line = -1;
+ char srch[2000];
+ total_peers++;
+ if (registeredonly && !peer->addr.sin_addr.s_addr)
+ continue;
+ if (peer->maxms) {
+ if (peer->lastms < 0) {
+ strcpy(status, "UNREACHABLE");
+ offline_peers++;
+ }
+ else if (peer->lastms > peer->maxms) {
+ snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
+ offline_peers++;
+ }
+ else if (peer->lastms) {
+ snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
+ online_peers++;
+ }
+ else {
+ strcpy(status, "UNKNOWN");
+ offline_peers++;
+ }
+ } else {
+ strcpy(status, "Unmonitored");
+ unmonitored_peers++;
+ }
+ if (peer->avgms)
+ snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);
+ else
+ strcpy(avgms, "Unavail");
+ snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
+ peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
+ peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
+
+ if (a->argc == 5) {
+ if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) {
+ print_line = -1;
+ } else if (!strcasecmp(a->argv[3],"exclude") && !strstr(srch,a->argv[4])) {
+ print_line = 1;
+ } else if (!strcasecmp(a->argv[3],"begin") && !strncasecmp(srch,a->argv[4],strlen(a->argv[4]))) {
+ print_line = -1;
+ } else {
+ print_line = 0;
+ }
+ }
+
+ if (print_line) {
+ ast_cli(a->fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),
+ peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
+ peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status);
+ }
+ }
+ ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);
+ AST_LIST_UNLOCK(&peers);
+ return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
+static char *dundi_show_trans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n"
+#define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n"
+ struct dundi_transaction *trans;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show trans";
+ e->usage =
+ "Usage: dundi show trans\n"
+ " Lists all known DUNDi transactions.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ AST_LIST_LOCK(&peers);
+ ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");
+ AST_LIST_TRAVERSE(&alltrans, trans, all) {
+ ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr),
+ ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);
+ }
+ AST_LIST_UNLOCK(&peers);
+ return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
+static char *dundi_show_entityid(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char eid_str[20];
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show entityid";
+ e->usage =
+ "Usage: dundi show entityid\n"
+ " Displays the global entityid for this host.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ AST_LIST_LOCK(&peers);
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid);
+ AST_LIST_UNLOCK(&peers);
+ ast_cli(a->fd, "Global EID for this system is '%s'\n", eid_str);
+ return CLI_SUCCESS;
+}
+
+static char *dundi_show_requests(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n"
+#define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n"
+ struct dundi_request *req;
+ char eidstr[20];
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show requests";
+ e->usage =
+ "Usage: dundi show requests\n"
+ " Lists all known pending DUNDi requests.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ AST_LIST_LOCK(&peers);
+ ast_cli(a->fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp");
+ AST_LIST_TRAVERSE(&requests, req, list) {
+ ast_cli(a->fd, FORMAT, req->number, req->dcontext,
+ dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount);
+ }
+ AST_LIST_UNLOCK(&peers);
+ return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
+/* Grok-a-dial DUNDi */
+
+static char *dundi_show_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
+#define FORMAT "%-12.12s %-7s %-12.12s %-10.10s %-5.5s %-25.25s\n"
+ struct dundi_mapping *map;
+ char fs[256];
+ char weight[8];
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show mappings";
+ e->usage =
+ "Usage: dundi show mappings\n"
+ " Lists all known DUNDi mappings.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ AST_LIST_LOCK(&peers);
+ ast_cli(a->fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination");
+ AST_LIST_TRAVERSE(&mappings, map, list) {
+ snprintf(weight, sizeof(weight), "%d", get_mapping_weight(map));
+ ast_cli(a->fd, FORMAT, map->dcontext, weight,
+ ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext,
+ dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest);
+ }
+ AST_LIST_UNLOCK(&peers);
+ return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
+static char *dundi_show_precache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT2 "%-12.12s %-12.12s %-10.10s\n"
+#define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n"
+ struct dundi_precache_queue *qe;
+ int h,m,s;
+ time_t now;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "dundi show precache";
+ e->usage =
+ "Usage: dundi show precache\n"
+ " Lists all known DUNDi scheduled precache updates.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ time(&now);
+ ast_cli(a->fd, FORMAT2, "Number", "Context", "Expiration");
+ AST_LIST_LOCK(&pcq);
+ AST_LIST_TRAVERSE(&pcq, qe, list) {
+ s = qe->expiration - now;
+ h = s / 3600;
+ s = s % 3600;
+ m = s / 60;
+ s = s % 60;
+ ast_cli(a->fd, FORMAT, qe->number, qe->context, h,m,s);
+ }
+ AST_LIST_UNLOCK(&pcq);
+
+ return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
+static struct ast_cli_entry cli_dundi[] = {
+ AST_CLI_DEFINE(dundi_do_debug, "Enable DUNDi debugging"),
+ AST_CLI_DEFINE(dundi_no_debug, "Disable DUNDi debugging"),
+ AST_CLI_DEFINE(dundi_do_store_history, "Enable DUNDi historic records"),
+ AST_CLI_DEFINE(dundi_no_store_history, "Disable DUNDi historic records"),
+ AST_CLI_DEFINE(dundi_flush, "Flush DUNDi cache"),
+ AST_CLI_DEFINE(dundi_show_peers, "Show defined DUNDi peers"),
+ AST_CLI_DEFINE(dundi_show_trans, "Show active DUNDi transactions"),
+ AST_CLI_DEFINE(dundi_show_entityid, "Display Global Entity ID"),
+ AST_CLI_DEFINE(dundi_show_mappings, "Show DUNDi mappings"),
+ AST_CLI_DEFINE(dundi_show_precache, "Show DUNDi precache"),
+ AST_CLI_DEFINE(dundi_show_requests, "Show DUNDi requests"),
+ AST_CLI_DEFINE(dundi_show_peer, "Show info on a specific DUNDi peer"),
+ AST_CLI_DEFINE(dundi_do_precache, "Precache a number in DUNDi"),
+ AST_CLI_DEFINE(dundi_do_lookup, "Lookup a number in DUNDi"),
+ AST_CLI_DEFINE(dundi_do_query, "Query a DUNDi EID"),
+};
+
+static struct dundi_transaction *create_transaction(struct dundi_peer *p)
+{
+ struct dundi_transaction *trans;
+ int tid;
+
+ /* Don't allow creation of transactions to non-registered peers */
+ if (p && !p->addr.sin_addr.s_addr)
+ return NULL;
+ tid = get_trans_id();
+ if (tid < 1)
+ return NULL;
+ if (!(trans = ast_calloc(1, sizeof(*trans))))
+ return NULL;
+
+ if (global_storehistory) {
+ trans->start = ast_tvnow();
+ ast_set_flag(trans, FLAG_STOREHIST);
+ }
+ trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
+ trans->autokillid = -1;
+ if (p) {
+ apply_peer(trans, p);
+ if (!p->sentfullkey)
+ ast_set_flag(trans, FLAG_SENDFULLKEY);
+ }
+ trans->strans = tid;
+ AST_LIST_INSERT_HEAD(&alltrans, trans, all);
+
+ return trans;
+}
+
+static int dundi_xmit(struct dundi_packet *pack)
+{
+ int res;
+ if (dundidebug)
+ dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));
+ res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",
+ ast_inet_ntoa(pack->parent->addr.sin_addr),
+ ntohs(pack->parent->addr.sin_port), strerror(errno));
+ }
+ if (res > 0)
+ res = 0;
+ return res;
+}
+
+static void destroy_packet(struct dundi_packet *pack, int needfree)
+{
+ if (pack->parent)
+ AST_LIST_REMOVE(&pack->parent->packets, pack, list);
+ if (pack->retransid > -1)
+ ast_sched_del(sched, pack->retransid);
+ if (needfree)
+ ast_free(pack);
+ else
+ pack->retransid = -1;
+}
+
+static void destroy_trans(struct dundi_transaction *trans, int fromtimeout)
+{
+ struct dundi_peer *peer;
+ int ms;
+ int x;
+ int cnt;
+ char eid_str[20];
+ if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) {
+ AST_LIST_TRAVERSE(&peers, peer, list) {
+ if (peer->regtrans == trans)
+ peer->regtrans = NULL;
+ if (peer->qualtrans == trans) {
+ if (fromtimeout) {
+ if (peer->lastms > -1)
+ ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ peer->lastms = -1;
+ } else {
+ ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
+ if (ms < 1)
+ ms = 1;
+ if (ms < peer->maxms) {
+ if ((peer->lastms >= peer->maxms) || (peer->lastms < 0))
+ ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ } else if (peer->lastms < peer->maxms) {
+ ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms);
+ }
+ peer->lastms = ms;
+ }
+ peer->qualtrans = NULL;
+ }
+ if (ast_test_flag(trans, FLAG_STOREHIST)) {
+ if (trans->parent && !ast_strlen_zero(trans->parent->number)) {
+ if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) {
+ peer->avgms = 0;
+ cnt = 0;
+ if (peer->lookups[DUNDI_TIMING_HISTORY-1])
+ ast_free(peer->lookups[DUNDI_TIMING_HISTORY-1]);
+ for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) {
+ peer->lookuptimes[x] = peer->lookuptimes[x-1];
+ peer->lookups[x] = peer->lookups[x-1];
+ if (peer->lookups[x]) {
+ peer->avgms += peer->lookuptimes[x];
+ cnt++;
+ }
+ }
+ peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
+ peer->lookups[0] = ast_malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
+ if (peer->lookups[0]) {
+ sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
+ peer->avgms += peer->lookuptimes[0];
+ cnt++;
+ }
+ if (cnt)
+ peer->avgms /= cnt;
+ }
+ }
+ }
+ }
+ }
+ if (trans->parent) {
+ /* Unlink from parent if appropriate */
+ AST_LIST_REMOVE(&trans->parent->trans, trans, parentlist);
+ if (AST_LIST_EMPTY(&trans->parent->trans)) {
+ /* Wake up sleeper */
+ if (trans->parent->pfds[1] > -1) {
+ write(trans->parent->pfds[1], "killa!", 6);
+ }
+ }
+ }
+ /* Unlink from all trans */
+ AST_LIST_REMOVE(&alltrans, trans, all);
+ destroy_packets(&trans->packets);
+ destroy_packets(&trans->lasttrans);
+ if (trans->autokillid > -1)
+ ast_sched_del(sched, trans->autokillid);
+ trans->autokillid = -1;
+ if (trans->thread) {
+ /* If used by a thread, mark as dead and be done */
+ ast_set_flag(trans, FLAG_DEAD);
+ } else
+ ast_free(trans);
+}
+
+static int dundi_rexmit(const void *data)
+{
+ struct dundi_packet *pack = (struct dundi_packet *)data;
+ int res;
+ AST_LIST_LOCK(&peers);
+ if (pack->retrans < 1) {
+ pack->retransid = -1;
+ if (!ast_test_flag(pack->parent, FLAG_ISQUAL))
+ ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",
+ ast_inet_ntoa(pack->parent->addr.sin_addr),
+ ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));
+ destroy_trans(pack->parent, 1);
+ res = 0;
+ } else {
+ /* Decrement retransmission, try again */
+ pack->retrans--;
+ dundi_xmit(pack);
+ res = 1;
+ }
+ AST_LIST_UNLOCK(&peers);
+ return res;
+}
+
+static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied)
+{
+ struct dundi_packet *pack;
+ int res;
+ int len;
+ char eid_str[20];
+ len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0);
+ /* Reserve enough space for encryption */
+ if (ast_test_flag(trans, FLAG_ENCRYPT))
+ len += 384;
+ pack = ast_calloc(1, len);
+ if (pack) {
+ pack->h = (struct dundi_hdr *)(pack->data);
+ if (cmdresp != DUNDI_COMMAND_ACK) {
+ pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack);
+ pack->retrans = DUNDI_DEFAULT_RETRANS - 1;
+ AST_LIST_INSERT_HEAD(&trans->packets, pack, list);
+ }
+ pack->parent = trans;
+ pack->h->strans = htons(trans->strans);
+ pack->h->dtrans = htons(trans->dtrans);
+ pack->h->iseqno = trans->iseqno;
+ pack->h->oseqno = trans->oseqno;
+ pack->h->cmdresp = cmdresp;
+ pack->datalen = sizeof(struct dundi_hdr);
+ if (ied) {
+ memcpy(pack->h->ies, ied->buf, ied->pos);
+ pack->datalen += ied->pos;
+ }
+ if (final) {
+ pack->h->cmdresp |= DUNDI_COMMAND_FINAL;
+ ast_set_flag(trans, FLAG_FINAL);
+ }
+ pack->h->cmdflags = flags;
+ if (cmdresp != DUNDI_COMMAND_ACK) {
+ trans->oseqno++;
+ trans->oseqno = trans->oseqno % 256;
+ }
+ trans->aseqno = trans->iseqno;
+ /* If we have their public key, encrypt */
+ if (ast_test_flag(trans, FLAG_ENCRYPT)) {
+ switch(cmdresp) {
+ case DUNDI_COMMAND_REGREQ:
+ case DUNDI_COMMAND_REGRESPONSE:
+ case DUNDI_COMMAND_DPDISCOVER:
+ case DUNDI_COMMAND_DPRESPONSE:
+ case DUNDI_COMMAND_EIDQUERY:
+ case DUNDI_COMMAND_EIDRESPONSE:
+ case DUNDI_COMMAND_PRECACHERQ:
+ case DUNDI_COMMAND_PRECACHERP:
+ if (dundidebug)
+ dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr));
+ res = dundi_encrypt(trans, pack);
+ break;
+ default:
+ res = 0;
+ }
+ } else
+ res = 0;
+ if (!res)
+ res = dundi_xmit(pack);
+ if (res)
+ ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
+
+ if (cmdresp == DUNDI_COMMAND_ACK)
+ ast_free(pack);
+ return res;
+ }
+ return -1;
+}
+
+static int do_autokill(const void *data)
+{
+ struct dundi_transaction *trans = (struct dundi_transaction *)data;
+ char eid_str[20];
+ ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid));
+ trans->autokillid = -1;
+ destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */
+ return 0;
+}
+
+static void dundi_ie_append_eid_appropriately(struct dundi_ie_data *ied, char *context, dundi_eid *eid, dundi_eid *us)
+{
+ struct dundi_peer *p;
+ if (!dundi_eid_cmp(eid, us)) {
+ dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
+ return;
+ }
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&peers, p, list) {
+ if (!dundi_eid_cmp(&p->eid, eid)) {
+ if (has_permission(&p->include, context))
+ dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid);
+ else
+ dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
+ break;
+ }
+ }
+ if (!p)
+ dundi_ie_append_eid(ied, DUNDI_IE_EID, eid);
+ AST_LIST_UNLOCK(&peers);
+}
+
+static int dundi_discover(struct dundi_transaction *trans)
+{
+ struct dundi_ie_data ied;
+ int x;
+ if (!trans->parent) {
+ ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
+ return -1;
+ }
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
+ if (!dundi_eid_zero(&trans->us_eid))
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid);
+ for (x=0;x<trans->eidcount;x++)
+ dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
+ dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
+ if (trans->parent->cbypass)
+ dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS);
+ if (trans->autokilltimeout)
+ trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
+ return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied);
+}
+
+static int precache_trans(struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers)
+{
+ struct dundi_ie_data ied;
+ int x, res;
+ int max = 999999;
+ int expiration = dundi_cache_time;
+ int ouranswers=0;
+ dundi_eid *avoid[1] = { NULL, };
+ int direct[1] = { 0, };
+ struct dundi_result dr[MAX_RESULTS];
+ struct dundi_hint_metadata hmd;
+ if (!trans->parent) {
+ ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n");
+ return -1;
+ }
+ memset(&hmd, 0, sizeof(hmd));
+ memset(&dr, 0, sizeof(dr));
+ /* Look up the answers we're going to include */
+ for (x=0;x<mapcount;x++)
+ ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd);
+ if (ouranswers < 0)
+ ouranswers = 0;
+ for (x=0;x<ouranswers;x++) {
+ if (dr[x].weight < max)
+ max = dr[x].weight;
+ }
+ if (max) {
+ /* If we do not have a canonical result, keep looking */
+ res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, trans->parent->dcontext, trans->parent->number, trans->ttl, 1, &hmd, &expiration, 0, 1, &trans->them_eid, avoid, direct);
+ if (res > 0) {
+ /* Append answer in result */
+ ouranswers += res;
+ }
+ }
+
+ if (ouranswers > 0) {
+ *foundanswers += ouranswers;
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
+ if (!dundi_eid_zero(&trans->us_eid))
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
+ for (x=0;x<trans->eidcount;x++)
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
+ dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
+ for (x=0;x<ouranswers;x++) {
+ /* Add answers */
+ if (dr[x].expiration && (expiration > dr[x].expiration))
+ expiration = dr[x].expiration;
+ dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest);
+ }
+ dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten);
+ dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration);
+ if (trans->autokilltimeout)
+ trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
+ if (expiration < *minexp)
+ *minexp = expiration;
+ return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied);
+ } else {
+ /* Oops, nothing to send... */
+ destroy_trans(trans, 0);
+ return 0;
+ }
+}
+
+static int dundi_query(struct dundi_transaction *trans)
+{
+ struct dundi_ie_data ied;
+ int x;
+ if (!trans->parent) {
+ ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n");
+ return -1;
+ }
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
+ if (!dundi_eid_zero(&trans->us_eid))
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid);
+ for (x=0;x<trans->eidcount;x++)
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]);
+ dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid);
+ dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext);
+ dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl);
+ if (trans->autokilltimeout)
+ trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans);
+ return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied);
+}
+
+static int discover_transactions(struct dundi_request *dr)
+{
+ struct dundi_transaction *trans;
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
+ dundi_discover(trans);
+ }
+ AST_LIST_UNLOCK(&peers);
+ return 0;
+}
+
+static int precache_transactions(struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers)
+{
+ struct dundi_transaction *trans;
+
+ /* Mark all as "in thread" so they don't disappear */
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
+ if (trans->thread)
+ ast_log(LOG_WARNING, "This shouldn't happen, really...\n");
+ trans->thread = 1;
+ }
+ AST_LIST_UNLOCK(&peers);
+
+ AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
+ if (!ast_test_flag(trans, FLAG_DEAD))
+ precache_trans(trans, maps, mapcount, expiration, foundanswers);
+ }
+
+ /* Cleanup any that got destroyed in the mean time */
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&dr->trans, trans, parentlist) {
+ trans->thread = 0;
+ if (ast_test_flag(trans, FLAG_DEAD)) {
+ ast_debug(1, "Our transaction went away!\n");
+ /* This is going to remove the transaction from the dundi_request's list, as well
+ * as the global transactions list */
+ destroy_trans(trans, 0);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END
+ AST_LIST_UNLOCK(&peers);
+
+ return 0;
+}
+
+static int query_transactions(struct dundi_request *dr)
+{
+ struct dundi_transaction *trans;
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
+ dundi_query(trans);
+ }
+ AST_LIST_UNLOCK(&peers);
+
+ return 0;
+}
+
+static int optimize_transactions(struct dundi_request *dr, int order)
+{
+ /* Minimize the message propagation through DUNDi by
+ alerting the network to hops which should be not be considered */
+ struct dundi_transaction *trans;
+ struct dundi_peer *peer;
+ dundi_eid tmp;
+ int x;
+ int needpush;
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&dr->trans, trans, parentlist) {
+ /* Pop off the true root */
+ if (trans->eidcount) {
+ tmp = trans->eids[--trans->eidcount];
+ needpush = 1;
+ } else {
+ tmp = trans->us_eid;
+ needpush = 0;
+ }
+
+ AST_LIST_TRAVERSE(&peers, peer, list) {
+ if (has_permission(&peer->include, dr->dcontext) &&
+ dundi_eid_cmp(&peer->eid, &trans->them_eid) &&
+ (peer->order <= order)) {
+ /* For each other transaction, make sure we don't
+ ask this EID about the others if they're not
+ already in the list */
+ if (!dundi_eid_cmp(&tmp, &peer->eid))
+ x = -1;
+ else {
+ for (x=0;x<trans->eidcount;x++) {
+ if (!dundi_eid_cmp(&trans->eids[x], &peer->eid))
+ break;
+ }
+ }
+ if (x == trans->eidcount) {
+ /* Nope not in the list, if needed, add us at the end since we're the source */
+ if (trans->eidcount < DUNDI_MAX_STACK - needpush) {
+ trans->eids[trans->eidcount++] = peer->eid;
+ /* Need to insert the real root (or us) at the bottom now as
+ a requirement now. */
+ needpush = 1;
+ }
+ }
+ }
+ }
+ /* If necessary, push the true root back on the end */
+ if (needpush)
+ trans->eids[trans->eidcount++] = tmp;
+ }
+ AST_LIST_UNLOCK(&peers);
+
+ return 0;
+}
+
+static int append_transaction(struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[])
+{
+ struct dundi_transaction *trans;
+ int x;
+ char eid_str[20];
+ char eid_str2[20];
+
+ /* Ignore if not registered */
+ if (!p->addr.sin_addr.s_addr)
+ return 0;
+ if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))
+ return 0;
+
+ if (ast_strlen_zero(dr->number))
+ ast_debug(1, "Will query peer '%s' for '%s' (context '%s')\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext);
+ else
+ ast_debug(1, "Will query peer '%s' for '%s@%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext);
+
+ trans = create_transaction(p);
+ if (!trans)
+ return -1;
+ trans->parent = dr;
+ trans->ttl = ttl;
+ for (x = 0; avoid[x] && (x < DUNDI_MAX_STACK); x++)
+ trans->eids[x] = *avoid[x];
+ trans->eidcount = x;
+ AST_LIST_INSERT_HEAD(&dr->trans, trans, parentlist);
+
+ return 0;
+}
+
+static void cancel_request(struct dundi_request *dr)
+{
+ struct dundi_transaction *trans;
+
+ AST_LIST_LOCK(&peers);
+ while ((trans = AST_LIST_REMOVE_HEAD(&dr->trans, parentlist))) {
+ /* Orphan transaction from request */
+ trans->parent = NULL;
+ /* Send final cancel */
+ dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL);
+ }
+ AST_LIST_UNLOCK(&peers);
+}
+
+static void abort_request(struct dundi_request *dr)
+{
+ struct dundi_transaction *trans;
+
+ AST_LIST_LOCK(&peers);
+ while ((trans = AST_LIST_FIRST(&dr->trans))) {
+ /* This will remove the transaction from the list */
+ destroy_trans(trans, 0);
+ }
+ AST_LIST_UNLOCK(&peers);
+}
+
+static void build_transactions(struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[])
+{
+ struct dundi_peer *p;
+ int x;
+ int res;
+ int pass;
+ int allowconnect;
+ char eid_str[20];
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&peers, p, list) {
+ if (modeselect == 1) {
+ /* Send the precache to push upstreams only! */
+ pass = has_permission(&p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND);
+ allowconnect = 1;
+ } else {
+ /* Normal lookup / EID query */
+ pass = has_permission(&p->include, dr->dcontext);
+ allowconnect = p->model & DUNDI_MODEL_OUTBOUND;
+ }
+ if (skip) {
+ if (!dundi_eid_cmp(skip, &p->eid))
+ pass = 0;
+ }
+ if (pass) {
+ if (p->order <= order) {
+ /* Check order first, then check cache, regardless of
+ omissions, this gets us more likely to not have an
+ affected answer. */
+ if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) {
+ res = 0;
+ /* Make sure we haven't already seen it and that it won't
+ affect our answer */
+ for (x=0;avoid[x];x++) {
+ if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) {
+ /* If not a direct connection, it affects our answer */
+ if (directs && !directs[x])
+ ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED);
+ break;
+ }
+ }
+ /* Make sure we can ask */
+ if (allowconnect) {
+ if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) {
+ /* Check for a matching or 0 cache entry */
+ append_transaction(dr, p, ttl, avoid);
+ } else {
+ ast_debug(1, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x]));
+ }
+ }
+ }
+ *foundcache |= res;
+ } else if (!*skipped || (p->order < *skipped))
+ *skipped = p->order;
+ }
+ }
+ AST_LIST_UNLOCK(&peers);
+}
+
+static int register_request(struct dundi_request *dr, struct dundi_request **pending)
+{
+ struct dundi_request *cur;
+ int res=0;
+ char eid_str[20];
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&requests, cur, list) {
+ ast_debug(1, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number,
+ dr->dcontext, dr->number);
+ if (!strcasecmp(cur->dcontext, dr->dcontext) &&
+ !strcasecmp(cur->number, dr->number) &&
+ (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) {
+ ast_debug(1, "Found existing query for '%s@%s' for '%s' crc '%08lx'\n",
+ cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32);
+ *pending = cur;
+ res = 1;
+ break;
+ }
+ }
+ if (!res) {
+ ast_debug(1, "Registering request for '%s@%s' on behalf of '%s' crc '%08lx'\n",
+ dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32);
+ /* Go ahead and link us in since nobody else is searching for this */
+ AST_LIST_INSERT_HEAD(&requests, dr, list);
+ *pending = NULL;
+ }
+ AST_LIST_UNLOCK(&peers);
+ return res;
+}
+
+static void unregister_request(struct dundi_request *dr)
+{
+ AST_LIST_LOCK(&peers);
+ AST_LIST_REMOVE(&requests, dr, list);
+ AST_LIST_UNLOCK(&peers);
+}
+
+static int check_request(struct dundi_request *dr)
+{
+ struct dundi_request *cur;
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&requests, cur, list) {
+ if (cur == dr)
+ break;
+ }
+ AST_LIST_UNLOCK(&peers);
+
+ return cur ? 1 : 0;
+}
+
+static unsigned long avoid_crc32(dundi_eid *avoid[])
+{
+ /* Idea is that we're calculating a checksum which is independent of
+ the order that the EID's are listed in */
+ unsigned long acrc32 = 0;
+ int x;
+ for (x=0;avoid[x];x++) {
+ /* Order doesn't matter */
+ if (avoid[x+1]) {
+ acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid));
+ }
+ }
+ return acrc32;
+}
+
+static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *hmd, int *expiration, int cbypass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[])
+{
+ int res;
+ struct dundi_request dr, *pending;
+ dundi_eid *rooteid=NULL;
+ int x;
+ int ttlms;
+ int ms;
+ int foundcache;
+ int skipped=0;
+ int order=0;
+ char eid_str[20];
+ struct timeval start;
+
+ /* Don't do anthing for a hungup channel */
+ if (chan && ast_check_hangup(chan))
+ return 0;
+
+ ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
+
+ for (x=0;avoid[x];x++)
+ rooteid = avoid[x];
+ /* Now perform real check */
+ memset(&dr, 0, sizeof(dr));
+ if (pipe(dr.pfds)) {
+ ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno));
+ return -1;
+ }
+ dr.dr = result;
+ dr.hmd = hmd;
+ dr.maxcount = maxret;
+ dr.expiration = *expiration;
+ dr.cbypass = cbypass;
+ dr.crc32 = avoid_crc32(avoid);
+ ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
+ ast_copy_string(dr.number, number, sizeof(dr.number));
+ if (rooteid)
+ dr.root_eid = *rooteid;
+ res = register_request(&dr, &pending);
+ if (res) {
+ /* Already a request */
+ if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) {
+ /* This is on behalf of someone else. Go ahead and close this out since
+ they'll get their answer anyway. */
+ ast_debug(1, "Oooh, duplicate request for '%s@%s' for '%s'\n",
+ dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid));
+ close(dr.pfds[0]);
+ close(dr.pfds[1]);
+ return -2;
+ } else {
+ /* Wait for the cache to populate */
+ ast_debug(1, "Waiting for similar request for '%s@%s' for '%s'\n",
+ dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
+ start = ast_tvnow();
+ while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
+ /* XXX Would be nice to have a way to poll/select here XXX */
+ /* XXX this is a busy wait loop!!! */
+ usleep(1);
+ }
+ /* Continue on as normal, our cache should kick in */
+ }
+ }
+ /* Create transactions */
+ do {
+ order = skipped;
+ skipped = 0;
+ foundcache = 0;
+ build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct);
+ } while (skipped && !foundcache && AST_LIST_EMPTY(&dr.trans));
+ /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't
+ do this earlier because we didn't know if we were going to have transactions
+ or not. */
+ if (!ttl) {
+ ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
+ abort_request(&dr);
+ unregister_request(&dr);
+ close(dr.pfds[0]);
+ close(dr.pfds[1]);
+ return 0;
+ }
+
+ /* Optimize transactions */
+ optimize_transactions(&dr, order);
+ /* Actually perform transactions */
+ discover_transactions(&dr);
+ /* Wait for transaction to come back */
+ start = ast_tvnow();
+ while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !ast_check_hangup(chan))) {
+ ms = 100;
+ ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
+ }
+ if (chan && ast_check_hangup(chan))
+ ast_debug(1, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext);
+ cancel_request(&dr);
+ unregister_request(&dr);
+ res = dr.respcount;
+ *expiration = dr.expiration;
+ close(dr.pfds[0]);
+ close(dr.pfds[1]);
+ return res;
+}
+
+int dundi_lookup(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int cbypass)
+{
+ struct dundi_hint_metadata hmd;
+ dundi_eid *avoid[1] = { NULL, };
+ int direct[1] = { 0, };
+ int expiration = dundi_cache_time;
+ memset(&hmd, 0, sizeof(hmd));
+ hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED;
+ return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct);
+}
+
+static void reschedule_precache(const char *number, const char *context, int expiration)
+{
+ int len;
+ struct dundi_precache_queue *qe, *prev;
+
+ AST_LIST_LOCK(&pcq);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&pcq, qe, list) {
+ if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) {
+ AST_LIST_REMOVE_CURRENT(list);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ if (!qe) {
+ len = sizeof(*qe);
+ len += strlen(number) + 1;
+ len += strlen(context) + 1;
+ if (!(qe = ast_calloc(1, len))) {
+ AST_LIST_UNLOCK(&pcq);
+ return;
+ }
+ strcpy(qe->number, number);
+ qe->context = qe->number + strlen(number) + 1;
+ strcpy(qe->context, context);
+ }
+ time(&qe->expiration);
+ qe->expiration += expiration;
+ if ((prev = AST_LIST_FIRST(&pcq))) {
+ while (AST_LIST_NEXT(prev, list) && ((AST_LIST_NEXT(prev, list))->expiration <= qe->expiration))
+ prev = AST_LIST_NEXT(prev, list);
+ AST_LIST_INSERT_AFTER(&pcq, prev, qe, list);
+ } else
+ AST_LIST_INSERT_HEAD(&pcq, qe, list);
+ AST_LIST_UNLOCK(&pcq);
+}
+
+static void dundi_precache_full(void)
+{
+ struct dundi_mapping *cur;
+ struct ast_context *con;
+ struct ast_exten *e;
+
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext);
+ ast_rdlock_contexts();
+ con = NULL;
+ while ((con = ast_walk_contexts(con))) {
+ if (strcasecmp(cur->lcontext, ast_get_context_name(con)))
+ continue;
+ /* Found the match, now queue them all up */
+ ast_rdlock_context(con);
+ e = NULL;
+ while ((e = ast_walk_context_extensions(con, e)))
+ reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0);
+ ast_unlock_context(con);
+ }
+ ast_unlock_contexts();
+ }
+}
+
+static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[])
+{
+ struct dundi_request dr;
+ struct dundi_hint_metadata hmd;
+ struct dundi_result dr2[MAX_RESULTS];
+ struct timeval start;
+ struct dundi_mapping *maps = NULL, *cur;
+ int nummaps = 0;
+ int foundanswers;
+ int foundcache, skipped, ttlms, ms;
+ if (!context)
+ context = "e164";
+ ast_debug(1, "Precache internal (%s@%s)!\n", number, context);
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ if (!strcasecmp(cur->dcontext, context))
+ nummaps++;
+ }
+ if (nummaps) {
+ maps = alloca(nummaps * sizeof(*maps));
+ nummaps = 0;
+ if (maps) {
+ AST_LIST_TRAVERSE(&mappings, cur, list) {
+ if (!strcasecmp(cur->dcontext, context))
+ maps[nummaps++] = *cur;
+ }
+ }
+ }
+ AST_LIST_UNLOCK(&peers);
+ if (!nummaps || !maps)
+ return -1;
+ ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
+ memset(&dr2, 0, sizeof(dr2));
+ memset(&dr, 0, sizeof(dr));
+ memset(&hmd, 0, sizeof(hmd));
+ dr.dr = dr2;
+ ast_copy_string(dr.number, number, sizeof(dr.number));
+ ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext));
+ dr.maxcount = MAX_RESULTS;
+ dr.expiration = dundi_cache_time;
+ dr.hmd = &hmd;
+ dr.pfds[0] = dr.pfds[1] = -1;
+ pipe(dr.pfds);
+ build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL);
+ optimize_transactions(&dr, 0);
+ foundanswers = 0;
+ precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers);
+ if (foundanswers) {
+ if (dr.expiration > 0)
+ reschedule_precache(dr.number, dr.dcontext, dr.expiration);
+ else
+ ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
+ }
+ start = ast_tvnow();
+ while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
+ if (dr.pfds[0] > -1) {
+ ms = 100;
+ ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
+ } else
+ usleep(1);
+ }
+ cancel_request(&dr);
+ if (dr.pfds[0] > -1) {
+ close(dr.pfds[0]);
+ close(dr.pfds[1]);
+ }
+ return 0;
+}
+
+int dundi_precache(const char *context, const char *number)
+{
+ dundi_eid *avoid[1] = { NULL, };
+ return dundi_precache_internal(context, number, dundi_ttl, avoid);
+}
+
+static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[])
+{
+ int res;
+ struct dundi_request dr;
+ dundi_eid *rooteid=NULL;
+ int x;
+ int ttlms;
+ int skipped=0;
+ int foundcache=0;
+ struct timeval start;
+
+ ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME;
+
+ for (x=0;avoid[x];x++)
+ rooteid = avoid[x];
+ /* Now perform real check */
+ memset(&dr, 0, sizeof(dr));
+ dr.hmd = hmd;
+ dr.dei = dei;
+ dr.pfds[0] = dr.pfds[1] = -1;
+ ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext));
+ memcpy(&dr.query_eid, eid, sizeof(dr.query_eid));
+ if (rooteid)
+ dr.root_eid = *rooteid;
+ /* Create transactions */
+ build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL);
+
+ /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't
+ do this earlier because we didn't know if we were going to have transactions
+ or not. */
+ if (!ttl) {
+ ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED);
+ return 0;
+ }
+
+ /* Optimize transactions */
+ optimize_transactions(&dr, 9999);
+ /* Actually perform transactions */
+ query_transactions(&dr);
+ /* Wait for transaction to come back */
+ start = ast_tvnow();
+ while (!AST_LIST_EMPTY(&dr.trans) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
+ usleep(1);
+ res = dr.respcount;
+ return res;
+}
+
+int dundi_query_eid(struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid)
+{
+ dundi_eid *avoid[1] = { NULL, };
+ struct dundi_hint_metadata hmd;
+ memset(&hmd, 0, sizeof(hmd));
+ return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid);
+}
+
+static int dundifunc_read(struct ast_channel *chan, const char *cmd, char *num, char *buf, size_t len)
+{
+ char *context;
+ char *opts;
+ int results;
+ int x;
+ int bypass = 0;
+ struct ast_module_user *u;
+ struct dundi_result dr[MAX_RESULTS];
+
+ buf[0] = '\0';
+
+ if (ast_strlen_zero(num)) {
+ ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n");
+ return -1;
+ }
+
+ u = ast_module_user_add(chan);
+
+ context = strchr(num, '|');
+ if (context) {
+ *context++ = '\0';
+ opts = strchr(context, '|');
+ if (opts) {
+ *opts++ = '\0';
+ if (strchr(opts, 'b'))
+ bypass = 1;
+ }
+ }
+
+ if (ast_strlen_zero(context))
+ context = "e164";
+
+ results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass);
+ if (results > 0) {
+ sort_results(dr, results);
+ for (x = 0; x < results; x++) {
+ if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) {
+ snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest);
+ break;
+ }
+ }
+ }
+
+ ast_module_user_remove(u);
+
+ return 0;
+}
+
+/*! DUNDILOOKUP
+ * \ingroup functions
+*/
+
+static struct ast_custom_function dundi_function = {
+ .name = "DUNDILOOKUP",
+ .synopsis = "Do a DUNDi lookup of a phone number.",
+ .syntax = "DUNDILOOKUP(number[|context[|options]])",
+ .desc = "This will do a DUNDi lookup of the given phone number.\n"
+ "If no context is given, the default will be e164. The result of\n"
+ "this function will return the Technology/Resource found in the first result\n"
+ "in the DUNDi lookup. If no results were found, the result will be blank.\n"
+ "If the 'b' option is specified, the internal DUNDi cache will\n"
+ "be bypassed.\n",
+ .read = dundifunc_read,
+};
+
+enum {
+ OPT_BYPASS_CACHE = (1 << 0),
+};
+
+AST_APP_OPTIONS(dundi_query_opts, BEGIN_OPTIONS
+ AST_APP_OPTION('b', OPT_BYPASS_CACHE),
+END_OPTIONS );
+
+unsigned int dundi_result_id;
+
+struct dundi_result_datastore {
+ struct dundi_result results[MAX_RESULTS];
+ unsigned int num_results;
+ unsigned int id;
+};
+
+static void drds_destroy(struct dundi_result_datastore *drds)
+{
+ ast_free(drds);
+}
+
+static void drds_destroy_cb(void *data)
+{
+ struct dundi_result_datastore *drds = data;
+ drds_destroy(drds);
+}
+
+static const struct ast_datastore_info dundi_result_datastore_info = {
+ .type = "DUNDIQUERY",
+ .destroy = drds_destroy_cb,
+};
+
+static int dundi_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ struct ast_module_user *u;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(number);
+ AST_APP_ARG(context);
+ AST_APP_ARG(options);
+ );
+ struct ast_flags opts = { 0, };
+ char *parse;
+ struct dundi_result_datastore *drds;
+ struct ast_datastore *datastore;
+
+ u = ast_module_user_add(chan);
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "DUNDIQUERY requires an argument (number)\n");
+ ast_module_user_remove(u);
+ return -1;
+ }
+
+ if (!chan) {
+ ast_log(LOG_ERROR, "DUNDIQUERY can not be used without a channel!\n");
+ ast_module_user_remove(u);
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (!ast_strlen_zero(args.options))
+ ast_app_parse_options(dundi_query_opts, &opts, NULL, args.options);
+
+ if (ast_strlen_zero(args.context))
+ args.context = "e164";
+
+ if (!(drds = ast_calloc(1, sizeof(*drds)))) {
+ ast_module_user_remove(u);
+ return -1;
+ }
+
+ drds->id = ast_atomic_fetchadd_int((int *) &dundi_result_id, 1);
+ snprintf(buf, len, "%u", drds->id);
+
+ if (!(datastore = ast_channel_datastore_alloc(&dundi_result_datastore_info, buf))) {
+ drds_destroy(drds);
+ ast_module_user_remove(u);
+ return -1;
+ }
+
+ datastore->data = drds;
+
+ drds->num_results = dundi_lookup(drds->results, ARRAY_LEN(drds->results), NULL, args.context,
+ args.number, ast_test_flag(&opts, OPT_BYPASS_CACHE));
+
+ if (drds->num_results > 0)
+ sort_results(drds->results, drds->num_results);
+
+ ast_channel_lock(chan);
+ ast_channel_datastore_add(chan, datastore);
+ ast_channel_unlock(chan);
+
+ ast_module_user_remove(u);
+
+ return 0;
+}
+
+static struct ast_custom_function dundi_query_function = {
+ .name = "DUNDIQUERY",
+ .synopsis = "Initiate a DUNDi query.",
+ .syntax = "DUNDIQUERY(number[|context[|options]])",
+ .desc = "This will do a DUNDi lookup of the given phone number.\n"
+ "If no context is given, the default will be e164. The result of\n"
+ "this function will be a numeric ID that can be used to retrieve\n"
+ "the results with the DUNDIRESULT function. If the 'b' option is\n"
+ "is specified, the internal DUNDi cache will be bypassed.\n",
+ .read = dundi_query_read,
+};
+
+static int dundi_result_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+ struct ast_module_user *u;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(id);
+ AST_APP_ARG(resultnum);
+ );
+ char *parse;
+ unsigned int num;
+ struct dundi_result_datastore *drds;
+ struct ast_datastore *datastore;
+ int res = -1;
+
+ u = ast_module_user_add(chan);
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "DUNDIRESULT requires an argument (id and resultnum)\n");
+ goto finish;
+ }
+
+ if (!chan) {
+ ast_log(LOG_ERROR, "DUNDRESULT can not be used without a channel!\n");
+ goto finish;
+ }
+
+ parse = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (ast_strlen_zero(args.id)) {
+ ast_log(LOG_ERROR, "A result ID must be provided to DUNDIRESULT\n");
+ goto finish;
+ }
+
+ if (ast_strlen_zero(args.resultnum)) {
+ ast_log(LOG_ERROR, "A result number must be given to DUNDIRESULT!\n");
+ goto finish;
+ }
+
+ ast_channel_lock(chan);
+ datastore = ast_channel_datastore_find(chan, &dundi_result_datastore_info, args.id);
+ ast_channel_unlock(chan);
+
+ if (!datastore) {
+ ast_log(LOG_WARNING, "No DUNDi results found for query ID '%s'\n", args.id);
+ goto finish;
+ }
+
+ drds = datastore->data;
+
+ if (!strcasecmp(args.resultnum, "getnum")) {
+ snprintf(buf, len, "%u", drds->num_results);
+ res = 0;
+ goto finish;
+ }
+
+ if (sscanf(args.resultnum, "%u", &num) != 1) {
+ ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to DUNDIRESULT!\n",
+ args.resultnum);
+ goto finish;
+ }
+
+ if (num && num <= drds->num_results) {
+ snprintf(buf, len, "%s/%s", drds->results[num - 1].tech, drds->results[num - 1].dest);
+ res = 0;
+ } else
+ ast_log(LOG_WARNING, "Result number %u is not valid for DUNDi query results for ID %s!\n", num, args.id);
+
+finish:
+ ast_module_user_remove(u);
+
+ return res;
+}
+
+static struct ast_custom_function dundi_result_function = {
+ .name = "DUNDIRESULT",
+ .synopsis = "Retrieve results from a DUNDIQUERY",
+ .syntax = "DUNDIRESULT(id|resultnum)",
+ .desc = "This function will retrieve results from a previous use\n"
+ "of the DUNDIQUERY function.\n"
+ " id - This argument is the identifier returned by the DUNDIQUERY function.\n"
+ " resultnum - This is the number of the result that you want to retrieve.\n"
+ " Results start at 1. If this argument is specified as \"getnum\",\n"
+ " then it will return the total number of results that are available.\n",
+ .read = dundi_result_read,
+};
+
+static void mark_peers(void)
+{
+ struct dundi_peer *peer;
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&peers, peer, list) {
+ peer->dead = 1;
+ }
+ AST_LIST_UNLOCK(&peers);
+}
+
+static void mark_mappings(void)
+{
+ struct dundi_mapping *map;
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&mappings, map, list) {
+ map->dead = 1;
+ }
+ AST_LIST_UNLOCK(&peers);
+}
+
+static void destroy_permissions(struct permissionlist *permlist)
+{
+ struct permission *perm;
+
+ while ((perm = AST_LIST_REMOVE_HEAD(permlist, list)))
+ ast_free(perm);
+}
+
+static void destroy_peer(struct dundi_peer *peer)
+{
+ if (peer->registerid > -1)
+ ast_sched_del(sched, peer->registerid);
+ if (peer->regtrans)
+ destroy_trans(peer->regtrans, 0);
+ if (peer->qualifyid > -1)
+ ast_sched_del(sched, peer->qualifyid);
+ destroy_permissions(&peer->permit);
+ destroy_permissions(&peer->include);
+ ast_free(peer);
+}
+
+static void destroy_map(struct dundi_mapping *map)
+{
+ if (map->weightstr)
+ ast_free(map->weightstr);
+ ast_free(map);
+}
+
+static void prune_peers(void)
+{
+ struct dundi_peer *peer;
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, list) {
+ if (peer->dead) {
+ AST_LIST_REMOVE_CURRENT(list);
+ destroy_peer(peer);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_UNLOCK(&peers);
+}
+
+static void prune_mappings(void)
+{
+ struct dundi_mapping *map;
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&mappings, map, list) {
+ if (map->dead) {
+ AST_LIST_REMOVE_CURRENT(list);
+ destroy_map(map);
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_UNLOCK(&peers);
+}
+
+static void append_permission(struct permissionlist *permlist, const char *s, int allow)
+{
+ struct permission *perm;
+
+ if (!(perm = ast_calloc(1, sizeof(*perm) + strlen(s) + 1)))
+ return;
+
+ strcpy(perm->name, s);
+ perm->allow = allow;
+
+ AST_LIST_INSERT_TAIL(permlist, perm, list);
+}
+
+#define MAX_OPTS 128
+
+static void build_mapping(const char *name, const char *value)
+{
+ char *t, *fields[MAX_OPTS];
+ struct dundi_mapping *map;
+ int x;
+ int y;
+
+ t = ast_strdupa(value);
+
+ AST_LIST_TRAVERSE(&mappings, map, list) {
+ /* Find a double match */
+ if (!strcasecmp(map->dcontext, name) &&
+ (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) &&
+ (!value[strlen(map->lcontext)] ||
+ (value[strlen(map->lcontext)] == ','))))
+ break;
+ }
+ if (!map) {
+ if (!(map = ast_calloc(1, sizeof(*map))))
+ return;
+ AST_LIST_INSERT_HEAD(&mappings, map, list);
+ map->dead = 1;
+ }
+ map->options = 0;
+ memset(fields, 0, sizeof(fields));
+ x = 0;
+ while (t && x < MAX_OPTS) {
+ fields[x++] = t;
+ t = strchr(t, ',');
+ if (t) {
+ *t = '\0';
+ t++;
+ }
+ } /* Russell was here, arrrr! */
+ if ((x == 1) && ast_strlen_zero(fields[0])) {
+ /* Placeholder mapping */
+ ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
+ map->dead = 0;
+ } else if (x >= 4) {
+ ast_copy_string(map->dcontext, name, sizeof(map->dcontext));
+ ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext));
+ if ((sscanf(fields[1], "%d", &map->_weight) == 1) && (map->_weight >= 0) && (map->_weight <= MAX_WEIGHT)) {
+ ast_copy_string(map->dest, fields[3], sizeof(map->dest));
+ if ((map->tech = str2tech(fields[2])))
+ map->dead = 0;
+ } else if (!strncmp(fields[1], "${", 2) && fields[1][strlen(fields[1]) - 1] == '}') {
+ map->weightstr = ast_strdup(fields[1]);
+ ast_copy_string(map->dest, fields[3], sizeof(map->dest));
+ if ((map->tech = str2tech(fields[2])))
+ map->dead = 0;
+ } else {
+ ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext);
+ }
+ for (y = 4;y < x; y++) {
+ if (!strcasecmp(fields[y], "nounsolicited"))
+ map->options |= DUNDI_FLAG_NOUNSOLICITED;
+ else if (!strcasecmp(fields[y], "nocomunsolicit"))
+ map->options |= DUNDI_FLAG_NOCOMUNSOLICIT;
+ else if (!strcasecmp(fields[y], "residential"))
+ map->options |= DUNDI_FLAG_RESIDENTIAL;
+ else if (!strcasecmp(fields[y], "commercial"))
+ map->options |= DUNDI_FLAG_COMMERCIAL;
+ else if (!strcasecmp(fields[y], "mobile"))
+ map->options |= DUNDI_FLAG_MOBILE;
+ else if (!strcasecmp(fields[y], "nopartial"))
+ map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL;
+ else
+ ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]);
+ }
+ } else
+ ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x);
+}
+
+/* \note Called with the peers list already locked */
+static int do_register(const void *data)
+{
+ struct dundi_ie_data ied;
+ struct dundi_peer *peer = (struct dundi_peer *)data;
+ char eid_str[20];
+ char eid_str2[20];
+ ast_debug(1, "Register us as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid));
+ peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data);
+ /* Destroy old transaction if there is one */
+ if (peer->regtrans)
+ destroy_trans(peer->regtrans, 0);
+ peer->regtrans = create_transaction(peer);
+ if (peer->regtrans) {
+ ast_set_flag(peer->regtrans, FLAG_ISREG);
+ memset(&ied, 0, sizeof(ied));
+ dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION);
+ dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid);
+ dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration);
+ dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied);
+
+ } else
+ ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+
+ return 0;
+}
+
+static int do_qualify(const void *data)
+{
+ struct dundi_peer *peer = (struct dundi_peer *)data;
+ peer->qualifyid = -1;
+ qualify_peer(peer, 0);
+ return 0;
+}
+
+static void qualify_peer(struct dundi_peer *peer, int schedonly)
+{
+ int when;
+ if (peer->qualifyid > -1)
+ ast_sched_del(sched, peer->qualifyid);
+ peer->qualifyid = -1;
+ if (peer->qualtrans)
+ destroy_trans(peer->qualtrans, 0);
+ peer->qualtrans = NULL;
+ if (peer->maxms > 0) {
+ when = 60000;
+ if (peer->lastms < 0)
+ when = 10000;
+ if (schedonly)
+ when = 5000;
+ peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer);
+ if (!schedonly)
+ peer->qualtrans = create_transaction(peer);
+ if (peer->qualtrans) {
+ peer->qualtx = ast_tvnow();
+ ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
+ dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
+ }
+ }
+}
+static void populate_addr(struct dundi_peer *peer, dundi_eid *eid)
+{
+ char data[256];
+ char *c;
+ int port, expire;
+ char eid_str[20];
+ dundi_eid_to_str(eid_str, sizeof(eid_str), eid);
+ if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) {
+ c = strchr(data, ':');
+ if (c) {
+ *c = '\0';
+ c++;
+ if (sscanf(c, "%d:%d", &port, &expire) == 2) {
+ /* Got it! */
+ inet_aton(data, &peer->addr.sin_addr);
+ peer->addr.sin_family = AF_INET;
+ peer->addr.sin_port = htons(port);
+ peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);
+ }
+ }
+ }
+}
+
+
+static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode)
+{
+ struct dundi_peer *peer;
+ struct ast_hostent he;
+ struct hostent *hp;
+ dundi_eid testeid;
+ int needregister=0;
+ char eid_str[20];
+
+ AST_LIST_LOCK(&peers);
+ AST_LIST_TRAVERSE(&peers, peer, list) {
+ if (!dundi_eid_cmp(&peer->eid, eid)) {
+ break;
+ }
+ }
+ if (!peer) {
+ /* Add us into the list */
+ if (!(peer = ast_calloc(1, sizeof(*peer)))) {
+ AST_LIST_UNLOCK(&peers);
+ return;
+ }
+ peer->registerid = -1;
+ peer->registerexpire = -1;
+ peer->qualifyid = -1;
+ peer->addr.sin_family = AF_INET;
+ peer->addr.sin_port = htons(DUNDI_PORT);
+ populate_addr(peer, eid);
+ AST_LIST_INSERT_HEAD(&peers, peer, list);
+ }
+ peer->dead = 0;
+ peer->eid = *eid;
+ peer->us_eid = global_eid;
+ destroy_permissions(&peer->permit);
+ destroy_permissions(&peer->include);
+ if (peer->registerid > -1)
+ ast_sched_del(sched, peer->registerid);
+ peer->registerid = -1;
+ for (; v; v = v->next) {
+ if (!strcasecmp(v->name, "inkey")) {
+ ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey));
+ } else if (!strcasecmp(v->name, "outkey")) {
+ ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));
+ } else if (!strcasecmp(v->name, "host")) {
+ if (!strcasecmp(v->value, "dynamic")) {
+ peer->dynamic = 1;
+ } else {
+ hp = ast_gethostbyname(v->value, &he);
+ if (hp) {
+ memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));
+ peer->dynamic = 0;
+ } else {
+ ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);
+ peer->dead = 1;
+ }
+ }
+ } else if (!strcasecmp(v->name, "ustothem")) {
+ if (!dundi_str_to_eid(&testeid, v->value))
+ peer->us_eid = testeid;
+ else
+ ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno);
+ } else if (!strcasecmp(v->name, "include")) {
+ append_permission(&peer->include, v->value, 1);
+ } else if (!strcasecmp(v->name, "permit")) {
+ append_permission(&peer->permit, v->value, 1);
+ } else if (!strcasecmp(v->name, "noinclude")) {
+ append_permission(&peer->include, v->value, 0);
+ } else if (!strcasecmp(v->name, "deny")) {
+ append_permission(&peer->permit, v->value, 0);
+ } else if (!strcasecmp(v->name, "register")) {
+ needregister = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "order")) {
+ if (!strcasecmp(v->value, "primary"))
+ peer->order = 0;
+ else if (!strcasecmp(v->value, "secondary"))
+ peer->order = 1;
+ else if (!strcasecmp(v->value, "tertiary"))
+ peer->order = 2;
+ else if (!strcasecmp(v->value, "quartiary"))
+ peer->order = 3;
+ else {
+ ast_log(LOG_WARNING, "'%s' is not a valid order, should be primary, secondary, tertiary or quartiary at line %d\n", v->value, v->lineno);
+ }
+ } else if (!strcasecmp(v->name, "qualify")) {
+ if (!strcasecmp(v->value, "no")) {
+ peer->maxms = 0;
+ } else if (!strcasecmp(v->value, "yes")) {
+ peer->maxms = DEFAULT_MAXMS;
+ } else if (sscanf(v->value, "%d", &peer->maxms) != 1) {
+ ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno);
+ peer->maxms = 0;
+ }
+ } else if (!strcasecmp(v->name, "model")) {
+ if (!strcasecmp(v->value, "inbound"))
+ peer->model = DUNDI_MODEL_INBOUND;
+ else if (!strcasecmp(v->value, "outbound"))
+ peer->model = DUNDI_MODEL_OUTBOUND;
+ else if (!strcasecmp(v->value, "symmetric"))
+ peer->model = DUNDI_MODEL_SYMMETRIC;
+ else if (!strcasecmp(v->value, "none"))
+ peer->model = 0;
+ else {
+ ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n",
+ v->value, v->lineno);
+ }
+ } else if (!strcasecmp(v->name, "precache")) {
+ if (!strcasecmp(v->value, "inbound"))
+ peer->pcmodel = DUNDI_MODEL_INBOUND;
+ else if (!strcasecmp(v->value, "outbound"))
+ peer->pcmodel = DUNDI_MODEL_OUTBOUND;
+ else if (!strcasecmp(v->value, "symmetric"))
+ peer->pcmodel = DUNDI_MODEL_SYMMETRIC;
+ else if (!strcasecmp(v->value, "none"))
+ peer->pcmodel = 0;
+ else {
+ ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n",
+ v->value, v->lineno);
+ }
+ }
+ }
+ (*globalpcmode) |= peer->pcmodel;
+ if (!peer->model && !peer->pcmodel) {
+ ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ peer->dead = 1;
+ } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
+ ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ peer->dead = 1;
+ } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) {
+ ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ peer->dead = 1;
+ } else if (!AST_LIST_EMPTY(&peer->include) && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) {
+ ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ } else if (!AST_LIST_EMPTY(&peer->permit) && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) {
+ ast_log(LOG_WARNING, "Peer '%s' is supposed to have permission for some inbound searches but isn't an inbound peer or outbound precache!\n",
+ dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
+ } else {
+ if (needregister) {
+ peer->registerid = ast_sched_add(sched, 2000, do_register, peer);
+ }
+ qualify_peer(peer, 1);
+ }
+ AST_LIST_UNLOCK(&peers);
+}
+
+static int dundi_helper(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *data, int flag)
+{
+ struct dundi_result results[MAX_RESULTS];
+ int res;
+ int x;
+ int found = 0;
+ if (!strncasecmp(context, "macro-", 6)) {
+ if (!chan) {
+ ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
+ return -1;
+ }
+ /* If done as a macro, use macro extension */
+ if (!strcasecmp(exten, "s")) {
+ exten = pbx_builtin_getvar_helper(chan, "ARG1");
+ if (ast_strlen_zero(exten))
+ exten = chan->macroexten;
+ if (ast_strlen_zero(exten))
+ exten = chan->exten;
+ if (ast_strlen_zero(exten)) {
+ ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
+ return -1;
+ }
+ }
+ if (ast_strlen_zero(data))
+ data = "e164";
+ } else {
+ if (ast_strlen_zero(data))
+ data = context;
+ }
+ res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
+ for (x=0;x<res;x++) {
+ if (ast_test_flag(results + x, flag))
+ found++;
+ }
+ if (found >= priority)
+ return 1;
+ return 0;
+}
+
+static int dundi_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS);
+}
+
+static int dundi_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH);
+}
+
+static int dundi_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ struct dundi_result results[MAX_RESULTS];
+ int res;
+ int x=0;
+ char req[1024];
+ const char *dundiargs;
+ struct ast_app *dial;
+
+ if (!strncasecmp(context, "macro-", 6)) {
+ if (!chan) {
+ ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n");
+ return -1;
+ }
+ /* If done as a macro, use macro extension */
+ if (!strcasecmp(exten, "s")) {
+ exten = pbx_builtin_getvar_helper(chan, "ARG1");
+ if (ast_strlen_zero(exten))
+ exten = chan->macroexten;
+ if (ast_strlen_zero(exten))
+ exten = chan->exten;
+ if (ast_strlen_zero(exten)) {
+ ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n");
+ return -1;
+ }
+ }
+ if (ast_strlen_zero(data))
+ data = "e164";
+ } else {
+ if (ast_strlen_zero(data))
+ data = context;
+ }
+ res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0);
+ if (res > 0) {
+ sort_results(results, res);
+ for (x=0;x<res;x++) {
+ if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) {
+ if (!--priority)
+ break;
+ }
+ }
+ }
+ if (x < res) {
+ /* Got a hit! */
+ dundiargs = pbx_builtin_getvar_helper(chan, "DUNDIDIALARGS");
+ snprintf(req, sizeof(req), "%s/%s,,%s", results[x].tech, results[x].dest,
+ S_OR(dundiargs, ""));
+ dial = pbx_findapp("Dial");
+ if (dial)
+ res = pbx_exec(chan, dial, req);
+ } else
+ res = -1;
+ return res;
+}
+
+static int dundi_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE);
+}
+
+static struct ast_switch dundi_switch =
+{
+ name: "DUNDi",
+ description: "DUNDi Discovered Dialplan Switch",
+ exists: dundi_exists,
+ canmatch: dundi_canmatch,
+ exec: dundi_exec,
+ matchmore: dundi_matchmore,
+};
+
+static int set_config(char *config_file, struct sockaddr_in* sin, int reload)
+{
+ struct ast_config *cfg;
+ struct ast_variable *v;
+ char *cat;
+ int x;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ char hn[MAXHOSTNAMELEN] = "";
+ struct ast_hostent he;
+ struct hostent *hp;
+ struct sockaddr_in sin2;
+ static int last_port = 0;
+ int globalpcmodel = 0;
+ dundi_eid testeid;
+
+ if (!(cfg = ast_config_load(config_file, config_flags))) {
+ ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
+ return -1;
+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
+ return 0;
+
+ dundi_ttl = DUNDI_DEFAULT_TTL;
+ dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME;
+ any_peer = NULL;
+
+ ipaddr[0] = '\0';
+ if (!gethostname(hn, sizeof(hn)-1)) {
+ hp = ast_gethostbyname(hn, &he);
+ if (hp) {
+ memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));
+ ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));
+ } else
+ ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);
+ } else
+ ast_log(LOG_WARNING, "Unable to get host name!\n");
+ AST_LIST_LOCK(&peers);
+ reset_global_eid();
+ global_storehistory = 0;
+ ast_copy_string(secretpath, "dundi", sizeof(secretpath));
+ v = ast_variable_browse(cfg, "general");
+ while(v) {
+ if (!strcasecmp(v->name, "port")){
+ sin->sin_port = ntohs(atoi(v->value));
+ if(last_port==0){
+ last_port=sin->sin_port;
+ } else if(sin->sin_port != last_port)
+ ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");
+ } else if (!strcasecmp(v->name, "bindaddr")) {
+ struct hostent *hp;
+ struct ast_hostent he;
+ hp = ast_gethostbyname(v->value, &he);
+ if (hp) {
+ memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
+ } else
+ ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);
+ } else if (!strcasecmp(v->name, "authdebug")) {
+ authdebug = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "ttl")) {
+ if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) {
+ dundi_ttl = x;
+ } else {
+ ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n",
+ v->value, v->lineno, DUNDI_DEFAULT_TTL);
+ }
+ } else if (!strcasecmp(v->name, "autokill")) {
+ if (sscanf(v->value, "%d", &x) == 1) {
+ if (x >= 0)
+ global_autokilltimeout = x;
+ else
+ ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno);
+ } else if (ast_true(v->value)) {
+ global_autokilltimeout = DEFAULT_MAXMS;
+ } else {
+ global_autokilltimeout = 0;
+ }
+ } else if (!strcasecmp(v->name, "entityid")) {
+ if (!dundi_str_to_eid(&testeid, v->value))
+ global_eid = testeid;
+ else
+ ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno);
+ } else if (!strcasecmp(v->name, "tos")) {
+ if (ast_str2tos(v->value, &tos))
+ ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
+ } else if (!strcasecmp(v->name, "department")) {
+ ast_copy_string(dept, v->value, sizeof(dept));
+ } else if (!strcasecmp(v->name, "organization")) {
+ ast_copy_string(org, v->value, sizeof(org));
+ } else if (!strcasecmp(v->name, "locality")) {
+ ast_copy_string(locality, v->value, sizeof(locality));
+ } else if (!strcasecmp(v->name, "stateprov")) {
+ ast_copy_string(stateprov, v->value, sizeof(stateprov));
+ } else if (!strcasecmp(v->name, "country")) {
+ ast_copy_string(country, v->value, sizeof(country));
+ } else if (!strcasecmp(v->name, "email")) {
+ ast_copy_string(email, v->value, sizeof(email));
+ } else if (!strcasecmp(v->name, "phone")) {
+ ast_copy_string(phone, v->value, sizeof(phone));
+ } else if (!strcasecmp(v->name, "storehistory")) {
+ global_storehistory = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "cachetime")) {
+ if ((sscanf(v->value, "%d", &x) == 1)) {
+ dundi_cache_time = x;
+ } else {
+ ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n",
+ v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME);
+ }
+ }
+ v = v->next;
+ }
+ AST_LIST_UNLOCK(&peers);
+ mark_mappings();
+ v = ast_variable_browse(cfg, "mappings");
+ while(v) {
+ build_mapping(v->name, v->value);
+ v = v->next;
+ }
+ prune_mappings();
+ mark_peers();
+ cat = ast_category_browse(cfg, NULL);
+ while(cat) {
+ if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) {
+ /* Entries */
+ if (!dundi_str_to_eid(&testeid, cat))
+ build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel);
+ else if (!strcasecmp(cat, "*")) {
+ build_peer(&empty_eid, ast_variable_browse(cfg, cat), &globalpcmodel);
+ any_peer = find_peer(NULL);
+ } else
+ ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat);
+ }
+ cat = ast_category_browse(cfg, cat);
+ }
+ prune_peers();
+ ast_config_destroy(cfg);
+ load_password();
+ if (globalpcmodel & DUNDI_MODEL_OUTBOUND)
+ dundi_precache_full();
+ return 0;
+}
+
+static int unload_module(void)
+{
+ pthread_t previous_netthreadid = netthreadid, previous_precachethreadid = precachethreadid;
+ ast_module_user_hangup_all();
+
+ /* Stop all currently running threads */
+ dundi_shutdown = 1;
+ if (previous_netthreadid != AST_PTHREADT_NULL) {
+ pthread_kill(previous_netthreadid, SIGURG);
+ pthread_join(previous_netthreadid, NULL);
+ }
+ if (previous_precachethreadid != AST_PTHREADT_NULL) {
+ pthread_kill(previous_precachethreadid, SIGURG);
+ pthread_join(previous_precachethreadid, NULL);
+ }
+
+ ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry));
+ ast_unregister_switch(&dundi_switch);
+ ast_custom_function_unregister(&dundi_function);
+ ast_custom_function_unregister(&dundi_query_function);
+ ast_custom_function_unregister(&dundi_result_function);
+ close(netsocket);
+ io_context_destroy(io);
+ sched_context_destroy(sched);
+
+ mark_mappings();
+ prune_mappings();
+ mark_peers();
+ prune_peers();
+
+ return 0;
+}
+
+static int reload(void)
+{
+ struct sockaddr_in sin;
+
+ if (set_config("dundi.conf", &sin, 1))
+ return AST_MODULE_LOAD_FAILURE;
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int load_module(void)
+{
+ struct sockaddr_in sin;
+
+ dundi_set_output(dundi_debug_output);
+ dundi_set_error(dundi_error_output);
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = ntohs(DUNDI_PORT);
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ /* Make a UDP socket */
+ io = io_context_create();
+ sched = sched_context_create();
+
+ if (!io || !sched)
+ return AST_MODULE_LOAD_FAILURE;
+
+ if (set_config("dundi.conf", &sin, 0))
+ return AST_MODULE_LOAD_DECLINE;
+
+ netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (netsocket < 0) {
+ ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
+ return AST_MODULE_LOAD_FAILURE;
+ }
+ if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) {
+ ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n",
+ ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+ ast_netsock_set_qos(netsocket, tos, 0, "DUNDi");
+
+ if (start_network_thread()) {
+ ast_log(LOG_ERROR, "Unable to start network thread\n");
+ close(netsocket);
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+ ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(*cli_dundi));
+ if (ast_register_switch(&dundi_switch))
+ ast_log(LOG_ERROR, "Unable to register DUNDi switch\n");
+ ast_custom_function_register(&dundi_function);
+ ast_custom_function_register(&dundi_query_function);
+ ast_custom_function_register(&dundi_result_function);
+
+ ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Distributed Universal Number Discovery (DUNDi)",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
+
diff --git a/trunk/pbx/pbx_gtkconsole.c b/trunk/pbx/pbx_gtkconsole.c
new file mode 100644
index 000000000..5e47ac668
--- /dev/null
+++ b/trunk/pbx/pbx_gtkconsole.c
@@ -0,0 +1,502 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief GTK Console monitor -- very kludgy right now
+ *
+ */
+
+/*** MODULEINFO
+ <depend>gtk</depend>
+ <defaultenabled>no</defaultenabled>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#include "asterisk/pbx.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/cli.h"
+#include "asterisk/utils.h"
+#include "asterisk/paths.h"
+#include "asterisk/term.h"
+
+AST_MUTEX_DEFINE_STATIC(verb_lock);
+
+static pthread_t console_thread;
+
+static int inuse=0;
+static int clipipe[2];
+static int cleanupid = -1;
+
+static GtkWidget *window;
+static GtkWidget *quit;
+static GtkWidget *closew;
+static GtkWidget *verb;
+static GtkWidget *modules;
+static GtkWidget *statusbar;
+static GtkWidget *cli;
+
+static struct timeval last;
+
+static void update_statusbar(char *msg)
+{
+ gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 1);
+ gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, msg);
+}
+
+static int unload_module(void)
+{
+ if (inuse) {
+ /* Kill off the main thread */
+ pthread_cancel(console_thread);
+ gdk_threads_enter();
+ gtk_widget_destroy(window);
+ gdk_threads_leave();
+ close(clipipe[0]);
+ close(clipipe[1]);
+ }
+ return 0;
+}
+
+static int cleanup(void *useless)
+{
+ gdk_threads_enter();
+ gtk_clist_thaw(GTK_CLIST(verb));
+ gtk_widget_queue_resize(verb->parent);
+ gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0);
+ cleanupid = -1;
+ gdk_threads_leave();
+ return 0;
+}
+
+
+static void __verboser(const char *_stuff)
+{
+ char *s2[2];
+ struct timeval tv;
+ int ms;
+ char *stuff;
+
+ stuff = ast_strdupa(_stuff);
+ term_strip(stuff, stuff, strlen(stuff) + 1);
+
+ s2[0] = (char *)stuff;
+ s2[1] = NULL;
+ gtk_clist_freeze(GTK_CLIST(verb));
+ gtk_clist_append(GTK_CLIST(verb), s2);
+ if (!ast_tvzero(last)) {
+ gdk_threads_leave();
+ gettimeofday(&tv, NULL);
+ if (cleanupid > -1)
+ gtk_timeout_remove(cleanupid);
+ ms = ast_tvdiff_ms(tv, last);
+ if (ms < 100) {
+ /* We just got a message within 100ms, so just schedule an update
+ in the near future */
+ cleanupid = gtk_timeout_add(200, cleanup, NULL);
+ } else {
+ cleanup(&cleanupid);
+ }
+ last = tv;
+ } else {
+ gettimeofday(&last, NULL);
+ }
+}
+
+static void verboser(const char *stuff)
+{
+ ast_mutex_lock(&verb_lock);
+ /* Lock appropriately if we're really being called in verbose mode */
+ __verboser(stuff);
+ ast_mutex_unlock(&verb_lock);
+}
+
+static void cliinput(void *data, int source, GdkInputCondition ic)
+{
+ static char buf[256];
+ static int offset = 0;
+ int res;
+ char *c;
+ char *l;
+ char n;
+ /* Read as much stuff is there */
+ res = read(source, buf + offset, sizeof(buf) - 1 - offset);
+ if (res > -1)
+ buf[res + offset] = '\0';
+ /* make sure we've null terminated whatever we have so far */
+ c = buf;
+ l = buf;
+ while(*c) {
+ if (*c == '\n') {
+ /* Keep the trailing \n */
+ c++;
+ n = *c;
+ *c = '\0';
+ __verboser(l);
+ *(c - 1) = '\0';
+ *c = n;
+ l = c;
+ } else
+ c++;
+ }
+ if (strlen(l)) {
+ /* We have some left over */
+ memmove(buf, l, strlen(l) + 1);
+ offset = strlen(buf);
+ } else {
+ offset = 0;
+ }
+
+}
+
+static void remove_module(void)
+{
+ int res;
+ char *module;
+ char buf[256];
+ if (GTK_CLIST(modules)->selection) {
+ module = (char *) gtk_clist_get_row_data(GTK_CLIST(modules), (long) GTK_CLIST(modules)->selection->data);
+ gdk_threads_leave();
+ res = ast_unload_resource(module, 0);
+ gdk_threads_enter();
+ if (res) {
+ snprintf(buf, sizeof(buf), "Module '%s' is in use", module);
+ update_statusbar(buf);
+ } else {
+ snprintf(buf, sizeof(buf), "Module '%s' removed", module);
+ update_statusbar(buf);
+ }
+ }
+}
+
+static int reload(void)
+{
+ int res, x;
+ char *module;
+ char buf[256];
+ if (GTK_CLIST(modules)->selection) {
+ module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (long) GTK_CLIST(modules)->selection->data);
+ module = strdup(module);
+ if (module) {
+ gdk_threads_leave();
+ res = ast_unload_resource(module, 0);
+ gdk_threads_enter();
+ if (res) {
+ snprintf(buf, sizeof(buf), "Module '%s' is in use", module);
+ update_statusbar(buf);
+ } else {
+ gdk_threads_leave();
+ res = ast_load_resource(module);
+ gdk_threads_enter();
+ if (res) {
+ snprintf(buf, sizeof(buf), "Error reloading module '%s'", module);
+ } else {
+ snprintf(buf, sizeof(buf), "Module '%s' reloaded", module);
+ }
+ for (x=0; x < GTK_CLIST(modules)->rows; x++) {
+ if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules), x), module)) {
+ gtk_clist_select_row(GTK_CLIST(modules), x, -1);
+ break;
+ }
+ }
+ update_statusbar(buf);
+
+ }
+ free(module);
+ }
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static void file_ok_sel(GtkWidget *w, GtkFileSelection *fs)
+{
+ char tmp[PATH_MAX];
+ char *module = gtk_file_selection_get_filename(fs);
+ char buf[256];
+ snprintf(tmp, sizeof(tmp), "%s/", ast_config_AST_MODULE_DIR);
+ if (!strncmp(module, (char *)tmp, strlen(tmp)))
+ module += strlen(tmp);
+ gdk_threads_leave();
+ if (ast_load_resource(module)) {
+ snprintf(buf, sizeof(buf), "Error loading module '%s'.", module);
+ update_statusbar(buf);
+ } else {
+ snprintf(buf, sizeof(buf), "Module '%s' loaded", module);
+ update_statusbar(buf);
+ }
+ gdk_threads_enter();
+ gtk_widget_destroy(GTK_WIDGET(fs));
+}
+
+static void add_module(void)
+{
+ char tmp[PATH_MAX];
+ GtkWidget *filew;
+ snprintf(tmp, sizeof(tmp), "%s/*.so", ast_config_AST_MODULE_DIR);
+ filew = gtk_file_selection_new("Load Module");
+ gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew)->ok_button),
+ "clicked", GTK_SIGNAL_FUNC(file_ok_sel), filew);
+ gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew)->cancel_button),
+ "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filew));
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), (char *)tmp);
+ gtk_widget_show(filew);
+}
+
+static int add_mod(const char *module, const char *description, int usecount, const char *like)
+{
+ char use[10];
+ const char *pass[4];
+ int row;
+ snprintf(use, sizeof(use), "%d", usecount);
+ pass[0] = module;
+ pass[1] = description;
+ pass[2] = use;
+ pass[3] = NULL;
+ row = gtk_clist_append(GTK_CLIST(modules), (char **) pass);
+ gtk_clist_set_row_data(GTK_CLIST(modules), row, (char *) module);
+ return 0;
+}
+
+static int mod_update(void)
+{
+ char *module= NULL;
+ /* Update the mod stuff */
+ if (GTK_CLIST(modules)->selection) {
+ module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (long) GTK_CLIST(modules)->selection->data);
+ }
+ gtk_clist_freeze(GTK_CLIST(modules));
+ gtk_clist_clear(GTK_CLIST(modules));
+ ast_update_module_list(add_mod, NULL);
+ if (module)
+ gtk_clist_select_row(GTK_CLIST(modules), gtk_clist_find_row_from_data(GTK_CLIST(modules), module), -1);
+ gtk_clist_thaw(GTK_CLIST(modules));
+ return 1;
+}
+
+static void exit_now(GtkWidget *widget, gpointer data)
+{
+ ast_loader_unregister(mod_update);
+ gtk_main_quit();
+ inuse--;
+ ast_update_use_count();
+ ast_unregister_verbose(verboser);
+ ast_unload_resource("pbx_gtkconsole", 0);
+ ast_verb(2, "GTK Console Monitor Exiting\n");
+ /* XXX Trying to quit after calling this makes asterisk segfault XXX */
+}
+
+static void exit_completely(GtkWidget *widget, gpointer data)
+{
+#if 0
+ /* Clever... */
+ ast_cli_command(clipipe[1], "quit");
+#else
+ kill(getpid(), SIGTERM);
+#endif
+}
+
+static void exit_nicely(GtkWidget *widget, gpointer data)
+{
+ fflush(stdout);
+ gtk_widget_destroy(window);
+}
+
+static void *consolethread(void *data)
+{
+ gtk_widget_show(window);
+ gdk_threads_enter();
+ gtk_main();
+ gdk_threads_leave();
+ return NULL;
+}
+
+static int cli_activate(void)
+{
+ char buf[256] = "";
+ strncpy(buf, gtk_entry_get_text(GTK_ENTRY(cli)), sizeof(buf) - 1);
+ gtk_entry_set_text(GTK_ENTRY(cli), "");
+ if (strlen(buf)) {
+ ast_cli_command(clipipe[1], buf);
+ }
+ return TRUE;
+}
+
+static int show_console(void)
+{
+ GtkWidget *hbox;
+ GtkWidget *wbox;
+ GtkWidget *notebook;
+ GtkWidget *sw;
+ GtkWidget *bbox, *hbbox, *add, *removew, *reloadw;
+ char *modtitles[3] = { "Module", "Description", "Use Count" };
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ statusbar = gtk_statusbar_new();
+ gtk_widget_show(statusbar);
+
+ gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC (exit_nicely), window);
+ gtk_signal_connect(GTK_OBJECT(window), "destroy",
+ GTK_SIGNAL_FUNC (exit_now), window);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+ quit = gtk_button_new_with_label("Quit Asterisk");
+ gtk_signal_connect(GTK_OBJECT(quit), "clicked",
+ GTK_SIGNAL_FUNC (exit_completely), window);
+ gtk_widget_show(quit);
+
+ closew = gtk_button_new_with_label("Close Window");
+ gtk_signal_connect(GTK_OBJECT(closew), "clicked",
+ GTK_SIGNAL_FUNC (exit_nicely), window);
+ gtk_widget_show(closew);
+
+ notebook = gtk_notebook_new();
+ verb = gtk_clist_new(1);
+ gtk_clist_columns_autosize(GTK_CLIST(verb));
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ gtk_container_add(GTK_CONTAINER(sw), verb);
+ gtk_widget_show(verb);
+ gtk_widget_show(sw);
+ gtk_widget_set_usize(verb, 640, 400);
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, gtk_label_new("Verbose Status"));
+
+
+ modules = gtk_clist_new_with_titles(3, modtitles);
+ gtk_clist_columns_autosize(GTK_CLIST(modules));
+ gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 0, TRUE);
+ gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 1, TRUE);
+ gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 2, TRUE);
+ gtk_clist_set_sort_column(GTK_CLIST(modules), 0);
+ gtk_clist_set_auto_sort(GTK_CLIST(modules), TRUE);
+ gtk_clist_column_titles_passive(GTK_CLIST(modules));
+ sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ gtk_container_add(GTK_CONTAINER(sw), modules);
+ gtk_clist_set_selection_mode(GTK_CLIST(modules), GTK_SELECTION_BROWSE);
+ gtk_widget_show(modules);
+ gtk_widget_show(sw);
+
+ add = gtk_button_new_with_label("Load...");
+ gtk_widget_show(add);
+ removew = gtk_button_new_with_label("Unload");
+ gtk_widget_show(removew);
+ reloadw = gtk_button_new_with_label("Reload");
+ gtk_widget_show(reloadw);
+ gtk_signal_connect(GTK_OBJECT(removew), "clicked",
+ GTK_SIGNAL_FUNC (remove_module), window);
+ gtk_signal_connect(GTK_OBJECT(add), "clicked",
+ GTK_SIGNAL_FUNC (add_module), window);
+ gtk_signal_connect(GTK_OBJECT(reloadw), "clicked",
+ GTK_SIGNAL_FUNC (reload), window);
+
+ bbox = gtk_vbox_new(FALSE, 5);
+ gtk_widget_show(bbox);
+
+ gtk_widget_set_usize(bbox, 100, -1);
+ gtk_box_pack_start(GTK_BOX(bbox), add, FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(bbox), removew, FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(bbox), reloadw, FALSE, FALSE, 5);
+
+ hbbox = gtk_hbox_new(FALSE, 5);
+ gtk_widget_show(hbbox);
+
+ gtk_box_pack_start(GTK_BOX(hbbox), sw, TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(hbbox), bbox, FALSE, FALSE, 5);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbbox, gtk_label_new("Module Information"));
+
+ gtk_widget_show(notebook);
+
+ wbox = gtk_hbox_new(FALSE, 5);
+ gtk_widget_show(wbox);
+ gtk_box_pack_end(GTK_BOX(wbox), quit, FALSE, FALSE, 5);
+ gtk_box_pack_end(GTK_BOX(wbox), closew, FALSE, FALSE, 5);
+
+ hbox = gtk_vbox_new(FALSE, 0);
+ gtk_widget_show(hbox);
+
+ /* Command line */
+ cli = gtk_entry_new();
+ gtk_widget_show(cli);
+
+ gtk_signal_connect(GTK_OBJECT(cli), "activate",
+ GTK_SIGNAL_FUNC (cli_activate), NULL);
+
+ gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), wbox, FALSE, FALSE, 5);
+ gtk_box_pack_start(GTK_BOX(hbox), cli, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), statusbar, FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(window), hbox);
+ gtk_window_set_title(GTK_WINDOW(window), "Asterisk Console");
+ gtk_widget_grab_focus(cli);
+ ast_pthread_create(&console_thread, NULL, consolethread, NULL);
+ /* XXX Okay, seriously fix me! XXX */
+ usleep(100000);
+ ast_register_verbose(verboser);
+ gtk_clist_freeze(GTK_CLIST(verb));
+ ast_loader_register(mod_update);
+ gtk_clist_thaw(GTK_CLIST(verb));
+ gdk_input_add(clipipe[0], GDK_INPUT_READ, cliinput, NULL);
+ mod_update();
+ update_statusbar("Asterisk Console Ready");
+ return 0;
+}
+
+
+static int load_module(void)
+{
+ if (pipe(clipipe)) {
+ ast_log(LOG_WARNING, "Unable to create CLI pipe\n");
+ return AST_MODULE_LOAD_FAILURE;
+ }
+ g_thread_init(NULL);
+ if (gtk_init_check(NULL, NULL)) {
+ if (!show_console()) {
+ inuse++;
+ ast_update_use_count();
+ ast_verb(2, "Launched GTK Console monitor\n");
+ } else
+ ast_log(LOG_WARNING, "Unable to start GTK console\n");
+ } else {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Unable to start GTK console monitor -- ignoring\n");
+ else
+ ast_verb(2, "GTK is not available -- skipping monitor\n");
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "GTK Console",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
diff --git a/trunk/pbx/pbx_loopback.c b/trunk/pbx/pbx_loopback.c
new file mode 100644
index 000000000..e6f4ed904
--- /dev/null
+++ b/trunk/pbx/pbx_loopback.c
@@ -0,0 +1,176 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Loopback PBX Module
+ *
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/frame.h"
+#include "asterisk/cli.h"
+#include "asterisk/lock.h"
+#include "asterisk/md5.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/chanvars.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/utils.h"
+#include "asterisk/crypto.h"
+#include "asterisk/astdb.h"
+
+
+/* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into
+ the data passed to it to try to get a string of the form:
+
+ [exten]@context[:priority][/extramatch]
+
+ Where exten, context, and priority are another extension, context, and priority
+ to lookup and "extramatch" is an extra match restriction the *original* number
+ must fit if specified. The "extramatch" begins with _ like an exten pattern
+ if it is specified. Note that the search context MUST be a different context
+ from the current context or the search will not succeed in an effort to reduce
+ the likelihood of loops (they're still possible if you try hard, so be careful!)
+
+*/
+
+
+#define LOOPBACK_COMMON \
+ char buf[1024]; \
+ int res; \
+ char *newexten=(char *)exten, *newcontext=(char *)context; \
+ int newpriority=priority; \
+ char *newpattern=NULL; \
+ loopback_helper(buf, sizeof(buf), exten, context, priority, data); \
+ loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \
+ ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \
+ if (!strcasecmp(newcontext, context)) return -1
+
+
+static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data)
+{
+ struct ast_var_t *newvariable;
+ struct varshead headp;
+ char tmp[80];
+
+ snprintf(tmp, sizeof(tmp), "%d", priority);
+ AST_LIST_HEAD_INIT_NOLOCK(&headp);
+ AST_LIST_INSERT_HEAD(&headp, ast_var_assign("EXTEN", exten), entries);
+ AST_LIST_INSERT_HEAD(&headp, ast_var_assign("CONTEXT", context), entries);
+ AST_LIST_INSERT_HEAD(&headp, ast_var_assign("PRIORITY", tmp), entries);
+ /* Substitute variables */
+ pbx_substitute_variables_varshead(&headp, data, buf, buflen);
+ /* free the list */
+ while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries)))
+ ast_var_delete(newvariable);
+ return buf;
+}
+
+static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf)
+{
+ char *con;
+ char *pri;
+ *newpattern = strchr(buf, '/');
+ if (*newpattern)
+ *(*newpattern)++ = '\0';
+ con = strchr(buf, '@');
+ if (con) {
+ *con++ = '\0';
+ pri = strchr(con, ':');
+ } else
+ pri = strchr(buf, ':');
+ if (!ast_strlen_zero(buf))
+ *newexten = buf;
+ if (!ast_strlen_zero(con))
+ *newcontext = con;
+ if (!ast_strlen_zero(pri))
+ sscanf(pri, "%d", priority);
+}
+
+static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ LOOPBACK_COMMON;
+ res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
+ if (newpattern && !ast_extension_match(newpattern, exten))
+ res = 0;
+ return res;
+}
+
+static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ LOOPBACK_COMMON;
+ res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid);
+ if (newpattern && !ast_extension_match(newpattern, exten))
+ res = 0;
+ return res;
+}
+
+static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ int found;
+ LOOPBACK_COMMON;
+ res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0);
+ /* XXX hmmm... res is overridden ? */
+ if (newpattern && !ast_extension_match(newpattern, exten))
+ res = -1;
+ return res;
+}
+
+static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ LOOPBACK_COMMON;
+ res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid);
+ if (newpattern && !ast_extension_match(newpattern, exten))
+ res = 0;
+ return res;
+}
+
+static struct ast_switch loopback_switch =
+{
+ name: "Loopback",
+ description: "Loopback Dialplan Switch",
+ exists: loopback_exists,
+ canmatch: loopback_canmatch,
+ exec: loopback_exec,
+ matchmore: loopback_matchmore,
+};
+
+static int unload_module(void)
+{
+ ast_unregister_switch(&loopback_switch);
+ return 0;
+}
+
+static int load_module(void)
+{
+ if (ast_register_switch(&loopback_switch))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch");
diff --git a/trunk/pbx/pbx_lua.c b/trunk/pbx/pbx_lua.c
new file mode 100644
index 000000000..a23b31ee2
--- /dev/null
+++ b/trunk/pbx/pbx_lua.c
@@ -0,0 +1,1354 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2007, Digium, Inc.
+ *
+ * Matthew Nicholson <mnicholson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \author Matthew Nicholson <mnicholson@digium.com>
+ * \brief Lua PBX Switch
+ *
+ */
+
+/*** MODULEINFO
+ <depend>lua</depend>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/cli.h"
+#include "asterisk/utils.h"
+#include "asterisk/term.h"
+#include "asterisk/paths.h"
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+static char *config = "extensions.lua";
+
+#define LUA_EXT_DATA_SIZE 256
+#define LUA_BUF_SIZE 4096
+
+static char *lua_read_extensions_file(lua_State *L, long *size);
+static int lua_load_extensions(lua_State *L, struct ast_channel *chan);
+static int lua_reload_extensions(lua_State *L);
+static void lua_free_extensions(void);
+static int lua_sort_extensions(lua_State *L);
+static int lua_extension_cmp(lua_State *L);
+static int lua_find_extension(lua_State *L, const char *context, const char *exten, int priority, ast_switch_f *func, int push_func);
+static int lua_pbx_findapp(lua_State *L);
+static int lua_pbx_exec(lua_State *L);
+
+static int lua_get_variable_value(lua_State *L);
+static int lua_set_variable_value(lua_State *L);
+static int lua_get_variable(lua_State *L);
+static int lua_set_variable(lua_State *L);
+static int lua_func_read(lua_State *L);
+
+static int lua_autoservice_start(lua_State *L);
+static int lua_autoservice_stop(lua_State *L);
+static int lua_autoservice_status(lua_State *L);
+static int lua_check_hangup(lua_State *L);
+
+static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority);
+static void lua_push_variable_table(lua_State *L, const char *name);
+static void lua_create_app_table(lua_State *L);
+static void lua_create_channel_table(lua_State *L);
+static void lua_create_variable_metatable(lua_State *L);
+static void lua_create_application_metatable(lua_State *L);
+static void lua_create_autoservice_functions(lua_State *L);
+static void lua_create_hangup_function(lua_State *L);
+
+void lua_state_destroy(void *data);
+static lua_State *lua_get_state(struct ast_channel *chan);
+
+static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
+static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
+static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
+static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
+
+AST_MUTEX_DEFINE_STATIC(config_file_lock);
+char *config_file_data = NULL;
+long config_file_size = 0;
+
+static const struct ast_datastore_info lua_datastore = {
+ .type = "lua",
+ .destroy = lua_state_destroy,
+};
+
+
+/*!
+ * \brief The destructor for lua_datastore
+ */
+void lua_state_destroy(void *data)
+{
+ if (data)
+ lua_close(data);
+}
+
+/*!
+ * \brief [lua_CFunction] Find an app and return it in a lua table (for access from lua, don't
+ * call directly)
+ *
+ * This function would be called in the following example as it would be found
+ * in extensions.lua.
+ *
+ * \code
+ * app.dial
+ * \endcode
+ */
+static int lua_pbx_findapp(lua_State *L)
+{
+ const char *app_name = luaL_checkstring(L, 2);
+
+ lua_newtable(L);
+
+ lua_pushstring(L, "name");
+ lua_pushstring(L, app_name);
+ lua_settable(L, -3);
+
+ luaL_getmetatable(L, "application");
+ lua_setmetatable(L, -2);
+
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] This function is part of the 'application' metatable
+ * and is used to execute applications similar to pbx_exec() (for access from
+ * lua, don't call directly)
+ *
+ * \param L the lua_State to use
+ * \return nothing
+ *
+ * This funciton is executed as the '()' operator for apps accessed through the
+ * 'app' table.
+ *
+ * \code
+ * app.playback('demo-congrats')
+ * \endcode
+ */
+static int lua_pbx_exec(lua_State *L)
+{
+ int res, nargs = lua_gettop(L);
+ char data[LUA_EXT_DATA_SIZE] = "";
+ char *data_next = data, *app_name;
+ char *context, *exten;
+ char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE];
+ int priority, autoservice;
+ size_t data_left = sizeof(data);
+ struct ast_app *app;
+ struct ast_channel *chan;
+
+ lua_getfield(L, 1, "name");
+ app_name = ast_strdupa(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ if (!(app = pbx_findapp(app_name))) {
+ lua_pushstring(L, "application '");
+ lua_pushstring(L, app_name);
+ lua_pushstring(L, "' not found");
+ lua_concat(L, 3);
+ return lua_error(L);
+ }
+
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "context");
+ context = ast_strdupa(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "exten");
+ exten = ast_strdupa(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "priority");
+ priority = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+
+ if (nargs > 1) {
+ int i;
+
+ if (!lua_isnil(L, 2))
+ ast_build_string(&data_next, &data_left, "%s", luaL_checkstring(L, 2));
+
+ for (i = 3; i <= nargs; i++) {
+ if (lua_isnil(L, i))
+ ast_build_string(&data_next, &data_left, ",");
+ else
+ ast_build_string(&data_next, &data_left, ",%s", luaL_checkstring(L, i));
+ }
+ }
+
+ ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
+ exten, context, priority,
+ term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)),
+ term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
+ term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3)));
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
+ autoservice = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+
+ if (autoservice)
+ ast_autoservice_stop(chan);
+
+ res = pbx_exec(chan, app, data);
+
+ if (autoservice)
+ ast_autoservice_start(chan);
+
+ /* error executing an application, report it */
+ if (res) {
+ lua_pushinteger(L, res);
+ return lua_error(L);
+ }
+ return 0;
+}
+
+/*!
+ * \brief [lua_CFunction] Used to get the value of a variable or dialplan
+ * function (for access from lua, don't call directly)
+ *
+ * The value of the variable or function is returned. This function is the
+ * 'get()' function in the following example as would be seen in
+ * extensions.lua.
+ *
+ * \code
+ * channel.variable:get()
+ * \endcode
+ */
+static int lua_get_variable_value(lua_State *L)
+{
+ struct ast_channel *chan;
+ char *value = NULL, *name;
+ char *workspace = alloca(LUA_BUF_SIZE);
+ int autoservice;
+
+ workspace[0] = '\0';
+
+ if (!lua_istable(L, 1)) {
+ lua_pushstring(L, "User probably used '.' instead of ':' for retrieving a channel variable value");
+ return lua_error(L);
+ }
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "name");
+ name = ast_strdupa(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
+ autoservice = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+
+ if (autoservice)
+ ast_autoservice_stop(chan);
+
+ /* if this is a dialplan function then use ast_func_read(), otherwise
+ * use pbx_retrieve_variable() */
+ if (!ast_strlen_zero(name) && name[strlen(name) - 1] == ')') {
+ value = ast_func_read(chan, name, workspace, LUA_BUF_SIZE) ? NULL : workspace;
+ } else {
+ pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, &chan->varshead);
+ }
+
+ if (autoservice)
+ ast_autoservice_start(chan);
+
+ if (value) {
+ lua_pushstring(L, value);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] Used to set the value of a variable or dialplan
+ * function (for access from lua, don't call directly)
+ *
+ * This function is the 'set()' function in the following example as would be
+ * seen in extensions.lua.
+ *
+ * \code
+ * channel.variable:set("value")
+ * \endcode
+ */
+static int lua_set_variable_value(lua_State *L)
+{
+ const char *name, *value;
+ struct ast_channel *chan;
+ int autoservice;
+
+ if (!lua_istable(L, 1)) {
+ lua_pushstring(L, "User probably used '.' instead of ':' for setting a channel variable");
+ return lua_error(L);
+ }
+
+ lua_getfield(L, 1, "name");
+ name = ast_strdupa(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ value = luaL_checkstring(L, 2);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
+ autoservice = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+
+ if (autoservice)
+ ast_autoservice_stop(chan);
+
+ pbx_builtin_setvar_helper(chan, name, value);
+
+ if (autoservice)
+ ast_autoservice_start(chan);
+
+ return 0;
+}
+
+/*!
+ * \brief Update the lua registry with the given context, exten, and priority.
+ *
+ * \param L the lua_State to use
+ * \param context the new context
+ * \param exten the new exten
+ * \param priority the new priority
+ */
+static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority)
+{
+ lua_pushstring(L, context);
+ lua_setfield(L, LUA_REGISTRYINDEX, "context");
+
+ lua_pushstring(L, exten);
+ lua_setfield(L, LUA_REGISTRYINDEX, "exten");
+
+ lua_pushinteger(L, priority);
+ lua_setfield(L, LUA_REGISTRYINDEX, "priority");
+}
+
+/*!
+ * \brief Push a 'variable' table on the stack for access the channel variable
+ * with the given name.
+ *
+ * \param L the lua_State to use
+ * \param name the name of the variable
+ */
+static void lua_push_variable_table(lua_State *L, const char *name)
+{
+ lua_newtable(L);
+ luaL_getmetatable(L, "variable");
+ lua_setmetatable(L, -2);
+
+ lua_pushstring(L, name);
+ lua_setfield(L, -2, "name");
+
+ lua_pushcfunction(L, &lua_get_variable_value);
+ lua_setfield(L, -2, "get");
+
+ lua_pushcfunction(L, &lua_set_variable_value);
+ lua_setfield(L, -2, "set");
+}
+
+/*!
+ * \brief Create the global 'app' table for executing applications
+ *
+ * \param L the lua_State to use
+ */
+static void lua_create_app_table(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_newmetatable(L, "app");
+
+ lua_pushstring(L, "__index");
+ lua_pushcfunction(L, &lua_pbx_findapp);
+ lua_settable(L, -3);
+
+ lua_setmetatable(L, -2);
+ lua_setglobal(L, "app");
+}
+
+/*!
+ * \brief Create the global 'channel' table for accesing channel variables
+ *
+ * \param L the lua_State to use
+ */
+static void lua_create_channel_table(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_newmetatable(L, "channel_data");
+
+ lua_pushstring(L, "__index");
+ lua_pushcfunction(L, &lua_get_variable);
+ lua_settable(L, -3);
+
+ lua_pushstring(L, "__newindex");
+ lua_pushcfunction(L, &lua_set_variable);
+ lua_settable(L, -3);
+
+ lua_setmetatable(L, -2);
+ lua_setglobal(L, "channel");
+}
+
+/*!
+ * \brief Create the 'variable' metatable, used to retrieve channel variables
+ *
+ * \param L the lua_State to use
+ */
+static void lua_create_variable_metatable(lua_State *L)
+{
+ luaL_newmetatable(L, "variable");
+
+ lua_pushstring(L, "__call");
+ lua_pushcfunction(L, &lua_func_read);
+ lua_settable(L, -3);
+
+ lua_pop(L, 1);
+}
+
+/*!
+ * \brief Create the 'application' metatable, used to execute asterisk
+ * applications from lua
+ *
+ * \param L the lua_State to use
+ */
+static void lua_create_application_metatable(lua_State *L)
+{
+ luaL_newmetatable(L, "application");
+
+ lua_pushstring(L, "__call");
+ lua_pushcfunction(L, &lua_pbx_exec);
+ lua_settable(L, -3);
+
+ lua_pop(L, 1);
+}
+
+/*!
+ * \brief Create the autoservice functions
+ *
+ * \param L the lua_State to use
+ */
+static void lua_create_autoservice_functions(lua_State *L)
+{
+ lua_pushcfunction(L, &lua_autoservice_start);
+ lua_setglobal(L, "autoservice_start");
+
+ lua_pushcfunction(L, &lua_autoservice_stop);
+ lua_setglobal(L, "autoservice_stop");
+
+ lua_pushcfunction(L, &lua_autoservice_status);
+ lua_setglobal(L, "autoservice_status");
+
+ lua_pushboolean(L, 0);
+ lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
+}
+
+/*!
+ * \brief Create the hangup check function
+ *
+ * \param L the lua_State to use
+ */
+static void lua_create_hangup_function(lua_State *L)
+{
+ lua_pushcfunction(L, &lua_check_hangup);
+ lua_setglobal(L, "check_hangup");
+}
+
+/*!
+ * \brief [lua_CFunction] Return a lua 'variable' object (for access from lua, don't call
+ * directly)
+ *
+ * This function is called to lookup a variable construct a 'variable' object.
+ * It would be called in the following example as would be seen in
+ * extensions.lua.
+ *
+ * \code
+ * channel.variable
+ * \endcode
+ */
+static int lua_get_variable(lua_State *L)
+{
+ struct ast_channel *chan;
+ char *name = ast_strdupa(luaL_checkstring(L, 2));
+ char *value = NULL;
+ char *workspace = alloca(LUA_BUF_SIZE);
+ workspace[0] = '\0';
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_push_variable_table(L, name);
+
+ /* if this is not a request for a dialplan funciton attempt to retrieve
+ * the value of the variable */
+ if (!ast_strlen_zero(name) && name[strlen(name) - 1] != ')') {
+ pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, &chan->varshead);
+ }
+
+ if (value) {
+ lua_pushstring(L, value);
+ lua_setfield(L, -2, "value");
+ }
+
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] Set the value of a channel variable or dialplan
+ * function (for access from lua, don't call directly)
+ *
+ * This function is called to set a variable or dialplan function. It would be
+ * called in the following example as would be seen in extensions.lua.
+ *
+ * \code
+ * channel.variable = "value"
+ * \endcode
+ */
+static int lua_set_variable(lua_State *L)
+{
+ struct ast_channel *chan;
+ int autoservice;
+ const char *name = luaL_checkstring(L, 2);
+ const char *value = luaL_checkstring(L, 3);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
+ autoservice = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+
+ if (autoservice)
+ ast_autoservice_stop(chan);
+
+ pbx_builtin_setvar_helper(chan, name, value);
+
+ if (autoservice)
+ ast_autoservice_start(chan);
+
+ return 0;
+}
+
+/*!
+ * \brief [lua_CFunction] Create a 'variable' object for accessing a dialplan
+ * function (for access from lua, don't call directly)
+ *
+ * This function is called to create a 'variable' object to access a dialplan
+ * function. It would be called in the following example as would be seen in
+ * extensions.lua.
+ *
+ * \code
+ * channel.func("arg1", "arg2", "arg3")
+ * \endcode
+ *
+ * To actually do anything with the resulting value you must use the 'get()'
+ * and 'set()' methods (the reason is the resulting value is not a value, but
+ * an object in the form of a lua table).
+ */
+static int lua_func_read(lua_State *L)
+{
+ int nargs = lua_gettop(L);
+ char fullname[LUA_EXT_DATA_SIZE] = "";
+ char *fullname_next = fullname, *name;
+ size_t fullname_left = sizeof(fullname);
+
+ lua_getfield(L, 1, "name");
+ name = ast_strdupa(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ ast_build_string(&fullname_next, &fullname_left, "%s(", name);
+
+ if (nargs > 1) {
+ int i;
+
+ if (!lua_isnil(L, 2))
+ ast_build_string(&fullname_next, &fullname_left, "%s", luaL_checkstring(L, 2));
+
+ for (i = 3; i <= nargs; i++) {
+ if (lua_isnil(L, i))
+ ast_build_string(&fullname_next, &fullname_left, ",");
+ else
+ ast_build_string(&fullname_next, &fullname_left, ",%s", luaL_checkstring(L, i));
+ }
+ }
+
+ ast_build_string(&fullname_next, &fullname_left, ")");
+
+ lua_push_variable_table(L, fullname);
+
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] Tell pbx_lua to maintain an autoservice on this
+ * channel (for access from lua, don't call directly)
+ *
+ * \param L the lua_State to use
+ *
+ * This function will set a flag that will cause pbx_lua to maintain an
+ * autoservice on this channel. The autoservice will automatically be stopped
+ * and restarted before calling applications and functions.
+ *
+ * \return This function returns the result of the ast_autoservice_start()
+ * function as a boolean to its lua caller.
+ */
+static int lua_autoservice_start(lua_State *L)
+{
+ struct ast_channel *chan;
+ int res;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ res = ast_autoservice_start(chan);
+
+ lua_pushboolean(L, !res);
+ lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
+
+ lua_pushboolean(L, !res);
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] Tell pbx_lua to stop maintaning an autoservice on
+ * this channel (for access from lua, don't call directly)
+ *
+ * \param L the lua_State to use
+ *
+ * This function will stop any autoservice running and turn off the autoservice
+ * flag. If this function returns false, it's probably because no autoservice
+ * was running to begin with.
+ *
+ * \return This function returns the result of the ast_autoservice_stop()
+ * function as a boolean to its lua caller.
+ */
+static int lua_autoservice_stop(lua_State *L)
+{
+ struct ast_channel *chan;
+ int res;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ res = ast_autoservice_stop(chan);
+
+ lua_pushboolean(L, 0);
+ lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
+
+ lua_pushboolean(L, !res);
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] Get the status of the autoservice flag (for access
+ * from lua, don't call directly)
+ *
+ * \param L the lua_State to use
+ *
+ * \return This function returns the status of the autoservice flag as a
+ * boolean to its lua caller.
+ */
+static int lua_autoservice_status(lua_State *L)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
+ return 1;
+}
+
+/*!
+ * \brief [lua_CFunction] Check if this channel has been hungup or not (for
+ * access from lua, don't call directly)
+ *
+ * \param L the lua_State to use
+ *
+ * \return This function returns true if the channel was hungup
+ */
+static int lua_check_hangup(lua_State *L)
+{
+ struct ast_channel *chan;
+ lua_getfield(L, LUA_REGISTRYINDEX, "channel");
+ chan = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushboolean(L, ast_check_hangup(chan));
+ return 1;
+}
+
+/*!
+ * \brief Store the sort order of each context
+
+ * In the event of an error, an error string will be pushed onto the lua stack.
+ *
+ * \retval 0 success
+ * \retval 1 failure
+ */
+static int lua_sort_extensions(lua_State *L)
+{
+ int extensions, extensions_order;
+
+ /* create the extensions_order table */
+ lua_newtable(L);
+ lua_setfield(L, LUA_REGISTRYINDEX, "extensions_order");
+ lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order");
+ extensions_order = lua_gettop(L);
+
+ /* sort each context in the extensions table */
+ /* load the 'extensions' table */
+ lua_getglobal(L, "extensions");
+ extensions = lua_gettop(L);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ lua_pushstring(L, "Unable to find 'extensions' table in extensions.lua\n");
+ return 1;
+ }
+
+ /* iterate through the extensions table and create a
+ * matching table (holding the sort order) in the
+ * extensions_order table for each context that is found
+ */
+ for (lua_pushnil(L); lua_next(L, extensions); lua_pop(L, 1)) {
+ int context = lua_gettop(L);
+ int context_name = context - 1;
+ int context_order;
+
+ lua_pushvalue(L, context_name);
+ lua_newtable(L);
+ context_order = lua_gettop(L);
+
+ /* iterate through this context an popluate the corrisponding
+ * table in the extensions_order table */
+ for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) {
+ int exten = lua_gettop(L) - 1;
+
+ lua_pushinteger(L, lua_objlen(L, context_order) + 1);
+ lua_pushvalue(L, exten);
+ lua_settable(L, context_order);
+ }
+ lua_settable(L, extensions_order); /* put the context_order table in the extensions_order table */
+
+ /* now sort the new table */
+
+ /* push the table.sort function */
+ lua_getglobal(L, "table");
+ lua_getfield(L, -1, "sort");
+ lua_remove(L, -2); /* remove the 'table' table */
+
+ /* push the context_order table */
+ lua_pushvalue(L, context_name);
+ lua_gettable(L, extensions_order);
+
+ /* push the comp function */
+ lua_pushcfunction(L, &lua_extension_cmp);
+
+ if (lua_pcall(L, 2, 0, 0)) {
+ lua_insert(L, -5);
+ lua_pop(L, 4);
+ return 1;
+ }
+ }
+
+ /* remove the extensions table and the extensions_order table */
+ lua_pop(L, 2);
+ return 0;
+}
+
+/*!
+ * \brief [lua_CFunction] Compare two extensions (for access from lua, don't
+ * call directly)
+ *
+ * This function returns true if the first extension passed should match after
+ * the second. It behaves like the '<' operator.
+ */
+static int lua_extension_cmp(lua_State *L)
+{
+ const char *a = luaL_checkstring(L, -2);
+ const char *b = luaL_checkstring(L, -1);
+
+ if (ast_extension_cmp(a, b) == -1)
+ lua_pushboolean(L, 1);
+ else
+ lua_pushboolean(L, 0);
+
+ return 1;
+}
+
+/*!
+ * \brief Load the extensions.lua file in to a buffer and execute the file
+ *
+ * \param L the lua_State to use
+ * \param size a pointer to store the size of the buffer
+ *
+ * \note The caller is expected to free the buffer at some point.
+ *
+ * \return a pointer to the buffer
+ */
+static char *lua_read_extensions_file(lua_State *L, long *size)
+{
+ FILE *f;
+ char *data;
+ char *path = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
+ sprintf(path, "%s/%s", ast_config_AST_CONFIG_DIR, config);
+
+ if (!(f = fopen(path, "r"))) {
+ lua_pushstring(L, "cannot open '");
+ lua_pushstring(L, path);
+ lua_pushstring(L, "' for reading: ");
+ lua_pushstring(L, strerror(errno));
+ lua_concat(L, 4);
+
+ return NULL;
+ }
+
+ fseek(f, 0l, SEEK_END);
+ *size = ftell(f);
+
+ fseek(f, 0l, SEEK_SET);
+
+ if (!(data = ast_malloc(*size))) {
+ *size = 0;
+ fclose(f);
+ lua_pushstring(L, "not enough memory");
+ return NULL;
+ }
+
+ fread(data, sizeof(char), *size, f);
+ fclose(f);
+
+ if (luaL_loadbuffer(L, data, *size, "extensions.lua")
+ || lua_pcall(L, 0, LUA_MULTRET, 0)
+ || lua_sort_extensions(L)) {
+ ast_free(data);
+ data = NULL;
+ *size = 0;
+ }
+ return data;
+}
+
+/*!
+ * \brief Load the extensions.lua file from the internal buffer
+ *
+ * \param L the lua_State to use
+ * \param chan channel to work on
+ *
+ * This function also sets up some constructs used by the extensions.lua file.
+ * In the event of an error, an error string will be pushed onto the lua stack.
+ *
+ * \retval 0 success
+ * \retval 1 failure
+ */
+static int lua_load_extensions(lua_State *L, struct ast_channel *chan)
+{
+
+ /* store a pointer to this channel */
+ lua_pushlightuserdata(L, chan);
+ lua_setfield(L, LUA_REGISTRYINDEX, "channel");
+
+ luaL_openlibs(L);
+
+ /* load and sort extensions */
+ ast_mutex_lock(&config_file_lock);
+ if (luaL_loadbuffer(L, config_file_data, config_file_size, "extensions.lua")
+ || lua_pcall(L, 0, LUA_MULTRET, 0)
+ || lua_sort_extensions(L)) {
+ ast_mutex_unlock(&config_file_lock);
+ return 1;
+ }
+ ast_mutex_unlock(&config_file_lock);
+
+ /* now we setup special tables and functions */
+
+ lua_create_app_table(L);
+ lua_create_channel_table(L);
+
+ lua_create_variable_metatable(L);
+ lua_create_application_metatable(L);
+
+ lua_create_autoservice_functions(L);
+ lua_create_hangup_function(L);
+
+ return 0;
+}
+
+/*!
+ * \brief Reload the extensions file and update the internal buffers if it
+ * loads correctly.
+ *
+ * \warning This function should not be called on a lua_State returned from
+ * lua_get_state().
+ *
+ * \param L the lua_State to use (must be freshly allocated with
+ * luaL_newstate(), don't use lua_get_state())
+ */
+static int lua_reload_extensions(lua_State *L)
+{
+ long size = 0;
+ char *data = NULL;
+
+ luaL_openlibs(L);
+
+ if (!(data = lua_read_extensions_file(L, &size))) {
+ return 1;
+ }
+
+ ast_mutex_lock(&config_file_lock);
+
+ if (config_file_data)
+ ast_free(config_file_data);
+
+ config_file_data = data;
+ config_file_size = size;
+
+ ast_mutex_unlock(&config_file_lock);
+ return 0;
+}
+
+/*!
+ * \brief Free the internal extensions buffer.
+ */
+static void lua_free_extensions()
+{
+ ast_mutex_lock(&config_file_lock);
+ config_file_size = 0;
+ ast_free(config_file_data);
+ ast_mutex_unlock(&config_file_lock);
+}
+
+/*!
+ * \brief Get the lua_State for this channel
+ *
+ * If no channel is passed then a new state is allocated. States with no
+ * channel assocatied with them should only be used for matching extensions.
+ * If the channel does not yet have a lua state associated with it, one will be
+ * created.
+ *
+ * \note If no channel was passed then the caller is expected to free the state
+ * using lua_close().
+ *
+ * \return a lua_State
+ */
+static lua_State *lua_get_state(struct ast_channel *chan)
+{
+ struct ast_datastore *datastore = NULL;
+ lua_State *L;
+
+ if (!chan) {
+ lua_State *L = luaL_newstate();
+ if (!L) {
+ ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
+ return NULL;
+ }
+
+ if (lua_load_extensions(L, NULL)) {
+ const char *error = lua_tostring(L, -1);
+ ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
+ lua_close(L);
+ return NULL;
+ }
+ return L;
+ } else {
+ datastore = ast_channel_datastore_find(chan, &lua_datastore, NULL);
+
+ if (!datastore) {
+ /* nothing found, allocate a new lua state */
+ datastore = ast_channel_datastore_alloc(&lua_datastore, NULL);
+ if (!datastore) {
+ ast_log(LOG_ERROR, "Error allocation channel datastore for lua_State\n");
+ return NULL;
+ }
+
+ datastore->data = luaL_newstate();
+ if (!datastore->data) {
+ ast_channel_datastore_free(datastore);
+ ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
+ return NULL;
+ }
+
+ ast_channel_lock(chan);
+ ast_channel_datastore_add(chan, datastore);
+ ast_channel_unlock(chan);
+
+ L = datastore->data;
+
+ if (lua_load_extensions(L, chan)) {
+ const char *error = lua_tostring(L, -1);
+ ast_log(LOG_ERROR, "Error loading extensions.lua for %s: %s\n", chan->name, error);
+
+ ast_channel_lock(chan);
+ ast_channel_datastore_remove(chan, datastore);
+ ast_channel_unlock(chan);
+
+ ast_channel_datastore_free(datastore);
+ return NULL;
+ }
+ }
+
+ return datastore->data;
+ }
+}
+
+static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ int res;
+ lua_State *L;
+ struct ast_module_user *u = ast_module_user_add(chan);
+ if (!u) {
+ ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
+ return 0;
+ }
+
+ L = lua_get_state(chan);
+ if (!L) {
+ ast_module_user_remove(u);
+ return 0;
+ }
+
+ res = lua_find_extension(L, context, exten, priority, &exists, 0);
+
+ if (!chan) lua_close(L);
+ ast_module_user_remove(u);
+ return res;
+}
+
+static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ int res;
+ lua_State *L;
+ struct ast_module_user *u = ast_module_user_add(chan);
+ if (!u) {
+ ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
+ return 0;
+ }
+
+ L = lua_get_state(chan);
+ if (!L) {
+ ast_module_user_remove(u);
+ return 0;
+ }
+
+ res = lua_find_extension(L, context, exten, priority, &canmatch, 0);
+
+ if (!chan) lua_close(L);
+ ast_module_user_remove(u);
+ return res;
+}
+
+static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ int res;
+ lua_State *L;
+ struct ast_module_user *u = ast_module_user_add(chan);
+ if (!u) {
+ ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
+ return 0;
+ }
+
+ L = lua_get_state(chan);
+ if (!L) {
+ ast_module_user_remove(u);
+ return 0;
+ }
+
+ res = lua_find_extension(L, context, exten, priority, &matchmore, 0);
+
+ if (!chan) lua_close(L);
+ ast_module_user_remove(u);
+ return res;
+}
+
+
+static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ int res;
+ lua_State *L;
+ struct ast_module_user *u = ast_module_user_add(chan);
+ if (!u) {
+ ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
+ return -1;
+ }
+
+ L = lua_get_state(chan);
+ if (!L) {
+ ast_module_user_remove(u);
+ return -1;
+ }
+
+ /* push the extension function onto the stack */
+ if (!lua_find_extension(L, context, exten, priority, &exists, 1)) {
+ ast_log(LOG_ERROR, "Could not find extension %s in context %s\n", exten, context);
+ if (!chan) lua_close(L);
+ ast_module_user_remove(u);
+ return -1;
+ }
+
+ lua_update_registry(L, context, exten, priority);
+
+ lua_pushstring(L, context);
+ lua_pushstring(L, exten);
+
+ res = lua_pcall(L, 2, 0, 0);
+ if (res) {
+ if (res == LUA_ERRRUN) {
+ if (lua_isnumber(L, -1)) {
+ res = lua_tointeger(L, -1);
+ } else if (lua_isstring(L, -1)) {
+ const char *error = lua_tostring(L, -1);
+ ast_log(LOG_ERROR, "Error executing lua extension: %s\n", error);
+ res = -1;
+ }
+ } else {
+ res = -1;
+ }
+ }
+ if (!chan) lua_close(L);
+ ast_module_user_remove(u);
+ return res;
+}
+
+/*!
+ * \brief Locate an extensions and optionally push the matching function on the
+ * stack
+ *
+ * \param L the lua_State to use
+ * \param context the context to look in
+ * \param exten the extension to look up
+ * \param priority the priority to check, '1' is the only valid priority
+ * \param func the calling func, used to adjust matching behavior between,
+ * match, canmatch, and matchmore
+ * \param push_func whether or not to push the lua function for the given
+ * extension onto the stack
+ */
+static int lua_find_extension(lua_State *L, const char *context, const char *exten, int priority, ast_switch_f *func, int push_func)
+{
+ int context_table, context_order_table, i;
+
+ ast_debug(2, "Looking up %s@%s:%i\n", exten, context, priority);
+ if (priority != 1)
+ return 0;
+
+ /* load the 'extensions' table */
+ lua_getglobal(L, "extensions");
+ if (lua_isnil(L, -1)) {
+ ast_log(LOG_ERROR, "Unable to find 'extensions' table in extensions.lua\n");
+ lua_pop(L, 1);
+ return 0;
+ }
+
+ /* load the given context */
+ lua_getfield(L, -1, context);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 2);
+ return 0;
+ }
+
+ /* remove the extensions table */
+ lua_remove(L, -2);
+
+ context_table = lua_gettop(L);
+
+ /* load the extensions order table for this context */
+ lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order");
+ lua_getfield(L, -1, context);
+
+ lua_remove(L, -2); /* remove the extensions order table */
+
+ context_order_table = lua_gettop(L);
+
+ /* step through the extensions looking for a match */
+ for (i = 1; i < lua_objlen(L, context_order_table) + 1; i++) {
+ int e_index, isnumber, match = 0;
+ const char *e;
+
+ lua_pushinteger(L, i);
+ lua_gettable(L, context_order_table);
+ e_index = lua_gettop(L);
+ isnumber = lua_isnumber(L, e_index);
+
+ if (!(e = lua_tostring(L, e_index))) {
+ lua_pop(L, 1);
+ continue;
+ }
+
+ /* make sure this is not the 'include' extension */
+ if (!strcasecmp(e, "include")) {
+ lua_pop(L, 1);
+ continue;
+ }
+
+ if (func == &matchmore)
+ match = ast_extension_close(e, exten, E_MATCHMORE);
+ else if (func == &canmatch)
+ match = ast_extension_close(e, exten, E_CANMATCH);
+ else
+ match = ast_extension_match(e, exten);
+
+ /* the extension matching functions return 0 on fail, 1 on
+ * match, 2 on earlymatch */
+
+ if (!match) {
+ lua_pop(L, 1);
+ continue; /* keep trying */
+ }
+
+ if (func == &matchmore && match == 2) {
+ /* We match an extension ending in '!'. The decision in
+ * this case is final and counts as no match. */
+ lua_pop(L, 3);
+ return 0;
+ }
+
+ /* remove the context table, the context order table, and the
+ * extension (or replace the extension with the corisponding
+ * function) */
+ if (push_func) {
+ /* here we must convert the exten back to an integer
+ * because lua_tostring will change the value on the
+ * stack to a string */
+ if (isnumber) {
+ int e_int = lua_tointeger(L, e_index);
+ lua_pop(L, 1); /* the exten should be the top of the stack */
+ lua_pushinteger(L, e_int);
+ }
+ lua_gettable(L, context_table);
+ lua_insert(L, -3);
+ lua_pop(L, 2);
+ } else {
+ lua_pop(L, 3);
+ }
+
+ return 1;
+ }
+
+ /* load the includes for this context */
+ lua_getfield(L, context_table, "include");
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 3);
+ return 0;
+ }
+
+ /* remove the context and the order table*/
+ lua_remove(L, context_order_table);
+ lua_remove(L, context_table);
+
+ /* Now try any includes we have in this context */
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
+ const char *c = lua_tostring(L, -1);
+ if (!c)
+ continue;
+
+ if (lua_find_extension(L, c, exten, priority, func, push_func)) {
+ /* remove the value, the key, and the includes table
+ * from the stack. Leave the function behind if
+ * necessary */
+
+ if (push_func)
+ lua_insert(L, -4);
+
+ lua_pop(L, 3);
+ return 1;
+ }
+ }
+
+ /* pop the includes table */
+ lua_pop(L, 1);
+ return 0;
+}
+
+static struct ast_switch lua_switch = {
+ .name = "Lua",
+ .description = "Lua PBX Switch",
+ .exists = exists,
+ .canmatch = canmatch,
+ .exec = exec,
+ .matchmore = matchmore,
+};
+
+
+static int load_or_reload_lua_stuff(void)
+{
+ int res = AST_MODULE_LOAD_SUCCESS;
+
+ lua_State *L = luaL_newstate();
+ if (!L) {
+ ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (lua_reload_extensions(L)) {
+ const char *error = lua_tostring(L, -1);
+ ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
+ res = AST_MODULE_LOAD_DECLINE;
+ }
+
+ lua_close(L);
+ return res;
+}
+
+static int unload_module(void)
+{
+ ast_unregister_switch(&lua_switch);
+ lua_free_extensions();
+ return 0;
+}
+
+static int reload(void)
+{
+ return load_or_reload_lua_stuff();
+}
+
+static int load_module(void)
+{
+ int res;
+
+ if ((res = load_or_reload_lua_stuff()))
+ return res;
+
+ if (ast_register_switch(&lua_switch)) {
+ ast_log(LOG_ERROR, "Unable to register LUA PBX switch\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Lua PBX Switch",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
+
diff --git a/trunk/pbx/pbx_realtime.c b/trunk/pbx/pbx_realtime.c
new file mode 100644
index 000000000..d4876bd7f
--- /dev/null
+++ b/trunk/pbx/pbx_realtime.c
@@ -0,0 +1,251 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Realtime PBX Module
+ *
+ * \arg See also: \ref AstARA
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/frame.h"
+#include "asterisk/term.h"
+#include "asterisk/manager.h"
+#include "asterisk/cli.h"
+#include "asterisk/lock.h"
+#include "asterisk/md5.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/chanvars.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/utils.h"
+#include "asterisk/crypto.h"
+#include "asterisk/astdb.h"
+
+#define MODE_MATCH 0
+#define MODE_MATCHMORE 1
+#define MODE_CANMATCH 2
+
+#define EXT_DATA_SIZE 256
+
+
+/* Realtime switch looks up extensions in the supplied realtime table.
+
+ [context@][realtimetable][/options]
+
+ If the realtimetable is omitted it is assumed to be "extensions". If no context is
+ specified the context is assumed to be whatever is the container.
+
+ The realtime table should have entries for context,exten,priority,app,args
+
+ The realtime table currently does not support callerid fields.
+
+*/
+
+
+static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode)
+{
+ struct ast_variable *var;
+ struct ast_config *cfg;
+ char pri[20];
+ char *ematch;
+ char rexten[AST_MAX_EXTENSION + 20]="";
+ int match;
+ snprintf(pri, sizeof(pri), "%d", priority);
+ switch(mode) {
+ case MODE_MATCHMORE:
+ ematch = "exten LIKE";
+ snprintf(rexten, sizeof(rexten), "%s_%%", exten);
+ break;
+ case MODE_CANMATCH:
+ ematch = "exten LIKE";
+ snprintf(rexten, sizeof(rexten), "%s%%", exten);
+ break;
+ case MODE_MATCH:
+ default:
+ ematch = "exten";
+ ast_copy_string(rexten, exten, sizeof(rexten));
+ }
+ var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL);
+ if (!var) {
+ cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
+ if (cfg) {
+ char *cat = ast_category_browse(cfg, NULL);
+
+ while(cat) {
+ switch(mode) {
+ case MODE_MATCHMORE:
+ match = ast_extension_close(cat, exten, 1);
+ break;
+ case MODE_CANMATCH:
+ match = ast_extension_close(cat, exten, 0);
+ break;
+ case MODE_MATCH:
+ default:
+ match = ast_extension_match(cat, exten);
+ }
+ if (match) {
+ var = ast_category_detach_variables(ast_category_get(cfg, cat));
+ break;
+ }
+ cat = ast_category_browse(cfg, cat);
+ }
+ ast_config_destroy(cfg);
+ }
+ }
+ return var;
+}
+
+static struct ast_variable *realtime_common(const char *context, const char *exten, int priority, const char *data, int mode)
+{
+ const char *ctx = NULL;
+ char *table;
+ struct ast_variable *var=NULL;
+ char *buf = ast_strdupa(data);
+ if (buf) {
+ char *opts = strchr(buf, '/');
+ if (opts)
+ *opts++ = '\0';
+ table = strchr(buf, '@');
+ if (table) {
+ *table++ = '\0';
+ ctx = buf;
+ }
+ ctx = S_OR(ctx, context);
+ table = S_OR(table, "extensions");
+ var = realtime_switch_common(table, ctx, exten, priority, mode);
+ }
+ return var;
+}
+
+static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
+ if (var) {
+ ast_variables_destroy(var);
+ return 1;
+ }
+ return 0;
+}
+
+static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_CANMATCH);
+ if (var) {
+ ast_variables_destroy(var);
+ return 1;
+ }
+ return 0;
+}
+
+static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ int res = -1;
+ struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCH);
+
+ if (var) {
+ char *tmp="";
+ char *app = NULL;
+ struct ast_variable *v;
+
+ for (v = var; v ; v = v->next) {
+ if (!strcasecmp(v->name, "app"))
+ app = ast_strdupa(v->value);
+ else if (!strcasecmp(v->name, "appdata"))
+ tmp = ast_strdupa(v->value);
+ }
+ ast_variables_destroy(var);
+ if (!ast_strlen_zero(app)) {
+ struct ast_app *a = pbx_findapp(app);
+ if (a) {
+ char appdata[512];
+ char tmp1[80];
+ char tmp2[80];
+ char tmp3[EXT_DATA_SIZE];
+
+ appdata[0] = 0; /* just in case the substitute var func isn't called */
+ if(!ast_strlen_zero(tmp))
+ pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1);
+ ast_verb(3, "Executing %s(\"%s\", \"%s\")\n",
+ term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)),
+ term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
+ term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
+ manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
+ "Channel: %s\r\n"
+ "Context: %s\r\n"
+ "Extension: %s\r\n"
+ "Priority: %d\r\n"
+ "Application: %s\r\n"
+ "AppData: %s\r\n"
+ "Uniqueid: %s\r\n",
+ chan->name, chan->context, chan->exten, chan->priority, app, !ast_strlen_zero(appdata) ? appdata : "(NULL)", chan->uniqueid);
+
+ res = pbx_exec(chan, a, appdata);
+ } else
+ ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context);
+ } else {
+ ast_log(LOG_WARNING, "No application specified for realtime extension '%s' in context '%s'\n", exten, context);
+ }
+ }
+ return res;
+}
+
+static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
+{
+ struct ast_variable *var = realtime_common(context, exten, priority, data, MODE_MATCHMORE);
+ if (var) {
+ ast_variables_destroy(var);
+ return 1;
+ }
+ return 0;
+}
+
+static struct ast_switch realtime_switch =
+{
+ name: "Realtime",
+ description: "Realtime Dialplan Switch",
+ exists: realtime_exists,
+ canmatch: realtime_canmatch,
+ exec: realtime_exec,
+ matchmore: realtime_matchmore,
+};
+
+static int unload_module(void)
+{
+ ast_unregister_switch(&realtime_switch);
+ return 0;
+}
+
+static int load_module(void)
+{
+ if (ast_register_switch(&realtime_switch))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Switch");
diff --git a/trunk/pbx/pbx_spool.c b/trunk/pbx/pbx_spool.c
new file mode 100644
index 000000000..113fc2b73
--- /dev/null
+++ b/trunk/pbx/pbx_spool.c
@@ -0,0 +1,509 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Full-featured outgoing call spool support
+ *
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/stat.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+
+#include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/callerid.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/utils.h"
+
+/*
+ * pbx_spool is similar in spirit to qcall, but with substantially enhanced functionality...
+ * The spool file contains a header
+ */
+
+enum {
+ /*! Always delete the call file after a call succeeds or the
+ * maximum number of retries is exceeded, even if the
+ * modification time of the call file is in the future.
+ */
+ SPOOL_FLAG_ALWAYS_DELETE = (1 << 0),
+ /* Don't unlink the call file after processing, move in qdonedir */
+ SPOOL_FLAG_ARCHIVE = (1 << 1)
+};
+
+static char qdir[255];
+static char qdonedir[255];
+
+struct outgoing {
+ char fn[256];
+ /*! Current number of retries */
+ int retries;
+ /*! Maximum number of retries permitted */
+ int maxretries;
+ /*! How long to wait between retries (in seconds) */
+ int retrytime;
+ /*! How long to wait for an answer */
+ int waittime;
+ /*! PID which is currently calling */
+ long callingpid;
+
+ /*! What to connect to outgoing */
+ char tech[256];
+ char dest[256];
+
+ /* If application */
+ char app[256];
+ char data[256];
+
+ /* If extension/context/priority */
+ char exten[AST_MAX_EXTENSION];
+ char context[AST_MAX_CONTEXT];
+ int priority;
+
+ /* CallerID Information */
+ char cid_num[256];
+ char cid_name[256];
+
+ /*! account code */
+ char account[AST_MAX_ACCOUNT_CODE];
+
+ /*! Variables and Functions */
+ struct ast_variable *vars;
+
+ /*! Maximum length of call */
+ int maxlen;
+
+ /*! options */
+ struct ast_flags options;
+};
+
+static void init_outgoing(struct outgoing *o)
+{
+ o->priority = 1;
+ o->retrytime = 300;
+ o->waittime = 45;
+ ast_set_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE);
+}
+
+static void free_outgoing(struct outgoing *o)
+{
+ ast_free(o);
+}
+
+static int apply_outgoing(struct outgoing *o, char *fn, FILE *f)
+{
+ char buf[256];
+ char *c, *c2;
+ int lineno = 0;
+ struct ast_variable *var;
+
+ while(fgets(buf, sizeof(buf), f)) {
+ lineno++;
+ /* Trim comments */
+ c = buf;
+ while ((c = strchr(c, '#'))) {
+ if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t'))
+ *c = '\0';
+ else
+ c++;
+ }
+
+ c = buf;
+ while ((c = strchr(c, ';'))) {
+ if ((c > buf) && (c[-1] == '\\')) {
+ memmove(c - 1, c, strlen(c) + 1);
+ c++;
+ } else {
+ *c = '\0';
+ break;
+ }
+ }
+
+ /* Trim trailing white space */
+ while(!ast_strlen_zero(buf) && buf[strlen(buf) - 1] < 33)
+ buf[strlen(buf) - 1] = '\0';
+ if (!ast_strlen_zero(buf)) {
+ c = strchr(buf, ':');
+ if (c) {
+ *c = '\0';
+ c++;
+ while ((*c) && (*c < 33))
+ c++;
+#if 0
+ printf("'%s' is '%s' at line %d\n", buf, c, lineno);
+#endif
+ if (!strcasecmp(buf, "channel")) {
+ ast_copy_string(o->tech, c, sizeof(o->tech));
+ if ((c2 = strchr(o->tech, '/'))) {
+ *c2 = '\0';
+ c2++;
+ ast_copy_string(o->dest, c2, sizeof(o->dest));
+ } else {
+ ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, fn);
+ o->tech[0] = '\0';
+ }
+ } else if (!strcasecmp(buf, "callerid")) {
+ ast_callerid_split(c, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
+ } else if (!strcasecmp(buf, "application")) {
+ ast_copy_string(o->app, c, sizeof(o->app));
+ } else if (!strcasecmp(buf, "data")) {
+ ast_copy_string(o->data, c, sizeof(o->data));
+ } else if (!strcasecmp(buf, "maxretries")) {
+ if (sscanf(c, "%d", &o->maxretries) != 1) {
+ ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn);
+ o->maxretries = 0;
+ }
+ } else if (!strcasecmp(buf, "context")) {
+ ast_copy_string(o->context, c, sizeof(o->context));
+ } else if (!strcasecmp(buf, "extension")) {
+ ast_copy_string(o->exten, c, sizeof(o->exten));
+ } else if (!strcasecmp(buf, "priority")) {
+ if ((sscanf(c, "%d", &o->priority) != 1) || (o->priority < 1)) {
+ ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, fn);
+ o->priority = 1;
+ }
+ } else if (!strcasecmp(buf, "retrytime")) {
+ if ((sscanf(c, "%d", &o->retrytime) != 1) || (o->retrytime < 1)) {
+ ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn);
+ o->retrytime = 300;
+ }
+ } else if (!strcasecmp(buf, "waittime")) {
+ if ((sscanf(c, "%d", &o->waittime) != 1) || (o->waittime < 1)) {
+ ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, fn);
+ o->waittime = 45;
+ }
+ } else if (!strcasecmp(buf, "retry")) {
+ o->retries++;
+ } else if (!strcasecmp(buf, "startretry")) {
+ if (sscanf(c, "%ld", &o->callingpid) != 1) {
+ ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n");
+ o->callingpid = 0;
+ }
+ } else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) {
+ o->callingpid = 0;
+ o->retries++;
+ } else if (!strcasecmp(buf, "delayedretry")) {
+ } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) {
+ c2 = c;
+ strsep(&c2, "=");
+ if (c2) {
+ var = ast_variable_new(c, c2, fn);
+ if (var) {
+ var->next = o->vars;
+ o->vars = var;
+ }
+ } else
+ ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", buf, buf);
+ } else if (!strcasecmp(buf, "account")) {
+ ast_copy_string(o->account, c, sizeof(o->account));
+ } else if (!strcasecmp(buf, "alwaysdelete")) {
+ ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE);
+ } else if (!strcasecmp(buf, "archive")) {
+ ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE);
+ } else {
+ ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
+ }
+ } else
+ ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn);
+ }
+ }
+ ast_copy_string(o->fn, fn, sizeof(o->fn));
+ if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
+ ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn);
+ return -1;
+ }
+ return 0;
+}
+
+static void safe_append(struct outgoing *o, time_t now, char *s)
+{
+ int fd;
+ FILE *f;
+ struct utimbuf tbuf;
+
+ if ((fd = open(o->fn, O_WRONLY | O_APPEND)) < 0)
+ return;
+
+ if ((f = fdopen(fd, "a"))) {
+ fprintf(f, "\n%s: %ld %d (%ld)\n", s, (long)ast_mainpid, o->retries, (long) now);
+ fclose(f);
+ } else
+ close(fd);
+
+ /* Update the file time */
+ tbuf.actime = now;
+ tbuf.modtime = now + o->retrytime;
+ if (utime(o->fn, &tbuf))
+ ast_log(LOG_WARNING, "Unable to set utime on %s: %s\n", o->fn, strerror(errno));
+}
+
+/*!
+ * \brief Remove a call file from the outgoing queue optionally moving it in the archive dir
+ *
+ * \param o the pointer to outgoing struct
+ * \param status the exit status of the call. Can be "Completed", "Failed" or "Expired"
+ */
+static int remove_from_queue(struct outgoing *o, const char *status)
+{
+ int fd;
+ FILE *f;
+ char newfn[256];
+ const char *bname;
+
+ if (!ast_test_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE)) {
+ struct stat current_file_status;
+
+ if (!stat(o->fn, &current_file_status)) {
+ if (time(NULL) < current_file_status.st_mtime)
+ return 0;
+ }
+ }
+
+ if (!ast_test_flag(&o->options, SPOOL_FLAG_ARCHIVE)) {
+ unlink(o->fn);
+ return 0;
+ }
+
+ if (ast_mkdir(qdonedir, 0777)) {
+ ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir);
+ unlink(o->fn);
+ return -1;
+ }
+
+ if ((fd = open(o->fn, O_WRONLY | O_APPEND))) {
+ if ((f = fdopen(fd, "a"))) {
+ fprintf(f, "Status: %s\n", status);
+ fclose(f);
+ } else
+ close(fd);
+ }
+
+ if (!(bname = strrchr(o->fn, '/')))
+ bname = o->fn;
+ else
+ bname++;
+ snprintf(newfn, sizeof(newfn), "%s/%s", qdonedir, bname);
+ /* a existing call file the archive dir is overwritten */
+ unlink(newfn);
+ if (rename(o->fn, newfn) != 0) {
+ unlink(o->fn);
+ return -1;
+ } else
+ return 0;
+}
+
+static void *attempt_thread(void *data)
+{
+ struct outgoing *o = data;
+ int res, reason;
+ if (!ast_strlen_zero(o->app)) {
+ ast_verb(3, "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
+ res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
+ } else {
+ ast_verb(3, "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
+ res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
+ }
+ if (res) {
+ ast_log(LOG_NOTICE, "Call failed to go through, reason (%d) %s\n", reason, ast_channel_reason2str(reason));
+ if (o->retries >= o->maxretries + 1) {
+ /* Max retries exceeded */
+ ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
+ remove_from_queue(o, "Expired");
+ } else {
+ /* Notate that the call is still active */
+ safe_append(o, time(NULL), "EndRetry");
+ }
+ } else {
+ ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest);
+ ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest);
+ remove_from_queue(o, "Completed");
+ }
+ free_outgoing(o);
+ return NULL;
+}
+
+static void launch_service(struct outgoing *o)
+{
+ pthread_t t;
+ int ret;
+
+ if ((ret = ast_pthread_create_detached(&t, NULL, attempt_thread, o))) {
+ ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret);
+ free_outgoing(o);
+ }
+}
+
+static int scan_service(char *fn, time_t now, time_t atime)
+{
+ struct outgoing *o = NULL;
+ FILE *f;
+ int res = 0;
+
+ if (!(o = ast_calloc(1, sizeof(*o)))) {
+ ast_log(LOG_WARNING, "Out of memory ;(\n");
+ return -1;
+ }
+
+ init_outgoing(o);
+
+ /* Attempt to open the file */
+ if (!(f = fopen(fn, "r+"))) {
+ remove_from_queue(o, "Failed");
+ free_outgoing(o);
+ ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno));
+ return -1;
+ }
+
+ /* Read in and verify the contents */
+ if (apply_outgoing(o, fn, f)) {
+ remove_from_queue(o, "Failed");
+ free_outgoing(o);
+ ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", fn);
+ fclose(f);
+ return -1;
+ }
+
+#if 0
+ printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries);
+#endif
+ fclose(f);
+ if (o->retries <= o->maxretries) {
+ now += o->retrytime;
+ if (o->callingpid && (o->callingpid == ast_mainpid)) {
+ safe_append(o, time(NULL), "DelayedRetry");
+ ast_log(LOG_DEBUG, "Delaying retry since we're currently running '%s'\n", o->fn);
+ free_outgoing(o);
+ } else {
+ /* Increment retries */
+ o->retries++;
+ /* If someone else was calling, they're presumably gone now
+ so abort their retry and continue as we were... */
+ if (o->callingpid)
+ safe_append(o, time(NULL), "AbortRetry");
+
+ safe_append(o, now, "StartRetry");
+ launch_service(o);
+ }
+ res = now;
+ } else {
+ ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
+ remove_from_queue(o, "Expired");
+ free_outgoing(o);
+ }
+
+ return res;
+}
+
+static void *scan_thread(void *unused)
+{
+ struct stat st;
+ DIR *dir;
+ struct dirent *de;
+ char fn[256];
+ int res;
+ time_t last = 0, next = 0, now;
+
+ for(;;) {
+ /* Wait a sec */
+ sleep(1);
+ time(&now);
+
+ if (stat(qdir, &st)) {
+ ast_log(LOG_WARNING, "Unable to stat %s\n", qdir);
+ continue;
+ }
+
+ /* Make sure it is time for us to execute our check */
+ if ((st.st_mtime == last) && (next && (next > now)))
+ continue;
+
+#if 0
+ printf("atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime);
+ printf("Ooh, something changed / timeout\n");
+#endif
+ next = 0;
+ last = st.st_mtime;
+
+ if (!(dir = opendir(qdir))) {
+ ast_log(LOG_WARNING, "Unable to open directory %s: %s\n", qdir, strerror(errno));
+ continue;
+ }
+
+ while ((de = readdir(dir))) {
+ snprintf(fn, sizeof(fn), "%s/%s", qdir, de->d_name);
+ if (stat(fn, &st)) {
+ ast_log(LOG_WARNING, "Unable to stat %s: %s\n", fn, strerror(errno));
+ continue;
+ }
+ if (!S_ISREG(st.st_mode))
+ continue;
+ if (st.st_mtime <= now) {
+ res = scan_service(fn, now, st.st_atime);
+ if (res > 0) {
+ /* Update next service time */
+ if (!next || (res < next)) {
+ next = res;
+ }
+ } else if (res)
+ ast_log(LOG_WARNING, "Failed to scan service '%s'\n", fn);
+ } else {
+ /* Update "next" update if necessary */
+ if (!next || (st.st_mtime < next))
+ next = st.st_mtime;
+ }
+ }
+ closedir(dir);
+ }
+ return NULL;
+}
+
+static int unload_module(void)
+{
+ return -1;
+}
+
+static int load_module(void)
+{
+ pthread_t thread;
+ int ret;
+ snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing");
+ if (ast_mkdir(qdir, 0777)) {
+ ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool disabled\n", qdir);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ snprintf(qdonedir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing_done");
+
+ if ((ret = ast_pthread_create_detached_background(&thread, NULL, scan_thread, NULL))) {
+ ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret);
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Outgoing Spool Support");