]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/commitdiff
Hinzugefügt:
authorms <ms@ea5c0bd1-69bd-2848-81d8-4f18e57aeed8>
Fri, 14 Apr 2006 23:12:47 +0000 (23:12 +0000)
committerms <ms@ea5c0bd1-69bd-2848-81d8-4f18e57aeed8>
Fri, 14 Apr 2006 23:12:47 +0000 (23:12 +0000)
  * Asterisk - mit Zaptel/LibPRI/BRISTUFF/app_fax
  * Spandsp
  * LibTIFF
  * LibXML2
  * eDonkey-commandline-client
Geändert:
  * busybox - tar-parameter zurückgesetzt
  * postfix hat Beta-Status-1

git-svn-id: http://svn.ipfire.org/svn/ipfire/trunk@101 ea5c0bd1-69bd-2848-81d8-4f18e57aeed8

33 files changed:
doc/packages-list.txt
lfs/asterisk [new file with mode: 0644]
lfs/busybox
lfs/edonkeyclc [new file with mode: 0644]
lfs/libtiff [new file with mode: 0644]
lfs/libxml2 [new file with mode: 0644]
lfs/postfix
lfs/spandsp [new file with mode: 0644]
make.sh
src/paks/asterisk/CONFFILES [new file with mode: 0644]
src/paks/asterisk/ROOTFILES [new file with mode: 0644]
src/paks/asterisk/install.sh [new file with mode: 0644]
src/paks/asterisk/uninstall.sh [new file with mode: 0644]
src/paks/edonkeyclc/CONFFILES [new file with mode: 0644]
src/paks/edonkeyclc/ROOTFILES [new file with mode: 0644]
src/paks/edonkeyclc/install.sh [new file with mode: 0644]
src/paks/edonkeyclc/uninstall.sh [new file with mode: 0644]
src/paks/libtiff/CONFFILES [new file with mode: 0644]
src/paks/libtiff/ROOTFILES [new file with mode: 0644]
src/paks/libtiff/install.sh [new file with mode: 0644]
src/paks/libtiff/uninstall.sh [new file with mode: 0644]
src/paks/libxml2/CONFFILES [new file with mode: 0644]
src/paks/libxml2/ROOTFILES [new file with mode: 0644]
src/paks/libxml2/install.sh [new file with mode: 0644]
src/paks/libxml2/uninstall.sh [new file with mode: 0644]
src/paks/spandsp/CONFFILES [new file with mode: 0644]
src/paks/spandsp/ROOTFILES [new file with mode: 0644]
src/paks/spandsp/install.sh [new file with mode: 0644]
src/paks/spandsp/uninstall.sh [new file with mode: 0644]
src/patches/asterisk-1.2.4-iax2-bristuff-0.3.0-PRE-1l.patch [new file with mode: 0644]
src/patches/asterisk-1.2.4-ipfire-bristuff-0.3.0-PRE-1l.patch [new file with mode: 0644]
src/patches/asterisk-1.2.4-libpri-bristuff-0.3.0-PRE-1l.patch [new file with mode: 0644]
src/patches/asterisk-1.2.4-zaptel-bristuff-0.3.0-PRE-1l.patch [new file with mode: 0644]

index bd1d335066a70d996dc40ee4d4324d232a2bc20f..b2ab7cd2837b0d22d6c63ecdbe7340b91da2cd39 100644 (file)
@@ -20,6 +20,8 @@
   * apache_1.3.34
   * arping-2.05
   * as86-0.16.17
+  * asterisk-1.2.4
+  * asterisk-1.2.4_1st
   * autoconf-2.59
   * automake-1.8.4
   * bash-2.05b
   * libnet-1.1.2.1
   * libpcap-0.8.3
   * libpng-1.2.8
+  * libpri-1.2.2
   * libsafe_2.0-16
   * libtool-1.5.6
   * libusb-0.1.7
   * libwww-perl-5.803
+  * libxml2-2.6.22
   * linux-2.4.31
   * linux-atm-2.4.1
   * logrotate-3.7
   * shadow-4.0.4.1
   * slang-1.4.5-mini
   * snort-2.3.3
+  * spandsp-0.0.2pre25
   * speedtouch-1.2
   * squid-2.5.STABLE13
   * squid-graph-3.1
   * tar-1.13.25
   * tcpdump-3.8.3
   * texinfo-4.7
+  * tiff-3.8.2
   * traceroute-1.4a12
   * uClibc-0.9.26
   * unzip552
   * wireless_tools.27
   * xampp-linux-1.5.1
   * xinetd-2.3.14
+  * zaptel-1.2.3_1st
   * zlib-1.2.3
diff --git a/lfs/asterisk b/lfs/asterisk
new file mode 100644 (file)
index 0000000..8c4bf7a
--- /dev/null
@@ -0,0 +1,145 @@
+###############################################################################
+# This file is part of the IPCop Firewall.                                    #
+#                                                                             #
+# IPCop is free software; you can redistribute it and/or modify               #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation; either version 2 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# IPCop is distributed in the hope that it will be useful,                    #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with IPCop; if not, write to the Free Software                        #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA    #
+#                                                                             #
+# Makefiles are based on LFSMake, which is                                    #
+# Copyright (C) 2002 Rod Roard <rod@sunsetsystems.com>                        #
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 1.2.4
+
+THISAPP    = asterisk-$(VER)
+DL_FILE    = $(THISAPP).tar.gz
+DL_FROM    = http://www.asterisk-support.de/mirror/asterisk-1.2.4
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+
+ASTERISK   = $(THISAPP)
+ZAPTEL     = zaptel-1.2.3
+BRISTUFF   = bristuff-0.3.0-PRE-1l
+LIBPRI     = libpri-1.2.2
+SPANDSP    = spandsp-0.0.2pre25
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE) \
+          $(ZAPTEL).tar.gz \
+          $(BRISTUFF).tar.gz \
+          $(LIBPRI).tar.gz \
+          app_rxfax.c \
+          app_txfax.c \
+          apps_Makefile.patch
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+$(ZAPTEL).tar.gz = http://www.asterisk-support.de/mirror/zaptel/$(ZAPTEL).tar.gz
+$(BRISTUFF).tar.gz = http://www.junghanns.net/downloads/$(BRISTUFF).tar.gz
+$(LIBPRI).tar.gz = http://www.asterisk-support.de/mirror/libpri/$(LIBPRI).tar.gz
+app_rxfax.c = http://soft-switch.org/downloads/spandsp/$(SPANDSP)/asterisk-1.2.x/app_rxfax.c
+app_txfax.c = http://soft-switch.org/downloads/spandsp/$(SPANDSP)/asterisk-1.2.x/app_txfax.c
+apps_Makefile.patch = http://soft-switch.org/downloads/spandsp/$(SPANDSP)/asterisk-1.2.x/apps_Makefile.patch
+
+$(DL_FILE)_MD5 = 14721abdc85fc3381db275b61dffce2d
+$(ZAPTEL).tar.gz_MD5 = 9bcb705458f9b20a9644310298a9cd4d
+$(BRISTUFF).tar.gz_MD5 = 81941539b03b6ac8f193b33451e0a740
+$(LIBPRI).tar.gz_MD5 = efce9c3699110588df5e4cf09eae01d9
+app_rxfax.c_MD5 = ab6983b51c412883545b36993d704999
+app_txfax.c_MD5 = 8c8fcb263b76897022b4c28052a7b439
+apps_Makefile.patch_MD5 = 6b0faa7a7cf8613962b17c23ee5a1583
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist: 
+       make-packages.sh asterisk $(THISAPP)
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_SRC)/$(BRISTUFF)
+       # Decompress the source-code
+       cd $(DIR_SRC) && \
+       tar zxf $(DIR_DL)/$(BRISTUFF).tar.gz -C $(DIR_SRC) && \
+       cd $(DIR_SRC)/$(BRISTUFF) && \
+       tar xfz $(DIR_DL)/$(ZAPTEL).tar.gz && \
+       tar xfz $(DIR_DL)/$(LIBPRI).tar.gz && \
+       tar xfz $(DIR_DL)/$(ASTERISK).tar.gz
+       # Build Zaptel
+       cd $(DIR_SRC)/$(BRISTUFF)/$(ZAPTEL) && \
+       patch -Np1 < $(DIR_SRC)/src/patches/asterisk-1.2.4-zaptel-$(BRISTUFF).patch && \
+       make clean all KVERS=$(KVER) && \
+       make install KVERS=$(KVER)
+       # Build Libpri
+       cd $(DIR_SRC)/$(BRISTUFF)/$(LIBPRI) && \
+       patch -Np1 < $(DIR_SRC)/src/patches/asterisk-1.2.4-libpri-$(BRISTUFF).patch && \
+       make clean all KVERS=$(KVER) && \
+       make install KVERS=$(KVER)
+       # Build qozap
+       cd $(DIR_SRC)/$(BRISTUFF)/qozap && \
+       make clean linux24 && \
+       install -D -m 644 qozap.o /lib/modules/$(KVER)/misc/qozap.o
+       # Build cwain
+       cd $(DIR_SRC)/$(BRISTUFF)/cwain && \
+       make clean linux24 && \
+       install -D -m 644 cwain.o /lib/modules/$(KVER)/misc/cwain.o
+       # Build zaphfc
+       cd $(DIR_SRC)/$(BRISTUFF)/zaphfc && \
+       make clean linux24 && \
+       install -D -m 644 zaphfc.o /lib/modules/$(KVER)/misc/zaphfc.o
+       # Build Asterisk
+       cd $(DIR_SRC)/$(BRISTUFF)/$(ASTERISK) && \
+       patch -Np1 < $(DIR_SRC)/src/patches/$(THISAPP)-ipfire-$(BRISTUFF).patch && \
+       patch -Np1 < $(DIR_SRC)/src/patches/$(THISAPP)-iax2-$(BRISTUFF).patch && \
+       cp -fv $(DIR_DL)/app_{r,t}xfax.c $(DIR_SRC)/$(BRISTUFF)/$(ASTERISK)/apps && \
+       cd $(DIR_SRC)/$(BRISTUFF)/$(ASTERISK)/apps && \
+       patch -Np1 < $(DIR_DL)/apps_Makefile.patch && \
+       cd $(DIR_SRC)/$(BRISTUFF)/$(ASTERISK) && \
+       make clean && \
+       make all && \
+       make install && \
+       make samples
+       @rm -rf $(DIR_SRC)/$(BRISTUFF)
+       @$(POSTBUILD)
+
index 7df7c6196d6b60216d74ca10420349c26479c4cf..a9027c4515899a7990bc3fbf379983ce287b434b 100644 (file)
@@ -90,7 +90,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
                cd $(DIR_APP) && sed -i -e 's/#define BB_RMMOD//' Config.h; \
                cd $(DIR_APP) && sed -i -e 's/#define BB_MODPROBE//' Config.h; \
        fi
-       cd $(DIR_APP) && sed -i -e 's/enum { NAME_SIZE = 100 };/enum { NAME_SIZE = 150 };/' tar.c; \
+#      cd $(DIR_APP) && sed -i -e 's/enum { NAME_SIZE = 100 };/enum { NAME_SIZE = 150 };/' tar.c; \
        
        cd $(DIR_APP) && make
        -mkdir -p /install/initrd/bin
diff --git a/lfs/edonkeyclc b/lfs/edonkeyclc
new file mode 100644 (file)
index 0000000..c2cabca
--- /dev/null
@@ -0,0 +1,82 @@
+###############################################################################
+# This file is part of the IPCop Firewall.                                    #
+#                                                                             #
+# IPCop is free software; you can redistribute it and/or modify               #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation; either version 2 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# IPCop is distributed in the hope that it will be useful,                    #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with IPCop; if not, write to the Free Software                        #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA    #
+#                                                                             #
+# Makefiles are based on LFSMake, which is                                    #
+# Copyright (C) 2002 Rod Roard <rod@sunsetsystems.com>                        #
+#                                                                             #
+# Modifications by:                                                           #
+# ??-12-2003 Mark Wormgoor < mark@wormgoor.com>                               #
+#          - Modified Makefile for IPCop build                                #
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 1.3.0
+
+THISAPP    = edonkeyclc_$(VER)_i386
+DL_FILE    = $(THISAPP).tar.gz
+DL_FROM    = http://www.zen18864.zen.co.uk/edonkey/1.3.0
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = 46ced65b8bde60db234ad781861139c8
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist: 
+       make-packages.sh edonkeyclc $(THISAPP)-ipfire-beta-1
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE) -C /
+       @$(POSTBUILD)
diff --git a/lfs/libtiff b/lfs/libtiff
new file mode 100644 (file)
index 0000000..658d6a2
--- /dev/null
@@ -0,0 +1,88 @@
+###############################################################################
+# This file is part of the IPCop Firewall.                                    #
+#                                                                             #
+# IPCop is free software; you can redistribute it and/or modify               #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation; either version 2 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# IPCop is distributed in the hope that it will be useful,                    #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with IPCop; if not, write to the Free Software                        #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA    #
+#                                                                             #
+# Makefiles are based on LFSMake, which is                                    #
+# Copyright (C) 2002 Rod Roard <rod@sunsetsystems.com>                        #
+#                                                                             #
+# Modifications by:                                                           #
+# ??-12-2003 Mark Wormgoor < mark@wormgoor.com>                               #
+#          - Modified Makefile for IPCop build                                #
+#                                                                             #
+# $Id: ntp,v 1.6.2.3 2005/02/05 15:38:15 gespinasse Exp $
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 3.8.2
+
+THISAPP    = tiff-$(VER)
+DL_FILE    = $(THISAPP).tar.gz
+DL_FROM    = ftp://ftp.remotesensing.org/libtiff
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = fbb6f446ea4ed18955e2714934e5b698
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist: 
+       make-packages.sh libtiff $(THISAPP)-ipfire-beta-1
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && ./configure --prefix=/usr
+       cd $(DIR_APP) && make
+       cd $(DIR_APP) && make install
+       @rm -rf $(DIR_APP)
+       @$(POSTBUILD)
diff --git a/lfs/libxml2 b/lfs/libxml2
new file mode 100644 (file)
index 0000000..338c2f8
--- /dev/null
@@ -0,0 +1,88 @@
+###############################################################################
+# This file is part of the IPCop Firewall.                                    #
+#                                                                             #
+# IPCop is free software; you can redistribute it and/or modify               #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation; either version 2 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# IPCop is distributed in the hope that it will be useful,                    #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with IPCop; if not, write to the Free Software                        #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA    #
+#                                                                             #
+# Makefiles are based on LFSMake, which is                                    #
+# Copyright (C) 2002 Rod Roard <rod@sunsetsystems.com>                        #
+#                                                                             #
+# Modifications by:                                                           #
+# ??-12-2003 Mark Wormgoor < mark@wormgoor.com>                               #
+#          - Modified Makefile for IPCop build                                #
+#                                                                             #
+# $Id: ntp,v 1.6.2.3 2005/02/05 15:38:15 gespinasse Exp $
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 2.6.22
+
+THISAPP    = libxml2-$(VER)
+DL_FILE    = $(THISAPP).tar.gz
+DL_FROM    = ftp://xmlsoft.org/libxml2
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = 1db8d06b4f49a665a8f47dc6d94450e6
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist: 
+       make-packages.sh libxml2 $(THISAPP)-ipfire-beta-1
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && ./configure --prefix=/usr
+       cd $(DIR_APP) && make
+       cd $(DIR_APP) && make install
+       @rm -rf $(DIR_APP)
+       @$(POSTBUILD)
index 35244734f89b8fac9f52fc4cd305a9ddf17ef1f9..b92f78ba74a4f8adfcb24c497784edc6b5dfdb95 100644 (file)
@@ -59,7 +59,7 @@ download :$(patsubst %,$(DIR_DL)/%,$(objects))
 md5 : $(subst %,%_MD5,$(objects))
 
 dist: 
-       make-packages.sh postfix $(THISAPP)
+       make-packages.sh postfix $(THISAPP)-ipfire-beta-1
 
 ###############################################################################
 # Downloading, checking, md5sum
diff --git a/lfs/spandsp b/lfs/spandsp
new file mode 100644 (file)
index 0000000..83c0e3b
--- /dev/null
@@ -0,0 +1,88 @@
+###############################################################################
+# This file is part of the IPCop Firewall.                                    #
+#                                                                             #
+# IPCop is free software; you can redistribute it and/or modify               #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation; either version 2 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# IPCop is distributed in the hope that it will be useful,                    #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with IPCop; if not, write to the Free Software                        #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA    #
+#                                                                             #
+# Makefiles are based on LFSMake, which is                                    #
+# Copyright (C) 2002 Rod Roard <rod@sunsetsystems.com>                        #
+#                                                                             #
+# Modifications by:                                                           #
+# ??-12-2003 Mark Wormgoor < mark@wormgoor.com>                               #
+#          - Modified Makefile for IPCop build                                #
+#                                                                             #
+# $Id: ntp,v 1.6.2.3 2005/02/05 15:38:15 gespinasse Exp $
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 0.0.2pre25
+
+THISAPP    = spandsp-$(VER)
+DL_FILE    = $(THISAPP).tar.gz
+DL_FROM    = http://soft-switch.org/downloads/spandsp/spandsp-0.0.2pre25
+DIR_APP    = $(DIR_SRC)/spandsp-0.0.2
+TARGET     = $(DIR_INFO)/$(THISAPP)
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = 2bbd518eec1ac0214d1d0f8abb6772a3
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist: 
+       make-packages.sh spandsp $(THISAPP)-ipfire-beta-1
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && ./configure --prefix=/usr
+       cd $(DIR_APP) && make
+       cd $(DIR_APP) && make install
+       @rm -rf $(DIR_APP)
+       @$(POSTBUILD)
diff --git a/make.sh b/make.sh
index 5f47f1a2f120abdc036711de76c429aad8ce9375..40b49da9ad5cdf2b4d2e528c250dea56f5ca547f 100644 (file)
--- a/make.sh
+++ b/make.sh
@@ -647,32 +647,37 @@ buildipcop() {
   ipcopmake libsafe
   ipcopmake 3c5x9setup
   echo -ne "`date -u '+%b %e %T'`: Building IPFire modules \n" | tee -a $LOGFILE
-  ipcopmake sudo
-##ipcopmake stunnel # Ausgeschaltet, weil wir es doch nicht nutzen
-  ipcopmake xinetd
+## Zuerst die Libs und dann die Programme. Ordnung muss sein!
+  ipcopmake berkeley-DB
+  ipcopmake libtiff
+  ipcopmake libxml2
+  ipcopmake spandsp
+  ipcopmake lzo
   ipcopmake pkg-config
   ipcopmake glib
+  ipcopmake pam
+  ipcopmake pammysql
+  ipcopmake sudo
+  ipcopmake mc
+  ipcopmake pwlib
+  ipcopmake openh323
+  ipcopmake xinetd
   ipcopmake wget
-  ipcopmake berkeley-DB
   ipcopmake xampp
   ipcopmake bridge-utils
-  ipcopmake pam
-  ipcopmake pammysql
   ipcopmake saslauthd PASS=1
   ipcopmake openldap
   ipcopmake saslauthd PASS=2
   ipcopmake samba
-  ipcopmake mc
   ipcopmake postfix
   ipcopmake stund
   ipcopmake lpd
-  ipcopmake pwlib
-  ipcopmake openh323
+  ipcopmake openvpn
+  ipcopmake asterisk
+  ipcopmake edonkeyclc
 #  wget http://www.guzu.net/linux/hddtemp.db && mv hddtemp.db $BASEDIR/build/etc/hddtemp.db
 #  ipcopmake hddtemp
-  ipcopmake lzo
-  ipcopmake openvpn
-
+# ipcopmake stunnel # Ausgeschaltet, weil wir es doch nicht nutzen
 }
 
 buildinstaller() {
@@ -762,8 +767,11 @@ buildpackages() {
   cp $LFS/install/images/{*.iso,*.tgz} $BASEDIR >> $LOGFILE 2>&1
 
   # Build IPFire packages
+  ipfiredist libtiff
+  ipfiredist libxml2
   ipfiredist mc
   ipfiredist postfix
+  ipfiredist spandsp
   ipfiredist sudo
   ipfiredist xinetd
   # Cleanup
diff --git a/src/paks/asterisk/CONFFILES b/src/paks/asterisk/CONFFILES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/paks/asterisk/ROOTFILES b/src/paks/asterisk/ROOTFILES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/paks/asterisk/install.sh b/src/paks/asterisk/install.sh
new file mode 100644 (file)
index 0000000..3a9ce55
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Extract the files
+tar xfz files.tgz -C /
+cp -f ROOTFILES /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/asterisk/uninstall.sh b/src/paks/asterisk/uninstall.sh
new file mode 100644 (file)
index 0000000..ad61226
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Delete the files
+## Befehl fehlt noch
+rm -f /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/edonkeyclc/CONFFILES b/src/paks/edonkeyclc/CONFFILES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/paks/edonkeyclc/ROOTFILES b/src/paks/edonkeyclc/ROOTFILES
new file mode 100644 (file)
index 0000000..3714bb5
--- /dev/null
@@ -0,0 +1,9 @@
+usr/bin/edonkeyclc
+#usr/share/doc/edonkeyclc
+#usr/share/doc/edonkeyclc/ChangeLog
+#usr/share/doc/edonkeyclc/LISEZMOI
+#usr/share/doc/edonkeyclc/README
+#usr/share/doc/edonkeyclc/changelog.Debian.gz
+#usr/share/edonkeyclc
+#usr/share/edonkeyclc/contact.dat
+#usr/share/edonkeyclc/server.met
diff --git a/src/paks/edonkeyclc/install.sh b/src/paks/edonkeyclc/install.sh
new file mode 100644 (file)
index 0000000..3a9ce55
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Extract the files
+tar xfz files.tgz -C /
+cp -f ROOTFILES /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/edonkeyclc/uninstall.sh b/src/paks/edonkeyclc/uninstall.sh
new file mode 100644 (file)
index 0000000..ad61226
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Delete the files
+## Befehl fehlt noch
+rm -f /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/libtiff/CONFFILES b/src/paks/libtiff/CONFFILES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/paks/libtiff/ROOTFILES b/src/paks/libtiff/ROOTFILES
new file mode 100644 (file)
index 0000000..87ac9f8
--- /dev/null
@@ -0,0 +1,235 @@
+usr/bin/bmp2tiff
+usr/bin/fax2ps
+usr/bin/fax2tiff
+usr/bin/gif2tiff
+usr/bin/pal2rgb
+usr/bin/ppm2tiff
+usr/bin/ras2tiff
+usr/bin/raw2tiff
+usr/bin/rgb2ycbcr
+usr/bin/thumbnail
+usr/bin/tiff2bw
+usr/bin/tiff2pdf
+usr/bin/tiff2ps
+usr/bin/tiff2rgba
+usr/bin/tiffcmp
+usr/bin/tiffcp
+usr/bin/tiffdither
+usr/bin/tiffdump
+usr/bin/tiffinfo
+usr/bin/tiffmedian
+usr/bin/tiffset
+usr/bin/tiffsplit
+#usr/include/tiff.h
+#usr/include/tiffconf.h
+#usr/include/tiffio.h
+#usr/include/tiffio.hxx
+#usr/include/tiffvers.h
+usr/lib/libtiff.a
+usr/lib/libtiff.la
+usr/lib/libtiff.so
+usr/lib/libtiff.so.3
+usr/lib/libtiff.so.3.8.2
+usr/lib/libtiffxx.a
+usr/lib/libtiffxx.la
+usr/lib/libtiffxx.so
+usr/lib/libtiffxx.so.3
+usr/lib/libtiffxx.so.3.8.2
+#usr/share/doc/tiff-3.8.2
+#usr/share/doc/tiff-3.8.2/COPYRIGHT
+#usr/share/doc/tiff-3.8.2/ChangeLog
+#usr/share/doc/tiff-3.8.2/README
+#usr/share/doc/tiff-3.8.2/RELEASE-DATE
+#usr/share/doc/tiff-3.8.2/TODO
+#usr/share/doc/tiff-3.8.2/VERSION
+#usr/share/doc/tiff-3.8.2/html
+#usr/share/doc/tiff-3.8.2/html/TIFFTechNote2.html
+#usr/share/doc/tiff-3.8.2/html/addingtags.html
+#usr/share/doc/tiff-3.8.2/html/bugs.html
+#usr/share/doc/tiff-3.8.2/html/build.html
+#usr/share/doc/tiff-3.8.2/html/contrib.html
+#usr/share/doc/tiff-3.8.2/html/document.html
+#usr/share/doc/tiff-3.8.2/html/images
+#usr/share/doc/tiff-3.8.2/html/images.html
+#usr/share/doc/tiff-3.8.2/html/images/back.gif
+#usr/share/doc/tiff-3.8.2/html/images/bali.jpg
+#usr/share/doc/tiff-3.8.2/html/images/cat.gif
+#usr/share/doc/tiff-3.8.2/html/images/cover.jpg
+#usr/share/doc/tiff-3.8.2/html/images/cramps.gif
+#usr/share/doc/tiff-3.8.2/html/images/dave.gif
+#usr/share/doc/tiff-3.8.2/html/images/info.gif
+#usr/share/doc/tiff-3.8.2/html/images/jello.jpg
+#usr/share/doc/tiff-3.8.2/html/images/jim.gif
+#usr/share/doc/tiff-3.8.2/html/images/note.gif
+#usr/share/doc/tiff-3.8.2/html/images/oxford.gif
+#usr/share/doc/tiff-3.8.2/html/images/quad.jpg
+#usr/share/doc/tiff-3.8.2/html/images/ring.gif
+#usr/share/doc/tiff-3.8.2/html/images/smallliz.jpg
+#usr/share/doc/tiff-3.8.2/html/images/strike.gif
+#usr/share/doc/tiff-3.8.2/html/images/warning.gif
+#usr/share/doc/tiff-3.8.2/html/index.html
+#usr/share/doc/tiff-3.8.2/html/internals.html
+#usr/share/doc/tiff-3.8.2/html/intro.html
+#usr/share/doc/tiff-3.8.2/html/libtiff.html
+#usr/share/doc/tiff-3.8.2/html/man
+#usr/share/doc/tiff-3.8.2/html/man/TIFFClose.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFDataWidth.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFError.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFFlush.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFGetField.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFOpen.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFPrintDirectory.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFRGBAImage.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadDirectory.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadEncodedStrip.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadEncodedTile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadRGBAImage.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadRGBAStrip.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadRGBATile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadRawStrip.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadRawTile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadScanline.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFReadTile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFSetDirectory.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFSetField.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWarning.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteDirectory.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteEncodedStrip.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteEncodedTile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteRawStrip.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteRawTile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteScanline.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFWriteTile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFbuffer.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFcodec.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFcolor.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFmemory.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFquery.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFsize.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFstrip.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFswab.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/TIFFtile.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/fax2ps.1.html
+#usr/share/doc/tiff-3.8.2/html/man/fax2tiff.1.html
+#usr/share/doc/tiff-3.8.2/html/man/gif2tiff.1.html
+#usr/share/doc/tiff-3.8.2/html/man/index.html
+#usr/share/doc/tiff-3.8.2/html/man/libtiff.3tiff.html
+#usr/share/doc/tiff-3.8.2/html/man/pal2rgb.1.html
+#usr/share/doc/tiff-3.8.2/html/man/ppm2tiff.1.html
+#usr/share/doc/tiff-3.8.2/html/man/ras2tiff.1.html
+#usr/share/doc/tiff-3.8.2/html/man/raw2tiff.1.html
+#usr/share/doc/tiff-3.8.2/html/man/rgb2ycbcr.1.html
+#usr/share/doc/tiff-3.8.2/html/man/sgi2tiff.1.html
+#usr/share/doc/tiff-3.8.2/html/man/thumbnail.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiff2bw.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiff2pdf.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiff2ps.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiff2rgba.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffcmp.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffcp.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffdither.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffdump.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffgt.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffinfo.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffmedian.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffset.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffsplit.1.html
+#usr/share/doc/tiff-3.8.2/html/man/tiffsv.1.html
+#usr/share/doc/tiff-3.8.2/html/misc.html
+#usr/share/doc/tiff-3.8.2/html/support.html
+#usr/share/doc/tiff-3.8.2/html/tools.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta007.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta016.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta018.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta024.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta028.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta029.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta031.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta032.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta033.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta034.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta035.html
+#usr/share/doc/tiff-3.8.2/html/v3.4beta036.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.1.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.2.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.3.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.4.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.5.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.6-beta.html
+#usr/share/doc/tiff-3.8.2/html/v3.5.7.html
+#usr/share/doc/tiff-3.8.2/html/v3.6.0.html
+#usr/share/doc/tiff-3.8.2/html/v3.6.1.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.0.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.0alpha.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.0beta.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.0beta2.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.1.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.2.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.3.html
+#usr/share/doc/tiff-3.8.2/html/v3.7.4.html
+#usr/share/doc/tiff-3.8.2/html/v3.8.0.html
+#usr/share/doc/tiff-3.8.2/html/v3.8.1.html
+#usr/share/doc/tiff-3.8.2/html/v3.8.2.html
+#usr/share/man/man1/bmp2tiff.1
+#usr/share/man/man1/fax2ps.1
+#usr/share/man/man1/fax2tiff.1
+#usr/share/man/man1/gif2tiff.1
+#usr/share/man/man1/pal2rgb.1
+#usr/share/man/man1/ppm2tiff.1
+#usr/share/man/man1/ras2tiff.1
+#usr/share/man/man1/raw2tiff.1
+#usr/share/man/man1/rgb2ycbcr.1
+#usr/share/man/man1/sgi2tiff.1
+#usr/share/man/man1/thumbnail.1
+#usr/share/man/man1/tiff2bw.1
+#usr/share/man/man1/tiff2pdf.1
+#usr/share/man/man1/tiff2ps.1
+#usr/share/man/man1/tiff2rgba.1
+#usr/share/man/man1/tiffcmp.1
+#usr/share/man/man1/tiffcp.1
+#usr/share/man/man1/tiffdither.1
+#usr/share/man/man1/tiffdump.1
+#usr/share/man/man1/tiffgt.1
+#usr/share/man/man1/tiffinfo.1
+#usr/share/man/man1/tiffmedian.1
+#usr/share/man/man1/tiffset.1
+#usr/share/man/man1/tiffsplit.1
+#usr/share/man/man1/tiffsv.1
+#usr/share/man/man3/TIFFClose.3tiff
+#usr/share/man/man3/TIFFDataWidth.3tiff
+#usr/share/man/man3/TIFFError.3tiff
+#usr/share/man/man3/TIFFFlush.3tiff
+#usr/share/man/man3/TIFFGetField.3tiff
+#usr/share/man/man3/TIFFOpen.3tiff
+#usr/share/man/man3/TIFFPrintDirectory.3tiff
+#usr/share/man/man3/TIFFRGBAImage.3tiff
+#usr/share/man/man3/TIFFReadDirectory.3tiff
+#usr/share/man/man3/TIFFReadEncodedStrip.3tiff
+#usr/share/man/man3/TIFFReadEncodedTile.3tiff
+#usr/share/man/man3/TIFFReadRGBAImage.3tiff
+#usr/share/man/man3/TIFFReadRGBAStrip.3tiff
+#usr/share/man/man3/TIFFReadRGBATile.3tiff
+#usr/share/man/man3/TIFFReadRawStrip.3tiff
+#usr/share/man/man3/TIFFReadRawTile.3tiff
+#usr/share/man/man3/TIFFReadScanline.3tiff
+#usr/share/man/man3/TIFFReadTile.3tiff
+#usr/share/man/man3/TIFFSetDirectory.3tiff
+#usr/share/man/man3/TIFFSetField.3tiff
+#usr/share/man/man3/TIFFWarning.3tiff
+#usr/share/man/man3/TIFFWriteDirectory.3tiff
+#usr/share/man/man3/TIFFWriteEncodedStrip.3tiff
+#usr/share/man/man3/TIFFWriteEncodedTile.3tiff
+#usr/share/man/man3/TIFFWriteRawStrip.3tiff
+#usr/share/man/man3/TIFFWriteRawTile.3tiff
+#usr/share/man/man3/TIFFWriteScanline.3tiff
+#usr/share/man/man3/TIFFWriteTile.3tiff
+#usr/share/man/man3/TIFFbuffer.3tiff
+#usr/share/man/man3/TIFFcodec.3tiff
+#usr/share/man/man3/TIFFcolor.3tiff
+#usr/share/man/man3/TIFFmemory.3tiff
+#usr/share/man/man3/TIFFquery.3tiff
+#usr/share/man/man3/TIFFsize.3tiff
+#usr/share/man/man3/TIFFstrip.3tiff
+#usr/share/man/man3/TIFFswab.3tiff
+#usr/share/man/man3/TIFFtile.3tiff
+#usr/share/man/man3/libtiff.3tiff
diff --git a/src/paks/libtiff/install.sh b/src/paks/libtiff/install.sh
new file mode 100644 (file)
index 0000000..3a9ce55
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Extract the files
+tar xfz files.tgz -C /
+cp -f ROOTFILES /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/libtiff/uninstall.sh b/src/paks/libtiff/uninstall.sh
new file mode 100644 (file)
index 0000000..ad61226
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Delete the files
+## Befehl fehlt noch
+rm -f /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/libxml2/CONFFILES b/src/paks/libxml2/CONFFILES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/paks/libxml2/ROOTFILES b/src/paks/libxml2/ROOTFILES
new file mode 100644 (file)
index 0000000..e9f76b0
--- /dev/null
@@ -0,0 +1,333 @@
+usr/bin/xml2-config
+usr/bin/xmlcatalog
+usr/bin/xmllint
+#usr/include/libxml2
+#usr/include/libxml2/libxml
+#usr/include/libxml2/libxml/DOCBparser.h
+#usr/include/libxml2/libxml/HTMLparser.h
+#usr/include/libxml2/libxml/HTMLtree.h
+#usr/include/libxml2/libxml/SAX.h
+#usr/include/libxml2/libxml/SAX2.h
+#usr/include/libxml2/libxml/c14n.h
+#usr/include/libxml2/libxml/catalog.h
+#usr/include/libxml2/libxml/chvalid.h
+#usr/include/libxml2/libxml/debugXML.h
+#usr/include/libxml2/libxml/dict.h
+#usr/include/libxml2/libxml/encoding.h
+#usr/include/libxml2/libxml/entities.h
+#usr/include/libxml2/libxml/globals.h
+#usr/include/libxml2/libxml/hash.h
+#usr/include/libxml2/libxml/list.h
+#usr/include/libxml2/libxml/nanoftp.h
+#usr/include/libxml2/libxml/nanohttp.h
+#usr/include/libxml2/libxml/parser.h
+#usr/include/libxml2/libxml/parserInternals.h
+#usr/include/libxml2/libxml/pattern.h
+#usr/include/libxml2/libxml/relaxng.h
+#usr/include/libxml2/libxml/schemasInternals.h
+#usr/include/libxml2/libxml/schematron.h
+#usr/include/libxml2/libxml/threads.h
+#usr/include/libxml2/libxml/tree.h
+#usr/include/libxml2/libxml/uri.h
+#usr/include/libxml2/libxml/valid.h
+#usr/include/libxml2/libxml/xinclude.h
+#usr/include/libxml2/libxml/xlink.h
+#usr/include/libxml2/libxml/xmlIO.h
+#usr/include/libxml2/libxml/xmlautomata.h
+#usr/include/libxml2/libxml/xmlerror.h
+#usr/include/libxml2/libxml/xmlexports.h
+#usr/include/libxml2/libxml/xmlmemory.h
+#usr/include/libxml2/libxml/xmlmodule.h
+#usr/include/libxml2/libxml/xmlreader.h
+#usr/include/libxml2/libxml/xmlregexp.h
+#usr/include/libxml2/libxml/xmlsave.h
+#usr/include/libxml2/libxml/xmlschemas.h
+#usr/include/libxml2/libxml/xmlschemastypes.h
+#usr/include/libxml2/libxml/xmlstring.h
+#usr/include/libxml2/libxml/xmlunicode.h
+#usr/include/libxml2/libxml/xmlversion.h
+#usr/include/libxml2/libxml/xmlwriter.h
+#usr/include/libxml2/libxml/xpath.h
+#usr/include/libxml2/libxml/xpathInternals.h
+#usr/include/libxml2/libxml/xpointer.h
+usr/lib/libxml2.a
+usr/lib/libxml2.la
+usr/lib/libxml2.so
+usr/lib/libxml2.so.2
+usr/lib/libxml2.so.2.6.22
+usr/lib/pkgconfig/libxml-2.0.pc
+usr/lib/python2.3/site-packages/drv_libxml2.py
+usr/lib/python2.3/site-packages/libxml2.py
+usr/lib/python2.3/site-packages/libxml2mod.a
+usr/lib/python2.3/site-packages/libxml2mod.la
+usr/lib/python2.3/site-packages/libxml2mod.so
+usr/lib/xml2Conf.sh
+#usr/share/aclocal/libxml.m4
+#usr/share/doc/libxml2-2.6.22
+#usr/share/doc/libxml2-2.6.22/Copyright
+#usr/share/doc/libxml2-2.6.22/examples
+#usr/share/doc/libxml2-2.6.22/examples/testHTML.c
+#usr/share/doc/libxml2-2.6.22/examples/testSAX.c
+#usr/share/doc/libxml2-2.6.22/examples/testXPath.c
+#usr/share/doc/libxml2-2.6.22/examples/xmllint.c
+#usr/share/doc/libxml2-2.6.22/html
+#usr/share/doc/libxml2-2.6.22/html/DOM.gif
+#usr/share/doc/libxml2-2.6.22/html/FAQ.html
+#usr/share/doc/libxml2-2.6.22/html/Libxml2-Logo-180x168.gif
+#usr/share/doc/libxml2-2.6.22/html/Libxml2-Logo-90x34.gif
+#usr/share/doc/libxml2-2.6.22/html/encoding.html
+#usr/share/doc/libxml2-2.6.22/html/examples.xml
+#usr/share/doc/libxml2-2.6.22/html/examples.xsl
+#usr/share/doc/libxml2-2.6.22/html/html
+#usr/share/doc/libxml2-2.6.22/html/html/book1.html
+#usr/share/doc/libxml2-2.6.22/html/html/home.png
+#usr/share/doc/libxml2-2.6.22/html/html/index.html
+#usr/share/doc/libxml2-2.6.22/html/html/left.png
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-DOCBparser.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-HTMLparser.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-HTMLtree.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-SAX.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-SAX2.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-c14n.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-catalog.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-chvalid.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-debugXML.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-dict.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-encoding.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-entities.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-globals.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-hash.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-lib.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-list.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-nanoftp.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-nanohttp.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-parser.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-parserInternals.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-pattern.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-relaxng.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-schemasInternals.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-schematron.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-threads.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-tree.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-uri.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-valid.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xinclude.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xlink.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlIO.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlautomata.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlerror.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlexports.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlmemory.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlmodule.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlreader.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlregexp.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlsave.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlschemas.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlschemastypes.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlstring.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlunicode.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlversion.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xmlwriter.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xpath.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xpathInternals.html
+#usr/share/doc/libxml2-2.6.22/html/html/libxml-xpointer.html
+#usr/share/doc/libxml2-2.6.22/html/html/right.png
+#usr/share/doc/libxml2-2.6.22/html/html/up.png
+#usr/share/doc/libxml2-2.6.22/html/io1.c
+#usr/share/doc/libxml2-2.6.22/html/io1.res
+#usr/share/doc/libxml2-2.6.22/html/io2.c
+#usr/share/doc/libxml2-2.6.22/html/io2.res
+#usr/share/doc/libxml2-2.6.22/html/libxml.gif
+#usr/share/doc/libxml2-2.6.22/html/parse1.c
+#usr/share/doc/libxml2-2.6.22/html/parse2.c
+#usr/share/doc/libxml2-2.6.22/html/parse3.c
+#usr/share/doc/libxml2-2.6.22/html/parse4.c
+#usr/share/doc/libxml2-2.6.22/html/reader1.c
+#usr/share/doc/libxml2-2.6.22/html/reader1.res
+#usr/share/doc/libxml2-2.6.22/html/reader2.c
+#usr/share/doc/libxml2-2.6.22/html/reader3.c
+#usr/share/doc/libxml2-2.6.22/html/reader3.res
+#usr/share/doc/libxml2-2.6.22/html/reader4.c
+#usr/share/doc/libxml2-2.6.22/html/reader4.res
+#usr/share/doc/libxml2-2.6.22/html/redhat.gif
+#usr/share/doc/libxml2-2.6.22/html/smallfootonly.gif
+#usr/share/doc/libxml2-2.6.22/html/structure.gif
+#usr/share/doc/libxml2-2.6.22/html/test1.xml
+#usr/share/doc/libxml2-2.6.22/html/test2.xml
+#usr/share/doc/libxml2-2.6.22/html/test3.xml
+#usr/share/doc/libxml2-2.6.22/html/testWriter.c
+#usr/share/doc/libxml2-2.6.22/html/tree1.c
+#usr/share/doc/libxml2-2.6.22/html/tree1.res
+#usr/share/doc/libxml2-2.6.22/html/tree2.c
+#usr/share/doc/libxml2-2.6.22/html/tree2.res
+#usr/share/doc/libxml2-2.6.22/html/tst.xml
+#usr/share/doc/libxml2-2.6.22/html/tutorial
+#usr/share/doc/libxml2-2.6.22/html/tutorial/apa.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/apb.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/apc.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/apd.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ape.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/apf.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/apg.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/aph.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/api.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s02.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s03.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s04.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s05.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s06.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s07.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s08.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ar01s09.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/blank.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/1.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/10.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/2.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/3.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/4.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/5.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/6.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/7.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/8.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/callouts/9.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/caution.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/draft.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/home.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/important.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/next.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/note.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/prev.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/tip.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/toc-blank.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/toc-minus.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/toc-plus.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/up.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/images/warning.png
+#usr/share/doc/libxml2-2.6.22/html/tutorial/includeaddattribute.c
+#usr/share/doc/libxml2-2.6.22/html/tutorial/includeaddkeyword.c
+#usr/share/doc/libxml2-2.6.22/html/tutorial/includeconvert.c
+#usr/share/doc/libxml2-2.6.22/html/tutorial/includegetattribute.c
+#usr/share/doc/libxml2-2.6.22/html/tutorial/includekeyword.c
+#usr/share/doc/libxml2-2.6.22/html/tutorial/includexpath.c
+#usr/share/doc/libxml2-2.6.22/html/tutorial/index.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/ix01.html
+#usr/share/doc/libxml2-2.6.22/html/tutorial/xmltutorial.pdf
+#usr/share/doc/libxml2-2.6.22/html/w3c.png
+#usr/share/doc/libxml2-2.6.22/html/writer.xml
+#usr/share/doc/libxml2-2.6.22/html/xml.html
+#usr/share/doc/libxml2-2.6.22/html/xpath1.c
+#usr/share/doc/libxml2-2.6.22/html/xpath1.res
+#usr/share/doc/libxml2-2.6.22/html/xpath2.c
+#usr/share/doc/libxml2-2.6.22/html/xpath2.res
+#usr/share/doc/libxml2-python-2.6.22
+#usr/share/doc/libxml2-python-2.6.22/TODO
+#usr/share/doc/libxml2-python-2.6.22/examples
+#usr/share/doc/libxml2-python-2.6.22/examples/attribs.py
+#usr/share/doc/libxml2-python-2.6.22/examples/build.py
+#usr/share/doc/libxml2-python-2.6.22/examples/ctxterror.py
+#usr/share/doc/libxml2-python-2.6.22/examples/cutnpaste.py
+#usr/share/doc/libxml2-python-2.6.22/examples/dtdvalid.py
+#usr/share/doc/libxml2-python-2.6.22/examples/error.py
+#usr/share/doc/libxml2-python-2.6.22/examples/inbuf.py
+#usr/share/doc/libxml2-python-2.6.22/examples/indexes.py
+#usr/share/doc/libxml2-python-2.6.22/examples/invalid.xml
+#usr/share/doc/libxml2-python-2.6.22/examples/nsdel.py
+#usr/share/doc/libxml2-python-2.6.22/examples/outbuf.py
+#usr/share/doc/libxml2-python-2.6.22/examples/push.py
+#usr/share/doc/libxml2-python-2.6.22/examples/pushSAX.py
+#usr/share/doc/libxml2-python-2.6.22/examples/pushSAXhtml.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader2.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader3.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader4.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader5.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader6.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader7.py
+#usr/share/doc/libxml2-python-2.6.22/examples/reader8.py
+#usr/share/doc/libxml2-python-2.6.22/examples/readererr.py
+#usr/share/doc/libxml2-python-2.6.22/examples/readernext.py
+#usr/share/doc/libxml2-python-2.6.22/examples/regexp.py
+#usr/share/doc/libxml2-python-2.6.22/examples/relaxng.py
+#usr/share/doc/libxml2-python-2.6.22/examples/resolver.py
+#usr/share/doc/libxml2-python-2.6.22/examples/schema.py
+#usr/share/doc/libxml2-python-2.6.22/examples/serialize.py
+#usr/share/doc/libxml2-python-2.6.22/examples/sync.py
+#usr/share/doc/libxml2-python-2.6.22/examples/test.dtd
+#usr/share/doc/libxml2-python-2.6.22/examples/thread2.py
+#usr/share/doc/libxml2-python-2.6.22/examples/tst.py
+#usr/share/doc/libxml2-python-2.6.22/examples/tst.xml
+#usr/share/doc/libxml2-python-2.6.22/examples/tstLastError.py
+#usr/share/doc/libxml2-python-2.6.22/examples/tstURI.py
+#usr/share/doc/libxml2-python-2.6.22/examples/tstmem.py
+#usr/share/doc/libxml2-python-2.6.22/examples/tstxpath.py
+#usr/share/doc/libxml2-python-2.6.22/examples/valid.xml
+#usr/share/doc/libxml2-python-2.6.22/examples/validDTD.py
+#usr/share/doc/libxml2-python-2.6.22/examples/validRNG.py
+#usr/share/doc/libxml2-python-2.6.22/examples/validSchemas.py
+#usr/share/doc/libxml2-python-2.6.22/examples/validate.py
+#usr/share/doc/libxml2-python-2.6.22/examples/walker.py
+#usr/share/doc/libxml2-python-2.6.22/examples/xpath.py
+#usr/share/doc/libxml2-python-2.6.22/examples/xpathext.py
+#usr/share/doc/libxml2-python-2.6.22/examples/xpathret.py
+#usr/share/gtk-doc/html/libxml2
+#usr/share/gtk-doc/html/libxml2/general.html
+#usr/share/gtk-doc/html/libxml2/home.png
+#usr/share/gtk-doc/html/libxml2/index.html
+#usr/share/gtk-doc/html/libxml2/left.png
+#usr/share/gtk-doc/html/libxml2/libxml2-DOCBparser.html
+#usr/share/gtk-doc/html/libxml2/libxml2-HTMLparser.html
+#usr/share/gtk-doc/html/libxml2/libxml2-HTMLtree.html
+#usr/share/gtk-doc/html/libxml2/libxml2-SAX.html
+#usr/share/gtk-doc/html/libxml2/libxml2-SAX2.html
+#usr/share/gtk-doc/html/libxml2/libxml2-c14n.html
+#usr/share/gtk-doc/html/libxml2/libxml2-catalog.html
+#usr/share/gtk-doc/html/libxml2/libxml2-chvalid.html
+#usr/share/gtk-doc/html/libxml2/libxml2-debugXML.html
+#usr/share/gtk-doc/html/libxml2/libxml2-dict.html
+#usr/share/gtk-doc/html/libxml2/libxml2-encoding.html
+#usr/share/gtk-doc/html/libxml2/libxml2-entities.html
+#usr/share/gtk-doc/html/libxml2/libxml2-globals.html
+#usr/share/gtk-doc/html/libxml2/libxml2-hash.html
+#usr/share/gtk-doc/html/libxml2/libxml2-list.html
+#usr/share/gtk-doc/html/libxml2/libxml2-nanoftp.html
+#usr/share/gtk-doc/html/libxml2/libxml2-nanohttp.html
+#usr/share/gtk-doc/html/libxml2/libxml2-parser.html
+#usr/share/gtk-doc/html/libxml2/libxml2-parserInternals.html
+#usr/share/gtk-doc/html/libxml2/libxml2-pattern.html
+#usr/share/gtk-doc/html/libxml2/libxml2-relaxng.html
+#usr/share/gtk-doc/html/libxml2/libxml2-schemasInternals.html
+#usr/share/gtk-doc/html/libxml2/libxml2-schematron.html
+#usr/share/gtk-doc/html/libxml2/libxml2-threads.html
+#usr/share/gtk-doc/html/libxml2/libxml2-tree.html
+#usr/share/gtk-doc/html/libxml2/libxml2-uri.html
+#usr/share/gtk-doc/html/libxml2/libxml2-valid.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xinclude.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xlink.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlIO.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlautomata.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlerror.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlexports.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlmemory.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlmodule.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlreader.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlregexp.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlsave.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlschemas.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlschemastypes.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlstring.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlunicode.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlversion.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xmlwriter.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xpath.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xpathInternals.html
+#usr/share/gtk-doc/html/libxml2/libxml2-xpointer.html
+#usr/share/gtk-doc/html/libxml2/libxml2.devhelp
+#usr/share/gtk-doc/html/libxml2/right.png
+#usr/share/gtk-doc/html/libxml2/style.css
+#usr/share/gtk-doc/html/libxml2/up.png
+#usr/share/man/man1/xml2-config.1
+#usr/share/man/man1/xmlcatalog.1
+#usr/share/man/man1/xmllint.1
+#usr/share/man/man3/libxml.3
diff --git a/src/paks/libxml2/install.sh b/src/paks/libxml2/install.sh
new file mode 100644 (file)
index 0000000..3a9ce55
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Extract the files
+tar xfz files.tgz -C /
+cp -f ROOTFILES /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/libxml2/uninstall.sh b/src/paks/libxml2/uninstall.sh
new file mode 100644 (file)
index 0000000..ad61226
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Delete the files
+## Befehl fehlt noch
+rm -f /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/spandsp/CONFFILES b/src/paks/spandsp/CONFFILES
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/paks/spandsp/ROOTFILES b/src/paks/spandsp/ROOTFILES
new file mode 100644 (file)
index 0000000..4689120
--- /dev/null
@@ -0,0 +1,65 @@
+#usr/include/spandsp
+#usr/include/spandsp.h
+#usr/include/spandsp/adsi.h
+#usr/include/spandsp/alaw_ulaw.h
+#usr/include/spandsp/arctan2.h
+#usr/include/spandsp/async.h
+#usr/include/spandsp/awgn.h
+#usr/include/spandsp/bert.h
+#usr/include/spandsp/biquad.h
+#usr/include/spandsp/complex.h
+#usr/include/spandsp/complex_filters.h
+#usr/include/spandsp/dc_restore.h
+#usr/include/spandsp/dds.h
+#usr/include/spandsp/ec_disable_tone.h
+#usr/include/spandsp/echo.h
+#usr/include/spandsp/fir.h
+#usr/include/spandsp/fsk.h
+#usr/include/spandsp/g168models.h
+#usr/include/spandsp/g722.h
+#usr/include/spandsp/g726.h
+#usr/include/spandsp/hdlc.h
+#usr/include/spandsp/ima_adpcm.h
+#usr/include/spandsp/logging.h
+#usr/include/spandsp/mmx.h
+#usr/include/spandsp/modem_echo.h
+#usr/include/spandsp/noise.h
+#usr/include/spandsp/oki_adpcm.h
+#usr/include/spandsp/oss.h
+#usr/include/spandsp/playout.h
+#usr/include/spandsp/plc.h
+#usr/include/spandsp/power_meter.h
+#usr/include/spandsp/queue.h
+#usr/include/spandsp/schedule.h
+#usr/include/spandsp/sig_tone.h
+#usr/include/spandsp/super_tone_rx.h
+#usr/include/spandsp/super_tone_tx.h
+#usr/include/spandsp/t30.h
+#usr/include/spandsp/t30_fcf.h
+#usr/include/spandsp/t31.h
+#usr/include/spandsp/t35.h
+#usr/include/spandsp/t4.h
+#usr/include/spandsp/telephony.h
+#usr/include/spandsp/time_scale.h
+#usr/include/spandsp/timing.h
+#usr/include/spandsp/tone_detect.h
+#usr/include/spandsp/tone_generate.h
+#usr/include/spandsp/v17rx.h
+#usr/include/spandsp/v17tx.h
+#usr/include/spandsp/v22bis.h
+#usr/include/spandsp/v27ter_rx.h
+#usr/include/spandsp/v27ter_tx.h
+#usr/include/spandsp/v29rx.h
+#usr/include/spandsp/v29tx.h
+#usr/include/spandsp/v42.h
+#usr/include/spandsp/v42bis.h
+#usr/include/spandsp/v8.h
+#usr/include/spandsp/vector.h
+usr/lib/libspandsp.a
+usr/lib/libspandsp.la
+usr/lib/libspandsp.so
+usr/lib/libspandsp.so.0
+usr/lib/libspandsp.so.0.0.1
+usr/share/spandsp
+usr/share/spandsp/global-tones.xml
+usr/share/spandsp/tones.dtd
diff --git a/src/paks/spandsp/install.sh b/src/paks/spandsp/install.sh
new file mode 100644 (file)
index 0000000..3a9ce55
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Extract the files
+tar xfz files.tgz -C /
+cp -f ROOTFILES /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/paks/spandsp/uninstall.sh b/src/paks/spandsp/uninstall.sh
new file mode 100644 (file)
index 0000000..ad61226
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+#################################################################
+#                                                               #
+# This file belongs to IPFire Firewall - GPLv2 - www.ipfire.org #
+#                                                               #
+#################################################################
+#
+# Delete the files
+## Befehl fehlt noch
+rm -f /opt/pakfire/installed/ROOTFILES.$2
diff --git a/src/patches/asterisk-1.2.4-iax2-bristuff-0.3.0-PRE-1l.patch b/src/patches/asterisk-1.2.4-iax2-bristuff-0.3.0-PRE-1l.patch
new file mode 100644 (file)
index 0000000..5cbd642
--- /dev/null
@@ -0,0 +1,1828 @@
+diff -urN asterisk-1.2.4/channels/chan_iax2.c asterisk-1.2.4.carrier/channels/chan_iax2.c
+--- asterisk-1.2.4/channels/chan_iax2.c        2006-01-31 09:41:43.000000000 +0100
++++ asterisk-1.2.4.carrier/channels/chan_iax2.c        2006-02-08 09:49:45.000000000 +0100
+@@ -179,6 +179,8 @@
+ static struct ast_netsock_list *netsock;
+ static int defaultsockfd = -1;
++static char servername[80];
++
+ static int usecnt;
+ AST_MUTEX_DEFINE_STATIC(usecnt_lock);
+@@ -232,6 +234,10 @@
+ static pthread_t netthreadid = AST_PTHREADT_NULL;
++static pthread_t regthreadid = AST_PTHREADT_NULL;
++
++static pthread_t auththreadid = AST_PTHREADT_NULL;
++
+ enum {
+       IAX_STATE_STARTED =             (1 << 0),
+       IAX_STATE_AUTHENTICATED =       (1 << 1),
+@@ -606,6 +612,25 @@
+       ast_mutex_t lock;
+ } iaxq;
++typedef struct iax_auth_frame {
++      struct iax_auth_frame *prev;
++      struct iax_auth_frame *next;
++      struct iax_frame *frame;
++      struct sockaddr_in sin;
++      int fd;
++      int subclass;
++      struct iax_ies ies;
++      unsigned char iebuf[4096];
++} iax_auth_frame;
++
++static struct ast_iax2_auth_queue {
++      struct iax_auth_frame *head;
++      struct iax_auth_frame *tail;
++      int count;
++      ast_cond_t cond;
++      ast_mutex_t lock;
++} callq, regq;
++
+ static struct ast_user_list {
+       struct iax2_user *users;
+       ast_mutex_t lock;
+@@ -712,6 +737,8 @@
+ static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
+ static ast_mutex_t iaxsl[IAX_MAX_CALLS];
+ static struct timeval lastused[IAX_MAX_CALLS];
++/* some packets have been queued for asynchronous processing */
++static int iaxs_queued[IAX_MAX_CALLS];
+ static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
+@@ -798,11 +825,12 @@
+ static int send_lagrq(void *data)
+ {
+       int callno = (long)data;
+-      /* Ping only if it's real not if it's bridged */
++      /* Ping only if it's real not if it's bridged (and not if it's queued!)*/
+       if (iaxs[callno]) {
+ #ifdef BRIDGE_OPTIMIZATION
+               if (!iaxs[callno]->bridgecallno)
+ #endif                
++                  if (!iaxs_queued[callno])
+                       send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+               return 1;
+       } else
+@@ -1070,8 +1098,9 @@
+               }
+       }
+       if ((res < 1) && (new >= NEW_ALLOW)) {
+-              if (!iax2_getpeername(*sin, host, sizeof(host), lockpeer))
+-                      snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
++              /* We are NOT calling iax2_getpeernme() here, because it WILL BLOCK when using realtime.
++                 Instead we will overwrite the host filed in the iax_pvt for each new call or registration. */
++              snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
+               gettimeofday(&now, NULL);
+               for (x=1;x<TRUNK_CALL_START;x++) {
+                       /* Find first unused call number that hasn't been used in a while */
+@@ -1141,6 +1170,58 @@
+       return 0;
+ }
++static int iax2_queue_auth_frame(struct ast_iax2_auth_queue *authq, int subclass, struct iax_frame *ifr, unsigned char *buf, unsigned char *iebuf, int iebuflen, struct sockaddr_in *sin, int fd, int maydrop)
++{
++      struct iax_auth_frame *fr = NULL;
++      /* 
++          ok, we get here with the iaxsl[callno] still locked. 
++          in any case we have to unlock it before returning.
++      */
++      
++      if (!authq || !ifr || !ifr->callno) return 1;       
++    
++      fr = malloc(sizeof(struct iax_auth_frame));
++      if (!fr) {
++          ast_log(LOG_ERROR, "Unable to malloc!\n");
++          return 1;
++      }
++      memset(fr,0,sizeof(fr));
++      fr->next = NULL;
++      fr->prev = NULL;
++      fr->frame = ifr;
++      fr->subclass = subclass;
++      fr->fd = fd;
++      memcpy(fr->iebuf, iebuf, iebuflen);
++      if (iebuflen)
++          iax_parse_ies(&fr->ies, fr->iebuf, iebuflen);
++      memcpy(&fr->sin, sin, sizeof(struct sockaddr_in));
++      ast_mutex_lock(&authq->lock);
++      if (maydrop && (authq->count > 5000)) {
++          ast_mutex_unlock(&authq->lock);
++          ast_mutex_unlock(&iaxsl[ifr->callno]);
++          free(fr);
++          if (option_verbose > 5)
++              ast_log(LOG_WARNING, "Queue too long, not queueing frame.\n");
++          return -1;
++      }
++      if (!authq->head) {
++              /* Empty queue */
++              authq->head = fr;
++              authq->tail = fr;
++      } else {
++              /* Double link */
++              authq->tail->next = fr;
++              fr->prev = authq->tail;
++              authq->tail = fr;
++      }
++      iaxs_queued[ifr->callno]++;
++      authq->count++;
++      ast_mutex_unlock(&iaxsl[ifr->callno]);
++      ast_cond_signal(&authq->cond);
++      ast_mutex_unlock(&authq->lock);
++      return 0;
++}
++
+ static void destroy_firmware(struct iax_firmware *cur)
+ {
+       /* Close firmware */
+@@ -1713,8 +1794,10 @@
+                                               /* Transfer timeout */
+                                               send_command(iaxs[f->callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
+                                       } else if (f->final) {
+-                                              if (f->final) 
++                                              if (!iaxs_queued[f->callno]) {
++                                                  if (f->final) 
+                                                       iax2_destroy_nolock(f->callno);
++                                              }
+                                       } else {
+                                               if (iaxs[f->callno]->owner)
+                                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass, f->ts, f->oseqno);
+@@ -1729,12 +1812,14 @@
+                                                       if (iaxs[f->callno]->owner)
+                                                               iaxs[f->callno]->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
+                                               } else {
+-                                                      if (iaxs[f->callno]->reg) {
++                                                      if (!iaxs_queued[f->callno]) {
++                                                          if (iaxs[f->callno]->reg) {
+                                                               memset(&iaxs[f->callno]->reg->us, 0, sizeof(iaxs[f->callno]->reg->us));
+                                                               iaxs[f->callno]->reg->regstate = REG_STATE_TIMEOUT;
+                                                               iaxs[f->callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
++                                                          }
++                                                          iax2_destroy_nolock(f->callno);
+                                                       }
+-                                                      iax2_destroy_nolock(f->callno);
+                                               }
+                                       }
+@@ -2706,6 +2791,8 @@
+       snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime);
+       ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin->sin_addr);
+       snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
++//    the following line is commented out for compatibility
++//    ast_update_realtime("iaxpeers", "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, "servername", servername, NULL);
+       ast_update_realtime("iaxpeers", "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, NULL);
+ }
+@@ -5034,16 +5121,17 @@
+       }
+       /* We release the lock for the call to prevent a deadlock, but it's okay because
+          only the current thread could possibly make it go away or make changes */
+-      ast_mutex_unlock(&iaxsl[callno]);
++//    ast_mutex_unlock(&iaxsl[callno]);
+       /* SLD: first call to lookup peer during registration */
+       p = find_peer(peer, 1);
+-      ast_mutex_lock(&iaxsl[callno]);
+-
++//    ast_mutex_lock(&iaxsl[callno]);
+       if (!p) {
+               if (authdebug)
+                       ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr));
+               return -1;
+       }
++      /* set the host name here. instead of doing it in find_callno() */
++      ast_copy_string(iaxs[callno]->host, p->name, sizeof(iaxs[callno]->host));
+       if (!ast_test_flag(p, IAX_DYNAMIC)) {
+               if (authdebug)
+@@ -5677,11 +5765,13 @@
+       if (!refresh)
+               refresh = min_reg_expire;
+       if (refresh > max_reg_expire) {
+-              ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
++              if (option_verbose > 5)
++                  ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, max_reg_expire, refresh);
+               p->expiry = max_reg_expire;
+       } else if (refresh < min_reg_expire) {
+-              ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
++              if (option_verbose > 5)
++                  ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, min_reg_expire, refresh);
+               p->expiry = min_reg_expire;
+       } else {
+@@ -5720,6 +5810,7 @@
+               iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
+       if (ast_test_flag(p, IAX_TEMPONLY))
+               destroy_peer(p);
++      ast_mutex_lock(&iaxsl[callno]);
+       return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
+ }
+@@ -6279,6 +6370,8 @@
+       struct timeval rxtrunktime;
+       struct iax_ies ies;
+       struct iax_ie_data ied0, ied1;
++      unsigned char iebuf[4096]; 
++      int iebuflen = 0;
+       int format;
+       int exists;
+       int minivid = 0;
+@@ -6609,9 +6702,11 @@
+                                                       cur->retries = -1;
+                                                       /* Destroy call if this is the end */
+                                                       if (cur->final) { 
+-                                                              if (iaxdebug && option_debug)
++                                                              if (!iaxs_queued[fr.callno]) {
++                                                                  if (iaxdebug && option_debug)
+                                                                       ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", fr.callno);
+-                                                              iax2_destroy_nolock(fr.callno);
++                                                                  iax2_destroy_nolock(fr.callno);
++                                                              }
+                                                       }
+                                               }
+                                       }
+@@ -6639,6 +6734,8 @@
+               if (f.datalen) {
+                       if (f.frametype == AST_FRAME_IAX) {
++                              memcpy(iebuf, buf + sizeof(struct ast_iax2_full_hdr), f.datalen);
++                              iebuflen = f.datalen;
+                               if (iax_parse_ies(&ies, buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
+                                       ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr));
+                                       ast_mutex_unlock(&iaxsl[fr.callno]);
+@@ -6772,166 +6869,11 @@
+                                       break;
+                               if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr)
+                                       check_provisioning(&sin, fd, ies.serviceident, ies.provver);
+-                              /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
+-                              if (ast_test_flag(iaxs[fr.callno], IAX_TRUNK)) {
+-                                      fr.callno = make_trunk(fr.callno, 1);
+-                              }
+                               /* For security, always ack immediately */
+                               if (delayreject)
+                                       send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
+-                              if (check_access(fr.callno, &sin, &ies)) {
+-                                      /* They're not allowed on */
+-                                      auth_fail(fr.callno, IAX_COMMAND_REJECT);
+-                                      if (authdebug)
+-                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
+-                                      break;
+-                              }
+-                              /* This might re-enter the IAX code and need the lock */
+-                              if (strcasecmp(iaxs[fr.callno]->exten, "TBD")) {
+-                                      ast_mutex_unlock(&iaxsl[fr.callno]);
+-                                      exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->cid_num);
+-                                      ast_mutex_lock(&iaxsl[fr.callno]);
+-                              } else
+-                                      exists = 0;
+-                              if (ast_strlen_zero(iaxs[fr.callno]->secret) && ast_strlen_zero(iaxs[fr.callno]->inkeys)) {
+-                                      if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
+-                                              memset(&ied0, 0, sizeof(ied0));
+-                                              iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
+-                                              iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
+-                                              send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
+-                                              if (authdebug)
+-                                                      ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
+-                                      } else {
+-                                              /* Select an appropriate format */
+-
+-                                              if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOPREFS)) {
+-                                                      if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOCAP)) {
+-                                                              using_prefs = "reqonly";
+-                                                      } else {
+-                                                              using_prefs = "disabled";
+-                                                      }
+-                                                      format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability;
+-                                                      memset(&pref, 0, sizeof(pref));
+-                                                      strcpy(caller_pref_buf, "disabled");
+-                                                      strcpy(host_pref_buf, "disabled");
+-                                              } else {
+-                                                      using_prefs = "mine";
+-                                                      if(ies.codec_prefs) {
+-                                                              ast_codec_pref_convert(&rpref, ies.codec_prefs, 32, 0);
+-                                                              /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
+-                                                              if (ast_test_flag(iaxs[fr.callno], IAX_CODEC_USER_FIRST)) {
+-                                                                      pref = rpref;
+-                                                                      using_prefs = "caller";
+-                                                              } else {
+-                                                                      pref = iaxs[fr.callno]->prefs;
+-                                                              }
+-                                                      } else
+-                                                              pref = iaxs[fr.callno]->prefs;
+-                                              
+-                                                      format = ast_codec_choose(&pref, iaxs[fr.callno]->capability & iaxs[fr.callno]->peercapability, 0);
+-                                                      ast_codec_pref_string(&rpref, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+-                                                      ast_codec_pref_string(&iaxs[fr.callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+-                                              }
+-                                              if (!format) {
+-                                                      if(!ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOCAP))
+-                                                              format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability;
+-                                                      if (!format) {
+-                                                              memset(&ied0, 0, sizeof(ied0));
+-                                                              iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
+-                                                              iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+-                                                              send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
+-                                                              if (authdebug) {
+-                                                                      if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOCAP))
+-                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->capability);
+-                                                                      else 
+-                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability);
+-                                                              }
+-                                                      } else {
+-                                                              /* Pick one... */
+-                                                              if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOCAP)) {
+-                                                                      if(!(iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability))
+-                                                                              format = 0;
+-                                                              } else {
+-                                                                      if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOPREFS)) {
+-                                                                              using_prefs = ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
+-                                                                              memset(&pref, 0, sizeof(pref));
+-                                                                              format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability);
+-                                                                              strcpy(caller_pref_buf,"disabled");
+-                                                                              strcpy(host_pref_buf,"disabled");
+-                                                                      } else {
+-                                                                              using_prefs = "mine";
+-                                                                              if(ies.codec_prefs) {
+-                                                                                      /* Do the opposite of what we tried above. */
+-                                                                                      if (ast_test_flag(iaxs[fr.callno], IAX_CODEC_USER_FIRST)) {
+-                                                                                              pref = iaxs[fr.callno]->prefs;                                                          
+-                                                                                      } else {
+-                                                                                              pref = rpref;
+-                                                                                              using_prefs = "caller";
+-                                                                                      }
+-                                                                                      format = ast_codec_choose(&pref, iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability, 1);
+-                                                                      
+-                                                                              } else /* if no codec_prefs IE do it the old way */
+-                                                                                      format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); 
+-                                                                      }
+-                                                              }
+-
+-                                                              if (!format) {
+-                                                                      memset(&ied0, 0, sizeof(ied0));
+-                                                                      iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
+-                                                                      iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+-                                                                      ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability);
+-                                                                      send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
+-                                                                      if (authdebug)
+-                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability);
+-                                                                      ast_set_flag(iaxs[fr.callno], IAX_ALREADYGONE); 
+-                                                                      break;
+-                                                              }
+-                                                      }
+-                                              }
+-                                              if (format) {
+-                                                      /* No authentication required, let them in */
+-                                                      memset(&ied1, 0, sizeof(ied1));
+-                                                      iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
+-                                                      send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
+-                                                      if (strcmp(iaxs[fr.callno]->exten, "TBD")) {
+-                                                              ast_set_flag(&iaxs[fr.callno]->state, IAX_STATE_STARTED);
+-                                                              if (option_verbose > 2) 
+-                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepting UNAUTHENTICATED call from %s:\n"
+-                                                                                              "%srequested format = %s,\n"
+-                                                                                              "%srequested prefs = %s,\n"
+-                                                                                              "%sactual format = %s,\n"
+-                                                                                              "%shost prefs = %s,\n"
+-                                                                                              "%spriority = %s\n",
+-                                                                                              ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), 
+-                                                                                              VERBOSE_PREFIX_4,
+-                                                                                              ast_getformatname(iaxs[fr.callno]->peerformat), 
+-                                                                                              VERBOSE_PREFIX_4,
+-                                                                                              caller_pref_buf,
+-                                                                                              VERBOSE_PREFIX_4,
+-                                                                                              ast_getformatname(format), 
+-                                                                                              VERBOSE_PREFIX_4,
+-                                                                                              host_pref_buf, 
+-                                                                                              VERBOSE_PREFIX_4,
+-                                                                                              using_prefs);
+-                                                              
+-                                                              if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format)))
+-                                                                      iax2_destroy_nolock(fr.callno);
+-                                                      } else {
+-                                                              ast_set_flag(&iaxs[fr.callno]->state, IAX_STATE_TBD);
+-                                                              /* If this is a TBD call, we're ready but now what...  */
+-                                                              if (option_verbose > 2)
+-                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr));
+-                                                      }
+-                                              }
+-                                      }
+-                                      break;
+-                              }
+-                              if (iaxs[fr.callno]->authmethods & IAX_AUTH_MD5)
+-                                      merge_encryption(iaxs[fr.callno],ies.encmethods);
+-                              else
+-                                      iaxs[fr.callno]->encmethods = 0;
+-                              authenticate_request(iaxs[fr.callno]);
+-                              ast_set_flag(&iaxs[fr.callno]->state, IAX_STATE_AUTHENTICATED);
++                              fr.af.datalen = 0;
++                              iax2_queue_auth_frame(&callq, f.subclass, iaxfrdup2(&fr), buf, iebuf, iebuflen, &sin, fd, 0);
+                               break;
+                       case IAX_COMMAND_DPREQ:
+                               /* Request status in the dialplan */
+@@ -6947,14 +6889,22 @@
+                               }
+                               break;
+                       case IAX_COMMAND_HANGUP:
+-                              ast_set_flag(iaxs[fr.callno], IAX_ALREADYGONE);
+-                              ast_log(LOG_DEBUG, "Immediately destroying %d, having received hangup\n", fr.callno);
+-                              /* Set hangup cause according to remote */
+-                              if (ies.causecode && iaxs[fr.callno]->owner)
+-                                      iaxs[fr.callno]->owner->hangupcause = ies.causecode;
+-                              /* Send ack immediately, before we destroy */
+-                              send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
+-                              iax2_destroy_nolock(fr.callno);
++                              if (iaxs_queued[fr.callno]) {
++                                  /* there is something queued, maybe the call has not been authorized yet. */
++                                  /* Send ack immediately, before we destroy */
++                                  send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
++                                  fr.af.datalen = 0;
++                                  iax2_queue_auth_frame(&callq, f.subclass, iaxfrdup2(&fr), buf, iebuf, iebuflen, &sin, fd, 0);
++                              } else {
++                                  ast_set_flag(iaxs[fr.callno], IAX_ALREADYGONE);
++                                  ast_log(LOG_DEBUG, "Immediately destroying %d, having received hangup\n", fr.callno);
++                                  /* Set hangup cause according to remote */
++                                  if (ies.causecode && iaxs[fr.callno]->owner)
++                                          iaxs[fr.callno]->owner->hangupcause = ies.causecode;
++                                  /* Send ack immediately, before we destroy */
++                                  send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
++                                  iax2_destroy_nolock(fr.callno);
++                              }
+                               break;
+                       case IAX_COMMAND_REJECT:
+                               memset(&f, 0, sizeof(f));
+@@ -7183,31 +7133,36 @@
+                               /* For security, always ack immediately */
+                               if (delayreject)
+                                       send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
+-                              /* Ignore once we've started */
+-                              if (ast_test_flag(&iaxs[fr.callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
++                              if (iaxs_queued[fr.callno]) {
++                                  /* there is something queued, take the same path  */
++                                  fr.af.datalen = 0;
++                                  iax2_queue_auth_frame(&callq, f.subclass, iaxfrdup2(&fr), buf, iebuf, iebuflen, &sin, fd, 0);
++                              } else {
++                                  /* Ignore once we've started */
++                                  if (ast_test_flag(&iaxs[fr.callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
+                                       ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>");
+                                       break;
+-                              }
+-                              if (authenticate_verify(iaxs[fr.callno], &ies)) {
++                                  }
++                                  if (authenticate_verify(iaxs[fr.callno], &ies)) {
+                                       if (authdebug)
+                                               ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[fr.callno]->addr.sin_addr), iaxs[fr.callno]->username);
+                                       memset(&ied0, 0, sizeof(ied0));
+                                       auth_fail(fr.callno, IAX_COMMAND_REJECT);
+                                       break;
+-                              }
+-                              if (strcasecmp(iaxs[fr.callno]->exten, "TBD")) {
++                                  }
++                                  if (strcasecmp(iaxs[fr.callno]->exten, "TBD")) {
+                                       /* This might re-enter the IAX code and need the lock */
+                                       exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->cid_num);
+-                              } else
++                                  } else
+                                       exists = 0;
+-                              if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
++                                  if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
+                                       if (authdebug)
+                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
+                                       memset(&ied0, 0, sizeof(ied0));
+                                       iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
+                                       iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
+                                       send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
+-                              } else {
++                                  } else {
+                                       /* Select an appropriate format */
+                                       if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOPREFS)) {
+                                               if(ast_test_flag(iaxs[fr.callno], IAX_CODEC_NOCAP)) {
+@@ -7332,6 +7287,7 @@
+                                                               ast_verbose(VERBOSE_PREFIX_3 "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr));
+                                               }
+                                       }
++                                  }
+                               }
+                               break;
+                       case IAX_COMMAND_DIAL:
+@@ -7357,11 +7313,16 @@
+                               }
+                               break;
+                       case IAX_COMMAND_INVAL:
+-                              iaxs[fr.callno]->error = ENOTCONN;
+-                              ast_log(LOG_DEBUG, "Immediately destroying %d, having received INVAL\n", fr.callno);
+-                              iax2_destroy_nolock(fr.callno);
+-                              if (option_debug)
++                              if (iaxs_queued[fr.callno]) {
++                                  fr.af.datalen = 0;
++                                  iax2_queue_auth_frame(&callq, f.subclass, iaxfrdup2(&fr), buf, iebuf, iebuflen, &sin, fd, 0);
++                              } else {
++                                  iaxs[fr.callno]->error = ENOTCONN;
++                                  ast_log(LOG_DEBUG, "Immediately destroying %d, having received INVAL\n", fr.callno);
++                                  iax2_destroy_nolock(fr.callno);
++                                  if (option_debug)
+                                       ast_log(LOG_DEBUG, "Destroying call %d\n", fr.callno);
++                              }
+                               break;
+                       case IAX_COMMAND_VNAK:
+                               ast_log(LOG_DEBUG, "Received VNAK: resending outstanding frames\n");
+@@ -7373,21 +7334,11 @@
+                               /* For security, always ack immediately */
+                               if (delayreject)
+                                       send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
+-                              if (register_verify(fr.callno, &sin, &ies)) {
+-                                      /* Send delayed failure */
+-                                      auth_fail(fr.callno, IAX_COMMAND_REGREJ);
+-                                      break;
+-                              }
+-                              if ((ast_strlen_zero(iaxs[fr.callno]->secret) && ast_strlen_zero(iaxs[fr.callno]->inkeys)) || ast_test_flag(&iaxs[fr.callno]->state, IAX_STATE_AUTHENTICATED)) {
+-                                      if (f.subclass == IAX_COMMAND_REGREL)
+-                                              memset(&sin, 0, sizeof(sin));
+-                                      if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype, fd, ies.refresh))
+-                                              ast_log(LOG_WARNING, "Registry error\n");
+-                                      if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr)
+-                                              check_provisioning(&sin, fd, ies.serviceident, ies.provver);
+-                                      break;
++                              fr.af.datalen = 0;
++                              if (iax2_queue_auth_frame(&regq, f.subclass, iaxfrdup2(&fr), buf, iebuf, iebuflen, &sin, fd, 1)) {
++                                  /* queueing failed due to a full queue */
++                                  iax2_destroy_nolock(fr.callno);
+                               }
+-                              registry_authrequest(iaxs[fr.callno]->peer, fr.callno);
+                               break;
+                       case IAX_COMMAND_REGACK:
+                               if (iax2_ack_registry(&ies, &sin, fr.callno)) 
+@@ -7989,6 +7940,478 @@
+       return ast_pthread_create(&netthreadid, NULL, network_thread, NULL);
+ }
++struct iax_auth_frame *iax2_get_next_auth_frame(struct ast_iax2_auth_queue *authq) {
++      struct iax_auth_frame *frame = NULL;
++
++      /* sleep until the network_thread queues us a frame, then grab it and release the lock A.S.A.P. */
++      ast_mutex_lock(&authq->lock);
++      if (authq->count == 0) 
++              ast_cond_wait(&authq->cond, &authq->lock);
++      frame = authq->head;
++      if (frame) {
++          if (frame->next) {
++//            frame->next->prev = NULL;
++              authq->head = frame->next;
++          } else {
++              authq->head = NULL;
++              authq->tail = NULL;
++          }
++          authq->count--;
++      } else {
++          ast_log(LOG_ERROR, "I SHOULD NEVER HAPPEN! EXPECT SOME MAJOR KABOOM! DUCK AND COVER!\n");
++      }
++      ast_mutex_unlock(&authq->lock);
++      return frame;
++}
++
++
++void *auth_thread(void *data)
++{
++      /* 
++          The network_thread queues iax_frames into our queue and wakes us up.
++          We will authenticate IAX_COMMAND_NEWs and IAX_COMMAND_REGREQs.
++
++          We also have to process IAX_COMMAND_HANGUP when somebody hangs up a call
++          before it has been authorized!
++
++          If ever possible we shall not lock any iaxsl[...].
++      */
++      struct ast_iax2_auth_queue *authq = (struct ast_iax2_auth_queue *)data;
++      struct iax_frame *ifr;
++      struct iax_auth_frame *fr;
++      struct iax_ies *ies;
++      struct iax_ie_data ied0, ied1;
++      struct ast_channel *c;
++      char iabuf[INET_ADDRSTRLEN];
++      int exists;
++      int format;
++      int dequeued = 0;
++      char host_pref_buf[128];
++      char caller_pref_buf[128];
++      struct ast_codec_pref pref,rpref;
++      char *using_prefs = "mine";
++
++      if (!authq) {
++          ast_log(LOG_ERROR, "no queue!\n");
++          return NULL;
++      }
++
++      for(;;) {
++          fr = iax2_get_next_auth_frame(authq);
++          ifr = fr->frame;
++          ies = &fr->ies;
++              if (ifr) {
++                  if (ifr->callno > 0) {
++                      /* we will not lock iaxsl[ifr->callno], instead we will haveset a flag in iaxs_queued[ifr->callno]. 
++                         if this flag is set the socket_read thread may not touch iaxs[ifr->callno]. instead of
++                         processing the incoming packets there it has to queue them to us!
++                         This should only happen with IAX_COMMAND_HANGUP when hanging up a not-yet-established call.
++
++                         However we will try to deliver audio frames in socket_read. If we get audio data for call
++                         whos signalling frames have been queued we should be safe to just drop them.
++                         
++                         When we really want to destroy something we will aquire the lock first.
++                      */
++                      switch(fr->subclass) {
++                          case IAX_COMMAND_NEW:
++                              iax2_getpeername(fr->sin, iaxs[ifr->callno]->host, sizeof(iaxs[ifr->callno]->host), 1);
++                              if (check_access(ifr->callno, &fr->sin, ies)) {
++                                      /* They're not allowed on */
++                                      if (authdebug)
++                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->exten, iaxs[ifr->callno]->context);
++                                      auth_fail(ifr->callno, IAX_COMMAND_REJECT);
++                                      break;
++                              }
++                              /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
++                              if (ast_test_flag(iaxs[ifr->callno], IAX_TRUNK)) {
++                                      ifr->callno = make_trunk(ifr->callno, 1);
++                              }
++                              /* This might re-enter the IAX code and need the lock */
++                              if (strcasecmp(iaxs[ifr->callno]->exten, "TBD")) {
++                              //      ast_mutex_unlock(&iaxsl[ifr->callno]);
++                                      exists = ast_exists_extension(NULL, iaxs[ifr->callno]->context, iaxs[ifr->callno]->exten, 1, iaxs[ifr->callno]->cid_num);
++                              //      ast_mutex_lock(&iaxsl[ifr->callno]);
++                              } else
++                                      exists = 0;
++                              if (ast_strlen_zero(iaxs[ifr->callno]->secret) && ast_strlen_zero(iaxs[ifr->callno]->inkeys)) {
++                                      if (strcmp(iaxs[ifr->callno]->exten, "TBD") && !exists) {
++                                              memset(&ied0, 0, sizeof(ied0));
++                                              iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
++                                              iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
++                                              send_command_final(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
++                                              if (authdebug)
++                                                      ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->exten, iaxs[ifr->callno]->context);
++                                      } else {
++                                              /* Select an appropriate format */
++                                              if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOPREFS)) {
++                                                      if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP)) {
++                                                              using_prefs = "reqonly";
++                                                      } else {
++                                                              using_prefs = "disabled";
++                                                      }
++                                                      format = iaxs[ifr->callno]->peerformat & iaxs[ifr->callno]->capability;
++                                                      memset(&pref, 0, sizeof(pref));
++                                                      strcpy(caller_pref_buf, "disabled");
++                                                      strcpy(host_pref_buf, "disabled");
++                                              } else {
++                                                      using_prefs = "mine";
++                                                      if(ies->codec_prefs) {
++                                                              ast_codec_pref_convert(&rpref, ies->codec_prefs, 32, 0);
++                                                              /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
++                                                              if (ast_test_flag(iaxs[ifr->callno], IAX_CODEC_USER_FIRST)) {
++                                                                      pref = rpref;
++                                                                      using_prefs = "caller";
++                                                              } else {
++                                                                      pref = iaxs[ifr->callno]->prefs;
++                                                              }
++                                                      } else
++                                                              pref = iaxs[ifr->callno]->prefs;
++                                              
++                                                      format = ast_codec_choose(&pref, iaxs[ifr->callno]->capability & iaxs[ifr->callno]->peercapability, 0);
++                                                      ast_codec_pref_string(&rpref, caller_pref_buf, sizeof(caller_pref_buf) - 1);
++                                                      ast_codec_pref_string(&iaxs[ifr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
++                                              }
++                                              if (!format) {
++                                                      if(!ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP))
++                                                              format = iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability;
++                                                      if (!format) {
++                                                              memset(&ied0, 0, sizeof(ied0));
++                                                              iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
++                                                              iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
++                                                              send_command_final(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
++                                                              if (authdebug) {
++                                                                      if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP))
++                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->capability);
++                                                                      else 
++                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->peercapability, iaxs[ifr->callno]->capability);
++                                                              }
++                                                      } else {
++                                                              /* Pick one... */
++                                                              if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP)) {
++                                                                      if(!(iaxs[ifr->callno]->peerformat & iaxs[ifr->callno]->capability))
++                                                                              format = 0;
++                                                              } else {
++                                                                      if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOPREFS)) {
++                                                                              using_prefs = ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
++                                                                              memset(&pref, 0, sizeof(pref));
++                                                                              format = ast_best_codec(iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability);
++                                                                              strcpy(caller_pref_buf,"disabled");
++                                                                              strcpy(host_pref_buf,"disabled");
++                                                                      } else {
++                                                                              using_prefs = "mine";
++                                                                              if(ies->codec_prefs) {
++                                                                                      /* Do the opposite of what we tried above. */
++                                                                                      if (ast_test_flag(iaxs[ifr->callno], IAX_CODEC_USER_FIRST)) {
++                                                                                              pref = iaxs[ifr->callno]->prefs;                                                                
++                                                                                      } else {
++                                                                                              pref = rpref;
++                                                                                              using_prefs = "caller";
++                                                                                      }
++                                                                                      format = ast_codec_choose(&pref, iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability, 1);
++                                                                      
++                                                                              } else /* if no codec_prefs IE do it the old way */
++                                                                                      format = ast_best_codec(iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability);     
++                                                                      }
++                                                              }
++
++                                                              if (!format) {
++                                                                      memset(&ied0, 0, sizeof(ied0));
++                                                                      iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
++                                                                      iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
++                                                                      ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability);
++                                                                      send_command_final(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
++                                                                      if (authdebug)
++                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->peercapability, iaxs[ifr->callno]->capability);
++                                                                      ast_set_flag(iaxs[ifr->callno], IAX_ALREADYGONE);       
++                                                                      break;
++                                                              }
++                                                      }
++                                              }
++                                              if (format) {
++                                                      /* No authentication required, let them in */
++                                                      memset(&ied1, 0, sizeof(ied1));
++                                                      iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
++                                                      send_command(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
++                                                      if (strcmp(iaxs[ifr->callno]->exten, "TBD")) {
++                                                              ast_set_flag(&iaxs[ifr->callno]->state, IAX_STATE_STARTED);
++                                                              if (option_verbose > 2) 
++                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepting UNAUTHENTICATED call from %s:\n"
++                                                                                              "%srequested format = %s,\n"
++                                                                                              "%srequested prefs = %s,\n"
++                                                                                              "%sactual format = %s,\n"
++                                                                                              "%shost prefs = %s,\n"
++                                                                                              "%spriority = %s\n",
++                                                                                              ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), 
++                                                                                              VERBOSE_PREFIX_4,
++                                                                                              ast_getformatname(iaxs[ifr->callno]->peerformat), 
++                                                                                              VERBOSE_PREFIX_4,
++                                                                                              caller_pref_buf,
++                                                                                              VERBOSE_PREFIX_4,
++                                                                                              ast_getformatname(format), 
++                                                                                              VERBOSE_PREFIX_4,
++                                                                                              host_pref_buf, 
++                                                                                              VERBOSE_PREFIX_4,
++                                                                                              using_prefs);
++                                                              
++                                                              if(!(c = ast_iax2_new(ifr->callno, AST_STATE_RING, format))) {
++                                                                  ast_mutex_lock(&iaxsl[ifr->callno]);
++                                                                      iax2_destroy_nolock(ifr->callno);
++                                                                  ast_mutex_unlock(&iaxsl[ifr->callno]);
++                                                              }
++                                                      } else {
++                                                              ast_set_flag(&iaxs[ifr->callno]->state, IAX_STATE_TBD);
++                                                              /* If this is a TBD call, we're ready but now what...  */
++                                                              if (option_verbose > 2)
++                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr));
++                                                      }
++                                              }
++                                      }
++                                      break;
++                              }
++                              if (iaxs[ifr->callno]->authmethods & IAX_AUTH_MD5)
++                                      merge_encryption(iaxs[ifr->callno],ies->encmethods);
++                              else
++                                      iaxs[ifr->callno]->encmethods = 0;
++                              authenticate_request(iaxs[ifr->callno]);
++                              ast_set_flag(&iaxs[ifr->callno]->state, IAX_STATE_AUTHENTICATED);
++                              break;
++                          case IAX_COMMAND_REGREQ:
++                          case IAX_COMMAND_REGREL:
++              //                  usleep(1000000);
++                              if (register_verify(ifr->callno, &fr->sin, ies)) {
++                                      /* Send delayed failure */
++                                      auth_fail(ifr->callno, IAX_COMMAND_REGREJ);
++                                  break;
++                              }
++                              if ((ast_strlen_zero(iaxs[ifr->callno]->secret) && ast_strlen_zero(iaxs[ifr->callno]->inkeys)) || ast_test_flag(&iaxs[ifr->callno]->state, IAX_STATE_AUTHENTICATED)) {
++                                  if (fr->subclass == IAX_COMMAND_REGREL)
++                                      memset(&fr->sin, 0, sizeof(struct sockaddr_in));
++                                  if (update_registry(iaxs[ifr->callno]->peer, &fr->sin, ifr->callno, ies->devicetype, fr->fd, ies->refresh))
++                                      ast_log(LOG_WARNING, "Registry error\n"); 
++                                  if (ies->provverpres && ies->serviceident && fr->sin.sin_addr.s_addr)
++                                      check_provisioning(&fr->sin, fr->fd, ies->serviceident, ies->provver);
++                                  /* update registry leaves us locked, so we have to unlock to not deadlock */
++                                  iaxs_queued[ifr->callno]--;
++                                  if (iaxs_queued[ifr->callno] < 0) iaxs_queued[ifr->callno] = 0;
++                                  ast_mutex_unlock(&iaxsl[ifr->callno]);
++                                  break;
++                              }
++                              registry_authrequest(iaxs[ifr->callno]->peer, ifr->callno);
++                              break;
++                          case IAX_COMMAND_HANGUP:
++                              /* Here we really have to lock */
++                              ast_mutex_lock(&iaxsl[ifr->callno]);
++                              if (iaxs[ifr->callno]) {
++                                  ast_set_flag(iaxs[ifr->callno], IAX_ALREADYGONE);
++                                  ast_log(LOG_DEBUG, "Asynchronously destroying %d, having received hangup\n", ifr->callno);
++                                  /* Set hangup cause according to remote */
++                                  if (ies->causecode && iaxs[ifr->callno]->owner)
++                                      iaxs[ifr->callno]->owner->hangupcause = ies->causecode;
++                                  iax2_destroy_nolock(ifr->callno);
++                              }
++                              iaxs_queued[ifr->callno]--;
++                              if (iaxs_queued[ifr->callno] < 0) iaxs_queued[ifr->callno] = 0;
++                              dequeued = 1;
++                              ast_mutex_unlock(&iaxsl[ifr->callno]);
++                              break;
++                      case IAX_COMMAND_INVAL:
++                              /* Here we really have to lock */
++                              ast_mutex_lock(&iaxsl[ifr->callno]);
++                              if (iaxs[ifr->callno]) {
++                                  iaxs[ifr->callno]->error = ENOTCONN;
++                                  ast_log(LOG_DEBUG, "Asynchronously destroying %d, having received INVAL\n", ifr->callno);
++                                  iax2_destroy_nolock(ifr->callno);
++                                  if (option_debug)
++                                      ast_log(LOG_DEBUG, "Destroying call %d\n", ifr->callno);
++                              }
++                              iaxs_queued[ifr->callno]--;
++                              if (iaxs_queued[ifr->callno] < 0) iaxs_queued[ifr->callno] = 0;
++                              dequeued = 1;
++                              ast_mutex_unlock(&iaxsl[ifr->callno]);
++                              break;
++                      case IAX_COMMAND_AUTHREP:
++                              /* Ignore once we've started */
++                              if (ast_test_flag(&iaxs[ifr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD)) {
++                                  ast_log(LOG_WARNING, "Call on %s is already up, can't start on it\n", iaxs[ifr->callno]->owner ? iaxs[ifr->callno]->owner->name : "<Unknown>");
++                                  break;
++                              }
++                              if (authenticate_verify(iaxs[ifr->callno], ies)) {
++                                      if (authdebug)
++                                              ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), iaxs[ifr->callno]->addr.sin_addr), iaxs[ifr->callno]->username);
++                                      memset(&ied0, 0, sizeof(ied0));
++                                      auth_fail(ifr->callno, IAX_COMMAND_REJECT);
++                                      break;
++                              }
++                              ast_mutex_lock(&iaxsl[ifr->callno]);
++                              if (strcasecmp(iaxs[ifr->callno]->exten, "TBD")) {
++                                      /* This might re-enter the IAX code and need the lock */
++                                      exists = ast_exists_extension(NULL, iaxs[ifr->callno]->context, iaxs[ifr->callno]->exten, 1, iaxs[ifr->callno]->cid_num);
++                              } else
++                                      exists = 0;
++                                  if (strcmp(iaxs[ifr->callno]->exten, "TBD") && !exists) {
++                                      if (authdebug)
++                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->exten, iaxs[ifr->callno]->context);
++                                      memset(&ied0, 0, sizeof(ied0));
++                                      iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
++                                      iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
++                                      send_command_final(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
++                              } else {
++                                      /* Select an appropriate format */
++                                      if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOPREFS)) {
++                                              if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP)) {
++                                                      using_prefs = "reqonly";
++                                              } else {
++                                                      using_prefs = "disabled";
++                                              }
++                                              format = iaxs[ifr->callno]->peerformat & iaxs[ifr->callno]->capability;
++                                              memset(&pref, 0, sizeof(pref));
++                                              strcpy(caller_pref_buf, "disabled");
++                                              strcpy(host_pref_buf, "disabled");
++                                      } else {
++                                              using_prefs = "mine";
++                                              if(ies->codec_prefs) {
++                                                      /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
++                                                      ast_codec_pref_convert(&rpref, ies->codec_prefs, 32, 0);
++                                                      if (ast_test_flag(iaxs[ifr->callno], IAX_CODEC_USER_FIRST)) {
++                                                              ast_codec_pref_convert(&pref, ies->codec_prefs, 32, 0);
++                                                              using_prefs = "caller";
++                                                      } else {
++                                                              pref = iaxs[ifr->callno]->prefs;
++                                                      }
++                                              } else /* if no codec_prefs IE do it the old way */
++                                                      pref = iaxs[ifr->callno]->prefs;
++                                      
++                                              format = ast_codec_choose(&pref, iaxs[ifr->callno]->capability & iaxs[ifr->callno]->peercapability, 0);
++                                              ast_codec_pref_string(&rpref, caller_pref_buf, sizeof(caller_pref_buf) - 1);
++                                              ast_codec_pref_string(&iaxs[ifr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
++                                      }
++                                      if (!format) {
++                                              if(!ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP)) {
++                                                      ast_log(LOG_DEBUG, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[ifr->callno]->peerformat), iaxs[ifr->callno]->peercapability);
++                                                      format = iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability;
++                                              }
++                                              if (!format) {
++                                                      if (authdebug) {
++                                                              if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP)) 
++                                                                      ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->capability);
++                                                              else
++                                                                      ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->peercapability, iaxs[ifr->callno]->capability);
++                                                      }
++                                                      memset(&ied0, 0, sizeof(ied0));
++                                                      iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
++                                                      iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
++                                                      send_command_final(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
++                                              } else {
++                                                      /* Pick one... */
++                                                      if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP)) {
++                                                              if(!(iaxs[ifr->callno]->peerformat & iaxs[ifr->callno]->capability))
++                                                                      format = 0;
++                                                      } else {
++                                                              if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOPREFS)) {
++                                                                      using_prefs = ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
++                                                                      memset(&pref, 0, sizeof(pref));
++                                                                      format = ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP) ?
++                                                                              iaxs[ifr->callno]->peerformat : ast_best_codec(iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability);
++                                                                      strcpy(caller_pref_buf,"disabled");
++                                                                      strcpy(host_pref_buf,"disabled");
++                                                              } else {
++                                                                      using_prefs = "mine";
++                                                                      if(ies->codec_prefs) {
++                                                                              /* Do the opposite of what we tried above. */
++                                                                              if (ast_test_flag(iaxs[ifr->callno], IAX_CODEC_USER_FIRST)) {
++                                                                                      pref = iaxs[ifr->callno]->prefs;                                                
++                                                                              } else {
++                                                                                      pref = rpref;
++                                                                                      using_prefs = "caller";
++                                                                              }
++                                                                              format = ast_codec_choose(&pref, iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability, 1);
++                                                                      } else /* if no codec_prefs IE do it the old way */
++                                                                              format = ast_best_codec(iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability);     
++                                                              }
++                                                      }
++                                                      if (!format) {
++                                                              ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[ifr->callno]->peercapability & iaxs[ifr->callno]->capability);
++                                                              if (authdebug) {
++                                                                      if(ast_test_flag(iaxs[ifr->callno], IAX_CODEC_NOCAP))
++                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->capability);
++                                                                      else
++                                                                              ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), iaxs[ifr->callno]->peerformat, iaxs[ifr->callno]->peercapability, iaxs[ifr->callno]->capability);
++                                                              }
++                                                              memset(&ied0, 0, sizeof(ied0));
++                                                              iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
++                                                              iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
++                                                              send_command_final(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
++                                                      }
++                                              }
++                                      }
++                                      if (format) {
++                                              /* Authentication received */
++                                              memset(&ied1, 0, sizeof(ied1));
++                                              iax_ie_append_int(&ied1, IAX_IE_FORMAT, format);
++                                              send_command(iaxs[ifr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
++                                              if (strcmp(iaxs[ifr->callno]->exten, "TBD")) {
++                                                      ast_set_flag(&iaxs[ifr->callno]->state, IAX_STATE_STARTED);
++                                                      if (option_verbose > 2) 
++                                                              ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s:\n"
++                                                                                      "%srequested format = %s,\n"
++                                                                                      "%srequested prefs = %s,\n"
++                                                                                      "%sactual format = %s,\n"
++                                                                                      "%shost prefs = %s,\n"
++                                                                                      "%spriority = %s\n", 
++                                                                                      ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr), 
++                                                                                      VERBOSE_PREFIX_4,
++                                                                                      ast_getformatname(iaxs[ifr->callno]->peerformat),
++                                                                                      VERBOSE_PREFIX_4,
++                                                                                      caller_pref_buf,
++                                                                                      VERBOSE_PREFIX_4,
++                                                                                      ast_getformatname(format),
++                                                                                      VERBOSE_PREFIX_4,
++                                                                                      host_pref_buf,
++                                                                                      VERBOSE_PREFIX_4,
++                                                                                      using_prefs);
++
++                                                      ast_set_flag(&iaxs[ifr->callno]->state, IAX_STATE_STARTED);
++                                                      if(!(c = ast_iax2_new(ifr->callno, AST_STATE_RING, format)))
++                                                              iax2_destroy_nolock(ifr->callno);
++                                              } else {
++                                                      ast_set_flag(&iaxs[ifr->callno]->state, IAX_STATE_TBD);
++                                                      /* If this is a TBD call, we're ready but now what...  */
++                                                      if (option_verbose > 2)
++                                                              ast_verbose(VERBOSE_PREFIX_3 "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), fr->sin.sin_addr));
++                                              }
++                                      }
++                              }
++                              iaxs_queued[ifr->callno]--;
++                              if (iaxs_queued[ifr->callno] < 0) iaxs_queued[ifr->callno] = 0;
++                              ast_mutex_unlock(&iaxsl[ifr->callno]);
++                      }
++                      if (!dequeued) {
++                          ast_mutex_lock(&iaxsl[ifr->callno]);
++                              iaxs_queued[ifr->callno]--;
++                              if (iaxs_queued[ifr->callno] < 0) iaxs_queued[ifr->callno] = 0;
++                          ast_mutex_unlock(&iaxsl[ifr->callno]);
++                      }
++                  }
++              iax_frame_free(ifr);
++              free(fr);
++              fr = NULL;
++              }
++      
++      }
++      return NULL;
++}
++
++
++static int start_auth_thread(void)
++{
++      return ast_pthread_create(&auththreadid, NULL, auth_thread, &callq);
++}
++
++static int start_reg_thread(void)
++{
++      return ast_pthread_create(&regthreadid, NULL, auth_thread, &regq);
++}
++
+ static struct iax2_context *build_context(char *context)
+ {
+       struct iax2_context *con = malloc(sizeof(struct iax2_context));
+@@ -8882,6 +9305,7 @@
+       tmpstr = ast_strdupa(data);
+       parse_dial_string(tmpstr, &pds);
++ast_log(LOG_NOTICE, "calling create_addr here\n");
+       /* Populate our address from the given */
+       if (create_addr(pds.peer, &sin, &cai))
+               return -1;
+@@ -9492,6 +9916,11 @@
+ static int __unload_module(void)
+ {
+       int x;
++      /* Cancel the authentication thread */
++      if (auththreadid != AST_PTHREADT_NULL) {
++              pthread_cancel(auththreadid);
++              pthread_join(auththreadid, NULL);
++      }
+       /* Cancel the network thread, close the net socket */
+       if (netthreadid != AST_PTHREADT_NULL) {
+               pthread_cancel(netthreadid);
+@@ -9514,6 +9943,8 @@
+ int unload_module()
+ {
++      ast_mutex_destroy(&regq.lock);
++      ast_mutex_destroy(&callq.lock);
+       ast_mutex_destroy(&iaxq.lock);
+       ast_mutex_destroy(&userl.lock);
+       ast_mutex_destroy(&peerl.lock);
+@@ -9535,6 +9966,9 @@
+       struct ast_netsock *ns;
+       struct sockaddr_in sin;
+       
++      /* you never can tell */
++      memset(iaxs_queued, 0, sizeof(iaxs_queued));
++      
+       ast_custom_function_register(&iaxpeer_function);
+       iax_set_output(iax_debug_output);
+@@ -9577,7 +10011,14 @@
+       }
+       ast_netsock_init(netsock);
++      gethostname(servername, sizeof(servername) - 1);
++      ast_log(LOG_NOTICE, "servername = %s\n", servername);
++
+       ast_mutex_init(&iaxq.lock);
++      ast_mutex_init(&regq.lock);
++      ast_cond_init(&regq.cond, NULL);
++      ast_mutex_init(&callq.lock);
++      ast_cond_init(&callq.cond, NULL);
+       ast_mutex_init(&userl.lock);
+       ast_mutex_init(&peerl.lock);
+       ast_mutex_init(&waresl.lock);
+@@ -9621,6 +10062,16 @@
+               ast_netsock_release(netsock);
+       }
++      res = start_reg_thread();
++      if (res) {
++              ast_log(LOG_ERROR, "Unable to start registration thread\n");
++      }
++
++      res = start_auth_thread();
++      if (res) {
++              ast_log(LOG_ERROR, "Unable to start authentication thread\n");
++      }
++
+       for (reg = registrations; reg; reg = reg->next)
+               iax2_do_register(reg);
+       ast_mutex_lock(&peerl.lock);
+diff -urN asterisk-1.2.4/res/Makefile asterisk-1.2.4.carrier/res/Makefile
+--- asterisk-1.2.4/res/Makefile        2006-01-31 09:41:43.000000000 +0100
++++ asterisk-1.2.4.carrier/res/Makefile        2006-01-31 15:04:30.000000000 +0100
+@@ -13,6 +13,21 @@
+ MODS=res_indications.so res_monitor.so res_adsi.so res_agi.so res_features.so res_watchdog.so
++#
++# MySQL stuff...  Autoconf anyone??
++#
++MODS+=$(shell if [ -d /usr/local/mysql/include ] || [ -d /usr/include/mysql ] || [ -d /usr/local/include/mysql ] || [ -d /opt/mysql/include ]; then echo "res_config_mysql.so"; fi)
++CFLAGS+=$(shell if [ -d /usr/local/mysql/include ]; then echo "-I/usr/local/mysql/include"; fi)
++CFLAGS+=$(shell if [ -d /usr/include/mysql ]; then echo "-I/usr/include/mysql"; fi)
++CFLAGS+=$(shell if [ -d /usr/local/include/mysql ]; then echo "-I/usr/local/include/mysql"; fi)
++CFLAGS+=$(shell if [ -d /opt/mysql/include/mysql ]; then echo "-I/opt/mysql/include/mysql"; fi)
++MLFLAGS=
++MLFLAGS+=$(shell if [ -d /usr/lib/mysql ]; then echo "-L/usr/lib/mysql"; fi)
++MLFLAGS+=$(shell if [ -d /usr/lib64/mysql ]; then echo "-L/usr/lib64/mysql"; fi)
++MLFLAGS+=$(shell if [ -d /usr/local/mysql/lib ]; then echo "-L/usr/local/mysql/lib"; fi)
++MLFLAGS+=$(shell if [ -d /usr/local/lib/mysql ]; then echo "-L/usr/local/lib/mysql"; fi)
++MLFLAGS+=$(shell if [ -d /opt/mysql/lib/mysql ]; then echo "-L/opt/mysql/lib/mysql"; fi)
++
+ ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/odbcinst.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/odbcinst.h),)
+   ifneq (${OSARCH},FreeBSD)
+     MODS+=res_config_odbc.so
+@@ -109,6 +124,9 @@
+ res_config_odbc.so: res_config_odbc.o
+       $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${CYG_RES_CONFIG_ODBC_LIB}
++res_config_mysql.so: res_config_mysql.o
++      $(CC) $(SOLINK) -o $@ $< -lmysqlclient -lz $(MLFLAGS)
++
+ ifneq ($(wildcard .depend),)
+   include .depend
+ endif
+diff -urN asterisk-1.2.4/res/res_config_mysql.c asterisk-1.2.4.carrier/res/res_config_mysql.c
+--- asterisk-1.2.4/res/res_config_mysql.c      1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4.carrier/res/res_config_mysql.c      2006-01-31 14:54:49.000000000 +0100
+@@ -0,0 +1,680 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Copyright (C) 1999-2005, Digium, Inc.
++ *
++ * Mark Spencer <markster@digium.com>  - Asterisk Author
++ * Matthew Boehm <mboehm@cytelcom.com> - MySQL RealTime Driver Author
++ *
++ * res_config_mysql.c <mysql plugin for RealTime configuration engine>
++ *
++ * v2.0   - (10-07-05) - mutex_lock fixes (bug #4973, comment #0034602)
++ *
++ * v1.9   - (08-19-05) - Added support to correctly honor the family database specified
++ *                       in extconfig.conf (bug #4973)
++ *
++ * v1.8   - (04-21-05) - Modified return values of update_mysql to better indicate
++ *                       what really happened.
++ *
++ * v1.7   - (01-28-05) - Fixed non-initialization of ast_category struct
++ *                       in realtime_multi_mysql function which caused segfault. 
++ *
++ * v1.6   - (00-00-00) - Skipped to bring comments into sync with version number in CVS.
++ *
++ * v1.5.1 - (01-26-05) - Added better(?) locking stuff
++ *
++ * v1.5   - (01-26-05) - Brought up to date with new config.h changes (bug #3406)
++ *                     - Added in extra locking provided by georg (bug #3248)
++ *
++ * v1.4   - (12-02-04) - Added realtime_multi_mysql function
++ *                        This function will return an ast_config with categories,
++ *                        unlike standard realtime_mysql which only returns
++ *                        a linked list of ast_variables
++ *
++ * v1.3   - (12-01-04) - Added support other operators
++ *                       Ex: =, !=, LIKE, NOT LIKE, RLIKE, etc...
++ *
++ * v1.2   - (11-DD-04) - Added reload. Updated load and unload.
++ *                       Code beautification (doc/CODING-GUIDELINES)
++ */
++
++#include <asterisk/channel.h>
++#include <asterisk/logger.h>
++#include <asterisk/config.h>
++#include <asterisk/module.h>
++#include <asterisk/lock.h>
++#include <asterisk/options.h>
++#include <asterisk/cli.h>
++#include <asterisk/utils.h>
++#include <stdlib.h>
++#include <string.h>
++#include <mysql.h>
++#include <mysql_version.h>
++#include <errmsg.h>
++
++static char *res_config_mysql_desc = "MySQL RealTime Configuration Driver";
++
++AST_MUTEX_DEFINE_STATIC(mysql_lock);
++#define RES_CONFIG_MYSQL_CONF "res_mysql.conf"
++MYSQL         mysql;
++static char   dbhost[50];
++static char   dbuser[50];
++static char   dbpass[50];
++static char   dbname[50];
++static char   dbsock[50];
++static int    dbport;
++static int    connected;
++static time_t connect_time;
++
++static int parse_config(void);
++static int mysql_reconnect(const char *database);
++static int realtime_mysql_status(int fd, int argc, char **argv);
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static char cli_realtime_mysql_status_usage[] =
++"Usage: realtime mysql status\n"
++"       Shows connection information for the MySQL RealTime driver\n";
++
++static struct ast_cli_entry cli_realtime_mysql_status = {
++        { "realtime", "mysql", "status", NULL }, realtime_mysql_status,
++        "Shows connection information for the MySQL RealTime driver", cli_realtime_mysql_status_usage, NULL };
++
++static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
++{
++      MYSQL_RES *result;
++      MYSQL_ROW row;
++      MYSQL_FIELD *fields;
++      int numFields, i;
++      char sql[256];
++      char *stringp;
++      char *chunk;
++      char *op;
++      const char *newparam, *newval;
++      struct ast_variable *var=NULL, *prev=NULL;
++
++      if(!table) {
++              ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
++              return NULL;
++      }
++
++      /* Get the first parameter and first value in our list of passed paramater/value pairs */
++      newparam = va_arg(ap, const char *);
++      newval = va_arg(ap, const char *);
++      if(!newparam || !newval)  {
++              ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
++              mysql_close(&mysql);
++              return NULL;
++      }
++
++      /* Create the first part of the query using the first parameter/value pairs we just extracted
++         If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
++
++      if(!strchr(newparam, ' ')) op = " ="; else op = "";
++
++      snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, newval);
++      while((newparam = va_arg(ap, const char *))) {
++              newval = va_arg(ap, const char *);
++              if(!strchr(newparam, ' ')) op = " ="; else op = "";
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, newval);
++      }
++      va_end(ap);
++
++      ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++      
++//    ast_log(LOG_NOTICE, "SQL: %s\m", sql);
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if((result = mysql_store_result(&mysql))) {
++              numFields = mysql_num_fields(result);
++              fields = mysql_fetch_fields(result);
++
++              while((row = mysql_fetch_row(result))) {
++                      for(i = 0; i < numFields; i++) {
++                              stringp = row[i];
++                              while(stringp) {
++                                      chunk = strsep(&stringp, ";");
++                                      if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
++                                              if(prev) {
++                                                      prev->next = ast_variable_new(fields[i].name, chunk);
++                                                      if (prev->next) {
++                                                              prev = prev->next;
++                                                      }
++                                              } else {
++                                                      prev = var = ast_variable_new(fields[i].name, chunk);
++                                              }
++                                      }
++                              }
++                      }
++              }
++      } else {                                
++              ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
++      }
++
++      mysql_free_result(result);
++      ast_mutex_unlock(&mysql_lock);
++
++      return var;
++}
++
++static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
++{
++      MYSQL_RES *result;
++      MYSQL_ROW row;
++      MYSQL_FIELD *fields;
++      int numFields, i;
++      char sql[256];
++      const char *initfield = NULL;
++      char *stringp;
++      char *chunk;
++      char *op;
++      const char *newparam, *newval;
++      struct ast_realloca ra;
++      struct ast_variable *var=NULL;
++      struct ast_config *cfg = NULL;
++      struct ast_category *cat = NULL;
++
++      if(!table) {
++              ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
++              return NULL;
++      }
++      
++      memset(&ra, 0, sizeof(ra));
++
++      cfg = ast_config_new();
++      if (!cfg) {
++              /* If I can't alloc memory at this point, why bother doing anything else? */
++              ast_log(LOG_WARNING, "Out of memory!\n");
++              return NULL;
++      }
++
++      /* Get the first parameter and first value in our list of passed paramater/value pairs */
++      newparam = va_arg(ap, const char *);
++      newval = va_arg(ap, const char *);
++      if(!newparam || !newval)  {
++              ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
++              mysql_close(&mysql);
++              return NULL;
++      }
++
++      initfield = ast_strdupa(newparam);
++      if(initfield && (op = strchr(initfield, ' '))) {
++              *op = '\0';
++      }
++
++      /* Create the first part of the query using the first parameter/value pairs we just extracted
++         If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
++
++      if(!strchr(newparam, ' ')) op = " ="; else op = "";
++
++      snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, newval);
++      while((newparam = va_arg(ap, const char *))) {
++              newval = va_arg(ap, const char *);
++              if(!strchr(newparam, ' ')) op = " ="; else op = "";
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam, op, newval);
++      }
++
++      if(initfield) {
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
++      }
++
++      va_end(ap);
++
++      ast_log(LOG_DEBUG, "MySQL RealTime: Retrieve SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if((result = mysql_store_result(&mysql))) {
++              numFields = mysql_num_fields(result);
++              fields = mysql_fetch_fields(result);
++
++              while((row = mysql_fetch_row(result))) {
++                      var = NULL;
++                      cat = ast_category_new("");
++                      if(!cat) {
++                              ast_log(LOG_WARNING, "Out of memory!\n");
++                              continue;
++                      }
++                      for(i = 0; i < numFields; i++) {
++                              stringp = row[i];
++                              while(stringp) {
++                                      chunk = strsep(&stringp, ";");
++                                      if(chunk && !ast_strlen_zero(ast_strip(chunk))) {
++                                              if(initfield && !strcmp(initfield, fields[i].name)) {
++                                                      ast_category_rename(cat, chunk);
++                                              }
++                                              var = ast_variable_new(fields[i].name, chunk);
++                                              ast_variable_append(cat, var);
++                                      }
++                              }
++                      }
++                      ast_category_append(cfg, cat);
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL RealTime: Could not find any rows in table %s.\n", table);
++      }
++
++      mysql_free_result(result);
++      ast_mutex_unlock(&mysql_lock);
++
++      return cfg;
++}
++
++static int update_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
++{
++      my_ulonglong numrows;
++      char sql[256];
++      const char *newparam, *newval;
++
++      if(!table) {
++              ast_log(LOG_WARNING, "MySQL RealTime: No table specified.\n");
++               return -1;
++      }
++
++      /* Get the first parameter and first value in our list of passed paramater/value pairs */
++      newparam = va_arg(ap, const char *);
++      newval = va_arg(ap, const char *);
++      if(!newparam || !newval)  {
++              ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
++              mysql_close(&mysql);
++               return -1;
++      }
++
++      /* Create the first part of the query using the first parameter/value pairs we just extracted
++         If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
++
++      snprintf(sql, sizeof(sql), "UPDATE %s SET %s = '%s'", table, newparam, newval);
++      while((newparam = va_arg(ap, const char *))) {
++              newval = va_arg(ap, const char *);
++              snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s = '%s'", newparam, newval);
++      }
++      va_end(ap);
++      snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s = '%s'", keyfield, lookup);
++
++      ast_log(LOG_DEBUG,"MySQL RealTime: Update SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return -1;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return -1;
++      }
++
++      numrows = mysql_affected_rows(&mysql);
++      ast_mutex_unlock(&mysql_lock);
++
++      ast_log(LOG_DEBUG,"MySQL RealTime: Updated %llu rows on table: %s\n", numrows, table);
++
++      /* From http://dev.mysql.com/doc/mysql/en/mysql-affected-rows.html
++       * An integer greater than zero indicates the number of rows affected
++       * Zero indicates that no records were updated
++       * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
++      */
++
++      if(numrows >= 0)
++              return (int)numrows;
++
++      return -1;
++}
++
++static struct ast_config *config_mysql(const char *database, const char *table, const char *file, struct ast_config *cfg)
++{
++      MYSQL_RES *result;
++      MYSQL_ROW row;
++      my_ulonglong num_rows;
++      struct ast_config *new;
++      struct ast_variable *cur_v, *new_v;
++      struct ast_category *cur_cat, *new_cat;
++      char sql[250] = "";
++      char last[80] = "";
++      int cat_started = 0;
++      int var_started = 0;
++      int last_cat_metric = 0;
++
++      last[0] = '\0';
++
++      if(!file || !strcmp(file, RES_CONFIG_MYSQL_CONF)) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Cannot configure myself.\n");
++              return NULL;
++      }
++
++      snprintf(sql, sizeof(sql), "SELECT category, var_name, var_val, cat_metric FROM %s WHERE filename='%s' and commented=0 ORDER BY filename, cat_metric desc, var_metric asc, category, var_name, var_val, id", table, file);
++
++      ast_log(LOG_DEBUG, "MySQL RealTime: Static SQL: %s\n", sql);
++
++      /* We now have our complete statement; Lets connect to the server and execute it. */
++      ast_mutex_lock(&mysql_lock);
++      if(!mysql_reconnect(database)) {
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if(mysql_real_query(&mysql, sql, strlen(sql))) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Failed to query database. Check debug for more info.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query: %s\n", sql);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Query Failed because: %s\n", mysql_error(&mysql));
++              ast_mutex_unlock(&mysql_lock);
++              return NULL;
++      }
++
++      if((result = mysql_store_result(&mysql))) {
++              num_rows = mysql_num_rows(result);
++              ast_log(LOG_DEBUG, "MySQL RealTime: Found %llu rows.\n", num_rows);
++
++              /* There might exist a better way to access the column names other than counting,
++                   but I believe that would require another loop that we don't need. */
++
++              while((row = mysql_fetch_row(result))) {
++                      if(!strcmp(row[1], "#include")) {
++                              if (!ast_config_internal_load(row[2], cfg)) {
++                                      mysql_free_result(result);
++                                      ast_mutex_unlock(&mysql_lock);
++                                      return NULL;
++                              }
++                              continue;
++                      }
++
++                      if(strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) {
++                              cur_cat = ast_category_new(row[0]);
++                              if (!cur_cat) {
++                                      ast_log(LOG_WARNING, "Out of memory!\n");
++                                      break;
++                              }
++                              strcpy(last, row[0]);
++                              last_cat_metric = atoi(row[3]);
++                              ast_category_append(cfg, cur_cat);
++                      }
++                      new_v = ast_variable_new(row[1], row[2]);
++                      ast_variable_append(cur_cat, new_v);
++              }
++      } else {
++              ast_log(LOG_WARNING, "MySQL RealTime: Could not find config '%s' in database.\n", file);
++      }
++
++      mysql_free_result(result);
++      ast_mutex_unlock(&mysql_lock);
++
++      return cfg;
++}
++
++static struct ast_config_engine mysql_engine = {
++      .name = "mysql",
++      .load_func = config_mysql,
++      .realtime_func = realtime_mysql,
++      .realtime_multi_func = realtime_multi_mysql,
++      .update_func = update_mysql
++};
++
++int load_module (void)
++{
++      parse_config();
++
++      ast_mutex_lock(&mysql_lock);
++
++      if(!mysql_reconnect(NULL)) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
++      }
++
++      ast_config_engine_register(&mysql_engine);
++      if(option_verbose) {
++              ast_verbose("MySQL RealTime driver loaded.\n");
++      }
++      ast_cli_register(&cli_realtime_mysql_status);
++
++      ast_mutex_unlock(&mysql_lock);
++
++      return 0;
++}
++
++int unload_module (void)
++{
++      /* Aquire control before doing anything to the module itself. */
++      ast_mutex_lock(&mysql_lock);
++
++      mysql_close(&mysql);
++      ast_cli_unregister(&cli_realtime_mysql_status);
++      ast_config_engine_deregister(&mysql_engine);
++      if(option_verbose) {
++              ast_verbose("MySQL RealTime unloaded.\n");
++      }
++
++      STANDARD_HANGUP_LOCALUSERS;
++
++      /* Unlock so something else can destroy the lock. */
++      ast_mutex_unlock(&mysql_lock);
++
++      return 0;
++}
++
++int reload (void)
++{
++      /* Aquire control before doing anything to the module itself. */
++      ast_mutex_lock(&mysql_lock);
++
++      mysql_close(&mysql);
++      connected = 0;
++      parse_config();
++
++      if(!mysql_reconnect(NULL)) {
++              ast_log(LOG_WARNING, "MySQL RealTime: Couldn't establish connection. Check debug.\n");
++              ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
++      }
++
++      ast_verbose(VERBOSE_PREFIX_2 "MySQL RealTime reloaded.\n");
++
++      /* Done reloading. Release lock so others can now use driver. */
++      ast_mutex_unlock(&mysql_lock);
++
++      return 0;
++}
++
++int parse_config (void)
++{
++      struct ast_config *config;
++      char *s;
++
++      config = ast_config_load(RES_CONFIG_MYSQL_CONF);
++
++      if(config) {
++              if(!(s=ast_variable_retrieve(config, "general", "dbuser"))) {
++                      ast_log(LOG_WARNING, "MySQL RealTime: No database user found, using 'asterisk' as default.\n");
++                      strncpy(dbuser, "asterisk", sizeof(dbuser) - 1);
++              } else {
++                      strncpy(dbuser, s, sizeof(dbuser) - 1);
++              }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbpass"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database password found, using 'asterisk' as default.\n");
++                        strncpy(dbpass, "asterisk", sizeof(dbpass) - 1);
++                } else {
++                        strncpy(dbpass, s, sizeof(dbpass) - 1);
++                }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbhost"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database host found, using localhost via socket.\n");
++                      dbhost[0] = '\0';
++                } else {
++                        strncpy(dbhost, s, sizeof(dbhost) - 1);
++                }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbname"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database name found, using 'asterisk' as default.\n");
++                      strncpy(dbname, "asterisk", sizeof(dbname) - 1);
++                } else {
++                        strncpy(dbname, s, sizeof(dbname) - 1);
++                }
++
++              if(!(s=ast_variable_retrieve(config, "general", "dbport"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database port found, using 3306 as default.\n");
++                      dbport = 3306;
++                } else {
++                      dbport = atoi(s);
++                }
++
++              if(dbhost && !(s=ast_variable_retrieve(config, "general", "dbsock"))) {
++                        ast_log(LOG_WARNING, "MySQL RealTime: No database socket found, using '/tmp/mysql.sock' as default.\n");
++                        strncpy(dbsock, "/tmp/mysql.sock", sizeof(dbsock) - 1);
++                } else {
++                        strncpy(dbsock, s, sizeof(dbsock) - 1);
++                }
++      }
++      ast_config_destroy(config);
++
++      if(dbhost) {
++              ast_log(LOG_DEBUG, "MySQL RealTime Host: %s\n", dbhost);
++              ast_log(LOG_DEBUG, "MySQL RealTime Port: %i\n", dbport);
++      } else {
++              ast_log(LOG_DEBUG, "MySQL RealTime Socket: %s\n", dbsock);
++      }
++      ast_log(LOG_DEBUG, "MySQL RealTime User: %s\n", dbuser);
++      ast_log(LOG_DEBUG, "MySQL RealTime Password: %s\n", dbpass);
++
++      return 1;
++}
++
++char *description (void)
++{
++      return res_config_mysql_desc;
++}
++
++int usecount (void)
++{
++      /* Try and get a lock. If unsuccessful, than that means another thread is using the mysql object. */
++      if(ast_mutex_trylock(&mysql_lock)) {
++              ast_log(LOG_DEBUG, "MySQL RealTime: Module usage count is 1.\n");
++              return 1;
++      }
++      ast_mutex_unlock(&mysql_lock);
++      return 0;
++}
++
++char *key ()
++{
++      return ASTERISK_GPL_KEY;
++}
++
++static int mysql_reconnect(const char *database)
++{
++      char my_database[50];
++
++      if(!database || ast_strlen_zero(database))
++              ast_copy_string(my_database, dbname, sizeof(my_database));
++      else
++              ast_copy_string(my_database, database, sizeof(my_database));
++
++      /* mutex lock should have been locked before calling this function. */
++
++      if((!connected) && (dbhost || dbsock) && dbuser && dbpass && my_database) {
++              if(!mysql_init(&mysql)) {
++                      ast_log(LOG_WARNING, "MySQL RealTime: Insufficient memory to allocate MySQL resource.\n");
++                      connected = 0;
++                      return 0;
++              }
++              if(mysql_real_connect(&mysql, dbhost, dbuser, dbpass, my_database, dbport, dbsock, 0)) {
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Successfully connected to database.\n");
++                      connected = 1;
++                      connect_time = time(NULL);
++                      return 1;
++              } else {
++                      ast_log(LOG_ERROR, "MySQL RealTime: Failed to connect database server %s on %s. Check debug for more info.\n", dbname, dbhost);
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Cannot Connect: %s\n", mysql_error(&mysql));
++                      connected = 0;
++                      return 0;
++              }
++      } else {
++              if(mysql_ping(&mysql) != 0) {
++                      connected = 0;
++                      ast_log(LOG_ERROR, "MySQL RealTime: Failed to reconnect. Check debug for more info.\n");
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Server Error: %s\n", mysql_error(&mysql));
++                      return 0;
++              }
++
++              connected = 1;
++
++              if(mysql_select_db(&mysql, my_database) != 0) {
++                      ast_log(LOG_WARNING, "MySQL RealTime: Unable to select database: %s. Still Connected.\n", my_database);
++                      ast_log(LOG_DEBUG, "MySQL RealTime: Database Select Failed: %s\n", mysql_error(&mysql));
++                      return 0;
++              }
++
++              ast_log(LOG_DEBUG, "MySQL RealTime: Everything is fine.\n");
++              return 1;
++      }
++}
++
++static int realtime_mysql_status(int fd, int argc, char **argv)
++{
++      char status[256], status2[100] = "";
++      int ctime = time(NULL) - connect_time;
++
++      ast_mutex_lock(&mysql_lock);
++      if(mysql_reconnect(NULL)) {
++              if(dbhost) {
++                      snprintf(status, 255, "Connected to %s@%s, port %d", dbname, dbhost, dbport);
++              } else if(dbsock) {
++                      snprintf(status, 255, "Connected to %s on socket file %s", dbname, dbsock);
++              } else {
++                      snprintf(status, 255, "Connected to %s@%s", dbname, dbhost);
++              }
++
++              if(dbuser && *dbuser) {
++                      snprintf(status2, 99, " with username %s", dbuser);
++              }
++
++              if (ctime > 31536000) {
++                      ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 31536000, (ctime % 31536000) / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 86400) {
++                      ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 86400, (ctime % 86400) / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 3600) {
++                      ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n", status, status2, ctime / 3600, (ctime % 3600) / 60, ctime % 60);
++              } else if (ctime > 60) {
++                      ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2, ctime / 60, ctime % 60);
++              } else {
++                      ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
++              }
++
++              ast_mutex_unlock(&mysql_lock);
++              return RESULT_SUCCESS;
++      } else {
++              ast_mutex_unlock(&mysql_lock);
++              return RESULT_FAILURE;
++      }
++}
diff --git a/src/patches/asterisk-1.2.4-ipfire-bristuff-0.3.0-PRE-1l.patch b/src/patches/asterisk-1.2.4-ipfire-bristuff-0.3.0-PRE-1l.patch
new file mode 100644 (file)
index 0000000..05aa370
--- /dev/null
@@ -0,0 +1,12853 @@
+diff -urN asterisk-1.2.4.orig/.version asterisk-1.2.4/.version
+--- asterisk-1.2.4.orig/.version       2006-01-31 04:55:50.000000000 +0100
++++ asterisk-1.2.4/.version    2006-01-31 09:41:43.000000000 +0100
+@@ -1 +1 @@
+-1.2.4
++1.2.4-BRIstuffed-0.3.0-PRE-1l-for-ipfire
+diff -urN asterisk-1.2.4.orig/HARDWARE asterisk-1.2.4/HARDWARE
+--- asterisk-1.2.4.orig/HARDWARE       2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/HARDWARE    2006-01-31 09:41:43.000000000 +0100
+@@ -37,6 +37,19 @@
+    * Wildcard TE410P - Quad T1/E1 switchable interface.  Supports PRI and 
+      RBS signalling, as well as PPP, FR, and HDLC data modes.
++-- Junghanns.NET (Primary author of BRIstuff)
++      http://www.junghanns.net
++      
++    * quadBRI PCI ISDN - 4port BRI ISDN interface, supports NT and TE mode
++    
++    * octoBRI PCI ISDN - 8port BRI ISDN interface, supports NT and TE mode
++
++    * singleE1 PCI ISDN - Single E1 interface
++
++    * doubleE1 PCI ISDN - Double E1 interface
++    
++    * quadGSM PCI ISDN - 4 channel GSM interface
++
+ Non-zaptel compatible hardware
+ ==============================
+diff -urN asterisk-1.2.4.orig/LICENSE asterisk-1.2.4/LICENSE
+--- asterisk-1.2.4.orig/LICENSE        2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/LICENSE     2006-01-31 09:41:43.000000000 +0100
+@@ -1,7 +1,7 @@
+-Asterisk is distributed under the GNU General Public License version 2
+-and is also available under alternative licenses negotiated directly
+-with Digium, Inc. If you obtained Asterisk under the GPL, then the GPL
+-applies to all loadable Asterisk modules used on your system as well,
++BRIstuffed Asterisk is distributed under the GNU General Public License version 2
++and is not available under any alternative licenses.
++If you obtained BRIstuffed Asterisk under the GPL, then the GPL
++applies to all loadable BRIstuffed Asterisk modules used on your system as well,
+ except as defined below. The GPL (version 2) is included in this
+ source tree in the file COPYING.
+diff -urN asterisk-1.2.4.orig/Makefile asterisk-1.2.4/Makefile
+--- asterisk-1.2.4.orig/Makefile       2005-12-05 07:47:51.000000000 +0100
++++ asterisk-1.2.4/Makefile    2006-01-31 09:41:43.000000000 +0100
+@@ -759,6 +759,9 @@
+               echo ";astctlowner = root" ; \
+               echo ";astctlgroup = apache" ; \
+               echo ";astctl = asterisk.ctl" ; \
++              echo "[options]" ; \
++              echo "uniquename = asterisk" ;\
++              echo "silence_suppression = yes" ;\
+               ) > $(DESTDIR)$(ASTCONFPATH) ; \
+       else \
+               echo "Skipping asterisk.conf creation"; \
+diff -urN asterisk-1.2.4.orig/README asterisk-1.2.4/README
+--- asterisk-1.2.4.orig/README 2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/README      2006-01-31 09:41:43.000000000 +0100
+@@ -4,6 +4,8 @@
+ Copyright (C) 2001-2005 Digium, Inc.
+ and other copyright holders.
++Copyright (C) 2002-2005 Junghanns.NET GmbH 
++and other copyright holders.
+ ================================================================
+ * SECURITY
+diff -urN asterisk-1.2.4.orig/README.chan_capi asterisk-1.2.4/README.chan_capi
+--- asterisk-1.2.4.orig/README.chan_capi       1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/README.chan_capi    2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,146 @@
++(CAPI*) chan_capi a Common ISDN API 2.0 implementation for Asterisk
++(C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH 
++Klaus-Peter Junghanns <kpj@junghanns.net>
++
++This program is free software and may be modified and distributed under
++the terms of the GNU Public License. There is _NO_ warranty for this!
++
++Thanks go to the debuggers and bugfixers (listed in chronological order) :)
++===========================================================================
++Lele Forzani <lele@windmill.it>
++Florian Overkamp <florian@obsimref.com>
++Gareth Watts <gareth@omnipotent.net>
++Jeff Noxon <jeff@planetfall.com>
++Petr Michalek <petr.michalek@aca.cz>
++Jan Stocker
++(...and all the others that i forgot..) :-)
++
++chan_capi version 0.4.0-PRE1 includes:
++======================================
++
++- multiple controller support
++- CID,DNID (callling party, called party)
++- CLIR/CLIP
++- supplementary services, CD,HOLD,RETRIEVE,ECT
++- DTMF (dependend on card) + software DTMF support
++- early B3 connects (always,success,never)
++- digital audio (what did you think?)
++- incoming/outgoing calls
++- overlap sending (dialtone)
++- E(xplicit) C(all) T(ransfer) (...although it's done implicit .. but dont tell!)
++- tuneable latency ;) you can configure the size of B3 blocks at compile time
++  (in chan_capi_pvt.h, AST_CAPI_MAX_B3_BLOCK_SIZE)
++  the default is 160 samples, for non-VoIP use you can tune it down to 130
++- use asterisk's internal dsp functions for dtmf
++- alaw support 
++- ulaw support! 
++- Eicon CAPI echo cancelation (echocancel=1)
++- reject call waiting (ACO)
++- DID for Point to Point mode (a.k.a overlap receiving)
++- experimental echo squelching (echosquelch=1)
++- call progress, no need to add ||r to your dialstring anymore
++- rx/tx gains (rxgain=1.0)
++- call deflection on circuitbusy (makefile option) (deflect=12345678)
++- (inter)national dialing prefix (for callerid) configurable in capi.conf
++- CLI command "capi info" shows B channel status
++- capiECT will announce the callerID since it gets lost on most isdn pbxes
++  the called party can press # to drop the call
++- audio syncing (timing outgoing dataB3 on incoming dataB3), supposed to fix
++  the DATA_B3_REQ (error = 0x1103) problem
++- catch all MSN (incomingmsn=*)
++- some configuration enhancements (msn=123,124,125 and controller=1,2,3,4)
++- accountcode= added.
++- finally the echo squelching works!
++- callgroup support
++- fixed pipe leak
++- updated to support the new frame->delivery field
++- compiles with latest cvs with a makefile option (LOOK AT THE MAKEFILE)
++- fixed channel name bug in p2p mode
++- added app_capiNoES for disabling the primitive echo suppressor, use this before
++  you start recording voicemail or your files may get choppy
++- fixed for latest cvs (AST_MUTEX_DEFINE_STATIC)
++- fixed for latest cvs (asterisk/parking.h -> asterisk/features.h)
++- fixed for latest cvs ast_pthread_create
++
++- ATTENTION! the dialstring syntax now uses the zaptel dialstring syntax 
++  it used to be:  Dial(CAPI/[@]<outgoingMSN>:[b|B]<destination>)
++ 
++  now it is:      Dial(CAPI/g<group>/[b|B]<destination>)
++  or:             Dial(CAPI/contr<controller>/[b|B]<destination>)
++ 
++  CLIP/CLIR is now uses the calling presentation of the calling channel, this can
++  be modified using the CallingPres() application. Use CallinPres(32) for CLIR.
++  That is why the msn= param in capi.conf is now obsolete. The callerID is also
++  taken from the calling channel.
++
++- fixes for BSD (Jan Stocker)
++
++Helper applications
++===================
++kapejod says: "No No No, dont use those yet....!" (except maybe HOLD,ECT...)
++
++app_capiCD.c          forwards an unanswered call to another phone (does not rely on sservice CD)
++                      example:
++                      exten => s,1,Wait,1
++                      exten => s,2,capiCD,12345678
++                      
++app_capiHOLD.c                puts an answered call on hold, this has nothing to do with asterisk's onhold thingie (music et al)
++                      after putting a call onhold, never use the Wait application!
++
++app_capiRETRIEVE.c    gets the holded call back
++
++app_capiECT.c         explicit call transfer of the holded call (must put call on hold first!)
++                      example:
++                      exten => s,1,Answer
++                      exten => s,2,capiHOLD
++                      exten => s,3,capiECT,55:50
++                      will ECT the call to 50 using 55 as the callerid/outgoing msn
++
++
++Using CLIR
++==========
++Use the CallingPres() application before you dial:
++exten => _X.,1,CallingPres(32)
++exten => _X.,2,Dial(CAPI/contr1/${EXTEN})    
++
++Enjoying early B3 connects (inband call progress, tones and announcements)
++==========================================================================
++early B3 is now configurable in the dialstring :)
++if you prefix the destination number with a 'b' early B3 will always be used, also if the call fails
++because the number is unprovisioned, etc ...
++if you prefix it with a 'B' early B3 will only be used on successful calls, giving you ring indication,etc...
++
++dont use indications in the Dial command, your local exchange will do that for you:
++exten => _X.,1,Dial(CAPI/contr1/B${EXTEN},30)         (early B3 on success)
++exten => _X.,1,Dial(CAPI/contr1/b${EXTEN},30)         (always early B3)
++exten => _X.,1,Dial(CAPI/contr1/${EXTEN},30,r)                (no early B3, fake ring indication)
++
++exten => _X.,1,Dial(CAPI/contr1/b${EXTEN},30,r)               (always early B3, fake indicatons if the exchange
++                                                      does not give us indications)
++exten => _X.,1,Dial(CAPI/contr1/B${EXTEN},30,r)               (early B3 on success, fake indicatons if the exchange
++                                                      does not give us indications)
++    
++you can totally turn B3 off in the Makefile at buildtime (-DNEVER_EVER_EARLY_B3_CONNECTS).
++
++For normal PBX usage you would use the "b" option, always early B3.
++
++Overlap sending (a.k.a. real dialtone)
++======================================
++when you dial an empty number, and have early B3 enabled, with:
++    Dial(CAPI/g1/b)
++the channel will come up at once and give you the dialtone it gets from the local exchange.
++at this point the channel is like a legacy phone, now you can send dtmf digits to dial.    
++
++Example context for incoming calls on MSN 12345678:
++===================================================
++
++[capi-in]
++exten => 12345678,1,Dial(SIP/phone1)
++exten => 12345678,2,Hangup
++
++
++More information/documentation and commercial support can be found at:
++      http://www.junghanns.net/asterisk/
++      
++
++
+diff -urN asterisk-1.2.4.orig/agi/Makefile asterisk-1.2.4/agi/Makefile
+--- asterisk-1.2.4.orig/agi/Makefile   2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/agi/Makefile        2006-01-31 09:41:43.000000000 +0100
+@@ -11,7 +11,7 @@
+ # the GNU General Public License
+ #
+-AGIS=agi-test.agi eagi-test eagi-sphinx-test
++AGIS=agi-test.agi eagi-test eagi-sphinx-test xagi-test
+ CFLAGS+=
+@@ -37,7 +37,7 @@
+       $(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o $(LIBS) 
+ clean:
+-      rm -f *.so *.o look .depend eagi-test eagi-sphinx-test
++      rm -f *.so *.o look .depend eagi-test eagi-sphinx-test xagi-test
+ %.so : %.o
+       $(CC) -shared -Xlinker -x -o $@ $<
+diff -urN asterisk-1.2.4.orig/agi/xagi-test.c asterisk-1.2.4/agi/xagi-test.c
+--- asterisk-1.2.4.orig/agi/xagi-test.c        1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/agi/xagi-test.c     2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,176 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * XAGI sample script 
++ * 
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * based on eagi-test.c
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/select.h>
++#ifdef SOLARIS
++#include <solaris-compat/compat.h>
++#endif
++
++#define AUDIO_FILENO_IN (STDERR_FILENO + 1)
++#define AUDIO_FILENO_OUT (STDERR_FILENO + 2)
++
++static int read_environment(void)
++{
++      char buf[256];
++      char *val;
++      /* Read environment */
++      for(;;) {
++              fgets(buf, sizeof(buf), stdin);
++              if (feof(stdin))
++                      return -1;
++              buf[strlen(buf) - 1] = '\0';
++              /* Check for end of environment */
++              if (!strlen(buf))
++                      return 0;
++              val = strchr(buf, ':');
++              if (!val) {
++                      fprintf(stderr, "Invalid environment: '%s'\n", buf);
++                      return -1;
++              }
++              *val = '\0';
++              val++;
++              val++;
++              /* Skip space */
++      //      fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
++
++              /* Load into normal environment */
++              setenv(buf, val, 1);
++              
++      }
++      /* Never reached */
++      return 0;
++}
++
++static void app_echo(void)
++{
++      fd_set fds;
++      int res;
++      int bytes = 0;
++      static char astresp[256];
++      char audiobuf[16000]; /* 1 second of audio */
++      for (;;) {
++              FD_ZERO(&fds);
++              FD_SET(STDIN_FILENO, &fds);
++              FD_SET(AUDIO_FILENO_IN, &fds);
++              /* Wait for *some* sort of I/O */
++              res = select(AUDIO_FILENO_IN + 1, &fds, NULL, NULL, NULL);
++              if (res < 0) {
++                      fprintf(stderr, "Error in select: %s\n", strerror(errno));
++                      return;
++              }
++              if (FD_ISSET(STDIN_FILENO, &fds)) {
++                      fgets(astresp, sizeof(astresp), stdin);
++                      if (feof(stdin)) {
++                              return NULL;
++                      }
++                      astresp[strlen(astresp) - 1] = '\0';
++                      fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
++                      return astresp;
++              }
++              if (FD_ISSET(AUDIO_FILENO_IN, &fds)) {
++                      /* what goes in.... */
++                      res = read(AUDIO_FILENO_IN, audiobuf, sizeof(audiobuf));
++                      if (res > 0) {
++                          bytes = res;
++                          /* must come out */
++                          write(AUDIO_FILENO_OUT, audiobuf, bytes);
++                      }
++              }
++      }
++}
++
++static char *wait_result(void)
++{
++      fd_set fds;
++      int res;
++      int bytes = 0;
++      static char astresp[256];
++      char audiobuf[4096];
++      for (;;) {
++              FD_ZERO(&fds);
++              FD_SET(STDIN_FILENO, &fds);
++              FD_SET(AUDIO_FILENO_IN, &fds);
++              /* Wait for *some* sort of I/O */
++              res = select(AUDIO_FILENO_IN + 1, &fds, NULL, NULL, NULL);
++              if (res < 0) {
++                      fprintf(stderr, "Error in select: %s\n", strerror(errno));
++                      return NULL;
++              }
++              if (FD_ISSET(STDIN_FILENO, &fds)) {
++                      fgets(astresp, sizeof(astresp), stdin);
++                      if (feof(stdin)) {
++                              fprintf(stderr, "Got hungup on apparently\n");
++                              return NULL;
++                      }
++                      astresp[strlen(astresp) - 1] = '\0';
++                      fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
++                      return astresp;
++              }
++              if (FD_ISSET(AUDIO_FILENO_IN, &fds)) {
++                      res = read(AUDIO_FILENO_IN, audiobuf, sizeof(audiobuf));
++                      /* drop it, like it's hot */
++              }
++      }
++              
++}
++
++static char *run_command(char *command)
++{
++      fprintf(stdout, "%s\n", command);
++      return wait_result();
++}
++
++
++static int run_script(void)
++{
++      char *res;
++              res = run_command("STREAM FILE demo-echotest \"\"");
++      if (!res) {
++              fprintf(stderr, "Failed to execute command\n");
++              return -1;
++      }
++      app_echo();
++      return 0;
++}
++
++int main(int argc, char *argv[])
++{
++      char *tmp;
++      int ver = 0;
++      int subver = 0;
++      /* Setup stdin/stdout for line buffering */
++      setlinebuf(stdin);
++      setlinebuf(stdout);
++      if (read_environment()) {
++              fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
++              exit(1);
++      }
++      tmp = getenv("agi_enhanced");
++      if (tmp) {
++              if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
++                      ver = 0;
++      }
++      if (ver < 2) {
++              fprintf(stderr, "No XAGI services available.  Use XAGI, not AGI or EAGI\n");
++              exit(1);
++      }
++      if (run_script())
++              return -1;
++      exit(0);
++}
+diff -urN asterisk-1.2.4.orig/apps/Makefile asterisk-1.2.4/apps/Makefile
+--- asterisk-1.2.4.orig/apps/Makefile  2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/apps/Makefile       2006-01-31 09:41:43.000000000 +0100
+@@ -28,8 +28,15 @@
+      app_test.so app_forkcdr.so app_math.so app_realtime.so \
+      app_dumpchan.so app_waitforsilence.so app_while.so app_setrdnis.so \
+      app_md5.so app_readfile.so app_chanspy.so app_settransfercapability.so \
++     app_pickup.so app_segfault.so app_callingpres.so app_devstate.so \
+      app_dictate.so app_externalivr.so app_directed_pickup.so \
+-     app_mixmonitor.so app_stack.so
++     app_mixmonitor.so app_stack.so 
++
++
++ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/capi20.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/capi20.h),)
++  APPS+= app_capiNoES.so app_capiCD.so app_capiECT.so
++endif
++    
+ #
+ # Obsolete things...
+diff -urN asterisk-1.2.4.orig/apps/app_callingpres.c asterisk-1.2.4/apps/app_callingpres.c
+--- asterisk-1.2.4.orig/apps/app_callingpres.c 1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_callingpres.c      2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,70 @@
++/*
++ * An application to change the CallingPresentation for an Asterisk channel.
++ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License. 
++ *
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++
++static char *synopsis_callingpres = "Change the presentation for the callerid";
++static char *descrip_callingpres = "Callingpres(number): Changes the presentation for the callerid. Should be called before placing an outgoing call\n";
++static char *app_callingpres = "CallingPres";
++STANDARD_LOCAL_USER;
++LOCAL_USER_DECL;
++
++
++static int change_callingpres(struct ast_channel *chan, void *data)
++{
++    int mode = 0;
++    struct localuser *u;
++    LOCAL_USER_ADD(u);
++    if (data) {
++        mode = atoi((char *)data);
++        chan->cid.cid_pres = mode;
++    } else
++        ast_log(LOG_NOTICE, "Application %s requres an argument: %s(number)\n", app_callingpres,app_callingpres);
++    LOCAL_USER_REMOVE(u);
++    return 0;
++}    
++
++int unload_module(void)
++{
++    STANDARD_HANGUP_LOCALUSERS;
++    return ast_unregister_application(app_callingpres);
++}
++
++int load_module(void)
++{
++    return ast_register_application(app_callingpres, change_callingpres, synopsis_callingpres, descrip_callingpres);
++}
++
++char *description(void)
++{
++    return descrip_callingpres;
++}
++
++int usecount(void)
++{
++    int res;
++    STANDARD_USECOUNT(res);
++    return res;
++}
++
++char *key()
++{
++    return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_capiCD.c asterisk-1.2.4/apps/app_capiCD.c
+--- asterisk-1.2.4.orig/apps/app_capiCD.c      1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_capiCD.c   2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,172 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Call Deflection, inspired by capircvd by Alexander Brickwedde
++ *
++ * Copyright (C) 2002,2003,2004,2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and 
++ * distributed under the terms of the GNU Public License.
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <linux/capi.h>
++#include <capi20.h>
++
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/chan_capi.h>
++#include <asterisk/chan_capi_app.h>
++
++
++
++static char *tdesc = "(CAPI*) Call Deflection, the magic thing.";
++static char *app = "capiCD";
++static char *synopsis = "call deflection";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int capiCD_exec(struct ast_channel *chan, void *data)
++{
++    struct ast_capi_pvt *i = chan->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR Info;
++    _cmsg     CMSG;
++    char      bchaninfo[1];
++    char      fac[60];
++    int res=0;
++    int ms=3000;
++    struct localuser *u;
++
++    if (!data) {
++      ast_log(LOG_WARNING, "cd requires an argument (destination phone number)\n");
++      return -1;
++    }
++    LOCAL_USER_ADD(u);
++    /* Do our thing here */
++
++    if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_BCONNECTED)) {
++      ast_log(LOG_ERROR, "call deflection does not work with calls that are already connected!\n");
++      LOCAL_USER_REMOVE(u);
++      return -1;
++    }
++    // wait until the channel is alerting, so we dont drop the call and interfer with msgs
++    while ((ms > 0) && (i->state != CAPI_STATE_ALERTING)) {
++      sleep(100);
++      ms -= 100;
++    }
++
++    // make sure we hang up correctly
++    i->state = CAPI_STATE_CONNECTPENDING;
++
++    fac[0]=0; // len 
++    fac[1]=0; //len 
++    fac[2]=0x01; // Use D-Chan
++    fac[3]=0; // Keypad len
++    fac[4]=31;        // user user data? len = 31 = 29 + 2
++    fac[5]=0x1c;      // magic?
++    fac[6]=0x1d;      // strlen destination + 18 = 29
++    fac[7]=0x91;      // ..
++    fac[8]=0xA1;
++    fac[9]=0x1A;      // strlen destination + 15 = 26
++    fac[10]=0x02;
++    fac[11]=0x01;
++    fac[12]=0x70;
++    fac[13]=0x02;
++    fac[14]=0x01;
++    fac[15]=0x0d;
++    fac[16]=0x30;
++    fac[17]=0x12;     // strlen destination + 7 = 18
++    fac[18]=0x30;     // ...hm 0x30
++    fac[19]=0x0d;     // strlen destination + 2       
++    fac[20]=0x80;     // CLIP
++    fac[21]=0x0b;     //  strlen destination 
++    fac[22]=0x01;     //  destination start
++    fac[23]=0x01;     //  
++    fac[24]=0x01;     //  
++    fac[25]=0x01;     //  
++    fac[26]=0x01;     //  
++    fac[27]=0x01;     //  
++    fac[28]=0x01;     //  
++    fac[29]=0x01;     //  
++    fac[30]=0x01;     //  
++    fac[31]=0x01;     //  
++    fac[32]=0x01;     //  
++    fac[33]=0x01;     // 0x1 = sending complete
++    fac[34]=0x01;
++    fac[35]=0x01;
++                                 
++    memcpy((unsigned char *)fac+22,data,strlen(data));
++    fac[22+strlen(data)]=0x01;        // fill with 0x01 if number is only 6 numbers (local call)
++    fac[23+strlen(data)]=0x01;
++    fac[24+strlen(data)]=0x01;
++    fac[25+strlen(data)]=0x01;
++    fac[26+strlen(data)]=0x01;
++     
++    fac[6]=18+strlen(data);
++    fac[9]=15+strlen(data);
++    fac[17]=7+strlen(data);
++    fac[19]=2+strlen(data);
++    fac[21]=strlen(data);
++
++    bchaninfo[0] = 0x1;
++    INFO_REQ_HEADER(&CMSG,ast_capi_ApplID,ast_capi_MessageNumber++,0);
++    INFO_REQ_CONTROLLER(&CMSG) = i->controller;
++    INFO_REQ_PLCI(&CMSG) = i->PLCI;
++    INFO_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char*)bchaninfo; // use D-Channel
++    INFO_REQ_KEYPADFACILITY(&CMSG) = 0;
++    INFO_REQ_USERUSERDATA(&CMSG) = 0;
++    INFO_REQ_FACILITYDATAARRAY(&CMSG) = (unsigned char*) fac + 4;
++
++    if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++      ast_log(LOG_ERROR,"Error sending INFO_REQ\n");
++      return Info;
++    } else {
++      if (capidebug) {
++          // ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG));
++          ast_log(LOG_NOTICE,"sent INFO_REQ PLCI = %#x\n",i->PLCI);
++      }
++    }
++
++    LOCAL_USER_REMOVE(u);
++    return res;
++}
++
++int unload_module(void)
++{
++      STANDARD_HANGUP_LOCALUSERS;
++      return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++      return ast_register_application(app, capiCD_exec,synopsis,tdesc);
++}
++
++char *description(void)
++{
++      return tdesc;
++}
++
++int usecount(void)
++{
++      int res;
++      STANDARD_USECOUNT(res);
++      return res;
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_capiECT.c asterisk-1.2.4/apps/app_capiECT.c
+--- asterisk-1.2.4.orig/apps/app_capiECT.c     1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_capiECT.c  2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,210 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * ECT transfer the held call 
++ *
++ * Copyright (C) 2002,2003,2004,2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and 
++ * distributed under the terms of the GNU Public License.
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <linux/capi.h>
++#include <capi20.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/say.h>
++#include <asterisk/chan_capi.h>
++#include <asterisk/chan_capi_app.h>
++
++
++static char *tdesc = "(CAPI*) ECT";
++static char *app = "capiECT";
++static char *synopsis = "transfer the call that is on hold";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++
++static int capiECT_exec(struct ast_channel *chan, void *data)
++{
++    struct ast_capi_pvt *i = chan->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR Info;
++    _cmsg     CMSG;
++    unsigned char fac[8];
++    int res=0;
++    struct localuser *u;
++    char *ecodes = "*#";
++
++    if (!data) {
++      ast_log(LOG_WARNING, "ECT requires an argument (destination phone number)\n");
++      return -1;
++    }
++    LOCAL_USER_ADD(u);
++    /* Do our thing here */
++    if (i->onholdPLCI <= 0) {
++      ast_log(LOG_WARNING, "no call on hold that could be transfered\n");
++      return -1;
++    }
++
++    ast_log(LOG_NOTICE,"ECT to %s\n",(char *)data);
++    capi_call(chan,data,0);
++
++    while ((i->state != CAPI_STATE_BCONNECTED) && (i->onholdPLCI != 0)) {
++      usleep(10000);
++    }
++
++
++    if (i->state == CAPI_STATE_BCONNECTED) {
++      ast_log(LOG_NOTICE,"call was answered\n");
++
++      capi_detect_dtmf(chan,1);
++
++      // put the stuff to play announcement message here --->   <-----
++      res = ast_say_digit_str(chan,i->cid,ecodes,chan->language);
++      if ( res == '#') {
++          ast_log(LOG_NOTICE,"res = %d\n",res);
++          // user pressed #, hangup
++              // first the holded user
++//            ast_exec("capiRETRIEVE",chan);
++
++              DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++              DISCONNECT_REQ_PLCI(&CMSG) = i->onholdPLCI;
++
++              if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++                  ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",i->onholdPLCI);
++              } else {
++                  ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n",i->onholdPLCI);
++              }
++              
++              // then the destination
++
++              DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++              DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
++
++              if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++                  ast_log(LOG_NOTICE, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++              } else {
++                  ast_log(LOG_NOTICE, "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++              }
++
++              // wait for the B3 layer to go down
++              while (i->state != CAPI_STATE_CONNECTED) {
++                  usleep(10000);
++              }
++
++              DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++              DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
++
++              if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++                  ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++              } else {
++                  ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++              }
++              
++              
++              LOCAL_USER_REMOVE(u);
++              return -1;
++
++      } else {
++          // now drop the bchannel
++          DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++          DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
++
++          if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++              ast_log(LOG_NOTICE, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++          } else {
++              ast_log(LOG_NOTICE, "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++          }
++
++          // wait for the B3 layer to go down
++          while (i->state != CAPI_STATE_CONNECTED) {
++              usleep(10000);
++          } 
++      }
++    }
++
++    // the caller onhold hungup or died away, drop the answered call
++    if (i->onholdPLCI == 0) {
++      DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
++
++      if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++      } else {
++          ast_log(LOG_NOTICE, "sent DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++      }
++      return -1;
++    }
++
++    ast_log(LOG_NOTICE,"onholdPLCI = %d\n",i->onholdPLCI);
++
++
++    fac[0] = 7;       // len
++    fac[1] = 0x06; // ECT (function)
++    fac[2] = 0x00;
++    fac[3] = 4; //len //sservice specific parameter , cstruct
++    fac[4] = (i->onholdPLCI << 8 ) >> 8;
++    fac[5] = i->onholdPLCI >> 8;
++    fac[6] = 0;
++    fac[7] = 0;
++
++    FACILITY_REQ_HEADER(&CMSG,ast_capi_ApplID,ast_capi_MessageNumber++,0);
++    FACILITY_REQ_CONTROLLER(&CMSG) = i->controller;
++    FACILITY_REQ_PLCI(&CMSG) = i->onholdPLCI;
++    FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; // sservices
++    FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (unsigned char *)&fac;
++
++    if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++      ast_log(LOG_ERROR,"Error sending FACILITY_REQ\n");
++      return Info;
++    } else {
++      ast_log(LOG_NOTICE,"sent FACILITY_REQ PLCI = %#x (%#x %#x) onholdPLCI = %#x\n ",i->PLCI,fac[4],fac[5],i->onholdPLCI);
++      ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG));
++    }
++
++//    i->outgoing = -1; // incoming + outgoing, this is a magic channel :)
++
++    LOCAL_USER_REMOVE(u);
++    return res;
++}
++
++int unload_module(void)
++{
++      STANDARD_HANGUP_LOCALUSERS;
++      return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++      return ast_register_application(app, capiECT_exec,synopsis,tdesc);
++}
++
++char *description(void)
++{
++      return tdesc;
++}
++
++int usecount(void)
++{
++      int res;
++      STANDARD_USECOUNT(res);
++      return res;
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_capiNoES.c asterisk-1.2.4/apps/app_capiNoES.c
+--- asterisk-1.2.4.orig/apps/app_capiNoES.c    1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_capiNoES.c 2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,96 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Disable echo suppression (useful for fax and voicemail!)
++ *
++ * Copyright (C) 2004,2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and 
++ * distributed under the terms of the GNU Public License.
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <linux/capi.h>
++#include <capi20.h>
++
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/chan_capi_app.h>
++
++
++
++#ifdef CAPI_ES
++static char *tdesc = "(CAPI*) No Echo Suppression.";
++static char *app = "capiNoES";
++static char *synopsis = "Disable Echo Suppression";
++#else
++static char *tdesc = "(CAPI*) No Echo Suppression at all!";
++static char *app = "capiNoES";
++static char *synopsis = "Bogus Application";
++#endif
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int capiNoES_exec(struct ast_channel *chan, void *data)
++{
++    int res=0;
++    struct localuser *u;
++    LOCAL_USER_ADD(u);
++
++#ifdef CAPI_ES
++    if (strcasecmp("CAPI",chan->type) == 0) {
++#ifdef CVS_HEAD
++      struct ast_capi_pvt *i = chan->tech_pvt;
++#else
++      struct ast_capi_pvt *i = chan->pvt->pvt;
++#endif
++      if (i->doES == 1) {
++          i->doES = 0;
++      }
++    } else {
++      ast_log(LOG_WARNING, "capiNoES only works on CAPI channels, check your extensions.conf!\n");
++    }
++#endif
++
++    LOCAL_USER_REMOVE(u);
++    return res;
++}
++
++int unload_module(void)
++{
++      STANDARD_HANGUP_LOCALUSERS;
++      return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++      return ast_register_application(app, capiNoES_exec,synopsis,tdesc);
++}
++
++char *description(void)
++{
++      return tdesc;
++}
++
++int usecount(void)
++{
++      int res;
++      STANDARD_USECOUNT(res);
++      return res;
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_chanisavail.c asterisk-1.2.4/apps/app_chanisavail.c
+--- asterisk-1.2.4.orig/apps/app_chanisavail.c 2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/apps/app_chanisavail.c      2006-01-31 09:41:43.000000000 +0100
+@@ -118,7 +118,7 @@
+                               snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
+                               status = inuse = ast_device_state(trychan);
+                       }
+-                      if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
++                      if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status, NULL))) {
+                                       pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
+                                       /* Store the originally used channel too */
+                                       snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
+diff -urN asterisk-1.2.4.orig/apps/app_devstate.c asterisk-1.2.4/apps/app_devstate.c
+--- asterisk-1.2.4.orig/apps/app_devstate.c    1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_devstate.c 2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,219 @@
++/*
++ * Devstate application
++ * 
++ * Since we like the snom leds so much, a little app to
++ * light the lights on the snom on demand ....
++ *
++ * Copyright (C) 2005, Druid Software
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/astdb.h>
++#include <asterisk/utils.h>
++#include <asterisk/cli.h>
++#include <asterisk/manager.h>
++#include <asterisk/devicestate.h>
++
++
++static char type[] = "DS";
++static char tdesc[] = "Application for sending device state messages";
++
++static char app[] = "Devstate";
++
++static char synopsis[] = "Generate a device state change event given the input parameters";
++
++static char descrip[] = " Devstate(device|state):  Generate a device state change event given the input parameters. Returns 0. State values match the asterisk device states. They are 0 = unknown, 1 = not inuse, 2 = inuse, 3 = busy, 4 = invalid, 5 = unavailable, 6 = ringing\n";
++
++static char devstate_cli_usage[] = 
++"Usage: devstate device state\n" 
++"       Generate a device state change event given the input parameters.\n Mainly used for lighting the LEDs on the snoms.\n";
++
++static int devstate_cli(int fd, int argc, char *argv[]);
++static struct ast_cli_entry  cli_dev_state =
++        { { "devstate", NULL }, devstate_cli, "Set the device state on one of the \"pseudo devices\".", devstate_cli_usage };
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++
++static int devstate_cli(int fd, int argc, char *argv[])
++{
++    char devName[128];
++    if ((argc != 3) && (argc != 4))
++        return RESULT_SHOWUSAGE;
++
++    if (ast_db_put("DEVSTATES", argv[1], argv[2]))
++    {
++        ast_log(LOG_DEBUG, "ast_db_put failed\n");
++    }
++    snprintf(devName, sizeof(devName), "DS/%s", argv[1]);
++    if (argc == 4) {
++        ast_log(LOG_NOTICE, "devname %s cid %s\n", devName, argv[3]);
++      ast_device_state_changed_literal(devName, argv[3], NULL);
++    } else {
++      ast_device_state_changed_literal(devName, NULL, NULL);
++    }
++    return RESULT_SUCCESS;
++}
++
++static int devstate_exec(struct ast_channel *chan, void *data)
++{
++    struct localuser *u;
++    char *device, *state, *info;
++    char devName[128];
++    if (!(info = ast_strdupa(data))) {
++            ast_log(LOG_WARNING, "Unable to dupe data :(\n");
++            return -1;
++    }
++    LOCAL_USER_ADD(u);
++    
++    device = info;
++    state = strchr(info, '|');
++    if (state) {
++        *state = '\0';
++        state++;
++    }
++    else
++    {
++        ast_log(LOG_DEBUG, "No state argument supplied\n");
++        return -1;
++    }
++
++    if (ast_db_put("DEVSTATES", device, state))
++    {
++        ast_log(LOG_DEBUG, "ast_db_put failed\n");
++    }
++
++    snprintf(devName, sizeof(devName), "DS/%s", device);
++    ast_device_state_changed_literal(devName, NULL, NULL);
++
++    LOCAL_USER_REMOVE(u);
++    return 0;
++}
++
++
++static int ds_devicestate(void *data)
++{
++    char *dest = data;
++    char stateStr[16];
++    if (ast_db_get("DEVSTATES", dest, stateStr, sizeof(stateStr)))
++    {
++        ast_log(LOG_DEBUG, "ds_devicestate couldnt get state in astdb\n");
++        return 0;
++    }
++    else
++    {
++        ast_log(LOG_DEBUG, "ds_devicestate dev=%s returning state %d\n",
++               dest, atoi(stateStr));
++        return (atoi(stateStr));
++    }
++}
++
++static struct ast_channel_tech devstate_tech = {
++      .type = type,
++      .description = tdesc,
++      .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
++      .devicestate = ds_devicestate,
++      .requester = NULL,
++      .send_digit = NULL,
++      .send_text = NULL,
++      .call = NULL,
++      .hangup = NULL,
++      .answer = NULL,
++      .read = NULL,
++      .write = NULL,
++      .bridge = NULL,
++      .exception = NULL,
++      .indicate = NULL,
++      .fixup = NULL,
++      .setoption = NULL,
++};
++
++static char mandescr_devstate[] = 
++"Description: Put a value into astdb\n"
++"Variables: \n"
++"     Family: ...\n"
++"     Key: ...\n"
++"     Value: ...\n";
++
++static int action_devstate(struct mansession *s, struct message *m)
++{
++        char *devstate = astman_get_header(m, "Devstate");
++        char *value = astman_get_header(m, "Value");
++      char *id = astman_get_header(m,"ActionID");
++      char devName[128];
++
++      if (!strlen(devstate)) {
++              astman_send_error(s, m, "No Devstate specified");
++              return 0;
++      }
++      if (!strlen(value)) {
++              astman_send_error(s, m, "No Value specified");
++              return 0;
++      }
++
++        if (!ast_db_put("DEVSTATES", devstate, value)) {
++          snprintf(devName, sizeof(devName), "DS/%s", devstate);
++          ast_device_state_changed(devName);
++          ast_cli(s->fd, "Response: Success\r\n");
++      } else {
++          ast_log(LOG_DEBUG, "ast_db_put failed\n");
++          ast_cli(s->fd, "Response: Failed\r\n");
++      }
++      if (id && !ast_strlen_zero(id))
++              ast_cli(s->fd, "ActionID: %s\r\n",id);
++      ast_cli(s->fd, "\r\n");
++      return 0;
++}
++
++int load_module(void)
++{
++    if (ast_channel_register(&devstate_tech)) {
++        ast_log(LOG_DEBUG, "Unable to register channel class %s\n", type);
++        return -1;
++    }
++    ast_cli_register(&cli_dev_state);  
++    ast_manager_register2( "Devstate", EVENT_FLAG_CALL, action_devstate, "Change a device state", mandescr_devstate );
++    return ast_register_application(app, devstate_exec, synopsis, descrip);
++}
++
++int unload_module(void)
++{
++    int res = 0;
++    STANDARD_HANGUP_LOCALUSERS;
++    ast_manager_unregister( "Devstate");
++    ast_cli_unregister(&cli_dev_state);
++    res = ast_unregister_application(app);
++    ast_channel_unregister(&devstate_tech);    
++    return res;
++}
++
++char *description(void)
++{
++    return tdesc;
++}
++
++int usecount(void)
++{
++    int res;
++    STANDARD_USECOUNT(res);
++    return res;
++}
++
++char *key()
++{
++    return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_dial.c asterisk-1.2.4/apps/app_dial.c
+--- asterisk-1.2.4.orig/apps/app_dial.c        2006-01-25 02:50:52.000000000 +0100
++++ asterisk-1.2.4/apps/app_dial.c     2006-01-31 09:41:43.000000000 +0100
+@@ -11,6 +11,10 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
+  * 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.
+@@ -113,7 +117,8 @@
+ "           context may be specified. Otherwise, the current extension is used.\n"
+ "    h    - Allow the called party to hang up by sending the '*' DTMF digit.\n"
+ "    H    - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
+-"    j    - Jump to priority n+101 if all of the requested channels were busy.\n"
++"    j    - Jump to priority n+101 if the called party was busy.\n"
++"           Jump to priority n+201 if all of the requested channels were busy.\n"
+ "    L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
+ "           left. Repeat the warning every 'z' ms. The following special\n"
+ "           variables can be used with this option:\n"
+@@ -158,8 +163,11 @@
+ "           family/key is not specified.\n"
+ "    r    - Indicate ringing to the calling party. Pass no audio to the calling\n"
+ "           party until the called channel has answered.\n"
++"    R          - indicate ringing to the calling party when the called party indicates\n"
++"            ringing, pass no audio until answered.\n"
+ "    S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
+-"           answered the call.\n"     
++"           answered the call.\n"
++"    c    - callback initiation, ring once and hangup.\n"
+ "    t    - Allow the called party to transfer the calling party by sending the\n"
+ "           DTMF sequence defined in features.conf.\n"
+ "    T    - Allow the calling party to transfer the called party by sending the\n"
+@@ -210,6 +218,8 @@
+       OPT_CALLEE_MONITOR = (1 << 21),
+       OPT_CALLER_MONITOR = (1 << 22),
+       OPT_GOTO = (1 << 23),
++      OPT_NOINBAND = (1 << 24),
++      OPT_CALLBACK_INIT = (1 << 25),
+ } dial_exec_option_flags;
+ #define DIAL_STILLGOING                       (1 << 30)
+@@ -248,6 +258,8 @@
+       AST_APP_OPTION('p', OPT_SCREENING),
+       AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+       AST_APP_OPTION('r', OPT_RINGBACK),
++      AST_APP_OPTION('R', OPT_NOINBAND),
++      AST_APP_OPTION('c', OPT_CALLBACK_INIT),
+       AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+       AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+       AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+@@ -383,7 +395,7 @@
+       char *context = NULL;
+       char cidname[AST_MAX_EXTENSION];
+-      single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK));
++      single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK | OPT_NOINBAND));
+       
+       if (single) {
+               /* Turn off hold music, etc */
+@@ -462,7 +474,7 @@
+                                               if (option_verbose > 2)
+                                                       ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
+                                               /* Setup parameters */
+-                                              o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
++                                              o->chan = ast_request(tech, in->nativeformats, stuff, &cause, NULL);
+                                               if (!o->chan)
+                                                       ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+                                       } else {
+@@ -916,17 +928,24 @@
+               }
+               
+               if( privdb_val == AST_PRIVACY_DENY ) {
++                      ast_copy_string(status, "NOANSWER", sizeof(status));
+                       ast_verbose( VERBOSE_PREFIX_3  "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
+                       res=0;
+                       goto out;
+               }
+               else if( privdb_val == AST_PRIVACY_KILL ) {
+-                      ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
++                      ast_copy_string(status, "DONTCALL", sizeof(status));
++                      if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
++                              ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
++                      }
+                       res = 0;
+                       goto out; /* Is this right? */
+               }
+               else if( privdb_val == AST_PRIVACY_TORTURE ) {
+-                      ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
++                      ast_copy_string(status, "TORTURE", sizeof(status));
++                      if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
++                              ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
++                      }
+                       res = 0;
+                       goto out; /* is this right??? */
+@@ -1005,7 +1024,7 @@
+                               ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
+               }
+               /* Request the peer */
+-              tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
++              tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause, NULL);
+               if (!tmp->chan) {
+                       /* If we can't, just go on to the next call */
+                       ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
+@@ -1036,7 +1055,7 @@
+                                       ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
+                               ast_hangup(tmp->chan);
+                               /* Setup parameters */
+-                              tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
++                              tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause, NULL);
+                               if (!tmp->chan)
+                                       ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+                       } else {
+@@ -1155,8 +1174,11 @@
+                       ast_indicate(chan, AST_CONTROL_RINGING);
+                       sentringing++;
+               }
+-      } else
++      } else {
+               strcpy(status, "CHANUNAVAIL");
++              /* See if there is a special message */
++              ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
++      }
+       time(&start_time);
+       peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result);
+@@ -1285,6 +1307,8 @@
+                                                                    opt_args[OPT_ARG_PRIVACY], privcid);
+                                               ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_DENY);
+                                       }
++                                      ast_copy_string(status, "NOANSWER", sizeof(status));
++
+                                       if (ast_test_flag(&opts, OPT_MUSICBACK)) {
+                                               ast_moh_stop(chan);
+                                       } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
+diff -urN asterisk-1.2.4.orig/apps/app_directed_pickup.c asterisk-1.2.4/apps/app_directed_pickup.c
+--- asterisk-1.2.4.orig/apps/app_directed_pickup.c     2005-12-20 18:34:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_directed_pickup.c  2006-01-31 09:41:43.000000000 +0100
+@@ -41,7 +41,7 @@
+ #include "asterisk/app.h"
+ static const char *tdesc = "Directed Call Pickup Application";
+-static const char *app = "Pickup";
++static const char *app = "DPickup";
+ static const char *synopsis = "Directed Call Pickup";
+ static const char *descrip =
+ "  Pickup(extension[@context]): This application can pickup any ringing channel\n"
+diff -urN asterisk-1.2.4.orig/apps/app_meetme.c asterisk-1.2.4/apps/app_meetme.c
+--- asterisk-1.2.4.orig/apps/app_meetme.c      2006-01-18 22:02:06.000000000 +0100
++++ asterisk-1.2.4/apps/app_meetme.c   2006-01-31 09:41:43.000000000 +0100
+@@ -454,7 +454,7 @@
+                       ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
+                       ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
+                       cnf->markedusers = 0;
+-                      cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL);
++                      cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL, NULL);
+                       if (cnf->chan) {
+                               cnf->fd = cnf->chan->fds[0];    /* for use by conf_play() */
+                       } else {
+@@ -822,8 +822,9 @@
+       char exitcontext[AST_MAX_CONTEXT] = "";
+       char recordingtmp[AST_MAX_EXTENSION] = "";
+       int dtmf;
++      int dyna_buff = CONF_SIZE;
+       ZT_BUFFERINFO bi;
+-      char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
++      char __buf[ZT_MAX_BUF_SPACE / ZT_DEFAULT_NUM_BUFS + AST_FRIENDLY_OFFSET];
+       char *buf = __buf + AST_FRIENDLY_OFFSET;
+       
+       if (!user) {
+@@ -986,7 +987,7 @@
+               }
+               /* Setup buffering information */
+               memset(&bi, 0, sizeof(bi));
+-              bi.bufsize = CONF_SIZE/2;
++              bi.bufsize = dyna_buff / 2;
+               bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+               bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+               bi.numbufs = audio_buffers;
+@@ -1271,6 +1272,14 @@
+                               f = ast_read(c);
+                               if (!f)
+                                       break;
++                              if (f->datalen && f->datalen != dyna_buff) {
++                                      ast_log(LOG_NOTICE, "Audio bytes: %d  Buffer size: %d\n", f->datalen, dyna_buff);
++                                      if (f->datalen < ZT_MAX_BUF_SPACE/audio_buffers) { /* skip too large frame to avoid overflow */
++                                              dyna_buff = f->datalen;
++                                              close(fd);
++                                              goto zapretry;
++                                      }
++                              }
+                               if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
+                                       if (user->talk.actual)
+                                               ast_frame_adjust_volume(f, user->talk.actual);
+@@ -1500,7 +1509,7 @@
+                               }
+                               ast_frfree(f);
+                       } else if (outfd > -1) {
+-                              res = read(outfd, buf, CONF_SIZE);
++                              res = read(outfd, buf, dyna_buff);
+                               if (res > 0) {
+                                       memset(&fr, 0, sizeof(fr));
+                                       fr.frametype = AST_FRAME_VOICE;
+diff -urN asterisk-1.2.4.orig/apps/app_milliwatt.c asterisk-1.2.4/apps/app_milliwatt.c
+--- asterisk-1.2.4.orig/apps/app_milliwatt.c   2006-01-19 05:17:45.000000000 +0100
++++ asterisk-1.2.4/apps/app_milliwatt.c        2006-01-31 09:41:43.000000000 +0100
+@@ -74,20 +74,28 @@
+ {
+       struct ast_frame wf;
+       unsigned char buf[AST_FRIENDLY_OFFSET + 640];
++      const int maxsamples = (sizeof (buf) - AST_FRIENDLY_OFFSET) / sizeof (buf[0]);
+       int i,*indexp = (int *) data;
+-      if (len + AST_FRIENDLY_OFFSET > sizeof(buf))
+-      {
+-              ast_log(LOG_WARNING,"Only doing %d bytes (%d bytes requested)\n",(int)(sizeof(buf) - AST_FRIENDLY_OFFSET),len);
+-              len = sizeof(buf) - AST_FRIENDLY_OFFSET;
+-      }
++      /* Instead of len, use samples, because channel.c generator_force 
++       * generate(chan, tmp, 0, 160) ignores len. In any case, len is  
++       * a multiple of samples, given by number of samples times bytes per
++       * sample. In the case of ulaw, len = samples. for signed linear 
++       * len = 2 * samples                                                 */
++ 
++      if (samples > maxsamples)
++      {
++              ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", maxsamples, samples);
++              samples = maxsamples;
++      }
++      len = samples * sizeof (buf[0]);
+       wf.frametype = AST_FRAME_VOICE;
+       wf.subclass = AST_FORMAT_ULAW;
+       wf.offset = AST_FRIENDLY_OFFSET;
+       wf.mallocd = 0;
+       wf.data = buf + AST_FRIENDLY_OFFSET;
+       wf.datalen = len;
+-      wf.samples = wf.datalen;
++      wf.samples = samples;
+       wf.src = "app_milliwatt";
+       wf.delivery.tv_sec = 0;
+       wf.delivery.tv_usec = 0;
+diff -urN asterisk-1.2.4.orig/apps/app_page.c asterisk-1.2.4/apps/app_page.c
+--- asterisk-1.2.4.orig/apps/app_page.c        2005-12-02 01:51:15.000000000 +0100
++++ asterisk-1.2.4/apps/app_page.c     2006-01-31 09:41:43.000000000 +0100
+@@ -85,7 +85,7 @@
+ {
+       struct calloutdata *cd = data;
+       ast_pbx_outgoing_app(cd->tech, AST_FORMAT_SLINEAR, cd->resource, 30000,
+-              "MeetMe", cd->meetmeopts, NULL, 0, cd->cidnum, cd->cidname, cd->variables, NULL);
++              "MeetMe", cd->meetmeopts, NULL, 0, 0, cd->cidnum, cd->cidname, cd->variables, NULL, NULL);
+       free(cd);
+       return NULL;
+ }
+diff -urN asterisk-1.2.4.orig/apps/app_parkandannounce.c asterisk-1.2.4/apps/app_parkandannounce.c
+--- asterisk-1.2.4.orig/apps/app_parkandannounce.c     2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/apps/app_parkandannounce.c  2006-01-31 09:41:43.000000000 +0100
+@@ -183,7 +183,7 @@
+       memset(&oh, 0, sizeof(oh));
+       oh.parent_channel = chan;
+-      dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
++      dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, 0, chan->cid.cid_num, chan->cid.cid_name, &oh, NULL);
+       if(dchan) {
+               if(dchan->_state == AST_STATE_UP) {
+diff -urN asterisk-1.2.4.orig/apps/app_pickup.c asterisk-1.2.4/apps/app_pickup.c
+--- asterisk-1.2.4.orig/apps/app_pickup.c      1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_pickup.c   2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,319 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Pickup, channel independent call pickup
++ * 
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * Copyright (C) 2004, Florian Overkamp <florian@obsimref.com>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <signal.h>
++#include <pthread.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++#include <asterisk/features.h>
++#include <asterisk/options.h>
++
++
++static char *tdesc = "PickUp/PickDown/Steal/PickupChan/StealChan";
++
++static char *app = "PickUp";
++
++static char *synopsis = "Channel independent call pickup.";
++
++static char *descrip = 
++"  PickDown([group]):  Tries to pickup the first ringing channel with callgroup == group.\n"
++"                    If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app2 = "Steal";
++
++static char *synopsis2 = "Channel independent call stealing. Just like pickup but for answered channels.";
++
++static char *descrip2 = 
++"  Steal([group]):  Tries to steal the first bridged channel with callgroup == group.\n"
++"                    If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app3 = "PickDown";
++
++static char *synopsis3 = "Channel independent call pickdown.";
++
++static char *descrip3 = 
++"  PickDown([group]):  Tries to hangup the first ringing channel with callgroup == group.\n"
++"                    If called without the group argument, the pickupgroup of the channel will be used.\n";
++
++static char *app4 = "PickupChan";
++
++static char *synopsis4 = "Channel independent call pickup.";
++
++static char *descrip4 = 
++"  PickupChan(Technology/resource[&Technology2/resource2...]):  Tries to pickup the first ringing channel in the parameter list.\n";
++
++static char *app5 = "StealChan";
++
++static char *synopsis5 = "Channel independent call stealing. Just like pickup but for answered channels.";
++
++static char *descrip5 = 
++"  StealChan(Technology/resource[&Technology2/resource2...]):  Tries to steal the first ringing channel in the parameter list.\n";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int my_pickup_call(struct ast_channel *chan, unsigned int pickupgroup, int chanstate, int bridge) {
++      struct ast_channel *cur;
++      int res = -1;
++      cur = ast_channel_walk_locked(NULL);
++      while(cur) {
++              if ((cur != chan) &&
++                      (pickupgroup & cur->callgroup) &&
++                       (cur->_state == chanstate)) {
++                              break;
++              }
++              ast_mutex_unlock(&cur->lock);
++              cur = ast_channel_walk_locked(cur);
++      }
++      if (cur) {
++              if(option_verbose > 2) {
++                  if (chanstate == AST_STATE_RINGING) {
++                      if (bridge == 1) {
++                          ast_verbose(VERBOSE_PREFIX_3 "Channel %s picked up ringing channel %s\n",chan->name,cur->name);
++                      } else {
++                          ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n",chan->name,cur->name);
++                      }
++                  } else {
++                      ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n",chan->name,cur->name);
++                  }
++              }
++              if (bridge == 1) {
++                  if (chan->_state != AST_STATE_UP) {
++                      ast_answer(chan);
++                  }
++                  if (ast_channel_masquerade(cur, chan)) {
++                      ast_log(LOG_ERROR, "unable to masquerade\n");
++                  }
++                  ast_mutex_unlock(&cur->lock);
++                  ast_mutex_unlock(&chan->lock);
++              } else {
++                  cur->_softhangup = AST_SOFTHANGUP_DEV;
++                  ast_mutex_unlock(&cur->lock);
++              }
++      } else  {
++              if(option_verbose > 2) {
++                  ast_verbose(VERBOSE_PREFIX_3 "No channel found %d.\n",pickupgroup);
++              }
++      } 
++      return res;
++}
++
++static int my_pickup_channel(struct ast_channel *chan, void *data, int chanstate, int bridge) {
++       struct ast_channel *cur;
++       char channels[256];
++       char evalchan[256];
++       char *endptr;
++       int res = -1;
++       cur = ast_channel_walk_locked(NULL);
++       strncpy(channels, (char *)data, sizeof(channels) - 1);
++       while(cur) {
++               if ((cur != chan) &&
++                        (cur->_state == chanstate)) {
++                               /* This call is a candidate (correct ringstate and not ourselves), now check if the channel is in our list */
++                               strncpy(evalchan, (char *)cur->name, sizeof(evalchan) - 1);                             
++                               /* strip the subchannel tag */
++                               endptr = strrchr(evalchan, '-');
++                               if(endptr) {
++                                       *endptr = '\0';
++                               }
++                               endptr = strrchr(evalchan, '/');
++                               if(endptr) {
++                                       *endptr = '\0';
++                               }
++                               /* check for each of the members if they match (probably a stristr will do ?) */
++                               /* if we match the code, break */
++                               if(strstr(channels, evalchan) != NULL) {
++                                       ast_verbose(VERBOSE_PREFIX_1 "Nice channel, I'll take it: %s\n",evalchan);
++                                       break;
++                               }
++               }
++               ast_mutex_unlock(&cur->lock);
++               cur = ast_channel_walk_locked(cur);
++       }
++       if (cur) {
++               if(option_verbose > 2) {
++                   if (chanstate == AST_STATE_RINGING) {
++                       if (bridge == 1) {
++                           ast_verbose(VERBOSE_PREFIX_3 "Channel %s picked up ringing channel %s\n",chan->name,cur->name);
++                       } else {
++                           ast_verbose(VERBOSE_PREFIX_3 "Channel %s hung up ringing channel %s\n",chan->name,cur->name);
++                       }
++                   } else {
++                       ast_verbose(VERBOSE_PREFIX_3 "Channel %s stole channel %s\n",chan->name,cur->name);
++                   }
++               }
++               if (bridge == 1) {
++                 if (chan->_state != AST_STATE_UP) {
++                     ast_answer(chan);
++                 }
++                   if (ast_channel_masquerade(cur, chan)) {
++                       ast_log(LOG_ERROR, "unable to masquerade\n");
++                   }
++                   ast_mutex_unlock(&cur->lock);
++                   ast_mutex_unlock(&chan->lock);
++               } else {
++                   cur->_softhangup = AST_SOFTHANGUP_DEV;
++                   ast_mutex_unlock(&cur->lock);
++               }
++       } else  {
++               if(option_verbose > 2) {
++                   ast_verbose(VERBOSE_PREFIX_3 "No channel found %s.\n",channels);
++               }
++       } 
++       return res;
++}
++
++
++static int pickup_exec(struct ast_channel *chan, void *data)
++{
++      int res=0;
++      unsigned int pickupgroup=0;
++      struct localuser *u;
++      if (!data || !strlen(data)) {
++          pickupgroup = chan->pickupgroup;
++      } else {
++          pickupgroup = ast_get_group(data);
++      }
++      LOCAL_USER_ADD(u);
++      if (!res) {
++              res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 1);
++      }
++      if (res > 0)
++              res = 0;
++      LOCAL_USER_REMOVE(u);
++      return res;
++}
++
++static int steal_exec(struct ast_channel *chan, void *data)
++{
++      int res=0;
++      unsigned int pickupgroup=0;
++      struct localuser *u;
++      if (!data || !strlen(data)) {
++          pickupgroup = chan->pickupgroup;
++      } else {
++          pickupgroup = ast_get_group(data);
++      }
++      LOCAL_USER_ADD(u);
++      if (!res) {
++              res = my_pickup_call(chan, pickupgroup, AST_STATE_UP, 1);
++      }
++      if (res > 0)
++              res = 0;
++      LOCAL_USER_REMOVE(u);
++      return res;
++}
++
++static int pickdown_exec(struct ast_channel *chan, void *data)
++{
++      int res=0;
++      unsigned int pickupgroup=0;
++      struct localuser *u;
++      if (!data || !strlen(data)) {
++          pickupgroup = chan->pickupgroup;
++      } else {
++          pickupgroup = ast_get_group(data);
++      }
++      LOCAL_USER_ADD(u);
++      if (!res) {
++              res = my_pickup_call(chan, pickupgroup, AST_STATE_RINGING, 0);
++      }
++      if (res > 0)
++              res = 0;
++      LOCAL_USER_REMOVE(u);
++      return res;
++}
++
++static int pickupchan_exec(struct ast_channel *chan, void *data) {
++       int res=0;
++       struct localuser *u;
++        if (!data) {
++                ast_log(LOG_WARNING, "PickupChan requires an argument (technology1/number1&technology2/number2...)\n");
++                return -1;
++        }
++       LOCAL_USER_ADD(u);
++       if (!res) {
++               res = my_pickup_channel(chan, data, AST_STATE_RINGING, 1);
++       }
++       if (res > 0)
++               res = 0;
++       LOCAL_USER_REMOVE(u);
++       return res;
++}
++
++static int stealchan_exec(struct ast_channel *chan, void *data)
++{
++      int res=0;
++      struct localuser *u;
++        if (!data) {
++                ast_log(LOG_WARNING, "StealChan requires an argument (technology1/number1&technology2/number2...)\n");
++                return -1;
++        }
++
++      LOCAL_USER_ADD(u);
++      if (!res) {
++              res = my_pickup_channel(chan, data, AST_STATE_UP, 1);
++      }
++      if (res > 0)
++              res = 0;
++      LOCAL_USER_REMOVE(u);
++      return res;
++}
++
++
++int unload_module(void)
++{
++      STANDARD_HANGUP_LOCALUSERS;
++      ast_unregister_application(app5);
++      ast_unregister_application(app4);
++      ast_unregister_application(app3);
++      ast_unregister_application(app2);
++      return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++      ast_register_application(app5, stealchan_exec, synopsis5, descrip5);
++      ast_register_application(app4, pickupchan_exec, synopsis4, descrip4);
++      ast_register_application(app3, pickdown_exec, synopsis3, descrip3);
++      ast_register_application(app2, steal_exec, synopsis2, descrip2);
++      return ast_register_application(app, pickup_exec, synopsis, descrip);
++}
++
++char *description(void)
++{
++      return tdesc;
++}
++
++int usecount(void)
++{
++      int res;
++      STANDARD_USECOUNT(res);
++      return res;
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_queue.c asterisk-1.2.4/apps/app_queue.c
+--- asterisk-1.2.4.orig/apps/app_queue.c       2006-01-22 20:03:53.000000000 +0100
++++ asterisk-1.2.4/apps/app_queue.c    2006-01-31 09:41:43.000000000 +0100
+@@ -501,7 +501,7 @@
+       return NULL;
+ }
+-static int statechange_queue(const char *dev, int state, void *ign)
++static int statechange_queue(const char *dev, int state, void *ign, char *cid_num, char *cid_name)
+ {
+       /* Avoid potential for deadlocks by spawning a new thread to handle
+          the event */
+@@ -1386,7 +1386,7 @@
+               location = "";
+       /* Request the peer */
+-      tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
++      tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status, NULL);
+       if (!tmp->chan) {                       /* If we can't, just go on to the next call */
+ #if 0
+               ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
+@@ -1692,7 +1692,7 @@
+                                       if (option_verbose > 2)
+                                               ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
+                                       /* Setup parameters */
+-                                      o->chan = ast_request(tech, in->nativeformats, stuff, &status);
++                                      o->chan = ast_request(tech, in->nativeformats, stuff, &status, NULL);
+                                       if (status != o->oldstatus) 
+                                               update_dial_status(qe->parent, o->member, status);                                              
+                                       if (!o->chan) {
+diff -urN asterisk-1.2.4.orig/apps/app_readfile.c asterisk-1.2.4/apps/app_readfile.c
+--- asterisk-1.2.4.orig/apps/app_readfile.c    2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/apps/app_readfile.c 2006-01-31 09:41:43.000000000 +0100
+@@ -40,7 +40,7 @@
+ #include "asterisk/app.h"
+ #include "asterisk/module.h"
+-static char *tdesc = "Stores output of file into a variable";
++static char *tdesc = "Stores content of file into a variable";
+ static char *app_readfile = "ReadFile";
+diff -urN asterisk-1.2.4.orig/apps/app_segfault.c asterisk-1.2.4/apps/app_segfault.c
+--- asterisk-1.2.4.orig/apps/app_segfault.c    1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/apps/app_segfault.c 2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,75 @@
++/*
++ * Segfault application
++ * 
++ * An application to provoke a segmentation fault from the dialplan.
++ * (I know what you are thinking now...., but since Asterisk is too stable...
++ *  I needed something to test my failover switches.)
++ *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License. THIS APPLICATION _WILL_ CRASH YOUR
++ * ASTERISK SERVER SO OF COURSE THERE IS NOT LIABILITY FOR NOTHING!
++ */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdio.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/module.h>
++
++static char *tdesc = "Application for crashing Asterisk with a segmentation fault";
++
++static char *app = "Segfault";
++
++static char *synopsis = "This application will crash Asterisk with a segmentation fault.";
++
++static char *descrip = 
++"  Segfault():  Crash with a segfault. Never returns nufin.\n";
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++static int segfault_exec(struct ast_channel *chan, void *data)
++{
++    struct localuser *u;
++    LOCAL_USER_ADD(u);
++    ((char *)0)[0] = 0;
++    LOCAL_USER_REMOVE(u);
++    return 0;
++}
++
++int unload_module(void)
++{
++    STANDARD_HANGUP_LOCALUSERS;
++    return ast_unregister_application(app);
++}
++
++int load_module(void)
++{
++    return ast_register_application(app, segfault_exec, synopsis, descrip);
++}
++
++char *description(void)
++{
++    return tdesc;
++}
++
++int usecount(void)
++{
++    int res;
++    STANDARD_USECOUNT(res);
++    return res;
++}
++
++char *key()
++{
++    return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/apps/app_sms.c asterisk-1.2.4/apps/app_sms.c
+--- asterisk-1.2.4.orig/apps/app_sms.c 2005-12-26 19:19:12.000000000 +0100
++++ asterisk-1.2.4/apps/app_sms.c      2006-01-31 09:41:43.000000000 +0100
+@@ -1179,32 +1179,31 @@
+ {
+       struct ast_frame f = { 0 };
+       unsigned char waste[AST_FRIENDLY_OFFSET];
++#define MAXSAMPLES (800)
+ #ifdef OUTALAW
+-      unsigned char buf[800];
++      unsigned char buf[MAXSAMPLES];
+ #else
+-      signed short buf[800];
++      signed short buf[MAXSAMPLES];
+ #endif
++#define SAMPLE2LEN (sizeof (buf[0]))
+       sms_t *h = data;
+       int i;
+-      if (len > sizeof (buf)) {
+-              ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
+-              len = sizeof (buf);
+-#ifdef OUTALAW
+-              samples = len;
+-#else
+-              samples = len / 2;
+-#endif
++      if (samples > MAXSAMPLES) {
++              ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
++                       MAXSAMPLES, samples);
++              samples = MAXSAMPLES;
+       }
+-      waste[0] = 0;                                    /* make compiler happy */
++      len = samples * SAMPLE2LEN;
++
++      waste[0] = 0;                            /* make compiler happy */
+       f.frametype = AST_FRAME_VOICE;
+ #ifdef OUTALAW
+       f.subclass = AST_FORMAT_ALAW;
+-      f.datalen = samples;
+ #else
+       f.subclass = AST_FORMAT_SLINEAR;
+-      f.datalen = samples * 2;
+ #endif
++      f.datalen = len;
+       f.offset = AST_FRIENDLY_OFFSET;
+       f.mallocd = 0;
+       f.data = buf;
+@@ -1256,6 +1255,8 @@
+               return -1;
+       }
+       return 0;
++#undef SAMPLE2LEN
++#undef MAXSAMPLES
+ }
+ static void sms_process (sms_t * h, int samples, signed short *data)
+diff -urN asterisk-1.2.4.orig/apps/app_zapras.c asterisk-1.2.4/apps/app_zapras.c
+--- asterisk-1.2.4.orig/apps/app_zapras.c      2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/apps/app_zapras.c   2006-01-31 09:41:43.000000000 +0100
+@@ -182,7 +182,7 @@
+                               }
+                       }
+                       /* Throw back into audio mode */
+-                      x = 1;
++                      x = 0;
+                       ioctl(chan->fds[0], ZT_AUDIOMODE, &x);
+                       /* Restore saved values */
+diff -urN asterisk-1.2.4.orig/asterisk.c asterisk-1.2.4/asterisk.c
+--- asterisk-1.2.4.orig/asterisk.c     2006-01-24 23:55:32.000000000 +0100
++++ asterisk-1.2.4/asterisk.c  2006-01-31 09:41:43.000000000 +0100
+@@ -221,6 +221,7 @@
+ char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
+ char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
+ char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
++char ast_config_AST_SYMBOLIC_NAME[20];
+ static char *_argv[256];
+ static int shuttingdown = 0;
+@@ -1878,6 +1879,7 @@
+       ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
+       ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
+       ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
++      ast_copy_string(ast_config_AST_SYMBOLIC_NAME, AST_SYMBOLIC_NAME, sizeof(ast_config_AST_SYMBOLIC_NAME));
+       /* no asterisk.conf? no problem, use buildtime config! */
+       if (!cfg) {
+@@ -1916,6 +1918,8 @@
+                       ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
+               } else if (!strcasecmp(v->name, "astmoddir")) {
+                       ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
++              } else if (!strcasecmp(v->name, "uniquename")) {
++                      strncpy(ast_config_AST_SYMBOLIC_NAME,v->value,sizeof(ast_config_AST_SYMBOLIC_NAME));
+               }
+               v = v->next;
+       }
+diff -urN asterisk-1.2.4.orig/build_tools/make_defaults_h asterisk-1.2.4/build_tools/make_defaults_h
+--- asterisk-1.2.4.orig/build_tools/make_defaults_h    2005-06-20 19:26:08.000000000 +0200
++++ asterisk-1.2.4/build_tools/make_defaults_h 2006-01-31 09:41:43.000000000 +0100
+@@ -16,6 +16,7 @@
+ #define AST_KEY_DIR    "${INSTALL_PATH}${ASTVARLIBDIR}/keys"
+ #define AST_DB         "${INSTALL_PATH}${ASTVARLIBDIR}/astdb"
+ #define AST_TMP_DIR    "${INSTALL_PATH}${ASTSPOOLDIR}/tmp"
++#define AST_SYMBOLIC_NAME     "asterisk"
+ #define AST_CONFIG_FILE "${INSTALL_PATH}${ASTCONFPATH}"
+diff -urN asterisk-1.2.4.orig/channel.c asterisk-1.2.4/channel.c
+--- asterisk-1.2.4.orig/channel.c      2006-01-25 10:46:43.000000000 +0100
++++ asterisk-1.2.4/channel.c   2006-01-31 09:41:43.000000000 +0100
+@@ -94,8 +94,8 @@
+  */
+ static int shutting_down = 0;
+-AST_MUTEX_DEFINE_STATIC(uniquelock);
+ static int uniqueint = 0;
++AST_MUTEX_DEFINE_EXPORTED(uniquelock);
+ unsigned long global_fin = 0, global_fout = 0;
+@@ -512,6 +512,17 @@
+       .description = "Null channel (should not see this)",
+ };
++char *ast_alloc_uniqueid(void) {
++      char *uniqueid;
++      uniqueid = malloc(64);
++      if (!uniqueid) return NULL;
++      ast_mutex_lock(&uniquelock);
++      snprintf(uniqueid, 63, "%s-%d-%li.%d", ast_config_AST_SYMBOLIC_NAME, ast_mainpid, (long)time(NULL), uniqueint++);
++      ast_mutex_unlock(&uniquelock);
++      return uniqueid;
++}
++
++
+ /*--- ast_channel_alloc: Create a new channel structure */
+ struct ast_channel *ast_channel_alloc(int needqueue)
+ {
+@@ -519,6 +530,7 @@
+       int x;
+       int flags;
+       struct varshead *headp;        
++      char *tmpuniqueid;
+               
+       /* If shutting down, don't allocate any new channels */
+@@ -584,9 +596,12 @@
+       tmp->data = NULL;
+       tmp->fin = global_fin;
+       tmp->fout = global_fout;
+-      ast_mutex_lock(&uniquelock);
+-      snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), "%li.%d", (long) time(NULL), uniqueint++);
+-      ast_mutex_unlock(&uniquelock);
++      tmpuniqueid = ast_alloc_uniqueid();
++      snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), tmpuniqueid);
++      if (tmpuniqueid) { 
++          free(tmpuniqueid);
++          tmpuniqueid = NULL;
++      }
+       headp = &tmp->varshead;
+       ast_mutex_init(&tmp->lock);
+       AST_LIST_HEAD_INIT_NOLOCK(headp);
+@@ -729,7 +744,7 @@
+  */
+ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
+                                              const char *name, const int namelen,
+-                                             const char *context, const char *exten)
++                                             const char *context, const char *exten, const char *uniqueid)
+ {
+       const char *msg = prev ? "deadlock" : "initial deadlock";
+       int retries, done;
+@@ -740,9 +755,14 @@
+               for (c = channels; c; c = c->next) {
+                       if (!prev) {
+                               /* want head of list */
+-                              if (!name && !exten)
++                              if (!name && !exten && !uniqueid)
+                                       break;
+-                              if (name) {
++                              if (uniqueid) {
++                                  if (!strcasecmp(c->uniqueid, uniqueid))
++                                      break;
++                                  else
++                                      continue;
++                              } else if (name) {
+                                       /* want match by full name */
+                                       if (!namelen) {
+                                               if (!strcasecmp(c->name, name))
+@@ -793,33 +813,39 @@
+ /*--- ast_channel_walk_locked: Browse channels in use */
+ struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev)
+ {
+-      return channel_find_locked(prev, NULL, 0, NULL, NULL);
++      return channel_find_locked(prev, NULL, 0, NULL, NULL, NULL);
+ }
+ /*--- ast_get_channel_by_name_locked: Get channel by name and lock it */
+ struct ast_channel *ast_get_channel_by_name_locked(const char *name)
+ {
+-      return channel_find_locked(NULL, name, 0, NULL, NULL);
++      return channel_find_locked(NULL, name, 0, NULL, NULL, NULL);
+ }
+ /*--- ast_get_channel_by_name_prefix_locked: Get channel by name prefix and lock it */
+ struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen)
+ {
+-      return channel_find_locked(NULL, name, namelen, NULL, NULL);
++      return channel_find_locked(NULL, name, namelen, NULL, NULL, NULL);
+ }
+ /*--- ast_walk_channel_by_name_prefix_locked: Get next channel by name prefix and lock it */
+ struct ast_channel *ast_walk_channel_by_name_prefix_locked(struct ast_channel *chan, const char *name, const int namelen)
+ {
+-      return channel_find_locked(chan, name, namelen, NULL, NULL);
++      return channel_find_locked(chan, name, namelen, NULL, NULL, NULL);
+ }
+ /*--- ast_get_channel_by_exten_locked: Get channel by exten (and optionally context) and lock it */
+ struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const char *context)
+ {
+-      return channel_find_locked(NULL, NULL, 0, context, exten);
++      return channel_find_locked(NULL, NULL, 0, context, exten, NULL);
+ }
++struct ast_channel *ast_get_channel_by_uniqueid_locked(const char *uniqueid)
++{
++      return channel_find_locked(NULL, NULL, 0, NULL, NULL, uniqueid);
++}
++
++
+ /*--- ast_safe_sleep_conditional: Wait, look for hangups and condition arg */
+ int ast_safe_sleep_conditional(       struct ast_channel *chan, int ms,
+       int (*cond)(void*), void *data )
+@@ -912,8 +938,10 @@
+               free(chan->tech_pvt);
+       }
+-      if (chan->sched)
+-              sched_context_destroy(chan->sched);
++      if (chan->sched) {
++              sched_context_destroy(chan->sched);     
++              chan->sched = NULL;
++      }
+       ast_copy_string(name, chan->name, sizeof(name));
+@@ -956,10 +984,11 @@
+       while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
+               ast_var_delete(vardata);
++
+       free(chan);
+       ast_mutex_unlock(&chlock);
+-      ast_device_state_changed_literal(name);
++      ast_device_state_changed_literal(name, NULL, NULL);
+ }
+ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy)
+@@ -2364,7 +2393,7 @@
+                         &chan->writetrans, 1);
+ }
+-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
++struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cid_num, const char *cid_name, struct outgoing_helper *oh, char* uniqueid)
+ {
+       int state = 0;
+       int cause = 0;
+@@ -2372,7 +2401,7 @@
+       struct ast_frame *f;
+       int res = 0;
+       
+-      chan = ast_request(type, format, data, &cause);
++      chan = ast_request(type, format, data, &cause, uniqueid);
+       if (chan) {
+               if (oh) {
+                       if (oh->vars)   
+@@ -2384,6 +2413,7 @@
+               }
+               ast_set_callerid(chan, cid_num, cid_name, cid_num);
++              chan->cid.cid_pres = callingpres;
+               if (!ast_call(chan, data, 0)) {
+                       while(timeout && (chan->_state != AST_STATE_UP)) {
+                               res = ast_waitfor(chan, timeout);
+@@ -2406,6 +2436,7 @@
+                                       if (f->subclass == AST_CONTROL_RINGING)
+                                               state = AST_CONTROL_RINGING;
+                                       else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
++                                              res = 0;
+                                               state = f->subclass;
+                                               ast_frfree(f);
+                                               break;
+@@ -2475,12 +2506,12 @@
+       return chan;
+ }
+-struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
++struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, int callingpres, const char *cidnum, const char *cidname, char *uniqueid)
+ {
+-      return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL);
++      return __ast_request_and_dial(type, format, data, timeout, outstate, 0, cidnum, cidname, NULL, uniqueid);
+ }
+-struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
++struct ast_channel *ast_request(const char *type, int format, void *data, int *cause, char *uniqueid)
+ {
+       struct chanlist *chan;
+       struct ast_channel *c;
+@@ -2517,6 +2548,7 @@
+               if (!(c = chan->tech->requester(type, capabilities, data, cause)))
+                       return NULL;
++              if (uniqueid) strncpy(c->uniqueid, uniqueid, sizeof(c->uniqueid));
+               if (c->_state == AST_STATE_DOWN) {
+                       manager_event(EVENT_FLAG_CALL, "Newchannel",
+                                     "Channel: %s\r\n"
+@@ -2764,6 +2796,29 @@
+       return res;
+ }
++int ast_channel_masquerade_locked(struct ast_channel *original, struct ast_channel *clone)
++{
++      struct ast_frame null = { AST_FRAME_NULL, };
++      int res = -1;
++      ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
++              clone->name, original->name);
++      if (original->masq) {
++              ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
++                      original->masq->name, original->name);
++      } else if (clone->masqr) {
++              ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
++                      clone->name, clone->masqr->name);
++      } else {
++              original->masq = clone;
++              clone->masqr = original;
++              ast_queue_frame(original, &null);
++              ast_queue_frame(clone, &null);
++              ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
++              res = 0;
++      }
++      return res;
++}
++
+ void ast_change_name(struct ast_channel *chan, char *newname)
+ {
+       char tmp[256];
+@@ -3130,15 +3185,14 @@
+                               );
+ }
+-int ast_setstate(struct ast_channel *chan, int state)
+-{
++int ast_setstate_and_cid(struct ast_channel *chan, int state, char *cid_num, char *cid_name) {
+       int oldstate = chan->_state;
+       if (oldstate == state)
+               return 0;
+       chan->_state = state;
+-      ast_device_state_changed_literal(chan->name);
++      ast_device_state_changed_literal(chan->name, cid_num, cid_name);
+       manager_event(EVENT_FLAG_CALL,
+                     (oldstate == AST_STATE_DOWN) ? "Newchannel" : "Newstate",
+                     "Channel: %s\r\n"
+@@ -3154,6 +3208,10 @@
+       return 0;
+ }
++int ast_setstate(struct ast_channel *chan, int state) {
++    return ast_setstate_and_cid(chan, state, NULL, NULL);
++}
++
+ /*--- Find bridged channel */
+ struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
+ {
+@@ -3331,6 +3389,7 @@
+       char callee_warning = 0;
+       int to;
++
+       if (c0->_bridge) {
+               ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", 
+                       c0->name, c0->_bridge->name);
+@@ -3341,6 +3400,10 @@
+                       c1->name, c1->_bridge->name);
+               return -1;
+       }
++
++      if (IS_DIGITAL(c0->transfercapability) || IS_DIGITAL(c1->transfercapability)) {
++          config->flags = 0;
++      }
+       
+       /* Stop if we're a zombie or need a soft hangup */
+       if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) ||
+diff -urN asterisk-1.2.4.orig/channels/Makefile asterisk-1.2.4/channels/Makefile
+--- asterisk-1.2.4.orig/channels/Makefile      2005-12-15 11:52:30.000000000 +0100
++++ asterisk-1.2.4/channels/Makefile   2006-01-31 09:41:43.000000000 +0100
+@@ -122,6 +122,35 @@
+ endif
+ endif # WITHOUT_ZAPTEL
++ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/capi20.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/capi20.h),)
++  CHANNEL_LIBS+=chan_capi.so
++# uncomment the following line if you really never ever want early b3 connects,
++# you can also configure it in the dialstring, this is just for performance
++# NOTE: this is probably obsolete by using the "R" dial option
++#CFLAGS+=-DCAPI_NEVER_EVER_EARLY_B3_CONNECTS
++
++# uncommnet next line to force dtmf software detection/generation, can also be configured
++# in capi.conf on a perdevice basis (softdtmf=1)
++#CFLAGS+=-DCAPI_FORCE_SOFTWARE_DTMF
++
++# uncomment the next line if you are in the ulaw world
++#CFLAGS+=-DCAPI_ULAW
++
++# very experimental echo squelching
++CFLAGS+=-DCAPI_ES
++
++#gains
++CFLAGS+=-DCAPI_GAIN
++
++# what do to with call waiting connect indications?
++# uncomment the next line for call deflection in that case
++CFLAGS+=-DCAPI_DEFLECT_ON_CIRCUITBUSY
++
++# audio sync
++CFLAGS+=-DCAPI_SYNC
++
++endif
++
+ ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/vpbapi.h),)
+   CHANNEL_LIBS+=chan_vpb.so
+   CFLAGS+=-DLINUX
+@@ -220,6 +249,9 @@
+ chan_nbs.so: chan_nbs.o
+       $(CC) $(SOLINK) -o $@ $< -lnbs
++chan_capi.so: chan_capi.o
++      $(CC) $(SOLINK) -o $@ $< -lcapi20
++
+ chan_vpb.o: chan_vpb.c
+       $(CXX) -c $(CFLAGS) -o $@ chan_vpb.c
+diff -urN asterisk-1.2.4.orig/channels/chan_agent.c asterisk-1.2.4/channels/chan_agent.c
+--- asterisk-1.2.4.orig/channels/chan_agent.c  2006-01-13 07:07:39.000000000 +0100
++++ asterisk-1.2.4/channels/chan_agent.c       2006-01-31 09:41:43.000000000 +0100
+@@ -1331,7 +1331,7 @@
+                                               chan = agent_new(p, AST_STATE_DOWN);
+                                       } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
+                                               /* Adjustable agent */
+-                                              p->chan = ast_request("Local", format, p->loginchan, cause);
++                                              p->chan = ast_request("Local", format, p->loginchan, cause, NULL);
+                                               if (p->chan)
+                                                       chan = agent_new(p, AST_STATE_DOWN);
+                                       }
+diff -urN asterisk-1.2.4.orig/channels/chan_capi.c asterisk-1.2.4/channels/chan_capi.c
+--- asterisk-1.2.4.orig/channels/chan_capi.c   1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/channels/chan_capi.c        2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,2888 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Copyright (C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and 
++ * distributed under the terms of the GNU Public License.
++ */
++
++#include <sys/time.h>
++#include <sys/signal.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <asterisk/lock.h>
++#include <asterisk/frame.h> 
++#include <asterisk/channel.h>
++#include <asterisk/logger.h>
++#include <asterisk/module.h>
++#include <asterisk/pbx.h>
++#include <asterisk/config.h>
++#include <asterisk/options.h>
++#include <asterisk/features.h>
++#include <asterisk/utils.h>
++#include <asterisk/cli.h>
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++#include <capi_bsd.h>
++#else
++#include <linux/capi.h>
++#endif
++#include <capi20.h>
++#include <asterisk/dsp.h>
++#include <asterisk/xlaw.h>
++#include <asterisk/chan_capi.h>
++
++unsigned ast_capi_ApplID;
++_cword ast_capi_MessageNumber=1;
++static char desc[] = "Common ISDN API for Asterisk";
++#ifdef CAPI_ULAW
++static char tdesc[] = "Common ISDN API Driver (0.4.0) muLaw";
++#else
++static char tdesc[] = "Common ISDN API Driver (0.4.0) aLaw ";
++#endif
++static char type[] = "CAPI";
++
++
++static int usecnt;
++AST_MUTEX_DEFINE_STATIC(usecnt_lock);
++AST_MUTEX_DEFINE_STATIC(iflock);
++AST_MUTEX_DEFINE_STATIC(pipelock);
++AST_MUTEX_DEFINE_STATIC(monlock);
++AST_MUTEX_DEFINE_STATIC(contrlock);
++AST_MUTEX_DEFINE_STATIC(capi_send_buffer_lock);
++AST_MUTEX_DEFINE_STATIC(capi_put_lock);
++
++#ifdef CAPI_ULAW
++static int capi_capability = AST_FORMAT_ULAW;
++#else
++static int capi_capability = AST_FORMAT_ALAW;
++#endif
++
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++static CAPIProfileBuffer_t profile;
++#else
++static struct ast_capi_profile profile;
++#endif
++static pthread_t monitor_thread = -1;
++
++static struct ast_capi_pvt *iflist = NULL;
++static struct capi_pipe *pipelist = NULL;
++static int capi_last_plci = 0;
++static struct ast_capi_controller *capi_controllers[AST_CAPI_MAX_CONTROLLERS];
++static int capi_num_controllers = 0;
++static int capi_counter = 0;
++static unsigned long capi_used_controllers=0;
++
++static char capi_send_buffer[AST_CAPI_MAX_B3_BLOCKS * AST_CAPI_MAX_B3_BLOCK_SIZE];
++static int capi_send_buffer_handle = 0;
++
++char capi_national_prefix[AST_MAX_EXTENSION];
++char capi_international_prefix[AST_MAX_EXTENSION];
++
++int capidebug = 0;
++
++static const struct ast_channel_tech capi_tech;
++
++MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG) {
++    MESSAGE_EXCHANGE_ERROR error;
++    if (ast_mutex_lock(&capi_put_lock)) {
++        ast_log(LOG_WARNING,"Unable to lock capi put!\n");
++        return -1;
++    } 
++    error = capi20_put_cmsg(CMSG);    
++    if (ast_mutex_unlock(&capi_put_lock)) {
++      ast_log(LOG_WARNING,"Unable to unlock capi put!\n");
++        return -1;
++    }
++    return error;
++}
++
++
++MESSAGE_EXCHANGE_ERROR check_wait_get_cmsg(_cmsg *CMSG) {
++    MESSAGE_EXCHANGE_ERROR Info;
++    struct timeval tv;
++    tv.tv_sec = 0;
++    tv.tv_usec = 10000;
++    Info = capi20_waitformessage(ast_capi_ApplID,&tv);
++    if ((Info != 0x0000) && (Info != 0x1104)) {
++      if (capidebug) {
++          ast_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info);
++      }
++      return Info;
++    }
++    
++    if (Info == 0x0000) {
++        Info = capi_get_cmsg(CMSG,ast_capi_ApplID);
++    }
++    return Info;
++}
++
++
++unsigned ListenOnController(unsigned long CIPmask,unsigned controller) {
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg                 CMSG,CMSG2;
++
++    LISTEN_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, controller);
++#ifdef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++    LISTEN_REQ_INFOMASK(&CMSG) = 0x00ff; // lots of info ;)
++#else
++    LISTEN_REQ_INFOMASK(&CMSG) = 0x03ff; // lots of info ;) + early B3 connect
++#endif
++    LISTEN_REQ_CIPMASK(&CMSG) = CIPmask;
++    if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++      return error;
++    }
++    while (!IS_LISTEN_CONF(&CMSG2)) {
++      error = check_wait_get_cmsg(&CMSG2);
++    }
++    return 0;
++}
++
++// Echo cancellation is for cards w/ integrated echo cancellation only
++// (i.e. Eicon active cards support it)
++
++#define EC_FUNCTION_ENABLE            1
++#define EC_FUNCTION_DISABLE           2
++#define EC_FUNCTION_FREEZE            3
++#define EC_FUNCTION_RESUME            4
++#define EC_FUNCTION_RESET             5
++#define EC_OPTION_DISABLE_NEVER               0
++#define EC_OPTION_DISABLE_G165                (1<<1)
++#define EC_OPTION_DISABLE_G164_OR_G165        (1<<1 | 1<<2)
++#define EC_DEFAULT_TAIL                       64
++
++static int capi_echo_canceller(struct ast_channel *c, int function) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg                 CMSG;
++    unsigned char   buf[7];
++
++      /* If echo cancellation is not requested or supported, don't attempt to enable it */
++      ast_mutex_lock(&contrlock);
++      if (!capi_controllers[i->controller]->echocancel || !i->doEC) {
++              ast_mutex_unlock(&contrlock);
++              return 0;
++      }
++      ast_mutex_unlock(&contrlock);
++
++      if (option_verbose > 2) 
++              ast_verbose(VERBOSE_PREFIX_3 "Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d)\n",i->PLCI,function,i->ecOption,i->ecTail);
++
++      FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      FACILITY_REQ_NCCI(&CMSG) = i->NCCI;
++      FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 6; /* Echo canceller */
++
++        buf[0]=6; /* msg size */
++        buf[1]=function;
++      if (function == EC_FUNCTION_ENABLE) {
++              buf[3]=i->ecOption; /* bit field - ignore echo canceller disable tone */
++              buf[5]=i->ecTail;   /* Tail length, ms */
++      }
++      else {
++              buf[3]=0;
++              buf[5]=0;
++      }
++
++      // Always null:
++        buf[2]=0;
++        buf[4]=0;
++        buf[6]=0;
++
++      FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf;
++        
++      if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++          return error;
++      }
++
++      if (option_verbose > 5) 
++         ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_REQ (PLCI=%#x)\n",i->PLCI);
++
++    return 0;
++}
++
++int capi_detect_dtmf(struct ast_channel *c, int flag) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg                 CMSG;
++    unsigned char buf[9];
++    // does the controller support dtmf? and do we want to use it?
++    ast_mutex_lock(&contrlock);
++    if ((capi_controllers[i->controller]->dtmf == 1) && (i->doDTMF == 0)) {
++      ast_mutex_unlock(&contrlock);
++      FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      FACILITY_REQ_PLCI(&CMSG) = i->PLCI;
++      FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 1;
++      buf[0] = 8;
++      if (flag == 1) {
++          buf[1] = 1;
++      } else {
++          buf[1] = 2;
++      }
++      buf[2] = 0;
++      buf[3] = AST_CAPI_DTMF_DURATION;
++      buf[4] = 0;
++      buf[5] = AST_CAPI_DTMF_DURATION;
++      buf[6] = 0;
++      buf[7] = 0;
++      buf[8] = 0;
++      FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf;
++        
++      if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++          return error;
++      } else {
++          if (option_verbose > 5) {
++              ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_REQ (PLCI=%#x)\n",i->PLCI);
++          }
++      }
++    } else {
++      ast_mutex_unlock(&contrlock);
++
++#endif
++      // do software dtmf detection
++      i->doDTMF = 1; // just being paranoid again...
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++    }
++#endif
++    return 0;
++}
++static int capi_send_digit(struct ast_channel *c,char digit) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg                 CMSG;
++    unsigned char     buf[10];
++    
++    if (i->state != CAPI_STATE_BCONNECTED) {
++      return 0;
++    }
++    
++    
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++    if(i->earlyB3 == 1)
++    /* we should really test for the network saying the number is incomplete
++    since i'm only doing a test and this is true at the right time
++    i'm going with this */
++    {
++
++      INFO_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      INFO_REQ_PLCI(&CMSG) = i->PLCI;
++      buf[0] = 2;
++      buf[1] = 0x80;
++      buf[2] = digit;
++      INFO_REQ_CALLEDPARTYNUMBER(&CMSG) = buf;
++
++
++      if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR,"error sending CALLEDPARTYNUMBER INFO (error=%#x)\n",error);
++          return error;
++      } else {
++          if (option_verbose > 5) {
++              ast_verbose(VERBOSE_PREFIX_4 "sent CALLEDPARTYNUMBER INFO digit = %c (PLCI=%#x)\n", digit, i->PLCI);
++          }
++      }
++
++    } else {
++#endif
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++      ast_mutex_lock(&contrlock);
++      if ((capi_controllers[i->controller]->dtmf == 0) || (i->doDTMF == 1)) {
++#endif
++          // let * fake it
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++          ast_mutex_unlock(&contrlock);
++#endif
++          return -1;
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++      }
++      ast_mutex_unlock(&contrlock);
++      
++      FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      FACILITY_REQ_PLCI(&CMSG) = i->NCCI;
++        FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 1;
++        buf[0] = 8;
++    
++        buf[1] = 3;
++        buf[2] = 0;
++    
++        buf[3] = AST_CAPI_DTMF_DURATION;
++        buf[4] = 0;
++    
++        buf[5] = AST_CAPI_DTMF_DURATION;
++        buf[6] = 0;
++    
++        buf[7] = 1;
++      buf[8] = digit;
++        buf[9] = 0;
++      FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = buf;
++        
++        if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++          return error;
++        } else {
++          if (option_verbose > 4) {
++              ast_verbose(VERBOSE_PREFIX_3 "sent dtmf '%c'\n",digit);
++          }
++      }
++#endif
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++    }
++#endif
++    return 0;
++}
++
++static int capi_alert(struct ast_channel *c) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg     CMSG;
++    
++    ALERT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
++    ALERT_REQ_PLCI(&CMSG) = i->PLCI;
++
++    if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++      ast_log(LOG_ERROR,"error sending ALERT_REQ PLCI = %#x\n",i->PLCI);
++      return -1;
++    } else {
++      if (option_verbose > 5) {
++          ast_verbose(VERBOSE_PREFIX_4 "sent ALERT_REQ PLCI = %#x\n",i->PLCI);
++      }
++    }
++
++    i->state = CAPI_STATE_ALERTING;
++    return 0;
++}
++
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++static int capi_deflect(struct ast_channel *chan, void *data)
++{
++    struct ast_capi_pvt *i = chan->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR Info;
++    _cmsg     CMSG;
++    char      bchaninfo[1];
++    char      fac[60];
++    int res=0;
++    int ms=3000;
++
++    if (!data) {
++      ast_log(LOG_WARNING, "cd requires an argument (destination phone number)\n");
++      return -1;
++    }
++
++    if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_BCONNECTED)) {
++      ast_log(LOG_ERROR, "call deflection does not work with calls that are already connected!\n");
++      return -1;
++    }
++    // wait until the channel is alerting, so we dont drop the call and interfer with msgs
++    while ((ms > 0) && (i->state != CAPI_STATE_ALERTING)) {
++      sleep(100);
++      ms -= 100;
++    }
++
++    // make sure we hang up correctly
++    i->state = CAPI_STATE_CONNECTPENDING;
++
++    fac[0]=0; // len 
++    fac[1]=0; //len 
++    fac[2]=0x01; // Use D-Chan
++    fac[3]=0; // Keypad len
++    fac[4]=31;        // user user data? len = 31 = 29 + 2
++    fac[5]=0x1c;      // magic?
++    fac[6]=0x1d;      // strlen destination + 18 = 29
++    fac[7]=0x91;      // ..
++    fac[8]=0xA1;
++    fac[9]=0x1A;      // strlen destination + 15 = 26
++    fac[10]=0x02;
++    fac[11]=0x01;
++    fac[12]=0x70;
++    fac[13]=0x02;
++    fac[14]=0x01;
++    fac[15]=0x0d;
++    fac[16]=0x30;
++    fac[17]=0x12;     // strlen destination + 7 = 18
++    fac[18]=0x30;     // ...hm 0x30
++    fac[19]=0x0d;     // strlen destination + 2       
++    fac[20]=0x80;     // CLIP
++    fac[21]=0x0b;     //  strlen destination 
++    fac[22]=0x01;     //  destination start
++    fac[23]=0x01;     //  
++    fac[24]=0x01;     //  
++    fac[25]=0x01;     //  
++    fac[26]=0x01;     //  
++    fac[27]=0x01;     //  
++    fac[28]=0x01;     //  
++    fac[29]=0x01;     //  
++    fac[30]=0x01;     //  
++    fac[31]=0x01;     //  
++    fac[32]=0x01;     //  
++    fac[33]=0x01;     // 0x1 = sending complete
++    fac[34]=0x01;
++    fac[35]=0x01;
++                                 
++    memcpy((unsigned char *)fac+22,data,strlen(data));
++    fac[22+strlen(data)]=0x01;        // fill with 0x01 if number is only 6 numbers (local call)
++    fac[23+strlen(data)]=0x01;
++    fac[24+strlen(data)]=0x01;
++    fac[25+strlen(data)]=0x01;
++    fac[26+strlen(data)]=0x01;
++     
++    fac[6]=18+strlen(data);
++    fac[9]=15+strlen(data);
++    fac[17]=7+strlen(data);
++    fac[19]=2+strlen(data);
++    fac[21]=strlen(data);
++
++    bchaninfo[0] = 0x1;
++    INFO_REQ_HEADER(&CMSG,ast_capi_ApplID,ast_capi_MessageNumber++,0);
++    INFO_REQ_CONTROLLER(&CMSG) = i->controller;
++    INFO_REQ_PLCI(&CMSG) = i->PLCI;
++    INFO_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char*)bchaninfo; // use D-Channel
++    INFO_REQ_KEYPADFACILITY(&CMSG) = 0;
++    INFO_REQ_USERUSERDATA(&CMSG) = 0;
++    INFO_REQ_FACILITYDATAARRAY(&CMSG) = (unsigned char*) fac + 4;
++
++    if ((Info = _capi_put_cmsg(&CMSG)) != 0) {
++      ast_log(LOG_ERROR,"Error sending INFO_REQ\n");
++      return Info;
++    } else {
++      if (capidebug) {
++          // ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(&CMSG));
++          ast_log(LOG_NOTICE,"sent INFO_REQ PLCI = %#x\n",i->PLCI);
++      }
++    }
++
++    return res;
++}
++#endif
++
++void remove_pipe(int PLCI) {
++    struct capi_pipe *p,*ptmp;
++
++    ast_mutex_lock(&pipelock);
++    p = pipelist;
++    ptmp = NULL;
++    while (p) {
++      if (p->PLCI == PLCI) {
++          if (ptmp == NULL) {
++              // mypipe == head of pipelist
++              pipelist = p->next;
++              if(p->fd > -1) close(p->fd);
++              if(p->i != NULL && p->i->fd > -1) close(p->i->fd);
++              free(p);
++              if (option_verbose > 4) {
++                  ast_verbose(VERBOSE_PREFIX_3 "removed pipe for PLCI = %#x\n",PLCI);
++              }
++              break;
++          } else {
++              // somehwere inbetween or at the end
++              ptmp->next = p->next;
++              if (p->next == NULL) {
++                  capi_last_plci = p->PLCI;
++              }
++              if(p->fd > -1) close(p->fd);
++              if(p->i != NULL && p->i->fd > -1) close(p->i->fd);
++              free(p);
++              if (option_verbose > 4) {
++                  ast_verbose(VERBOSE_PREFIX_3 "removed pipe for PLCI = %#x\n",PLCI);
++              }
++              break;
++          }
++      }
++      ptmp = p;
++      p = p->next;
++    }
++    ast_mutex_unlock(&pipelock);
++}
++
++static int capi_activehangup(struct ast_channel *c) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg     CMSG;
++
++    if (option_verbose > 2) {
++      if (capidebug)
++            ast_verbose(VERBOSE_PREFIX_4 "activehangingup\n");
++    }
++
++    if (i == NULL) {
++      return 0;
++    }
++
++    if (c->_state == AST_STATE_RING) {
++      CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
++      CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
++      CONNECT_RESP_REJECT(&CMSG) = 2;
++      if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",i->PLCI);
++      } else {
++          if (option_verbose > 5) {
++              ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",i->PLCI);
++          }
++      }
++      return 0;
++    }
++
++    // active disconnect
++    if (i->state == CAPI_STATE_BCONNECTED) {
++      DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
++
++      if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR, "error sending DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++      } else {
++          if (option_verbose > 5) {
++              ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
++          }
++      }
++      // wait for the B3 layer to go down
++      while (i->state != CAPI_STATE_CONNECTED) {
++          usleep(10000);
++      }
++    }
++    if ((i->state == CAPI_STATE_CONNECTED) || (i->state == CAPI_STATE_CONNECTPENDING)){
++      DISCONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++      DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
++
++      if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++          ast_log(LOG_ERROR, "error sending DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++      } else {
++          if (option_verbose > 5) {
++              ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_REQ PLCI=%#x\n",i->PLCI);
++          }
++      }
++      // wait for the B1 layer to go down
++      while (i->state != CAPI_STATE_DISCONNECTED) {
++          usleep(10000);
++      }
++    }
++    return 0;
++}
++
++static int capi_hangup(struct ast_channel *c) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++
++    // hmm....ok...this is called to free the capi interface (passive disconnect)
++    // or to bring down the channel (active disconnect)
++    
++    if (option_verbose > 3)
++          ast_verbose(VERBOSE_PREFIX_3 "CAPI Hangingup\n");
++
++    if (i == NULL) {
++      ast_log(LOG_ERROR,"channel has no interface!\n");
++      return -1;
++    }
++    
++    // are we down, yet?
++    if (i->state != CAPI_STATE_DISCONNECTED) {
++      // no
++      capi_activehangup(c);
++    }
++
++    remove_pipe(i->PLCI);
++    i->PLCI = 0;
++    i->NCCI = 0;
++    if ((i->doDTMF == 1) && (i->vad != NULL)) {
++      ast_dsp_free(i->vad);
++    }
++    ast_smoother_free(i->smoother); // discard any frames left hanging
++    i->smoother=ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE * 2);
++    memset(i->cid,0,sizeof(i->cid));
++    i->owner=NULL;
++    ast_mutex_lock(&usecnt_lock);
++      usecnt--;
++    ast_mutex_unlock(&usecnt_lock);
++    ast_update_use_count();
++    i->mypipe = NULL;
++    i = NULL;
++    c->tech_pvt = NULL;
++    ast_setstate(c,AST_STATE_DOWN);
++    return 0;
++}
++
++static char *capi_number(char *data,int strip) {
++    unsigned len = *data;
++    // XXX fix me
++    // convert a capi struct to a \0 terminated string
++    if (!len || len < (unsigned int) strip) return NULL;
++    len = len - strip;
++    data = (char *)(data + 1 + strip);
++    return strndup((char *)data,len);
++}
++
++int capi_call(struct ast_channel *c, char *idest, int timeout)
++{
++      struct ast_capi_pvt *i;
++      struct capi_pipe *p = NULL;
++      int fds[2];
++      char *dest,*interface;
++      char buffer[AST_MAX_EXTENSION];
++      char called[AST_MAX_EXTENSION],calling[AST_MAX_EXTENSION];
++      char bchaninfo[3];
++      long flags;
++              
++      _cmsg CMSG;
++      MESSAGE_EXCHANGE_ERROR  error;
++      
++      strncpy(buffer,idest,sizeof(buffer)-1);
++      interface = strtok(buffer, "/");
++      dest = strtok(NULL, "/");
++
++
++      if (!dest) {
++              ast_log(LOG_WARNING, "Destination %s requires a real destination\n", idest);
++              return -1;
++      }
++      i = c->tech_pvt;
++      i->doB3 = AST_CAPI_B3_DONT; // <homer>DOH</homer>
++
++      // always B3
++      if (((char *)dest)[0] == 'b') {
++          i->doB3 = AST_CAPI_B3_ALWAYS;
++      }
++      // only do B3 on successfull calls
++      if (((char *)dest)[0] == 'B') {
++          i->doB3 = AST_CAPI_B3_ON_SUCCESS;
++      } 
++      
++      if (i->doB3 != AST_CAPI_B3_DONT) {
++          dest++;
++      }
++
++      if (option_verbose > 1) {
++          if (capidebug)
++              ast_verbose(VERBOSE_PREFIX_2 "CAPI Call %s %s", c->name, i->doB3?"with B3":"");
++      }
++      switch (c->cid.cid_pres) {
++          case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
++          case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
++          case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
++          case PRES_ALLOWED_NETWORK_NUMBER:
++          case PRES_NUMBER_NOT_AVAILABLE:
++              i->CLIR = 0;
++              break;
++          case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++          case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++          case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++          case PRES_PROHIB_NETWORK_NUMBER:
++              i->CLIR = 1;
++              break;
++          default:
++              i->CLIR = 0;
++      }
++    
++      if (pipe(fds) == 0) {
++          ast_mutex_lock(&pipelock);
++          i->fd = fds[0];
++          flags = fcntl(i->fd,F_GETFL);
++          fcntl(i->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++          p = malloc(sizeof(struct capi_pipe));
++          memset(p, 0, sizeof(struct capi_pipe));
++          p->fd = fds[1];
++          flags = fcntl(i->fd,F_GETFL);
++          fcntl(p->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++          c->fds[0] = i->fd;
++          p->PLCI = -1;
++          p->i = i;
++          p->c = c;
++          i->mypipe = p;
++          p->next = pipelist;
++          pipelist = p;
++          if (option_verbose > 4) {
++              ast_verbose(VERBOSE_PREFIX_3 "creating pipe for PLCI=-1\n");
++          }
++          ast_mutex_unlock(&pipelock);
++      }
++      i->outgoing = 1;
++      
++      i->MessageNumber = ast_capi_MessageNumber++;
++      CONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, i->controller);
++      CONNECT_REQ_CONTROLLER(&CMSG) = i->controller;
++      CONNECT_REQ_CIPVALUE(&CMSG) = 0x10;     // Telephony, could also use 0x04 (3.1Khz audio)
++      called[0] = strlen(dest)+1;
++      called[1] = 0x80;
++      strncpy(&called[2],dest,sizeof(called)-2);
++      CONNECT_REQ_CALLEDPARTYNUMBER(&CMSG) = (unsigned char *)called;
++      CONNECT_REQ_CALLEDPARTYSUBADDRESS(&CMSG) = NULL;
++
++      if (c->cid.cid_num) {
++          calling[0] = strlen(c->cid.cid_num)+2;
++          calling[1] = 0x0;
++      } else {
++          calling[0] = 0x0;
++          calling[1] = 0x0;
++      }
++
++      if (i->CLIR == 1) {
++          calling[2] = 0xA0; // CLIR
++      } else {
++          calling[2] = 0x80; // CLIP
++      }
++
++      if (c->cid.cid_num) {
++          strncpy(&calling[3],c->cid.cid_num,sizeof(calling)-3);
++      }
++      CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = (unsigned char *)calling;
++      CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = NULL;
++
++      CONNECT_REQ_B1PROTOCOL(&CMSG) = 1;
++      CONNECT_REQ_B2PROTOCOL(&CMSG) = 1; // 1
++      CONNECT_REQ_B3PROTOCOL(&CMSG) = 0;
++
++      bchaninfo[0] = 2;
++      bchaninfo[1] = 0x0;
++      bchaninfo[2] = 0x0;
++      CONNECT_REQ_BCHANNELINFORMATION(&CMSG) = (unsigned char *)bchaninfo; // 0
++
++        if ((error = _capi_put_cmsg(&CMSG))) {
++          ast_log(LOG_ERROR,"error sending CONNECT_REQ (error=%#x)\n",error);
++          return error;
++      } else {
++          if (option_verbose > 5) {
++              ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_REQ MN =%#x\n",CMSG.Messagenumber);
++          }
++      }
++
++      i->state = CAPI_STATE_CONNECTPENDING;
++
++      ast_setstate(c, AST_STATE_DIALING);
++
++      // XXX fixme, not nice:
++/*    if (i->controller > 0) {
++          capi_controllers[i->controller]->nfreebchannels--;
++      } */
++
++      // now we shall return .... the rest has to be done by handle_msg
++    return 0;
++}
++
++
++static int capi_answer(struct ast_channel *c) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++    MESSAGE_EXCHANGE_ERROR  error;
++    _cmsg                 CMSG;
++    char buf[AST_MAX_EXTENSION];
++    char *dnid;
++    
++    if (i->isdnmode && (strlen(i->incomingmsn)<strlen(i->dnid)))
++      dnid = i->dnid + strlen(i->incomingmsn);
++    else
++      dnid = i->dnid;
++
++    CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
++    CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
++    CONNECT_RESP_REJECT(&CMSG) = 0;
++    buf[0] = strlen(dnid)+2;
++    buf[1] = 0x0;
++    buf[2] = 0x80;
++    strncpy(&buf[3],dnid,sizeof(buf)-4);
++    CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = (unsigned char *)buf;
++    CONNECT_RESP_CONNECTEDSUBADDRESS(&CMSG) = NULL;
++    CONNECT_RESP_LLC(&CMSG) = NULL;
++    CONNECT_RESP_B1PROTOCOL(&CMSG) = 1;
++    CONNECT_RESP_B2PROTOCOL(&CMSG) = 1;
++    CONNECT_RESP_B3PROTOCOL(&CMSG) = 0;
++
++    if (option_verbose > 3)
++      ast_verbose(VERBOSE_PREFIX_3 "CAPI Answering for MSN %s\n", dnid);
++    if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++      return -1;      
++    } else {
++      if (option_verbose > 5) {
++          if (capidebug) 
++              ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP PLCI = %#x DNID = %s\n",i->PLCI,i->dnid);
++      }
++    }
++    
++    i->state = CAPI_STATE_ANSWERING;
++    i->doB3 = AST_CAPI_B3_DONT;
++    i->outgoing = 0;
++    i->earlyB3 = -1;
++
++    return 0;
++}
++
++struct ast_frame *capi_read(struct ast_channel *c) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++      int readsize = 0;
++
++      if ((i->state == CAPI_STATE_REMOTE_HANGUP)) {
++          ast_log(LOG_ERROR,"this channel is not connected\n");
++          return NULL;
++      }
++      if (i->state == CAPI_STATE_ONHOLD) {
++          i->fr.frametype = AST_FRAME_NULL;
++          return &i->fr;
++      }
++      
++      if (i == NULL) {
++          ast_log(LOG_ERROR,"channel has no interface\n");
++          return NULL;
++      }
++      i->fr.frametype = AST_FRAME_NULL;
++      i->fr.subclass = 0;
++      i->fr.delivery.tv_sec = 0;
++      i->fr.delivery.tv_usec = 0;
++      readsize = read(i->fd,&i->fr,sizeof(struct ast_frame));
++      if (readsize != sizeof(struct ast_frame)) {
++          ast_log(LOG_ERROR,"did not read a whole frame\n");
++      }
++      if (i->fr.frametype == AST_FRAME_VOICE) {
++          readsize = read(i->fd,i->fr.data,i->fr.datalen);
++          if (readsize != i->fr.datalen) {
++              ast_log(LOG_ERROR,"did not read whole frame data\n");
++          }
++      }
++      i->fr.mallocd = 0;      
++      if (i->fr.frametype == AST_FRAME_NULL) {
++          return NULL;
++      }
++      if ((i->fr.frametype == AST_FRAME_DTMF) && (i->fr.subclass == 'f')) {
++          if (strcmp(c->exten, "fax")) {
++              if (ast_exists_extension(c, ast_strlen_zero(c->macrocontext) ? c->context : c->macrocontext, "fax", 1, c->cid.cid_num)) {
++                  if (option_verbose > 2)
++                      ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", c->name);
++                      /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
++                      pbx_builtin_setvar_helper(c,"FAXEXTEN",c->exten);
++                      if (ast_async_goto(c, c->context, "fax", 1))
++                          ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", c->name, c->context);
++                      } else {
++                          ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
++                      }
++          } else {
++              ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
++          }
++      }
++      return &i->fr;
++}
++
++int capi_write(struct ast_channel *c, struct ast_frame *f) {
++    struct ast_capi_pvt *i = c->tech_pvt;
++      _cmsg CMSG;
++      MESSAGE_EXCHANGE_ERROR  error;
++      int j=0;
++      char buf[1000];
++      struct ast_frame *fsmooth;
++#ifdef CAPI_ES
++      int txavg=0;
++#endif
++
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++      // dont send audio to the local exchange!
++      if (i->earlyB3 == 1 || !i->NCCI) {
++          return 0;
++      }
++#endif
++
++      if (!i) {
++          ast_log(LOG_ERROR,"channel has no interface\n");
++          return -1;
++      } 
++
++      if (f->frametype == AST_FRAME_NULL) {
++          return 0;
++      }
++      if (f->frametype == AST_FRAME_DTMF) {
++          ast_log(LOG_ERROR,"dtmf frame should be written\n");
++          return 0;
++      }
++      if (f->frametype != AST_FRAME_VOICE) {
++          ast_log(LOG_ERROR,"not a voice frame\n");
++          return -1;
++      }
++      if (f->subclass != capi_capability) {
++          ast_log(LOG_ERROR,"dont know how to write subclass %d\n",f->subclass);
++          return -1;
++      }
++//    ast_log(LOG_NOTICE,"writing frame %d %d\n",f->frametype,f->subclass);
++
++    if (ast_smoother_feed(i->smoother, f)!=0) {
++        ast_log(LOG_ERROR,"failed to fill smoother\n");
++        return -1;
++    }
++
++    fsmooth=ast_smoother_read(i->smoother);
++    while(fsmooth != NULL) {
++        DATA_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++        DATA_B3_REQ_NCCI(&CMSG) = i->NCCI;
++        DATA_B3_REQ_DATALENGTH(&CMSG) = fsmooth->datalen;
++        DATA_B3_REQ_FLAGS(&CMSG) = 0; 
++
++        if (ast_mutex_lock(&capi_send_buffer_lock)) {
++            ast_log(LOG_WARNING,"Unable to lock B3 send buffer!\n");
++            return -1;
++        }
++#ifndef CAPI_ES
++#ifdef CAPI_GAIN
++        for (j=0;j<fsmooth->datalen;j++) {
++          buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]]; 
++        }
++#else
++        for (j=0;j<fsmooth->datalen;j++) {
++          buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; 
++        }
++#endif
++#else
++      if ((i->doES == 1)) {
++          for (j=0;j<fsmooth->datalen;j++) {
++              buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; 
++              txavg += abs( capiXLAW2INT(reversebits[ ((unsigned char*)fsmooth->data)[j]]) );
++          }
++          txavg = txavg/j;
++          for(j=0;j<ECHO_TX_COUNT-1;j++) {
++              i->txavg[j] = i->txavg[j+1];
++          }
++          i->txavg[ECHO_TX_COUNT-1] = txavg;
++          
++//        ast_log(LOG_NOTICE,"txavg = %d\n",txavg);
++      } else {
++#ifdef CAPI_GAIN
++          for (j=0;j<fsmooth->datalen;j++) {
++              buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]]; 
++          }
++#else
++          for (j=0;j<fsmooth->datalen;j++) {
++              buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; 
++          }
++#endif
++      }
++#endif
++    
++        DATA_B3_REQ_DATAHANDLE(&CMSG) = capi_send_buffer_handle;
++      memcpy((char *)&capi_send_buffer[(capi_send_buffer_handle % AST_CAPI_MAX_B3_BLOCKS) * AST_CAPI_MAX_B3_BLOCK_SIZE],&buf,fsmooth->datalen);
++        DATA_B3_REQ_DATA(&CMSG) = (unsigned char *)&capi_send_buffer[(capi_send_buffer_handle % AST_CAPI_MAX_B3_BLOCKS) * AST_CAPI_MAX_B3_BLOCK_SIZE];
++      capi_send_buffer_handle++;
++    
++        if (ast_mutex_unlock(&capi_send_buffer_lock)) {
++            ast_log(LOG_WARNING,"Unable to unlock B3 send buffer!\n");
++            return -1;
++        }
++
++
++#ifdef CAPI_SYNC    
++    ast_mutex_lock(&i->lockB3in);
++    if ((i->B3in >= 1) && (i->B3in <= AST_CAPI_MAX_B3_BLOCKS)) {
++      i->B3in--;
++      ast_mutex_unlock(&i->lockB3in);
++        if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++            ast_log(LOG_ERROR,"error sending DATA_B3_REQ (error=%#x, datalen=%d) B3in=%d\n",error,fsmooth->datalen,i->B3in);
++//            ast_log(LOG_NOTICE,"f: timelen %d b = %d MN = %d \n",fsmooth->timelen,b,CMSG.Messagenumber);
++      } else {
++                  if (option_verbose > 5) {
++              if (capidebug) 
++                  ast_verbose(VERBOSE_PREFIX_4 "sent DATA_B3_REQ (NCCI=%#x) (%d bytes)\n",i->NCCI,fsmooth->datalen);
++                  }
++      }
++    } else {
++      if (i->B3in > 0) i->B3in--;
++      ast_mutex_unlock(&i->lockB3in);
++    }
++#else
++        if ((error = _capi_put_cmsg(&CMSG)) != 0) {
++            ast_log(LOG_ERROR,"error sending DATA_B3_REQ (error=%#x, datalen=%d)\n",error,fsmooth->datalen);
++//            ast_log(LOG_NOTICE,"f: timelen %d b = %d MN = %d \n",fsmooth->timelen,b,CMSG.Messagenumber);
++      } else {
++                  if (option_verbose > 5) {
++              if (capidebug) 
++                  ast_verbose(VERBOSE_PREFIX_4 "sent DATA_B3_REQ (NCCI=%#x) (%d bytes)\n",i->NCCI,fsmooth->datalen);
++                  }
++      }
++#endif
++    
++//    ast_frfree(fsmooth);
++
++        fsmooth=ast_smoother_read(i->smoother);
++    }
++      return 0;
++}
++
++static int capi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) {
++    struct ast_capi_pvt *p = newchan->tech_pvt;
++      p->owner = newchan;
++      return 0;
++}
++
++int capi_indicate(struct ast_channel *c,int condition) {
++    return -1;
++}
++
++int capi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) {
++    return -1;
++}
++
++
++struct ast_channel *capi_new(struct ast_capi_pvt *i,int state) {
++    struct ast_channel *tmp;
++    int fmt;
++
++    tmp = ast_channel_alloc(1);
++    if (tmp != NULL) {
++      snprintf(tmp->name,sizeof(tmp->name),"CAPI/contr%d/%s-%d",i->controller,i->dnid,capi_counter++);
++      tmp->type = type;
++      tmp->tech = &capi_tech;
++      tmp->nativeformats = capi_capability;
++      ast_setstate(tmp,state);
++      tmp->fds[0] = i->fd;
++      i->smoother = ast_smoother_new(AST_CAPI_MAX_B3_BLOCK_SIZE);
++      if (i->smoother == NULL) {
++          ast_log(LOG_ERROR, "smoother NULL!\n");
++      }
++      i->fr.frametype = 0;
++      i->fr.subclass = 0;
++      i->fr.delivery.tv_sec = 0;
++      i->fr.delivery.tv_usec = 0;
++      i->state = CAPI_STATE_DISCONNECTED;
++      i->CLIR = 0;
++      i->calledPartyIsISDN = 0; // let's be pessimistic
++      i->earlyB3 = -1;
++      i->doB3 = AST_CAPI_B3_DONT;
++      i->outgoing = 0;
++      i->onholdPLCI = 0;
++#ifdef CAPI_SYNC
++      i->B3in = 0;
++      ast_mutex_init(&i->lockB3in);
++#endif                
++#ifdef CAPI_ES
++      memset(i->txavg,0,ECHO_TX_COUNT);
++#endif
++
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++          if (i->doDTMF == 1) {
++#endif
++              i->vad = ast_dsp_new();
++              ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++          }
++#endif
++
++      tmp->tech_pvt = i;
++      tmp->callgroup = i->callgroup;
++      tmp->nativeformats = capi_capability;
++      fmt = ast_best_codec(tmp->nativeformats);
++//    fmt = capi_capability;
++      tmp->readformat = fmt;
++      tmp->writeformat = fmt;
++      tmp->rawreadformat = fmt;
++      tmp->rawwriteformat = fmt;
++      strncpy(tmp->context,i->context,sizeof(tmp->context)-1);
++      tmp->cid.cid_num = strdup(i->cid);
++      tmp->cid.cid_dnid = strdup(i->dnid);
++      strncpy(tmp->exten,i->dnid,sizeof(tmp->exten)-1);
++      strncpy(tmp->accountcode,i->accountcode,sizeof(tmp->accountcode)-1);
++      i->owner = tmp;
++      ast_mutex_lock(&usecnt_lock);
++      usecnt++;
++      ast_mutex_unlock(&usecnt_lock);
++      ast_update_use_count();
++      if (state != AST_STATE_DOWN) {
++          // we are alerting (phones ringing)
++          if (state == AST_STATE_RING)
++              capi_alert(tmp);
++          if (ast_pbx_start(tmp)) {
++              ast_log(LOG_ERROR,"Unable to start pbx on channel!\n");
++              ast_hangup(tmp);
++              tmp = NULL;
++          } else {
++              if (option_verbose > 2) {
++                  ast_verbose(VERBOSE_PREFIX_3 "started pbx on channel (callgroup=%d)!\n",tmp->callgroup);
++              }
++          }
++      }
++    } else {
++      ast_log(LOG_ERROR,"Unable to allocate channel!\n");
++    }
++    return tmp;
++}
++
++
++struct ast_channel *capi_request(const char *type, int format, void *data, int *cause)
++{
++      struct ast_capi_pvt *i;
++      struct ast_channel *tmp = NULL;
++      char *dest,*interface;
++      char buffer[AST_MAX_EXTENSION];
++      unsigned int capigroup=0, controller=0;
++      int notfound = 1;
++
++      if (option_verbose > 1) {
++          if (capidebug)
++              ast_verbose(VERBOSE_PREFIX_3 "data = %s\n",(char *)data);
++      }
++      strncpy(buffer,(char *)data,sizeof(buffer)-1);
++
++      interface = strtok(buffer, "/");
++      dest = strtok(NULL, "/");
++
++      
++      if (((char *)interface)[0] == 'g') {
++          interface++;
++          capigroup = atoi(interface);
++          if (option_verbose > 1) {
++              if (capidebug)
++                  ast_verbose(VERBOSE_PREFIX_3 "capi request group = %d\n",capigroup);
++          }
++      } else if (!strncmp(interface,"contr",5)) {
++          interface += 5;
++          controller = atoi(interface);
++          if (option_verbose > 1) {
++              if (capidebug)
++                  ast_verbose(VERBOSE_PREFIX_3 "capi request controller = %d\n",controller);
++          }
++      } else {
++          ast_log(LOG_ERROR,"Syntax error in dialstring. read the docs!\n");
++      }
++
++      ast_mutex_lock(&iflock);
++      i = iflist;
++      while (i && notfound) {
++          // unused channel
++          if (!i->owner) {
++              if (controller && (i->controllers & (1 << controller))) {
++                  // DIAL(CAPI/contrX/...)
++                  ast_mutex_lock(&contrlock);
++                  if (capi_controllers[controller]->nfreebchannels > 0) {
++                      strncpy(i->dnid,dest,sizeof(i->dnid)-1);
++                      i->controller = controller;
++                      tmp = capi_new(i, AST_STATE_DOWN);
++                      i->PLCI = -1;
++                      i->datahandle = 0;
++                      i->outgoing = 1;        // this is an outgoing line
++                      i->earlyB3 = -1;
++                      // capi_detect_dtmf(tmp,1);
++                      ast_mutex_unlock(&contrlock);
++                      ast_mutex_unlock(&iflock);
++                      return tmp;
++                  } else {
++                      // keep on running!
++                      ast_mutex_unlock(&contrlock);
++                  }
++              } else if (capigroup && (i->group & (1 << capigroup))) {
++                  int c;
++                  // DIAL(CAPI/gX/...)
++                  ast_mutex_lock(&contrlock);
++                  for (c=1;c<=capi_num_controllers;c++) {
++                      if (i->controllers & (1 << c)) {
++                          if (capi_controllers[c]->nfreebchannels > 0) {
++                              strncpy(i->dnid,dest,sizeof(i->dnid)-1);
++                              i->controller = c;
++                              tmp = capi_new(i, AST_STATE_DOWN);
++                              i->PLCI = -1;
++                              i->datahandle = 0;
++                              i->outgoing = 1;        // this is an outgoing line
++                              i->earlyB3 = -1;
++                              // capi_detect_dtmf(tmp,1);
++                              ast_mutex_unlock(&contrlock);
++                              ast_mutex_unlock(&iflock);
++                              return tmp;
++                          } else {
++                              // keep on running!
++                          }
++                      }
++                  }
++                  ast_mutex_unlock(&contrlock);
++              }
++          }
++//        ast_log(LOG_NOTICE,"not contr %d group %d\n",i->controllers, i->group);
++          i = i->next;
++      }
++      ast_mutex_unlock(&iflock);
++      ast_log(LOG_NOTICE,"didn't find capi device with controller = %d or group = %d.\n",controller, capigroup);
++      return NULL;
++}
++
++
++struct capi_pipe *find_pipe(int PLCI,int MN) {
++    struct capi_pipe *p;
++    // find a pipe by PLCI or by MessageNumber (in case this is a CONNECT_CONF)
++    ast_mutex_lock(&pipelock);
++    p = pipelist;
++    if ((p == NULL) && (capi_last_plci != PLCI)){
++      if (capidebug) {
++      ast_log(LOG_NOTICE,"PLCI doesnt match last pipe (PLCI = %#x)\n",PLCI);
++      }
++      ast_mutex_unlock(&pipelock);
++      return NULL;
++    }
++    while(p != NULL) {
++      if ((p->PLCI == PLCI) || ( (p->PLCI == -1) && (p->i->MessageNumber == MN) ) ){
++          ast_mutex_unlock(&pipelock);
++          return p;
++      }
++      p = p->next;
++    }
++    if (capidebug) {
++      ast_log(LOG_ERROR,"unable to find a pipe for PLCI = %#x MN = %#x\n",PLCI,MN);
++    }
++    ast_mutex_unlock(&pipelock);
++    return NULL;
++}
++
++int pipe_frame(struct capi_pipe *p,struct ast_frame *f) {
++      fd_set wfds;
++      int written=0;
++      struct timeval tv;
++      FD_ZERO(&wfds);
++      FD_SET(p->fd,&wfds);
++      tv.tv_sec = 0;
++      tv.tv_usec = 10;
++      if ((f->frametype == AST_FRAME_VOICE) && (p->i->doDTMF == 1) && (p->i->vad != NULL)) {
++          f = ast_dsp_process(p->c,p->i->vad,f);
++          if (f->frametype == AST_FRAME_NULL) {
++              return 0;
++          }
++      }
++      // we dont want the monitor thread to block
++      if (select(p->fd + 1,NULL,&wfds,NULL,&tv) == 1) {
++          written = write(p->fd,f,sizeof(struct ast_frame));
++          if (written < (signed int) sizeof(struct ast_frame)) {
++              ast_log(LOG_ERROR,"wrote %d bytes instead of %d\n", written, (int)sizeof(struct ast_frame));
++              return -1;
++          }
++          if (f->frametype == AST_FRAME_VOICE) {
++              written = write(p->fd,f->data,f->datalen);
++              if (written < f->datalen) {
++                  ast_log(LOG_ERROR,"wrote %d bytes instead of %d\n",written,f->datalen);
++                  return -1;
++              }
++          }
++      } else {
++          return 0;
++      }
++      return -1;
++}
++
++static int search_did(struct ast_channel *c)
++{
++    // Returns 
++    // -1 = Failure 
++    //  0 = Match
++    //  1 = possible match 
++    struct ast_capi_pvt *i = c->tech_pvt;
++    char *exten;
++    
++    if (strlen(i->dnid)<strlen(i->incomingmsn))
++      return -1;
++      
++//    exten = i->dnid + strlen(i->incomingmsn);
++    exten = i->dnid;
++
++    if (ast_exists_extension(NULL, c->context, exten, 1, NULL)) {
++          c->priority = 1;
++          strncpy(c->exten, exten, sizeof(c->exten) - 1);
++      return 0;
++    }
++
++    if (ast_canmatch_extension(NULL, c->context, exten, 1, NULL)) {
++      return 1;
++    }
++
++
++    return -1;
++}
++
++int pipe_msg(int PLCI,_cmsg *CMSG) {
++      struct capi_pipe *p;
++      _cmsg CMSG2;
++      MESSAGE_EXCHANGE_ERROR  error;
++      struct ast_frame fr;
++      char b3buf[1024];
++      int j;
++      int b3len=0;
++      char dtmf;
++      unsigned dtmflen;
++#ifdef CAPI_ES
++      int rxavg = 0;
++      int txavg = 0;
++#endif    
++
++      p = find_pipe(PLCI,CMSG->Messagenumber);
++      if (p == NULL) {
++          if (IS_DISCONNECT_IND(CMSG)) {
++              DISCONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber , 0);
++              DISCONNECT_RESP_PLCI(&CMSG2) = PLCI;
++              if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                  ast_log(LOG_NOTICE, "error sending DISCONNECT_RESP PLCI=%#x\n",PLCI);
++              } else {
++                  if (option_verbose > 5) {
++                      if (capidebug)
++                          ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_RESP PLCI=%#x\n",PLCI);
++                  }
++              }           
++              return 0;
++          }
++          if (capidebug) {
++              ast_log(LOG_NOTICE,"%s",capi_cmsg2str(CMSG));
++          } 
++          return -1;
++      }
++
++      if (CMSG != NULL) {
++          switch (CMSG->Subcommand) {
++              case CAPI_IND:
++                  switch (CMSG->Command) {
++                      case CAPI_DISCONNECT_B3:
++//                        ast_log(LOG_NOTICE,"DISCONNECT_B3_IND\n");
++
++                          DISCONNECT_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++                          DISCONNECT_B3_RESP_NCCI(&CMSG2) = DISCONNECT_B3_IND_NCCI(CMSG);
++
++                          if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                              ast_log(LOG_NOTICE, "error sending DISCONNECT_B3_RESP NCCI=%#x\n",(int)DISCONNECT_B3_IND_NCCI(CMSG));
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_B3_RESP NCCI=%#x\n",(int)DISCONNECT_B3_IND_NCCI(CMSG));
++                              }
++                          }
++                          if (p->i->state == CAPI_STATE_BCONNECTED) {
++                              // passive disconnect
++                              p->i->state = CAPI_STATE_CONNECTED;
++                          } else
++                          if (p->i->state == CAPI_STATE_DISCONNECTING) {
++                              // active disconnect
++                              memset(&CMSG2,0,sizeof(_cmsg));
++                              DISCONNECT_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++                              DISCONNECT_REQ_PLCI(&CMSG2) = PLCI;
++
++                              if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                                  ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",PLCI);
++                              } else {
++                                  if (option_verbose > 5) {
++                                      if (capidebug)
++                                          ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_REQ PLCI=%#x\n",PLCI);
++                                  }
++                              }                               
++                          } else 
++                          if (p->i->state == CAPI_STATE_ONHOLD) {
++                                  // no hangup
++                          }
++                          ast_mutex_lock(&contrlock);
++                          if (p->i->controller > 0) {
++                              capi_controllers[p->i->controller]->nfreebchannels++;
++                          }
++                          ast_mutex_unlock(&contrlock);
++                          break;
++                      case CAPI_DISCONNECT:
++//                        ast_log(LOG_NOTICE,"DISCONNECT_IND\n");
++                          DISCONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber , 0);
++                          DISCONNECT_RESP_PLCI(&CMSG2) = PLCI;
++/*                        if (p->i->controller > 0) {
++                              capi_controllers[p->i->controller]->nfreebchannels++;
++                          } */
++
++                          if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                              ast_log(LOG_NOTICE, "error sending DISCONNECT_RESP PLCI=%#x\n",PLCI);
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_RESP PLCI=%#x\n",PLCI);
++                              }
++                          }
++                          if (p->c) {
++                              p->c->hangupcause = DISCONNECT_IND_REASON(CMSG) - 0x3480;
++                          }
++                          
++                          if (PLCI == p->i->onholdPLCI) {
++                              // the caller onhold hung up (or ECTed away)
++                              p->i->onholdPLCI = 0;
++                              remove_pipe(PLCI);
++                              return 0;
++                          }
++                          
++                          if (p->i->state == CAPI_STATE_DID) {
++                              if ((p->c) != NULL) {
++                                  ast_hangup(p->c);
++                              } else {    
++                                  ast_log(LOG_WARNING, "unable to hangup channel on DID. Channel is NULL.\n");
++                              }
++                              return 0;                               
++                          }
++                          
++                          p->i->state = CAPI_STATE_DISCONNECTED;
++
++                          fr.frametype = AST_FRAME_CONTROL;
++                          if (DISCONNECT_IND_REASON(CMSG) == 0x34a2) {
++                              fr.subclass = AST_CONTROL_BUSY;
++                          } else {
++                              fr.frametype = AST_FRAME_NULL;
++                          }
++                          fr.datalen = 0;
++                          if (pipe_frame(p,(struct ast_frame *)&fr) == -1) {
++              // printf("STATE = %#x\n",p->i->state);
++                              // in this case * did not read our hangup control frame
++                              // so we must hangup the channel!
++                              if ( (p->i->state != CAPI_STATE_DISCONNECTED) && (ast_check_hangup(p->c) == 0)) {
++                                  if (option_verbose > 1) {
++                                      ast_verbose(VERBOSE_PREFIX_3 "soft hangup by capi\n");
++                                  }
++                                  ast_softhangup(p->c,AST_SOFTHANGUP_DEV);
++                              } else {
++                                  // dont ever hangup while hanging up!
++//                                ast_log(LOG_NOTICE,"no soft hangup by capi\n");
++                              }
++                              return -1;
++                          } else {
++                              return 0;
++                          }
++
++/*                        fr.frametype = AST_FRAME_NULL;
++                          fr.datalen = 0;
++                          pipe_frame(p,(struct ast_frame *)&fr); */
++                          break;
++                      case CAPI_DATA_B3:
++
++                          memcpy(&b3buf[AST_FRIENDLY_OFFSET],(char *)DATA_B3_IND_DATA(CMSG),DATA_B3_IND_DATALENGTH(CMSG));
++                          b3len = DATA_B3_IND_DATALENGTH(CMSG);
++                      
++                          // send a DATA_B3_RESP very quickly to free the buffer in capi
++                          DATA_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber,0);
++                          DATA_B3_RESP_NCCI(&CMSG2) = DATA_B3_IND_NCCI(CMSG);
++                          DATA_B3_RESP_DATAHANDLE(&CMSG2) = DATA_B3_IND_DATAHANDLE(CMSG);
++                          if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                              ast_log(LOG_ERROR,"error sending DATA_B3_RESP (error=%#x)\n",error);
++                          } else {
++                              if (option_verbose > 6) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent DATA_B3_RESP (NCCI=%#x)\n",(int)DATA_B3_IND_NCCI(CMSG));
++                              }
++                          }
++#ifdef CAPI_SYNC
++                          ast_mutex_lock(&p->i->lockB3in);
++                          p->i->B3in++;
++                          if (p->i->B3in > AST_CAPI_MAX_B3_BLOCKS) p->i->B3in = AST_CAPI_MAX_B3_BLOCKS;
++                          ast_mutex_unlock(&p->i->lockB3in);
++#endif                            
++#ifdef CAPI_ES
++                          if ((p->i->doES == 1)) {
++                              for (j=0;j<b3len;j++) {
++                                  b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]; 
++                                  rxavg += abs(capiXLAW2INT( reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]));
++                              }
++                              rxavg = rxavg/j;
++                              for(j=0;j<ECHO_EFFECTIVE_TX_COUNT;j++) {
++                                  txavg += p->i->txavg[j];
++                              }
++                              txavg = txavg/j;
++                          
++                              if( (txavg/ECHO_TXRX_RATIO) > rxavg) { 
++#ifdef CAPI_ULAW
++                                  memset(&b3buf[AST_FRIENDLY_OFFSET],255,b3len);
++#else
++                                  memset(&b3buf[AST_FRIENDLY_OFFSET],84,b3len);
++#endif
++                                  if (capidebug) {
++                                      ast_log(LOG_NOTICE,"SUPPRESSING ECHOrx=%d, tx=%d\n",rxavg,txavg);
++                                  }
++                              }
++                          } else {
++#ifdef CAPI_GAIN
++                              for (j=0;j<b3len;j++) {
++                                  b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[p->i->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]]; 
++                              }
++#else
++                              for (j=0;j<b3len;j++) {
++                                  b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]; 
++                              }
++#endif
++                          }
++#else
++
++#ifdef CAPI_GAIN
++                          for (j=0;j<b3len;j++) {
++                              b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[p->i->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]]; 
++                          }
++#else
++                          for (j=0;j<b3len;j++) {
++                              b3buf[AST_FRIENDLY_OFFSET + j] = reversebits[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]; 
++                          }
++#endif
++
++#endif
++                          // just being paranoid ...
++              /*          if (p->c->_state != AST_STATE_UP) {
++                              ast_setstate(p->c,AST_STATE_UP);
++                          } */
++                          
++                          fr.frametype = AST_FRAME_VOICE;
++                          fr.subclass = capi_capability;
++                          fr.data = (char *)&b3buf[AST_FRIENDLY_OFFSET];
++                          fr.datalen = b3len;
++                          fr.samples = b3len;
++                          fr.offset = AST_FRIENDLY_OFFSET;
++                          fr.mallocd = 0;
++                          fr.delivery.tv_sec = 0;
++                          fr.delivery.tv_usec = 0;
++                          fr.src = NULL;
++                      //          ast_verbose(VERBOSE_PREFIX_3 "DATA_B3_IND (len=%d) fr.datalen=%d fr.subclass=%d\n",(int)DATA_B3_IND_DATALENGTH(CMSG),fr.datalen,fr.subclass);
++                          return pipe_frame(p,(struct ast_frame *)&fr);
++                          break;
++                      case CAPI_FACILITY:
++                          if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0001) {
++                      // DTMF received
++                              if (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] != (0xff)) {
++                                  dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0];
++                                  FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 1;
++                              } else {
++                                  dtmflen = ((__u16 *) (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) + 1))[0];
++                                  FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG) += 3;
++                              }
++                              if (dtmflen == 1) {
++                                  dtmf = (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG))[0];
++                                  fr.frametype = AST_FRAME_DTMF;
++                                  fr.subclass = dtmf;
++                                  if (option_verbose > 1) {
++                                      if (capidebug)
++                                          ast_verbose(VERBOSE_PREFIX_3 "c_dtmf = %c\n",dtmf);
++                                  }
++                                  pipe_frame(p,(struct ast_frame *)&fr);
++                              } 
++                          }
++                          if (FACILITY_IND_FACILITYSELECTOR(CMSG) == 0x0003) {
++                          // sservices
++                      /*       ast_log(LOG_NOTICE,"FACILITY_IND PLCI = %#x\n",(int)FACILITY_IND_PLCI(CMSG));
++                               ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]);
++                               ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]);
++                               ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2]);
++                               ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3]);
++                               ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]);
++                               ast_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5]);  */
++                              // RETRIEVE
++                              if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x3) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2)) {
++                                  p->i->state = CAPI_STATE_CONNECTED;
++                                  p->i->PLCI = p->i->onholdPLCI;
++                                  p->i->onholdPLCI = 0;
++                              }
++                              if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x2) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2)) {
++                                  if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5] != 0) && (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4] != 0)) { 
++                                      // reason != 0x0000 == problem
++                                      p->i->onholdPLCI = 0;
++                                      p->i->state = CAPI_STATE_ONHOLD;
++                                      ast_log(LOG_WARNING, "unable to put PLCI=%#x onhold, REASON = %#x%#x, maybe you need to subscribe for this...\n",(int)FACILITY_IND_PLCI(CMSG),FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5],FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]);
++                                  } else {
++                                      // reason = 0x0000 == call on hold
++                                      p->i->state = CAPI_STATE_ONHOLD;
++                                      if (capidebug) 
++                                          ast_log(LOG_NOTICE, "PLCI=%#x put onhold\n",(int)FACILITY_IND_PLCI(CMSG));
++                                  }
++                              }
++                          }
++                          
++                          error = FACILITY_RESP(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber,FACILITY_IND_PLCI(CMSG),FACILITY_IND_FACILITYSELECTOR(CMSG),FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG));
++
++                          if (error != 0) {
++                              ast_log(LOG_ERROR,"error sending FACILITY_RESP (error=%#x)\n",error);
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_RESP (PLCI=%#x)\n",(int)FACILITY_IND_PLCI(CMSG));
++                              }
++                          }
++                          break;
++                      case CAPI_INFO:
++                          // ast_log(LOG_ERROR,"INFO_IND PLCI=%#x INFO# = %#x\n",PLCI,INFO_IND_INFONUMBER(CMSG));
++
++                          memset(&CMSG2,0,sizeof(_cmsg));
++                          error = INFO_RESP(&CMSG2,ast_capi_ApplID,CMSG->Messagenumber,PLCI);
++                          if (error != 0) {
++                              ast_log(LOG_ERROR,"error sending INFO_RESP (error=%#x)\n",error);
++                              return -1;
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent INFO_RESP (PLCI=%#x)\n",PLCI);
++                              }
++                          }
++/*                        if ((INFO_IND_INFONUMBER(CMSG) >> 8) == 0x00) {
++                              ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[0]);
++                              ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[1]);
++                              ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[2]);
++                              ast_log(LOG_ERROR,"%#x\n",INFO_IND_INFOELEMENT(CMSG)[3]);
++                          } */
++#ifndef CAPI_NEVER_EVER_EARLY_B3_CONNECTS
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x001e) && (p->i->doB3 != AST_CAPI_B3_DONT) && (p->i->earlyB3 == -1) && (p->i->state != CAPI_STATE_BCONNECTED)){
++                              // ETSI 300 102-1 Progress Indicator
++                              // we do early B3 Connect
++                                if(INFO_IND_INFOELEMENT(CMSG)[0] >= 2) {
++                                  if(INFO_IND_INFOELEMENT(CMSG)[2] & 0x2) {
++                                      p->i->calledPartyIsISDN = 0;
++                                      // ast_log(LOG_NOTICE,"A N A L O G \n");
++                                  } else {
++                                      p->i->calledPartyIsISDN = 1;
++                                      // ast_log(LOG_NOTICE,"I S D N\n");
++                                  }
++                                  if(INFO_IND_INFOELEMENT(CMSG)[2] & 0x88) {
++                                       // in-band info available
++                                      p->i->earlyB3 = 1;
++                                      memset(&CMSG2,0,sizeof(_cmsg));
++                                      CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++,0);
++                                      CONNECT_B3_REQ_PLCI(&CMSG2) = PLCI;
++                                      if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                                          ast_log(LOG_ERROR,"error sending early CONNECT_B3_REQ (error=%#x)\n",error);
++                                          return -1;
++                                      } else {
++                                          if (option_verbose > 1) {
++                                              if (capidebug)
++                                                  ast_verbose(VERBOSE_PREFIX_4 "sent early CONNECT_B3_REQ (PLCI=%#x)\n",PLCI);
++                                          }
++                                      }
++                                  }
++                              }
++                          }
++                          // DISCONNECT
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (PLCI == p->i->onholdPLCI)) {
++                              // the caller onhold hung up (or ECTed away)
++                              // send a disconnect_req , we cannot hangup the channel here!!!
++                              memset(&CMSG2,0,sizeof(_cmsg));
++                              DISCONNECT_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++                              DISCONNECT_REQ_PLCI(&CMSG2) = p->i->onholdPLCI;
++
++                              if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                                  ast_log(LOG_NOTICE, "error sending DISCONNECT_REQ PLCI=%#x\n",PLCI);
++                              } else {
++                                  if (option_verbose > 1) {
++                                      if (capidebug)
++                                          ast_verbose(VERBOSE_PREFIX_4 "sent DISCONNECT_REQ for onholdPLCI=%#x\n",PLCI);
++                                  }
++                              }                               
++                              return 0;
++                          }
++
++                          // case 1: B3 on success or no B3 at all
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->doB3 != AST_CAPI_B3_ALWAYS) && (p->i->outgoing == 1)) {
++                              p->i->earlyB3 = 0; // !!!
++                              fr.frametype = AST_FRAME_NULL;
++                              fr.datalen = 0;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          // case 2: we are doing B3, and receive the 0x8045 after a successful call
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->doB3 != AST_CAPI_B3_DONT) && (p->i->earlyB3 == 0) && (p->i->outgoing == 1)) {
++                              fr.frametype = AST_FRAME_NULL;
++                              fr.datalen = 0;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          // case 3: this channel is an incoming channel! the user hung up!
++                          // it is much better to hangup now instead of waiting for a timeout and
++                          // network caused DISCONNECT_IND!
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->outgoing == 0)) {
++                          // ast_log(LOG_NOTICE,"case 3\n");
++                              fr.frametype = AST_FRAME_NULL;
++                              fr.datalen = 0;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          // case 4 (a.k.a. the italian case): B3 always. call is unsuccessful
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x8045) && (p->i->doB3 == AST_CAPI_B3_ALWAYS) && (p->i->earlyB3 == -1) && (p->i->outgoing == 1)) {
++                              // wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network
++                              return 0;
++                          }
++#endif
++                          // Handle DID digits
++                          if ((INFO_IND_INFONUMBER(CMSG) == 0x0070) && p->i->isdnmode && (p->c != NULL)) {
++                              int search = -1;
++                              char name[AST_CHANNEL_NAME] = "";
++                              char *did;
++
++                              did = capi_number((char *)INFO_IND_INFOELEMENT(CMSG),1);
++                              if (strcasecmp(p->i->dnid, did)) {
++                                  strncat(p->i->dnid, did, sizeof(p->i->dnid)-1);
++                              }
++                              
++                              snprintf(name,sizeof(name),"CAPI/contr%d/%s/-%d",p->i->controller,p->i->dnid,capi_counter++);
++                              ast_change_name(p->c, name);
++                              
++                              search = search_did(p->c);
++                              if (search != -1) {
++                                  if (!search) {
++                                      ast_setstate(p->c, AST_STATE_RING);
++                                      // we are alerting (phones ringing)
++                                      capi_alert(p->c); // Do this here after pbx_start the Channel can be destroyed
++                                      if (ast_pbx_start(p->c)) {
++                                          ast_log(LOG_ERROR,"Unable to start pbx on channel!\n");
++                                          ast_hangup(p->c);
++                                      } else {
++                                          if (option_verbose > 2) {
++                                              if (capidebug)
++                                                  ast_verbose(VERBOSE_PREFIX_3 "started pbx on channel!\n");
++                                          }
++                                      }
++                                  }
++                              } else {
++                                  ast_log(LOG_ERROR,"did not find device for msn = %s\n",p->i->dnid);
++                                  CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++                                  CONNECT_RESP_PLCI(&CMSG2) = PLCI;
++                                  CONNECT_RESP_REJECT(&CMSG2) = 1; // ignore
++                                  if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                                      ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++                                  } else {
++                                      if (option_verbose > 5) {
++                                          if (capidebug)
++                                              ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++                                      }
++                                  }
++                                  
++                                  return 0;
++                              }
++                          }
++                          if (INFO_IND_INFONUMBER(CMSG) == 0x8001) {
++                              fr.frametype = AST_FRAME_CONTROL;
++                              fr.subclass = AST_CONTROL_RINGING;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          if (INFO_IND_INFONUMBER(CMSG) == 0x800d) {
++                              fr.frametype = AST_FRAME_CONTROL;
++                              fr.subclass = AST_CONTROL_PROGRESS;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          if (INFO_IND_INFONUMBER(CMSG) == 0x74) {
++                              strncpy(p->i->owner->exten,capi_number((char *)INFO_IND_INFOELEMENT(CMSG),3),sizeof(p->i->owner->exten)-1);
++                              ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(CMSG));
++                          }
++                          if (INFO_IND_INFONUMBER(CMSG) == 0x28) {
++                      //      ast_sendtext(p->i->owner,capi_number(INFO_IND_INFOELEMENT(CMSG),0));
++                      //      struct ast_frame ft = { AST_FRAME_TEXT, capi_number(INFO_IND_INFOELEMENT(CMSG),0), };
++                        //            ast_queue_frame(p->i->owner, &ft);
++                      //      ast_log(LOG_NOTICE,"%s\n",capi_number(INFO_IND_INFOELEMENT(CMSG),0));
++                          }
++                          break;
++                      case CAPI_CONNECT_ACTIVE:
++//                        ast_log(LOG_NOTICE,"CONNECT_ACTIVE_IND PLCI=%#x\n",(int)CONNECT_ACTIVE_IND_PLCI(CMSG));
++                          CONNECT_ACTIVE_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber,0);
++                          CONNECT_ACTIVE_RESP_PLCI(&CMSG2) = PLCI;
++                          if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                              ast_log(LOG_ERROR,"error sending CONNECT_ACTIVE_RESP (error=%#x)\n",error);
++                              return -1;
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_ACTIVE_RESP (PLCI=%#x)\n",PLCI);
++                              }
++                          }
++                          // normal processing
++                          if (p->i->earlyB3 != 1) {
++                              p->i->state = CAPI_STATE_CONNECTED;
++                          
++                              // send a CONNECT_B3_REQ
++                              if (p->i->outgoing == 1) {
++                                  // outgoing call
++                                  memset(&CMSG2,0,sizeof(_cmsg));
++                                  CONNECT_B3_REQ_HEADER(&CMSG2, ast_capi_ApplID, ast_capi_MessageNumber++,0);
++                                  CONNECT_B3_REQ_PLCI(&CMSG2) = PLCI;
++                                  if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                                      ast_log(LOG_ERROR,"error sending CONNECT_B3_REQ (error=%#x)\n",error);
++                                      return -1;
++                                  } else {
++                                      if (option_verbose > 1) {
++                                          if (capidebug)
++                                              ast_verbose(VERBOSE_PREFIX_3 "sent CONNECT_B3_REQ (PLCI=%#x)\n",PLCI);
++                                      }
++                                  }
++                              } else {
++                                  // incoming call
++                                  // RESP already sent ... wait for CONNECT_B3_IND
++//                                ast_log(LOG_NOTICE,"waiting for CONNECT_B3_IND\n");
++                              }
++                          } else {
++                              // special treatment for early B3 connects
++                              p->i->state = CAPI_STATE_BCONNECTED;
++                              if (p->c->_state != AST_STATE_UP) {
++                                  ast_setstate(p->c,AST_STATE_UP);
++                              }
++                              p->i->earlyB3 = 0;      // not early anymore
++                              fr.frametype = AST_FRAME_CONTROL;
++                              fr.subclass = AST_CONTROL_ANSWER;
++                              fr.datalen = 0;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                              
++                          }
++                          break;
++                      case CAPI_CONNECT_B3:
++                          // then send a CONNECT_B3_RESP
++                          memset(&CMSG2,0,sizeof(_cmsg));
++                          CONNECT_B3_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++                          CONNECT_B3_RESP_NCCI(&CMSG2) = CONNECT_B3_IND_NCCI(CMSG);
++                          p->NCCI = CONNECT_B3_IND_NCCI(CMSG);
++                          p->i->NCCI = p->NCCI;
++                          CONNECT_B3_RESP_REJECT(&CMSG2) = 0;
++
++                          if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                              ast_log(LOG_ERROR,"error sending CONNECT_B3_RESP (error=%#x)\n",error);
++                              return -1;
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_B3_RESP (NCCI=%#x)\n",p->i->NCCI);
++                              }
++                          }
++              /*          if (p->i->controller > 0) {
++                              capi_controllers[p->i->controller]->nfreebchannels--;
++                          } */
++                          break; 
++                      case CAPI_CONNECT_B3_ACTIVE:
++//                        ast_log(LOG_NOTICE,"CONNECT_B3_ACTIVE_IND NCCI=%#x\n",p->i->NCCI);
++                          // then send a CONNECT_B3__ACTIVERESP
++
++                          CONNECT_B3_ACTIVE_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++                          CONNECT_B3_ACTIVE_RESP_NCCI(&CMSG2) = p->i->NCCI;
++
++                          if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                              ast_log(LOG_ERROR,"error sending CONNECT_B3_ACTIVE_RESP (error=%#x)\n",error);
++                              return -1;
++                          } else {
++                              if (option_verbose > 5) {
++                                  if (capidebug)
++                                      ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_B3_ACTIVE_RESP (NCCI=%#x)\n",p->i->NCCI);
++                              }
++                          }
++
++                          ast_mutex_lock(&contrlock);
++                          if (p->i->controller > 0) {
++                              capi_controllers[p->i->controller]->nfreebchannels--;
++                          }
++                          ast_mutex_unlock(&contrlock);
++
++                          p->i->state = CAPI_STATE_BCONNECTED;
++                          capi_echo_canceller(p->c,EC_FUNCTION_ENABLE);
++                          capi_detect_dtmf(p->c,1);
++
++                          if (p->i->earlyB3 != 1) {
++                              ast_setstate(p->c,AST_STATE_UP);
++                              fr.frametype = AST_FRAME_CONTROL;
++                              fr.subclass = AST_CONTROL_ANSWER;
++                              fr.datalen = 0;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          return 0;
++                          break;
++                  }
++                  break;
++
++              case CAPI_CONF:
++                  switch (CMSG->Command) {
++                      case CAPI_FACILITY:
++                          if (FACILITY_CONF_FACILITYSELECTOR(CMSG) == 0x3) {
++                              if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[1] == 0x2) && (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[2] == 0x0)) {
++                                  if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[4] == 0x0) && (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(CMSG)[5] == 0x0)) {
++                                  } else {
++                                      p->i->state = CAPI_STATE_BCONNECTED;
++                                      if (capidebug)
++                                          ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(CMSG));
++                                  }
++                              }
++                          }
++                          break;
++                      case CAPI_DATA_B3:
++//                        ast_log(LOG_NOTICE,"DATA_B3_CONF (NCCI %#x) for DATAHANDLE %#x\n",DATA_B3_CONF_NCCI(CMSG),DATA_B3_CONF_DATAHANDLE(CMSG));
++                          break;
++                      case CAPI_ALERT:
++//                        ast_log(LOG_NOTICE,"ALERT_CONF (PLCI=%#x)\n",(int)ALERT_CONF_PLCI(CMSG));
++                          p->i->state = CAPI_STATE_ALERTING;
++                          if (p->c->_state == AST_STATE_RING) {
++                              p->c->rings = 1;
++                          }
++                          break;
++                      case CAPI_CONNECT:
++                          if (option_verbose > 1) {
++                              if (capidebug)
++                                  ast_verbose(VERBOSE_PREFIX_2 "received CONNECT_CONF PLCI = %#x INFO = %#x\n",(int)CONNECT_CONF_PLCI(CMSG),CONNECT_CONF_INFO(CMSG));
++                          }
++                          if (CONNECT_CONF_INFO(CMSG) == 0) {
++                              p->i->PLCI = CONNECT_CONF_PLCI(CMSG);
++                              p->PLCI = p->i->PLCI;
++                              ast_setstate(p->c,AST_STATE_DIALING);
++                          } else {
++      // here, something has to be done -->
++                              fr.frametype = AST_FRAME_CONTROL;
++                              fr.subclass = AST_CONTROL_BUSY;
++                              fr.datalen = 0;
++                              return pipe_frame(p,(struct ast_frame *)&fr);
++                          }
++                          break;
++                      case CAPI_CONNECT_B3:
++//                        ast_log(LOG_NOTICE,"received CONNECT_B3_CONF NCCI = %#x INFO = %#x\n",(int)CONNECT_B3_CONF_NCCI(CMSG),CONNECT_B3_CONF_INFO(CMSG));
++                          if (CONNECT_B3_CONF_INFO(CMSG) == 0) {
++                              p->i->NCCI = CONNECT_B3_CONF_NCCI(CMSG);
++                          } else {
++                              p->i->earlyB3 = -1;
++                              p->i->doB3 = AST_CAPI_B3_DONT;
++                          }
++                          break;
++                  }
++                  break;                  
++          }
++      }
++//    ast_log(LOG_NOTICE,"returning\n");
++      return 0;
++}
++
++static void capi_handle_msg(_cmsg *CMSG) {
++    struct ast_capi_pvt *i;
++    char *DNID;
++    char *CID;
++    char *msn;
++    _cmsg CMSG2;
++    MESSAGE_EXCHANGE_ERROR  error;
++    int PLCI=0,NCCI;
++    int NPLAN=0;
++    int fds[2];
++    int controller=0;
++    char buffer[AST_MAX_EXTENSION];
++    struct capi_pipe *p;
++    char *magicmsn = "*\0";
++    char *emptyid = "\0";
++    char *emptydnid = "s\0";
++    long flags;
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++    int deflect=0;
++#endif
++    
++    switch (CMSG->Subcommand) {
++      // indication msgs      
++      case CAPI_IND:
++
++      switch (CMSG->Command) {
++          case CAPI_CONNECT:  // only connect_ind are global (not channel specific)
++              if (capidebug)
++                  ast_log(LOG_NOTICE,"%s\n",capi_cmsg2str(CMSG));
++              DNID = capi_number((char *)CONNECT_IND_CALLEDPARTYNUMBER(CMSG),1);
++              if ((DNID && *DNID == 0) || !DNID) {
++                  DNID = emptydnid;
++              }
++                NPLAN = (CONNECT_IND_CALLINGPARTYNUMBER(CMSG)[1] & 0x70);
++              CID = capi_number((char *)CONNECT_IND_CALLINGPARTYNUMBER(CMSG),2);
++              PLCI = CONNECT_IND_PLCI(CMSG);
++              controller = PLCI & 0xff;
++              if (option_verbose > 1) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_2 "CONNECT_IND (PLCI=%#x,DID=%s,CID=%s,CIP=%#x,CONTROLLER=%#x)\n",PLCI,DNID,CID,CONNECT_IND_CIPVALUE(CMSG),controller);
++              }
++              if(CONNECT_IND_BCHANNELINFORMATION(CMSG))
++              if ((CONNECT_IND_BCHANNELINFORMATION(CMSG)[1] == 0x02) && (!capi_controllers[controller]->isdnmode)) {
++                  // this is a call waiting CONNECT_IND with BChannelinformation[1] == 0x02
++                  // meaning "no B or D channel for this call", since we can't do anything with call waiting now
++                  // just reject it with "user busy"
++                  // however...if we are a p2p BRI then the telco switch will allow us to choose the b channel
++                  // so it will look like a callwaiting connect_ind to us
++
++                    ast_log(LOG_ERROR,"received a call waiting CONNECT_IND\n");
++#ifndef CAPI_DEFLECT_ON_CIRCUITBUSY
++                  CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++                    CONNECT_RESP_PLCI(&CMSG2) = CONNECT_IND_PLCI(CMSG);
++                    CONNECT_RESP_REJECT(&CMSG2) = 3; // user is busy
++                    if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                       ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++                  } else {
++                       if (option_verbose > 5) {
++                          if (capidebug)
++                              ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++                     }
++                  }
++                    // no need to pipe this
++                    PLCI = 0;
++                  break;              
++#else
++                  deflect = 1;
++#endif
++              }
++              // well...somebody is calling us. let's set up a channel
++              ast_mutex_lock(&iflock);
++              i = iflist;
++              while(i) {
++                  //XXX test this!
++                  // has no owner
++                  if ((!i->owner) && (i->incomingmsn != NULL)){
++                      strncpy(buffer,i->incomingmsn,sizeof(buffer)-1);
++                      msn = strtok(buffer,",");
++                      while (msn != NULL) {
++//                    ast_log(LOG_NOTICE,"msn=%s\n",msn);
++                          if (DNID && ((!strcasecmp(msn,DNID)) ||
++                               (i->isdnmode && (strlen(msn)<strlen(DNID)) && !strncasecmp(msn, DNID, strlen(msn))) || (!strncasecmp(msn,magicmsn,strlen(msn)))) && 
++                              (i->controllers & (1 << controller))) {
++                              if (CID != NULL) {
++                                  if(NPLAN == CAPI_ETSI_NPLAN_NATIONAL)
++                                      snprintf(i->cid, (sizeof(i->cid)-1), "%s%s%s", i->prefix, capi_national_prefix, CID);
++                                  else if(NPLAN == CAPI_ETSI_NPLAN_INTERNAT)
++                                      snprintf(i->cid, (sizeof(i->cid)-1), "%s%s%s", i->prefix, capi_international_prefix, CID);
++                                  else
++                                      snprintf(i->cid, (sizeof(i->cid)-1), "%s%s", i->prefix, CID);
++                              } else
++                                  strncpy(i->cid,emptyid,sizeof(i->cid)-1);
++
++                              if (DNID != NULL) 
++                                  strncpy(i->dnid,DNID,sizeof(i->dnid)-1);
++                              else
++                                  strncpy(i->dnid,emptydnid,sizeof(i->dnid)-1);
++                              
++                              i->controller=controller;
++                              i->PLCI = PLCI;
++                              i->MessageNumber = CMSG->Messagenumber;
++                              if (pipe(fds) == 0) {
++                                  if (option_verbose > 4) {
++                                      ast_verbose(VERBOSE_PREFIX_3 "creating pipe for PLCI=%#x msn = %s\n",PLCI,msn);
++                                  }
++                                  i->fd = fds[0];
++                                  flags = fcntl(i->fd,F_GETFL);
++                                  fcntl(i->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++//                                ast_log(LOG_NOTICE,"i->fd = %d\n",i->fd);
++                                  p = malloc(sizeof(struct capi_pipe));
++                                  memset(p, 0, sizeof(struct capi_pipe));
++                                  p->fd = fds[1];
++                                  flags = fcntl(i->fd,F_GETFL);
++                                  fcntl(p->fd,F_SETFL,flags | O_SYNC | O_DIRECT);
++//                                ast_log(LOG_NOTICE,"p->fd = %d\n",p->fd);
++                                  p->PLCI = PLCI;
++                                  p->i = i;
++                                  ast_mutex_init(&(p->lock));
++                                  i->mypipe = p;
++                                  if (i->isdnmode) {
++                                      p->c = capi_new(i,AST_STATE_DOWN);
++                                      i->state = CAPI_STATE_DID;
++                                  } else {
++                                      p->c = capi_new(i,AST_STATE_RING);
++                                  }
++                                  p->next = pipelist;
++                                  pipelist = p;
++                              // hmmm....
++                                  ast_mutex_unlock(&iflock);
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++                                  if ((deflect == 1) && (i->deflect2)) {
++                                      capi_deflect(p->c,i->deflect2);
++                                  }
++#endif
++                                  return;
++                              } else {
++                                  ast_log(LOG_ERROR,"creating pipe for PLCI=%#x failed\n",PLCI);
++                              }
++                              break;
++                          } // if strcasecmp
++                          msn = strtok(NULL,",");
++                      } // while strtok
++                  } // if
++                  i = i->next;
++              } // while interface list
++              ast_mutex_unlock(&iflock);              // obviously we are not called...so tell capi to ignore this call
++              if (capidebug) {
++                  ast_log(LOG_ERROR,"did not find device for msn = %s\n",DNID);
++              }
++              CONNECT_RESP_HEADER(&CMSG2, ast_capi_ApplID, CMSG->Messagenumber, 0);
++              CONNECT_RESP_PLCI(&CMSG2) = CONNECT_IND_PLCI(CMSG);
++              CONNECT_RESP_REJECT(&CMSG2) = 1; // ignore
++              if ((error = _capi_put_cmsg(&CMSG2)) != 0) {
++                  ast_log(LOG_ERROR,"error sending CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++              } else {
++                  if (option_verbose > 5) {
++                      if (capidebug)
++                          ast_verbose(VERBOSE_PREFIX_4 "sent CONNECT_RESP for PLCI = %#x\n",(int)CONNECT_IND_PLCI(CMSG));
++                  }
++              }
++              ast_mutex_lock(&pipelock);
++              if (pipelist == NULL) {
++                  capi_last_plci = PLCI;
++              }
++              ast_mutex_unlock(&pipelock);
++              // no need to pipe this
++              PLCI = 0;
++//            ast_mutex_unlock(&iflock);
++//            return;
++              break;
++          case CAPI_FACILITY:
++              PLCI = FACILITY_IND_PLCI(CMSG) & 0xffff;  // this is for you eicon
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"FACILITY_IND PLCI=%#x\n",PLCI);
++          break;
++          case CAPI_INFO:
++              PLCI = INFO_IND_PLCI(CMSG);
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"INFO_IND PLCI=%#x INFO# = %#x\n",PLCI,INFO_IND_INFONUMBER(CMSG));
++          break;
++          case CAPI_CONNECT_ACTIVE:
++              PLCI = CONNECT_ACTIVE_IND_PLCI(CMSG);
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"CONNECT_ACTIVE_IND PLCI=%#x\n",PLCI);
++          break;
++          case CAPI_CONNECT_B3:
++              NCCI = CONNECT_B3_IND_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"CONNECT_B3_IND NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++          break;
++          case CAPI_CONNECT_B3_ACTIVE:
++              NCCI = CONNECT_B3_IND_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"CONNECT_B3_ACTIVE_IND NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++          break;
++          case CAPI_DATA_B3:
++              NCCI = DATA_B3_IND_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++//            ast_log(LOG_ERROR,"DATA_B3_IND NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++          break;
++          case CAPI_DISCONNECT_B3:
++              NCCI = DISCONNECT_B3_IND_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 1) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_2 "DISCONNECT_B3_IND NCCI=%#x\n",NCCI);
++              }
++          break;
++          case CAPI_DISCONNECT:
++              PLCI = DISCONNECT_IND_PLCI(CMSG);
++              if (option_verbose > 1) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_2 "DISCONNECT_IND PLCI=%#x REASON=%#x\n",PLCI,DISCONNECT_IND_REASON(CMSG));
++              }
++          break;
++          default:
++              ast_log(LOG_ERROR,"Command.Subcommand = %#x.%#x\n",CMSG->Command,CMSG->Subcommand);
++      }
++      break;
++      // confirmation msgs
++      case CAPI_CONF:
++      switch (CMSG->Command) {
++          case CAPI_FACILITY:
++              NCCI = FACILITY_CONF_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 2) {
++                      if (FACILITY_CONF_FACILITYSELECTOR(CMSG) == 6) {
++                              if (FACILITY_CONF_INFO(CMSG)) 
++                                      ast_verbose (VERBOSE_PREFIX_3 "Error setting up echo canceller (PLCI=%#x, Info=%#04x)\n", PLCI, FACILITY_CONF_INFO(CMSG));
++                              else
++                                      ast_verbose (VERBOSE_PREFIX_3 "Echo canceller successfully set up (PLCI=%#x)\n",PLCI);
++                      }
++              }
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"FACILITY_CONF NCCI=%#x INFO=%#x\n",(int)FACILITY_CONF_NCCI(CMSG),FACILITY_CONF_INFO(CMSG));
++          break;
++          case CAPI_INFO:
++              PLCI = INFO_CONF_PLCI(CMSG);
++//            ast_log(LOG_ERROR,"INFO_CONF PLCI=%#x INFO=%#x\n",PLCI,INFO_CONF_INFO(CMSG));
++          break;
++          case CAPI_CONNECT:
++              PLCI = CONNECT_CONF_PLCI(CMSG);
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"CONNECT_CONF PLCI=%#x INFO=%#x MN=%#x\n",PLCI,CONNECT_CONF_INFO(CMSG),CMSG->Messagenumber);
++          break;
++          case CAPI_DISCONNECT:
++              PLCI = DISCONNECT_CONF_PLCI(CMSG);
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"DISCONNECT_CONF PLCI=%#x INFO=%#x MN=%#x\n",PLCI,DISCONNECT_CONF_INFO(CMSG),CMSG->Messagenumber);
++          break;
++          case CAPI_DISCONNECT_B3:
++              NCCI = DISCONNECT_B3_CONF_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"DISCONNECT_B3_CONF NCCI=%#x INFO=%#x MN=%#x\n",NCCI,DISCONNECT_B3_CONF_INFO(CMSG),CMSG->Messagenumber);
++          break;
++          case CAPI_CONNECT_B3:
++              NCCI = CONNECT_B3_CONF_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//                ast_log(LOG_ERROR,"CONNECT_B3_CONF PLCI=%#x INFO=%#x MN=%#x\n",PLCI,CONNECT_B3_CONF_INFO(CMSG),CMSG->Messagenumber);
++          break;
++          case CAPI_ALERT:
++              PLCI = ALERT_CONF_PLCI(CMSG);
++              if (option_verbose > 3) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"ALERT_CONF PLCI=%#x\n",PLCI);
++          break;          
++          case CAPI_DATA_B3:
++              NCCI = DATA_B3_CONF_NCCI(CMSG);
++              PLCI = (NCCI << 16) >> 16;
++              if (option_verbose > 5) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(CMSG));
++              }
++//            ast_log(LOG_ERROR,"DATA_B3_CONF NCCI=%#x PLCI=%#x\n",NCCI,PLCI);
++          break;
++          default:
++              ast_log(LOG_ERROR,"Command.Subcommand = %#x.%#x\n",CMSG->Command,CMSG->Subcommand);
++      }
++      break;
++    }
++    if (PLCI > 0) {
++      pipe_msg(PLCI,CMSG);
++    }
++
++}
++
++// module stuff, monitor...
++
++static void *do_monitor(void *data) {
++   unsigned int Info;
++    _cmsg *monCMSG;
++    for (;;) {
++/*
++      if (ast_mutex_lock(&monlock)) {
++          ast_log(LOG_ERROR,"Unable to get monitor lock!\n");
++          return NULL;
++      }
++      // do some nifty stuff
++      ast_mutex_unlock(&monlock);
++*/
++      monCMSG = malloc(sizeof(_cmsg));
++      memset(monCMSG,0,sizeof(_cmsg));
++      switch(Info = check_wait_get_cmsg(monCMSG)) {
++          case 0x0000:
++              if (option_verbose > 8) {
++                  if (capidebug)
++                      ast_verbose(VERBOSE_PREFIX_3 "%s\n",capi_cmsg2str(monCMSG));
++              }
++              capi_handle_msg(monCMSG);
++              break;
++          case 0x1104:
++              // CAPI queue is empty
++              break;
++          default:
++              // something is wrong!
++               break;
++      } //switch
++      free(monCMSG);
++    } // for
++    // never reached
++    return NULL;
++}
++
++#ifdef CAPI_GAIN
++static void capi_gains(struct ast_capi_gains *g,float rxgain,float txgain) {
++    int i=0;
++    int x=0;
++    if (rxgain != 1.0) {
++      for (i=0;i<256;i++) {
++          x = (int)(((float)capiXLAW2INT(i)) * rxgain);
++          if (x > 32767) x = 32767;
++          if (x < -32767) x = -32767;
++          g->rxgains[i] = capiINT2XLAW(x);
++      }
++    } else {
++      for (i=0;i<256;i++) {
++          g->rxgains[i] = i;
++      }
++    }
++    if (txgain != 1.0) {
++      for (i=0;i<256;i++) {
++          x = (int)(((float)capiXLAW2INT(i)) * txgain);
++          if (x > 32767) x = 32767;
++          if (x < -32767) x = -32767;
++          g->txgains[i] = capiINT2XLAW(x);
++      }
++    } else {
++      for (i=0;i<256;i++) {
++          g->txgains[i] = i;
++      }
++    }
++    
++}
++#endif
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++int mkif(char *incomingmsn,char *context,char *controllerstr,int devices,int softdtmf,int echocancel,int ecoption,int ectail, char *prefix, int isdnmode, int es,float rxgain,float txgain, char *deflect2, char *accountcode, unsigned int callgroup, unsigned int group) {
++#else
++int mkif(char *incomingmsn,char *context,char *controllerstr,int devices,int softdtmf,int echocancel,int ecoption,int ectail, char *prefix, int isdnmode, int es,float rxgain,float txgain, char *accountcode, unsigned int callgroup, unsigned int group) {
++#endif
++    struct ast_capi_pvt *tmp;
++    int i=0;
++    char buffer[100];
++    char *contr;
++    unsigned long contrmap=0;
++
++    for (i=0;i<devices;i++) {
++      tmp = malloc(sizeof(struct ast_capi_pvt));
++      memset(tmp, 0, sizeof(struct ast_capi_pvt));
++      if (tmp) {
++          ast_mutex_init(&(tmp->lock));
++          strncpy(tmp->context, context, sizeof(tmp->context)-1);
++          strncpy(tmp->incomingmsn, incomingmsn, sizeof(tmp->incomingmsn)-1);
++          strncpy(tmp->prefix, prefix, sizeof(tmp->prefix)-1);
++          strncpy(tmp->accountcode, accountcode, sizeof(tmp->accountcode)-1);
++          
++          strncpy(buffer,controllerstr,sizeof(buffer)-1);
++          contr = strtok(buffer,",");
++          while (contr != NULL) {
++              contrmap |= (1 << atoi(contr));
++              if (capi_controllers[atoi(contr)]) {
++                  capi_controllers[atoi(contr)]->isdnmode = isdnmode;
++              //    ast_log(LOG_NOTICE, "contr %d isdnmode %d\n",atoi(contr),isdnmode);
++              }
++              contr = strtok(NULL,",");
++          }
++          tmp->controllers = contrmap;
++          capi_used_controllers |= contrmap;
++          tmp->controller = 0;
++          tmp->CLIR = 0;
++          tmp->earlyB3 = -1;
++          tmp->onholdPLCI = 0;
++          tmp->doEC = echocancel;
++          tmp->ecOption = ecoption;
++          tmp->ecTail = ectail;
++          tmp->isdnmode = isdnmode;
++          tmp->doES = es;
++          tmp->callgroup = callgroup;
++          tmp->group = group;
++#ifdef CAPI_ES            
++#endif
++#ifdef CAPI_GAIN
++          tmp->rxgain = rxgain;
++          tmp->txgain = txgain;
++          capi_gains(&tmp->g,rxgain,txgain);
++#endif
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++          strncpy(tmp->deflect2, deflect2, sizeof(tmp->deflect2)-1);
++#endif
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++          if (softdtmf == 1) {
++#endif
++              tmp->doDTMF = 1;
++#ifndef CAPI_FORCE_SOFTWARE_DTMF
++          } else {
++              tmp->doDTMF = 0;
++          }
++#endif
++          tmp->next = iflist; // prepend
++          iflist = tmp;
++      //          ast_log(LOG_NOTICE, "ast_capi_pvt(%s,%s,%#x,%d) (%d,%d,%d) (%d)(%f/%f) %d\n",tmp->incomingmsn,tmp->context,(int)tmp->controllers,devices,tmp->doEC,tmp->ecOption,tmp->ecTail,tmp->doES,tmp->rxgain,tmp->txgain,callgroup);
++          if (option_verbose > 2) {
++                  ast_verbose(VERBOSE_PREFIX_2 "ast_capi_pvt(%s,%s,%d,%d) (%d,%d,%d)\n",tmp->incomingmsn,tmp->context,tmp->controller,devices,tmp->doEC,tmp->ecOption,tmp->ecTail);
++          }
++          
++      } else {
++          return -1;
++      }
++    }
++    return 0;
++}
++
++void supported_sservices(struct ast_capi_controller *cp) {
++    MESSAGE_EXCHANGE_ERROR error;
++    _cmsg     CMSG,CMSG2;
++    struct timeval tv;
++    char fac[20];
++
++    FACILITY_REQ_HEADER(&CMSG, ast_capi_ApplID, ast_capi_MessageNumber++, 0);
++    FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller;
++    FACILITY_REQ_FACILITYSELECTOR(&CMSG) = 0x0003; // sservices
++    fac[0] = 3;
++    fac[1] = 0;
++    fac[2] = 0;
++    fac[3] = 0;
++    FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (unsigned char *)&fac;
++    if ((error= _capi_put_cmsg(&CMSG)) != 0) {
++      ast_log(LOG_ERROR,"error sending FACILITY_REQ (error=%#x)\n",error);
++    } else {
++        if (option_verbose > 5) {
++          ast_verbose(VERBOSE_PREFIX_4 "sent FACILITY_REQ (CONTROLLER=%#x)\n",cp->controller);
++      }
++    }
++
++    tv.tv_sec = 1;
++    tv.tv_usec = 0;
++    for (;;){
++        error = capi20_waitformessage(ast_capi_ApplID,&tv);
++        error = capi_get_cmsg(&CMSG2,ast_capi_ApplID); 
++//        error = check_wait_get_cmsg(&CMSG2);
++      if (error == 0) {
++              if (IS_FACILITY_CONF(&CMSG2)) {
++                  if (option_verbose > 5) {
++                      ast_verbose(VERBOSE_PREFIX_4 "FACILITY_CONF INFO = %#x\n",FACILITY_CONF_INFO(&CMSG2));
++                  }
++                  break;
++              }
++      }
++    } 
++    // parse supported sservices
++    if (FACILITY_CONF_FACILITYSELECTOR(&CMSG2) == 0x0003) {
++      // success
++      if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[4] == 0) {
++          if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 1) == 1) {
++              cp->holdretrieve = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "HOLD/RETRIEVE\n");
++          } else {
++              cp->holdretrieve = 0;   
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 2) >> 1) == 1) {
++              cp->terminalportability = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "TERMINAL PORTABILITY\n");
++          } else {
++              cp->terminalportability = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 4) >> 2) == 1) {
++              cp->ECT = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "ECT\n");
++          } else {
++              cp->ECT = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 8) >> 3) == 1) {
++              cp->threePTY = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "3PTY\n");
++          } else {
++              cp->threePTY = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 16) >> 4) == 1) {
++              cp->CF = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "CF\n");
++          } else {
++              cp->CF = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 32) >> 5) == 1) {
++              cp->CD = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "CD\n");
++          } else {
++              cp->CD = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 64) >> 6) == 1) {
++              cp->MCID = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "MCID\n");
++          } else {
++              cp->MCID = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[6] & 128) >> 7) == 1) {
++              cp->CCBS = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "CCBS\n");
++          } else {
++              cp->CCBS = 0;
++          }
++          if ((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 1) == 1) {
++              cp->MWI = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "MWI\n");
++          } else {
++              cp->MWI = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 2) >> 1) == 1) {
++              cp->CCNR = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "CCNR\n");
++          } else {
++              cp->CCNR = 0;
++          }
++          if (((FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[7] & 4) >> 2) == 1) {
++              cp->CONF = 1;
++              if (option_verbose > 3)
++                  ast_verbose(VERBOSE_PREFIX_4 "CONF\n");
++          } else {
++              cp->CONF = 0;
++          }
++      } else {
++          ast_log(LOG_NOTICE,"supplementary services info  = %#x\n",(short)FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG2)[1]);
++      }
++    } else  {
++      ast_log(LOG_NOTICE,"unexpected FACILITY_SELECTOR = %#x\n",FACILITY_CONF_FACILITYSELECTOR(&CMSG2));
++    }
++}
++
++static int capi_info(int fd, int argc, char *argv[])
++{
++      int i=0;
++      if (argc != 2)
++              return RESULT_SHOWUSAGE;
++      for (i=1;i<=capi_num_controllers;i++) {
++          ast_mutex_lock(&contrlock);
++          if (capi_controllers[i] != NULL) {
++              ast_cli(fd,"Contr%d: %d B channels total, %d B channels free.\n",i,capi_controllers[i]->nbchannels,capi_controllers[i]->nfreebchannels);
++          }
++          ast_mutex_unlock(&contrlock);
++      }
++      return RESULT_SUCCESS;
++}
++
++static int capi_do_debug(int fd, int argc, char *argv[])
++{
++      if (argc != 2)
++              return RESULT_SHOWUSAGE;
++      capidebug = 1;
++      ast_cli(fd, "CAPI Debugging Enabled\n");
++      return RESULT_SUCCESS;
++}
++
++static int capi_no_debug(int fd, int argc, char *argv[])
++{
++      if (argc != 3)
++              return RESULT_SHOWUSAGE;
++      capidebug = 0;
++      ast_cli(fd, "CAPI Debugging Disabled\n");
++      return RESULT_SUCCESS;
++}
++
++static char info_usage[] = 
++"Usage: capi info\n"
++"       Show info about B channels.\n";
++
++static char debug_usage[] = 
++"Usage: capi debug\n"
++"       Enables dumping of CAPI packets for debugging purposes\n";
++
++static char no_debug_usage[] = 
++"Usage: capi no debug\n"
++"       Disables dumping of CAPI packets for debugging purposes\n";
++
++static struct ast_cli_entry  cli_info =
++      { { "capi", "info", NULL }, capi_info, "Show CAPI info", info_usage };
++static struct ast_cli_entry  cli_debug =
++      { { "capi", "debug", NULL }, capi_do_debug, "Enable CAPI debugging", debug_usage };
++static struct ast_cli_entry  cli_no_debug =
++      { { "capi", "no", "debug", NULL }, capi_no_debug, "Disable CAPI debugging", no_debug_usage };
++
++static const struct ast_channel_tech capi_tech = {
++      .type = type,
++      .description = tdesc,
++#ifdef CAPI_ULAW
++      .capabilities = AST_FORMAT_ULAW,
++#else
++      .capabilities = AST_FORMAT_ALAW,
++#endif
++      .requester = capi_request,
++      .send_digit = capi_send_digit,
++      .send_text = NULL,
++      .call = capi_call,
++      .hangup = capi_hangup,
++      .answer = capi_answer,
++      .read = capi_read,
++      .write = capi_write,
++      .bridge = NULL,
++      .exception = NULL,
++      .indicate = capi_indicate,
++      .fixup = capi_fixup,
++      .setoption = NULL,
++};
++
++int load_module(void)
++{
++      struct ast_config *cfg;
++      struct ast_variable *v;
++      char *config = "capi.conf";
++      char incomingmsn[AST_MAX_EXTENSION]="";
++      char context[AST_MAX_EXTENSION]="";
++      char prefix[AST_MAX_EXTENSION]="";
++      char accountcode[20]="";
++      char *empty = "\0";
++      char deflect2[AST_MAX_EXTENSION]="";
++      char controllerstr[AST_MAX_EXTENSION]="";
++      int res = 0;
++      int controller=0;
++      int softdtmf=0;
++      int echocancel=1;
++      int ecoption=EC_OPTION_DISABLE_G165;
++      int ectail=EC_DEFAULT_TAIL;
++      int es=0;
++      float rxgain = 1.0;
++      float txgain = 1.0;
++      int isdnmode = 0;
++      unsigned int callgroup=0;
++      unsigned int group=0;
++      struct ast_capi_controller *cp;
++
++      cfg = ast_config_load(config);
++
++      /* We *must* have a config file otherwise stop immediately, well no... */
++      if (!cfg) {
++              ast_log(LOG_ERROR, "Unable to load config %s, CAPI disabled\n", config);
++              return 0;
++      }
++      if (ast_mutex_lock(&iflock)) {
++              ast_log(LOG_ERROR, "Unable to lock interface list???\n");
++              return -1;
++      }
++
++      strncpy(capi_national_prefix, AST_CAPI_NATIONAL_PREF, sizeof(capi_national_prefix)-1);
++      strncpy(capi_international_prefix, AST_CAPI_NATIONAL_PREF, sizeof(capi_national_prefix)-1);
++      v = ast_variable_browse(cfg, "general");
++      while(v) {
++              if (!strcasecmp(v->name, "nationalprefix")) {
++                  strncpy(capi_national_prefix, v->value, sizeof(capi_national_prefix)-1);
++              } else if (!strcasecmp(v->name, "internationalprefix")) {
++                      strncpy(capi_international_prefix, v->value, sizeof(capi_international_prefix)-1);
++              } else if (!strcasecmp(v->name, "rxgain")) {
++                      if (sscanf(v->value,"%f",&rxgain) != 1) {
++                          ast_log(LOG_ERROR,"invalid rxgain\n");
++                      }
++              } else if (!strcasecmp(v->name, "txgain")) {
++                      if (sscanf(v->value,"%f",&txgain) != 1) {
++                          ast_log(LOG_ERROR,"invalid txgain\n");
++                      }
++              }
++              v = v->next;
++      }
++
++
++
++      
++      if (capi20_isinstalled() != 0) {
++          ast_log(LOG_WARNING,"CAPI not installed, CAPI disabled!\n");
++          return 0;
++      }
++
++      if (capi20_register(AST_CAPI_BCHANS,AST_CAPI_MAX_B3_BLOCKS,AST_CAPI_MAX_B3_BLOCK_SIZE,&ast_capi_ApplID) != 0) {
++          ast_log(LOG_NOTICE,"unable to register application at CAPI!\n");
++          return -1;
++      }
++
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++      if (capi20_get_profile(0,&profile) != 0) {
++#else
++      if (capi20_get_profile(0,(unsigned char *)&profile) != 0) {
++#endif
++          ast_log(LOG_NOTICE,"unable to get CAPI profile!\n");
++          return -1;
++      } else {
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++          capi_num_controllers = profile.wCtlr;
++#else
++          capi_num_controllers = profile.ncontrollers;
++#endif
++          if (option_verbose > 3)
++          ast_verbose(VERBOSE_PREFIX_3 "This box has %d capi controller(s).\n",capi_num_controllers);
++          for (controller=1;controller<=capi_num_controllers;controller++) {
++
++              memset(&profile,0,sizeof(profile));
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++              capi20_get_profile(controller,&profile);
++#else
++              capi20_get_profile(controller,(unsigned char *)&profile);
++#endif
++              cp = malloc(sizeof(struct ast_capi_controller));
++              cp->controller = controller;
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++              cp->nbchannels = profile.wNumBChannels;
++              cp->nfreebchannels = profile.wNumBChannels;
++              if (profile.dwGlobalOptions & CAPI_PROFILE_DTMF_SUPPORT) {
++#else
++              cp->nbchannels = profile.nbchannels;
++              cp->nfreebchannels = profile.nbchannels;
++              if ((profile.globaloptions & 8) >> 3 == 1) {
++#endif
++                  if (option_verbose > 3)
++                      ast_verbose(VERBOSE_PREFIX_3 "CAPI/contr%d supports DTMF\n",controller);
++                  cp->dtmf = 1;
++              } else {
++                  cp->dtmf = 0;           
++              }
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++              if (profile.dwGlobalOptions & CAPI_PROFILE_ECHO_CANCELLATION) {
++#else
++              if (profile.globaloptions2 & 1) {
++#endif
++                  if (option_verbose > 3)
++                      ast_verbose(VERBOSE_PREFIX_3 "CAPI/contr%d supports echo cancellation\n",controller);
++                  cp->echocancel = 1;
++              } else {
++                  cp->echocancel = 0;
++              }
++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
++              if (profile.dwGlobalOptions & CAPI_PROFILE_SUPPLEMENTARY_SERVICES)  {
++#else
++              if ((profile.globaloptions & 16) >> 4 == 1) {
++#endif
++                  cp->sservices = 1;
++              } else {
++                  cp->sservices = 0;      
++              }
++              capi_controllers[controller] = cp;
++              if (cp->sservices == 1) {
++                  if (option_verbose > 3)
++                      ast_verbose(VERBOSE_PREFIX_3 "CAPI/contr%d supports supplementary services\n",controller);
++                  supported_sservices(cp);
++              }
++          }
++      }
++
++      v = ast_variable_browse(cfg, "interfaces");
++      while(v) {
++              /* Create the interface list */
++              if (!strcasecmp(v->name, "devices")) {
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++                      if (mkif(incomingmsn,context,controllerstr,atoi(v->value),softdtmf,echocancel,ecoption,ectail, prefix, isdnmode, es,rxgain,txgain,deflect2,accountcode,callgroup, group)) {
++#else
++                      if (mkif(incomingmsn,context,controllerstr,atoi(v->value),softdtmf,echocancel,ecoption,ectail, prefix, isdnmode, es,rxgain,txgain,accountcode,callgroup, group)) {
++#endif
++                          ast_log(LOG_ERROR,"Error creating interface list\n");
++                          return -1;
++                      }
++                      es=0; 
++                      strncpy(deflect2, empty, sizeof(deflect2)-1);
++              } else if (!strcasecmp(v->name, "context")) {
++                      strncpy(context, v->value, sizeof(context)-1);
++              } else if (!strcasecmp(v->name, "incomingmsn")) {
++                      strncpy(incomingmsn, v->value, sizeof(incomingmsn)-1);
++              } else if (!strcasecmp(v->name, "controller")) {
++                      strncpy(controllerstr, v->value, sizeof(controllerstr)-1);
++              } else if (!strcasecmp(v->name, "softdtmf")) {
++                      softdtmf = atoi(v->value);
++              } else if (!strcasecmp(v->name, "echosquelch")) {
++                      es = atoi(v->value);
++              } else if (!strcasecmp(v->name, "callgroup")) {
++                      callgroup = ast_get_group(v->value);
++              } else if (!strcasecmp(v->name, "group")) {
++                      group = ast_get_group(v->value);
++              } else if (!strcasecmp(v->name, "deflect")) {
++                      strncpy(deflect2, v->value, sizeof(deflect2)-1);
++              } else if (!strcasecmp(v->name, "rxgain")) {
++                      if (sscanf(v->value,"%f",&rxgain) != 1) {
++                          ast_log(LOG_ERROR,"invalid rxgain\n");
++                      }
++              } else if (!strcasecmp(v->name, "txgain")) {
++                      if (sscanf(v->value,"%f",&txgain) != 1) {
++                          ast_log(LOG_ERROR,"invalid txgain\n");
++                      }
++              } else if (!strcasecmp(v->name, "echocancel")) {
++                      if (!strcasecmp(v->value, "yes") || !strcasecmp(v->value, "1") || !strcasecmp(v->value, "on")) {
++                              echocancel=1;
++                              ecoption=EC_OPTION_DISABLE_G165;
++                      }       
++                      else if (!strcasecmp(v->value, "no") || !strcasecmp(v->value, "0") || !strcasecmp(v->value, "off")) {
++                              echocancel=0;
++                              ecoption=0;
++                      }       
++                      else if (!strcasecmp(v->value, "g165") || !strcasecmp(v->value, "g.165")) {
++                              echocancel=1;
++                              ecoption=EC_OPTION_DISABLE_G165;
++                      }       
++                      else if (!strcasecmp(v->value, "g164") || !strcasecmp(v->value, "g.164")) {
++                              echocancel=1;
++                              ecoption=EC_OPTION_DISABLE_G164_OR_G165;
++                      }       
++                      else if (!strcasecmp(v->value, "force")) {
++                              echocancel=1;
++                              ecoption=EC_OPTION_DISABLE_NEVER;
++                      }
++                      else {
++                              ast_log(LOG_ERROR,"Unknown echocancel parameter \"%s\" -- ignoring\n",v->value);
++                      }
++              } else if (!strcasecmp(v->name, "echotail")) {
++                      ectail = atoi(v->value);
++                      if (ectail > 255)
++                              ectail = 255;
++              } else if (!strcasecmp(v->name, "prefix")) {
++                      strncpy(prefix, v->value, sizeof(prefix)-1);
++              } else if (!strcasecmp(v->name, "accountcode")) {
++                      strncpy(accountcode, v->value, sizeof(accountcode)-1);
++              } else if (!strcasecmp(v->name, "isdnmode")) {
++                      if (!strcasecmp(v->value, "ptp") || !strcasecmp(v->value, "1"))
++                          isdnmode = 1;
++                      else if (!strcasecmp(v->value, "ptm") || !strcasecmp(v->value, "0") || !strcasecmp(v->value, "ptmp"))
++                          isdnmode = 0;
++                      else
++                          ast_log(LOG_ERROR,"Unknown isdnmode parameter \"%s\" -- ignoring\n",v->value);
++
++              }
++
++              v = v->next;
++      }
++      ast_config_destroy(cfg);
++
++          for (controller=1;controller<=capi_num_controllers;controller++) {
++              if (capi_used_controllers & (1 << controller)) {
++                  if (ListenOnController(ALL_SERVICES,controller) != 0) {
++                      ast_log(LOG_ERROR,"Unable to listen on contr%d\n",controller);
++                  } else {
++                      if (option_verbose > 2) 
++                          ast_verbose(VERBOSE_PREFIX_3 "listening on contr%d CIPmask = %#x\n",controller,ALL_SERVICES);
++                  }
++              } else {
++                  ast_log(LOG_WARNING,"Unused contr%d\n",controller);
++              }
++          }
++
++
++      ast_mutex_unlock(&iflock);
++
++      if (ast_channel_register(&capi_tech)) {
++              ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
++              unload_module();
++              return -1;
++      }
++
++      ast_cli_register(&cli_info);
++      ast_cli_register(&cli_debug);
++      ast_cli_register(&cli_no_debug);
++
++      if (ast_mutex_lock(&monlock)) {
++          ast_log(LOG_WARNING,"Unable to get monitor lock!\n");
++          return -1;
++      }
++        if (monitor_thread == pthread_self()) {
++          ast_mutex_unlock(&monlock);
++          ast_log(LOG_WARNING,"Unable to kill myself!\n");
++          return -1;
++      }
++    
++      if (ast_pthread_create(&monitor_thread,NULL,do_monitor,NULL) < 0) {
++          ast_mutex_unlock(&monlock);
++          ast_log(LOG_ERROR,"Unable to start monitor thread!\n");
++          return -1;
++      }
++
++      return res;
++}
++
++
++int unload_module()
++{
++      if (capi20_release(ast_capi_ApplID) != 0)
++              ast_log(LOG_WARNING,"Unable to unregister from CAPI!\n");
++      ast_channel_unregister(&capi_tech);
++      return 0;
++}
++
++int usecount()
++{
++      int res;
++      ast_mutex_lock(&usecnt_lock);
++      res = usecnt;
++      ast_mutex_unlock(&usecnt_lock);
++      return res;
++}
++
++char *description()
++{
++      return desc;
++}
++
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/channels/chan_features.c asterisk-1.2.4/channels/chan_features.c
+--- asterisk-1.2.4.orig/channels/chan_features.c       2006-01-25 19:39:44.000000000 +0100
++++ asterisk-1.2.4/channels/chan_features.c    2006-01-31 09:41:43.000000000 +0100
+@@ -438,7 +438,7 @@
+       }
+       ast_mutex_unlock(&featurelock);
+       if (!tmp) {
+-              chan = ast_request(tech, format, dest, &status);
++              chan = ast_request(tech, format, dest, &status, NULL);
+               if (!chan) {
+                       ast_log(LOG_NOTICE, "Unable to allocate subchannel '%s/%s'\n", tech, dest);
+                       return NULL;
+diff -urN asterisk-1.2.4.orig/channels/chan_iax2.c asterisk-1.2.4/channels/chan_iax2.c
+--- asterisk-1.2.4.orig/channels/chan_iax2.c   2006-01-20 02:00:46.000000000 +0100
++++ asterisk-1.2.4/channels/chan_iax2.c        2006-01-31 09:41:43.000000000 +0100
+@@ -11,6 +11,9 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Hangup cause signalling implementation by
++ * Levent Guendogdu <levon@feature-it.com>
++ *
+  * 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.
+@@ -3050,7 +3053,7 @@
+       memset(&ied, 0, sizeof(ied));
+       ast_mutex_lock(&iaxsl[callno]);
+       if (callno && iaxs[callno]) {
+-              ast_log(LOG_DEBUG, "We're hanging up %s now...\n", c->name);
++              ast_log(LOG_DEBUG, "We're hanging up %s with cause %i now...\n", c->name, c->hangupcause);
+               alreadygone = ast_test_flag(iaxs[callno], IAX_ALREADYGONE);
+               /* Send the hangup unless we have had a transmission error or are already gone */
+               iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, (unsigned char)c->hangupcause);
+@@ -3102,7 +3105,8 @@
+ static struct ast_frame *iax2_read(struct ast_channel *c) 
+ {
+       static struct ast_frame f = { AST_FRAME_NULL, };
+-      ast_log(LOG_NOTICE, "I should never be called!\n");
++      if (option_verbose > 3)
++          ast_log(LOG_NOTICE, "I should never be called!\n");
+       return &f;
+ }
+@@ -6688,7 +6692,7 @@
+               }
+               if (f.frametype == AST_FRAME_IAX) {
+                       if (iaxs[fr.callno]->initid > -1) {
+-                              /* Don't auto congest anymore since we've gotten something usefulb ack */
++                              /* Don't auto congest anymore since we've gotten something useful back */
+                               ast_sched_del(sched, iaxs[fr.callno]->initid);
+                               iaxs[fr.callno]->initid = -1;
+                       }
+diff -urN asterisk-1.2.4.orig/channels/chan_sip.c asterisk-1.2.4/channels/chan_sip.c
+--- asterisk-1.2.4.orig/channels/chan_sip.c    2006-01-28 14:52:15.000000000 +0100
++++ asterisk-1.2.4/channels/chan_sip.c 2006-01-31 09:41:43.000000000 +0100
+@@ -596,6 +596,7 @@
+       unsigned int flags;                     /*!< SIP_ flags */      
+       int timer_t1;                           /*!< SIP timer T1, ms rtt */
+       unsigned int sipoptions;                /*!< Supported SIP sipoptions on the other end */
++      int dialog_established;                 /*!< SIP dialog established */
+       int capability;                         /*!< Special capability (codec) */
+       int jointcapability;                    /*!< Supported capability at both ends (codecs ) */
+       int peercapability;                     /*!< Supported peer capability */
+@@ -619,6 +620,7 @@
+       char refer_to[AST_MAX_EXTENSION];       /*!< Place to store REFER-TO extension */
+       char referred_by[AST_MAX_EXTENSION];    /*!< Place to store REFERRED-BY extension */
+       char refer_contact[AST_MAX_EXTENSION];  /*!< Place to store Contact info from a REFER extension */
++      char refer_replaces[AST_MAX_EXTENSION]; /*!< Place to store Replaces header of REFER-TO header */
+       struct sip_pvt *refer_call;             /*!< Call we are referring */
+       struct sip_route *route;                /*!< Head of linked list of routing steps (fm Record-Route) */
+       int route_persistant;                   /*!< Is this the "real" route? */
+@@ -638,6 +640,7 @@
+       char peername[256];                     /*!< [peer] name, not set if [user] */
+       char authname[256];                     /*!< Who we use for authentication */
+       char uri[256];                          /*!< Original requested URI */
++      char origuri[256];                      /*!< REAL! Original requested URI */
+       char okcontacturi[256];                 /*!< URI from the 200 OK on INVITE */
+       char peersecret[256];                   /*!< Password */
+       char peermd5secret[256];
+@@ -921,7 +924,7 @@
+ static int determine_firstline_parts(struct sip_request *req);
+ static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to LOG_DEBUG at end of dialog, before destroying data */
+ static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
+-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int substate);
++static int transmit_state_notify(struct sip_pvt *p, int state, int full, int substate, char *cid_num, char *cid_name);
+ static char *gettag(struct sip_request *req, char *header, char *tagbuf, int tagbufsize);
+ /*! \brief Definition of this channel for PBX channel registration */
+@@ -1304,7 +1307,7 @@
+       /* If this is a subscription, tell the phone that we got a timeout */
+       if (p->subscribed) {
+               p->subscribed = TIMEOUT;
+-              transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, 1);      /* Send first notification */
++              transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, 1, NULL, NULL);  /* Send first notification */
+               p->subscribed = NONE;
+               append_history(p, "Subscribestatus", "timeout");
+               return 10000;   /* Reschedule this destruction so that we know that it's gone */
+@@ -3109,16 +3112,30 @@
+ /*! \brief  find_call: Connect incoming SIP message to current dialog or create new dialog structure */
+ /*               Called by handle_request, sipsock_read */
+-static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
++static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method, const int replaces_callid)
+ {
+       struct sip_pvt *p;
+       char *callid;
+       char *tag = "";
++      char *replaces;
+       char totag[128];
+       char fromtag[128];
++      char *c;
+       callid = get_header(req, "Call-ID");
++      if (replaces_callid) {
++          replaces = get_header(req, "Replaces");
++          c = strchr(replaces, ';');
++          if (c)
++              *c = '\0';
++          if (!ast_strlen_zero(replaces)) {
++              callid = replaces;
++          } else {
++              return NULL;
++          }
++      }
++
+       if (pedanticsipchecking) {
+               /* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
+                  we need more to identify a branch - so we have to check branch, from
+@@ -4043,6 +4060,7 @@
+       if (sipmethod == SIP_CANCEL) {
+               c = p->initreq.rlPart2; /* Use original URI */
+       } else if (sipmethod == SIP_ACK) {
++// XXX+       } else if (!strcasecmp(msg, "ACK") && !p->dialog_established) {
+               /* Use URI from Contact: in 200 OK (if INVITE) 
+               (we only have the contacturi on INVITEs) */
+               if (!ast_strlen_zero(p->okcontacturi))
+@@ -4808,10 +4826,12 @@
+               ast_build_string(&invite, &invite_max, ";%s", p->options->uri_options);
+       ast_copy_string(p->uri, invite_buf, sizeof(p->uri));
++      ast_copy_string(p->origuri, invite, sizeof(p->origuri));
+       /* If there is a VXML URL append it to the SIP URL */
+       if (p->options && p->options->vxml_url) {
+-              snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
++//            snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
++              snprintf(to, sizeof(to), "<%s;%s>", p->uri, p->options->vxml_url);
+       } else {
+               snprintf(to, sizeof(to), "<%s>", p->uri);
+       }
+@@ -4867,6 +4887,11 @@
+               if (!ast_strlen_zero(p->referred_by))
+                       add_header(&req, "Referred-By", p->referred_by);
+       }
++      if (sipmethod == SIP_INVITE) {
++          if (!ast_strlen_zero(p->refer_replaces)) {
++              add_header(&req, "Replaces", p->refer_replaces);
++          }
++      }
+ #ifdef OSP_SUPPORT
+       if ((req.method != SIP_OPTIONS) && p->options && !ast_strlen_zero(p->options->osptoken)) {
+               ast_log(LOG_DEBUG,"Adding OSP Token: %s\n", p->options->osptoken);
+@@ -4941,8 +4966,7 @@
+ }
+ /*! \brief  transmit_state_notify: Used in the SUBSCRIBE notification subsystem ----*/
+-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int substate)
+-{
++static int transmit_state_notify(struct sip_pvt *p, int state, int full, int substate, char *cid_num, char *cid_name) {
+       char tmp[4000], from[256], to[256];
+       char *t = tmp, *c, *a, *mfrom, *mto;
+       size_t maxbytes = sizeof(tmp);
+@@ -5086,10 +5110,19 @@
+       case DIALOG_INFO_XML: /* SNOM subscribes in this format */
+               ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");
+               ast_build_string(&t, &maxbytes, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full":"partial", mto);
+-              if ((state & AST_EXTENSION_RINGING) && global_notifyringing)
+-                      ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
+-              else
++              if ((state & AST_EXTENSION_RINGING) && global_notifyringing) {
++                  ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
++                  if (cid_num) {
++                      ast_build_string(&t, &maxbytes, "<local><identity display=\"%s\">%s</identity><target uri=\"%s\"/></local>\n", p->exten, p->exten, mfrom);
++                      if (cid_name && !ast_strlen_zero(cid_name)) {
++                           ast_build_string(&t, &maxbytes, "<remote><identity display=\"%s\">sip:%s@%s</identity><target uri=\"sip:%s%s@%s\"/></remote>\n", cid_name, cid_num, p->fromdomain, ast_pickup_ext(), p->exten, p->fromdomain);
++                      } else {
++                           ast_build_string(&t, &maxbytes, "<remote><identity display=\"%s\">sip:%s@%s</identity><target uri=\"sip:%s%s@%s\"/></remote>\n", cid_num, cid_num, p->fromdomain, ast_pickup_ext(), p->exten, p->fromdomain);
++                      }
++                  }
++              } else {
+                       ast_build_string(&t, &maxbytes, "<dialog id=\"%s\">\n", p->exten);
++              }
+               ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring);
+               ast_build_string(&t, &maxbytes, "</dialog>\n</dialog-info>\n");
+               break;
+@@ -6299,7 +6332,7 @@
+ /*! \brief  cb_extensionstate: Callback for the devicestate notification (SUBSCRIBE) support subsystem ---*/
+ /*    If you add an "hint" priority to the extension in the dial plan,
+       you will get notifications on device state changes */
+-static int cb_extensionstate(char *context, char* exten, int state, void *data)
++static int cb_extensionstate(char *context, char* exten, int state, void *data, char *cid_num, char *cid_name)
+ {
+       struct sip_pvt *p = data;
+@@ -6318,7 +6351,7 @@
+               p->laststate = state;
+               break;
+       }
+-      transmit_state_notify(p, state, 1, 1);
++      transmit_state_notify(p, state, 1, 1, cid_num, cid_name);
+       if (option_debug > 1)
+               ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %s for Notify User %s\n", exten, ast_extension_state2str(state), p->username);
+@@ -8584,6 +8617,7 @@
+       char buf[1024];
+       unsigned int event;
+       char *c;
++      struct ast_call_feature *feature;
+       
+       /* Need to check the media/type */
+       if (!strcasecmp(get_header(req, "Content-Type"), "application/dtmf-relay") ||
+@@ -8647,6 +8681,19 @@
+                       ast_queue_control(p->owner, AST_CONTROL_VIDUPDATE);
+               transmit_response(p, "200 OK", req);
+               return;
++      } else if ((c = get_header(req, "Record"))) {
++              feature = ast_find_builtin_feature("automon");
++              if (feature && (!ast_strlen_zero(feature->exten))) {
++                  int i = 0;
++//                ast_log(LOG_NOTICE, "feature exten %s\n", feature->exten);
++                  for (i=0; i<strlen(feature->exten); i++) {
++                      struct ast_frame f = { AST_FRAME_DTMF, feature->exten[i] };
++                      ast_queue_frame(p->owner, &f); 
++                  }
++              } else {
++                  ast_log(LOG_NOTICE, "Feature \"One Touch Monitor\" not configured in features.conf.\n");
++              }
++              return;
+       } else if ((c = get_header(req, "X-ClientCode"))) {
+               /* Client code (from SNOM phone) */
+               if (ast_test_flag(p, SIP_USECLIENTCODE)) {
+@@ -8746,12 +8793,63 @@
+       return RESULT_SUCCESS;
+ }
++
++/*! \brief  sip_notify: Send SIP notify to peer */
++static int sip_send_notify(int fd, char *notify_type, char *peer)
++{
++      struct ast_variable *varlist;
++      struct sip_pvt *p;
++      struct sip_request req;
++      struct ast_variable *var;
++
++      varlist = ast_variable_browse(notify_types, notify_type);
++
++      if (!varlist) {
++              if (fd > 0)
++                  ast_cli(fd, "Unable to find notify type '%s'\n", notify_type);
++              return RESULT_FAILURE;
++      }
++
++      p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY);
++      if (!p) {
++              ast_log(LOG_WARNING, "Unable to build sip pvt data for notify\n");
++              return RESULT_FAILURE;
++      }
++
++      if (create_addr(p, peer)) {
++              /* Maybe they're not registered, etc. */
++              sip_destroy(p);
++              if (fd > 0)
++                  ast_cli(fd, "Could not create address for '%s'\n", peer);
++              return RESULT_FAILURE;
++      }
++
++      initreqprep(&req, p, SIP_NOTIFY);
++
++      for (var = varlist; var; var = var->next)
++              add_header(&req, var->name, var->value);
++
++      add_blank_header(&req);
++      /* Recalculate our side, and recalculate Call ID */
++      if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
++              memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
++      build_via(p, p->via, sizeof(p->via));
++      build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
++      if (fd > 0)
++          ast_cli(fd, "Sending NOTIFY of type '%s' to '%s'\n", notify_type, peer);
++      transmit_sip_request(p, &req);
++      sip_scheddestroy(p, 15000);
++
++      return RESULT_SUCCESS;
++}
++
+ /*! \brief  sip_notify: Send SIP notify to peer */
+ static int sip_notify(int fd, int argc, char *argv[])
+ {
+       struct ast_variable *varlist;
+       int i;
+-
++      int res = RESULT_SUCCESS;
++      
+       if (argc < 4)
+               return RESULT_SHOWUSAGE;
+@@ -8768,41 +8866,13 @@
+       }
+       for (i = 3; i < argc; i++) {
+-              struct sip_pvt *p;
+-              struct sip_request req;
+-              struct ast_variable *var;
+-
+-              p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY);
+-              if (!p) {
+-                      ast_log(LOG_WARNING, "Unable to build sip pvt data for notify\n");
+-                      return RESULT_FAILURE;
+-              }
+-
+-              if (create_addr(p, argv[i])) {
+-                      /* Maybe they're not registered, etc. */
+-                      sip_destroy(p);
+-                      ast_cli(fd, "Could not create address for '%s'\n", argv[i]);
+-                      continue;
+-              }
+-
+-              initreqprep(&req, p, SIP_NOTIFY);
+-
+-              for (var = varlist; var; var = var->next)
+-                      add_header(&req, var->name, var->value);
++              if (sip_send_notify(fd, argv[2], argv[i]) == RESULT_FAILURE) 
++                  res = RESULT_FAILURE;
++      }
++      return res;
++}
+-              add_blank_header(&req);
+-              /* Recalculate our side, and recalculate Call ID */
+-              if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
+-                      memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
+-              build_via(p, p->via, sizeof(p->via));
+-              build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain);
+-              ast_cli(fd, "Sending NOTIFY of type '%s' to '%s'\n", argv[2], argv[i]);
+-              transmit_sip_request(p, &req);
+-              sip_scheddestroy(p, 15000);
+-      }
+-      return RESULT_SUCCESS;
+-}
+ /*! \brief  sip_do_history: Enable SIP History logging (CLI) ---*/
+ static int sip_do_history(int fd, int argc, char *argv[])
+ {
+@@ -9447,7 +9517,7 @@
+               if (!ignore && p->owner) {
+                       ast_queue_control(p->owner, AST_CONTROL_RINGING);
+                       if (p->owner->_state != AST_STATE_UP)
+-                              ast_setstate(p->owner, AST_STATE_RINGING);
++                              ast_setstate_and_cid(p->owner, AST_STATE_RINGING, p->owner->cid.cid_num, p->owner->cid.cid_name);
+               }
+               if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
+                       process_sdp(p, req);
+@@ -10801,7 +10871,7 @@
+                       struct sip_pvt *p_old;
+                       transmit_response(p, "200 OK", req);
+-                      transmit_state_notify(p, firststate, 1, 1);     /* Send first notification */
++                      transmit_state_notify(p, firststate, 1, 1, NULL, NULL); /* Send first notification */
+                       append_history(p, "Subscribestatus", ast_extension_state2str(firststate));
+                       /* remove any old subscription from this peer for the same exten/context,
+@@ -11113,7 +11183,7 @@
+       /* Process request, with netlock held */
+ retrylock:
+       ast_mutex_lock(&netlock);
+-      p = find_call(&req, &sin, req.method);
++      p = find_call(&req, &sin, req.method, 0);
+       if (p) {
+               /* Go ahead and lock the owner if it has one -- we may need it */
+               if (p->owner && ast_mutex_trylock(&p->owner->lock)) {
+@@ -11435,6 +11505,52 @@
+       return 0;
+ }
++static char mandescr_sip_notify[] = 
++"Description: Send a NOTIFY message to one or more SIP peers.\n"
++"Variables: \n"
++"  Peer: <name>           The peer name you want to send a NOTIFY to.\n"
++"  Type: <name>           The notify type (see sip_notify.conf).\n"
++"  ActionID: <id>       Optional action ID for this AMI transaction.\n";
++
++/*! \brief  manager_sip_notify: Send a notify (see sip_notify.conf) to a peer ---*/
++static int manager_sip_notify(struct mansession *s, struct message *m)
++{
++      char *id = astman_get_header(m,"ActionID");
++      char *peer;
++      char *notify_type;
++      int res = 0;
++
++      peer = astman_get_header(m,"Peer");
++      if (ast_strlen_zero(peer)) {
++              astman_send_error(s, m, "Peer: <name> missing.\n");
++              return 0;
++      }
++      notify_type = astman_get_header(m,"Type");
++      if (ast_strlen_zero(notify_type)) {
++              astman_send_error(s, m, "Type: <name> missing.\n");
++              return 0;
++      }
++
++      res = sip_send_notify(-1, notify_type, peer);
++      if (res != RESULT_SUCCESS) {
++          ast_cli(s->fd, "Response: SIPNotify Failure\r\n"
++                      "Peer: %s\r\n"
++                      "Type: %s\r\n"
++                      "ActionID: %s\r\n"
++                      "\r\n",
++                      peer, notify_type, id);
++      } else {
++          ast_cli(s->fd, "Response: SIPNotify Success\r\n"
++                      "Peer: %s\r\n"
++                      "Type: %s\r\n"
++                      "ActionID: %s\r\n"
++                      "\r\n",
++                      peer, notify_type, id);
++      }
++      return res;
++}
++
++
+ /*! \brief  sip_devicestate: Part of PBX channel interface ---*/
+ /* Return values:---
+@@ -13128,6 +13244,8 @@
+                       "List SIP peers (text format)", mandescr_show_peers);
+       ast_manager_register2("SIPshowpeer", EVENT_FLAG_SYSTEM, manager_sip_show_peer,
+                       "Show SIP peer (text format)", mandescr_show_peer);
++      ast_manager_register2("SIPNotify", EVENT_FLAG_SYSTEM, manager_sip_notify,
++                      "Send NOTIFY to peer", mandescr_sip_notify);
+       sip_poke_all_peers();   
+       sip_send_all_registers();
+@@ -13158,6 +13276,7 @@
+       ast_rtp_proto_unregister(&sip_rtp);
++      ast_manager_unregister("SIPNotify");
+       ast_manager_unregister("SIPpeers");
+       ast_manager_unregister("SIPshowpeer");
+diff -urN asterisk-1.2.4.orig/channels/chan_zap.c asterisk-1.2.4/channels/chan_zap.c
+--- asterisk-1.2.4.orig/channels/chan_zap.c    2006-01-30 18:08:28.000000000 +0100
++++ asterisk-1.2.4/channels/chan_zap.c 2006-01-31 09:46:14.000000000 +0100
+@@ -11,6 +11,10 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2003, 2004, 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ *
+  * 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.
+@@ -96,6 +100,7 @@
+ #include "asterisk/term.h"
+ #include "asterisk/utils.h"
+ #include "asterisk/transcap.h"
++#include "asterisk/devicestate.h"
+ #ifndef ZT_SIG_EM_E1
+ #error "Your zaptel is too old.  please cvs update"
+@@ -183,7 +188,7 @@
+ #define SIG_GR303FXOKS        (0x0100000 | ZT_SIG_FXOKS)
+ #define SIG_GR303FXSKS        (0x0100000 | ZT_SIG_FXSKS)
+-#define NUM_SPANS             32
++#define NUM_SPANS             128     /*!<"32 spans", muahahaha, us alaws like to have some more... */
+ #define NUM_DCHANS            4       /*!< No more than 4 d-channels */
+ #define MAX_CHANNELS  672             /*!< No more than a DS3 per trunk group */
+@@ -201,6 +206,9 @@
+ static char defaultcic[64] = "";
+ static char defaultozz[64] = "";
++static char nocid[256] = "No CID available";
++static char withheldcid[256] = "CID withheld";
++
+ static char language[MAX_LANGUAGE] = "";
+ static char musicclass[MAX_MUSICCLASS] = "";
+ static char progzone[10]= "";
+@@ -287,6 +295,7 @@
+ static int cur_priexclusive = 0;
+ static int priindication_oob = 0;
++static int pritransfer = 0;
+ #ifdef ZAPATA_PRI
+ static int minunused = 2;
+@@ -294,6 +303,7 @@
+ static char idleext[AST_MAX_EXTENSION];
+ static char idledial[AST_MAX_EXTENSION];
+ static int overlapdial = 0;
++static int usercid = 0;
+ static int facilityenable = 0;
+ static char internationalprefix[10] = "";
+ static char nationalprefix[10] = "";
+@@ -305,8 +315,6 @@
+ #ifdef PRI_GETSET_TIMERS
+ static int pritimers[PRI_MAX_TIMERS];
+ #endif
+-static int pridebugfd = -1;
+-static char pridebugfilename[1024]="";
+ #endif
+ /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
+@@ -327,10 +335,6 @@
+ static int ifcount = 0;
+-#ifdef ZAPATA_PRI
+-AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
+-#endif
+-
+ /*! \brief Whether we answer on a Polarity Switch event */
+ static int answeronpolarityswitch = 0;
+@@ -403,6 +407,27 @@
+ #define PRI_SPAN(p) (((p) >> 8) & 0xff)
+ #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
++struct zt_suspended_call {
++      ast_mutex_t lock;               /* Mutex */
++      char msn[AST_MAX_EXTENSION];    /* the MSN to which this parked call belongs */
++      char callid[10];                        /* the callID provided by the user */
++      int parked_at;                  /* extension in the call parking context */
++      struct zt_suspended_call *next;
++};
++
++struct zt_holded_call {
++      ast_mutex_t lock;               /* Mutex */
++      char msn[AST_MAX_EXTENSION];    /* the MSN to which this parked call belongs */
++      char uniqueid[AST_MAX_EXTENSION];       /* unique id of the onhold channel */
++      int tei;
++      int cref;
++      int alreadyhungup;
++      struct ast_channel *channel;
++      struct ast_channel *bridge;
++      q931_call *call;        /* this also covers tei mumbojumbo */
++      struct zt_holded_call *next;
++};
++
+ struct zt_pri {
+       pthread_t master;                                               /*!< Thread of master */
+       ast_mutex_t lock;                                               /*!< Mutex */
+@@ -416,6 +441,8 @@
+       int nsf;                                                        /*!< Network-Specific Facilities */
+       int dialplan;                                                   /*!< Dialing plan */
+       int localdialplan;                                              /*!< Local dialing plan */
++      char nocid[256];
++      char withheldcid[256];
+       char internationalprefix[10];                                   /*!< country access code ('00' for european dialplans) */
+       char nationalprefix[10];                                        /*!< area access code ('0' for european dialplans) */
+       char localprefix[20];                                           /*!< area access code + area code ('0'+area code for european dialplans) */
+@@ -435,6 +462,7 @@
+       int fds[NUM_DCHANS];                                            /*!< FD's for d-channels */
+       int offset;
+       int span;
++      int usercid;                                                    /* trust user provided callerid (callerani) ?? */
+       int resetting;
+       int resetpos;
+       time_t lastreset;                                               /*!< time when unused channels were last reset */
+@@ -442,6 +470,9 @@
+       struct zt_pvt *pvts[MAX_CHANNELS];                              /*!< Member channel pvt structs */
+       struct zt_pvt *crvs;                                            /*!< Member CRV structs */
+       struct zt_pvt *crvend;                                          /*!< Pointer to end of CRV structs */
++      struct zt_suspended_call *suspended_calls; /* Calls parked with SUSPEND messages */
++      struct zt_holded_call *holded_calls; /* Calls on hold */
++      int debugfd;
+ };
+@@ -561,6 +592,8 @@
+       unsigned int echocanbridged:1;
+       unsigned int echocanon:1;
+       unsigned int faxhandled:1;                      /*!< Has a fax tone already been handled? */
++                                                      /*!< KPJ: i will abuse this flag to implement a zapata option for dialing out
++                                                          on a zap channel with EC to be off no matter what happens. */
+       unsigned int firstradio:1;
+       unsigned int hanguponpolarityswitch:1;
+       unsigned int hardwaredtmf:1;
+@@ -573,7 +606,8 @@
+       unsigned int overlapdial:1;
+       unsigned int permcallwaiting:1;
+       unsigned int permhidecallerid:1;                /*!< Whether to hide our outgoing caller ID or not */
+-      unsigned int priindication_oob:1;
++      unsigned int priindication_oob:2;
++      unsigned int pritransfer:2;
+       unsigned int priexclusive:1;
+       unsigned int pulse:1;
+       unsigned int pulsedial:1;                       /*!< whether a pulse dial phone is detected */
+@@ -612,6 +646,7 @@
+ #endif
+       char cid_num[AST_MAX_EXTENSION];
+       int cid_ton;                                    /*!< Type Of Number (TON) */
++      int cid_pres;                                   /*!< Calling Presentation */
+       char cid_name[AST_MAX_EXTENSION];
+       char lastcid_num[AST_MAX_EXTENSION];
+       char lastcid_name[AST_MAX_EXTENSION];
+@@ -676,6 +711,8 @@
+       struct zt_pri *pri;
+       struct zt_pvt *bearer;
+       struct zt_pvt *realcall;
++      int tei;                                        /* channel in use by this tei */
++      q931_call *holdedcall;
+       q931_call *call;
+       int prioffset;
+       int logicalspan;
+@@ -701,11 +738,14 @@
+ static int zt_indicate(struct ast_channel *chan, int condition);
+ static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+ static int zt_setoption(struct ast_channel *chan, int option, void *data, int datalen);
++static int zt_devicestate(void *data);
++static void disable_dtmf_detect(struct zt_pvt *p);
++static void enable_dtmf_detect(struct zt_pvt *p);
+ static const struct ast_channel_tech zap_tech = {
+       .type = type,
+       .description = tdesc,
+-      .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,
++      .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
+       .requester = zt_request,
+       .send_digit = zt_digit,
+       .send_text = zt_sendtext,
+@@ -719,6 +759,7 @@
+       .indicate = zt_indicate,
+       .fixup = zt_fixup,
+       .setoption = zt_setoption,
++      .devicestate = zt_devicestate
+ };
+ #ifdef ZAPATA_PRI
+@@ -730,6 +771,13 @@
+ struct zt_pvt *round_robin[32];
+ #ifdef ZAPATA_PRI
++struct app_tmp {
++      char app[256];
++      char data[256];
++      struct ast_channel *chan;
++      pthread_t t;
++};
++
+ static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri)
+ {
+       int res;
+@@ -779,6 +827,112 @@
+ #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
+ #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
++static int zt_devicestate(void *data)
++{
++      int groupmatch = 0;
++      int channelmatch = 0;
++      struct zt_pvt *p;
++      char *dest=NULL;
++      int x,d;
++      char *s;
++      char opt=0;
++      int res, y=0;
++      struct zt_pvt *exit, *start, *end;
++      ast_mutex_t *lock;
++
++//    ast_log(LOG_NOTICE, "data = %s\n", (char *)data);
++      return AST_DEVICE_UNKNOWN;
++      
++      /* Assume we're locking the iflock */
++      lock = &iflock;
++      start = iflist;
++      end = ifend;
++
++      if (data) {
++              dest = ast_strdupa((char *)data);
++      } else {
++              ast_log(LOG_WARNING, "Channel requested with no data\n");
++              return AST_DEVICE_INVALID;
++      }
++      if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
++              /* Retrieve the group number */
++              char *stringp=NULL;
++              stringp=dest + 1;
++              s = strsep(&stringp, "/");
++              if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
++                      ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
++                      return AST_DEVICE_INVALID;
++              }
++              groupmatch = 1 << x;
++      } else {
++              char *stringp=NULL;
++              stringp=dest;
++              s = strsep(&stringp, "/");
++              p = iflist;
++              if (!strcasecmp(s, "pseudo")) {
++                      /* Special case for pseudo */
++                      x = CHAN_PSEUDO;
++                      channelmatch = x;
++                      /* bail out */
++                      return AST_DEVICE_INVALID;
++              } 
++
++              else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
++                      ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
++                      return AST_DEVICE_INVALID;
++              } else {
++                      channelmatch = x;
++                      ast_log(LOG_NOTICE, "channelmatch = %d\n", channelmatch);
++              }
++      }
++      /* Search for an unowned channel */
++      if (ast_mutex_lock(lock)) {
++              ast_log(LOG_ERROR, "Unable to lock interface list???\n");
++              return AST_DEVICE_INVALID;
++      }
++      p = iflist;
++      exit = iflist;
++      res = AST_DEVICE_INVALID; /* start pessimistic */
++      while(p) {
++              if (p) {
++                  ast_mutex_lock(&p->lock);
++                  if ((groupmatch && ((p->group & groupmatch) != 0)) || (channelmatch && (p->channel == channelmatch))) {
++#ifdef ZAPATA_PRI
++                      if (p->pri) {
++                          for(d=0;d<NUM_DCHANS;d++) {
++                              if (p->pri->dchanavail[d] & DCHAN_UP) {
++                                  res = AST_DEVICE_UNKNOWN;
++                              }
++                          }
++                      }
++#endif
++                      if ((!ast_strlen_zero(p->cid_num) && (strncasecmp(p->cid_num, dest, strlen(p->cid_num)))) || (!ast_strlen_zero(p->dnid) && (strncasecmp(p->dnid, dest, strlen(p->dnid))))) {
++                          res = AST_DEVICE_UNKNOWN;
++                          if (p->owner) {
++                                  if ((p->owner->_state == AST_STATE_RINGING) && (p->outgoing)) {
++                                      res = AST_DEVICE_RINGING;
++                                  }
++                                  if (((p->owner->_state == AST_STATE_RINGING) && (!p->outgoing)) || (p->owner->_state == AST_STATE_UP) || (p->owner->_state == AST_STATE_DIALING) || (p->owner->_state == AST_STATE_RESERVED) || (p->owner->_state == AST_STATE_RING)){
++                                      res = AST_DEVICE_INUSE;
++                                  }
++                          }
++                          if ((res == AST_DEVICE_INUSE) || (res == AST_DEVICE_RINGING)) {
++                              /* stop searching now, one non-idle channel is sufficient */
++                              ast_mutex_unlock(&p->lock);
++                              break;
++                          }
++                      }
++                  }
++                  ast_mutex_unlock(&p->lock);
++              }       
++              p = p->next;
++      }
++      ast_mutex_unlock(lock);
++
++      return res;
++
++}
++
+ static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
+ {
+       int res;
+@@ -1381,12 +1535,16 @@
+       int res;
+       if (!p)
+               return;
++      if (p->faxhandled)  {
++              ast_log(LOG_DEBUG, "Not enabling echo cancellation on a fax/modem call\n");
++              return;
++      }
+       if (p->echocanon) {
+               ast_log(LOG_DEBUG, "Echo cancellation already on\n");
+               return;
+       }
+       if (p->digital) {
+-              ast_log(LOG_DEBUG, "Echo cancellation isn't required on digital connection\n");
++              ast_log(LOG_DEBUG, "Echo cancellation does not make any sense on digital connections!\n");
+               return;
+       }
+       if (p->echocancel) {
+@@ -1412,7 +1570,7 @@
+ {
+       int x;
+       int res;
+-      if (p && p->echocancel && p->echotraining) {
++      if (p && p->echocancel && p->echotraining && (!p->digital) && (!p->faxhandled)) {
+               x = p->echotraining;
+               res = ioctl(p->subs[SUB_REAL].zfd, ZT_ECHOTRAIN, &x);
+               if (res) 
+@@ -1774,7 +1932,13 @@
+               ast_log(LOG_WARNING, "Unable to flush input on channel %d\n", p->channel);
+       p->outgoing = 1;
+-      set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
++      if (IS_DIGITAL(ast->transfercapability)) {
++          set_actual_gain(p->subs[SUB_REAL].zfd, 0, 0, 0, p->law);
++      } else {
++          set_actual_gain(p->subs[SUB_REAL].zfd, 0, p->rxgain, p->txgain, p->law);
++      }
++
++      disable_dtmf_detect(p);
+       switch(p->sig) {
+       case SIG_FXOLS:
+@@ -2016,6 +2180,12 @@
+               int ldp_strip;
+               int exclusive;
++              if ((p->pri->nodetype == BRI_NETWORK_PTMP) || (p->pri->nodetype == BRI_NETWORK)) {
++                  // pass NO audio when ringing an isdn phone
++                  p->dialing = 1;
++                  // maybe we could allow passing audio when calling a p2p PBX, but well... ;-)
++              }
++
+               c = strchr(dest, '/');
+               if (c)
+                       c++;
+@@ -2033,6 +2203,7 @@
+                       ast_mutex_unlock(&p->lock);
+                       return -1;
+               }
++              strncpy(p->dnid, (c + p->stripmsd), sizeof(p->dnid)-1);
+               if (p->sig != SIG_FXSKS) {
+                       p->dop.op = ZT_DIAL_OP_REPLACE;
+                       s = strchr(c + p->stripmsd, 'w');
+@@ -2056,6 +2227,8 @@
+                       pri_rel(p->pri);
+                       ast_mutex_unlock(&p->lock);
+                       return -1;
++              } else {
++              //      ast_log(LOG_NOTICE, "call %d\n", p->call);
+               }
+               if (!(sr = pri_sr_new())) {
+                       ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
+@@ -2287,8 +2460,10 @@
+       }
+       if (newslot < 0) {
+               newslot = 0;
+-              ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
++              if (pri->nodetype != BRI_CPE_PTMP) {
++                  ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
+                       pri->dchannels[newslot]);
++              }
+       }
+       if (old && (oldslot != newslot))
+               ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
+@@ -2344,8 +2519,7 @@
+       ast_log(LOG_DEBUG, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
+               p->channel, index, p->subs[SUB_REAL].zfd, p->subs[SUB_CALLWAIT].zfd, p->subs[SUB_THREEWAY].zfd);
+-      p->ignoredtmf = 0;
+-      
++
+       if (index > -1) {
+               /* Real channel, do some fixup */
+               p->subs[index].owner = NULL;
+@@ -2442,6 +2616,7 @@
+       if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
++              int outgoing = p->outgoing;
+               p->owner = NULL;
+               p->ringt = 0;
+               p->distinctivering = 0;
+@@ -2505,6 +2680,26 @@
+                                                               icause = atoi(cause);
+                                               }
+                                               pri_hangup(p->pri->pri, p->call, icause);
++
++                                              /* if we send a release complete we wont ge no hangup event, so clear the call here */
++                                              if (icause == 34 || icause == 44 || icause == 82 || icause == 1 || icause == 81 || icause == 17) {
++                                                  if ((ast->_state == AST_STATE_RING) || (ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING)) {
++                                                      p->call = NULL;
++                                                  } else {
++                                                      ast_log(LOG_ERROR, "What is wrong with you? You cannot use cause %d number when in state %d!\n", icause, ast->_state);
++                                                      icause = 16;
++                                                  }
++                                              } 
++                                              
++                                              if (p->pri->nodetype == BRI_NETWORK_PTMP) {
++                                                  if ((icause == 16 || icause == -1) && (ast->_state != AST_STATE_UP)) {
++                                                      if (outgoing) {
++                                                          p->call = NULL;
++                                                      }
++                                                  }
++                                              }
++                                              
++                                              
+                                       }
+                                       if (res < 0) 
+                                               ast_log(LOG_WARNING, "pri_disconnect failed\n");
+@@ -2701,10 +2896,14 @@
+                       p->proceeding = 1;
+                       res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
+                       pri_rel(p->pri);
++                      /* stop ignoring inband dtmf */
++                      enable_dtmf_detect(p);
+               } else {
+                       ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
+                       res= -1;
+               }
++              /* the audio path is complete now, train the echo canceler */
++              zt_train_ec(p);
+               break;
+ #endif
+ #ifdef ZAPATA_R2
+@@ -3274,6 +3473,15 @@
+ {
+       struct zt_pvt *p = newchan->tech_pvt;
+       int x;
++      if (newchan && newchan->tech_pvt) {
++          p = newchan->tech_pvt;
++      }
++      if (!p) {
++          if (newchan) {
++              ast_log(LOG_ERROR, "channel %s has no tech_pvt structure\n", newchan->name);
++          }
++          return 0;
++      }
+       ast_mutex_lock(&p->lock);
+       ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name);
+       if (p->owner == oldchan) {
+@@ -4600,7 +4808,7 @@
+               p->subs[index].f.data = NULL;
+               p->subs[index].f.datalen= 0;
+       }
+-      if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect  || p->callprogress) && !index) {
++      if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !index) {
+               /* Perform busy detection. etc on the zap line */
+               f = ast_dsp_process(ast, p->dsp, &p->subs[index].f);
+               if (f) {
+@@ -4612,8 +4820,9 @@
+                               }
+                       } else if (f->frametype == AST_FRAME_DTMF) {
+ #ifdef ZAPATA_PRI
+-                              if (!p->proceeding && p->sig==SIG_PRI && p->pri && p->pri->overlapdial) {
+-                                      /* Don't accept in-band DTMF when in overlap dial mode */
++                              if (p->ignoredtmf) {
++                                      /* Don't accept in-band DTMF when in overlap dial mode 
++                                         or when in non-overlap overlapdialing mode ... */
+                                       f->frametype = AST_FRAME_NULL;
+                                       f->subclass = 0;
+                               }
+@@ -4748,7 +4957,9 @@
+ #endif
+       /* Write a frame of (presumably voice) data */
+       if (frame->frametype != AST_FRAME_VOICE) {
+-              if (frame->frametype != AST_FRAME_IMAGE)
++              if (frame->frametype == AST_FRAME_TEXT) {
++                      ast_log(LOG_NOTICE, "text\n");
++              } else if (frame->frametype != AST_FRAME_IMAGE)
+                       ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
+               return 0;
+       }
+@@ -4819,7 +5030,7 @@
+               switch(condition) {
+               case AST_CONTROL_BUSY:
+ #ifdef ZAPATA_PRI
+-                      if (p->priindication_oob && p->sig == SIG_PRI) {
++                      if ((p->priindication_oob == 1) && p->sig == SIG_PRI) {
+                               chan->hangupcause = AST_CAUSE_USER_BUSY;
+                               chan->_softhangup |= AST_SOFTHANGUP_DEV;
+                               res = 0;
+@@ -4901,7 +5112,7 @@
+               case AST_CONTROL_CONGESTION:
+                       chan->hangupcause = AST_CAUSE_CONGESTION;
+ #ifdef ZAPATA_PRI
+-                      if (p->priindication_oob && p->sig == SIG_PRI) {
++                      if ((p->priindication_oob == 1) && p->sig == SIG_PRI) {
+                               chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
+                               chan->_softhangup |= AST_SOFTHANGUP_DEV;
+                               res = 0;
+@@ -5086,8 +5297,12 @@
+               if (state == AST_STATE_RING)
+                       tmp->rings = 1;
+               tmp->tech_pvt = i;
+-              if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
+-                      /* Only FXO signalled stuff can be picked up */
++#ifdef ZAPATA_PRI
++              if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS) || (i->sig == SIG_PRI)) {
++#else
++              if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
++#endif
++              /* Only FXO signalled stuff can be picked up */ /* i dont think so, mr. ulaw! we alaws like to pick up BRIs/PRIs */
+                       tmp->callgroup = i->callgroup;
+                       tmp->pickupgroup = i->pickupgroup;
+               }
+@@ -5217,6 +5432,7 @@
+       int len = 0;
+       int res;
+       int index;
++      int network;
+       if (option_verbose > 2) 
+               ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s'\n", chan->name);
+       index = zt_get_index(chan, p, 1);
+@@ -5235,10 +5451,17 @@
+               len = strlen(exten);
+               res = 0;
+               while((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
+-                      if (len && !ast_ignore_pattern(chan->context, exten))
++                      if (len && !ast_ignore_pattern(chan->context, exten)) {
+                               tone_zone_play_tone(p->subs[index].zfd, -1);
+-                      else
+-                              tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);
++                      } else {
++                              network = p->pri->nodetype == PRI_NETWORK || p->pri->nodetype == BRI_NETWORK || p->pri->nodetype == BRI_NETWORK_PTMP;
++                              if (network) {
++                                  tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);
++                              } else {
++                                  /* cpe be quiet */
++                                  tone_zone_play_tone(p->subs[index].zfd, -1);
++                              }
++                      }
+                       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
+                               timeout = matchdigittimeout;
+                       else
+@@ -6720,6 +6943,8 @@
+               } else {
+                       if (si->totalchans == 31) { /* if it's an E1 */
+                               pris[*span].dchannels[0] = 16 + offset;
++                      } else if (si->totalchans == 3) { /* if it's an S0 ZAPBRI */
++                              pris[*span].dchannels[0] = 3 + offset;
+                       } else {
+                               pris[*span].dchannels[0] = 24 + offset;
+                       }
+@@ -6965,6 +7190,11 @@
+                                                       destroy_zt_pvt(&tmp);
+                                                       return NULL;
+                                               }
++                                              if ((pris[span].localdialplan) && (pris[span].localdialplan != localdialplan)) {
++                                                      ast_log(LOG_ERROR, "Span %d is already a %s local dialing plan\n", span + 1, dialplan2str(pris[span].localdialplan));
++                                                      destroy_zt_pvt(&tmp);
++                                                      return NULL;
++                                              }
+                                               if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, idledial)) {
+                                                       ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, idledial);
+                                                       destroy_zt_pvt(&tmp);
+@@ -6992,6 +7222,17 @@
+                                                       return NULL;
+                                               }
+                                               pris[span].nodetype = pritype;
++// XXX
++                                              if (pritype == BRI_NETWORK_PTMP) {
++                                                  pris[span].dchanavail[0] =  DCHAN_AVAILABLE;
++                                                  pri_find_dchan(&pris[span]);
++                                              }
++// XXX tuev
++
++                                              if ((pritype == BRI_CPE) || (pritype == BRI_CPE_PTMP)) {
++                                                  pris[span].dchanavail[0] =  DCHAN_AVAILABLE;
++                                                  pri_find_dchan(&pris[span]);
++                                              }
+                                               pris[span].switchtype = myswitchtype;
+                                               pris[span].nsf = nsf;
+                                               pris[span].dialplan = dialplan;
+@@ -7000,9 +7241,14 @@
+                                               pris[span].minunused = minunused;
+                                               pris[span].minidle = minidle;
+                                               pris[span].overlapdial = overlapdial;
++                                              pris[span].usercid = usercid;
++                                              pris[span].suspended_calls = NULL;
++                                              pris[span].holded_calls = NULL;
+                                               pris[span].facilityenable = facilityenable;
+                                               ast_copy_string(pris[span].idledial, idledial, sizeof(pris[span].idledial));
+                                               ast_copy_string(pris[span].idleext, idleext, sizeof(pris[span].idleext));
++                                              ast_copy_string(pris[span].nocid, nocid, sizeof(pris[span].nocid) - 1);
++                                              ast_copy_string(pris[span].withheldcid, withheldcid, sizeof(pris[span].withheldcid) - 1);
+                                               ast_copy_string(pris[span].internationalprefix, internationalprefix, sizeof(pris[span].internationalprefix));
+                                               ast_copy_string(pris[span].nationalprefix, nationalprefix, sizeof(pris[span].nationalprefix));
+                                               ast_copy_string(pris[span].localprefix, localprefix, sizeof(pris[span].localprefix));
+@@ -7156,6 +7402,7 @@
+               tmp->restrictcid = restrictcid;
+               tmp->use_callingpres = use_callingpres;
+               tmp->priindication_oob = priindication_oob;
++              tmp->pritransfer = pritransfer;
+               tmp->priexclusive = cur_priexclusive;
+               if (tmp->usedistinctiveringdetection) {
+                       if (!tmp->use_callerid) {
+@@ -7429,7 +7676,7 @@
+                       break;
+               if (!backwards && (x >= pri->numchans))
+                       break;
+-              if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
++              if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner && !pri->pvts[x]->call) {
+                       ast_log(LOG_DEBUG, "Found empty available channel %d/%d\n", 
+                               pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
+                       return x;
+@@ -7476,7 +7723,7 @@
+       end = ifend;
+       /* We do signed linear */
+       oldformat = format;
+-      format &= (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
++      format &= (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW);
+       if (!format) {
+               ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
+               return NULL;
+@@ -7636,6 +7883,11 @@
+                                       p->digital = 1;
+                                       if (tmp)
+                                               tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
++                              } else if (opt == 'm') {
++                                      /* If this is a modem/fax call, pretend to have the fax handled and dont do EC */
++                                      p->faxhandled = 1;
++                                      if (tmp)
++                                          tmp->transfercapability = AST_TRANS_CAP_3_1K_AUDIO;
+                               } else {
+                                       ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
+                               }
+@@ -7689,6 +7941,57 @@
+       return NULL;
+ }
++static int pri_find_tei(struct zt_pri *pri, q931_call *c, int tei)
++{
++      int x=0;
++      for (x=0;x<pri->numchans;x++) {
++              if (!pri->pvts[x]) continue;
++              if ((pri->pvts[x]->tei == tei) && (pri->pvts[x]-> call != c)) {
++                  return x;
++              }
++      }
++      return -1;
++}
++
++static struct zt_holded_call *pri_get_callonhold(struct zt_pri *pri, int cref, int tei) {
++      struct zt_holded_call *zhc = pri->holded_calls;
++      struct zt_holded_call *zhctemp = NULL;
++
++      while (zhc) {
++          if ((zhc->tei == tei) && ((zhc->cref == cref) || (cref == -1))) {
++              return zhc;
++          }                   
++          zhctemp = zhc;
++          if (zhc) zhc = zhc->next;
++      }
++      return NULL;    
++}
++
++static int pri_destroy_callonhold(struct zt_pri *pri, struct zt_holded_call *onhold) {
++      struct zt_holded_call *zhc = pri->holded_calls;
++      struct zt_holded_call *zhctemp = NULL;
++
++      while (zhc) {
++          if (zhc == onhold) {
++              if (zhctemp) {
++                  zhctemp->next = zhc->next;
++                  zhc = zhctemp;
++              } else {
++                  pri->holded_calls = zhc->next;
++                  zhc = pri->holded_calls;
++                  zhctemp = NULL;
++              }
++          }                   
++          zhctemp = zhc;
++          if (zhc) zhc = zhc->next;
++      }
++      if (onhold) {
++          free(onhold);
++          onhold = NULL;
++          return 1;   
++      }
++      return 0;       
++}
+ static int pri_find_principle(struct zt_pri *pri, int channel)
+ {
+@@ -7721,7 +8024,9 @@
+ static int pri_fixup_principle(struct zt_pri *pri, int principle, q931_call *c)
+ {
+       int x;
++      int res = 0;
+       struct zt_pvt *crv;
++      char tmpname[256];
+       if (!c) {
+               if (principle < 0)
+                       return -1;
+@@ -7735,6 +8040,7 @@
+       /* First, check for other bearers */
+       for (x=0;x<pri->numchans;x++) {
+               if (!pri->pvts[x]) continue;
++// ast_log(LOG_NOTICE, "principle %d channel %d call %d channel[x]->call %d\n",principle, x, c, pri->pvts[x]->call);
+               if (pri->pvts[x]->call == c) {
+                       /* Found our call */
+                       if (principle != x) {
+@@ -7748,19 +8054,56 @@
+                               }
+                               /* Fix it all up now */
+                               pri->pvts[principle]->owner = pri->pvts[x]->owner;
++                              pri->pvts[principle]->outgoing = pri->pvts[x]->outgoing;
+                               if (pri->pvts[principle]->owner) {
+                                       snprintf(pri->pvts[principle]->owner->name, sizeof(pri->pvts[principle]->owner->name), 
+                                               "Zap/%d:%d-%d", pri->trunkgroup, pri->pvts[principle]->channel, 1);
+                                       pri->pvts[principle]->owner->tech_pvt = pri->pvts[principle];
+                                       pri->pvts[principle]->owner->fds[0] = pri->pvts[principle]->subs[SUB_REAL].zfd;
+                                       pri->pvts[principle]->subs[SUB_REAL].owner = pri->pvts[x]->subs[SUB_REAL].owner;
+-                              } else
++                              } else {
+                                       ast_log(LOG_WARNING, "Whoa, there's no  owner, and we're having to fix up channel %d to channel %d\n", pri->pvts[x]->channel, pri->pvts[principle]->channel);
++                              }
+                               pri->pvts[principle]->call = pri->pvts[x]->call;
++                              pri->pvts[principle]->dsp = pri->pvts[x]->dsp;
++                              pri->pvts[principle]->alreadyhungup = pri->pvts[x]->alreadyhungup;
++                              pri->pvts[principle]->digital = pri->pvts[x]->digital;
++                              pri->pvts[principle]->faxhandled = pri->pvts[x]->faxhandled;
++  
++                              if ((pri->nodetype == BRI_CPE_PTMP) || (pri->nodetype == BRI_CPE)) { 
++                                  /* this might also apply for other pri types! */
++                                  pri->pvts[principle]->law = pri->pvts[x]->law;
++                                  if (ioctl(pri->pvts[principle]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &pri->pvts[principle]->law) == -1)
++                                      ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", pri->pvts[principle]->channel, pri->pvts[principle]->law);
++                                  res = zt_setlaw(pri->pvts[principle]->subs[SUB_REAL].zfd, pri->pvts[principle]->law);
++                                  if (res < 0) 
++                                      ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[principle]->channel);
++                                  if (!pri->pvts[principle]->digital) {
++                                      res = set_actual_gain(pri->pvts[principle]->subs[SUB_REAL].zfd, 0, pri->pvts[principle]->rxgain, pri->pvts[principle]->txgain, pri->pvts[principle]->law);
++                                  } else {
++                                      res = set_actual_gain(pri->pvts[principle]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[principle]->law);
++                                  }
++                                  if (res < 0) 
++                                      ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[principle]->channel);
++                                  zt_confmute(pri->pvts[x], 0);
++                                  update_conf(pri->pvts[x]);
++                                  reset_conf(pri->pvts[x]);
++                                  restore_gains(pri->pvts[x]);
++                                  zt_disable_ec(pri->pvts[x]);
++                                  zt_setlinear(pri->pvts[x]->subs[SUB_REAL].zfd, 0);
++                              }
++  
++                              if (pri->pvts[principle]->owner) {
++                                  snprintf(tmpname, sizeof(tmpname), "Zap/%d-1", pri->pvts[principle]->channel);
++                                  ast_change_name(pri->pvts[principle]->owner, tmpname);
++                              }
++
++
+                               /* Free up the old channel, now not in use */
+                               pri->pvts[x]->subs[SUB_REAL].owner = NULL;
+                               pri->pvts[x]->owner = NULL;
+                               pri->pvts[x]->call = NULL;
++                              pri->pvts[x]->dsp = NULL;
+                       }
+                       return principle;
+               }
+@@ -7789,7 +8132,9 @@
+               }
+               crv = crv->next;
+       }
+-      ast_log(LOG_WARNING, "Call specified, but not found?\n");
++      if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++          ast_log(LOG_WARNING, "Call specified, but not found?\n");
++      }
+       return -1;
+ }
+@@ -7851,86 +8196,21 @@
+ #ifndef PRI_RESTART
+ #error "Upgrade your libpri"
+ #endif
+-static void zt_pri_message(struct pri *pri, char *s)
++static void zt_pri_message(char *s, int span)
+ {
+-      int x, y;
+-      int dchan = -1, span = -1;
+-      int dchancount = 0;
+-
+-      if (pri) {
+-              for (x = 0; x < NUM_SPANS; x++) {
+-                      for (y = 0; y < NUM_DCHANS; y++) {
+-                              if (pris[x].dchans[y])
+-                                      dchancount++;
+-
+-                              if (pris[x].dchans[y] == pri)
+-                                      dchan = y;
+-                      }
+-                      if (dchan >= 0) {
+-                              span = x;
+-                              break;
+-                      }
+-                      dchancount = 0;
+-              }
+-              if ((dchan >= 0) && (span >= 0)) {
+-                      if (dchancount > 1)
+-                              ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
+-                      else
+-                              ast_verbose("%s", s);
+-              } else
+-                      ast_verbose("PRI debug error: could not find pri associated it with debug message output\n");
+-      } else
+-              ast_verbose("%s", s);
+-
+-      ast_mutex_lock(&pridebugfdlock);
+-
+-      if (pridebugfd >= 0)
+-              write(pridebugfd, s, strlen(s));
+-
+-      ast_mutex_unlock(&pridebugfdlock);
++      ast_verbose("%d %s", span, s);
+ }
+-static void zt_pri_error(struct pri *pri, char *s)
++static void zt_pri_error(char *s, int span)
+ {
+-      int x, y;
+-      int dchan = -1, span = -1;
+-      int dchancount = 0;
+-
+-      if (pri) {
+-              for (x = 0; x < NUM_SPANS; x++) {
+-                      for (y = 0; y < NUM_DCHANS; y++) {
+-                              if (pris[x].dchans[y])
+-                                      dchancount++;
+-
+-                              if (pris[x].dchans[y] == pri)
+-                                      dchan = y;
+-                      }
+-                      if (dchan >= 0) {
+-                              span = x;
+-                              break;
+-                      }
+-                      dchancount = 0;
+-              }
+-              if ((dchan >= 0) && (span >= 0)) {
+-                      if (dchancount > 1)
+-                              ast_log(LOG_WARNING, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
+-                      else
+-                              ast_verbose("%s", s);
+-              } else
+-                      ast_verbose("PRI debug error: could not find pri associated it with debug message output\n");
+-      } else
+-              ast_log(LOG_WARNING, "%s", s);
+-
+-      ast_mutex_lock(&pridebugfdlock);
+-
+-      if (pridebugfd >= 0)
+-              write(pridebugfd, s, strlen(s));
+-
+-      ast_mutex_unlock(&pridebugfdlock);
++      ast_log(LOG_WARNING, "%d %s", span, s);
+ }
+ static int pri_check_restart(struct zt_pri *pri)
+ {
++      if ((pri->nodetype != PRI_NETWORK) || (pri->nodetype != PRI_CPE)) {
++          return 0;
++      }
+       do {
+               pri->resetpos++;
+       } while((pri->resetpos < pri->numchans) &&
+@@ -8013,6 +8293,32 @@
+       }
+ }
++static void pri_make_callerid(struct zt_pri *pri, char *callerid, int callerid_len, char *callingnum, int callingnum_len, int callingplan, int callingpres, int stripmsd) {
++    if (callingnum && (callingnum_len > stripmsd)) {
++      callingnum += stripmsd;
++    }
++    switch (callingplan) {
++      case PRI_INTERNATIONAL_ISDN:
++          snprintf(callerid, callerid_len, "%s%s", pri->internationalprefix, callingnum);
++          break;
++      case PRI_NATIONAL_ISDN:
++          snprintf(callerid, callerid_len, "%s%s", pri->nationalprefix, callingnum);
++          break;
++      case PRI_LOCAL_ISDN:
++          snprintf(callerid, callerid_len, "%s%s", pri->localprefix, callingnum);
++          break;
++      case PRI_PRIVATE:
++          snprintf(callerid, callerid_len, "%s%s", pri->privateprefix, callingnum);
++          break;
++      case PRI_UNKNOWN:
++          snprintf(callerid, callerid_len, "%s%s", pri->unknownprefix, callingnum);
++          break;
++      default:
++          snprintf(callerid, callerid_len, "%s", callingnum);
++          break;
++    }
++}
++
+ static void *pri_dchannel(void *vpri)
+ {
+       struct zt_pri *pri = vpri;
+@@ -8104,6 +8410,8 @@
+                               } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
+                                       activeidles++;
+                       }
++      //    ast_log(LOG_NOTICE, "name = %s condition = %d index = %d (%d) zfd = %d res = %d\n",chan->name, condition, index, SUB_REAL, p->subs[index].zfd, res);
++
+ #if 0
+                       printf("nextidle: %d, haveidles: %d, minunsed: %d\n",
+                               nextidle, haveidles, minunused);
+@@ -8205,9 +8513,36 @@
+                                       if (x == ZT_EVENT_ALARM) {
+                                               pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
+                                               pri_find_dchan(pri);
++                                              if ((pri->nodetype == BRI_CPE) || (pri->nodetype == BRI_CPE_PTMP)) {
++                                                  if (pri->pri) {
++                                                      ast_log(LOG_NOTICE, "pri_shutdown\n");
++                                                      for (i=0; i<pri->numchans; i++) {
++                                                          struct zt_pvt *p = pri->pvts[i];
++                                                          if (p) {
++                                                              if (p->call) {
++                                                                  if (p->pri && p->pri->pri) {
++                                                                      pri_destroycall(p->pri->pri, p->call);
++                                                                      p->call = NULL;
++                                                                      p->tei = -1;
++                                                                  } else
++                                                                      ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
++                                                              }
++                                                              if (p->owner)
++                                                                  p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++                                                              p->inalarm = 1;
++                                                          }
++                                                      }
++                                                      pri_shutdown(pri->pri);
++                                                  }
++                                              }
+                                       } else if (x == ZT_EVENT_NOALARM) {
+-                                              pri->dchanavail[which] |= DCHAN_NOTINALARM;
+-                                              pri_restart(pri->dchans[which]);
++                                              if ((pri->nodetype == BRI_CPE) || (pri->nodetype == BRI_CPE_PTMP)) {
++                                                  pri->dchanavail[which] |= DCHAN_NOTINALARM;
++                                                  pri->dchanavail[which] |= DCHAN_UP;
++                                              } else {
++                                                  pri->dchanavail[which] |= DCHAN_NOTINALARM;
++                                                  pri_restart(pri->dchans[which]);
++                                              }
+                                       }
+                               
+                                       if (option_debug)
+@@ -8219,8 +8554,7 @@
+                                       break;
+                       }
+               } else if (errno != EINTR)
+-                      ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
+-
++                      ast_log(LOG_WARNING, "pri_event returned error %d (%s) on span %d\n", errno, strerror(errno), pri->span);
+               if (e) {
+                       if (pri->debug)
+                               pri_dump_event(pri->dchans[which], e);
+@@ -8228,32 +8562,101 @@
+                               pri->dchanavail[which] |= DCHAN_UP;
+                       switch(e->e) {
+                       case PRI_EVENT_DCHAN_UP:
+-                              if (option_verbose > 1) 
+-                                      ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
+-                              pri->dchanavail[which] |= DCHAN_UP;
+-                              if (!pri->pri) pri_find_dchan(pri);
+-
+-                              /* Note presense of D-channel */
+-                              time(&pri->lastreset);
+-
+-                              /* Restart in 5 seconds */
+-                              if (pri->resetinterval > -1) {
+-                                      pri->lastreset -= pri->resetinterval;
+-                                      pri->lastreset += 5;
+-                              }
+-                              pri->resetting = 0;
+-                              /* Take the channels from inalarm condition */
+-                              for (i=0; i<pri->numchans; i++)
+-                                      if (pri->pvts[i]) {
+-                                              pri->pvts[i]->inalarm = 0;
+-                                      }
++                              if (pri->nodetype == BRI_NETWORK_PTMP) {
++                                  if (option_verbose > 3) 
++                                      ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up for TEI %d\n", pri_order(which), pri->span, e->gen.tei);
++                                  pri->dchanavail[which] |= (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP);
++                                  pri_find_dchan(pri);
++  
++                                  /* Note presense of D-channel */
++                                  time(&pri->lastreset);
++  
++                                  pri->resetting = 0;
++                                  /* Take the channels from inalarm condition */
++                                  for (i=0; i<pri->numchans; i++)
++                                      if (pri->pvts[i]) {
++                                              pri->pvts[i]->inalarm = 0;
++                                      }
++                              } else {
++                                  if (pri->nodetype == BRI_CPE_PTMP) {
++                                      if (option_verbose > 3) 
++                                          ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
++                                  } else {
++                                      if (option_verbose > 1) 
++                                          ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
++                                  }
++                                  pri->dchanavail[which] |= (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP);
++                                  pri_find_dchan(pri);
++  
++                                  /* Note presense of D-channel */
++                                  time(&pri->lastreset);
++  
++                                  /* Restart in 5 seconds */
++                                  pri->lastreset -= pri->resetinterval;
++                                  pri->lastreset += 5;
++                                  pri->resetting = 0;
++                                  /* Take the channels from inalarm condition */
++                                  for (i=0; i<pri->numchans; i++) {
++                                      struct zt_pvt *p = pri->pvts[i];
++                                      if (p) {
++                                          p->inalarm = 0;
++                                          /* hang up calls that are not bridged yet, dont touch bridged calls */
++                                          if (p->call) {
++                                              if (p->pri && p->pri->pri) {
++                                                  if (p->owner) {
++                                                      if (p->owner->_state != AST_STATE_UP) {
++                                                          p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++                                                          pri_destroycall(p->pri->pri, p->call);
++                                                      }
++                                                  } else {
++                                                      pri_destroycall(p->pri->pri, p->call);
++                                                  }
++                                                  p->call = NULL;
++                                              }
++                                          }
++                                      }
++                                  }
++                              }
+                               break;
+                       case PRI_EVENT_DCHAN_DOWN:
+-                              if (option_verbose > 1) 
+-                                      ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
+-                              pri->dchanavail[which] &= ~DCHAN_UP;
+-                              pri_find_dchan(pri);
+-                              if (!pri_is_up(pri)) {
++                              if (pri->nodetype == BRI_NETWORK_PTMP) {
++                                  if (option_verbose > 3) 
++                                      ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down for TEI %d\n", pri_order(which), pri->span, e->gen.tei);
++                                  // PTMP BRIs have N dchans, handled by libpri
++                                  if (e->gen.tei == 0) break;
++                                  /* Hangup active channels */
++                                  for (i=0; i<pri->numchans; i++) {
++                                      struct zt_pvt *p = pri->pvts[i];
++                                      if (p) {
++                      //              ast_log(LOG_NOTICE, "chan %d tei %d\n",i,p->tei);
++                                          if (p->tei == e->gen.tei) {
++                                              if (p->call) {
++                                                      if (p->pri && p->pri->pri) {
++                                                              pri_hangup(p->pri->pri, p->call, -1);
++                                                              pri_destroycall(p->pri->pri, p->call);
++                                                              p->tei = -1;
++                                                              p->call = NULL;
++                                                      } else
++                                                              ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
++                                              }
++                                              if (p->owner)
++                                                  p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++                                              p->inalarm = 1;
++                                              p->tei = -1;
++                                          }
++                                      }
++                                  } 
++                              } else {
++                                  if (pri->nodetype == BRI_CPE_PTMP) {
++                                      if (option_verbose > 3) 
++                                          ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
++                                  } else {
++                                      if (option_verbose > 1) 
++                                          ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
++                                  }
++                                  pri->dchanavail[which] &= ~DCHAN_UP;
++                                  pri_find_dchan(pri);
++                                  if (!pri_is_up(pri)) {
+                                       pri->resetting = 0;
+                                       /* Hangup active channels and put them in alarm mode */
+                                       for (i=0; i<pri->numchans; i++) {
+@@ -8261,7 +8664,7 @@
+                                               if (p) {
+                                                       if (p->call) {
+                                                               if (p->pri && p->pri->pri) {
+-                                                                      pri_hangup(p->pri->pri, p->call, -1);
++                                                              //      pri_hangup(p->pri->pri, p->call, -1);
+                                                                       pri_destroycall(p->pri->pri, p->call);
+                                                                       p->call = NULL;
+                                                               } else
+@@ -8274,6 +8677,7 @@
+                                                       p->inalarm = 1;
+                                               }
+                                       }
++                                  }
+                               }
+                               break;
+                       case PRI_EVENT_RESTART:
+@@ -8308,8 +8712,8 @@
+                                                               pri_destroycall(pri->pri, pri->pvts[x]->call);
+                                                               pri->pvts[x]->call = NULL;
+                                                       }
+-                                                      if (pri->pvts[chanpos]->realcall) 
+-                                                              pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
++                                                      if (pri->pvts[x]->realcall) 
++                                                              pri_hangup_all(pri->pvts[x]->realcall, pri);
+                                                       else if (pri->pvts[x]->owner)
+                                                               pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                                                       ast_mutex_unlock(&pri->pvts[x]->lock);
+@@ -8343,7 +8747,6 @@
+                                       }
+                               }
+                               break;
+-                              
+                       case PRI_EVENT_INFO_RECEIVED:
+                               chanpos = pri_find_principle(pri, e->ring.channel);
+                               if (chanpos < 0) {
+@@ -8352,9 +8755,11 @@
+                               } else {
+                                       chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
+                                       if (chanpos > -1) {
++//                                    ast_log(LOG_NOTICE, "INFO received on  channel %d/%d span %d\n", 
++//                                            PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+                                               ast_mutex_lock(&pri->pvts[chanpos]->lock);
+                                               /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
+-                                              if (pri->overlapdial && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
++                                              if (pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
+                                                       /* how to do that */
+                                                       int digitlen = strlen(e->ring.callednum);
+                                                       char digit;
+@@ -8366,6 +8771,14 @@
+                                                                       zap_queue_frame(pri->pvts[chanpos], &f, pri);
+                                                               }
+                                                       }
++                                                      if (!pri->overlapdial) {
++                                                          strncat(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
++                                                          if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten + 1)) {
++                                                              tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++                                                          } else {
++                                                              tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++                                                          }
++                                                      } 
+                                               }
+                                               ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+                                       }
+@@ -8373,39 +8786,55 @@
+                               break;
+                       case PRI_EVENT_RING:
+                               crv = NULL;
+-                              if (e->ring.channel == -1)
++                              if (e->ring.channel == -1) {
++                                      /* if no channel specified find one empty */
+                                       chanpos = pri_find_empty_chan(pri, 1);
+-                              else
++                              } else {
+                                       chanpos = pri_find_principle(pri, e->ring.channel);
+-                              /* if no channel specified find one empty */
++                              }
+                               if (chanpos < 0) {
+-                                      ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n", 
+-                                              PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
++                                      /* no channel specified and no free channel. this is a callwating SETUP */
++                                      if (e->ring.channel == -1) {
++                                          if (option_verbose > 2)
++                                              ast_verbose(VERBOSE_PREFIX_3 "Ignoring callwaiting SETUP on channel %d/%d span %d %d\n", PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span, e->ring.channel);
++                                          pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_USER_BUSY);
++                                          break;
++                                      }
+                               } else {
++                                      /* ok, we got a b channel for this call, lock it */
+                                       ast_mutex_lock(&pri->pvts[chanpos]->lock);
+                                       if (pri->pvts[chanpos]->owner) {
+-                                              if (pri->pvts[chanpos]->call == e->ring.call) {
+-                                                      ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
+-                                                              PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+-                                                      break;
+-                                              } else {
+-                                                      ast_log(LOG_WARNING, "Ring requested on channel %d/%d already in use on span %d.  Hanging up owner.\n", 
++                                          /* safety check, for messed up retransmissions? */
++                                          if (pri->pvts[chanpos]->call == e->ring.call) {
++                                              ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
+                                                       PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+-                                                      if (pri->pvts[chanpos]->realcall) 
+-                                                              pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
+-                                                      else
+-                                                              pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+-                                                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+-                                                      chanpos = -1;
+-                                              }
+-                                      }
+-                                      if (chanpos > -1)
+                                               ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                              chanpos = -1;
++                                              break;
++                                          } else {
++                                              ast_log(LOG_WARNING, "Ring requested on channel %d/%d already in use on span %d. Hanging up owner.\n", 
++                                              PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
++                                              if (pri->pvts[chanpos]->realcall) 
++                                                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
++                                              else
++                                                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++                                              ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                              chanpos = -1;
++                                              break;
++                                          }
++                                      }
++                                      if (chanpos > -1) {
++                                              /* everything is ok with the b channel */
++                                          ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                      }
+                               }
+-                              if ((chanpos < 0) && (e->ring.flexible))
+-                                      chanpos = pri_find_empty_chan(pri, 1);
++                              /* actually, we already got a valid channel by now */
+                               if (chanpos > -1) {
+                                       ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                      /* dont detect dtmfs before the signalling is done */
++                                      disable_dtmf_detect(pri->pvts[chanpos]);
++                                      /* this channel is owned by this TEI */
++                                      pri->pvts[chanpos]->tei = e->ring.tei;
+                                       if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+                                               /* Should be safe to lock CRV AFAIK while bearer is still locked */
+                                               crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
+@@ -8426,6 +8855,7 @@
+                                                       break;
+                                               }
+                                       }
++                                      /* assign call to b channel */
+                                       pri->pvts[chanpos]->call = e->ring.call;
+                                       apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+                                       if (pri->pvts[chanpos]->use_callerid) {
+@@ -8450,29 +8880,78 @@
+                                       }
+                                       apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
+                                                            e->ring.redirectingnum, e->ring.callingplanrdnis);
++                                      /* get callingpres */
++                                      pri->pvts[chanpos]->cid_pres = e->ring.callingpres;
++                                      switch (e->ring.callingpres) {
++                                          case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++                                          case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++                                          case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++                                          case PRES_PROHIB_NETWORK_NUMBER:
++                                              strncpy(pri->pvts[chanpos]->cid_name, pri->withheldcid, sizeof(pri->pvts[chanpos]->cid_name));
++                                              break;
++                                          case PRES_NUMBER_NOT_AVAILABLE:
++                                              strncpy(pri->pvts[chanpos]->cid_name, pri->nocid, sizeof(pri->pvts[chanpos]->cid_name));
++                                              break;
++                                      }
+                                       /* If immediate=yes go to s|1 */
+                                       if (pri->pvts[chanpos]->immediate) {
+                                               if (option_verbose > 2)
+                                                       ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of immediate=yes\n");
+                                               pri->pvts[chanpos]->exten[0] = 's';
+                                               pri->pvts[chanpos]->exten[1] = '\0';
+-                                      }
+-                                      /* Get called number */
+-                                      else if (!ast_strlen_zero(e->ring.callednum)) {
+-                                              ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+-                                              ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+-                                      } else
+-                                              pri->pvts[chanpos]->exten[0] = '\0';
+-                                      /* Set DNID on all incoming calls -- even immediate */
+-                                      if (!ast_strlen_zero(e->ring.callednum))
+-                                              ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
+-                                      /* No number yet, but received "sending complete"? */
+-                                      if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
++                                      } else if (ast_strlen_zero(e->ring.callednum)) {
++                                          /* called party number is empty */
++                                          if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
++                                              if (!pri->overlapdial) {
++                                                  // be able to set digittimeout for BRI phones
++                                                  pri->pvts[chanpos]->exten[0] = 's';
++                                                  pri->pvts[chanpos]->exten[1] = '\0';
++                                                  tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++                                              } else {
++                                                  pri->pvts[chanpos]->exten[0] = '\0';
++                                              }
++                                          } else {
++                                              if (pri->nodetype == BRI_CPE) { 
++                                                  /* fix for .at p2p bri lines */
++                                                  pri->pvts[chanpos]->exten[0] = 's';
++                                                  pri->pvts[chanpos]->exten[1] = '\0';
++                                              } else {
++                                                  pri->pvts[chanpos]->exten[0] = '\0';
++                                              }
++                                          }
++                                          /* No number yet, but received "sending complete"? */
++                                          if (e->ring.complete) {
+                                               if (option_verbose > 2)
+                                                       ast_verbose(VERBOSE_PREFIX_3 "Going to extension s|1 because of Complete received\n");
+                                               pri->pvts[chanpos]->exten[0] = 's';
+                                               pri->pvts[chanpos]->exten[1] = '\0';
+-                                      }
++                                          }
++                                      } else {
++                                              /* Get called number */
++                                              pri_make_callerid(pri, pri->pvts[chanpos]->dnid, sizeof(pri->pvts[chanpos]->dnid), e->ring.callednum, sizeof(e->ring.callednum),  e->ring.calledplan, 0, pri->pvts[chanpos]->stripmsd);
++                                              pri_make_callerid(pri, pri->pvts[chanpos]->exten, sizeof(pri->pvts[chanpos]->exten), e->ring.callednum, sizeof(e->ring.callednum), e->ring.calledplan, 0, pri->pvts[chanpos]->stripmsd);
++                                              if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) {
++                                                  /* if we get the next digit we should stop the dialtone */
++                                                  if (!pri->overlapdial) {
++                                                      // with overlapdial=no the exten is always prefixed by "s"
++                                                      if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten + 1)) {
++                                                          tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++                                                      } else {
++                                                          tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++                                                      }
++                                                  } else {
++                                                      if (!ast_ignore_pattern(pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten)) {
++                                                          tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, -1);
++                                                      } else {
++                                                          tone_zone_play_tone(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_TONE_DIALTONE);
++                                                      }
++                                                  }
++                                              }
++                                      }
++                                      /* Part 3: create channel, setup audio... */
++                                      /* Set DNID on all incoming calls -- even immediate */
++                                      if (!ast_strlen_zero(e->ring.callednum))
++                                              strncpy(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid) - 1);
+                                       /* Make sure extension exists (or in overlap dial mode, can exist) */
+                                       if ((pri->overlapdial && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+                                               ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+@@ -8491,22 +8970,38 @@
+                                               res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
+                                               if (res < 0) 
+                                                       ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
+-                                              res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++                                              if (IS_DIGITAL(e->ring.ctype)) {
++                                                  res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[chanpos]->law);
++                                              } else {
++                                                  res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++                                              }
+                                               if (res < 0)
+                                                       ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
+-                                              if (e->ring.complete || !pri->overlapdial)
++                                              if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++                                                  if (e->ring.complete || !pri->overlapdial) {
+                                                       /* Just announce proceeding */
+                                                       pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
+-                                              else  {
++                                              //      pri->pvts[chanpos]->ignoredtmf = 0;
++                                                  } else  {
+                                                       if (pri->switchtype != PRI_SWITCH_GR303_TMC) 
+                                                               pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+                                                       else
+                                                               pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
++                                                  }
++                                              } else {
++                                                      /* BRI_NETWORK | BRI_NETWORK_PTMP */
++                                                      if (pri->overlapdial || (!strcasecmp(pri->pvts[chanpos]->exten, "s"))) {
++                                                          /* send a SETUP_ACKNOWLEDGE */
++                                                          pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
++                                                      } else {
++                                                          /* send an ALERTING ??? wtf */
++                                                      //    pri_acknowledge(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
++                                                          pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
++                                                      }
+                                               }
+-                                              /* Get the use_callingpres state */
+-                                              pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+-                                      
+-                                              /* Start PBX */
++
++                                              /* overlapdial = yes  and the extension can be valid */
++
+                                               if (pri->overlapdial && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+                                                       /* Release the PRI lock while we create the channel */
+                                                       ast_mutex_unlock(&pri->lock);
+@@ -8518,10 +9013,21 @@
+                                                               ast_log(LOG_DEBUG, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
+                                                       } else {
+                                                               c = zt_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
++                                                              zt_enable_ec(pri->pvts[chanpos]);
+                                                       }
+                                                       if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+                                                               pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+                                                       }
++                                                      if (!ast_strlen_zero(e->ring.callingnum)) {
++                                                          char tmpstr[256];
++                                                          pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingnum, sizeof(e->ring.callingnum), e->ring.callingplan, e->ring.callingpres, 0);
++                                                          pbx_builtin_setvar_helper(c, "PRI_NETWORK_CID", tmpstr);
++                                                      }
++                                                      if (!ast_strlen_zero(e->ring.callingani)) {
++                                                          char tmpstr[256];
++                                                          pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingani, sizeof(e->ring.callingani), e->ring.callingplanuser, e->ring.callingpresuser, 0);
++                                                          pbx_builtin_setvar_helper(c, "PRI_USER_CID", e->ring.callednum);
++                                                      }
+                                                       if(e->ring.ani2 >= 0) {
+                                                               snprintf(ani2str, 5, "%.2d", e->ring.ani2);
+                                                               pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+@@ -8541,8 +9047,8 @@
+                                                       ast_mutex_lock(&pri->lock);
+                                                       if (c && !ast_pthread_create(&threadid, &attr, ss_thread, c)) {
+                                                               if (option_verbose > 2)
+-                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+-                                                                              plancallingnum, !ast_strlen_zero(pri->pvts[chanpos]->exten) ? pri->pvts[chanpos]->exten : "<unspecified>", 
++                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepting overlap %s call from '%s' to '%s' on channel %d/%d, span %d\n",
++                                                                              pri->pvts[chanpos]->digital ? "data" : "voice", plancallingnum, !ast_strlen_zero(pri->pvts[chanpos]->exten) ? pri->pvts[chanpos]->exten : "<unspecified>", 
+                                                                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+                                                       } else {
+                                                               ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", 
+@@ -8555,6 +9061,7 @@
+                                                               }
+                                                       }
+                                               } else  {
++                                              /* overlapdial = no */    
+                                                       ast_mutex_unlock(&pri->lock);
+                                                       /* Release PRI lock while we create the channel */
+                                                       c = zt_new(pri->pvts[chanpos], AST_STATE_RING, 1, SUB_REAL, law, e->ring.ctype);
+@@ -8578,10 +9085,26 @@
+                                                               snprintf(calledtonstr, sizeof(calledtonstr)-1, "%d", e->ring.calledplan);
+                                                               pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+                                                               if (option_verbose > 2)
+-                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+-                                                                              plancallingnum, pri->pvts[chanpos]->exten, 
++                                                                      ast_verbose(VERBOSE_PREFIX_3 "Accepting %s call from '%s' to '%s' on channel %d/%d, span %d\n",
++                                                                              pri->pvts[chanpos]->digital ? "data" : "voice", e->ring.callingnum, pri->pvts[chanpos]->exten, 
+                                                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+                                                               zt_enable_ec(pri->pvts[chanpos]);
++                                                          if(!ast_strlen_zero(e->ring.callingsubaddr)) {
++                                                              pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
++                                                          }
++                                                          if (!ast_strlen_zero(e->ring.callingnum)) {
++                                                              char tmpstr[256];
++                                                              pri_make_callerid(pri, tmpstr, sizeof(tmpstr), e->ring.callingnum, sizeof(e->ring.callingnum), e->ring.callingplan, e->ring.callingpres, 0);
++                                                              pbx_builtin_setvar_helper(c, "PRI_NETWORK_CID", tmpstr);
++                                                          }
++                                                          if (!ast_strlen_zero(e->ring.callingani)) {
++                                                              char tmpstr[256];
++                                                              pri_make_callerid(pri, tmpstr,sizeof(tmpstr),  e->ring.callingani, sizeof(e->ring.callingani), e->ring.callingplanuser, e->ring.callingpresuser, 0);
++                                                              pbx_builtin_setvar_helper(c, "PRI_USER_CID", e->ring.callednum);
++                                                          }
++                                                          if (!ast_strlen_zero(e->ring.useruserinfo)) {
++                                                              pbx_builtin_setvar_helper(c, "UUI", e->ring.useruserinfo);
++                                                          }
+                                                       } else {
+                                                               ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", 
+                                                                       pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+@@ -8590,6 +9113,7 @@
+                                                       }
+                                               }
+                                       } else {
++                                      /* invalid extension */
+                                               if (option_verbose > 2)
+                                                       ast_verbose(VERBOSE_PREFIX_3 "Extension '%s' in context '%s' from '%s' does not exist.  Rejecting call on channel %d/%d, span %d\n",
+                                                               pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan, 
+@@ -8620,7 +9144,7 @@
+                                       } else {
+                                               ast_mutex_lock(&pri->pvts[chanpos]->lock);
+                                               if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
+-                                                      zt_enable_ec(pri->pvts[chanpos]);
++                                              // XXX  zt_enable_ec(pri->pvts[chanpos]);
+                                                       pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
+                                                       pri->pvts[chanpos]->alerting = 1;
+                                               } else
+@@ -8649,9 +9173,15 @@
+                               }
+                               break;
+                       case PRI_EVENT_PROGRESS:
+-                              /* Get chan value if e->e is not PRI_EVNT_RINGING */
++                              /* Get chan value if e->e is not PRI_EVENT_RINGING */
+                               chanpos = pri_find_principle(pri, e->proceeding.channel);
+                               if (chanpos > -1) {
++                                  if ((pri->pvts[chanpos]->priindication_oob == 2) && (e->proceeding.cause == PRI_CAUSE_USER_BUSY)) {
++                                      /* received PROGRESS with cause BUSY, no inband callprogress wanted => hang up! */
++                                      if (pri->pvts[chanpos]->owner) {
++                                          pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++                                      }
++                                  } else {
+ #ifdef PRI_PROGRESS_MASK
+                                       if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
+ #else
+@@ -8698,6 +9228,12 @@
+                       case PRI_EVENT_PROCEEDING:
+                               chanpos = pri_find_principle(pri, e->proceeding.channel);
+                               if (chanpos > -1) {
++                                  chanpos = pri_fixup_principle(pri, chanpos, e->proceeding.call);
++                                  if (chanpos < 0) {
++                                      ast_log(LOG_WARNING, "Received PROCEEDING on channel %d/%d not in use on span %d\n", 
++                                              PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), pri->span);
++                                      chanpos = -1;
++                                  } else {
+                                       if (!pri->pvts[chanpos]->proceeding) {
+                                               struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
+                                               
+@@ -8748,6 +9284,295 @@
+                                       }
+                               }
+                               break;                          
++                      case PRI_EVENT_SUSPEND_REQ:
++                              if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++                                  pri_suspend_reject(pri->pri, e->suspend_req.call, "");
++                                  break;
++                              }
++                              chanpos = pri_find_principle(pri, e->suspend_req.channel);
++                              if (chanpos < 0)  {
++                                      ast_log(LOG_WARNING, "Suspend requested on unconfigured channel %d span %d\n", chanpos, pri->span);
++                                      chanpos = -1;
++                              }
++
++                              if (chanpos > -1) {
++                                  ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                  if (pri->pvts[chanpos]->owner) {
++                                      if (ast_bridged_channel(pri->pvts[chanpos]->owner)) {
++                                          struct zt_suspended_call *zpc;
++                                          char tmpstr[256];
++                                          zpc = malloc(sizeof(struct zt_suspended_call));
++                                          if (!zpc) {
++                                              ast_log(LOG_ERROR, "unable to malloc zt_suspended_call\n");
++                                              break;
++                                          }
++                                          strncpy(zpc->msn,  pri->pvts[chanpos]->cid_num, sizeof(zpc->msn));
++                                          strncpy(zpc->callid,  e->suspend_req.callid, sizeof(zpc->callid));
++                                          ast_masq_park_call(ast_bridged_channel(pri->pvts[chanpos]->owner), NULL, 0, &zpc->parked_at);
++                                          zpc->next = pri->suspended_calls;
++                                          pri->suspended_calls = zpc;
++                                          snprintf(tmpstr, sizeof(tmpstr), "Parked at %d", zpc->parked_at);
++                                          pri_suspend_acknowledge(pri->pri, e->suspend_req.call,tmpstr);
++                                          pri->pvts[chanpos]->call = NULL;
++                                          pri->pvts[chanpos]->tei = -1;
++                                          pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++                                      } else {
++                                          pri_suspend_reject(pri->pri, e->suspend_req.call, "cant park a non-bridge");
++                                          ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                          break;
++                                      }
++                                  } else {
++                                      pri_suspend_reject(pri->pri, e->suspend_req.call, "");
++                                  }
++                                  ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                              }
++                              break;
++                      case PRI_EVENT_RESUME_REQ:
++                              if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++                                  break;
++                              }
++                              chanpos = pri_find_empty_chan(pri, 1);
++                              if (chanpos < 0) { 
++                                      pri_resume_reject(pri->pri, e->resume_req.call,"All channels busy");
++                                      ast_log(LOG_WARNING, "Resume requested on odd channel number %d span %d\n", chanpos, pri->span);
++                                      chanpos = -1;
++                              } else if (!pri->pvts[chanpos]) {
++                                      pri_resume_reject(pri->pri, e->resume_req.call,"General protection fault in module 0x0BRI");
++                                      chanpos = -1;
++                              }
++
++                              if (chanpos > -1) {
++                                  ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                  if (!pri->pvts[chanpos]->owner) {
++                                      struct zt_suspended_call *zpc, *zpcl;
++                                      int unparked=0;
++                                      char extenstr[255], temp[255];
++                                      zpc = NULL;
++                                      zpcl = pri->suspended_calls;
++                                      while (zpcl) {
++                                      //    ast_log(LOG_NOTICE, "zpc->parked_at %d zpcl->callid %s\n",zpcl->parked_at, zpcl->callid);
++                                          if (((strlen(zpcl->callid) == 0) && (strlen(e->resume_req.callid)==0)) || (!strcmp(zpcl->callid,e->resume_req.callid))) {
++                                              int law;
++                                              // found a parked call
++                                              snprintf(extenstr, sizeof(extenstr), "%d", zpcl->parked_at);
++                                              strncpy(pri->pvts[chanpos]->exten, extenstr, sizeof(pri->pvts[chanpos]->exten));
++                                      //      strncpy(pri->pvts[chanpos]->context, ast_parking_con(), sizeof(pri->pvts[chanpos]->context));
++                                              pri->pvts[chanpos]->call = e->resume_req.call;
++                                              law = 1;
++                                              if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++                                                  ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law);
++                                      // uhh ohh...what shall we do without the bearer cap???
++                                              law = ZT_LAW_ALAW;
++                                              res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
++                                              if (res < 0) 
++                                                  ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++                                              if (!pri->pvts[chanpos]->digital) {
++                                                  res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++                                              } else {
++                                                  res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, 0, 0, pri->pvts[chanpos]->law);
++                                              }
++                                              if (res < 0)
++                                                  ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++                                              /* Start PBX */
++                                              c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 1, SUB_REAL, law, PRI_TRANS_CAP_SPEECH);
++                                              if (c) {
++                                                  pri->pvts[chanpos]->owner = c;
++                                                  pri->pvts[chanpos]->call = e->resume_req.call;
++                                                  zt_enable_ec(pri->pvts[chanpos]);
++                                                  zt_train_ec(pri->pvts[chanpos]);
++                                              } else {
++                                                  ast_log(LOG_ERROR, "unable to start pbx\n");
++                                              }
++
++                                              if (zpc) {
++                                                  zpc->next = zpcl->next;
++                                                  free(zpcl);
++                                                  zpcl = zpc->next;
++                                              } else {
++                                                  // remove head
++                                                  pri->suspended_calls = zpcl->next;
++                                                  free(zpcl);
++                                                  zpcl = pri->suspended_calls;
++                                                  zpc = NULL;
++                                              }
++                                              unparked = 1;
++                                              snprintf(temp, sizeof(temp), "Unparked %s", extenstr);
++                                              pri_resume_acknowledge(pri->pri, e->resume_req.call, chanpos + 1, temp);
++                                              break;
++                                          }
++                                          zpc = zpcl;
++                                          if (zpcl) zpcl = zpcl->next;
++                                      }
++                                      if (!unparked)
++                                          pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!");
++                                  } else {
++                                      pri_resume_reject(pri->pri, e->resume_req.call,"No suspended call to unpark!");
++                                  }
++                                  ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                              }
++                              break;
++                      case PRI_EVENT_HOLD_REQ:
++                              if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++                                  pri_hold_reject(pri->pri, e->hold_req.call);
++                                  break;
++                              }
++                              chanpos = pri_find_principle(pri, e->hold_req.channel);
++                              if (chanpos < 0)  {
++                                      ast_log(LOG_WARNING, "Hold requested on unconfigured channel %d span %d\n", chanpos, pri->span);
++                                      chanpos = -1;
++                              }
++                              if (chanpos > -1) {
++                              //    ast_log(LOG_NOTICE, "Hold request for channel number %d span %d\n", chanpos, pri->span);
++                                  ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                  if (pri->pvts[chanpos]->owner) {
++                                      struct zt_pvt *p = pri->pvts[chanpos];
++                                      struct zt_holded_call *zhc;
++                                      int holdacked=0;
++                                      
++//                                    ast_log(LOG_NOTICE,"HOLD request from channel %s tei %d\n",p->owner->name, e->hold_req.tei);
++                                      if (ast_bridged_channel(p->owner)) {
++                                          zhc = malloc(sizeof(struct zt_holded_call));
++                                          if (!zhc) {
++                                              ast_log(LOG_ERROR, "unable to malloc zt_holded_call\n");
++                                              break;
++                                          }
++                                          memset(zhc, 0, sizeof(zhc));
++                                          strncpy(zhc->msn,  pri->pvts[chanpos]->cid_num, sizeof(zhc->msn));
++                                          strncpy(zhc->uniqueid,  ast_bridged_channel(p->owner)->uniqueid, sizeof(zhc->uniqueid));
++                                          zhc->tei = e->hold_req.tei;
++                                          zhc->cref = e->hold_req.cref;
++                                          zhc->call = e->hold_req.call;
++                                          zhc->channel = p->owner;
++                                          zhc->alreadyhungup = 0;
++                                          zhc->bridge = ast_bridged_channel(p->owner);
++                                          zhc->next = pri->holded_calls;
++                                          pri->holded_calls = zhc;
++
++                                          /* put channel on hold */
++                                          ast_masq_hold_call(ast_bridged_channel(p->owner), p->owner);
++
++                                          pri_hold_acknowledge(pri->pri, e->hold_req.call);
++                                          holdacked = 1;
++                                          p->call = NULL; // free the bchannel withouth destroying the call
++                                          p->tei = -1;
++                                      } else {
++                                          // cant hold a non-bridge,...yet
++                                          
++                                          // make a fake channel
++                                          
++                                          // masquerade
++                                          
++                                          // put on hold
++                                          pri_hold_reject(pri->pri, e->hold_req.call);
++                                      }
++                                  } else {
++                                          pri_hold_reject(pri->pri, e->hold_req.call);
++                                  }
++                                  ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                              } else {
++                                      pri_hold_reject(pri->pri, e->hold_req.call);
++                              }
++                              break; 
++                      case PRI_EVENT_RETRIEVE_REQ:
++                              if ((pri->nodetype != BRI_NETWORK_PTMP) && (pri->nodetype != BRI_NETWORK)) {
++                                  pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++                                  break;
++                              }
++                              chanpos = pri_find_empty_chan(pri, 1);
++                              if (chanpos < 0) { 
++                                      pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++                                      ast_log(LOG_WARNING, "Retrieve requested on odd channel number %d span %d\n", chanpos, pri->span);
++                                      chanpos = -1;
++                                      break;
++                              } else if (!pri->pvts[chanpos]) {
++                                      ast_log(LOG_WARNING, "Retrieve requested on unconfigured channel number %d span %d\n", chanpos, pri->span);
++                                      pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++                                      chanpos = -1;
++                                      break;
++                              }
++                              if (chanpos > -1) {
++                                  struct zt_holded_call *onhold = NULL;
++                                  int retrieved = 0;
++                                  int res = -1;
++                                  struct app_tmp *tmp;
++                                  pthread_attr_t attr;
++                                  int law;
++
++                                  onhold = pri_get_callonhold(pri, e->retrieve_req.cref, e->retrieve_req.tei);
++
++                                  if (!onhold) {
++                                      pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++                                      break;
++                                  }
++                                  ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                      // found a parked call
++                                      law = 1;
++                                      if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1)
++                                          ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]), law);
++                                      // uhh ohh...what shall we do without the bearer cap???
++                                      law = ZT_LAW_ALAW;
++                                      res = zt_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].zfd, law);
++                                      if (res < 0) 
++                                          ast_log(LOG_WARNING, "Unable to set law on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++                                      res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].zfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
++                                      if (res < 0)
++                                          ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", PVT_TO_CHANNEL(pri->pvts[chanpos]));
++                                      /* Start PBX */
++                                      c = zt_new(pri->pvts[chanpos], AST_STATE_UP, 0, SUB_REAL, law, PRI_TRANS_CAP_SPEECH);
++                                      if (c) {
++                                          pri->pvts[chanpos]->owner = c;
++                                          pri->pvts[chanpos]->outgoing = 1; /* for not sending proceedings... */
++                                          pri->pvts[chanpos]->call = e->retrieve_req.call;
++                                          pri->pvts[chanpos]->tei = e->retrieve_req.tei;
++                                          zt_enable_ec(pri->pvts[chanpos]);
++                                          zt_train_ec(pri->pvts[chanpos]);
++                                      } else {
++                                          ast_log(LOG_ERROR, "unable to start pbx\n");
++                                      }
++
++                                      retrieved = 1;
++                              //      ast_log(LOG_NOTICE, "sending RETRIEVE ACK on channel %d, span %d for tei %d cref %d\n",chanpos,pri->span, e->retrieve_req.tei,  e->retrieve_req.cref);
++                                      pri_retrieve_acknowledge(pri->pri, e->retrieve_req.call, chanpos + 1);
++
++                                      // the magic begins here: ....
++                                      tmp = malloc(sizeof(struct app_tmp));
++                                      if (tmp) {
++                                          memset(tmp, 0, sizeof(struct app_tmp));
++                                          strncpy(tmp->app, "holdedcall", sizeof(tmp->app) - 1);
++                                          strncpy(tmp->data, onhold->uniqueid, sizeof(tmp->data) - 1);
++                                          tmp->chan = c;
++                                      }
++                                      pri_destroy_callonhold(pri, onhold);
++                                      onhold = NULL;
++
++                                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                      pthread_attr_init(&attr);
++                                      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++                                      if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
++                                          ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", c->name, strerror(errno));
++                                          free(tmp);
++                                          ast_hangup(c);
++                                          retrieved = 0;
++                                      }
++
++                                  if (!retrieved) {
++                                      pri_retrieve_reject(pri->pri, e->retrieve_req.call);
++                                  }
++                              }
++                              break; 
++                      case PRI_EVENT_DISPLAY_RECEIVED:
++                              ast_log(LOG_NOTICE, "DISPLAY IE: [ %s ] received\n",e->display.text);
++                              chanpos = pri_find_principle(pri, e->display.channel);
++                              if (chanpos < 0) {
++                                  ast_log(LOG_WARNING, "odd channel number %d span %d\n", chanpos, pri->span);
++                                  chanpos = -1;
++                              } 
++                              if (chanpos > -1) {
++                                  if (pri->pvts[chanpos]->owner) {
++                      //              ast_sendtext(pri->pvt[chanpos]->owner, e->display.text);
++                                  }
++                              }                               
++                              break;
+                       case PRI_EVENT_ANSWER:
+                               chanpos = pri_find_principle(pri, e->answer.channel);
+                               if (chanpos < 0) {
+@@ -8763,6 +9588,7 @@
+                                               chanpos = -1;
+                                       } else {
+                                               ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                              pri->pvts[chanpos]->tei = e->answer.tei;
+                                               /* Now we can do call progress detection */
+                                               /* We changed this so it turns on the DSP no matter what... progress or no progress.
+@@ -8792,11 +9618,15 @@
+                                                               ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
+                                                       pri->pvts[chanpos]->dop.dialstr[0] = '\0';
+                                               } else if (pri->pvts[chanpos]->confirmanswer) {
+-                                                      ast_log(LOG_DEBUG, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
++                                                      ast_log(LOG_DEBUG, "Waiting for answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
+                                               } else {
++                                                      pri->pvts[chanpos]->dialing = 0;
+                                                       pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
+                                                       /* Enable echo cancellation if it's not on already */
+                                                       zt_enable_ec(pri->pvts[chanpos]);
++                                                      zt_train_ec(pri->pvts[chanpos]);
++                                                      /* stop ignoring inband dtmf */
++                                                      enable_dtmf_detect(pri->pvts[chanpos]);
+                                               }
+ #ifdef SUPPORT_USERUSER
+@@ -8845,18 +9675,21 @@
+                                                               }
+                                                       }
+                                                       if (option_verbose > 2) 
+-                                                              ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup\n", 
+-                                                                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
++                                                              ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup, cause %d\n", 
++                                                                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
+                                               } else {
+                                                       pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+                                                       pri->pvts[chanpos]->call = NULL;
++                                                      pri->pvts[chanpos]->tei = -1;
+                                               }
+                                               if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
+-                                                      if (option_verbose > 2)
++                                                      if ((pri->nodetype != BRI_CPE_PTMP) && (pri->nodetype != BRI_NETWORK_PTMP)) {
++                                                          if (option_verbose > 2)
+                                                               ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d on span %d since channel reported in use\n", 
+                                                                       PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+-                                                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+-                                                      pri->pvts[chanpos]->resetting = 1;
++                                                          pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
++                                                          pri->pvts[chanpos]->resetting = 1;
++                                                      }
+                                               }
+                                               if (e->hangup.aoc_units > -1)
+                                                       if (option_verbose > 2)
+@@ -8871,8 +9704,20 @@
+                                               ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+                                       } else {
+-                                              ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
+-                                                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                              struct zt_holded_call *onhold = NULL;
++                                              /* check calls on hold */
++                                              onhold = pri_get_callonhold(pri, e->hangup.cref, e->hangup.tei);
++                                              
++                                              if (onhold) {
++                                                  // ast_log(LOG_NOTICE, "hangup, found cref %d, tei %d\n",e->hangup.cref, e->hangup.tei);
++                                                  pri_hangup(pri->pri, onhold->call, e->hangup.cause);
++                                                  pri_destroy_callonhold(pri, onhold);
++                                                  onhold = NULL;
++                                              } else {
++                                                  ast_log(LOG_NOTICE, "Hangup, did not find cref %d, tei %d\n",e->hangup.cref, e->hangup.tei);
++                                                  ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
++                                                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                              }
+                                       }
+                               } 
+                               break;
+@@ -8882,17 +9727,25 @@
+                       case PRI_EVENT_HANGUP_REQ:
+                               chanpos = pri_find_principle(pri, e->hangup.channel);
+                               if (chanpos < 0) {
+-                                      ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
+-                                              PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                      if (pri->nodetype == BRI_NETWORK_PTMP) {
++                                          pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
++                                      } else {
++                                          ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
++                                              PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                      }
+                                       chanpos = -1;
+                               }
+-                              if (chanpos > -1) {
++                              /* dont hang up if we want to hear inband call progress */
++                              if ((chanpos > -1) && ((pri->pvts[chanpos]->priindication_oob != 2) || (!e->hangup.inband_progress) || (!pri->pvts[chanpos]->outgoing))){
+                                       chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
+                                       if (chanpos > -1) {
+                                               ast_mutex_lock(&pri->pvts[chanpos]->lock);
+                                               if (pri->pvts[chanpos]->realcall) 
+                                                       pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
+                                               else if (pri->pvts[chanpos]->owner) {
++                                                      char tmpstr[256];
++                                                      snprintf(tmpstr, sizeof(tmpstr), "%d", e->hangup.cause);
++                                                      pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "PRI_CAUSE", tmpstr);
+                                                       pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
+                                                       switch(e->hangup.cause) {
+                                                       case PRI_CAUSE_USER_BUSY:
+@@ -8915,16 +9768,73 @@
+                                                               if (option_verbose > 2)
+                                                                       ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
+                                                                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
++                                                      if (pri->nodetype == BRI_NETWORK_PTMP) {
++                                                          // check for bri transfers, not everybody uses ECT...
++                                                          if (pri->pvts[chanpos]->owner) {
++                                                              // find on hold call
++                                                              struct zt_holded_call *onhold = NULL;
++                                                              struct ast_channel *transferee = NULL;
++                                                              int transfer_ok = 0;
++ 
++                                                              onhold = pri_get_callonhold(pri, -1, e->hangup.tei);
++ 
++                                                              if (onhold) {
++                                                                  if (pri->pvts[chanpos]->pritransfer == 2) {
++                                                                      if (((pri->pvts[chanpos]->owner->_state != AST_STATE_RING) && (pri->pvts[chanpos]->owner->_state != AST_STATE_RESERVED)) || ((!ast_strlen_zero(pri->pvts[chanpos]->exten)) && (strncasecmp(pri->pvts[chanpos]->exten, "s", sizeof(pri->pvts[chanpos]->exten))))) {
++                                                                          transferee = ast_get_holded_call(onhold->uniqueid);
++ 
++                                                                          if (transferee) {
++                                                                              if (pri->pvts[chanpos]->owner->_state == AST_STATE_RINGING) {
++                                                                                  ast_indicate(transferee, AST_CONTROL_RINGING);
++                                                                              }
++ 
++                                                                              pri->pvts[chanpos]->owner->_softhangup &= ~AST_SOFTHANGUP_DEV;
++  
++                                                                              ast_mutex_unlock(&transferee->lock);
++                                                                              if (ast_channel_masquerade(pri->pvts[chanpos]->owner, transferee)) {
++                                                                                  ast_log(LOG_WARNING, "unable to masquerade\n");
++                                                                              } else { 
++                                                                                  /* beware of zombies!!! */
++                                                                                  ast_set_flag(transferee, AST_FLAG_ZOMBIE);
++                                                                                  pri->pvts[chanpos]->owner = NULL;
++                                                                                  pri->pvts[chanpos]->tei = -1;
++                                                                                  transfer_ok = 1;
++                                                                              }
++                                                                          }
++                                                                      }       
++                                                                  } else if (pri->pvts[chanpos]->pritransfer == 0) {
++                                                                      ast_log(LOG_NOTICE, "killing channel %s \n", onhold->uniqueid);
++                                                                      ast_retrieve_call_to_death(onhold->uniqueid);
++                                                                      transfer_ok = 1;
++                                                                  } else if (pri->pvts[chanpos]->pritransfer == 1) {
++                                                                      /* we use ECT transfers, so just ignore this */
++                                                                      transfer_ok = 0;
++                                                                  }
++                                                      
++                                                                  if (transfer_ok) {
++                                                                      onhold->alreadyhungup = 1;      
++                                                                      pri_hangup(pri->pri, onhold->call, e->hangup.cause);
++                                                                      onhold = NULL;
++                                                                  }
++                                                                  ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                                                  break;
++                                                              }
++                                                          }
++                                                      }
+                                               } else {
+                                                       pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
+                                                       pri->pvts[chanpos]->call = NULL;
++                                                      pri->pvts[chanpos]->tei = -1;
+                                               }
+                                               if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
+-                                                      if (option_verbose > 2)
+-                                                              ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d span %d since channel reported in use\n", 
+-                                                                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+-                                                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
+-                                                      pri->pvts[chanpos]->resetting = 1;
++                                                      if ((pri->nodetype != BRI_CPE_PTMP) && (pri->nodetype != BRI_NETWORK_PTMP)) {
++                                                          if (option_verbose > 2)
++                                                              ast_verbose(VERBOSE_PREFIX_3 "Forcing restart of channel %d/%d span %d since channel reported in use\n", 
++                                                                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                                          pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
++                                                          pri->pvts[chanpos]->resetting = 1;
++                                                      }
++
+                                               }
+ #ifdef SUPPORT_USERUSER
+@@ -8935,9 +9845,28 @@
+                                               ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+                                       } else {
+-                                              ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                              if (pri->nodetype != BRI_NETWORK_PTMP) {
++                                                  ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                              } else {
++                                                  // check holded_calls!!!
++                                                  struct zt_holded_call *onhold = NULL;
++ 
++                                                  onhold = pri_get_callonhold(pri, e->hangup.cref, e->hangup.tei);
++ 
++                                                  if (onhold) {
++                                                          pri_hangup(pri->pri, e->hangup.call, e->hangup.cause);
++                                                          ast_retrieve_call_to_death(onhold->uniqueid);
++                                                          pri_destroy_callonhold(pri, onhold);
++                                                          onhold = NULL;
++                                                  } else {
++                                                      ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
++                                                  }
++                                              }
+                                       }
+                               } 
++                              if ((chanpos > -1) && (pri->pvts[chanpos]->owner) && (pri->pvts[chanpos]->priindication_oob == 2) && (e->hangup.inband_progress) && (pri->pvts[chanpos]->outgoing)) {
++                                  ast_channel_setwhentohangup(pri->pvts[chanpos]->owner, 5);
++                              }
+                               break;
+                       case PRI_EVENT_HANGUP_ACK:
+                               chanpos = pri_find_principle(pri, e->hangup.channel);
+@@ -8951,6 +9880,7 @@
+                                       if (chanpos > -1) {
+                                               ast_mutex_lock(&pri->pvts[chanpos]->lock);
+                                               pri->pvts[chanpos]->call = NULL;
++                                              pri->pvts[chanpos]->tei = -1;
+                                               pri->pvts[chanpos]->resetting = 0;
+                                               if (pri->pvts[chanpos]->owner) {
+                                                       if (option_verbose > 2) 
+@@ -8964,7 +9894,9 @@
+ #endif
+                                               ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                          }
+                                       }
++                                  }
+                               }
+                               break;
+                       case PRI_EVENT_CONFIG_ERR:
+@@ -9031,15 +9963,25 @@
+                                       ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", 
+                                               PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
+                               } else {
+-                                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
+-                                      pri->pvts[chanpos]->setup_ack = 1;
+-                                      /* Send any queued digits */
+-                                      for (x=0;x<strlen(pri->pvts[chanpos]->dialdest);x++) {
++                                      chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
++                                      if (chanpos < 0) {
++                                              ast_log(LOG_WARNING, "Received SETUP_ACK on channel %d/%d not in use on span %d\n", 
++                                                      PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
++                                              chanpos = -1;
++                                      } else {
++                                          ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                          pri->pvts[chanpos]->setup_ack = 1;
++                                          if (pri->pvts[chanpos]->owner) {
++                                          //    ast_log(LOG_NOTICE, "SETUP_ACK for '%s'\n", pri->pvts[chanpos]->owner->name);
++                                          }
++                                          /* Send any queued digits */
++                                          for (x=0;x<strlen(pri->pvts[chanpos]->dialdest);x++) {
+                                               ast_log(LOG_DEBUG, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
+                                               pri_information(pri->pri, pri->pvts[chanpos]->call, 
+                                                       pri->pvts[chanpos]->dialdest[x]);
++                                          }
++                                          ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+                                       }
+-                                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+                               }
+                               break;
+                       case PRI_EVENT_NOTIFY:
+@@ -9063,6 +10005,78 @@
+                                       ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+                               }
+                               break;
++                      case PRI_EVENT_FACILITY:
++                                  if (e->facility.operation == 0x06) {
++                                      struct ast_channel *chan = NULL;
++                                      struct zt_holded_call *onhold = NULL;
++                                      if (option_verbose > 2) {
++                                          ast_verbose(VERBOSE_PREFIX_3 "ECT requested by TEI %d for cref %d\n", e->facility.tei, e->facility.cref);
++                                      }
++                                      /* search for cref/tei in held calls */
++                                      onhold = pri_get_callonhold(pri, e->facility.cref, e->facility.tei);
++                                      if (onhold) {
++                                          chan = ast_get_holded_call(onhold->uniqueid);
++                                          onhold->alreadyhungup = 1;
++                                          onhold = NULL;
++                                          if (!chan) {
++                                              /* hang up */
++                                              pri_hangup(pri->pri, e->facility.call, 16);
++                                              break;
++                                          }
++                                      } else {
++                                          /* unknown cref/tei */
++                                          ast_log(LOG_WARNING, "did not find call on hold for cref %d tei %d\n", e->facility.tei, e->facility.cref);
++                                          /* hang up */
++                                          pri_hangup(pri->pri, e->facility.call, 16);
++                                          break;
++                                      }
++ 
++                                      /* find an active call for the same tei */
++                                      chanpos = pri_find_tei(pri, e->facility.call, e->facility.tei);
++                                      if (chanpos < 0) {
++                                          /* did not find active call, hangup call on hold */
++                                          if (chan) {
++                                              ast_hangup(chan);
++                                              chan = NULL;
++                                          }
++                                      } else {
++                                          ast_mutex_lock(&pri->pvts[chanpos]->lock);
++                                          /* transfer */
++                                          if (pri->pvts[chanpos]->owner) {
++                                              if (option_verbose > 3) {
++                                                  ast_verbose(VERBOSE_PREFIX_3 "ECT: found %s on channel %d for tei %d\n", pri->pvts[chanpos]->owner->name ,chanpos, e->facility.tei);
++                                              }
++                                              /* pass callprogress if the channel is not up yet */
++                                              if (pri->pvts[chanpos]->owner->_state == AST_STATE_RINGING) {
++                                                  ast_indicate(chan, AST_CONTROL_RINGING);
++                                              }
++                                              /* unlock the channel we removed from hold */
++                                              ast_mutex_unlock(&chan->lock);
++                                              if (ast_channel_masquerade(pri->pvts[chanpos]->owner, chan)) {
++                                                  ast_log(LOG_WARNING, "unable to masquerade\n");
++                                              } else {
++                                                  /* beware of zombies !!! */
++                                                  ast_set_flag(chan, AST_FLAG_ZOMBIE);
++                                              //    chan->zombie = 1;
++                                              }
++                                          }
++                                          ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++                                      }
++                                      /* disconnect */
++                                      pri_hangup(pri->pri, e->facility.call, 16);
++                                  } else if (e->facility.operation == 0x0D) {
++                                      ast_log(LOG_NOTICE, "call deflection to %s requested.\n", e->facility.forwardnum);
++                                      /* mmmmmkay */
++                                      
++                                      /* lock the channel */
++                                      
++                                      /* async goto */
++                                      
++                                      /* disconnect isdn layer */
++                                  } else {
++                                      ast_log(LOG_WARNING, "Unknown facility operation %#x requested.\n", e->facility.operation);
++                                  }
++                              break;
+                       default:
+                               ast_log(LOG_DEBUG, "Event: %d\n", e->e);
+                       }
+@@ -9124,7 +10138,7 @@
+                       pri->fds[i] = -1;
+                       return -1;
+               }
+-              pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
++              pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype, pri->span);
+               /* Force overlap dial if we're doing GR-303! */
+               if (pri->switchtype == PRI_SWITCH_GR303_TMC)
+                       pri->overlapdial = 1;
+@@ -9193,39 +10207,77 @@
+ static int handle_pri_set_debug_file(int fd, int argc, char **argv)
+ {
+-      int myfd;
++      int myfd, x, d;
++      int span;
++ 
++      if (argc < 6) 
++              return RESULT_SHOWUSAGE;
+       if (!strncasecmp(argv[1], "set", 3)) {
+-              if (argc < 5) 
++              if (argc < 7) 
+                       return RESULT_SHOWUSAGE;
+-              if (ast_strlen_zero(argv[4]))
++              if (!argv[4] || ast_strlen_zero(argv[4]))
+                       return RESULT_SHOWUSAGE;
++              if (!argv[5])
++                      return RESULT_SHOWUSAGE;
++ 
++              if (!argv[6] || ast_strlen_zero(argv[6]))
++                      return RESULT_SHOWUSAGE;
++ 
++              span = atoi(argv[6]);
++              if ((span < 1) && (span > NUM_SPANS)) {
++                      return RESULT_SUCCESS;
++              }
++              
++
+               myfd = open(argv[4], O_CREAT|O_WRONLY);
+               if (myfd < 0) {
+-                      ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
+-                      return RESULT_SUCCESS;
++                  ast_cli(fd, "Unable to open '%s' for writing\n", argv[4]);
++                  return RESULT_SUCCESS;
+               }
+-
+-              ast_mutex_lock(&pridebugfdlock);
+-
+-              if (pridebugfd >= 0)
+-                      close(pridebugfd);
+-
+-              pridebugfd = myfd;
+-              ast_copy_string(pridebugfilename,argv[4],sizeof(pridebugfilename));
+-              
+-              ast_mutex_unlock(&pridebugfdlock);
+-
+-              ast_cli(fd, "PRI debug output will be sent to '%s'\n", argv[4]);
++              for (x=0; x < NUM_SPANS; x++) {
++                  ast_mutex_lock(&pris[x].lock);
++                  
++                  if (pris[x].span == span) {
++                      if (pris[x].debugfd >= 0)
++                          close(pris[x].debugfd);
++                      pris[x].debugfd = myfd;
++                      for (d=0; d < NUM_DCHANS; d++) {
++                          if (pris[x].dchans[d])
++                              pri_set_debug_fd(pris[x].dchans[d], myfd);
++                      }
++                  }
++                  ast_mutex_unlock(&pris[x].lock);
++              }
++  
++              ast_cli(fd, "PRI debug output for span %d will be sent to '%s'\n", span, argv[4]);
+       } else {
++              if (!argv[5] || ast_strlen_zero(argv[5]))
++                      return RESULT_SHOWUSAGE;
+               /* Assume it is unset */
+-              ast_mutex_lock(&pridebugfdlock);
+-              close(pridebugfd);
+-              pridebugfd = -1;
+-              ast_cli(fd, "PRI debug output to file disabled\n");
+-              ast_mutex_unlock(&pridebugfdlock);
++              span = atoi(argv[5]);
++              if ((span < 1) && (span > NUM_SPANS)) {
++                      return RESULT_SUCCESS;
++              }
++ 
++              for (x=0; x < NUM_SPANS; x++) {
++                  ast_mutex_lock(&pris[x].lock);
++                  
++                  if (pris[x].span == span) {
++                      if (pris[x].debugfd >= 0)
++                          close(pris[x].debugfd);
++                      pris[x].debugfd = -1;
++                      for (d=0; d < NUM_DCHANS; d++) {
++                          if (pris[x].dchans[d])
++                              pri_set_debug_fd(pris[x].dchans[d], -1);
++                      }
++                  }
++                  ast_mutex_unlock(&pris[x].lock);
++              }
++ 
++              ast_cli(fd, "PRI debug output to file for span %d disabled\n", span);
+       }
+       return RESULT_SUCCESS;
+@@ -9257,6 +10309,7 @@
++
+ static int handle_pri_no_debug(int fd, int argc, char *argv[])
+ {
+       int span;
+@@ -9363,36 +10416,6 @@
+       return RESULT_SUCCESS;
+ }
+-static int handle_pri_show_debug(int fd, int argc, char *argv[])
+-{
+-      int x;
+-      int span;
+-      int count=0;
+-      int debug=0;
+-
+-      for(span=0;span<NUM_SPANS;span++) {
+-              if (pris[span].pri) {
+-                      for(x=0;x<NUM_DCHANS;x++) {
+-                              debug=0;
+-                              if (pris[span].dchans[x]) {
+-                                      debug = pri_get_debug(pris[span].dchans[x]);
+-                                      ast_cli(fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" );
+-                                      count++;
+-                              }
+-                      }
+-              }
+-
+-      }
+-      ast_mutex_lock(&pridebugfdlock);
+-      if (pridebugfd >= 0) 
+-              ast_cli(fd, "Logging PRI debug to file %s\n", pridebugfilename);
+-      ast_mutex_unlock(&pridebugfdlock);
+-          
+-      if (!count) 
+-              ast_cli(fd, "No debug set or no PRI running\n");
+-      return RESULT_SUCCESS;
+-}
+-
+ static char pri_debug_help[] = 
+       "Usage: pri debug span <span>\n"
+       "       Enables debugging on a given PRI span\n";
+@@ -9409,6 +10432,18 @@
+       "Usage: pri show span <span>\n"
+       "       Displays PRI Information\n";
++static char bri_debug_help[] = 
++      "Usage: bri debug span <span>\n"
++      "       Enables debugging on a given BRI span\n";
++      
++static char bri_no_debug_help[] = 
++      "Usage: bri no debug span <span>\n"
++      "       Disables debugging on a given BRI span\n";
++
++static char bri_really_debug_help[] = 
++      "Usage: bri intensive debug span <span>\n"
++      "       Enables debugging down to the Q.921 level\n";
++
+ static struct ast_cli_entry zap_pri_cli[] = {
+       { { "pri", "debug", "span", NULL }, handle_pri_debug,
+         "Enables PRI debugging on a span", pri_debug_help, complete_span_4 },
+@@ -9416,19 +10451,77 @@
+         "Disables PRI debugging on a span", pri_no_debug_help, complete_span_5 },
+       { { "pri", "intense", "debug", "span", NULL }, handle_pri_really_debug,
+         "Enables REALLY INTENSE PRI debugging", pri_really_debug_help, complete_span_5 },
++      { { "bri", "debug", "span", NULL }, handle_pri_debug,
++        "Enables BRI debugging on a span", bri_debug_help, complete_span_4 },
++      { { "bri", "no", "debug", "span", NULL }, handle_pri_no_debug,
++        "Disables BRI debugging on a span", bri_no_debug_help, complete_span_5 },
++      { { "bri", "intense", "debug", "span", NULL }, handle_pri_really_debug,
++        "Enables REALLY INTENSE BRI debugging", bri_really_debug_help, complete_span_5 },
+       { { "pri", "show", "span", NULL }, handle_pri_show_span,
+         "Displays PRI Information", pri_show_span_help, complete_span_4 },
+-      { { "pri", "show", "debug", NULL }, handle_pri_show_debug,
+-        "Displays current PRI debug settings" },
+       { { "pri", "set", "debug", "file", NULL }, handle_pri_set_debug_file,
+         "Sends PRI debug output to the specified file" },
+-      { { "pri", "unset", "debug", "file", NULL }, handle_pri_set_debug_file,
++      { { "pri", "unset", "debug", "file", "span", NULL }, handle_pri_set_debug_file,
+         "Ends PRI debug output to file" },
+ };
++static int app_zapCD(struct ast_channel *chan, void *data)
++{
++    struct zt_pvt *p = chan->tech_pvt;
++
++    if(!data) {
++        ast_log(LOG_WARNING, "zapCD wants a number to deflect to\n");
++      return -1;
++    }
++    return pri_deflect(p->pri->pri, p->call, data);
++}
++
++static char *zapCD_tdesc = "Call Deflection";
++static char *zapCD_app = "zapCD";
++static char *zapCD_synopsis = "Call Deflection";
+ #endif /* ZAPATA_PRI */
++static int app_zapEC(struct ast_channel *chan, void *data)
++{
++ int res=-1;
++ struct zt_pvt *p = NULL;
++
++ if (!data) {
++      ast_log(LOG_WARNING, "zapEC requires one argument (on | off)\n");
++ }
++ if (chan && !strcasecmp("ZAP",chan->type)) {
++      p = chan->tech_pvt;
++      if (!p) return res;
++      if (!strcasecmp("on",(char *)data)) {
++          zt_enable_ec(p);
++          res = 0;
++          if (option_verbose > 3) {
++              ast_verbose(VERBOSE_PREFIX_3 "Enabled echo cancelation on channel %s.\n", chan->name);
++          }
++      } else if (!strcasecmp("off",(char *)data)) {
++          zt_disable_ec(p);
++          res = 0;
++          if (option_verbose > 3) {
++              ast_verbose(VERBOSE_PREFIX_3 "Disabled echo cancelation on channel %s.\n", chan->name);
++          }
++      } else {
++          ast_log(LOG_WARNING, "Unknown argument %s to zapEC\n", (char *)data);
++      }
++ } else {
++     ast_log(LOG_WARNING, "zapNoEC only works on ZAP channels, check your extensions.conf!\n");
++     res = 0;
++ }
++
++ return res;
++}
++
++static char *zapEC_tdesc = "Enable/disable Echo cancelation";
++static char *zapEC_app = "zapEC";
++static char *zapEC_synopsis = "Enable/Disable Echo Cancelation on a Zap channel";
++
++
++
+ #ifdef ZAPATA_R2
+ static int handle_r2_no_debug(int fd, int argc, char *argv[])
+ {
+@@ -10051,6 +11144,7 @@
+       ast_manager_unregister( "ZapDNDoff" );
+       ast_manager_unregister( "ZapDNDon" );
+       ast_manager_unregister("ZapShowChannels");
++      ast_unregister_application(zapEC_app);
+       ast_channel_unregister(&zap_tech);
+       if (!ast_mutex_lock(&iflock)) {
+               /* Hangup all interfaces if they have an owner */
+@@ -10409,8 +11503,8 @@
+                       }
+               } else if (!strcasecmp(v->name, "echotraining")) {
+                       if (sscanf(v->value, "%d", &y) == 1) {
+-                              if ((y < 10) || (y > 4000)) {
+-                                      ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 2000 ms at line %d\n", v->lineno);                                   
++                              if ((y < 10) || (y > 1000)) {
++                                      ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 1000 ms at line %d\n", v->lineno);                                   
+                               } else {
+                                       echotraining = y;
+                               }
+@@ -10596,6 +11690,22 @@
+                                       cur_signalling = SIG_GR303FXSKS;
+                                       cur_radio = 0;
+                                       pritype = PRI_CPE;
++                      } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
++                              cur_radio = 0;
++                              cur_signalling = SIG_PRI;
++                              pritype = BRI_NETWORK_PTMP;
++                      } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
++                              cur_signalling = SIG_PRI;
++                              cur_radio = 0;
++                              pritype = BRI_CPE_PTMP;
++                      } else if (!strcasecmp(v->value, "bri_net")) {
++                              cur_radio = 0;
++                              cur_signalling = SIG_PRI;
++                              pritype = BRI_NETWORK;
++                      } else if (!strcasecmp(v->value, "bri_cpe")) {
++                              cur_signalling = SIG_PRI;
++                              cur_radio = 0;
++                              pritype = BRI_CPE;
+ #endif
+ #ifdef ZAPATA_R2
+                               } else if (!strcasecmp(v->value, "r2")) {
+@@ -10684,8 +11794,20 @@
+                                       priindication_oob = 1;
+                               else if (!strcasecmp(v->value, "inband"))
+                                       priindication_oob = 0;
++                              else if (!strcasecmp(v->value, "passthrough"))
++                                      priindication_oob = 2;
+                               else
+-                                      ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d\n",
++                                      ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' , 'outofband' or 'passthrough' at line %d\n",
++                                              v->value, v->lineno);
++                      } else if (!strcasecmp(v->name, "pritransfer")) {
++                              if (!strcasecmp(v->value, "no"))
++                                      pritransfer = 0;
++                              else if (!strcasecmp(v->value, "ect"))
++                                      pritransfer = 1;
++                              else if (!strcasecmp(v->value, "hangup"))
++                                      pritransfer = 2;
++                              else
++                                      ast_log(LOG_WARNING, "'%s' is not a valid pri transfer value, should be 'no' , 'ect' or 'hangup' at line %d\n",
+                                               v->value, v->lineno);
+                       } else if (!strcasecmp(v->name, "priexclusive")) {
+                               cur_priexclusive = ast_true(v->value);
+@@ -10699,6 +11821,10 @@
+                               ast_copy_string(privateprefix, v->value, sizeof(privateprefix));
+                       } else if (!strcasecmp(v->name, "unknownprefix")) {
+                               ast_copy_string(unknownprefix, v->value, sizeof(unknownprefix));
++                      } else if (!strcasecmp(v->name, "nocid")) {
++                              ast_copy_string(nocid, v->value, sizeof(nocid) - 1);
++                      } else if (!strcasecmp(v->name, "withheldcid")) {
++                              ast_copy_string(withheldcid, v->value, sizeof(withheldcid) - 1);
+                       } else if (!strcasecmp(v->name, "resetinterval")) {
+                               if (!strcasecmp(v->value, "never"))
+                                       resetinterval = -1;
+@@ -10713,6 +11839,8 @@
+                               ast_copy_string(idleext, v->value, sizeof(idleext));
+                       } else if (!strcasecmp(v->name, "idledial")) {
+                               ast_copy_string(idledial, v->value, sizeof(idledial));
++                      } else if (!strcasecmp(v->name, "pritrustusercid")) {
++                              usercid = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "overlapdial")) {
+                               overlapdial = ast_true(v->value);
+                       } else if (!strcasecmp(v->name, "pritimer")) {
+@@ -10898,6 +12026,7 @@
+ #ifdef ZAPATA_PRI
+       if (!reload) {
+               for (x=0;x<NUM_SPANS;x++) {
++                      pris[x].debugfd = -1;
+                       if (pris[x].pvts[0]) {
+                               if (start_pri(pris + x)) {
+                                       ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
+@@ -10955,11 +12084,46 @@
+       ast_manager_register( "ZapDNDon", 0, action_zapdndon, "Toggle Zap channel Do Not Disturb status ON" );
+       ast_manager_register( "ZapDNDoff", 0, action_zapdndoff, "Toggle Zap channel Do Not Disturb status OFF" );
+       ast_manager_register("ZapShowChannels", 0, action_zapshowchannels, "Show status zapata channels");
+-
++      ast_register_application(zapEC_app, app_zapEC, zapEC_synopsis, zapEC_tdesc);
++#ifdef ZAPATA_PRI
++        ast_register_application(zapCD_app, app_zapCD, zapCD_synopsis, zapCD_tdesc);
++#endif
+       return res;
+ }
++#ifdef ZAPATA_PRI
++static int zt_tdd_sendtext(struct ast_channel *c, const char *text);
++
++static int zt_pri_sendtext(struct ast_channel *c, const char *text) {
++    struct zt_pvt *p = c->tech_pvt;
++    if (!p) return -1;
++    if (!p->pri) return -1;
++          if (strlen(text)) {
++              if (p->pri) {           
++                  if (!pri_grab(p, p->pri)) {
++              //      ast_log(LOG_NOTICE, "Sending Display IE  '%s'\n", text);
++                      pri_information_display(p->pri->pri,p->call,(char *)text);
++                      pri_rel(p->pri);
++                  } else ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
++              }
++          }
++    return 0;
++}
++
++static int zt_sendtext(struct ast_channel *c, const char *text) {
++    struct zt_pvt *p = c->tech_pvt;
++    if (!p) return -1;
++    if (p->sig == SIG_PRI) {
++      return zt_pri_sendtext(c, text);
++    } else {
++      return zt_tdd_sendtext(c, text);
++    }
++}
++
++static int zt_tdd_sendtext(struct ast_channel *c, const char *text)
++#else
+ static int zt_sendtext(struct ast_channel *c, const char *text)
++#endif
+ {
+ #define       END_SILENCE_LEN 400
+ #define       HEADER_MS 50
+@@ -10978,6 +12142,7 @@
+       float scont = 0.0;
+       int index;
++
+       index = zt_get_index(c, p, 0);
+       if (index < 0) {
+               ast_log(LOG_WARNING, "Huh?  I don't exist?\n");
+diff -urN asterisk-1.2.4.orig/codecs/codec_ilbc.c asterisk-1.2.4/codecs/codec_ilbc.c
+--- asterisk-1.2.4.orig/codecs/codec_ilbc.c    2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/codecs/codec_ilbc.c 2006-01-31 09:41:43.000000000 +0100
+@@ -49,7 +49,7 @@
+ #include "slin_ilbc_ex.h"
+ #include "ilbc_slin_ex.h"
+-#define USE_ILBC_ENHANCER     0
++#define USE_ILBC_ENHANCER     1
+ #define ILBC_MS                       30
+ /* #define ILBC_MS                    20 */
+diff -urN asterisk-1.2.4.orig/configs/capi.conf.sample asterisk-1.2.4/configs/capi.conf.sample
+--- asterisk-1.2.4.orig/configs/capi.conf.sample       1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/configs/capi.conf.sample    2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,44 @@
++;
++; CAPI config
++;
++;
++[general]
++nationalprefix=0
++internationalprefix=00
++rxgain=0.8
++txgain=0.8
++
++[interfaces]
++
++; mode: ptmp (point-to-multipoint) or ptp (point-to-point)
++isdnmode=ptmp
++; allow incoming calls to this list of MSNs, * == any
++incomingmsn=*
++; capi controller number
++controller=1
++; dialout group
++group=1
++; enable/disable software dtmf detection, recommended for AVM cards
++softdtmf=1
++; accountcode to use in CDRs
++accountcode=
++; context for incoming calls
++context=capi-in
++; _VERY_PRIMITIVE_ echo suppression
++;echosquelch=1
++; EICON DIVA SERVER echo cancelation
++;echocancel=yes
++;echotail=64
++; call group
++;callgroup=1
++; deflect incoming calls to 12345678 if all B channels are busy
++;deflect=12345678
++; number of concurrent calls on this controller (2 makes sense for single BRI)
++devices => 2
++
++
++;PointToPoint (55512-0)
++;isdnmode=ptp
++;msn=55512
++;controller=2
++;devices => 30
+diff -urN asterisk-1.2.4.orig/configs/modules.conf.sample asterisk-1.2.4/configs/modules.conf.sample
+--- asterisk-1.2.4.orig/configs/modules.conf.sample    2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/configs/modules.conf.sample 2006-01-31 09:41:43.000000000 +0100
+@@ -51,3 +51,4 @@
+ ; exported to modules loaded after them.
+ ;
+ [global]
++chan_capi.so=yes
+diff -urN asterisk-1.2.4.orig/configs/watchdog.conf.sample asterisk-1.2.4/configs/watchdog.conf.sample
+--- asterisk-1.2.4.orig/configs/watchdog.conf.sample   1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/configs/watchdog.conf.sample        2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,22 @@
++;
++; Configuration file for res_watchdog
++;
++; type     = isdnguard | watchdog
++; device   = /dev/...
++; interval = interval to trigger the watchdog in ms
++
++;[ISDNguard-direct]
++;type = isdnguard
++;device = /dev/ttyS0
++;interval = 200
++
++;[ISDNguard-with-daemon]
++;type = isdnguard
++;device = /var/run/guard.ctl
++;interval = 200
++
++;[kernel_watchdog]
++;type = watchdog
++;device = /dev/watchdog
++;interval = 100
++
+diff -urN asterisk-1.2.4.orig/configs/zapata.conf.sample asterisk-1.2.4/configs/zapata.conf.sample
+--- asterisk-1.2.4.orig/configs/zapata.conf.sample     2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/configs/zapata.conf.sample  2006-01-31 09:41:43.000000000 +0100
+@@ -121,9 +121,20 @@
+ ; 
+ ; outofband:      Signal Busy/Congestion out of band with RELEASE/DISCONNECT
+ ; inband:         Signal Busy/Congestion using in-band tones
++; passthrough:          Listen to the telco
+ ;
+ ; priindication = outofband
+ ;
++; PRI/BRI transfers (HOLD -> SETUP -> ECT/Hangup)
++;
++; Configure how transfers are initiated. ECT should be preferred
++;
++; no:         no transfers allowed (results in hangup)
++; ect:        use ECT (facility)
++: hangup:     transfer on hangup (if your phones dont support ECT)
++;
++; pritransfer = ect
++;
+ ; If you need to override the existing channels selection routine and force all
+ ; PRI channels to be marked as exclusively selected, set this to yes.
+ ; priexclusive = yes
+diff -urN asterisk-1.2.4.orig/db.c asterisk-1.2.4/db.c
+--- asterisk-1.2.4.orig/db.c   2006-01-09 19:09:53.000000000 +0100
++++ asterisk-1.2.4/db.c        2006-01-31 09:41:43.000000000 +0100
+@@ -516,11 +516,18 @@
+ struct ast_cli_entry cli_database_deltree =
+ { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
++static char mandescr_dbput[] = 
++"Description: Put a value into astdb\n"
++"Variables: \n"
++"     Family: ...\n"
++"     Key: ...\n"
++"     Value: ...\n";
++
+ static int manager_dbput(struct mansession *s, struct message *m)
+ {
+       char *family = astman_get_header(m, "Family");
+       char *key = astman_get_header(m, "Key");
+-      char *val = astman_get_header(m, "Val");
++      char *val = astman_get_header(m, "Value");
+       int res;
+       if (!strlen(family)) {
+@@ -545,6 +552,12 @@
+       return 0;
+ }
++static char mandescr_dbget[] = 
++"Description: Get a value from astdb\n"
++"Variables: \n"
++"     Family: ...\n"
++"     Key: ...\n";
++
+ static int manager_dbget(struct mansession *s, struct message *m)
+ {
+       char *id = astman_get_header(m,"ActionID");
+@@ -574,7 +587,7 @@
+               ast_cli(s->fd, "Event: DBGetResponse\r\n"
+                               "Family: %s\r\n"
+                               "Key: %s\r\n"
+-                              "Val: %s\r\n"
++                              "Value: %s\r\n"
+                               "%s"
+                               "\r\n",
+                               family, key, tmp, idText);
+@@ -582,6 +595,39 @@
+       return 0;
+ }
++static char mandescr_dbdel[] = 
++"Description: remove value from astdb\n"
++"Variables: \n"
++"     Family: ...\n"
++"     Key: ...\n";
++
++static int manager_dbdel(struct mansession *s, struct message *m)
++{
++        char *family = astman_get_header(m, "Family");
++        char *key = astman_get_header(m, "Key");
++      char *id = astman_get_header(m,"ActionID");
++
++      if (!strlen(family)) {
++              astman_send_error(s, m, "No family specified");
++              return 0;
++      }
++      if (!strlen(key)) {
++              astman_send_error(s, m, "No key specified");
++              return 0;
++      }
++
++      if (ast_db_del(family, key)) {
++          ast_cli(s->fd, "Response: Failed\r\n");
++      } else {
++          ast_cli(s->fd, "Response: Success\r\n");
++      }
++      if (id && !ast_strlen_zero(id))
++              ast_cli(s->fd, "ActionID: %s\r\n",id);
++      ast_cli(s->fd, "\r\n");
++
++      return 0;
++}
++
+ int astdb_init(void)
+ {
+       dbinit();
+@@ -591,7 +637,8 @@
+       ast_cli_register(&cli_database_put);
+       ast_cli_register(&cli_database_del);
+       ast_cli_register(&cli_database_deltree);
+-      ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
+-      ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
++      ast_manager_register("DBget", EVENT_FLAG_SYSTEM, manager_dbget, mandescr_dbget);
++      ast_manager_register("DBput", EVENT_FLAG_SYSTEM, manager_dbput, mandescr_dbput);
++      ast_manager_register("DBdel", EVENT_FLAG_SYSTEM, manager_dbdel, mandescr_dbdel);
+       return 0;
+ }
+diff -urN asterisk-1.2.4.orig/devicestate.c asterisk-1.2.4/devicestate.c
+--- asterisk-1.2.4.orig/devicestate.c  2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/devicestate.c       2006-01-31 09:41:43.000000000 +0100
+@@ -62,6 +62,8 @@
+ struct state_change {
+       AST_LIST_ENTRY(state_change) list;
++      char cid_num[AST_MAX_EXTENSION];
++      char cid_name[AST_MAX_EXTENSION];
+       char device[1];
+ };
+@@ -177,7 +179,7 @@
+ }
+ /*--- do_state_change: Notify callback watchers of change, and notify PBX core for hint updates */
+-static void do_state_change(const char *device)
++static void do_state_change(const char *device, char *cid_num, char *cid_name)
+ {
+       int state;
+       struct devstate_cb *devcb;
+@@ -188,13 +190,13 @@
+       AST_LIST_LOCK(&devstate_cbs);
+       AST_LIST_TRAVERSE(&devstate_cbs, devcb, list)
+-              devcb->callback(device, state, devcb->data);
++              devcb->callback(device, state, devcb->data, cid_num, cid_name);
+       AST_LIST_UNLOCK(&devstate_cbs);
+-      ast_hint_state_changed(device);
++      ast_hint_state_changed(device, cid_num, cid_name);
+ }
+-static int __ast_device_state_changed_literal(char *buf)
++static int __ast_device_state_changed_literal(char *buf, char *cid_num, char *cid_name)
+ {
+       char *device, *tmp;
+       struct state_change *change = NULL;
+@@ -209,10 +211,16 @@
+       if (!change) {
+               /* we could not allocate a change struct, or */
+               /* there is no background thread, so process the change now */
+-              do_state_change(device);
++              do_state_change(device, cid_num, cid_name);
+       } else {
+               /* queue the change */
+               strcpy(change->device, device);
++              if (cid_num && (!ast_strlen_zero(cid_num))) {
++                  strncpy(change->cid_num, cid_num, sizeof(change->cid_num) - 1);
++              }
++              if (cid_name && (!ast_strlen_zero(cid_name))) {
++                  strncpy(change->cid_name, cid_name, sizeof(change->cid_name) - 1);
++              }
+               AST_LIST_LOCK(&state_changes);
+               AST_LIST_INSERT_TAIL(&state_changes, change, list);
+               if (AST_LIST_FIRST(&state_changes) == change)
+@@ -224,23 +232,49 @@
+       return 1;
+ }
+-int ast_device_state_changed_literal(const char *dev)
++int ast_device_state_changed_literal(const char *dev, const char *cid_num, const char *cid_name)
+ {
+       char *buf;
++      char *buf2 = NULL;
++      char *buf3 = NULL;
+       buf = ast_strdupa(dev);
+-      return __ast_device_state_changed_literal(buf);
++      if (cid_num)
++          buf2 = ast_strdupa(cid_num);
++      if (cid_name)
++          buf3 = ast_strdupa(cid_name);
++      return __ast_device_state_changed_literal(buf, buf2, buf3);
+ }
+ /*--- ast_device_state_changed: Accept change notification, add it to change queue */
+ int ast_device_state_changed(const char *fmt, ...) 
+ {
+       char buf[AST_MAX_EXTENSION];
++      char cid_num[AST_MAX_EXTENSION];
++      char cid_name[AST_MAX_EXTENSION];
++      char *s = NULL;
+       va_list ap;
+       va_start(ap, fmt);
+-      vsnprintf(buf, sizeof(buf), fmt, ap);
++      if (*fmt == 's') {
++          s = va_arg(ap, char *);
++          snprintf(buf, sizeof(buf), s);
++          *fmt++;
++          if (*fmt == 's') {
++              s = va_arg(ap, char *);
++              if (s) {
++                  snprintf(cid_num, sizeof(cid_num), s);
++              }
++              *fmt++;
++              if (*fmt == 's') {
++                  s = va_arg(ap, char *);
++                  if (s) {
++                      snprintf(cid_name, sizeof(cid_name), s);
++                  }
++              }
++          }
++      }
+       va_end(ap);
+-      return __ast_device_state_changed_literal(buf);
++      return __ast_device_state_changed_literal(buf, cid_num, cid_name);
+ }
+ /*--- do_devstate_changes: Go through the dev state change queue and update changes in the dev state thread */
+@@ -255,7 +289,7 @@
+               if (cur) {
+                       /* we got an entry, so unlock the list while we process it */
+                       AST_LIST_UNLOCK(&state_changes);
+-                      do_state_change(cur->device);
++                      do_state_change(cur->device, cur->cid_num, cur->cid_name);
+                       free(cur);
+                       AST_LIST_LOCK(&state_changes);
+               } else {
+diff -urN asterisk-1.2.4.orig/doc/README.asterisk.conf asterisk-1.2.4/doc/README.asterisk.conf
+--- asterisk-1.2.4.orig/doc/README.asterisk.conf       2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/doc/README.asterisk.conf    2006-01-31 09:41:43.000000000 +0100
+@@ -62,6 +62,7 @@
+ maxcalls = 255                                        ; The maximum number of concurrent calls you want to allow 
+ execincludes = yes | no                       ; Allow #exec entries in configuration files
+ dontwarn = yes | no                           ; Don't over-inform the Asterisk sysadm, he's a guru
++uniquename = asterisk                         ; host name part to be included in the uniqueid
+ [files]
+ ; Changing the following lines may compromise your security
+diff -urN asterisk-1.2.4.orig/editline/cygdef.h asterisk-1.2.4/editline/cygdef.h
+--- asterisk-1.2.4.orig/editline/cygdef.h      1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/editline/cygdef.h   2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,11 @@
++/* cygdef.h. Generated automatically by configure. */ 
++#ifndef _CYGDEF_H_
++#define _CYGDEF_H_ 1
++#include <sys/ioctl.h>
++#define __linux__ 1
++ 
++
++typedef void (*sig_t)(int);
++ 
++
++#endif /* _CYGDEF_H_ */
+diff -urN asterisk-1.2.4.orig/include/asterisk/agi.h asterisk-1.2.4/include/asterisk/agi.h
+--- asterisk-1.2.4.orig/include/asterisk/agi.h 2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/agi.h      2006-01-31 09:41:43.000000000 +0100
+@@ -29,7 +29,8 @@
+ typedef struct agi_state {
+       int fd;         /* FD for general output */
+-      int audio;      /* FD for audio output */
++      int audio_out;  /* FD for audio output */
++      int audio_in;   /* FD for audio output */
+       int ctrl;       /* FD for input control */
+ } AGI;
+diff -urN asterisk-1.2.4.orig/include/asterisk/chan_capi.h asterisk-1.2.4/include/asterisk/chan_capi.h
+--- asterisk-1.2.4.orig/include/asterisk/chan_capi.h   1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/chan_capi.h        2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,276 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and 
++ * distributed under the terms of the GNU Public License.
++ */
++ 
++#ifndef _ASTERISK_CAPI_H
++#define _ASTERISK_CAPI_H
++
++#define AST_CAPI_MAX_CONTROLLERS 16
++#define AST_CAPI_MAX_DEVICES 30
++#define AST_CAPI_MAX_BUF 160
++
++#define AST_CAPI_MAX_B3_BLOCKS 7
++
++/* was : 130 bytes Alaw = 16.25 ms audio not suitable for VoIP */
++/* now : 160 bytes Alaw = 20 ms audio */
++/* you can tune this to your need. higher value == more latency */
++#define AST_CAPI_MAX_B3_BLOCK_SIZE 160
++
++#define AST_CAPI_BCHANS 120
++#define ALL_SERVICES 0x1FFF03FF
++
++/* duration in ms for sending and detecting dtmfs */
++#define AST_CAPI_DTMF_DURATION        0x40
++
++#define AST_CAPI_NATIONAL_PREF                "0"
++#define AST_CAPI_INTERNAT_PREF                "00"
++
++#ifdef CAPI_ES
++#define ECHO_TX_COUNT 5                       // 5 x 20ms = 100ms
++#define ECHO_EFFECTIVE_TX_COUNT 3     // 2 x 20ms = 40ms == 40-100ms  ... ignore first 40ms
++#define ECHO_TXRX_RATIO 2.3           // if( rx < (txavg/ECHO_TXRX_RATIO) ) rx=0;
++#endif
++
++/*
++ * state combination for a normal incoming call:
++ * DIS -> ALERT -> CON -> BCON -> CON -> DIS
++ *
++ * outgoing call:
++ * DIS -> CONP -> BCONNECTED -> CON -> DIS
++ */
++
++#define CAPI_STATE_ALERTING 1
++#define CAPI_STATE_CONNECTED 2
++#define CAPI_STATE_BCONNECTED 3
++
++#define CAPI_STATE_DISCONNECTING 4
++#define CAPI_STATE_DISCONNECTED 5
++#define CAPI_STATE_REMOTE_HANGUP 6
++
++#define CAPI_STATE_CONNECTPENDING 7
++#define CAPI_STATE_ONHOLD 8
++#define CAPI_STATE_NETWORKHANGUP 9
++#define CAPI_STATE_ANSWERING 10
++#define CAPI_STATE_PUTTINGONHOLD 11
++#define CAPI_STATE_RETRIEVING 12
++
++#define CAPI_STATE_DID 13
++
++#define AST_CAPI_B3_DONT 0
++#define AST_CAPI_B3_ALWAYS 1
++#define AST_CAPI_B3_ON_SUCCESS 2
++
++#ifdef CAPI_GAIN
++struct ast_capi_gains {
++      unsigned char   txgains[256];
++      unsigned char   rxgains[256];
++};
++#endif
++
++#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED   0x00
++#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN  0x01
++#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN  0x02
++#define PRES_ALLOWED_NETWORK_NUMBER                             0x03
++#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED    0x20
++#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN   0x21
++#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN   0x22
++#define PRES_PROHIB_NETWORK_NUMBER                              0x23
++#define PRES_NUMBER_NOT_AVAILABLE                               0x43
++
++
++//! Private data for a capi device
++struct ast_capi_pvt {
++      ast_mutex_t lock;
++      int fd;
++
++      /*! Channel we belong to, possibly NULL */
++      struct ast_channel *owner;              
++      /*! Frame */
++      struct ast_frame fr;                    
++      
++      char offset[AST_FRIENDLY_OFFSET];
++      
++      // capi message number
++      _cword MessageNumber;   
++      int NCCI;
++      int PLCI;
++      /* on which controller we do live */
++      int controller;
++      
++      /* we could live on those */
++      unsigned long controllers;
++
++      int datahandle;
++
++      short buf[AST_CAPI_MAX_BUF];
++      int buflen;
++      /*! Immediate, or wait for an answer */
++      int mode;                                               
++      /*! State of modem in miniature */
++      int state;                                      
++      /*! Digits to strip on outgoing numbers */
++      int stripmsd;                                   
++      /*! ringer timeout */
++      int ringt;                              
++      /*! actual time of last ring */
++      time_t lastring;                        
++      /*! dtmf receive state/data */
++      char dtmfrx;                            
++      
++      char context[AST_MAX_EXTENSION];
++      /*! Multiple Subscriber Number we listen to (, seperated list) */
++      char incomingmsn[AST_MAX_EXTENSION];    
++      /*! Prefix to Build CID */
++      char prefix[AST_MAX_EXTENSION]; 
++      /*! Caller ID if available */
++      char cid[AST_MAX_EXTENSION];    
++      /*! Dialed Number if available */
++      char dnid[AST_MAX_EXTENSION];   
++
++      char accountcode[20];   
++
++      unsigned int callgroup;
++      unsigned int group;
++      
++      /*! default language */
++      char language[MAX_LANGUAGE];    
++      /*! Static response buffer */
++      char response[256];                             
++
++      int calledPartyIsISDN;
++      // this is an outgoing channel
++      int outgoing;
++      // use CLIR
++      int CLIR;
++      // are we doing early B3 connect on this interface?
++      int earlyB3;
++      // should we do early B3 on this interface?
++      int doB3;
++      // store plci here for the call that is onhold
++      int onholdPLCI;
++      // do software dtmf detection
++      int doDTMF;
++      // CAPI echo cancellation
++      int doEC;
++      int ecOption;
++      int ecTail;
++      // isdnmode ptp or ptm 
++      int isdnmode;
++#ifdef CAPI_DEFLECT_ON_CIRCUITBUSY
++      // deflect on circuitbusy
++      char deflect2[AST_MAX_EXTENSION];
++#endif
++      
++    // not all codecs supply frames in nice 320 byte chunks
++    struct ast_smoother *smoother;
++    // ok, we stop to be nice and give them the lowest possible latency 130 samples * 2 = 260 bytes */
++#ifdef CAPI_SYNC
++      int B3in;
++      ast_mutex_t lockB3in;
++#endif
++
++      // do ECHO SURPRESSION
++      int doES;
++#ifdef CAPI_ES
++      short txavg[ECHO_TX_COUNT];
++      float rxmin;
++      float txmin;
++#endif    
++#ifdef CAPI_GAIN
++      struct ast_capi_gains g;
++#endif    
++      float txgain;
++      float rxgain;
++      struct ast_dsp *vad;
++      
++      
++      struct capi_pipe *mypipe;
++      /*! Next channel in list */
++      struct ast_capi_pvt *next;                      
++};
++
++
++struct ast_capi_profile {
++    unsigned short ncontrollers;
++    unsigned short nbchannels;
++    unsigned char globaloptions;
++    unsigned char globaloptions2;
++    unsigned char globaloptions3;
++    unsigned char globaloptions4;
++    unsigned int b1protocols;
++    unsigned int b2protocols;
++    unsigned int b3protocols;
++    unsigned int reserved3[6];
++    unsigned int manufacturer[5];
++};
++
++struct capi_pipe {
++    // lock
++    ast_mutex_t lock;
++
++    // fd for writing to the channel
++    int fd;
++
++    // PLCI and NCCI of the B3 CON
++    int PLCI;
++    int NCCI;
++    // pointer to the interface
++    struct ast_capi_pvt *i;
++    // pointer to the channel
++    struct ast_channel *c;
++    // next pipe
++    struct capi_pipe *next;
++};
++
++struct ast_capi_controller {
++    // which controller is this?
++    int controller;
++    // how many bchans?
++    int nbchannels;
++    // free bchans
++    int nfreebchannels;
++    // DID
++    int isdnmode;
++    // features:
++    int dtmf;
++    int echocancel;
++    int sservices;    // supplementray services
++    // supported sservices:
++    int holdretrieve;
++    int terminalportability;
++    int ECT;
++    int threePTY;
++    int CF;
++    int CD;
++    int MCID;
++    int CCBS;
++    int MWI;
++    int CCNR;
++    int CONF;
++};
++
++
++// ETSI 300 102-1 information element identifiers
++#define CAPI_ETSI_IE_CAUSE 0x08;
++#define CAPI_ETSI_IE_PROGRESS_INDICATOR 0x1e;
++#define CAPI_ETSI_IE_CALLED_PARTY_NUMBER 0x70;
++
++// ETIS 300 102-1 message types
++#define CAPI_ETSI_ALERTING 0x01;
++#define CAPI_ETSI_SETUP_ACKKNOWLEDGE 0x0d;
++#define CAPI_ETSI_DISCONNECT 0x45;
++
++// ETSI 300 102-1 Numbering Plans
++#define CAPI_ETSI_NPLAN_NATIONAL      0x20
++#define CAPI_ETSI_NPLAN_INTERNAT      0x10
++
++#endif
+diff -urN asterisk-1.2.4.orig/include/asterisk/chan_capi_app.h asterisk-1.2.4/include/asterisk/chan_capi_app.h
+--- asterisk-1.2.4.orig/include/asterisk/chan_capi_app.h       1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/chan_capi_app.h    2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * (CAPI*)
++ *
++ * An implementation of Common ISDN API 2.0 for Asterisk
++ *
++ * include file for helper applications
++ *
++ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
++ *
++ * This program is free software and may be modified and 
++ * distributed under the terms of the GNU Public License.
++ */
++
++#ifndef _ASTERISK_CAPI_IF_H
++#define _ASTERISK_CAPI_IF_H
++ 
++// exported symbols from chan_capi
++
++// important things we need
++extern unsigned ast_capi_ApplID;
++extern unsigned ast_capi_MessageNumber;
++extern int capidebug;
++
++extern int capi_call(struct ast_channel *c, char *idest, int timeout);
++extern int capi_detect_dtmf(struct ast_channel *c, int flag);
++extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG);
++
++#endif
+diff -urN asterisk-1.2.4.orig/include/asterisk/channel.h asterisk-1.2.4/include/asterisk/channel.h
+--- asterisk-1.2.4.orig/include/asterisk/channel.h     2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/channel.h  2006-01-31 09:41:43.000000000 +0100
+@@ -86,6 +86,9 @@
+ #ifndef _ASTERISK_CHANNEL_H
+ #define _ASTERISK_CHANNEL_H
++/* Max length of the uniqueid */
++#define AST_MAX_UNIQUEID 64
++
+ #include <unistd.h>
+ #include <setjmp.h>
+ #ifdef POLLCOMPAT 
+@@ -380,7 +383,7 @@
+       unsigned int fout;
+       /* Unique Channel Identifier */
+-      char uniqueid[32];
++      char uniqueid[AST_MAX_UNIQUEID];
+       /* Why is the channel hanged up */
+       int hangupcause;
+@@ -531,6 +534,11 @@
+ #define AST_STATE_MUTE                (1 << 16)       
+ /*! @} */
++extern ast_mutex_t uniquelock;                        
++
++/*! \brief Change the state of a channel and the callerid of the calling channel*/
++int ast_setstate_and_cid(struct ast_channel *chan, int state, char *cid_num, char *cid_name);
++
+ /*! \brief Change the state of a channel */
+ int ast_setstate(struct ast_channel *chan, int state);
+@@ -567,7 +575,7 @@
+  * by the low level module
+  * \return Returns an ast_channel on success, NULL on failure.
+  */
+-struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
++struct ast_channel *ast_request(const char *type, int format, void *data, int *status, char *uniqueid);
+ /*!
+  * \brief Request a channel of a given type, with data as optional information used 
+@@ -582,9 +590,9 @@
+  * \return Returns an ast_channel on success or no answer, NULL on failure.  Check the value of chan->_state
+  * to know if the call was answered or not.
+  */
+-struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname);
++struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, char *uniqueid);
+-struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
++struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, int callingpres, const char *cidnum, const char *cidname, struct outgoing_helper *oh, char *uniqueid);
+ /*!\brief Register a channel technology (a new channel driver)
+  * Called by a channel module to register the kind of channels it supports.
+@@ -837,6 +845,10 @@
+ /*--- ast_get_channel_by_exten_locked: Get channel by exten (and optionally context) and lock it */
+ struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const char *context);
++/*! Get channel by uniqueid (locks channel) */
++struct ast_channel *ast_get_channel_by_uniqueid_locked(const char *uniqueid);
++ 
++
+ /*! Waits for a digit */
+ /*! 
+  * \param c channel to wait for a digit on
+@@ -907,6 +919,9 @@
+    p->owner pointer) that is affected by the change.  The physical layer of the original
+    channel is hung up.  */
+ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
++int ast_channel_masquerade_locked(struct ast_channel *original, struct ast_channel *clone);
++ 
++char *ast_alloc_uniqueid(void);
+ /*! Gives the string form of a given cause code */
+ /*! 
+diff -urN asterisk-1.2.4.orig/include/asterisk/devicestate.h asterisk-1.2.4/include/asterisk/devicestate.h
+--- asterisk-1.2.4.orig/include/asterisk/devicestate.h 2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/devicestate.h      2006-01-31 09:41:43.000000000 +0100
+@@ -42,7 +42,7 @@
+ /*! Device is ringing */
+ #define AST_DEVICE_RINGING    6
+-typedef int (*ast_devstate_cb_type)(const char *dev, int state, void *data);
++typedef int (*ast_devstate_cb_type)(const char *dev, int state, void *data, char *cid_num, char *cid_name);
+ /*! \brief Convert device state to text string for output 
+  * \param devstate Current device state 
+@@ -84,7 +84,7 @@
+  * callbacks for the changed extensions
+  * Returns 0 on success, -1 on failure
+  */
+-int ast_device_state_changed_literal(const char *device);
++int ast_device_state_changed_literal(const char *device, const char *cid_num, const char *cid_name);
+ /*! \brief Registers a device state change callback 
+  * \param callback Callback
+diff -urN asterisk-1.2.4.orig/include/asterisk/features.h asterisk-1.2.4/include/asterisk/features.h
+--- asterisk-1.2.4.orig/include/asterisk/features.h    2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/features.h 2006-01-31 09:41:43.000000000 +0100
+@@ -45,6 +45,8 @@
+ };
++extern int ast_autoanswer_login(struct ast_channel *chan, void *data);
++extern int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data);
+ /*! \brief Park a call and read back parked location 
+  *  \param chan the channel to actually be parked
+@@ -68,11 +70,19 @@
+ */
+ extern int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
++extern int ast_hold_call(struct ast_channel *chan, struct ast_channel *host);
++extern int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *host);
++extern int ast_retrieve_call(struct ast_channel *chan, char *uniqueid);
++extern int ast_retrieve_call_to_death(char *uniqueid);
++extern struct ast_channel *ast_get_holded_call(char *uniqueid);
++
+ /*! \brief Determine system parking extension
+  *  Returns the call parking extension for drivers that provide special
+     call parking help */
+ extern char *ast_parking_ext(void);
++extern char *ast_parking_con(void);
++
+ /*! \brief Determine system call pickup extension */
+ extern char *ast_pickup_ext(void);
+@@ -92,4 +102,12 @@
+     \param feature the ast_call_feature object which was registered before*/
+ extern void ast_unregister_feature(struct ast_call_feature *feature);
++/*! \brief find a  feature by name
++    \param name of the feature to be returned */
++extern struct ast_call_feature *ast_find_feature(char *name);
++
++/*! \brief find a builtin feature by name
++    \param name of the feature to be returned */
++extern struct ast_call_feature *ast_find_builtin_feature(char *name);
++
+ #endif /* _AST_FEATURES_H */
+diff -urN asterisk-1.2.4.orig/include/asterisk/pbx.h asterisk-1.2.4/include/asterisk/pbx.h
+--- asterisk-1.2.4.orig/include/asterisk/pbx.h 2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/pbx.h      2006-01-31 09:41:43.000000000 +0100
+@@ -57,7 +57,7 @@
+       AST_EXTENSION_BUSY = 1 << 1,
+       /*! All devices UNAVAILABLE/UNREGISTERED */
+       AST_EXTENSION_UNAVAILABLE = 1 << 2,
+-      /*! All devices RINGING */
++      /*! One or more devices RINGING */
+       AST_EXTENSION_RINGING = 1 << 3,
+ };
+@@ -80,7 +80,7 @@
+ struct ast_ignorepat;
+ struct ast_sw;
+-typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
++typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data, char *cid_num, char *cid_name);
+ /*! Data structure associated with a custom function */
+ struct ast_custom_function {
+@@ -156,6 +156,8 @@
+  */
+ extern struct ast_app *pbx_findapp(const char *app);
++void *ast_pbx_run_app(void *data);
++
+ /*! executes an application */
+ /*!
+  * \param c channel to execute on
+@@ -563,11 +565,11 @@
+ /* Synchronously or asynchronously make an outbound call and send it to a
+    particular extension */
+-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel);
++int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel, char *uniqueid);
+ /* Synchronously or asynchronously make an outbound call and send it to a
+    particular application with given extension */
+-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel);
++int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel, char *uniqueid);
+ /* Functions for returning values from structures */
+ const char *ast_get_context_name(struct ast_context *con);
+@@ -656,7 +658,7 @@
+  */
+ void ast_func_write(struct ast_channel *chan, const char *in, const char *value);
+-void ast_hint_state_changed(const char *device);
++void ast_hint_state_changed(const char *device, const char *cid_num, const char *cid_name);
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+diff -urN asterisk-1.2.4.orig/include/asterisk/xlaw.h asterisk-1.2.4/include/asterisk/xlaw.h
+--- asterisk-1.2.4.orig/include/asterisk/xlaw.h        1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/include/asterisk/xlaw.h     2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,1665 @@
++#ifndef _ASTERISK_XLAW_H
++#define _ASTERISK_XLAW_H
++
++#ifdef CAPI_ULAW
++#define capiXLAW2INT(x) capiULAW2INT[x]
++#define capiINT2XLAW(x) capiINT2ULAW[((unsigned short)x) >> 2]
++#else
++#define capiXLAW2INT(x) capiALAW2INT[x]
++#define capiINT2XLAW(x) capiINT2ALAW[(x>>4)+4096]
++#endif
++
++static unsigned char reversebits[256] =
++{
++0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
++0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
++0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
++0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
++0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
++0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
++0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
++0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
++0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
++0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
++0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
++0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
++0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
++0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
++0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
++0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
++0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
++0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
++0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
++0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
++0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
++0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
++0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
++0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
++0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
++0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
++0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
++0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
++0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
++0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
++0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
++0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
++};
++
++#ifdef CAPI_ULAW
++static short capiULAW2INT[] =
++{
++0x8284, 0x7d7c, 0xf8a4, 0x075c, 0xe104, 0x1efc, 0xfe8c, 0x0174,
++0xc184, 0x3e7c, 0xfc94, 0x036c, 0xf0c4, 0x0f3c, 0xff88, 0x0078,
++0xa284, 0x5d7c, 0xfaa4, 0x055c, 0xe904, 0x16fc, 0xff0c, 0x00f4,
++0xd184, 0x2e7c, 0xfd94, 0x026c, 0xf4c4, 0x0b3c, 0xffc8, 0x0038,
++0x9284, 0x6d7c, 0xf9a4, 0x065c, 0xe504, 0x1afc, 0xfecc, 0x0134,
++0xc984, 0x367c, 0xfd14, 0x02ec, 0xf2c4, 0x0d3c, 0xffa8, 0x0058,
++0xb284, 0x4d7c, 0xfba4, 0x045c, 0xed04, 0x12fc, 0xff4c, 0x00b4,
++0xd984, 0x267c, 0xfe14, 0x01ec, 0xf6c4, 0x093c, 0xffe8, 0x0018,
++0x8a84, 0x757c, 0xf924, 0x06dc, 0xe304, 0x1cfc, 0xfeac, 0x0154,
++0xc584, 0x3a7c, 0xfcd4, 0x032c, 0xf1c4, 0x0e3c, 0xff98, 0x0068,
++0xaa84, 0x557c, 0xfb24, 0x04dc, 0xeb04, 0x14fc, 0xff2c, 0x00d4,
++0xd584, 0x2a7c, 0xfdd4, 0x022c, 0xf5c4, 0x0a3c, 0xffd8, 0x0028,
++0x9a84, 0x657c, 0xfa24, 0x05dc, 0xe704, 0x18fc, 0xfeec, 0x0114,
++0xcd84, 0x327c, 0xfd54, 0x02ac, 0xf3c4, 0x0c3c, 0xffb8, 0x0048,
++0xba84, 0x457c, 0xfc24, 0x03dc, 0xef04, 0x10fc, 0xff6c, 0x0094,
++0xdd84, 0x227c, 0xfe54, 0x01ac, 0xf7c4, 0x083c, 0xfff8, 0x0008,
++0x8684, 0x797c, 0xf8e4, 0x071c, 0xe204, 0x1dfc, 0xfe9c, 0x0164,
++0xc384, 0x3c7c, 0xfcb4, 0x034c, 0xf144, 0x0ebc, 0xff90, 0x0070,
++0xa684, 0x597c, 0xfae4, 0x051c, 0xea04, 0x15fc, 0xff1c, 0x00e4,
++0xd384, 0x2c7c, 0xfdb4, 0x024c, 0xf544, 0x0abc, 0xffd0, 0x0030,
++0x9684, 0x697c, 0xf9e4, 0x061c, 0xe604, 0x19fc, 0xfedc, 0x0124,
++0xcb84, 0x347c, 0xfd34, 0x02cc, 0xf344, 0x0cbc, 0xffb0, 0x0050,
++0xb684, 0x497c, 0xfbe4, 0x041c, 0xee04, 0x11fc, 0xff5c, 0x00a4,
++0xdb84, 0x247c, 0xfe34, 0x01cc, 0xf744, 0x08bc, 0xfff0, 0x0010,
++0x8e84, 0x717c, 0xf964, 0x069c, 0xe404, 0x1bfc, 0xfebc, 0x0144,
++0xc784, 0x387c, 0xfcf4, 0x030c, 0xf244, 0x0dbc, 0xffa0, 0x0060,
++0xae84, 0x517c, 0xfb64, 0x049c, 0xec04, 0x13fc, 0xff3c, 0x00c4,
++0xd784, 0x287c, 0xfdf4, 0x020c, 0xf644, 0x09bc, 0xffe0, 0x0020,
++0x9e84, 0x617c, 0xfa64, 0x059c, 0xe804, 0x17fc, 0xfefc, 0x0104,
++0xcf84, 0x307c, 0xfd74, 0x028c, 0xf444, 0x0bbc, 0xffc0, 0x0040,
++0xbe84, 0x417c, 0xfc64, 0x039c, 0xf004, 0x0ffc, 0xff7c, 0x0084,
++0xdf84, 0x207c, 0xfe74, 0x018c, 0xf844, 0x07bc, 0x0000, 0x0000
++};
++
++const unsigned char capiINT2ULAW[16384] = {
++255,127,127,191,191,63,63,223,223,95,95,159,159,31,31,239,
++239,111,111,175,175,47,47,207,207,79,79,143,143,15,15,247,
++247,247,247,119,119,119,119,183,183,183,183,55,55,55,55,215,
++215,215,215,87,87,87,87,151,151,151,151,23,23,23,23,231,
++231,231,231,103,103,103,103,167,167,167,167,39,39,39,39,199,
++199,199,199,71,71,71,71,135,135,135,135,7,7,7,7,251,
++251,251,251,251,251,251,251,123,123,123,123,123,123,123,123,187,
++187,187,187,187,187,187,187,59,59,59,59,59,59,59,59,219,
++219,219,219,219,219,219,219,91,91,91,91,91,91,91,91,155,
++155,155,155,155,155,155,155,27,27,27,27,27,27,27,27,235,
++235,235,235,235,235,235,235,107,107,107,107,107,107,107,107,171,
++171,171,171,171,171,171,171,43,43,43,43,43,43,43,43,203,
++203,203,203,203,203,203,203,75,75,75,75,75,75,75,75,139,
++139,139,139,139,139,139,139,11,11,11,11,11,11,11,11,243,
++243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,115,
++115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,179,
++179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,51,
++51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,211,
++211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,83,
++83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,147,
++147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,19,
++19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,227,
++227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,99,
++99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,163,
++163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,35,
++35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,195,
++195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,67,
++67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,131,
++131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,3,
++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,253,
++253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
++253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,125,
++125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,
++125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,189,
++189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
++189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,61,
++61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
++61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,221,
++221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
++221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,93,
++93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,
++93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,157,
++157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
++157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,29,
++29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,
++29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,237,
++237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
++237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,109,
++109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
++109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,173,
++173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
++173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,45,
++45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,
++45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,205,
++205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
++205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,77,
++77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
++77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,141,
++141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
++141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,13,
++13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
++13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
++249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,
++121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
++185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
++57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
++217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,
++89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
++153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,
++25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
++233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
++105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
++169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,
++41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
++201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,
++73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
++137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
++9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++128,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++64,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++192,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++32,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++160,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++96,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++224,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++16,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++144,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++80,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++208,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++48,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++176,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++112,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++240,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
++8,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
++136,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,
++72,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
++200,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,
++40,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
++168,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,
++104,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,
++232,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,
++24,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
++152,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,
++88,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,
++216,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
++56,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
++184,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
++120,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
++248,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++4,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++132,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++68,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++196,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++36,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++164,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++100,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++228,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++20,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++148,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++84,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++212,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++52,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++180,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++116,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++244,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++12,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++140,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++76,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++204,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++44,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++172,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++108,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++236,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++28,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++156,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++92,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++220,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++60,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++188,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++124,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++252,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
++2,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
++130,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
++66,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,
++194,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
++34,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
++162,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,
++98,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,
++226,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
++18,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
++146,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,
++82,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,
++210,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
++50,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
++178,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
++114,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,
++242,10,10,10,10,10,10,10,10,138,138,138,138,138,138,138,
++138,74,74,74,74,74,74,74,74,202,202,202,202,202,202,202,
++202,42,42,42,42,42,42,42,42,170,170,170,170,170,170,170,
++170,106,106,106,106,106,106,106,106,234,234,234,234,234,234,234,
++234,26,26,26,26,26,26,26,26,154,154,154,154,154,154,154,
++154,90,90,90,90,90,90,90,90,218,218,218,218,218,218,218,
++218,58,58,58,58,58,58,58,58,186,186,186,186,186,186,186,
++186,122,122,122,122,122,122,122,122,250,250,250,250,250,250,250,
++250,6,6,6,6,134,134,134,134,70,70,70,70,198,198,198,
++198,38,38,38,38,166,166,166,166,102,102,102,102,230,230,230,
++230,22,22,22,22,150,150,150,150,86,86,86,86,214,214,214,
++214,54,54,54,54,182,182,182,182,118,118,118,118,246,246,246,
++246,14,14,142,142,78,78,206,206,46,46,174,174,110,110,238,
++238,30,30,158,158,94,94,222,222,62,62,190,190,126,126,254,
++};
++#else
++static short capiALAW2INT[] =
++{
++      0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
++      0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
++      0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
++      0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
++      0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
++      0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
++      0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
++      0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
++      0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
++      0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
++      0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
++      0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
++      0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
++      0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
++      0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
++      0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
++      0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
++      0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
++      0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
++      0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
++      0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
++      0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
++      0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
++      0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
++      0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
++      0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
++      0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
++      0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
++      0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
++      0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
++      0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
++      0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
++};
++
++const unsigned char capiINT2ALAW[8192] = {
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,
++  212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++  212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++  212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++  212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,
++  20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++  20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++  20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++  20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
++  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++  148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
++  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++  116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
++  244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++  244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++  244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++  244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
++  52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++  52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++  52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++  52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,
++  180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++  180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++  180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++  180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
++  68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++  68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++  68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++  68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,
++  196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++  196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++  196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++  196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,
++  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
++  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++  132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
++  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++  100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
++  228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++  228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++  228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++  228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,
++  36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++  36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++  36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++  36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
++  164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++  164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++  164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++  164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
++  92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++  92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,
++  220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++  220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,
++  28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++  28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
++  156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++  156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
++  124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++  124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,
++  252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++  252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,
++  60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++  60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
++  188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++  188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
++  76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++  76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,
++  204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++  204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
++  12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++  12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
++  140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++  140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
++  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++  108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
++  236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++  236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,
++  44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++  44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,
++  172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++  172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
++  80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,
++  208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
++  16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
++  144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,
++  112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,
++  240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
++  48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,
++  176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
++  64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
++  192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
++  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++  128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
++  96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,
++  224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
++  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
++  160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
++  88,88,88,88,88,88,88,88,216,216,216,216,216,216,216,216,
++  24,24,24,24,24,24,24,24,152,152,152,152,152,152,152,152,
++  120,120,120,120,120,120,120,120,248,248,248,248,248,248,248,248,
++  56,56,56,56,56,56,56,56,184,184,184,184,184,184,184,184,
++  72,72,72,72,72,72,72,72,200,200,200,200,200,200,200,200,
++  8,8,8,8,8,8,8,8,136,136,136,136,136,136,136,136,
++  104,104,104,104,104,104,104,104,232,232,232,232,232,232,232,232,
++  40,40,40,40,40,40,40,40,168,168,168,168,168,168,168,168,
++  86,86,86,86,214,214,214,214,22,22,22,22,150,150,150,150,
++  118,118,118,118,246,246,246,246,54,54,54,54,182,182,182,182,
++  70,70,70,70,198,198,198,198,6,6,6,6,134,134,134,134,
++  102,102,102,102,230,230,230,230,38,38,38,38,166,166,166,166,
++  94,94,222,222,30,30,158,158,126,126,254,254,62,62,190,190,
++  78,78,206,206,14,14,142,142,110,110,238,238,46,46,174,174,
++  82,210,18,146,114,242,50,178,66,194,2,130,98,226,34,162,
++  90,218,26,154,122,250,58,186,74,202,10,138,106,234,42,170,
++  171,43,235,107,139,11,203,75,187,59,251,123,155,27,219,91,
++  163,35,227,99,131,3,195,67,179,51,243,115,147,19,211,83,
++  175,175,47,47,239,239,111,111,143,143,15,15,207,207,79,79,
++  191,191,63,63,255,255,127,127,159,159,31,31,223,223,95,95,
++  167,167,167,167,39,39,39,39,231,231,231,231,103,103,103,103,
++  135,135,135,135,7,7,7,7,199,199,199,199,71,71,71,71,
++  183,183,183,183,55,55,55,55,247,247,247,247,119,119,119,119,
++  151,151,151,151,23,23,23,23,215,215,215,215,87,87,87,87,
++  169,169,169,169,169,169,169,169,41,41,41,41,41,41,41,41,
++  233,233,233,233,233,233,233,233,105,105,105,105,105,105,105,105,
++  137,137,137,137,137,137,137,137,9,9,9,9,9,9,9,9,
++  201,201,201,201,201,201,201,201,73,73,73,73,73,73,73,73,
++  185,185,185,185,185,185,185,185,57,57,57,57,57,57,57,57,
++  249,249,249,249,249,249,249,249,121,121,121,121,121,121,121,121,
++  153,153,153,153,153,153,153,153,25,25,25,25,25,25,25,25,
++  217,217,217,217,217,217,217,217,89,89,89,89,89,89,89,89,
++  161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
++  33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
++  225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,
++  97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,
++  129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
++  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
++  193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
++  65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
++  177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
++  49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,
++  241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,
++  113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
++  145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,
++  17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
++  209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
++  81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,
++  173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
++  173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
++  45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,
++  45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,
++  237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
++  237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
++  109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
++  109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
++  141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
++  141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
++  13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
++  13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
++  205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
++  205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
++  77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
++  77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
++  189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
++  189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
++  61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
++  61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
++  253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
++  253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
++  125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,
++  125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,
++  157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
++  157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,
++  29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,
++  29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,
++  221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
++  221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
++  93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,
++  93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,
++  165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++  165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++  165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++  165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
++  37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++  37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++  37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++  37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
++  229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++  229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++  229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++  229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,
++  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++  101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,
++  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++  133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
++  5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++  5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++  5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++  5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
++  197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++  197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++  197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++  197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
++  69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++  69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++  69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++  69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,
++  181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++  181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++  181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++  181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
++  53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++  53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++  53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++  53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,
++  245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++  245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++  245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++  245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,
++  117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++  117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++  117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++  117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,
++  149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++  149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++  149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++  149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,
++  21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++  21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++  21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++  21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
++  213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++  213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++  213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++  213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,
++  85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85
++};
++
++#endif // CAPI_ULAW
++#endif
++
+diff -urN asterisk-1.2.4.orig/include/asterisk.h asterisk-1.2.4/include/asterisk.h
+--- asterisk-1.2.4.orig/include/asterisk.h     2005-11-30 04:37:37.000000000 +0100
++++ asterisk-1.2.4/include/asterisk.h  2006-01-31 09:41:43.000000000 +0100
+@@ -36,6 +36,7 @@
+ extern char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
++extern char ast_config_AST_SYMBOLIC_NAME[20];
+ extern char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH];
+ extern char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH];
+diff -urN asterisk-1.2.4.orig/manager.c asterisk-1.2.4/manager.c
+--- asterisk-1.2.4.orig/manager.c      2006-01-09 05:52:16.000000000 +0100
++++ asterisk-1.2.4/manager.c   2006-01-31 09:41:43.000000000 +0100
+@@ -11,6 +11,9 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2003-2004, Junghanns.NET Gmbh
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
+  * 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.
+@@ -62,6 +65,7 @@
+ #include "asterisk/md5.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/utils.h"
++#include "asterisk/astdb.h"
+ struct fast_originate_helper {
+       char tech[256];
+@@ -75,6 +79,8 @@
+       char exten[256];
+       char idtext[256];
+       int priority;
++      int callingpres;
++      char uniqueid[64];
+       struct ast_variable *vars;
+ };
+@@ -656,11 +662,17 @@
+ {
+       struct ast_channel *c = NULL;
+       char *name = astman_get_header(m, "Channel");
+-      if (ast_strlen_zero(name)) {
+-              astman_send_error(s, m, "No channel specified");
++      char *uniqueid = astman_get_header(m, "Uniqueid");
++      if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
++              astman_send_error(s, m, "No channel or uniqueid specified");
+               return 0;
+       }
+-      c = ast_get_channel_by_name_locked(name);
++      if (!ast_strlen_zero(uniqueid)) {
++              c = ast_get_channel_by_uniqueid_locked(uniqueid);
++      } else {
++          if (!ast_strlen_zero(name))
++              c = ast_get_channel_by_name_locked(name);
++      }       
+       if (!c) {
+               astman_send_error(s, m, "No such channel");
+               return 0;
+@@ -759,6 +771,7 @@
+ }
++
+ /*! \brief  action_status: Manager "status" command to show channels */
+ /* Needs documentation... */
+ static int action_status(struct mansession *s, struct message *m)
+@@ -865,32 +878,50 @@
+       char *exten = astman_get_header(m, "Exten");
+       char *context = astman_get_header(m, "Context");
+       char *priority = astman_get_header(m, "Priority");
++      char *uniqueid = astman_get_header(m, "Uniqueid");
++      char *uniqueid2 = astman_get_header(m, "ExtraUniqueid");
++      char *exten2 = astman_get_header(m, "ExtraExten");
++      char *context2 = astman_get_header(m, "ExtraContext");
++      char *priority2 = astman_get_header(m, "ExtraPriority");
+       struct ast_channel *chan, *chan2 = NULL;
+       int pi = 0;
++      int pi2 = 0;
+       int res;
+-      if (ast_strlen_zero(name)) {
+-              astman_send_error(s, m, "Channel not specified");
++      if ((!name || ast_strlen_zero(name)) && (!uniqueid || ast_strlen_zero(uniqueid))) {
++              astman_send_error(s, m, "Channel or Uniqueid not specified");
+               return 0;
+       }
+       if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
+               astman_send_error(s, m, "Invalid priority\n");
+               return 0;
+       }
+-      chan = ast_get_channel_by_name_locked(name);
++      if (uniqueid && (!ast_strlen_zero(uniqueid))) {
++          chan = ast_get_channel_by_uniqueid_locked(uniqueid);
++      } else {
++          chan = ast_get_channel_by_name_locked(name);
++      }
+       if (!chan) {
+               char buf[BUFSIZ];
+               snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
+               astman_send_error(s, m, buf);
+               return 0;
+       }
+-      if (!ast_strlen_zero(name2))
++      if (!ast_strlen_zero(uniqueid2)) {
++              chan2 = ast_get_channel_by_uniqueid_locked(uniqueid2);
++              if (!ast_strlen_zero(priority2) && (sscanf(priority, "%d", &pi2) != 1)) {
++                  astman_send_error(s, m, "Invalid priority2\n");
++                  return 0;
++              }
++      } else {
++          if (!ast_strlen_zero(name2))
+               chan2 = ast_get_channel_by_name_locked(name2);
++      }
+       res = ast_async_goto(chan, context, exten, pi);
+       if (!res) {
+-              if (!ast_strlen_zero(name2)) {
++              if ((!ast_strlen_zero(name2)) || (!ast_strlen_zero(uniqueid2))){
+                       if (chan2)
+-                              res = ast_async_goto(chan2, context, exten, pi);
++                              res = ast_async_goto(chan2, context2, exten2, pi2);
+                       else
+                               res = -1;
+                       if (!res)
+@@ -936,15 +967,15 @@
+       struct ast_channel *chan = NULL;
+       if (!ast_strlen_zero(in->app)) {
+-              res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, 
++              res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, in->callingpres, 
+                       !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
+                       !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
+-                      in->vars, &chan);
++                      in->vars, &chan, in->uniqueid);
+       } else {
+-              res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, 
++              res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, in->callingpres, 
+                       !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL, 
+                       !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
+-                      in->vars, &chan);
++                      in->vars, &chan, in->uniqueid);
+       }   
+       if (!res)
+               manager_event(EVENT_FLAG_CALL,
+@@ -955,7 +986,7 @@
+                       "Exten: %s\r\n"
+                       "Reason: %d\r\n"
+                       "Uniqueid: %s\r\n",
+-                      in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
++                      in->idtext, in->tech, in->data, in->context, in->exten, reason, in->uniqueid ? in->uniqueid : (chan ? chan->uniqueid : "<null>"));
+       else
+               manager_event(EVENT_FLAG_CALL,
+                       "OriginateFailure",
+@@ -965,7 +996,7 @@
+                       "Exten: %s\r\n"
+                       "Reason: %d\r\n"
+                       "Uniqueid: %s\r\n",
+-                      in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
++                      in->idtext, in->tech, in->data, in->context, in->exten, reason, in->uniqueid ? in->uniqueid : (chan ? chan->uniqueid : "<null>"));
+       /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
+       if (chan)
+@@ -998,6 +1029,7 @@
+       char *priority = astman_get_header(m, "Priority");
+       char *timeout = astman_get_header(m, "Timeout");
+       char *callerid = astman_get_header(m, "CallerID");
++      char *callingpres = astman_get_header(m, "CallingPres");
+       char *account = astman_get_header(m, "Account");
+       char *app = astman_get_header(m, "Application");
+       char *appdata = astman_get_header(m, "Data");
+@@ -1006,12 +1038,15 @@
+       struct ast_variable *vars = astman_get_variables(m);
+       char *tech, *data;
+       char *l=NULL, *n=NULL;
++      char *uniqueid;
+       int pi = 0;
++      int cpresi = 0;
+       int res;
+       int to = 30000;
+       int reason = 0;
+       char tmp[256];
+       char tmp2[256];
++      char idText[256] = "";
+       
+       pthread_t th;
+       pthread_attr_t attr;
+@@ -1027,6 +1062,10 @@
+               astman_send_error(s, m, "Invalid timeout\n");
+               return 0;
+       }
++      if (!ast_strlen_zero(callingpres) && (sscanf(callingpres, "%d", &cpresi) != 1)) {
++              astman_send_error(s, m, "Invalid CallingPres\n");
++              return 0;
++      }
+       ast_copy_string(tmp, name, sizeof(tmp));
+       tech = tmp;
+       data = strchr(tmp, '/');
+@@ -1053,6 +1092,7 @@
+               newvar->next = vars;
+               vars = newvar;
+       }
++      uniqueid = ast_alloc_uniqueid();
+       if (ast_true(async)) {
+               struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
+               if (!fast) {
+@@ -1072,8 +1112,10 @@
+                       fast->vars = vars;      
+                       ast_copy_string(fast->context, context, sizeof(fast->context));
+                       ast_copy_string(fast->exten, exten, sizeof(fast->exten));
++                      ast_copy_string(fast->uniqueid, uniqueid, sizeof(fast->uniqueid));
+                       fast->timeout = to;
+                       fast->priority = pi;
++                      fast->callingpres = cpresi;
+                       pthread_attr_init(&attr);
+                       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+                       if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
+@@ -1083,19 +1125,28 @@
+                       }
+               }
+       } else if (!ast_strlen_zero(app)) {
+-              res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
++              res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, cpresi, l, n, vars, NULL, uniqueid);
+       } else {
+               if (exten && context && pi)
+-                      res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
++                      res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, cpresi, l, n, vars, NULL, uniqueid);
+               else {
+                       astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
+                       return 0;
+               }
+       }   
+-      if (!res)
+-              astman_send_ack(s, m, "Originate successfully queued");
+-      else
++      if (!res) {
++              if (id && !ast_strlen_zero(id)) {
++                  snprintf(idText,256,"ActionID: %s\r\n",id);
++              }
++              ast_cli(s->fd, "Response: Success\r\n"
++                                  "%s"
++                                 "Message: Originate successfully queued\r\n"
++                                 "Uniqueid: %s\r\n"
++                                 "\r\n",
++                                  idText, uniqueid);
++      } else {
+               astman_send_error(s, m, "Originate failed");
++      }
+       return 0;
+ }
+@@ -1569,10 +1620,10 @@
+       return 0;
+ }
+-static int manager_state_cb(char *context, char *exten, int state, void *data)
++static int manager_state_cb(char *context, char *exten, int state, void *data, char *cid_num, char *cid_name)
+ {
+       /* Notify managers of change */
+-      manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
++      manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\nCallerID: \"%s\" <%s>\r\n", exten, context, state, cid_num, cid_name);
+       return 0;
+ }
+diff -urN asterisk-1.2.4.orig/pbx/pbx_spool.c asterisk-1.2.4/pbx/pbx_spool.c
+--- asterisk-1.2.4.orig/pbx/pbx_spool.c        2006-01-09 21:08:24.000000000 +0100
++++ asterisk-1.2.4/pbx/pbx_spool.c     2006-01-31 09:41:43.000000000 +0100
+@@ -260,11 +260,11 @@
+       if (!ast_strlen_zero(o->app)) {
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_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, NULL);
++              res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, 0, o->cid_num, o->cid_name, o->vars, NULL, NULL);
+       } else {
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_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, NULL);
++              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 */, 0, o->cid_num, o->cid_name, o->vars, NULL, NULL);
+       }
+       if (res) {
+               ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason);
+diff -urN asterisk-1.2.4.orig/pbx.c asterisk-1.2.4/pbx.c
+--- asterisk-1.2.4.orig/pbx.c  2006-01-22 03:05:41.000000000 +0100
++++ asterisk-1.2.4/pbx.c       2006-01-31 09:41:43.000000000 +0100
+@@ -350,7 +350,8 @@
+       
+       { "Hangup", pbx_builtin_hangup,
+       "Hang up the calling channel",
+-      "  Hangup(): This application will hang up the calling channel.\n"
++      "  Hangup(Cause): Unconditionally hangs up a given channel by returning -1 always.\n" 
++      "                 If cause is given, it will set the hangup cause accordingly.\n" 
+       },
+       { "NoOp", pbx_builtin_noop,
+@@ -1871,7 +1872,7 @@
+       return ast_extension_state2(e);                 /* Check all devices in the hint */
+ }
+-void ast_hint_state_changed(const char *device)
++void ast_hint_state_changed(const char *device, const char *cid_num, const char *cid_name)
+ {
+       struct ast_hint *hint;
+       struct ast_state_cb *cblist;
+@@ -1899,11 +1900,11 @@
+                       
+                       /* For general callbacks */
+                       for (cblist = statecbs; cblist; cblist = cblist->next)
+-                              cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
++                              cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data, cid_num, cid_name);
+                       
+                       /* For extension callbacks */
+                       for (cblist = hint->callbacks; cblist; cblist = cblist->next)
+-                              cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
++                              cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data, cid_num, cid_name);
+                       
+                       hint->laststate = state;
+                       break;
+@@ -2144,7 +2145,7 @@
+                               /* Notify with -1 and remove all callbacks */
+                               cbprev = cblist;            
+                               cblist = cblist->next;
+-                              cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
++                              cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data, NULL, NULL);
+                               free(cbprev);
+                       }
+                       list->callbacks = NULL;
+@@ -3758,7 +3759,7 @@
+                       while (thiscb) {
+                               prevcb = thiscb;            
+                               thiscb = thiscb->next;
+-                              prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
++                              prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data, NULL, NULL);
+                               free(prevcb);
+                       }
+               } else {
+@@ -4957,7 +4958,7 @@
+       return 0;  /* success */
+ }
+-int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **channel)
++int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **channel, char *uniqueid)
+ {
+       struct ast_channel *chan;
+       struct async_stat *as;
+@@ -4967,7 +4968,7 @@
+       if (sync) {
+               LOAD_OH(oh);
+-              chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++              chan = __ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
+               if (channel) {
+                       *channel = chan;
+                       if (chan)
+@@ -5063,7 +5064,7 @@
+                       goto outgoing_exten_cleanup;
+               }       
+               memset(as, 0, sizeof(struct async_stat));
+-              chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
++              chan = ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
+               if (channel) {
+                       *channel = chan;
+                       if (chan)
+@@ -5105,7 +5106,7 @@
+       pthread_t t;
+ };
+-static void *ast_pbx_run_app(void *data)
++void *ast_pbx_run_app(void *data)
+ {
+       struct app_tmp *tmp = data;
+       struct ast_app *app;
+@@ -5121,7 +5122,7 @@
+       return NULL;
+ }
+-int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel)
++int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, int callingpres, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel, char *uniqueid)
+ {
+       struct ast_channel *chan;
+       struct async_stat *as;
+@@ -5140,7 +5141,7 @@
+               goto outgoing_app_cleanup;      
+       }
+       if (sync) {
+-              chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++              chan = __ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
+               if (chan) {
+                       if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
+                               ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
+@@ -5225,7 +5226,8 @@
+                       goto outgoing_app_cleanup;
+               }
+               memset(as, 0, sizeof(struct async_stat));
+-              chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
++              chan = __ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, &oh, uniqueid);
++//            chan = ast_request_and_dial(type, format, data, timeout, reason, callingpres, cid_num, cid_name, uniqueid);
+               if (!chan) {
+                       free(as);
+                       res = -1;
+@@ -5510,6 +5512,9 @@
+  */
+ static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
+ {
++        /* Copy the hangup cause as specified */
++        if (data)
++             chan->hangupcause = atoi(data);
+       /* Just return non-zero and it will hang up */
+       if (!chan->hangupcause)
+               chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+@@ -6151,6 +6156,9 @@
+                       return -1;
+               }
+       }
++      if (chan->_state != AST_STATE_UP) {
++          ast_answer(chan);
++      }
+       return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
+ }
+@@ -6158,8 +6166,12 @@
+ {
+       int res = 0;
+-      if (data)
++      if (data) {
++              if (chan->_state != AST_STATE_UP) {
++                  ast_answer(chan);
++              }
+               res = ast_say_digit_str(chan, (char *)data, "", chan->language);
++      }
+       return res;
+ }
+       
+@@ -6167,8 +6179,12 @@
+ {
+       int res = 0;
+-      if (data)
++      if (data) {
++              if (chan->_state != AST_STATE_UP) {
++                  ast_answer(chan);
++              }
+               res = ast_say_character_str(chan, (char *)data, "", chan->language);
++      }
+       return res;
+ }
+       
+@@ -6176,8 +6192,12 @@
+ {
+       int res = 0;
+-      if (data)
++      if (data) {
++              if (chan->_state != AST_STATE_UP) {
++                  ast_answer(chan);
++              }
+               res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
++      }
+       return res;
+ }
+       
+diff -urN asterisk-1.2.4.orig/res/Makefile asterisk-1.2.4/res/Makefile
+--- asterisk-1.2.4.orig/res/Makefile   2005-11-29 19:24:39.000000000 +0100
++++ asterisk-1.2.4/res/Makefile        2006-01-31 09:41:43.000000000 +0100
+@@ -11,7 +11,7 @@
+ # the GNU General Public License
+ #
+-MODS=res_indications.so res_monitor.so res_adsi.so res_agi.so res_features.so
++MODS=res_indications.so res_monitor.so res_adsi.so res_agi.so res_features.so res_watchdog.so
+ ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/odbcinst.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/odbcinst.h),)
+   ifneq (${OSARCH},FreeBSD)
+diff -urN asterisk-1.2.4.orig/res/res_agi.c asterisk-1.2.4/res/res_agi.c
+--- asterisk-1.2.4.orig/res/res_agi.c  2005-12-20 21:21:26.000000000 +0100
++++ asterisk-1.2.4/res/res_agi.c       2006-01-31 09:41:43.000000000 +0100
+@@ -11,6 +11,9 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
+  * 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.
+@@ -74,16 +77,19 @@
+ static char *app = "AGI";
++static char *xapp = "XAGI";
++
+ static char *eapp = "EAGI";
+ static char *deadapp = "DeadAGI";
+ static char *synopsis = "Executes an AGI compliant application";
++static char *xsynopsis = "Executes an XAGI compliant application";
+ static char *esynopsis = "Executes an EAGI compliant application";
+ static char *deadsynopsis = "Executes AGI on a hungup channel";
+ static char *descrip =
+-"  [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
++"  [E|Dead|X]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
+ "program on a channel. AGI allows Asterisk to launch external programs\n"
+ "written in any language to control a telephony channel, play audio,\n"
+ "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
+@@ -91,7 +97,9 @@
+ "Returns -1 on hangup (except for DeadAGI) or if application requested\n"
+ " hangup, or 0 on non-hangup exit. \n"
+ "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band"
+-"on file descriptor 3\n\n"
++" on file descriptor 3\n"
++"Using 'XAGI' provides enhanced AGI, with incoming audio available out of band"
++" on file descriptor 3 and outgoing audio available out of band on file descriptor 4\n\n"
+ "Use the CLI command 'show agi' to list available agi commands\n";
+ static int agidebug = 0;
+@@ -214,13 +222,14 @@
+       return 0;
+ }
+-static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
++static int launch_script(char *script, char *argv[], int *fds, int *efd, int *efd2, int *opid)
+ {
+       char tmp[256];
+       int pid;
+       int toast[2];
+       int fromast[2];
+       int audio[2];
++      int audio2[2];
+       int x;
+       int res;
+       sigset_t signal_set;
+@@ -265,6 +274,33 @@
+                       return -1;
+               }
+       }
++      if (efd2) {
++              if (pipe(audio2)) {
++                      ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
++                      close(fromast[0]);
++                      close(fromast[1]);
++                      close(toast[0]);
++                      close(toast[1]);
++                      close(audio[0]);
++                      close(audio[1]);
++                      return -1;
++              }
++              res = fcntl(audio2[0], F_GETFL);
++              if (res > -1) 
++                      res = fcntl(audio2[0], F_SETFL, res | O_NONBLOCK);
++              if (res < 0) {
++                      ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
++                      close(fromast[0]);
++                      close(fromast[1]);
++                      close(toast[0]);
++                      close(toast[1]);
++                      close(audio[0]);
++                      close(audio[1]);
++                      close(audio2[0]);
++                      close(audio2[1]);
++                      return -1;
++              }
++      }
+       pid = fork();
+       if (pid < 0) {
+               ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
+@@ -279,15 +315,19 @@
+               } else {
+                       close(STDERR_FILENO + 1);
+               }
++              if (efd2) {
++                      dup2(audio2[1], STDERR_FILENO + 2);
++              } else {
++                      close(STDERR_FILENO + 2);
++              }
+               
+               /* unblock important signal handlers */
+               if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
+                       ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
+                       exit(1);
+               }
+-
+               /* Close everything but stdin/out/error */
+-              for (x=STDERR_FILENO + 2;x<1024;x++) 
++              for (x=STDERR_FILENO + 3;x<1024;x++) 
+                       close(x);
+               /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
+@@ -306,6 +346,9 @@
+       if (efd) {
+               *efd = audio[1];
+       }
++      if (efd2) {
++              *efd2 = audio2[0];
++      }
+       /* close what we're not using in the parent */
+       close(toast[1]);
+       close(fromast[0]);
+@@ -314,6 +357,9 @@
+               /* [PHM 12/18/03] */
+               close(audio[0]);
+       }
++      if (efd2) {
++              close(audio2[1]);
++      }
+       *opid = pid;
+       return 0;
+@@ -344,7 +390,7 @@
+       fdprintf(fd, "agi_context: %s\n", chan->context);
+       fdprintf(fd, "agi_extension: %s\n", chan->exten);
+       fdprintf(fd, "agi_priority: %d\n", chan->priority);
+-      fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
++      fdprintf(fd, "agi_enhanced: %d%s\n", enhanced, ".0");
+       /* User information */
+       fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
+@@ -376,7 +422,7 @@
+               return RESULT_SHOWUSAGE;
+       if (sscanf(argv[3], "%d", &to) != 1)
+               return RESULT_SHOWUSAGE;
+-      res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
++      res = ast_waitfordigit_full(chan, to, agi->audio_out, agi->ctrl);
+       fdprintf(agi->fd, "200 result=%d\n", res);
+       if (res >= 0)
+               return RESULT_SUCCESS;
+@@ -552,7 +598,7 @@
+               else
+                       return RESULT_FAILURE;
+       }
+-      res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
++      res = ast_waitstream_full(chan, argv[3], agi->audio_out, agi->ctrl);
+       /* this is to check for if ast_waitstream closed the stream, we probably are at
+        * the end of the stream, return that amount, else check for the amount */
+       sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
+@@ -612,7 +658,7 @@
+                 else
+                         return RESULT_FAILURE;
+         }
+-        res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
++        res = ast_waitstream_full(chan, argv[3], agi->audio_out, agi->ctrl);
+         /* this is to check for if ast_waitstream closed the stream, we probably are at
+          * the end of the stream, return that amount, else check for the amount */
+         sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
+@@ -624,7 +670,7 @@
+       /* If the user didnt press a key, wait for digitTimeout*/
+       if (res == 0 ) {
+-              res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
++              res = ast_waitfordigit_full(chan, timeout, agi->audio_out, agi->ctrl);
+               /* Make sure the new result is in the escape digits of the GET OPTION */
+               if ( !strchr(edigits,res) )
+                       res=0;
+@@ -651,7 +697,7 @@
+               return RESULT_SHOWUSAGE;
+       if (sscanf(argv[2], "%d", &num) != 1)
+               return RESULT_SHOWUSAGE;
+-      res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
++      res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio_out, agi->ctrl);
+       if (res == 1)
+               return RESULT_SUCCESS;
+       fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -671,7 +717,7 @@
+       if (sscanf(argv[2], "%d", &num) != 1)
+               return RESULT_SHOWUSAGE;
+-      res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
++      res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl);
+       if (res == 1) /* New command */
+               return RESULT_SUCCESS;
+       fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -688,7 +734,7 @@
+       if (argc != 4)
+               return RESULT_SHOWUSAGE;
+-      res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
++      res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl);
+       if (res == 1) /* New command */
+               return RESULT_SUCCESS;
+       fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -778,7 +824,7 @@
+       if (argc != 4)
+               return RESULT_SHOWUSAGE;
+-      res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
++      res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio_out, agi->ctrl);
+       if (res == 1) /* New command */
+               return RESULT_SUCCESS;
+       fdprintf(agi->fd, "200 result=%d\n", res);
+@@ -805,7 +851,7 @@
+               max = atoi(argv[4]); 
+       else
+               max = 1024;
+-      res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
++      res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio_out, agi->ctrl);
+       if (res == 2)                   /* New command */
+               return RESULT_SUCCESS;
+       else if (res == 1)
+@@ -1843,7 +1889,12 @@
+       int ms;
+       int returnstatus = 0;
+       struct ast_frame *f;
++      struct ast_frame fr;
+       char buf[2048];
++      char audiobuf[2048];
++      int audiobytes;
++      int fds[2];
++      int enhanced = 0;
+       FILE *readf;
+       /* how many times we'll retry if ast_waitfor_nandfs will return without either 
+         channel or file descriptor in case select is interrupted by a system call (EINTR) */
+@@ -1857,10 +1908,22 @@
+               return -1;
+       }
+       setlinebuf(readf);
+-      setup_env(chan, request, agi->fd, (agi->audio > -1));
++      if (agi->audio_out > -1) {
++          enhanced = 1;
++      }
++      if (agi->audio_in > -1) {
++          enhanced++;
++      }
++      setup_env(chan, request, agi->fd, enhanced);
++      fds[0] = agi->ctrl;
++      fds[1] = agi->audio_in;
+       for (;;) {
+               ms = -1;
+-              c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
++              if (agi->audio_in > -1) {
++                  c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, fds, 2, NULL, &outfd, &ms);
++              } else {
++                  c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
++              }
+               if (c) {
+                       retry = RETRY;
+                       /* Idle the channel until we get a command */
+@@ -1871,13 +1934,24 @@
+                               break;
+                       } else {
+                               /* If it's voice, write it to the audio pipe */
+-                              if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
++                              if ((agi->audio_out > -1) && (f->frametype == AST_FRAME_VOICE)) {
+                                       /* Write, ignoring errors */
+-                                      write(agi->audio, f->data, f->datalen);
++                                      write(agi->audio_out, f->data, f->datalen);
+                               }
+                               ast_frfree(f);
+                       }
+               } else if (outfd > -1) {
++                  if ((agi->audio_in > -1) && (outfd == agi->audio_in)) {
++                      audiobytes = read(agi->audio_in, audiobuf, sizeof(audiobuf));
++                      if (audiobytes > 0) {
++                      //    ast_log(LOG_NOTICE, "read %d bytes of audio\n", audiobytes);
++                          fr.frametype = AST_FRAME_VOICE;
++                          fr.subclass = AST_FORMAT_SLINEAR;
++                          fr.datalen = audiobytes;
++                          fr.data = audiobuf;
++                          ast_write(chan, &fr);
++                      }
++                  } else {
+                       retry = RETRY;
+                       if (!fgets(buf, sizeof(buf), readf)) {
+                               /* Program terminated */
+@@ -1899,6 +1973,7 @@
+                       if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
+                               break;
+                       }
++                  }
+               } else {
+                       if (--retry <= 0) {
+                               ast_log(LOG_WARNING, "No channel, no fd?\n");
+@@ -2005,6 +2080,7 @@
+       int argc = 0;
+       int fds[2];
+       int efd = -1;
++      int efd2 = -1;
+       int pid;
+         char *stringp;
+       AGI agi;
+@@ -2030,15 +2106,18 @@
+               }
+       }
+ #endif
+-      res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
++      res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, (enhanced == 2) ? &efd2 : NULL, &pid);
+       if (!res) {
+               agi.fd = fds[1];
+               agi.ctrl = fds[0];
+-              agi.audio = efd;
++              agi.audio_out = efd;
++              agi.audio_in = efd2;
+               res = run_agi(chan, argv[0], &agi, pid, dead);
+               close(fds[1]);
+               if (efd > -1)
+                       close(efd);
++              if (efd2 > -1)
++                      close(efd2);
+       }
+       LOCAL_USER_REMOVE(u);
+       return res;
+@@ -2072,6 +2151,35 @@
+       return res;
+ }
++static int xagi_exec(struct ast_channel *chan, void *data)
++{
++      int readformat, writeformat;
++      int res;
++
++      if (chan->_softhangup)
++              ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
++      readformat = chan->readformat;
++      if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
++              ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
++              return -1;
++      }
++      writeformat = chan->writeformat;
++      if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
++              ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
++              return -1;
++      }
++      res = agi_exec_full(chan, data, 2, 0);
++      if (!res) {
++              if (ast_set_read_format(chan, readformat)) {
++                      ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
++              }
++              if (ast_set_write_format(chan, writeformat)) {
++                      ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(writeformat));
++              }
++      }
++      return res;
++}
++
+ static int deadagi_exec(struct ast_channel *chan, void *data)
+ {
+       return agi_exec_full(chan, data, 0, 1);
+@@ -2101,6 +2209,7 @@
+       ast_cli_unregister(&dumpagihtml);
+       ast_cli_unregister(&cli_debug);
+       ast_cli_unregister(&cli_no_debug);
++      ast_unregister_application(xapp);
+       ast_unregister_application(eapp);
+       ast_unregister_application(deadapp);
+       return ast_unregister_application(app);
+@@ -2114,6 +2223,7 @@
+       ast_cli_register(&cli_no_debug);
+       ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
+       ast_register_application(eapp, eagi_exec, esynopsis, descrip);
++      ast_register_application(xapp, xagi_exec, xsynopsis, descrip);
+       return ast_register_application(app, agi_exec, synopsis, descrip);
+ }
+diff -urN asterisk-1.2.4.orig/res/res_features.c asterisk-1.2.4/res/res_features.c
+--- asterisk-1.2.4.orig/res/res_features.c     2006-01-17 19:29:57.000000000 +0100
++++ asterisk-1.2.4/res/res_features.c  2006-01-31 09:41:43.000000000 +0100
+@@ -11,6 +11,10 @@
+  * the project provides a web site, mailing lists and IRC
+  * channels for your use.
+  *
++ * Copyright (C) 2004, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
+  * 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.
+@@ -56,6 +60,7 @@
+ #include "asterisk/utils.h"
+ #include "asterisk/adsi.h"
+ #include "asterisk/monitor.h"
++#include "asterisk/indications.h"
+ #ifdef __AST_DEBUG_MALLOC
+ static void FREE(void *ptr)
+@@ -73,6 +78,7 @@
+ #define AST_MAX_WATCHERS 256
+ static char *parkedcall = "ParkedCall";
++static char *holdedcall = "HoldedCall";
+ /* No more than 45 seconds parked before you do something with them */
+ static int parkingtime = DEFAULT_PARK_TIME;
+@@ -132,6 +138,20 @@
+ "into the dialplan, although you should include the 'parkedcalls'\n"
+ "context.\n";
++static char *autoanswerlogin = "AutoanswerLogin";
++
++static char *synopsis3 = "Log in for autoanswer";
++
++static char *descrip3 = "AutoanswerLogin(exten):"
++"Used to login to the autoanswer application for an extension.\n";
++
++static char *autoanswer = "Autoanswer";
++
++static char *synopsis4 = "Autoanswer a call";
++
++static char *descrip4 = "Autoanswer(exten):"
++"Used to autoanswer a call for an extension.\n";
++
+ static struct ast_app *monitor_app=NULL;
+ static int monitor_ok=1;
+@@ -150,12 +170,51 @@
+       struct parkeduser *next;
+ };
++struct holdeduser {
++      struct ast_channel *chan;
++      struct timeval start;
++      int parkingnum;
++      int cref;
++      int tei;
++      /* Where to go if our parking time expires */
++      char context[AST_MAX_EXTENSION];
++      char exten[AST_MAX_EXTENSION];
++      int priority;
++      int parkingtime;
++      char uniqueid[AST_MAX_UNIQUEID];
++      char uniqueidpeer[AST_MAX_UNIQUEID];
++      struct holdeduser *next;
++};
++
++/* auto answer user */
++struct aauser {
++      struct ast_channel *chan;
++      struct timeval start;
++      /* waiting on this extension/context */
++      char exten[AST_MAX_EXTENSION];
++      char context[AST_MAX_EXTENSION];
++      int priority;
++      int notquiteyet;
++      struct aauser *next;
++};
++
++ 
++static struct aauser *aalot;
++AST_MUTEX_DEFINE_STATIC(autoanswer_lock);
++static pthread_t autoanswer_thread;
++
+ static struct parkeduser *parkinglot;
++static struct holdeduser *holdlist;
++
+ AST_MUTEX_DEFINE_STATIC(parking_lock);
++AST_MUTEX_DEFINE_STATIC(holding_lock);
++
+ static pthread_t parking_thread;
++static pthread_t holding_thread;
++
+ STANDARD_LOCAL_USER;
+ LOCAL_USER_DECL;
+@@ -165,6 +224,12 @@
+       return parking_ext;
+ }
++char *ast_parking_con(void)
++{
++      return parking_con;
++}
++
++
+ char *ast_pickup_ext(void)
+ {
+       return pickup_ext;
+@@ -362,10 +427,11 @@
+               "Timeout: %ld\r\n"
+               "CallerID: %s\r\n"
+               "CallerIDName: %s\r\n"
++              "Unqiueid: %s\r\n\r\n"
+               ,pu->parkingnum, pu->chan->name, peer->name
+               ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
+               ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-              ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++              ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+               );
+       if (peer) {
+@@ -418,7 +484,8 @@
+               ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
+               ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
+               chan->priority = rchan->priority;
+-
++              /* might be dirty but we want trackable channels */
++              strncpy(chan->uniqueid, rchan->uniqueid, sizeof(chan->uniqueid) - 1);
+               /* Make the masq execute */
+               f = ast_read(chan);
+               if (f)
+@@ -906,7 +973,7 @@
+ }
+ /* find a feature by name */
+-static struct ast_call_feature *find_feature(char *name)
++struct ast_call_feature *ast_find_feature(char *name)
+ {
+       struct ast_call_feature *tmp;
+@@ -916,10 +983,21 @@
+                       break;
+       }
+       AST_LIST_UNLOCK(&feature_list);
+-
+       return tmp;
+ }
++struct ast_call_feature *ast_find_builtin_feature(char *name)
++{
++      int x = 0;
++
++      for (x = 0; x < FEATURES_COUNT; x++) {
++              if (!strcasecmp(name, builtin_features[x].sname)) {
++                  return &builtin_features[x];
++              } 
++      }
++      return NULL;
++}
++
+ /* exec an app by feature */
+ static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
+ {
+@@ -1014,7 +1092,7 @@
+                       return res;
+               
+               while ((tok = strsep(&tmp, "#")) != NULL) {
+-                      feature = find_feature(tok);
++                      feature = ast_find_feature(tok);
+                       
+                       if (feature) {
+                               /* Feature is up for consideration */
+@@ -1064,7 +1142,7 @@
+                       /* while we have a feature */
+                       while (NULL != (tok = strsep(&tmp, "#"))) {
+-                              if ((feature = find_feature(tok))) {
++                              if ((feature = ast_find_feature(tok))) {
+                                       if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
+                                               if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
+                                                       ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
+@@ -1089,7 +1167,7 @@
+       struct ast_frame *f = NULL;
+       int res = 0, ready = 0;
+       
+-      if ((chan = ast_request(type, format, data, &cause))) {
++      if ((chan = ast_request(type, format, data, &cause, NULL))) {
+               ast_set_callerid(chan, cid_num, cid_name, cid_num);
+               ast_channel_inherit_variables(caller, chan);    
+               if (!ast_call(chan, data, timeout)) {
+@@ -1538,9 +1616,10 @@
+                                       "Channel: %s\r\n"
+                                       "CallerID: %s\r\n"
+                                       "CallerIDName: %s\r\n"
++                                      "Uniqueid: %s\r\n\r\n"
+                                       ,pu->parkingnum, pu->chan->name
+                                       ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-                                      ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++                                      ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+                                       );
+                               if (option_verbose > 1) 
+@@ -1583,9 +1662,10 @@
+                                                               "Channel: %s\r\n"
+                                                               "CallerID: %s\r\n"
+                                                               "CallerIDName: %s\r\n"
++                                                              "Uniqueid: %s\r\n\r\n"
+                                                               ,pu->parkingnum, pu->chan->name
+                                                               ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-                                                              ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++                                                              ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+                                                               );
+                                                       /* There's a problem, hang them up*/
+@@ -1672,6 +1752,280 @@
+       return res;
+ }
++int ast_hold_call(struct ast_channel *chan, struct ast_channel *peer)
++{
++      /* We put the user in the parking list, then wake up the parking thread to be sure it looks
++         after these channels too */
++      struct holdeduser *pu;
++      pu = malloc(sizeof(struct holdeduser));
++      if (pu) {
++              memset(pu, 0, sizeof(pu));
++              ast_mutex_lock(&holding_lock);
++              chan->appl = "Holded Call";
++              chan->data = NULL; 
++
++              pu->chan = chan;
++              strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
++              strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
++              /* Start music on hold */
++              ast_moh_start(pu->chan, NULL);
++              gettimeofday(&pu->start, NULL);
++              pu->next = holdlist;
++              holdlist = pu;
++              ast_mutex_unlock(&holding_lock);
++              /* Wake up the (presumably select()ing) thread */
++              pthread_kill(holding_thread, SIGURG);
++
++              manager_event(EVENT_FLAG_CALL, "HoldedCall",
++                            "Channel1: %s\r\n"
++                            "Channel2: %s\r\n"
++                          "Uniqueid1: %s\r\n"
++                          "Uniqueid2: %s\r\n"
++                            ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
++
++      } else {
++              ast_log(LOG_WARNING, "Out of memory\n");
++              return -1;
++      }
++      return 0;
++}
++
++int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer)
++{
++      struct ast_channel *chan;
++      struct ast_frame *f;
++      /* Make a new, fake channel that we'll use to masquerade in the real one */
++      chan = ast_channel_alloc(0);
++      if (chan) {
++              /* Let us keep track of the channel name */
++              snprintf(chan->name, sizeof (chan->name), "Onhold/%s",rchan->name);
++              /* Make formats okay */
++              chan->readformat = rchan->readformat;
++              chan->writeformat = rchan->writeformat;
++              ast_channel_masquerade(chan, rchan);
++              /* Setup the extensions and such */
++              strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
++              strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
++              chan->priority = rchan->priority;
++              /* this might be dirty, but we need to preserve the uniqueid */
++              strncpy(chan->uniqueid, rchan->uniqueid, sizeof(chan->uniqueid) - 1);
++              /* Make the masq execute */
++              f = ast_read(chan);
++              if (f)
++                      ast_frfree(f);
++              ast_hold_call(chan, peer);
++              return -1;
++      } else {
++              ast_log(LOG_WARNING, "Unable to create holded channel\n");
++              return -1;
++      }
++      return 0;
++}
++
++int ast_retrieve_call(struct ast_channel *chan, char *uniqueid)
++{
++      int res=-1, dres=-1;
++      struct ast_channel *peer=NULL;
++      struct ast_bridge_config config;
++
++      peer = ast_get_holded_call(uniqueid);
++
++      /* JK02: it helps to answer the channel if not already up */
++      if (chan->_state != AST_STATE_UP) {
++              ast_answer(chan);
++      }
++
++      if (peer) {
++              ast_mutex_unlock(&peer->lock);
++              ast_moh_stop(peer);
++              res = ast_channel_make_compatible(chan, peer);
++              if (res < 0) {
++                      ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
++                      ast_hangup(peer);
++                      return -1;
++              }
++              /* This runs sorta backwards, since we give the incoming channel control, as if it
++                 were the person called. */
++              if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
++
++              memset(&config,0,sizeof(struct ast_bridge_config));
++              ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
++              ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
++              config.timelimit = 0;
++              config.play_warning = 0;
++              config.warning_freq = 0;
++              config.warning_sound=NULL;
++              res = ast_bridge_call(chan,peer,&config);
++
++              /* Simulate the PBX hanging up */
++              if (res != AST_PBX_NO_HANGUP_PEER)
++                      ast_hangup(peer);
++              return res;
++      } else {
++              /* XXX Play a message XXX */
++        dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
++        if (!dres)
++          dres = ast_waitstream(chan, "");
++        else {
++          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
++          dres = 0;
++        }
++      }
++      return res;
++}
++
++int ast_retrieve_call_to_death(char *uniqueid)
++{
++      int res=-1;
++      struct ast_channel *peer=NULL;
++
++      peer = ast_get_holded_call(uniqueid);
++
++      if (peer) {
++              res=0;
++              if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
++              ast_mutex_unlock(&peer->lock);
++              ast_hangup(peer);
++      } else {
++              ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
++      }
++      return res;
++}
++
++struct ast_channel *ast_get_holded_call(char *uniqueid)
++{
++      int res=-1;
++      struct ast_channel *peer=NULL;
++      struct holdeduser *pu, *pl=NULL;
++
++      ast_mutex_lock(&holding_lock);
++      pu = holdlist;
++      while(pu) {
++              if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
++                      if (pl)
++                              pl->next = pu->next;
++                      else
++                              holdlist = pu->next; 
++                      break;
++              }
++              pl = pu;
++              pu = pu->next;
++      }
++      ast_mutex_unlock(&holding_lock);
++      if (pu) {
++              peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
++              free(pu);
++              if (peer) {
++                  res=0;
++                  if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
++                  ast_moh_stop(peer);
++                  return peer;
++              } else {
++                  if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
++                  return NULL;
++              }
++      } else {
++              ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
++      }
++      return NULL;
++}
++
++/* this is our autmagically service thread that keeps channels onhold happy */
++static void *do_holding_thread(void *ignore)
++{
++      int ms, tms, max;
++      struct holdeduser *pu, *pl, *pt = NULL;
++      struct timeval tv;
++      struct ast_frame *f;
++      int x;
++      fd_set rfds, efds;
++      fd_set nrfds, nefds;
++      FD_ZERO(&rfds);
++      FD_ZERO(&efds);
++      for (;;) {
++              ms = -1;
++              max = -1;
++              ast_mutex_lock(&holding_lock);
++              pl = NULL;
++              pu = holdlist;
++              gettimeofday(&tv, NULL);
++              FD_ZERO(&nrfds);
++              FD_ZERO(&nefds);
++              while(pu) {
++                      tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
++                              for (x=0;x<AST_MAX_FDS;x++) {
++                                      if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
++                              /*              if (FD_ISSET(pu->chan->fds[x], &efds))
++                                                      pu->chan->exception = 1; */
++                                              pu->chan->fdno = x;
++                                              /* See if they need servicing */
++                                              f = ast_read(pu->chan);
++                                              if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
++                                                      /* There's a problem, hang them up*/
++                                                      if (option_verbose > 1) 
++                                                              ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
++                                                      ast_hangup(pu->chan);
++                                                      /* find the corresponding channel and hang them up too! */
++                                                      /* but only if it is not bridged yet! */
++                                                      /* And take them out of the parking lot */
++                                                      if (pl) 
++                                                              pl->next = pu->next;
++                                                      else
++                                                              holdlist = pu->next;
++                                                      pt = pu;
++                                                      pu = pu->next;
++                                                      free(pt);
++                                                      break;
++                                              } else {
++                                                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
++                                                      ast_frfree(f);
++                                                      goto std;       /* XXX Ick: jumping into an else statement??? XXX */
++                                              }
++                                      }
++                              }
++                              if (x >= AST_MAX_FDS) {
++std:                                  for (x=0;x<AST_MAX_FDS;x++) {
++                                              /* Keep this one for next one */
++                                              if (pu->chan->fds[x] > -1) {
++                                                      FD_SET(pu->chan->fds[x], &nrfds);
++                                                      FD_SET(pu->chan->fds[x], &nefds);
++                                                      if (pu->chan->fds[x] > max)
++                                                              max = pu->chan->fds[x];
++                                              }
++                                      }
++                                      /* Keep track of our longest wait */
++                                      if ((tms < ms) || (ms < 0))
++                                              ms = tms;
++                                      pl = pu;
++                                      pu = pu->next;
++                              }
++              }
++              ast_mutex_unlock(&holding_lock);
++              rfds = nrfds;
++              efds = nefds;
++              tv.tv_sec = ms / 1000;
++              tv.tv_usec = (ms % 1000) * 1000;
++              /* Wait for something to happen */
++              ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
++              pthread_testcancel();
++      }
++      return NULL;    /* Never reached */
++}
++
++static int retrieve_call_exec(struct ast_channel *chan, void *data) {
++      int res=0;
++      struct localuser *u;
++      char *uniqueid = (char *)data;
++      LOCAL_USER_ADD(u);
++          res = ast_retrieve_call(chan, uniqueid);
++      LOCAL_USER_REMOVE(u);
++      return res;
++}
++
+ static int park_exec(struct ast_channel *chan, void *data)
+ {
+       int res=0;
+@@ -1720,9 +2074,10 @@
+                       "From: %s\r\n"
+                       "CallerID: %s\r\n"
+                       "CallerIDName: %s\r\n"
++                      "Uniqueid: %s\r\n\r\n"
+                       ,pu->parkingnum, pu->chan->name, chan->name
+                       ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
+-                      ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
++                      ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>"), pu->chan->uniqueid
+                       );
+               free(pu);
+@@ -1890,12 +2245,13 @@
+                       "Timeout: %ld\r\n"
+                       "CallerID: %s\r\n"
+                       "CallerIDName: %s\r\n"
++                      "Uniqueid: %s\r\n"
+                       "%s"
+                       "\r\n"
+                         ,cur->parkingnum, cur->chan->name
+                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
+                       ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
+-                      ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
++                      ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : ""), cur->chan->uniqueid
+                       ,idText);
+             cur = cur->next;
+@@ -1911,6 +2267,386 @@
+         return RESULT_SUCCESS;
+ }
++static int handle_autoanswer(int fd, int argc, char *argv[])
++{
++      struct aauser *cur;
++
++      ast_cli(fd, "%25s %10s %15s \n", "Channel"
++              , "Extension", "Context");
++
++      ast_mutex_lock(&autoanswer_lock);
++
++      cur=aalot;
++      while(cur) {
++              ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
++
++              cur = cur->next;
++      }
++
++      ast_mutex_unlock(&autoanswer_lock);
++
++      return RESULT_SUCCESS;
++}
++static char showautoanswer_help[] =
++"Usage: show autoanswer\n"
++"       Lists currently logged in autoanswr channels.\n";
++
++static struct ast_cli_entry showautoanswer =
++{ { "show", "autoanswer", NULL }, handle_autoanswer, "Lists autoanswer channels", showautoanswer_help };
++
++int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data)
++{
++      struct ast_channel *chan;
++      struct ast_frame *f;
++      /* Make a new, fake channel that we'll use to masquerade in the real one */
++      chan = ast_channel_alloc(0);
++      if (chan) {
++              /* Let us keep track of the channel name */
++              snprintf(chan->name, sizeof (chan->name), "Autoanswer/%s",rchan->name);
++              /* Make formats okay */
++              chan->readformat = rchan->readformat;
++              chan->writeformat = rchan->writeformat;
++              ast_channel_masquerade(chan, rchan);
++              /* Setup the extensions and such */
++              strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
++              strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
++              chan->priority = rchan->priority;
++              /* Make the masq execute */
++              f = ast_read(chan);
++              if (f)
++                      ast_frfree(f);
++              ast_autoanswer_login(chan, data);
++      } else {
++              ast_log(LOG_WARNING, "Unable to create aa channel\n");
++              return -1;
++      }
++      return 0;
++}
++
++static int autoanswer_login_exec(struct ast_channel *chan, void *data)
++{
++      int res=0;
++      struct localuser *u;
++      LOCAL_USER_ADD(u);
++      if (!data) {
++              ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
++              return -1;
++      }
++      res = ast_masq_autoanswer_login(chan, data);
++      LOCAL_USER_REMOVE(u);
++      return res; 
++}
++
++int ast_autoanswer_login(struct ast_channel *chan, void *data)
++{
++      /* We put the user in the parking list, then wake up the parking thread to be sure it looks
++         after these channels too */
++      struct ast_context *con;
++      char exten[AST_MAX_EXTENSION];
++      struct aauser *pu,*pl = NULL;
++      char *s, *stringp, *aacontext, *aaexten = NULL;
++
++      s = ast_strdupa((void *) data);
++      stringp=s;
++      aacontext = strsep(&stringp, "|");
++      aaexten = strsep(&stringp, "|");
++      if (!aaexten) {
++          aaexten = aacontext;
++          aacontext = NULL;
++      }
++      if (!aaexten) {
++              ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
++              return -1;
++      } else {
++              if (!aacontext) {
++                      aacontext = "default";
++              }
++      }
++
++      ast_mutex_lock(&autoanswer_lock);
++      pu = aalot;
++      while(pu) {
++              if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
++                      if (pl)
++                              pl->next = pu->next;
++                      else
++                              aalot = pu->next;
++                      break;
++              }
++              pl = pu;
++              pu = pu->next;
++      }
++      ast_mutex_unlock(&autoanswer_lock);
++      if (pu) {
++          ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
++          manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
++                                          "Channel: %s\r\n"
++                                          "Uniqueid: %s\r\n"
++                                          "Context: %s\r\n"
++                                          "Exten: %s\r\n"
++                                      ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++          ast_hangup(pu->chan);
++          free(pu);
++      }
++      pu = malloc(sizeof(struct aauser));
++      if (pu) {
++              memset(pu, 0, sizeof(pu));
++              ast_mutex_lock(&autoanswer_lock);
++              chan->appl = "Autoanswer";
++              chan->data = NULL; 
++
++              pu->chan = chan;
++              if (chan->_state != AST_STATE_UP) {
++                  ast_answer(chan);
++              }
++
++              /* Start music on hold */
++              ast_moh_start(pu->chan, NULL);
++              gettimeofday(&pu->start, NULL);
++              strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
++              strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
++              pu->next = aalot;
++              aalot = pu;
++              con = ast_context_find(aacontext);
++              if (!con) {
++                      con = ast_context_create(NULL,aacontext, registrar);
++                      if (!con) {
++                              ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
++                      }
++              }
++              if (con) {
++                      snprintf(exten, sizeof(exten), "%s", aaexten);
++                      ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
++              }
++
++              ast_mutex_unlock(&autoanswer_lock);
++              /* Wake up the (presumably select()ing) thread */
++              pthread_kill(autoanswer_thread, SIGURG);
++              if (option_verbose > 1) 
++                      ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
++                      manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
++                                "Channel: %s\r\n"
++                                "Uniqueid: %s\r\n"
++                              "Context: %s\r\n"
++                              "Exten: %s\r\n"
++                              ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++
++                      return 0;
++      } else {
++              ast_log(LOG_WARNING, "Out of memory\n");
++              return -1;
++      }
++      return 0;
++}
++
++static void *do_autoanswer_thread(void *ignore)
++{
++      int ms, tms, max;
++      struct ast_context *con;
++      char exten[AST_MAX_EXTENSION];
++      struct aauser *pu, *pl, *pt = NULL;
++      struct timeval tv;
++      struct ast_frame *f;
++      int x;
++      fd_set rfds, efds;
++      fd_set nrfds, nefds;
++      FD_ZERO(&rfds);
++      FD_ZERO(&efds);
++      for (;;) {
++              ms = -1;
++              max = -1;
++              ast_mutex_lock(&autoanswer_lock);
++              pl = NULL;
++              pu = aalot;
++              gettimeofday(&tv, NULL);
++              FD_ZERO(&nrfds);
++              FD_ZERO(&nefds);
++              while(pu) {
++                      tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
++                      for (x=0;x<AST_MAX_FDS;x++) {
++                              if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
++/*                                    if (FD_ISSET(pu->chan->fds[x], &efds))
++                                              pu->chan->exception = 1; */
++                                      pu->chan->fdno = x;
++                                      /* See if they need servicing */
++                                      f = ast_read(pu->chan);
++                                      if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
++                                              /* There's a problem, hang them up*/
++                                              if (option_verbose > 1) 
++                                                      ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
++                                              manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
++                                                  "Channel: %s\r\n"
++                                                  "Uniqueid: %s\r\n"
++                                                  "Context: %s\r\n"
++                                                  "Exten: %s\r\n"
++                                              ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
++                                              ast_hangup(pu->chan);
++                                              con = ast_context_find(pu->context);
++                                              if (con) {
++                                                  snprintf(exten, sizeof(exten), "%s", pu->exten);
++                                                  if (ast_context_remove_extension2(con, exten, 1, registrar))
++                                                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
++                                              } else {
++                                                      ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
++                                              }
++                                              /* And take them out of the parking lot */
++                                              if (pl) 
++                                                      pl->next = pu->next;
++                                              else
++                                                      aalot = pu->next;
++                                              pt = pu;
++                                              pu = pu->next;
++                                              free(pt);
++                                              break;
++                                      } else {
++                                              /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
++                                              ast_frfree(f);
++                                              goto std;       /* XXX Ick: jumping into an else statement??? XXX */
++                                      }
++                              }
++                      }
++                      if (x >= AST_MAX_FDS) {
++std:                          for (x=0;x<AST_MAX_FDS;x++) {
++                                      /* Keep this one for next one */
++                                      if (pu->chan->fds[x] > -1) {
++                                              FD_SET(pu->chan->fds[x], &nrfds);
++                                              FD_SET(pu->chan->fds[x], &nefds);
++                                              if (pu->chan->fds[x] > max)
++                                                      max = pu->chan->fds[x];
++                                      }
++                              }
++                              /* Keep track of our longest wait */
++                              if ((tms < ms) || (ms < 0))
++                                      ms = tms;
++                              pl = pu;
++                              pu = pu->next;
++                      }
++              }
++              ast_mutex_unlock(&autoanswer_lock);
++              rfds = nrfds;
++              efds = nefds;
++              tv.tv_sec = ms / 1000;
++              tv.tv_usec = (ms % 1000) * 1000;
++              /* Wait for something to happen */
++              ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
++              pthread_testcancel();
++      }
++      return NULL;    /* Never reached */
++}
++
++static int autoanswer_exec(struct ast_channel *chan, void *data)
++{
++      int res=0;
++      struct localuser *u;
++      struct ast_channel *peer=NULL;
++      struct aauser *pu, *pl=NULL;
++      struct ast_bridge_config config;
++      char *s, *stringp, *aacontext, *aaexten = NULL;
++      char datastring[80];
++
++      if (!data) {
++              ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
++              return -1;
++      }
++      s = ast_strdupa((void *) data);
++      stringp=s;
++      aacontext = strsep(&stringp, "|");
++      aaexten = strsep(&stringp, "|");
++      if (!aaexten) {
++          aaexten = aacontext;
++          aacontext = NULL;
++      }
++      if (!aaexten) {
++              ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
++              return -1;
++      } else {
++              if (!aacontext) {
++                      aacontext = "default";
++              }
++      }
++
++      LOCAL_USER_ADD(u);
++      ast_mutex_lock(&autoanswer_lock);
++      pu = aalot;
++      while(pu) {
++              if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
++                      if (pl)
++                              pl->next = pu->next;
++                      else
++                              aalot = pu->next;
++                      break;
++              }
++              pl = pu;
++              pu = pu->next;
++      }
++      ast_mutex_unlock(&autoanswer_lock);
++      if (pu) {
++              peer = pu->chan;
++              free(pu);
++              pu = NULL;
++      }
++      /* JK02: it helps to answer the channel if not already up */
++      if (chan->_state != AST_STATE_UP) {
++              ast_answer(chan);
++      }
++
++      if (peer) {
++              ast_moh_stop(peer);
++              /* Play a courtesy beep in the callED channel to prefix the bridge connecting */        
++              if (!ast_strlen_zero(courtesytone)) {
++                      if (!ast_streamfile(peer, courtesytone, peer->language)) {
++                              if (ast_waitstream(peer, "") < 0) {
++                                      ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
++                                      ast_hangup(peer);
++                                      return -1;
++                              }
++                      }
++              }
++ 
++              res = ast_channel_make_compatible(chan, peer);
++              if (res < 0) {
++                      ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
++                      ast_hangup(peer);
++                      return -1;
++              }
++              /* This runs sorta backwards, since we give the incoming channel control, as if it
++                 were the person called. */
++              if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered  %s\n", peer->name, chan->name);
++              manager_event(EVENT_FLAG_CALL, "Autoanswer",
++                    "Channel: %s\r\n"
++                    "Uniqueid: %s\r\n"
++                    "Channel2: %s\r\n"
++                    "Uniqueid2: %s\r\n"
++                    "Context: %s\r\n"
++                    "Exten: %s\r\n"
++                ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
++
++
++              memset(&config,0,sizeof(struct ast_bridge_config));
++              ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
++              ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
++              config.timelimit = 0;
++              config.play_warning = 0;
++              config.warning_freq = 0;
++              config.warning_sound=NULL;
++              res = ast_bridge_call(chan,peer,&config);
++
++              if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
++                      /* relogin */
++              snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
++              ast_autoanswer_login(peer, datastring);
++              return res;
++      } else {
++              if (option_verbose > 2) 
++                      ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
++              res = -1;
++      }
++      LOCAL_USER_REMOVE(u);
++      return res;
++}
++
+ int ast_pickup_call(struct ast_channel *chan)
+ {
+@@ -2064,7 +2800,7 @@
+                       }
+                       {
+-                              struct ast_call_feature *feature=find_feature(var->name);
++                              struct ast_call_feature *feature = ast_find_feature(var->name);
+                               int mallocd=0;
+                               
+                               if (!feature) {
+@@ -2140,14 +2876,22 @@
+       if ((res = load_config()))
+               return res;
+       ast_cli_register(&showparked);
++      ast_cli_register(&showautoanswer);
+       ast_cli_register(&showfeatures);
+       ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
++      ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL);
+       res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
+       if (!res)
+               res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
+       if (!res) {
+               ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
+       }
++      res = ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
++      ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
++      if (!res)
++              res = ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
++      if (!res)
++              res = ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4);
+       return res;
+ }
+@@ -2158,7 +2902,11 @@
+       ast_manager_unregister("ParkedCalls");
+       ast_cli_unregister(&showfeatures);
++      ast_cli_unregister(&showautoanswer);
+       ast_cli_unregister(&showparked);
++      ast_unregister_application(autoanswer);
++      ast_unregister_application(autoanswerlogin);
++      ast_unregister_application(holdedcall);
+       ast_unregister_application(parkcall);
+       return ast_unregister_application(parkedcall);
+ }
+diff -urN asterisk-1.2.4.orig/res/res_watchdog.c asterisk-1.2.4/res/res_watchdog.c
+--- asterisk-1.2.4.orig/res/res_watchdog.c     1970-01-01 01:00:00.000000000 +0100
++++ asterisk-1.2.4/res/res_watchdog.c  2006-01-31 09:41:43.000000000 +0100
+@@ -0,0 +1,148 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Resource to make watchdogs happy
++ *
++ * Copyright (C) 2005, Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++#include <stdlib.h>
++#include <errno.h>
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/time.h>
++#include <sys/signal.h>
++#include <netinet/in.h>
++#include <asterisk/lock.h>
++#include <asterisk/file.h>
++#include <asterisk/logger.h>
++#include <asterisk/channel.h>
++#include <asterisk/pbx.h>
++#include <asterisk/options.h>
++#include <asterisk/module.h>
++#include <asterisk/translate.h>
++#include <asterisk/say.h>
++#include <asterisk/features.h>
++#include <asterisk/musiconhold.h>
++#include <asterisk/config.h>
++#include <asterisk/cli.h>
++#include <asterisk/manager.h>
++#include <asterisk/utils.h>
++#include <asterisk/adsi.h>
++
++static struct watchdog_pvt *watchdogs = NULL;
++
++STANDARD_LOCAL_USER;
++
++LOCAL_USER_DECL;
++
++typedef struct watchdog_pvt {
++    char device[80];
++    int fd;
++    int type;
++    int interval;
++    pthread_t watchdog_thread;
++    struct watchdog_pvt *next;
++} watchdog_pvt;
++
++static void *do_watchdog_thread(void *data) {
++    struct watchdog_pvt *woof = (struct watchdog_pvt *)data;
++    for (;;) {
++      if (woof->fd) {
++          write(woof->fd, "PING\n", 1);
++      }
++      usleep(woof->interval * 1000);
++    }
++    return NULL;
++}
++
++
++int load_module(void)
++{
++      int res = 0;
++      char *cat, *utype, *udevice, *uinterval;
++      struct ast_config *cfg;
++      struct watchdog_pvt *woof = NULL;
++
++      cfg = ast_config_load("watchdog.conf");
++      if (cfg) {
++          cat = ast_category_browse(cfg, NULL);
++          while(cat) {
++              cat = ast_category_browse(cfg, cat);
++              utype = ast_variable_retrieve(cfg, cat, "type");
++              if (utype) {
++                  ast_log(LOG_NOTICE, "type = %s\n", utype);
++              }
++              udevice = ast_variable_retrieve(cfg, cat, "device");
++              if (udevice) {
++                  ast_log(LOG_NOTICE, "device = %s\n", udevice);
++              }
++              uinterval = ast_variable_retrieve(cfg, cat, "interval");
++              if (uinterval) {
++                  ast_log(LOG_NOTICE, "interval = %s\n", uinterval);
++              }
++              if (uinterval && udevice && utype) {
++                  woof = malloc(sizeof(struct watchdog_pvt));
++                  if (!woof) {
++                      ast_log(LOG_ERROR, "unable to malloc!\n");
++                      return -1;
++                  }
++                  memset(woof, 0x0, sizeof(struct watchdog_pvt));
++                  strncpy(woof->device, udevice, sizeof(woof->device) - 1);
++                  
++                  woof->interval = atoi(uinterval);;
++                  woof->next = watchdogs;
++                  watchdogs = woof;
++                  woof->fd = open(woof->device, O_WRONLY | O_SYNC);
++                  if (woof->fd) {
++                      if (!strncmp(utype, "isdnguard", sizeof(utype))) {
++                          woof->type = 1;
++                          write(woof->fd, "START\n", 6);
++                      }
++                      ast_pthread_create(&woof->watchdog_thread, NULL, do_watchdog_thread, woof);
++                  } else {
++                      ast_log(LOG_WARNING, "error opening watchdog device %s !\n", woof->device);
++                  }
++              }
++          }
++          ast_config_destroy(cfg);
++      }
++      return res;
++}
++
++
++int unload_module(void)
++{
++      struct watchdog_pvt *dogs, *woof;
++      STANDARD_HANGUP_LOCALUSERS;
++      dogs = watchdogs;
++      while (dogs) {
++          pthread_cancel(dogs->watchdog_thread);
++          woof = dogs->next;
++          free(dogs);
++          dogs = woof;
++      }
++      return 0;
++}
++
++char *description(void)
++{
++      return "Watchdog Resource";
++}
++
++int usecount(void)
++{
++      return 1;
++}
++
++char *key()
++{
++      return ASTERISK_GPL_KEY;
++}
+diff -urN asterisk-1.2.4.orig/rtp.c asterisk-1.2.4/rtp.c
+--- asterisk-1.2.4.orig/rtp.c  2005-11-30 15:27:59.000000000 +0100
++++ asterisk-1.2.4/rtp.c       2006-01-31 09:41:43.000000000 +0100
+@@ -442,6 +442,11 @@
+       struct rtpPayloadType rtpPT;
+       
+       len = sizeof(sin);
++
++      /* XXX SYMPTON CURE, DIRTY FIX, CHECK, BEGIN */
++      if (!rtp)
++          return &null_frame;
++      /* XXX SYMPTON CURE, DIRTY FIX, CHECK, END */
+       
+       /* Cache where the header will go */
+       res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
diff --git a/src/patches/asterisk-1.2.4-libpri-bristuff-0.3.0-PRE-1l.patch b/src/patches/asterisk-1.2.4-libpri-bristuff-0.3.0-PRE-1l.patch
new file mode 100644 (file)
index 0000000..a744964
--- /dev/null
@@ -0,0 +1,6200 @@
+diff -urN libpri-1.2.2.orig/Makefile libpri-1.2.2/Makefile
+--- libpri-1.2.2.orig/Makefile 2006-01-10 21:19:14.000000000 +0100
++++ libpri-1.2.2/Makefile      2006-01-18 12:28:07.000000000 +0100
+@@ -38,7 +38,7 @@
+ DYNAMIC_LIBRARY=libpri.so.1.0
+ STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o
+ DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo
+-CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g $(ALERTING) $(LIBPRI_COUNTERS)
++CFLAGS=-Wall -Wstrict-prototypes -Wmissing-prototypes -g $(ALERTING) $(LIBPRI_COUNTERS) -DRELAX_TRB
+ INSTALL_PREFIX?=
+ INSTALL_BASE=/usr
+ SOFLAGS = -Wl,-hlibpri.so.1.0
+diff -urN libpri-1.2.2.orig/README libpri-1.2.2/README
+--- libpri-1.2.2.orig/README   2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/README        2006-01-18 12:28:07.000000000 +0100
+@@ -1,6 +1,7 @@
+-libpri: An implementation of Primate Rate ISDN
+-
+-Written by Mark Spencer <markster@digium.com>
++libpri: An implementation of Primate Rate ISDN (and BRI ISDN)
++ 
++Written by Mark Spencer <markster@linux-support.net>
++Modified for BRI support by Klaus-Peter Junghanns <kpj@junghanns.net>
+ What is libpri?
+ ===============
+@@ -9,6 +10,7 @@
+ based on the Bellcore specification SR-NWT-002343 for National ISDN.  As of
+ May 12, 2001, it has been tested work with NI-2, Nortel DMS-100, and 
+ Lucent 5E Custom protocols on switches from Nortel and Lucent.
++The BRI and euroISDN modifications are based on ETS 300 102-1.
+ What is the license for libpri?
+ ===============================
+@@ -22,9 +24,8 @@
+ or the GPL of libpri.
+ If you wish to use libpri in an application for which the GPL is not 
+-appropriate (e.g. a proprietary embedded system), licenses for libpri 
+-under more flexible terms can be readily obtained through Digium, Inc. 
+-at reasonable cost.
++appropriate (e.g. a proprietary embedded system), then you have to use
++a non-standard compliant version without BRI support.
+ How do I report bugs or contribute?
+diff -urN libpri-1.2.2.orig/TODO libpri-1.2.2/TODO
+--- libpri-1.2.2.orig/TODO     2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/TODO  2006-01-18 12:28:07.000000000 +0100
+@@ -2,9 +2,7 @@
+ -- D-Channel Backup
+ -- Test against 4e
+-Q.921:
+--- Support unnumbered information frames
+-
+ Q.931:
+--- Locking Shift IE
+--- Implement the 11 missing Q.931 timers
++-- Locking Shift IE (you did that already, didnt you??)
++-- Implement the 10 missing Q.931 timers
++-- more facilities
+diff -urN libpri-1.2.2.orig/libpri.h libpri-1.2.2/libpri.h
+--- libpri-1.2.2.orig/libpri.h 2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/libpri.h      2006-01-18 12:28:07.000000000 +0100
+@@ -26,8 +26,12 @@
+ #define _LIBPRI_H
+ /* Node types */
+-#define PRI_NETWORK           1
++#define PRI_NETWORK           1       /* PTP modes, default for PRI */
+ #define PRI_CPE                       2
++#define BRI_NETWORK_PTMP      3       /* PTMP modes, default for BRI */
++#define BRI_CPE_PTMP          4       
++#define BRI_NETWORK           5       /* PTP modes */
++#define BRI_CPE                       6       
+ /* Debugging */
+ #define PRI_DEBUG_Q921_RAW            (1 << 0)        /* Show raw HDLC frames */
+@@ -76,6 +80,12 @@
+ #define PRI_EVENT_NOTIFY              16      /* Notification received */
+ #define PRI_EVENT_PROGRESS            17      /* When we get CALL_PROCEEDING or PROGRESS */
+ #define PRI_EVENT_KEYPAD_DIGIT                18      /* When we receive during ACTIVE state */
++#define PRI_EVENT_HOLD_REQ    19      /* R */
++#define PRI_EVENT_RETRIEVE_REQ  20
++#define PRI_EVENT_SUSPEND_REQ   21    /* park */
++#define PRI_EVENT_RESUME_REQ    22    /* unpark */
++#define PRI_EVENT_DISPLAY_RECEIVED    23
++#define PRI_EVENT_FACILITY    24      /* Facility */
+ /* Simple states */
+ #define PRI_STATE_DOWN                0
+@@ -250,11 +260,13 @@
+ #define PRI_NSF_ATT_MULTIQUEST         0xF0
+ #define PRI_NSF_CALL_REDIRECTION_SERVICE       0xF7
++typedef struct q921_call q921_call;
+ typedef struct q931_call q931_call;
+ typedef struct pri_event_generic {
+       /* Events with no additional information fall in this category */
+       int e;
++      int tei;
+ } pri_event_generic;
+ typedef struct pri_event_error {
+@@ -273,18 +285,19 @@
+       int cref;
+       int progress;
+       int progressmask;
+-      q931_call *call;
+       char useruserinfo[260];         /* User->User info */
++      q931_call *call;
+ } pri_event_ringing;
+ typedef struct pri_event_answer {
+       int e;
+       int channel;
++      int tei;                                /* belongs to this tei */
+       int cref;
+       int progress;
+       int progressmask;
+-      q931_call *call;
+       char useruserinfo[260];         /* User->User info */
++      q931_call *call;
+ } pri_event_answer;
+ typedef struct pri_event_facname {
+@@ -302,26 +315,29 @@
+       int e;
+       int channel;                            /* Channel requested */
+       int callingpres;                        /* Presentation of Calling CallerID */
+-      int callingplanani;                     /* Dialing plan of Calling entity ANI */
++      int callingpresuser;                    /* Presentation of Calling CallerID */
+       int callingplan;                        /* Dialing plan of Calling entity */
+-      char callingani[256];           /* Calling ANI */
+-      char callingnum[256];           /* Calling number */
++      int callingplanuser;                    /* Dialing plan of Calling entity */
++      int callingplanani;                     /* Dialing plan of Calling entity ANI */
++      char callingnum[256];           /* Calling number, network provided */
++      char callingani[256];           /* Calling number, user provided */
+       char callingname[256];          /* Calling name (if provided) */
+       int calledplan;                         /* Dialing plan of Called number */
+       int ani2;                   /* ANI II */
+       char callednum[256];            /* Called number */
+-      char redirectingnum[256];       /* Redirecting number */
+-      char redirectingname[256];      /* Redirecting name */
+-      int redirectingreason;          /* Reason for redirect */
++      char redirectingnum[256];               /* Redirecting number */
++      char redirectingname[256];              /* Redirecting name */
++      int redirectingreason;                  /* Reason for redirect */
+       int callingplanrdnis;                   /* Dialing plan of Redirecting Number */
+-      char useruserinfo[260];         /* User->User info */
++      char useruserinfo[260];                 /* User->User info */
+       int flexible;                           /* Are we flexible with our channel selection? */
+       int cref;                                       /* Call Reference Number */
+       int ctype;                                      /* Call type (see PRI_TRANS_CAP_* */
+-      int layer1;                                     /* User layer 1 */
++      int layer1;                             /* User layer 1 */
+       int complete;                           /* Have we seen "Complete" i.e. no more number? */
+       q931_call *call;                        /* Opaque call pointer */
+-      char callingsubaddr[256];       /* Calling parties subaddress */
++      int tei;                                /* belongs to this tei */
++      char callingsubaddr[256];               /* Calling parties subaddress */
+       int progress;
+       int progressmask;
+       char origcalledname[256];
+@@ -335,6 +351,8 @@
+       int channel;                            /* Channel requested */
+       int cause;
+       int cref;
++      int tei;
++      int inband_progress;
+       q931_call *call;                        /* Opaque call pointer */
+       long aoc_units;                         /* Advise of Charge number of charged units */
+       char useruserinfo[260];         /* User->User info */
+@@ -359,6 +377,7 @@
+ typedef struct pri_event_setup_ack {
+       int e;
+       int channel;
++      q931_call *call;                        /* Opaque call pointer */
+ } pri_event_setup_ack;
+ typedef struct pri_event_notify {
+@@ -374,20 +393,80 @@
+       char digits[64];
+ } pri_event_keypad_digit;
++typedef struct pri_event_hold_req {
++      int e;
++      int channel;
++      int cref;
++      int tei;
++      q931_call *call;
++} pri_event_hold_req;
++
++/* euroisdn faciltiy fun */
++typedef struct pri_event_facility_req {
++      int e;
++      int channel;
++      int cref;
++      int tei;
++      int operation;
++      char forwardnum[256];           /* Redirection destination */
++      q931_call *call;
++} pri_event_facility_req;
++
++typedef struct pri_event_retrieve_req {
++      int e;
++      int channel;
++      int cref;
++      int tei;
++      q931_call *call;
++} pri_event_retrieve_req;
++
++typedef struct pri_event_suspend_req {
++      int e;
++      int channel;
++      int cref;
++      int tei;
++      q931_call *call;
++      char callid[10];
++} pri_event_suspend_req;
++
++typedef struct pri_event_resume_req {
++      int e;
++      int channel;
++      int cref;
++      int tei;
++      q931_call *call;
++      char callid[10];
++} pri_event_resume_req;
++
++typedef struct pri_event_display {
++      int e;
++      int channel;            
++      int cref;                       
++      q931_call *call;
++      char text[256];
++} pri_event_display;
++
++
+ typedef union {
+       int e;
+       pri_event_generic gen;          /* Generic view */
+       pri_event_restart restart;      /* Restart view */
+       pri_event_error   err;          /* Error view */
+       pri_event_facname facname;      /* Caller*ID Name on Facility */
++      pri_event_facility_req facility;        /* sservices */
+       pri_event_ring    ring;         /* Ring */
+       pri_event_hangup  hangup;       /* Hang up */
+       pri_event_ringing ringing;      /* Ringing */
+-      pri_event_ringing answer;       /* Answer */
++      pri_event_answer  answer;       /* Answer */
+       pri_event_restart_ack restartack;       /* Restart Acknowledge */
+       pri_event_proceeding  proceeding;       /* Call proceeding & Progress */
+       pri_event_setup_ack   setup_ack;        /* SETUP_ACKNOWLEDGE structure */
+       pri_event_notify notify;                /* Notification */
++      pri_event_hold_req hold_req;
++      pri_event_retrieve_req retrieve_req;
++      pri_event_suspend_req suspend_req;
++      pri_event_resume_req resume_req;
++      pri_event_display display;
+       pri_event_keypad_digit digit;                   /* Digits that come during a call */
+ } pri_event;
+@@ -402,7 +481,9 @@
+    channel operating in HDLC mode with FCS computed by the fd's driver.  Also it
+    must be NON-BLOCKING! Frames received on the fd should include FCS.  Nodetype 
+    must be one of PRI_NETWORK or PRI_CPE.  switchtype should be PRI_SWITCH_* */
+-extern struct pri *pri_new(int fd, int nodetype, int switchtype);
++extern struct pri *pri_new(int fd, int nodetype, int switchtype, int span);
++
++extern void pri_shutdown(struct pri *pri);
+ /* Create D-channel just as above with user defined I/O callbacks and data */
+ extern struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata);
+@@ -426,6 +507,9 @@
+ /* Enable transmission support of Facility IEs on the pri */
+ extern void pri_facility_enable(struct pri *pri);
++/* Set file descriptor for debugging to a file */
++extern void pri_set_debug_fd(struct pri *pri, int fd);
++
+ /* Run PRI on the given D-channel, taking care of any events that
+    need to be handled.  If block is set, it will block until an event
+    occurs which needs to be handled */
+@@ -462,6 +546,12 @@
+ /* Send a digit in overlap mode */
+ extern int pri_information(struct pri *pri, q931_call *call, char digit);
++/* Send a INFO msg with display ie  */
++extern int pri_information_display(struct pri *pri, q931_call *call, char *display);
++
++/* add a display ie to a call, so it can be sent with the next message */
++extern int pri_add_display(struct pri *pri, q931_call *call, char *display);
++
+ /* Answer the incomplete(call without called number) call on the given channel.
+    Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+ extern int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
+@@ -470,6 +560,35 @@
+    Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+ extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
++extern int pri_deflect(struct pri *pri, q931_call *call, char *destination);
++
++/* Ack a HOLD_REQ */
++extern int pri_hold_acknowledge(struct pri *pri, q931_call *call);
++
++/* Reject a HOLD_REQ */
++extern int pri_hold_reject(struct pri *pri, q931_call *call);
++
++/* Ack a RETRIEVE_REQ */
++extern int pri_retrieve_acknowledge(struct pri *pri, q931_call *call, int channel);
++
++/* Reject a RETRIEVE_REQ */
++extern int pri_retrieve_reject(struct pri *pri, q931_call *call);
++
++/* Ack a SUSPEND_REQ */
++extern int pri_suspend_acknowledge(struct pri *pri, q931_call *call, char *display);
++
++/* Reject a SUSPEND_REQ */
++extern int pri_suspend_reject(struct pri *pri, q931_call *call, char *display);
++
++/* Reject a RESUME_REQ */
++extern int pri_resume_reject(struct pri *pri, q931_call *call, char *display);
++
++/* Ack a RESUME_REQ */
++extern int pri_resume_acknowledge(struct pri *pri, q931_call *call, int channel, char *display);
++
++/* Send a Facility Message */
++extern int pri_facility(struct pri *pri, q931_call *call, int operation, char *arguments);
++
+ /* Set CRV reference for GR-303 calls */
+@@ -525,7 +644,6 @@
+ #define PRI_USER_USER_TX
+ /* Set the user user field.  Warning!  don't send binary data accross this field */
+ extern void pri_sr_set_useruser(struct pri_sr *sr, char *userchars);
+-
+ extern void pri_call_set_useruser(q931_call *sr, char *userchars);
+ extern int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
+@@ -546,8 +664,8 @@
+ /* Override message and error stuff */
+ #define PRI_NEW_SET_API
+-extern void pri_set_message(void (*__pri_error)(struct pri *pri, char *));
+-extern void pri_set_error(void (*__pri_error)(struct pri *pri, char *));
++extern void pri_set_message(void (*__pri_error)(char *, int span));
++extern void pri_set_error(void (*__pri_error)(char *, int span));
+ /* Set overlap mode */
+ #define PRI_SET_OVERLAPDIAL
+diff -urN libpri-1.2.2.orig/pri.c libpri-1.2.2/pri.c
+--- libpri-1.2.2.orig/pri.c    2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri.c 2006-01-18 12:28:07.000000000 +0100
+@@ -1,24 +1,12 @@
+ /*
+  * libpri: An implementation of Primary Rate ISDN
+  *
+- * Written by Mark Spencer <markster@digium.com>
++ * Written by Mark Spencer <markster@linux-suppot.net>
+  *
+- * Copyright (C) 2001-2005, Digium
+- * All Rights Reserved.
++ * This program is confidential
+  *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- * 
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- * 
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
++ * Copyright (C) 2001, Linux Support Services, Inc.
++ * All Rights Reserved.
+  *
+  */
+@@ -48,6 +36,14 @@
+               return "Network";
+       case PRI_CPE:
+               return "CPE";
++      case BRI_NETWORK:
++              return "Network";
++      case BRI_CPE:
++              return "CPE";
++      case BRI_NETWORK_PTMP:
++              return "Network (PtMP)";
++      case BRI_CPE_PTMP:
++              return "CPE (PtMP)";
+       default:
+               return "Invalid value";
+       }
+@@ -187,7 +183,7 @@
+       return res;
+ }
+-static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata)
++static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int span)
+ {
+       struct pri *p;
+       p = malloc(sizeof(struct pri));
+@@ -207,6 +203,8 @@
+               p->master = master;
+               p->callpool = &p->localpool;
+               pri_default_timers(p, switchtype);
++              p->debugfd = -1;
++              p->span = span;
+ #ifdef LIBPRI_COUNTERS
+               p->q921_rxcount = 0;
+               p->q921_txcount = 0;
+@@ -217,7 +215,7 @@
+                       p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+                       p->sapi = Q921_SAPI_GR303_EOC;
+                       p->tei = Q921_TEI_GR303_EOC_OPS;
+-                      p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL);
++                      p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL, span);
+                       if (!p->subchannel) {
+                               free(p);
+                               p = NULL;
+@@ -226,7 +224,7 @@
+                       p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+                       p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
+                       p->tei = Q921_TEI_GR303_TMC_CALLPROC;
+-                      p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL);
++                      p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL, span);
+                       if (!p->subchannel) {
+                               free(p);
+                               p = NULL;
+@@ -242,7 +240,7 @@
+               }
+               /* Start Q.921 layer, Wait if we're the network */
+               if (p)
+-                      q921_start(p, p->localtype == PRI_CPE);
++                      q921_start(p, p->localtype == PRI_CPE, 0);
+       }
+       return p;
+ }
+@@ -262,15 +260,16 @@
+ {
+       /* Restart Q.921 layer */
+       if (pri) {
+-              q921_reset(pri);
+-              q921_start(pri, pri->localtype == PRI_CPE);     
++// XXX                q921_reset(pri);
++//            q921_start(pri, pri->localtype == PRI_CPE);     
+       }
+       return 0;
+ }
+-struct pri *pri_new(int fd, int nodetype, int switchtype)
++
++struct pri *pri_new(int fd, int nodetype, int switchtype, int span)
+ {
+-      return __pri_new(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL);
++      return __pri_new(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL, span);
+ }
+ struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata)
+@@ -279,7 +278,7 @@
+               io_read = __pri_read;
+       if (!io_write)
+               io_write = __pri_write;
+-      return __pri_new(fd, nodetype, switchtype, NULL, io_read, io_write, userdata);
++      return __pri_new(fd, nodetype, switchtype, NULL, io_read, io_write, userdata, -1);
+ }
+ void *pri_get_userdata(struct pri *pri)
+@@ -385,7 +384,7 @@
+ {
+       /* Return a configuration error */
+       pri->ev.err.e = PRI_EVENT_CONFIG_ERR;
+-      libpri_copy_string(pri->ev.err.err, errstr, sizeof(pri->ev.err.err));
++      strncpy(pri->ev.err.err, errstr, sizeof(pri->ev.err.err) - 1);
+       return &pri->ev;
+ }
+@@ -443,6 +442,15 @@
+       return;
+ }
++void pri_set_debug_fd(struct pri *pri, int fd)
++{
++      if (!pri)
++              return;
++      pri->debugfd = fd;
++      if (pri->subchannel)
++              pri_set_debug_fd(pri->subchannel, fd);
++}
++
+ int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info)
+ {
+       if (!pri || !call)
+@@ -478,6 +486,21 @@
+       return q931_notify(pri, call, channel, info);
+ }
++int pri_information_display(struct pri *pri, q931_call *call, char *display)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_information_display(pri, call, display);
++}
++
++int pri_add_display(struct pri *pri, q931_call *call, char *display)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_add_display(pri, call, display);
++}
++
++
+ void pri_destroycall(struct pri *pri, q931_call *call)
+ {
+       if (pri && call)
+@@ -499,6 +522,76 @@
+       return q931_connect(pri, call, channel, nonisdn);
+ }
++int pri_hold_acknowledge(struct pri *pri, q931_call *call)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_hold_acknowledge(pri, call);
++}
++
++int pri_hold_reject(struct pri *pri, q931_call *call)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_hold_reject(pri, call);
++}
++
++int pri_retrieve_acknowledge(struct pri *pri, q931_call *call, int channel)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_retrieve_acknowledge(pri, call, channel);
++}
++
++int pri_retrieve_reject(struct pri *pri, q931_call *call)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_retrieve_reject(pri, call);
++}
++
++int pri_suspend_acknowledge(struct pri *pri, q931_call *call, char *display)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_suspend_acknowledge(pri, call, display);
++}
++
++int pri_suspend_reject(struct pri *pri, q931_call *call, char *display)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_suspend_reject(pri, call, display);
++}
++
++int pri_resume_reject(struct pri *pri, q931_call *call, char *display)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_resume_reject(pri, call, display);
++}
++
++int pri_resume_acknowledge(struct pri *pri, q931_call *call, int channel, char *display)
++{
++      if (!pri || !call)
++              return -1;
++      return q931_resume_acknowledge(pri, call, channel, display);
++}
++
++int pri_facility(struct pri *pri, q931_call *call, int operation, char *arguments)
++{
++      if (!pri || !call)
++              return -1;
++//    return q931_facility(pri, call, operation, arguments);
++      return q931_facility(pri, call);
++}
++
++int pri_deflect(struct pri *pri, q931_call *call, char *destination)
++{
++    add_call_deflection_facility_ie(pri, call, destination);
++    return q931_facility(pri, call);
++}
++
+ #if 0
+ /* deprecated routines, use pri_hangup */
+ int pri_release(struct pri *pri, q931_call *call, int cause)
+@@ -543,12 +636,29 @@
+ int pri_hangup(struct pri *pri, q931_call *call, int cause)
+ {
++      int res=0;
+       if (!pri || !call)
+               return -1;
+       if (cause == -1)
+               /* normal clear cause */
+               cause = 16;
+-      return q931_hangup(pri, call, cause);
++      if ((cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81 || cause == 17) && (call->ourcallstate == Q931_CALL_STATE_ACTIVE)) {
++          pri_error(pri, "Cause code %d not allowed when disconnecting an active call. Changing to cause 16.\n", cause);
++          cause = 16;
++      }
++
++      if (pri->localtype == BRI_NETWORK_PTMP) {
++          res = q921_hangup(pri, call, 127);
++          if (res) {
++              // q921_setup might give a HANGUP_ACK, if nobody got the call
++              q931_hangup(pri, call, cause);
++              return res;
++          } else {
++              return q931_hangup(pri, call, cause);
++          }
++      } else {
++          return q931_hangup(pri, call, cause);
++      }
+ }
+ int pri_reset(struct pri *pri, int channel)
+@@ -688,15 +798,15 @@
+       return q931_setup(pri, c, &req);
+ }     
+-static void (*__pri_error)(struct pri *pri, char *stuff);
+-static void (*__pri_message)(struct pri *pri, char *stuff);
++static void (*__pri_error)(char *stuff,int span);
++static void (*__pri_message)(char *stuff,int span);
+-void pri_set_message(void (*func)(struct pri *pri, char *stuff))
++void pri_set_message(void (*func)(char *stuff,int span))
+ {
+       __pri_message = func;
+ }
+-void pri_set_error(void (*func)(struct pri *pri, char *stuff))
++void pri_set_error(void (*func)(char *stuff,int span))
+ {
+       __pri_error = func;
+ }
+@@ -708,10 +818,14 @@
+       va_start(ap, fmt);
+       vsnprintf(tmp, sizeof(tmp), fmt, ap);
+       va_end(ap);
+-      if (__pri_message)
+-              __pri_message(pri, tmp);
+-      else
+-              fputs(tmp, stdout);
++      if (__pri_message && pri) {
++          if (pri->debugfd >= 0)
++              write(pri->debugfd, tmp, strlen(tmp));
++          else
++              __pri_message(tmp, pri->span);
++      } else {
++          fputs(tmp, stdout);
++      }
+ }
+ void pri_error(struct pri *pri, char *fmt, ...)
+@@ -721,10 +835,14 @@
+       va_start(ap, fmt);
+       vsnprintf(tmp, sizeof(tmp), fmt, ap);
+       va_end(ap);
+-      if (__pri_error)
+-              __pri_error(pri, tmp);
+-      else
+-              fputs(tmp, stderr);
++      if (__pri_error && pri) {
++          if (pri->debugfd >= 0)
++              write(pri->debugfd, tmp, strlen(tmp));
++          else 
++              __pri_error(tmp, pri->span);
++      } else {
++          fputs(tmp, stderr);
++      }
+ }
+ /* Set overlap mode */
+@@ -765,11 +883,13 @@
+       }
+       len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding);
+ #endif
+-      len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window);
+-      len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej);
+-      len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit);
+-      len += sprintf(buf + len, "Retrans: %d\n", pri->retrans);
+-      len += sprintf(buf + len, "Busy: %d\n", pri->busy);
++      if (pri->localtype != BRI_NETWORK_PTMP) {
++          len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen[0], pri->window[0]);
++          len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej[0]);
++          len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit[0]);
++          len += sprintf(buf + len, "Retrans: %d\n", pri->retrans[0]);
++          len += sprintf(buf + len, "Busy: %d\n", pri->busy[0]);
++      }
+       len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial);
+       len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]);
+       len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]);
+@@ -778,6 +898,7 @@
+       len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]);
+       len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]);
++
+       return strdup(buf);
+ }
+@@ -851,3 +972,10 @@
+       sr->redirectingreason = reason;
+       return 0;
+ }
++
++void pri_shutdown(struct pri *pri)
++{
++    if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) {
++      q921_reset(pri, pri->tei, 1);
++    }
++}
+diff -urN libpri-1.2.2.orig/pri_facility.c libpri-1.2.2/pri_facility.c
+--- libpri-1.2.2.orig/pri_facility.c   2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri_facility.c        2006-01-19 11:55:21.000000000 +0100
+@@ -1,26 +1,13 @@
+-/*
+- * libpri: An implementation of Primary Rate ISDN
+- *
+- * Written by Matthew Fredrickson <creslin@digium.com>
+- *
+- * Copyright (C) 2004-2005, Digium
+- * All Rights Reserved.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- * 
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- * 
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+- *
+- */
++/* 
++   This file and it's contents are licensed under the terms and conditions
++   of the GNU Public License.  See http://www.gnu.org for details.
++   
++   Routines for dealing with facility messages and their respective
++   components (ROSE)
++
++   by Matthew Fredrickson <creslin@digium.com>
++   Copyright (C) 2004-2005 Digium, Inc
++*/
+ #include "compat.h"
+ #include "libpri.h"
+@@ -208,9 +195,9 @@
+       if (datalen > buflen) {
+               /* Truncate */
+               datalen = buflen;
++              memcpy(namebuf, comp->data, datalen);
+       }
+-      memcpy(namebuf, comp->data, datalen);
+-      return res + 2;
++      return res;
+ }
+ int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len)
+@@ -305,7 +292,7 @@
+                       return -1;
+               value->ton = ton;
+-              return res + 3;
++              return res + 2;
+       } while(0);
+       return -1;
+@@ -375,11 +362,10 @@
+                       pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type);
+                       return -1;
+               }
+-              ASN1_FIXUP_LEN(comp, res);
+               NEXT_COMPONENT(comp, i);
+               if(i < len)
+                       pri_message(pri, "!! not all information is handled from Address component\n");
+-              return res + 2;
++              return res;
+       }
+       while (0);
+@@ -389,7 +375,6 @@
+ static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
+ {
+       int i = 0;
+-      int size = 0;
+       struct rose_component *comp = NULL;
+       unsigned char *vdata = data;
+@@ -404,9 +389,7 @@
+               switch(comp->type) {
+               case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0):           /* [0] presentationAllowedNumber */
+                       value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+-                      size = rose_address_decode(pri, call, comp->data, comp->len, value);
+-                      ASN1_FIXUP_LEN(comp, size);
+-                      return size + 2;
++                      return rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+               case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1):              /* [1] IMPLICIT presentationRestricted */
+                       if (comp->len != 0) { /* must be NULL */
+                               pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
+@@ -423,9 +406,7 @@
+                       return 2;
+               case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):           /* [3] presentationRestrictedNumber */
+                       value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+-                      size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+-                      ASN1_FIXUP_LEN(comp, size);
+-                      return size + 2;
++                      return rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+               default:
+                       pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type);
+               }
+@@ -436,7 +417,7 @@
+       return -1;
+ }
+-static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
+ {
+       int i = 0;
+       int diversion_counter;
+@@ -445,21 +426,9 @@
+       struct addressingdataelements_presentednumberunscreened divertingnr;
+       struct addressingdataelements_presentednumberunscreened originalcallednr;
+       struct rose_component *comp = NULL;
+-      unsigned char *vdata = sequence->data;
++      unsigned char *vdata = data;
+       int res = 0;
+-      /* Data checks */
+-      if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+-              pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
+-              return -1;
+-      }
+-
+-      if (sequence->len == ASN1_LEN_INDEF) {
+-              len -= 4; /* For the 2 extra characters at the end
+-                           * and two characters of header */
+-      } else
+-              len -= 2;
+-
+       do {
+               /* diversionCounter stuff */
+               GET_COMPONENT(comp, i, vdata, len);
+@@ -477,20 +446,18 @@
+       
+               if(pri->debug & PRI_DEBUG_APDU)
+                       pri_message(pri, "    Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
+-              pri_message(NULL, "Length of message is %d\n", len);
+               for(; i < len; NEXT_COMPONENT(comp, i)) {
+                       GET_COMPONENT(comp, i, vdata, len);
+-                      switch(comp->type) {
+-                      case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
++                      switch(comp->type & ASN1_TYPE_MASK) {
++                      case ASN1_TAG_0:
+                               call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]);
+                               if (pri->debug & PRI_DEBUG_APDU)
+                                       pri_message(pri, "    Received reason for original redirection %d\n", call->origredirectingreason);
+                               break;
+-                      case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):
++                      case ASN1_TAG_1:                /* divertingnr: presentednumberunscreened */
+                               res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr);
+                               /* TODO: Fix indefinite length form hacks */
+-                              ASN1_FIXUP_LEN(comp, res);
+                               comp->len = res;
+                               if (res < 0)
+                                       return -1;
+@@ -499,64 +466,62 @@
+                                       pri_message(pri, "      ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
+                               }
+                               break;
+-                      case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):
++                      case ASN1_TAG_2:                /* originalCalledNr: PresentedNumberUnscreened */
+                               res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr);
+                               if (res < 0)
+                                       return -1;
+-                              ASN1_FIXUP_LEN(comp, res);
+                               comp->len = res;
+                               if (pri->debug & PRI_DEBUG_APDU) {
+                                       pri_message(pri, "    Received originalcallednr '%s'\n", originalcallednr.partyaddress);
+                                       pri_message(pri, "      ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
+                               }
+                               break;
+-                      case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):
+-                              res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
+-                              if (res < 0)
+-                                      return -1;
+-                              ASN1_FIXUP_LEN(comp, res);
+-                              comp->len = res;
++                      case ASN1_TAG_3:
++                              comp->len = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
+                               if (pri->debug & PRI_DEBUG_APDU)
+                                       pri_message(pri, "    Received RedirectingName '%s'\n", redirectingname);
+                               break;
+-                      case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):
+-                              res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
+-                              if (res < 0)
+-                                      return -1;
+-                              ASN1_FIXUP_LEN(comp, res);
+-                              comp->len = res;
++                      case ASN1_TAG_4:
++                              comp->len = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
+                               if (pri->debug & PRI_DEBUG_APDU)
+                                       pri_message(pri, "    Received Originally Called Name '%s'\n", origcalledname);
+                               break;
+                       default:
+-                              if (comp->type == 0 && comp->len == 0) {
+-                                      break; /* Found termination characters */
+-                              }
+                               pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
+                               return -1;
+                       }
+               }
++              if (i < len)
++                      return -1;      /* Aborted before */
+               if (divertingnr.pres >= 0) {
+                       call->redirectingplan = divertingnr.npi;
+                       call->redirectingpres = divertingnr.pres;
+                       call->redirectingreason = diversion_reason;
+-                      libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum));
++                      strncpy(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum)-1);
++                      call->redirectingnum[sizeof(call->redirectingnum)-1] = '\0';
+               }
+               if (originalcallednr.pres >= 0) {
+                       call->origcalledplan = originalcallednr.npi;
+                       call->origcalledpres = originalcallednr.pres;
+-                      libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum));
++                      strncpy(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum)-1);
++                      call->origcallednum[sizeof(call->origcallednum)-1] = '\0';
++              }
++              if (strlen(redirectingname) > 0) {
++                      strncpy(call->redirectingname, redirectingname, sizeof(call->redirectingname));
++                      call->redirectingname[sizeof(call->redirectingname)-1] = '\0';
++              }
++              if (strlen(origcalledname) > 0) {
++                      strncpy(call->origcalledname, origcalledname, sizeof(call->origcalledname));
++                      call->origcalledname[sizeof(call->origcalledname)-1] = '\0';
+               }
+-              libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname));
+-              libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname));
+               return 0;
+       }
+       while (0);
+       return -1;
+ }
+-                              
++
+ static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call)
+ {
+       int i = 0, j, compsp = 0;
+@@ -694,6 +659,64 @@
+       return 0;
+ }
++/* Call deflection */
++int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination) {
++    int i = 0, j, compsp = 0;
++    struct rose_component *comp, *compstk[10];
++    unsigned char buffer[256];
++
++    buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
++    /* invoke */
++    ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
++    ASN1_PUSH(compstk, compsp, comp);
++
++    ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++    ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_CALLDEFLECTION); 
++
++    /* Argument sequence */
++    ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
++    ASN1_PUSH(compstk, compsp, comp);
++
++    /* arg.Address */
++    ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
++    ASN1_PUSH(compstk, compsp, comp);
++    
++#ifndef CD_UNLIKE_IN_CAPI
++    /* arg.address.PartyNumber */
++
++    
++    j = asn1_string_encode((ASN1_CONTEXT_SPECIFIC|ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination));
++    if (j<0) return -1;
++    i += j;
++#else
++    /* using PublicPartyNumber instead */
++    ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE | ASN1_CONTEXT_SPECIFIC| ASN1_TAG_1), buffer, i);
++    ASN1_PUSH(compstk, compsp, comp);
++    /* ToN: unknown */
++    ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
++    j = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination));
++    if(j<0) return -1;
++    i += j;
++    /* close PublicPartyNumber */
++    ASN1_FIXUP(compstk, compsp, buffer, i);
++#endif
++
++    /* close Address */
++    ASN1_FIXUP(compstk, compsp, buffer, i);
++
++    /* add boolean */
++    ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0);
++
++    /* Fix length of stacked components */
++    while(compsp > 0) {
++        ASN1_FIXUP(compstk, compsp, buffer, i);
++    }
++    if (pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL))
++                     return -1;
++   
++        return 0;
++}
++
+ /* Sending callername information functions */
+ static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe)
+ {
+@@ -1132,6 +1155,7 @@
+       int operation_tag;
+       unsigned char *vdata = data;
+       struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
++      struct addressingdataelements_presentednumberunscreened value;
+       
+       do {
+               /* Invoke ID stuff */
+@@ -1148,13 +1172,15 @@
+               NEXT_COMPONENT(comp, i);
+               /* No argument - return with error */
+-              if (i >= len) 
++              if ((i >= len) && (operation_tag != ROSE_EXPLICIT_CALL_TRANSFER))
+                       return -1;
+-              /* Arguement Tag */
+-              GET_COMPONENT(comp, i, vdata, len);
+-              if (!comp->type)
+-                      return -1;
++              if (operation_tag != ROSE_EXPLICIT_CALL_TRANSFER) {
++                  /* Arguement Tag */
++                  GET_COMPONENT(comp, i, vdata, len);
++                  if (!comp->type)
++                      return -1;
++              }
+               if (pri->debug & PRI_DEBUG_APDU)
+                       pri_message(pri, "  [ Handling operation %d ]\n", operation_tag);
+@@ -1178,7 +1204,11 @@
+               case ROSE_DIVERTING_LEG_INFORMATION2:
+                       if (pri->debug & PRI_DEBUG_APDU)
+                               pri_message(pri, "  Handle DivertingLegInformation2\n");
+-                      return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
++                      if (comp->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
++                              pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
++                              return -1;
++                      }
++                      return rose_diverting_leg_information2_decode(pri, call, comp->data, comp->len);
+               case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
+                       if (pri->debug & PRI_DEBUG_APDU) {
+                               pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
+@@ -1229,6 +1259,34 @@
+                               dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+                       }
+                       return -1;
++              case ROSE_CALLDEFLECTION:
++              //      if (pri->debug & PRI_DEBUG_APDU) {
++                              pri_message(pri, "ROSE %i: CD - not handled!", operation_tag);
++                              dump_apdu (pri, comp->data, comp->len);
++                      rose_public_party_number_decode(pri, call, comp->data + 2 , comp->len - 2, &value);
++                      pri_message(pri, "party address %s\n", value.partyaddress);
++              //      }
++/*                GET_COMPONENT(comp, i, vdata, len);
++                  if (comp->type == ASN1_SEQUENCE | ASN1_CONSTRUCTOR | ASN1_TAG_0) {
++                      int j=0;
++                      for (j=0;j<comp->len;j++) {
++                          pri_error(pri, "comp->data %#x\n",comp->data[j]);
++                      }
++
++                      pri_error(pri, "c type %#x, c len %#x\n", comp->type, comp->len);
++                      if (comp->type == ASN1_SEQUENCE | ASN1_CONSTRUCTOR) {
++                          pri_error(pri, "c type %#x, c len %#x\n", comp->type, comp->len);
++                      } 
++                      
++                  }
++                  */
++                      return -1;
++              case ROSE_EXPLICIT_CALL_TRANSFER:
++                      call->facility = operation_tag;
++                      if (pri->debug & PRI_DEBUG_APDU) {
++                              pri_message(pri, "ROSE %i: received ECT execute!", operation_tag);
++                      }
++                      return 0;
+               default:
+                       if (pri->debug & PRI_DEBUG_APDU) {
+                               pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
+diff -urN libpri-1.2.2.orig/pri_facility.h libpri-1.2.2/pri_facility.h
+--- libpri-1.2.2.orig/pri_facility.h   2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri_facility.h        2006-01-19 11:51:18.000000000 +0100
+@@ -34,7 +34,7 @@
+ /* Operation ID values */
+ /* Q.952 ROSE operations (Diverting) */
+ #define ROSE_DIVERTING_LEG_INFORMATION1               18
+-#define ROSE_DIVERTING_LEG_INFORMATION2               0x15
++#define ROSE_DIVERTING_LEG_INFORMATION2               15
+ #define ROSE_DIVERTING_LEG_INFORMATION3               19
+ /* Q.956 ROSE operations (Advice Of Charge) */
+ #define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE   26
+@@ -48,11 +48,14 @@
+ #define ROSE_AOC_IDENTIFICATION_OF_CHARGE     37
+ /* Q.SIG operations */
+ #define SS_CNID_CALLINGNAME                                   0
+-#define SS_DIVERTING_LEG_INFORMATION2         21
++#define SS_DIVERTING_LEG_INFORMATION2         22
+ #define SS_MWI_ACTIVATE                                               80
+ #define SS_MWI_DEACTIVATE                                     81
+ #define SS_MWI_INTERROGATE                                    82
++#define ROSE_CALLDEFLECTION                   0x0D
++#define ROSE_EXPLICIT_CALL_TRANSFER           0x06
++
+ /* ROSE definitions and data structures */
+ #define INVOKE_IDENTIFIER                     0x02
+ #define INVOKE_LINKED_IDENTIFIER      0x80
+@@ -180,12 +183,6 @@
+                       (variable) = ((variable) << 8) | (component)->data[comp_idx]; \
+       } while (0)
+-#define ASN1_FIXUP_LEN(component, size) \
+-      do { \
+-              if ((component)->len == ASN1_LEN_INDEF) \
+-                      size += 2; \
+-      } while (0)
+-
+ #define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
+       do { \
+               (component) = (struct rose_component *)&((ptr)[(idx)]); \
+@@ -260,4 +257,6 @@
+ /* Adds the "standard" ADPUs to a call */
+ extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
++extern int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination);
++
+ #endif /* _PRI_FACILITY_H */
+diff -urN libpri-1.2.2.orig/pri_internal.h libpri-1.2.2/pri_internal.h
+--- libpri-1.2.2.orig/pri_internal.h   2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri_internal.h        2006-01-18 12:28:07.000000000 +0100
+@@ -30,7 +30,10 @@
+ struct pri_sched {
+       struct timeval when;
+       void (*callback)(void *data);
++      void (*callback2)(void *data, int);
+       void *data;
++      char hasdata2;
++      int data2;
+ };
+ struct q921_frame;
+@@ -38,8 +41,15 @@
+ enum q931_mode;
+ /* No more than 128 scheduled events */
++/* XXX is this sufficient for nfs ??? */
+ #define MAX_SCHED 128
++/* this can be freely configured to support more devices .... ok, 63 would be max! */
++#define Q921_MAX_TEIS 16
++
++/* dynamically allocated TEIs start here */
++#define Q921_TEI_BASE 64
++
+ #define MAX_TIMERS 32
+ struct pri {
+@@ -51,6 +61,7 @@
+       struct pri *master;             /* Master channel if appropriate */
+       struct pri_sched pri_sched[MAX_SCHED];  /* Scheduled events */
+       int debug;                      /* Debug stuff */
++      int debugfd;
+       int state;                      /* State of D-channel */
+       int switchtype;         /* Switch type */
+       int nsf;                /* Network-Specific Facility (if any) */
+@@ -62,25 +73,42 @@
+       int protodisc;
+       
+       /* Q.921 State */
+-      int q921_state; 
+-      int window;                     /* Max window size */
+-      int windowlen;          /* Fullness of window */
+-      int v_s;                        /* Next N(S) for transmission */
+-      int v_a;                        /* Last acknowledged frame */
+-      int v_r;                        /* Next frame expected to be received */
+-      int v_na;                       /* What we've told our peer we've acknowledged */
+-      int solicitfbit;        /* Have we sent an I or S frame with the F-bit set? */
+-      int retrans;            /* Retransmissions */
+-      int sentrej;            /* Are we in reject state */
+-      
++      int q921_state[Q921_MAX_TEIS];  
++      char dchanup;
++      
++      /* TEI registry */
++              char q921_teis[Q921_MAX_TEIS];
++
++              char q921_tei_check[Q921_MAX_TEIS];
++              unsigned short q921_tei_check_ri[Q921_MAX_TEIS];
++      
++      unsigned int ri; 
++  
++      int busy[Q921_MAX_TEIS];                        /* Peer is busy */
++   
++      int window[Q921_MAX_TEIS];                      /* Max window size */
++      int windowlen[Q921_MAX_TEIS];           /* Fullness of window */
++      int v_s[Q921_MAX_TEIS];                 /* Next N(S) for transmission */
++      int v_a[Q921_MAX_TEIS];                 /* Last acknowledged frame */
++      int v_r[Q921_MAX_TEIS];                 /* Next frame expected to be received */
++      int v_na[Q921_MAX_TEIS];                        /* What we've told our peer we've acknowledged */
++      int solicitfbit[Q921_MAX_TEIS]; /* Have we sent an I or S frame with the F-bit set? */
++      int retrans[Q921_MAX_TEIS];             /* Retransmissions */
++      int sabme_retrans[Q921_MAX_TEIS];               /* Retransmissions */
++  
++      int sentrej[Q921_MAX_TEIS];             /* Are we in reject state */
++      
++      /* Various timers */
++      int sabme_timer[Q921_MAX_TEIS];
++      int t203_timer[Q921_MAX_TEIS];
++      int t202_timer[Q921_MAX_TEIS];
++
++      int t201_timer[Q921_MAX_TEIS];
++      int t200_timer[Q921_MAX_TEIS];
++ 
++
+       int cref;                       /* Next call reference value */
+       
+-      int busy;                       /* Peer is busy */
+-
+-      /* Various timers */
+-      int sabme_timer;        /* SABME retransmit */
+-      int t203_timer;         /* Max idle time */
+-      int t200_timer;         /* T-200 retransmission timer */
+       /* All ISDN Timer values */
+       int timers[MAX_TIMERS];
+@@ -89,8 +117,8 @@
+       int schedev;
+       pri_event ev;           /* Static event thingy */
+       
+-      /* Q.921 Re-transmission queue */
+-      struct q921_frame *txqueue;
++      /* Q.921 (Re)transmission queue */
++      struct q921_frame *txqueue[Q921_MAX_TEIS];
+       
+       /* Q.931 calls */
+       q931_call **callpool;
+@@ -109,6 +137,9 @@
+       unsigned char last_invoke;      /* Last ROSE invoke ID */
+       unsigned char sendfacility;
++
++      int span; /* our fellow pri lives on this zaptel span */
++
+ };
+ struct pri_sr {
+@@ -118,6 +149,7 @@
+       int nonisdn;
+       char *caller;
+       int callerplan;
++      int callerplanani;
+       char *callername;
+       int callerpres;
+       char *called;
+@@ -167,8 +199,13 @@
+       
+       int alive;                      /* Whether or not the call is alive */
+       int acked;                      /* Whether setup has been acked or not */
++      int con_acked;                  /* Whether CONNECT has been CONNECT_ACKNOWLEDGEd or not */
+       int sendhangupack;      /* Whether or not to send a hangup ack */
+       int proc;                       /* Whether we've sent a call proceeding / alerting */
++      int alert;                      /* Whether we've sent an alerting */
++ 
++      int tei;
++      q921_call *phones;
+       
+       int ri;                         /* Restart Indicator (Restart Indicator IE) */
+@@ -202,15 +239,18 @@
+       int callerplan;
+       int callerplanani;
+       int callerpres;                 /* Caller presentation */
+-      char callerani[256];    /* Caller */
+-      char callernum[256];
++      int callerplanuser;
++      int callerpresuser;                     /* Caller presentation */
++      char callernum[256];    /* Calling Number (network provided) */
++      char callerani[256];    /* Calling Number, (user provided) */
++
+       char callername[256];
+-      char digitbuf[64];              /* Buffer for digits that come in KEYPAD_FACILITY */
++      char digitbuf[64];      /* Buffer for digits that come in KEYPAD_FACILITY */
+       int ani2;               /* ANI II */
+       
+-      int calledplan;
++      int  calledplan;
+       int nonisdn;
+       char callednum[256];    /* Called Number */
+       int complete;                   /* no more digits coming */
+@@ -225,16 +265,27 @@
+       char redirectingnum[256];       /* Number of redirecting party */
+       char redirectingname[256];      /* Name of redirecting party */
++      int t303timer;          
++      int t303running;                
++
+       /* Filled in cases of multiple diversions */
+       int origcalledplan;
+       int origcalledpres;
+-      int origredirectingreason;      /* Original reason for redirect (in cases of multiple redirects) */
++      int origredirectingreason;      /* Original reason for redirect (in cases of multiple redirects) */
+       char origcalledname[256];       /* Original name of person being called */
+-      char origcallednum[256];        /* Orignal number of person being called */
++      char origcallednum[256];                /* Orignal number of person being called */
+-      int useruserprotocoldisc;
++        int useruserprotocoldisc;
+       char useruserinfo[256];
+       char callingsubaddr[256];       /* Calling parties sub address */
++
++      char callid[10];        /* call identity for SUSPEND/RESUME */
++      char digits[256];       /* additional digits received via info msgs (cpn or keypad) */
++      char display[256];      /* display ie received in info msgs or for sending */
++ 
++      /* euroisdn facility fun */
++      int facility; /* FACILTIY received */
++      int aoc;
+       
+       long aoc_units;                         /* Advice of Charge Units */
+@@ -242,6 +293,7 @@
+ };
+ extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
++extern int pri_schedule_event2(struct pri *pri, int ms, void (*function)(void *data, int data2), void *data, int data2);
+ extern pri_event *pri_schedule_run(struct pri *pri);
+@@ -250,7 +302,7 @@
+ extern pri_event *pri_mkerror(struct pri *pri, char *errstr);
+ extern void pri_message(struct pri *pri, char *fmt, ...);
+-
++  
+ extern void pri_error(struct pri *pri, char *fmt, ...);
+ void libpri_copy_string(char *dst, const char *src, size_t size);
+diff -urN libpri-1.2.2.orig/pri_q921.h libpri-1.2.2/pri_q921.h
+--- libpri-1.2.2.orig/pri_q921.h       2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri_q921.h    2006-01-18 12:28:07.000000000 +0100
+@@ -47,6 +47,13 @@
+ #define Q921_FRAMETYPE_S      0x1
+ #define Q921_TEI_GROUP                                127
++#define Q921_TEI_ID_REQUEST   0x1
++#define Q921_TEI_ID_ASSIGNED  0x2
++#define Q921_TEI_ID_DENIED    0x3
++#define Q921_TEI_ID_CHK_REQ   0x4
++#define Q921_TEI_ID_CHK_RES   0x5
++#define Q921_TEI_ID_REMOVE    0x6
++#define Q921_TEI_ID_VERIFY    0x7
+ #define Q921_TEI_GR303_EOC_PATH                       0
+ #define Q921_TEI_GR303_EOC_OPS                        4
+ #define Q921_TEI_GR303_TMC_SWITCHING          0
+@@ -164,12 +171,14 @@
+ extern void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx);
+ /* Bring up the D-channel */
+-extern void q921_start(struct pri *pri, int now);
++extern void q921_start(struct pri *pri, int now, int tei);
+-extern void q921_reset(struct pri *pri);
++extern void q921_reset(struct pri *pri, int tei, int discard);
+ extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len);
+-extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
++extern int q921_transmit_uframe(struct pri *pri, void *buf, int len, int cr, int tei);
++
++extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr, int tei);
+ #endif
+diff -urN libpri-1.2.2.orig/pri_q931.h libpri-1.2.2/pri_q931.h
+--- libpri-1.2.2.orig/pri_q931.h       2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri_q931.h    2006-01-18 12:28:07.000000000 +0100
+@@ -190,6 +190,10 @@
+ #define Q931_IE_CODESET(x)            ((x) >> 8)
+ #define Q931_IE_IE(x)                 ((x) & 0xff)
+ #define Q931_FULL_IE(codeset, ie)     (((codeset) << 8) | ((ie) & 0xff))
++#define Q931_IE_MAX_LEN                       257
++
++// BRI+
++#define Q931_COLP     0x4c
+ #define Q931_DISPLAY                                  0x28
+ #define Q931_IE_SEGMENTED_MSG                 0x00
+@@ -218,6 +222,8 @@
+ #define Q931_IE_USER_USER                             0x7E
+ #define Q931_IE_ESCAPE_FOR_EXT                        0x7F
++#define Q931_IE_SPECIAL               0x02
++
+ /* Call state stuff */
+ #define Q931_CALL_STATE_NULL                          0
+@@ -243,7 +249,7 @@
+ /* EuroISDN  */
+ #define Q931_SENDING_COMPLETE         0xa1
+-extern int q931_receive(struct pri *pri, q931_h *h, int len);
++extern int q931_receive(struct pri *pri, q931_h *h, int len, int tei);
+ extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info);
+@@ -257,6 +263,10 @@
+ extern int q931_information(struct pri *pri, q931_call *call, char digit);
++extern int q931_information_display(struct pri *pri, q931_call *call, char *display);
++
++extern int q931_add_display(struct pri *pri, q931_call *call, char *display);
++
+ extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn);
+ extern int q931_release(struct pri *pri, q931_call *call, int cause);
+@@ -265,6 +275,10 @@
+ extern int q931_hangup(struct pri *pri, q931_call *call, int cause);
++extern int q921_hangup(struct pri *pri, q931_call *c, int tei);
++
++extern int q921_handle_hangup(struct pri *pri, q931_call *c, int tei);
++
+ extern int q931_restart(struct pri *pri, int channel);
+ extern int q931_facility(struct pri *pri, q931_call *call);
+@@ -279,5 +293,23 @@
+ extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
+ extern void __q931_destroycall(struct pri *pri, q931_call *c);
++ 
++extern int q931_hold_acknowledge(struct pri *pri, q931_call *c);
++
++extern int q931_hold_reject(struct pri *pri, q931_call *c);
++
++extern int q931_retrieve_acknowledge(struct pri *pri, q931_call *c, int channel);
+       
++extern int q931_retrieve_reject(struct pri *pri, q931_call *c);
++
++extern int q931_suspend_acknowledge(struct pri *pri, q931_call *c, char *display);
++
++extern int q931_suspend_reject(struct pri *pri, q931_call *c, char *display);
++
++extern int q931_resume_reject(struct pri *pri, q931_call *c, char *display);
++
++extern int q931_resume_acknowledge(struct pri *pri, q931_call *c, int channel, char *display);
++
++//extern int q931_facility(struct pri *pri, q931_call *c, int operation, char *arguments);
++
+ #endif
+diff -urN libpri-1.2.2.orig/pri_timers.h libpri-1.2.2/pri_timers.h
+--- libpri-1.2.2.orig/pri_timers.h     2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pri_timers.h  2006-01-18 12:28:07.000000000 +0100
+@@ -27,17 +27,17 @@
+ /* -1 means we dont currently support the timer/counter */
+ #define PRI_TIMERS_DEFAULT {  3,      /* N200 */ \
+-                              -1,     /* N201 */ \
+-                              -1,     /* N202 */ \
++                              260,    /* N201 */ \
++                              3,      /* N202 */ \
+                               7,      /* K */ \
+                               1000,   /* T200 */ \
+-                              -1,     /* T201 */ \
+-                              -1,     /* T202 */ \
++                              2000,   /* T201 */ \
++                              5000,   /* T202 */ \
+                               10000,  /* T203 */ \
+                               -1,     /* T300 */ \
+                               -1,     /* T301 */ \
+                               -1,     /* T302 */ \
+-                              -1,     /* T303 */ \
++                              4000,   /* T303 */ \
+                               -1,     /* T304 */ \
+                               30000,  /* T305 */ \
+                               -1,     /* T306 */ \
+diff -urN libpri-1.2.2.orig/pridump.c libpri-1.2.2/pridump.c
+--- libpri-1.2.2.orig/pridump.c        2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pridump.c     2006-01-18 12:28:07.000000000 +0100
+@@ -1,9 +1,9 @@
+ /*
+  * libpri: An implementation of Primary Rate ISDN
+  *
+- * Written by Mark Spencer <markster@digium.com>
++ * Written by Mark Spencer <markster@linux-support.net>
+  *
+- * Copyright (C) 2001-2005, Digium
++ * Copyright (C) 2001, Linux Support Services, Inc.
+  * All Rights Reserved.
+  *
+  * This program is free software; you can redistribute it and/or modify
+diff -urN libpri-1.2.2.orig/prisched.c libpri-1.2.2/prisched.c
+--- libpri-1.2.2.orig/prisched.c       2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/prisched.c    2006-01-18 12:28:07.000000000 +0100
+@@ -1,9 +1,9 @@
+ /*
+  * libpri: An implementation of Primary Rate ISDN
+  *
+- * Written by Mark Spencer <markster@digium.com>
++ * Written by Mark Spencer <markster@linux-support.net>
+  *
+- * Copyright (C) 2001-2005, Digium
++ * Copyright (C) 2001, Linux Support Services, Inc.
+  * All Rights Reserved.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -22,10 +22,9 @@
+  *
+  */
+-#include <stdio.h>
+-
+ #include "libpri.h"
+ #include "pri_internal.h"
++#include <stdio.h>
+ static int maxsched = 0;
+@@ -36,7 +35,7 @@
+       int x;
+       struct timeval tv;
+       for (x=1;x<MAX_SCHED;x++)
+-              if (!pri->pri_sched[x].callback)
++              if ((!pri->pri_sched[x].callback2) && (!pri->pri_sched[x].callback))
+                       break;
+       if (x == MAX_SCHED) {
+               pri_error(pri, "No more room in scheduler\n");
+@@ -53,7 +52,39 @@
+       }
+       pri->pri_sched[x].when = tv;
+       pri->pri_sched[x].callback = function;
++      pri->pri_sched[x].callback2 = NULL;
+       pri->pri_sched[x].data = data;
++      pri->pri_sched[x].hasdata2 = 0;
++      pri->pri_sched[x].data2 = 0;
++      return x;
++}
++
++int pri_schedule_event2(struct pri *pri, int ms, void (*function)(void *data, int data2), void *data, int data2)
++{
++      int x;
++      struct timeval tv;
++      for (x=1;x<MAX_SCHED;x++)
++              if ((!pri->pri_sched[x].callback2) && (!pri->pri_sched[x].callback))
++                      break;
++      if (x == MAX_SCHED) {
++              pri_error(pri, "No more room in scheduler\n");
++              return -1;
++      }
++      if (x > maxsched)
++              maxsched = x;
++      gettimeofday(&tv, NULL);
++      tv.tv_sec += ms / 1000;
++      tv.tv_usec += (ms % 1000) * 1000;
++      if (tv.tv_usec > 1000000) {
++              tv.tv_usec -= 1000000;
++              tv.tv_sec += 1;
++      }
++      pri->pri_sched[x].when = tv;
++      pri->pri_sched[x].callback = NULL;
++      pri->pri_sched[x].callback2 = function;
++      pri->pri_sched[x].data = data;
++      pri->pri_sched[x].hasdata2 = 1;
++      pri->pri_sched[x].data2 = data2;
+       return x;
+ }
+@@ -65,7 +96,7 @@
+       if (pri->subchannel)
+               closest = pri_schedule_next(pri->subchannel);
+       for (x=1;x<MAX_SCHED;x++) {
+-              if (pri->pri_sched[x].callback && 
++              if ((pri->pri_sched[x].callback || pri->pri_sched[x].callback2) && 
+                       (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) ||
+                               ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) && 
+                                (closest->tv_usec > pri->pri_sched[x].when.tv_usec))))
+@@ -76,26 +107,38 @@
+ static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv)
+ {
+-      int x;
+-      void (*callback)(void *);
+-      void *data;
++      int x;
++      void (*callback)(void *);
++      void (*callback2)(void *, int);
++      void *data;
++      int data2;
+       pri_event *e;
++
+       if (pri->subchannel) {
+               if ((e = __pri_schedule_run(pri->subchannel, tv))) {
+                       return e;
+               }
+       }
+       for (x=1;x<MAX_SCHED;x++) {
+-              if (pri->pri_sched[x].callback &&
++              if ((pri->pri_sched[x].callback || pri->pri_sched[x].callback2) &&
+                       ((pri->pri_sched[x].when.tv_sec < tv->tv_sec) ||
+                        ((pri->pri_sched[x].when.tv_sec == tv->tv_sec) &&
+                         (pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
+                               pri->schedev = 0;
+                               callback = pri->pri_sched[x].callback;
++                              callback2 = pri->pri_sched[x].callback2;
+                               data = pri->pri_sched[x].data;
++                              data2 = pri->pri_sched[x].data2;
+                               pri->pri_sched[x].callback = NULL;
++                              pri->pri_sched[x].callback2 = NULL;
+                               pri->pri_sched[x].data = NULL;
+-                              callback(data);
++                              pri->pri_sched[x].data2 = 0;
++                              if (pri->pri_sched[x].hasdata2 == 1) {
++                                  pri->pri_sched[x].hasdata2 = 0;
++                                  callback2(data, data2);
++                              } else {
++                                  callback(data);
++                              }
+             if (pri->schedev)
+                   return &pri->ev;
+           }
+@@ -116,4 +159,6 @@
+       if ((id >= MAX_SCHED) || (id < 0)) 
+               pri_error(pri, "Asked to delete sched id %d???\n", id);
+       pri->pri_sched[id].callback = NULL;
++      pri->pri_sched[id].callback2 = NULL;
+ }
++
+diff -urN libpri-1.2.2.orig/pritest.c libpri-1.2.2/pritest.c
+--- libpri-1.2.2.orig/pritest.c        2005-11-29 19:39:18.000000000 +0100
++++ libpri-1.2.2/pritest.c     2006-01-18 12:28:07.000000000 +0100
+@@ -1,9 +1,9 @@
+ /*
+  * libpri: An implementation of Primary Rate ISDN
+  *
+- * Written by Mark Spencer <markster@digium.com>
++ * Written by Mark Spencer <markster@linux-support.net>
+  *
+- * Copyright (C) 2001-2005, Digium
++ * Copyright (C) 2001, Linux Support Services, Inc.
+  * All Rights Reserved.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -51,8 +51,8 @@
+ #define PRI_DEF_NODETYPE      PRI_CPE
+ #define PRI_DEF_SWITCHTYPE    PRI_SWITCH_NI2
+-#define MAX_CHAN              32
+-#define       DCHANNEL_TIMESLOT       16
++#define MAX_CHAN              3
++#define       DCHANNEL_TIMESLOT       3
+ static int offset = 0;
+@@ -60,7 +60,7 @@
+ static void do_channel(ZAP *z)
+ {
+       /* This is the part that runs on a given channel */
+-      zap_playf(z, "raw.ulaw", 0);
++      zap_playf(z, "raw.alaw", 0);
+ }
+ struct pri_chan {
+@@ -76,6 +76,14 @@
+               return PRI_CPE;
+       if (!strcasecmp(node, "network"))
+               return PRI_NETWORK;
++      if (!strcasecmp(node, "bri_cpe_ptmp"))
++              return BRI_CPE_PTMP;
++      if (!strcasecmp(node, "bri_network_ptmp"))
++              return BRI_NETWORK_PTMP;
++      if (!strcasecmp(node, "bri_cpe"))
++              return BRI_CPE;
++      if (!strcasecmp(node, "bri_network"))
++              return BRI_NETWORK;
+       return -1;
+ }
+@@ -285,6 +293,10 @@
+               }
+               
+               break;
++      case PRI_EVENT_HANGUP_REQ:
++              printf("-- Hanging up channel %d\n", e->hangup.channel);
++              hangup_channel(e->hangup.channel);
++              break;
+       default:
+               fprintf(stderr, "--!! Unknown PRI event %d\n", e->e);
+       }
+diff -urN libpri-1.2.2.orig/q921.c libpri-1.2.2/q921.c
+--- libpri-1.2.2.orig/q921.c   2005-12-06 22:35:50.000000000 +0100
++++ libpri-1.2.2/q921.c        2006-01-18 12:28:07.000000000 +0100
+@@ -1,10 +1,12 @@
+ /*
+  * libpri: An implementation of Primary Rate ISDN
+  *
+- * Written by Mark Spencer <markster@digium.com>
++ * Written by Mark Spencer <markster@linux-support.net>
+  *
+- * Copyright (C) 2001-2005, Digium
++ * Copyright (C) 2001, Linux Support Services, Inc.
+  * All Rights Reserved.
++ * Copyright (C) 2003,2004,2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -21,7 +23,7 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+  *
+  */
+-
++ 
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -50,19 +52,23 @@
+       (hf).h.tei = (pri)->tei; \
+ } while(0)
+-static void reschedule_t203(struct pri *pri);
++static void reschedule_t203(struct pri *pri, int tei);
++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull);
+-static void q921_discard_retransmissions(struct pri *pri)
++static void q921_discard_retransmissions(struct pri *pri, int tei)
+ {
+       struct q921_frame *f, *p;
+-      f = pri->txqueue;
++      int teio = tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      
++      f = pri->txqueue[teio];
+       while(f) {
+-              p = f;
+-              f = f->next;
+-              /* Free frame */
+-              free(p);
++          p = f;
++          f = f->next;
++          /* Free frame */
++          free(p);
+       }
+-      pri->txqueue = NULL;
++        pri->txqueue[teio] = NULL;
+ }
+ static int q921_transmit(struct pri *pri, q921_h *h, int len) 
+@@ -88,11 +94,15 @@
+               pri_error(pri, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno));
+               return -1;
+       }
+-      reschedule_t203(pri);
++      if (pri->localtype == BRI_CPE_PTMP) {
++          reschedule_t203(pri, pri->tei);
++      } else if (h->h.tei != Q921_TEI_GROUP) {
++          reschedule_t203(pri, h->h.tei);
++      }
+       return 0;
+ }
+-static void q921_send_ua(struct pri *pri, int pfbit)
++static void q921_send_ua(struct pri *pri, int pfbit, int tei)
+ {
+       q921_h h;
+       Q921_INIT(pri, h);
+@@ -100,6 +110,7 @@
+       h.u.m2 = 0;             /* M2 = 0 */
+       h.u.p_f = pfbit;        /* Final bit on */
+       h.u.ft = Q921_FRAMETYPE_U;
++      h.h.tei = tei;
+       switch(pri->localtype) {
+       case PRI_NETWORK:
+               h.h.c_r = 0;
+@@ -107,6 +118,19 @@
+       case PRI_CPE:
+               h.h.c_r = 1;
+               break;
++      case BRI_NETWORK_PTMP:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE_PTMP:
++              h.h.tei = pri->tei;
++              h.h.c_r = 1;
++              break;
++      case BRI_NETWORK:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE:
++              h.h.c_r = 1;
++              break;
+       default:
+               pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
+               return;
+@@ -116,18 +140,359 @@
+       q921_transmit(pri, &h, 3);
+ }
+-static void q921_send_sabme_now(void *vpri);
++/*
++static void q921_send_disconnect(struct pri *pri, int pfbit, int tei) {
++      q921_h h;
++      Q921_INIT(pri, h);
++      h.u.m3 = 2;
++      h.u.m2 = 0;
++      h.u.p_f = pfbit;
++      h.u.ft = Q921_FRAMETYPE_U;
++      h.h.tei = tei;
++      switch(pri->localtype) {
++      case PRI_NETWORK:
++              h.h.c_r = 0;
++              break;
++      case PRI_CPE:
++              h.h.c_r = 1;
++              break;
++      case BRI_NETWORK_PTMP:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE_PTMP:
++              h.h.tei = pri->tei;
++              h.h.c_r = 1;
++              break;
++      case BRI_NETWORK:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE:
++              h.h.c_r = 1;
++              break;
++      default:
++              pri_error(pri, "Don't know how to disconnect on a type %d node\n", pri->localtype);
++              return;
++      }
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++              pri_message(pri, "Sending Disconnect\n");
++      q921_transmit(pri, &h, 3);
++ }
++*/
+-static void q921_send_sabme(void *vpri, int now)
++static void q921_send_dm(struct pri *pri, int pfbit, int tei)
++{
++      q921_h h;
++      Q921_INIT(pri, h);
++      h.u.m3 = 0;             /* M3 = 0 */
++      h.u.m2 = 3;             /* M2 = 3 */
++      h.u.p_f = pfbit;        /* Final bit on */
++      h.u.ft = Q921_FRAMETYPE_U;
++      h.h.tei = tei;
++      switch(pri->localtype) {
++      case PRI_NETWORK:
++              h.h.c_r = 0;
++              break;
++      case PRI_CPE:
++              h.h.c_r = 1;
++              break;
++      case BRI_NETWORK_PTMP:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE_PTMP:
++              h.h.tei = pri->tei;
++              h.h.c_r = 1;
++              break;
++      case BRI_NETWORK:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE:
++              h.h.c_r = 1;
++              break;
++      default:
++              pri_error(pri, "Don't know how to DM on a type %d node\n", pri->localtype);
++              return;
++      }
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++              pri_message(pri, "Sending DM\n");
++      q921_transmit(pri, &h, 3);
++}
++   
++static void q921_send_teireq(void *vpri) {
++    struct pri *pri = vpri;
++    unsigned short ri=0x6464;
++    q921_u *f;
++    ri = rand();
++
++    if (pri->localtype != BRI_CPE_PTMP) {
++      pri_error(pri, "TEI req for non-ptmp???\n"); 
++      return;
++    }
++    if (pri->t202_timer[0]) { 
++      pri_schedule_del(pri, pri->t202_timer[0]);
++      pri->t202_timer[0] = 0;
++    }
++    if (pri->sabme_retrans[0]++ > (pri->timers[PRI_TIMER_N202])) {
++      /* delete txqueue */
++      q921_flush_txqueue(pri, 0, 1);
++      /* N202 retransmissions, activation of layer 2 failed, tell upper layer, start again */
++      pri->schedev = 1;
++      pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
++      pri->ev.gen.tei = 0;
++      pri->sabme_retrans[0] = 0;
++      /* dont try again, they are gone */
++      return;
++    }
++ 
++    pri->t202_timer[0] = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_send_teireq, pri);
++  
++    pri->ri = ri;
++    f = malloc(sizeof(q921_u) + 5 + 2);
++    memset(f,0x0,sizeof(q921_u) + 5 + 2);
++    if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++        f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 0;   
++        f->h.ea1 = 0; 
++        f->h.ea2 = 1; 
++        f->m2 = 0;
++        f->m3 = 0;
++        f->ft = Q921_FRAMETYPE_U;
++        f->data[0] = 0xf;
++        f->data[1] = ri >> 8;
++        f->data[2] = ri & 0xff;
++        f->data[3] = Q921_TEI_ID_REQUEST;
++        f->data[4] = 0xff;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++          pri_message(pri, "Sending TEI Request ri=%d\n",ri);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++    }
++}
++  
++static void q921_send_teiassign(struct pri *pri,int ri,int tei) {
++    q921_u *f;
++  
++    if (pri->localtype != BRI_NETWORK_PTMP) {
++      pri_error(pri, "TEI assign for non-ptmp???\n"); 
++      return;
++    }
++  
++    f = malloc(sizeof(q921_u) + 5 + 2);
++    memset(f,0x0,sizeof(q921_u) + 5 + 2);
++    if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++      f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 1;   
++      f->h.ea1 = 0;   
++      f->h.ea2 = 1;   
++      f->m2 = 0;
++      f->m3 = 0;
++      f->ft = Q921_FRAMETYPE_U;
++      f->data[0] = 0xf;
++      f->data[1] = ri >> 8;
++      f->data[2] = ri & 0xff;
++      f->data[3] = Q921_TEI_ID_ASSIGNED;
++      f->data[4] = (tei << 1) | 0x1;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Sending TEI assign ri=%d tei=%d\n",ri,tei);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++      free(f);
++    } else {
++      pri_error(pri, "q921_send_teiassign: failed to malloc f!\n");
++    }
++}
++  
++static void q921_send_teichkresp(struct pri *pri,int tei) {
++    q921_u *f;
++    unsigned short ri=0x6464;
++    ri = rand();
++  
++    if (pri->localtype != BRI_CPE_PTMP) {
++      pri_error(pri, "TEI check response for non-ptmp???\n"); 
++      return;
++    }
++  
++    f = malloc(sizeof(q921_u) + 5 + 2);
++    memset(f,0x0,sizeof(q921_u) + 5 + 2);
++    if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++      f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 0; // command u->n   
++      f->h.ea1 = 0;   
++      f->h.ea2 = 1;   
++      f->m2 = 0;
++      f->m3 = 0;
++      f->ft = Q921_FRAMETYPE_U;
++      f->data[0] = 0xf;
++      f->data[1] = ri >> 8;
++      f->data[2] = ri & 0xff;
++      f->data[3] = Q921_TEI_ID_CHK_RES;
++      f->data[4] = (tei << 1) | 0x1;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Sending TEI check resp ri=%d tei=%d\n",ri,tei);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++      free(f);
++    }
++}
++
++static void q921_send_teichkreq(struct pri *pri,int tei) {
++    q921_u *f;
++    unsigned short ri=0x6464;
++    ri = rand();
++  
++    if (pri->localtype != BRI_NETWORK_PTMP) {
++      pri_error(pri, "TEI check response for non-ptmp???\n"); 
++      return;
++    }
++  
++    f = malloc(sizeof(q921_u) + 5 + 2);
++    memset(f,0x0,sizeof(q921_u) + 5 + 2);
++    if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++      f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 1; // command u->n   
++      f->h.ea1 = 0;   
++      f->h.ea2 = 1;   
++      f->m2 = 0;
++      f->m3 = 0;
++      f->ft = Q921_FRAMETYPE_U;
++      f->data[0] = 0xf;
++      f->data[1] = 0;
++      f->data[2] = 0;
++      f->data[3] = Q921_TEI_ID_CHK_REQ;
++      f->data[4] = (tei << 1) | 0x1;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Sending TEI check request ri=%d tei=%d\n",ri,tei);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++      free(f);
++    }
++}
++ 
++static void q921_send_teiverify(struct pri *pri,int tei) {
++    q921_u *f;
++  
++    if (pri->localtype != BRI_CPE_PTMP) {
++      pri_error(pri, "TEI verify for non-ptmp???\n"); 
++      return;
++    }
++  
++    f = malloc(sizeof(q921_u) + 5 + 2);
++    memset(f,0x0,sizeof(q921_u) + 5 + 2);
++    if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++      f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 0; // command u->n   
++      f->h.ea1 = 0;   
++      f->h.ea2 = 1;   
++      f->m2 = 0;
++      f->m3 = 0;
++      f->ft = Q921_FRAMETYPE_U;
++      f->data[0] = 0xf;
++      f->data[1] = 0;
++      f->data[2] = 0;
++      f->data[3] = Q921_TEI_ID_VERIFY;
++      f->data[4] = (tei << 1) | 0x1;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Sending TEI verify tei=%d\n", tei);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++      free(f);
++    }
++}
++
++  static void q921_send_teiremove(struct pri *pri, int tei) {
++      q921_u *f;
++      unsigned short ri=0x6464;
++      ri = rand();
++  
++      if (pri->localtype != BRI_NETWORK_PTMP) {
++      pri_error(pri, "TEI remove for non-ptmp???\n"); 
++      return;
++      }
++  
++      f = malloc(sizeof(q921_u) + 5 + 2);
++      memset(f,0x0,sizeof(q921_u) + 5 + 2);
++      if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++      f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 1;   
++      f->h.ea1 = 0;   
++      f->h.ea2 = 1;   
++      f->m2 = 0;
++      f->m3 = 0;
++      f->ft = Q921_FRAMETYPE_U;
++      f->data[0] = 0xf;
++      f->data[1] = ri >> 8;
++      f->data[2] = ri & 0xff;
++      f->data[3] = Q921_TEI_ID_REMOVE;
++      f->data[4] = (tei << 1) | 0x1;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Sending TEI remove tei=%d\n",tei);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++      free(f);
++      }
++  }
++  
++  static void q921_send_teidenied(struct pri *pri, int ri, int tei) {
++      q921_u *f;
++  
++      if (pri->localtype != BRI_NETWORK_PTMP) {
++      pri_error(pri, "TEI ID denied for non-ptmp???\n"); 
++      return;
++      }
++  
++      f = malloc(sizeof(q921_u) + 5 + 2);
++      memset(f,0x0,sizeof(q921_u) + 5 + 2);
++      if (f) {
++      f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++      f->h.tei = Q921_TEI_GROUP;
++      f->h.c_r = 1;   
++      f->h.ea1 = 0;   
++      f->h.ea2 = 1;   
++      f->m2 = 0;
++      f->m3 = 0;
++      f->ft = Q921_FRAMETYPE_U;
++      f->data[0] = 0xf;
++      f->data[1] = ri >> 8;
++      f->data[2] = ri & 0xff;
++      f->data[3] = Q921_TEI_ID_DENIED;
++      f->data[4] = (tei << 1) | 0x1;
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Sending TEI ID denied tei=%d\n",tei);
++      q921_transmit(pri,(q921_h *)&(f->h),8);
++      free(f);
++      }
++  }
++  
++ 
++static void q921_send_sabme_now(void *vpri, int tei);
++  
++static void q921_send_sabme(void *vpri, int now, int tei)
+ {
+       struct pri *pri = vpri;
+       q921_h h;
+-      pri_schedule_del(pri, pri->sabme_timer);
+-      pri->sabme_timer = 0;
+-      pri->sabme_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri);
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++  
++      if (pri->sabme_timer[teio]) {
++          pri_schedule_del(pri, pri->sabme_timer[teio]);
++          pri->sabme_timer[teio] = 0;
++      }
++      pri->sabme_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri, tei);
+       if (!now)
+               return;
++      if (pri->sabme_retrans[teio]++ > (pri->timers[PRI_TIMER_N202])) {
++          /* delete txqueue */
++          q921_flush_txqueue(pri, tei, 1);
++          /* N202 retransmissions, activation of layer 2 failed, tell upper layer, start again */
++          pri->schedev = 1;
++          pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
++          pri->ev.gen.tei = tei;
++          pri->sabme_retrans[teio] = 0;
++          /* dont try again, they are gone */
++          return;
++      }
+       Q921_INIT(pri, h);
++      // XXX
++      h.h.tei = tei;
+       h.u.m3 = 3;     /* M3 = 3 */
+       h.u.m2 = 3;     /* M2 = 3 */
+       h.u.p_f = 1;    /* Poll bit set */
+@@ -139,25 +504,42 @@
+       case PRI_CPE:
+               h.h.c_r = 0;
+               break;
++      case BRI_NETWORK_PTMP:
++              h.h.c_r = 1;
++              break;
++      case BRI_CPE_PTMP:
++              h.h.c_r = 0;
++              h.h.tei = pri->tei;
++              break;
++      case BRI_NETWORK:
++              h.h.c_r = 1;
++              break;
++      case BRI_CPE:
++              h.h.c_r = 0;
++              break;
+       default:
+-              pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++              pri_error(pri, "Don't know how to send SABME on a type %d node\n", pri->localtype);
+               return;
+       }
+       if (pri->debug & PRI_DEBUG_Q921_STATE)
+               pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n");
+       q921_transmit(pri, &h, 3);
+-      pri->q921_state = Q921_AWAITING_ESTABLISH;
++      pri->q921_state[teio] = Q921_AWAITING_ESTABLISH;
+ }
+-static void q921_send_sabme_now(void *vpri)
++static void q921_send_sabme_now(void *vpri, int tei)
+ {
+-      q921_send_sabme(vpri, 1);
++      q921_send_sabme(vpri, 1, tei);
+ }
+-static int q921_ack_packet(struct pri *pri, int num)
++  
++
++static int q921_ack_packet(struct pri *pri, int num, int tei)
+ {
+       struct q921_frame *f, *prev = NULL;
+-      f = pri->txqueue;
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      f = pri->txqueue[teio];
+       while(f) {
+               if (f->h.n_s == num) {
+                       /* Cancel each packet as necessary */
+@@ -165,26 +547,26 @@
+                       if (prev)
+                               prev->next = f->next;
+                       else
+-                              pri->txqueue = f->next;
++                              pri->txqueue[teio] = f->next;
+                       if (pri->debug & PRI_DEBUG_Q921_STATE)
+-                              pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue ? pri->txqueue->h.n_s : -1);
++                              pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue[teio] ? pri->txqueue[teio]->h.n_s : -1);
+                       /* Update v_a */
+-                      pri->v_a = num;
++                      pri->v_a[teio] = num;
+                       free(f);
+                       /* Reset retransmission counter if we actually acked something */
+-                      pri->retrans = 0;
++                      pri->retrans[teio] = 0;
+                       /* Decrement window size */
+-                      pri->windowlen--;
++                      pri->windowlen[teio]--;
+                       /* Search for something to send */
+-                      f = pri->txqueue;
++                      f = pri->txqueue[teio];
+                       while(f) {
+                               if (!f->transmitted) {
+                                       /* Send it now... */
+                                       if (pri->debug & PRI_DEBUG_Q921_STATE)
+                                               pri_message(pri, "-- Finally transmitting %d, since window opened up\n", f->h.n_s);
+                                       f->transmitted++;
+-                                      pri->windowlen++;
+-                                      f->h.n_r = pri->v_r;
++                                      pri->windowlen[teio]++;
++                                      f->h.n_r = pri->v_r[teio];
+                                       q921_transmit(pri, (q921_h *)(&f->h), f->len);
+                                       break;
+                               }
+@@ -198,77 +580,136 @@
+       return 0;
+ }
+-static void t203_expire(void *);
+-static void t200_expire(void *);
+-static pri_event *q921_dchannel_down(struct pri *pri);
++static void t203_expire(void *, int tei);
++static void t200_expire(void *, int tei);
++static pri_event *q921_dchannel_down(struct pri *pri, int tei);
++
++static void reschedule_t203(struct pri *pri, int tei)
++{
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      if (pri->t203_timer[teio]) {
++              pri_schedule_del(pri, pri->t203_timer[teio]);
++              pri->t203_timer[teio] = 0;
++              if (pri->q921_state[teio] != Q921_LINK_CONNECTION_RELEASED) {
++                  if (pri->debug &  PRI_DEBUG_Q921_STATE)
++                      pri_message(pri, "-- Restarting T203 counter\n");
++                  /* Nothing to transmit, start the T203 counter instead */
++                  pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
++              }
++      }
++}
+-static void reschedule_t203(struct pri *pri)
++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull)
+ {
+-      if (pri->t203_timer) {
+-              pri_schedule_del(pri, pri->t203_timer);
+-              if (pri->debug &  PRI_DEBUG_Q921_STATE)
+-                      pri_message(pri, "-- Restarting T203 counter\n");
+-              /* Nothing to transmit, start the T203 counter instead */
+-              pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++      struct q921_frame *f, *tmp = NULL;      
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      f = pri->txqueue[teio];
++
++      /* nothing to send */
++      if (!f) return;
++
++      /* transmit all i-frames that were queued up while we were waiting for layer 2 to rise */
++      while(f) {
++          if (devnull) {
++              tmp = f;
++              f = f->next;
++              free(tmp);
++              tmp = NULL;
++          } else {
++              if (pri->localtype == BRI_CPE_PTMP) {
++                  /* update TEI, it might have changed */
++                  f->h.h.tei = pri->tei;
++              }
++              q921_transmit(pri, (q921_h *)&f->h, f->len);
++              f->transmitted++;
++              f = f->next;
++          }
++      }
++      
++      if (devnull) {
++          pri->txqueue[teio] = NULL;
++          pri->v_s[teio] = 0;
++      } else {
++          if (pri->t200_timer[teio]) {
++              pri_schedule_del(pri, pri->t200_timer[teio]);
++              pri->t200_timer[teio] = 0;
++          }
++          if (pri->t203_timer[teio]) {
++              pri_schedule_del(pri, pri->t203_timer[teio]);
++              pri->t203_timer[teio] = 0;
++          }
++          pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
+       }
+ }
+-static pri_event *q921_ack_rx(struct pri *pri, int ack)
++static pri_event *q921_ack_rx(struct pri *pri, int ack, int tei)
+ {
+       int x;
+       int cnt=0;
+       pri_event *ev;
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+       /* Make sure the ACK was within our window */
+-      for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x));
++      for (x=pri->v_a[teio]; (x != pri->v_s[teio]) && (x != ack); Q921_INC(x));
+       if (x != ack) {
+               /* ACK was outside of our window --- ignore */
+-              pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a, pri->v_s);
+-              ev = q921_dchannel_down(pri);
+-              q921_start(pri, 1);
++              pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a[teio], pri->v_s[teio]);
++              ev = q921_dchannel_down(pri, tei);
++              q921_start(pri, 1, tei);
+               pri->schedev = 1;
+               return ev;
+       }
+       /* Cancel each packet as necessary */
+       if (pri->debug & PRI_DEBUG_Q921_STATE)
+-              pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, ack);
+-      for (x=pri->v_a; x != ack; Q921_INC(x)) 
+-              cnt += q921_ack_packet(pri, x); 
+-      if (!pri->txqueue) {
++              pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a[teio], ack);
++      for (x=pri->v_a[teio]; x != ack; Q921_INC(x)) 
++              cnt += q921_ack_packet(pri, x, tei);    
++      if (!pri->txqueue[teio]) {
++              /* Something was ACK'd.  Stop T200 counter */
++              if (pri->t200_timer[teio]) {
++                  pri_schedule_del(pri, pri->t200_timer[teio]);
++                  pri->t200_timer[teio] = 0;
++              }
+               if (pri->debug &  PRI_DEBUG_Q921_STATE)
+                       pri_message(pri, "-- Since there was nothing left, stopping T200 counter\n");
+-              /* Something was ACK'd.  Stop T200 counter */
+-              pri_schedule_del(pri, pri->t200_timer);
+-              pri->t200_timer = 0;
+       }
+-      if (pri->t203_timer) {
++      if (pri->t203_timer[teio]) {
++              pri_schedule_del(pri, pri->t203_timer[teio]);
++              pri->t203_timer[teio] = 0;
+               if (pri->debug &  PRI_DEBUG_Q921_STATE)
+                       pri_message(pri, "-- Stopping T203 counter since we got an ACK\n");
+-              pri_schedule_del(pri, pri->t203_timer);
+-              pri->t203_timer = 0;
+       }
+-      if (pri->txqueue) {
++      if (pri->txqueue[teio]) {
+               /* Something left to transmit, Start the T200 counter again if we stopped it */
++              if (pri->t200_timer[teio]) {
++                  pri_schedule_del(pri, pri->t200_timer[teio]);
++                  pri->t200_timer[teio] = 0;
++              }
+               if (pri->debug &  PRI_DEBUG_Q921_STATE)
+-                      pri_message(pri, "-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue->h.n_s);
+-              if (!pri->t200_timer)
+-                      pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++                      pri_message(pri, "-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue[teio]->h.n_s);
++              pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++
+       } else {
+               if (pri->debug &  PRI_DEBUG_Q921_STATE)
+                       pri_message(pri, "-- Nothing left, starting T203 counter\n");
+               /* Nothing to transmit, start the T203 counter instead */
+-              pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++              pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
+       }
+       return NULL;
+ }
+-static void q921_reject(struct pri *pri, int pf)
++static void q921_reject(struct pri *pri, int pf, int tei)
+ {
+       q921_h h;
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+       Q921_INIT(pri, h);
+       h.s.x0 = 0;     /* Always 0 */
+       h.s.ss = 2;     /* Reject */
+       h.s.ft = 1;     /* Frametype (01) */
+-      h.s.n_r = pri->v_r;     /* Where to start retransmission */
++      h.s.n_r = pri->v_r[teio];       /* Where to start retransmission */
+       h.s.p_f = pf;   
+       switch(pri->localtype) {
+       case PRI_NETWORK:
+@@ -277,23 +718,38 @@
+       case PRI_CPE:
+               h.h.c_r = 1;
+               break;
++      case BRI_NETWORK_PTMP:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE_PTMP:
++              h.h.c_r = 1;
++              h.h.tei = tei;
++              break;
++      case BRI_NETWORK:
++              h.h.c_r = 0;
++              break;
++      case BRI_CPE:
++              h.h.c_r = 1;
++              break;
+       default:
+-              pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++              pri_error(pri, "Don't know how to REJECT on a type %d node\n", pri->localtype);
+               return;
+       }
+       if (pri->debug & PRI_DEBUG_Q921_STATE)
+-              pri_message(pri, "Sending Reject (%d)\n", pri->v_r);
+-      pri->sentrej = 1;
++              pri_message(pri, "Sending Reject (%d)\n", pri->v_r[teio]);
++      pri->sentrej[teio] = 1;
+       q921_transmit(pri, &h, 4);
+ }
+-static void q921_rr(struct pri *pri, int pbit, int cmd) {
++static void q921_rr(struct pri *pri, int pbit, int cmd, int tei) {
+       q921_h h;
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+       Q921_INIT(pri, h);
+       h.s.x0 = 0;     /* Always 0 */
+       h.s.ss = 0; /* Receive Ready */
+       h.s.ft = 1;     /* Frametype (01) */
+-      h.s.n_r = pri->v_r;     /* N/R */
++      h.s.n_r = pri->v_r[teio];       /* N/R */
+       h.s.p_f = pbit;         /* Poll/Final set appropriately */
+       switch(pri->localtype) {
+       case PRI_NETWORK:
+@@ -308,81 +764,192 @@
+               else
+                       h.h.c_r = 1;
+               break;
++      case BRI_NETWORK_PTMP:
++              h.h.tei = tei;
++              if (cmd)
++                      h.h.c_r = 1;
++              else
++                      h.h.c_r = 0;
++              break;
++      case BRI_CPE_PTMP:
++              h.h.tei = tei;
++              if (cmd)
++                      h.h.c_r = 0;
++              else
++                      h.h.c_r = 1;
++              break;
++      case BRI_NETWORK:
++              if (cmd)
++                      h.h.c_r = 1;
++              else
++                      h.h.c_r = 0;
++              break;
++      case BRI_CPE:
++              if (cmd)
++                      h.h.c_r = 0;
++              else
++                      h.h.c_r = 1;
++              break;
+       default:
+-              pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++              pri_error(pri, "Don't know how to RR on a type %d node\n", pri->localtype);
+               return;
+       }
+-      pri->v_na = pri->v_r;   /* Make a note that we've already acked this */
++      pri->v_na[teio] = pri->v_r[teio];       /* Make a note that we've already acked this */
+       if (pri->debug & PRI_DEBUG_Q921_STATE)
+-              pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r);
++              pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r[teio]);
+       q921_transmit(pri, &h, 4);
+ }
+-static void t200_expire(void *vpri)
++static void t200_expire(void *vpri, int tei)
+ {
+       struct pri *pri = vpri;
+-      if (pri->txqueue) {
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      if (pri->txqueue[teio]) {
+               /* Retransmit first packet in the queue, setting the poll bit */
+               if (pri->debug & PRI_DEBUG_Q921_STATE)
+                       pri_message(pri, "-- T200 counter expired, What to do...\n");
+-              /* Force Poll bit */
+-              pri->txqueue->h.p_f = 1;        
+-              /* Update nr */
+-              pri->txqueue->h.n_r = pri->v_r;
+-              pri->v_na = pri->v_r;
+-              pri->solicitfbit = 1;
+-              pri->retrans++;
++              if (pri->txqueue[teio]->transmitted) {
++                  /* Force Poll bit, if this is a retransmission */
++                  pri->txqueue[teio]->h.p_f = 1;      
++                  pri->solicitfbit[teio] = 1;
++                  /* Update nr */
++                  pri->txqueue[teio]->h.n_r = pri->v_r[teio];
++                  pri->v_na[teio] = pri->v_r[teio];
++                  pri->retrans[teio]++;
++              }
+       /* Up to three retransmissions */
+-      if (pri->retrans < pri->timers[PRI_TIMER_N200]) {
++      if ((pri->retrans[teio] + 1)  <= pri->timers[PRI_TIMER_N200]) {
+          /* Reschedule t200_timer */
+          if (pri->debug & PRI_DEBUG_Q921_STATE)
+-            pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue->len);
+-              if (pri->busy) 
+-                      q921_rr(pri, 1, 1);
+-              else {
+-                      if (!pri->txqueue->transmitted) 
++              pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue[teio]->len);
++              if (pri->busy[teio]) {
++              // pri_message(pri, "-- q921_rr(pri, 1, 1) \n", tei);
++                      q921_rr(pri, 1, 1, tei);
++              } else {
++                      if (!pri->txqueue[teio]->transmitted)
+                               pri_error(pri, "!! Not good - head of queue has not been transmitted yet\n");
+-                      q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
++                      q921_transmit(pri, (q921_h *)&pri->txqueue[teio]->h, pri->txqueue[teio]->len);
++          //layer 3
++                      pri->txqueue[teio]->transmitted++;
+               }
+          if (pri->debug & PRI_DEBUG_Q921_STATE) 
+-               pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans);
+-         pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++               pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans[teio]);
++         pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
+       } else {
+          if (pri->debug & PRI_DEBUG_Q921_STATE) 
+                pri_message(pri, "-- Timeout occured, restarting PRI\n");
+-         pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
+-              pri->t200_timer = 0;
+-         q921_dchannel_down(pri);
+-         q921_start(pri, 1);
++         pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++               pri->t200_timer[teio] = 0;
++         q921_dchannel_down(pri, tei);
++         q921_start(pri, 1, tei);
+          pri->schedev = 1;
+       }
+-      } else if (pri->solicitfbit) {
++      } else if (pri->solicitfbit[teio]) {
+          if (pri->debug & PRI_DEBUG_Q921_STATE)
+             pri_message(pri, "-- Retrying poll with f-bit\n");
+-              pri->retrans++;
+-              if (pri->retrans < pri->timers[PRI_TIMER_N200]) {
+-                      pri->solicitfbit = 1;
+-                      q921_rr(pri, 1, 1);
+-                      pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++              pri->retrans[teio]++;
++              if (pri->retrans[teio] < pri->timers[PRI_TIMER_N200]) {
++                      pri->solicitfbit[teio] = 1;
++                      q921_rr(pri, 1, 1, tei);
++                      pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
+               } else {
+                       if (pri->debug & PRI_DEBUG_Q921_STATE) 
+                               pri_message(pri, "-- Timeout occured, restarting PRI\n");
+-                      pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
+-                      pri->t200_timer = 0;
+-                      q921_dchannel_down(pri);
+-                      q921_start(pri, 1);
++                      pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++                      pri->t200_timer[teio] = 0;
++                      q921_dchannel_down(pri, tei);
++                      q921_start(pri, 1, tei);
+                       pri->schedev = 1;
+               }
+       } else {
+               pri_error(pri, "T200 counter expired, nothing to send...\n");
+-              pri->t200_timer = 0;
++              pri->t200_timer[teio] = 0;
++              if (pri->busy[teio]) {
++                  if ((pri->retrans[teio] + 1) <= pri->timers[PRI_TIMER_N200]) {
++                      /* poll RR */
++                      pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++                      pri->retrans[teio]++;
++                      q921_rr(pri, 1, 1, tei);
++                  } else {
++                      q921_reset(pri, tei, 1);
++                      q921_start(pri, 1, tei);
++                  }
++              }
+       }
+ }
+-int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
++int q921_transmit_uframe(struct pri *pri, void *buf, int len, int cr, int tei)
++{
++      q921_u *uf;
++      uf = malloc(sizeof(q921_u) + len + 2);
++      memset(uf,0,sizeof(q921_u) + len + 2);
++
++      uf->h.sapi = 0;
++      uf->h.ea1 = 0;
++      uf->h.ea2 = 1;
++      uf->h.tei = tei;
++      uf->m3 = 0;
++      uf->m2 = 0;
++      uf->ft = Q921_FRAMETYPE_U;
++      switch(pri->localtype) {
++      case PRI_NETWORK:
++              uf->h.c_r = 1;
++              break;
++      case PRI_CPE:
++              uf->h.c_r = 0;
++              break;
++      case BRI_NETWORK_PTMP:
++              uf->h.c_r = 1;
++              break;
++      case BRI_CPE_PTMP:
++              uf->h.c_r = 0;
++              break;
++      case BRI_NETWORK:
++              uf->h.c_r = 1;
++              break;
++      case BRI_CPE:
++              uf->h.c_r = 0;
++              break;
++      default:
++              pri_error(pri, "Don't know how to send U frames on a type %d node\n", pri->localtype);
++              return -1;
++      }
++      memcpy(uf->data,buf,len);
++      q921_transmit(pri, (q921_h*)&(uf->h), 3+len);
++      free(uf);
++      return 0;
++}
++
++
++int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr, int tei)
+ {
+       q921_frame *f, *prev=NULL;
+-      for (f=pri->txqueue; f; f = f->next) prev = f;
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      if ((pri->q921_state[teio] == Q921_LINK_CONNECTION_RELEASED) && (!pri->sabme_timer[teio])) {
++          if (pri->localtype == BRI_CPE_PTMP) {
++              if (pri->tei > 0) {
++                  /* p2p datalink is down */
++                  pri->sabme_retrans[teio] = 0;
++                  q921_send_sabme_now(pri, pri->tei);
++                  if (pri->debug & PRI_DEBUG_Q921_STATE)
++                      pri_message(pri, "Reactivating layer 2\n");
++              } else {
++                  /* no tei */
++                  if (pri->debug & PRI_DEBUG_Q921_STATE)
++                      pri_message(pri, "reactivating layer 2, sending tei req\n");
++                  q921_send_teireq(pri);
++              }
++          } else if ((pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) {
++              /* p2p datalink is down */
++              pri->sabme_retrans[teio] = 0;
++              q921_send_sabme_now(pri, pri->tei);
++              if (pri->debug & PRI_DEBUG_Q921_STATE)
++                  pri_message(pri, "Reactivating layer 2\n");
++          }
++      }
++      for (f=pri->txqueue[teio]; f; f = f->next) prev = f;
+       f = malloc(sizeof(q921_frame) + len + 2);
+       if (f) {
+               memset(f,0,sizeof(q921_frame) + len + 2);
+@@ -400,47 +967,80 @@
+                       else
+                               f->h.h.c_r = 1;
+               break;
++              case BRI_NETWORK_PTMP:
++                      f->h.h.tei = tei;
++                      if (cr)
++                              f->h.h.c_r = 1;
++                      else
++                              f->h.h.c_r = 0;
++              break;
++              case BRI_CPE_PTMP:
++                      f->h.h.tei = pri->tei;
++                      if (cr)
++                              f->h.h.c_r = 0;
++                      else
++                              f->h.h.c_r = 1;
++              break;
++              case BRI_NETWORK:
++                      if (cr)
++                              f->h.h.c_r = 1;
++                      else
++                              f->h.h.c_r = 0;
++              break;
++              case BRI_CPE:
++                      if (cr)
++                              f->h.h.c_r = 0;
++                      else
++                              f->h.h.c_r = 1;
++              break;
+               }
+               f->next = NULL;
+               f->transmitted = 0;
+               f->len = len + 4;
+               memcpy(f->h.data, buf, len);
+-              f->h.n_s = pri->v_s;
+-              f->h.n_r = pri->v_r;
+-              pri->v_s++;
+-              pri->v_na = pri->v_r;
++              f->h.n_s = pri->v_s[teio];
++              f->h.n_r = pri->v_r[teio];
++              pri->v_s[teio]++;
++              pri->v_na[teio] = pri->v_r[teio];
+               f->h.p_f = 0;
+               f->h.ft = 0;
+               if (prev)
+                       prev->next = f;
+               else
+-                      pri->txqueue = f;
+-              /* Immediately transmit unless we're in a recovery state, or the window
+-                 size is too big */
+-              if (!pri->retrans && !pri->busy) {
+-                      if (pri->windowlen < pri->window) {
+-                              pri->windowlen++;
++                      pri->txqueue[teio] = f;
++
++              if  ((pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) && ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK))){
++                  /* no p2p datalink, yet. queue up the iframes... */
++                  if (pri->debug & PRI_DEBUG_Q921_STATE)
++                      pri_message(pri, "Layer 3 transmit waiting for layer 2\n");             
++              } else {
++                  /* Immediately transmit unless we're in a recovery state, or the window
++                      size is too big */
++                  if (!pri->retrans[teio] && !pri->busy[teio]) {
++                      if (pri->windowlen[teio] < pri->window[teio]) {
++                              pri->windowlen[teio]++;
+                               q921_transmit(pri, (q921_h *)(&f->h), f->len);
+                               f->transmitted++;
+                       } else {
+                               if (pri->debug & PRI_DEBUG_Q921_STATE)
+                                       pri_message(pri, "Delaying transmission of %d, window is %d/%d long\n", 
+-                                              f->h.n_s, pri->windowlen, pri->window);
++                                              f->h.n_s, pri->windowlen[teio], pri->window[teio]);
+                       }
+-              }
+-              if (pri->t203_timer) {
++                  }
++                  if (pri->t203_timer[teio]) {
++                      pri_schedule_del(pri, pri->t203_timer[teio]);
++                      pri->t203_timer[teio] = 0;
+                       if (pri->debug & PRI_DEBUG_Q921_STATE)
+                               pri_message(pri, "Stopping T_203 timer\n");
+-                      pri_schedule_del(pri, pri->t203_timer);
+-                      pri->t203_timer = 0;
+-              }
+-              if (!pri->t200_timer) {
++                  }
++                  if (!pri->t200_timer[teio]) {
+                       if (pri->debug & PRI_DEBUG_Q921_STATE)
+                               pri_message(pri, "Starting T_200 timer\n");
+-                      pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+-              } else
++                      pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++                  } else
+                       if (pri->debug & PRI_DEBUG_Q921_STATE)
+-                              pri_message(pri, "T_200 timer already going (%d)\n", pri->t200_timer);
++                              pri_message(pri, "T_200 timer already going (%d)\n", pri->t200_timer[teio]);
++              }
+               
+       } else {
+               pri_error(pri, "!! Out of memory for Q.921 transmit\n");
+@@ -449,49 +1049,86 @@
+       return 0;
+ }
+-static void t203_expire(void *vpri)
++static void t203_expire(void *vpri, int tei)
+ {
+-      struct pri *pri = vpri;
+-      if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) {
+-              if (pri->debug &  PRI_DEBUG_Q921_STATE)
++      struct pri *pri = vpri;
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++ 
++      if (pri->q921_state[teio] == Q921_LINK_CONNECTION_ESTABLISHED) {
++              if (pri->debug &  PRI_DEBUG_Q921_STATE)
+                       pri_message(pri, "T203 counter expired, sending RR and scheduling T203 again\n");
+-              /* Solicit an F-bit in the other's RR */
+-              pri->solicitfbit = 1;
+-              pri->retrans = 0;
+-              q921_rr(pri, 1, 1);
+-              /* Start timer T200 to resend our RR if we don't get it */
+-              pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++              /* Solicit an F-bit in the other's RR */
++              pri->solicitfbit[teio] = 1;
++              pri->retrans[teio] = 0;
++              q921_rr(pri, 1, 1, tei);
++              /* Start timer T200 to resend our RR if we don't get it */
++              pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++      } else {
++              if (pri->debug &  PRI_DEBUG_Q921_STATE)
++                      pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state[teio]);
++              pri->t203_timer[teio] = 0;
++      }
++}
++
++static void q921_start_tei(struct pri *pri, int tei);
++
++
++static void t201_expire(void *vpri, int tei)
++{
++      struct pri *pri = vpri;
++      int teio=tei - Q921_TEI_BASE;
++      int i = 0;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++      if (tei == Q921_TEI_GROUP) {
++          for (i=0;i<Q921_MAX_TEIS;i++) {
++              if (pri->q921_tei_check[i] == 1) {
++                  pri->q921_tei_check[i] = 0;
++                  q921_start_tei(pri, Q921_TEI_BASE + i);
++              }
++          }
+       } else {
+-              if (pri->debug &  PRI_DEBUG_Q921_STATE)
+-                      pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
+-              pri->t203_timer = 0;
++          if (pri->q921_tei_check[teio] == 1) {
++              pri->q921_tei_check[teio] = 0;
++              q921_start_tei(pri, tei);
++          }
+       }
++      pri->t201_timer[teio] = 0;
+ }
+ static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
+ {
+       int res;
+       pri_event *ev;
++      int teio= i->h.tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++//    pri_error(pri, "q921_handle_iframe: i->n_s %d pri->v_r[%d] %d \n", i->n_s, teio, pri->v_r[teio]);
+       /* Make sure this is a valid packet */
+-      if (i->n_s == pri->v_r) {
++      if (i->n_s == pri->v_r[teio]) {
+               /* Increment next expected I-frame */
+-              Q921_INC(pri->v_r);
++              Q921_INC(pri->v_r[teio]);
+               /* Handle their ACK */
+-              pri->sentrej = 0;
+-              ev = q921_ack_rx(pri, i->n_r);
++              pri->sentrej[teio] = 0;
++              ev = q921_ack_rx(pri, i->n_r, i->h.tei);
++              if (ev) {
++                  pri_error(pri, "q921_handle_iframe: ev = %d \n", ev->e);
++              }
+               if (ev)
+                       return ev;
+               if (i->p_f) {
+                       /* If the Poll/Final bit is set, immediate send the RR */
+-                      q921_rr(pri, 1, 0);
+-              } else if (pri->busy) {
+-                      q921_rr(pri, 0, 0);
++                      q921_rr(pri, 1, 0, i->h.tei);
++              } else if (pri->busy[teio]) {
++                      q921_rr(pri, 0, 0, i->h.tei);
++              } else if (pri->t200_timer[teio] && pri->retrans[teio]) {
++              pri_error(pri, "q921_handle_iframe: sending RR \n");
++                      q921_rr(pri, 0, 0, i->h.tei);
+               }
+               /* Receive Q.931 data */
+-              res = q931_receive(pri, (q931_h *)i->data, len - 4);
++              res = q931_receive(pri, (q931_h *)i->data, len - 4, i->h.tei);
+               /* Send an RR if one wasn't sent already */
+-              if (pri->v_na != pri->v_r) 
+-                      q921_rr(pri, 0, 0);
++              if (pri->v_na[teio] != pri->v_r[teio]) 
++                      q921_rr(pri, 0, 0,  i->h.tei);
+               if (res == -1) {
+                       return NULL;
+               }
+@@ -500,10 +1137,10 @@
+       } else {
+               /* If we haven't already sent a reject, send it now, otherwise
+                  we are obliged to RR */
+-              if (!pri->sentrej)
+-                      q921_reject(pri, i->p_f);
++              if (!pri->sentrej[teio])
++                      q921_reject(pri, i->p_f, i->h.tei);
+               else if (i->p_f)
+-                      q921_rr(pri, 1, 0);
++                      q921_rr(pri, 1, 0, i->h.tei);
+       }
+       return NULL;
+ }
+@@ -641,75 +1278,152 @@
+       };
+ }
+-static pri_event *q921_dchannel_up(struct pri *pri)
++static void q921_tei_recovery(struct pri *pri, int tei) {
++    int i = 0;
++    int teio=tei - Q921_TEI_BASE;
++    if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++    for (i=0;i<Q921_MAX_TEIS;i++) {
++      if ((i + Q921_TEI_BASE == tei) || (tei == Q921_TEI_GROUP)) {
++          pri->q921_tei_check[i] = 1;
++      }
++    }
++    q921_send_teichkreq(pri, tei);
++    if (!pri->t201_timer[teio]) {
++      pri->t201_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T201], t201_expire, pri, tei);
++    }
++}
++/*
++static void q921_invoke_tei_recovery(void *vpri, int tei) {
++      struct pri *pri = vpri;
++      q921_tei_recovery(pri, tei);
++}
++*/
++
++static pri_event *q921_dchannel_up(struct pri *pri, int tei)
+ {
+-      /* Reset counters, etc */
+-      q921_reset(pri);
++      // we treat this as MFE
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++      if  (((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) && (pri->txqueue[teio])) {
++          /* Reset counters, etc */
++          q921_reset(pri, tei, 0);
++      } else {
++          /* Reset counters, discard frames, etc */
++          q921_reset(pri, tei, 1);
++      }
+       
+       /* Stop any SABME retransmissions */
+-      pri_schedule_del(pri, pri->sabme_timer);
+-      pri->sabme_timer = 0;
++      if (pri->sabme_timer[teio]) {
++          pri_schedule_del(pri, pri->sabme_timer[teio]);
++          pri->sabme_timer[teio] = 0;
++      }
++      
++      if (pri->t202_timer[teio]) {
++          pri_schedule_del(pri, pri->t202_timer[teio]);
++          pri->t202_timer[teio] = 0;
++      }
+       
+       /* Reset any rejects */
+-      pri->sentrej = 0;
++      pri->sentrej[teio] = 0;
+       
+       /* Go into connection established state */
+-      pri->q921_state = Q921_LINK_CONNECTION_ESTABLISHED;
+-
+-      /* Start the T203 timer */
+-      pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++      pri->q921_state[teio] = Q921_LINK_CONNECTION_ESTABLISHED;
+       
+-      /* Report event that D-Channel is now up */
+-      pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
+-      return &pri->ev;
++      if  (((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) && (pri->txqueue[teio])) {
++          /* transmit queued iframes ans start T200 (handled by flush_txqueue) */
++          q921_flush_txqueue(pri, tei, 0);
++          /* dont upset upper layers if we reactivate layer 2 */
++          return NULL;
++      } else {
++          /* Start the T203 timer */
++          pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
++          
++          /* Report event that D-Channel is now up */
++          pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
++          pri->ev.gen.tei = tei;
++          return &pri->ev;
++      }
+ }
+-static pri_event *q921_dchannel_down(struct pri *pri)
++static pri_event *q921_dchannel_down(struct pri *pri, int tei)
+ {
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++      pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++
+       /* Reset counters, reset sabme timer etc */
+-      q921_reset(pri);
++      if (pri->localtype == BRI_NETWORK_PTMP) {
++          if (pri->t203_timer[teio]) {
++              pri_schedule_del(pri, pri->t203_timer[teio]);
++              pri->t203_timer[teio] = 0;
++              if (pri->debug & PRI_DEBUG_Q921_STATE) {
++                      pri_message(pri, "Stopping T_203 timer for TEI %d\n", tei);
++              }
++          }
++      }
++
++      q921_reset(pri, tei, 1);
+       
+-      /* Report event that D-Channel is now up */
++      /* Report event that D-Channel is now down */
+       pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
++      pri->ev.gen.tei = tei;
+       return &pri->ev;
+ }
+-void q921_reset(struct pri *pri)
++void q921_reset(struct pri *pri, int tei, int discard)
+ {
++      int teio=tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+       /* Having gotten a SABME we MUST reset our entire state */
+-      pri->v_s = 0;
+-      pri->v_a = 0;
+-      pri->v_r = 0;
+-      pri->v_na = 0;
+-      pri->window = pri->timers[PRI_TIMER_K];
+-      pri->windowlen = 0;
+-      pri_schedule_del(pri, pri->sabme_timer);
+-      pri_schedule_del(pri, pri->t203_timer);
+-      pri_schedule_del(pri, pri->t200_timer);
+-      pri->sabme_timer = 0;
+-      pri->t203_timer = 0;
+-      pri->t200_timer = 0;
+-      pri->busy = 0;
+-      pri->solicitfbit = 0;
+-      pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
+-      pri->retrans = 0;
+-      pri->sentrej = 0;
++      if (discard) {
++          pri->v_s[teio] = 0;
++      }
++      pri->v_a[teio] = 0;
++      pri->v_r[teio] = 0;
++      pri->v_na[teio] = 0;
++      pri->window[teio] = pri->timers[PRI_TIMER_K];
++      pri->windowlen[teio] = 0;
++      pri_schedule_del(pri, pri->sabme_timer[teio]);
++      pri_schedule_del(pri, pri->t203_timer[teio]);
++      pri_schedule_del(pri, pri->t200_timer[teio]);
++      pri->sabme_timer[teio] = 0;
++      pri->t203_timer[teio] = 0;
++      pri->t200_timer[teio] = 0;
++      pri_schedule_del(pri, pri->t202_timer[teio]);
++      pri->t202_timer[teio] = 0;
++      pri_schedule_del(pri, pri->t201_timer[teio]);
++      pri->t201_timer[teio] = 0;
++      pri->busy[teio] = 0;
++      pri->solicitfbit[teio] = 0;
++      pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++      pri->retrans[teio] = 0;
++      pri->sabme_retrans[teio] = 0;
++      pri->sentrej[teio] = 0;
+       
+-      /* Discard anything waiting to go out */
+-      q921_discard_retransmissions(pri);
++      if (discard) {
++          /* Discard anything waiting to go out */
++          q921_discard_retransmissions(pri, tei);
++      }
+ }
++
+ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
+ {
+       q921_frame *f;
+       pri_event *ev;
+       int sendnow;
++      int tei;
++      int res=-1;
++      int teio=h->h.tei - Q921_TEI_BASE;
++      if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+       switch(h->h.data[0] & Q921_FRAMETYPE_MASK) {
+       case 0:
+       case 2:
+-              if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) {
+-                      pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state);
++              if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) {
++                      pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state[teio]);
+                       return NULL;
+               }
+               /* Informational frame */
+@@ -720,8 +1434,10 @@
+               return q921_handle_iframe(pri, &h->i, len);     
+               break;
+       case 1:
+-              if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) {
++              if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) {
+                       pri_error(pri, "!! Got S-frame while link down\n");
++                      q921_send_dm(pri, 1,  h->h.tei);
++                      q921_reset(pri, h->h.tei, 1);
+                       return NULL;
+               }
+               if (len < 4) {
+@@ -731,80 +1447,122 @@
+               switch(h->s.ss) {
+               case 0:
+                       /* Receiver Ready */
+-                      pri->busy = 0;
++                      pri->busy[teio] = 0;
+                       /* Acknowledge frames as necessary */
+-                      ev = q921_ack_rx(pri, h->s.n_r);
++                      ev = q921_ack_rx(pri, h->s.n_r, h->h.tei);
+                       if (ev)
+                               return ev;
+                       if (h->s.p_f) {
+-                              /* If it's a p/f one then send back a RR in return with the p/f bit set */
+-                              if (pri->solicitfbit) {
++                      /* If it's a p/f one then send back a RR in return with the p/f bit set */
++//                    pri_error(pri, "-- h->s.pf %d pri->solicitfbit[teio] %d\n", h->s.p_f, pri->solicitfbit[teio]);
++                              if (pri->solicitfbit[teio]) {
+                                       if (pri->debug & PRI_DEBUG_Q921_STATE) 
+                                               pri_message(pri, "-- Got RR response to our frame\n");
+                               } else {
+-                                      if (pri->debug & PRI_DEBUG_Q921_STATE) 
++                                      if (pri->txqueue[teio]) {
++                                          q921_flush_txqueue(pri, pri->tei, 0);
++                                      } else {
++                                          if (pri->debug & PRI_DEBUG_Q921_STATE) 
+                                               pri_message(pri, "-- Unsolicited RR with P/F bit, responding\n");
+-                                              q921_rr(pri, 1, 0);
++                                              q921_rr(pri, 1, 0, h->h.tei);
++                                      }
+                               }
+-                              pri->solicitfbit = 0;
++                              pri->solicitfbit[teio] = 0;
+                       }
+                       break;
+       case 1:
+          /* Receiver not ready */
+          if (pri->debug & PRI_DEBUG_Q921_STATE)
+             pri_message(pri, "-- Got receiver not ready\n");
+-       if(h->s.p_f) {
+-              /* Send RR if poll bit set */
+-              q921_rr(pri, h->s.p_f, 0);
++       if ((pri->localtype != PRI_NETWORK) && (pri->localtype != BRI_NETWORK) && (pri->localtype != BRI_NETWORK_PTMP)) {
++           if (h->s.p_f && h->s.h.c_r) {
++//            if (!pri->t200_timer[teio]) {
++                  /* Send RR if poll bit set */
++                  q921_rr(pri, h->s.p_f, 0, h->h.tei);
++//            }
++          }
++       } else {
++           if (h->s.p_f && (!h->s.h.c_r)) {
++//            if (!pri->t200_timer[teio]) {
++                  /* Send RR if poll bit set */
++                  q921_rr(pri, h->s.p_f, 0, h->h.tei);
++//            }
++          }
+        }
+-         pri->busy = 1;
+-         break;   
++         pri->busy[teio] = 1;
++       if (pri->t200_timer[teio]) {
++          pri_schedule_del(pri, pri->t200_timer[teio]);
++          pri->t200_timer[teio] = 0;
++       }
++       pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, h->h.tei);
++         break;
+       case 2:
+          /* Just retransmit */
+          if (pri->debug & PRI_DEBUG_Q921_STATE)
+             pri_message(pri, "-- Got reject requesting packet %d...  Retransmitting.\n", h->s.n_r);
+-         if (h->s.p_f) {
+-            /* If it has the poll bit set, send an appropriate supervisory response */
+-            q921_rr(pri, 1, 0);
+-         }
+                sendnow = 0;
++// XXX                 
++      q921_ack_rx(pri, h->s.n_r, h->h.tei);
+          /* Resend the proper I-frame */
+-         for(f=pri->txqueue;f;f=f->next) {
++         for(f=pri->txqueue[teio];f;f=f->next) {
++//        pri_error(pri, "!! frame n_s %d transmitted %d (searching for %d)!\n", f->h.n_s, f->transmitted, h->s.n_r);
+                if ((sendnow || (f->h.n_s == h->s.n_r)) && f->transmitted) {
+                      /* Matches the request, or follows in our window, and has
+                                           already been transmitted. */
+-                                       sendnow = 1;
+-                                       pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
+-                                   f->h.n_r = pri->v_r;
++
++                   /* multiframe established */
++                   f->transmitted = 0;
++                   f->h.n_r = pri->v_r[teio];
++                  
++                  if (pri->busy[teio]) {
++                    pri->busy[teio] = 0;
++                    sendnow = 0;
++                   } else {
++                      f->h.p_f = 0;
++                    sendnow = 1;
++                      pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
+                      q921_transmit(pri, (q921_h *)(&f->h), f->len);
++                   }
+                }
+          }
+          if (!sendnow) {
+-               if (pri->txqueue) {
+-                     /* This should never happen */
+-                   if (!h->s.p_f || h->s.n_r) {
++               if (pri->txqueue[teio]) {
++                   if (h->s.p_f) {
++                      q921_rr(pri, 1, 0, h->h.tei);
++                   } else if (!h->s.p_f || h->s.n_r) {
+                       pri_error(pri, "!! Got reject for frame %d, but we only have others!\n", h->s.n_r);
+                    }
+                } else {
+                      /* Hrm, we have nothing to send, but have been REJ'd.  Reset v_a, v_s, etc */
+-                              pri_error(pri, "!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r);
+-                     pri->v_a = h->s.n_r;
+-                     pri->v_s = h->s.n_r;
++/*                            pri_error(pri, "!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r);
++                     pri->v_a[teio] = h->s.n_r;
++                     pri->v_s[teio] = h->s.n_r; */
+                      /* Reset t200 timer if it was somehow going */
+-                     if (pri->t200_timer) {
+-                           pri_schedule_del(pri, pri->t200_timer);
+-                           pri->t200_timer = 0;
++                     if (pri->t200_timer[teio]) {
++                           pri_schedule_del(pri, pri->t200_timer[teio]);
++                           pri->t200_timer[teio] = 0;
+                      }
+                      /* Reset and restart t203 timer */
+-                     if (pri->t203_timer)
+-                           pri_schedule_del(pri, pri->t203_timer);
+-                     pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++                     if (pri->t203_timer[teio])
++                           pri_schedule_del(pri, pri->t203_timer[teio]);
++                     pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
++                   pri->solicitfbit[teio] = 0;
+                }
+-         }
++         } else {
++          if (h->s.p_f) {
++              /* If it has the poll bit set (and an iframe was retransmitted), send an appropriate supervisory response */
++//            q921_rr(pri, 1, 0, h->h.tei);
++                 /* Reset and restart t203 timer */
++                pri->solicitfbit[teio] = 0;
++                 if (pri->t203_timer[teio])
++                       pri_schedule_del(pri, pri->t203_timer[teio]);
++                 pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, h->h.tei);
++            }
++       }
+          break;
+               default:
+                       pri_error(pri, "!! XXX Unknown Supervisory frame ss=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", h->s.ss, h->s.p_f, h->s.n_r,
+-                                      pri->v_s, pri->v_a);
++                                      pri->v_s[teio], pri->v_a[teio]);
+               }
+               break;
+       case 3:
+@@ -821,8 +1579,16 @@
+                                       if (pri->debug & PRI_DEBUG_Q921_STATE)
+                                               pri_message(pri, "-- Got DM Mode from peer.\n");
+                                       /* Disconnected mode, try again after T200 */
+-                                      ev = q921_dchannel_down(pri);
+-                                      q921_start(pri, 0);
++                                      ev = q921_dchannel_down(pri, h->h.tei);
++                                      if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) {
++                                          /* release layer 2 */
++                                      //    pri_error(pri, "got DM, restarting layer 2.\n");
++                                      //    return NULL;
++                                          q921_start(pri, 0, h->h.tei);
++                                      }
++                                      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){
++                                          q921_start(pri, 0, h->h.tei);
++                                      }
+                                       return ev;
+                                               
+                               } else {
+@@ -830,21 +1596,144 @@
+                                               pri_message(pri, "-- Ignoring unsolicited DM with p/f set to 0\n");
+ #if 0
+                                       /* Requesting that we start */
+-                                      q921_start(pri, 0);
++                                      q921_start(pri, 0, h->h.tei);
+ #endif                                        
+                               }
+                               break;
+-                      } else if (!h->u.m2) {
+-                              pri_message(pri, "XXX Unnumbered Information not implemented XXX\n");
++                      } else if (h->u.m2 == 0) {
++                              if (h->u.ft == 3) {
++                                  switch (h->u.data[0]) { /* Management Entity Identifier  */
++                                      case 0x0f:
++                                      /* TEI Procedure */
++                                      switch (h->u.data[3]) {
++                                          case Q921_TEI_ID_VERIFY:
++                                              if (pri->localtype != BRI_NETWORK_PTMP)
++                                                  break;
++                                                  if (pri->debug & PRI_DEBUG_Q921_STATE)
++                                                      pri_message(pri, "got TEI verify for TEI = %d\n",h->u.data[4] >> 1);
++                                          break;
++                                          case Q921_TEI_ID_ASSIGNED:
++                                              if (pri->localtype != BRI_CPE_PTMP)
++                                                  break;
++                                              if (pri->tei == (h->u.data[4] >> 1)) {
++                                                  // TEI already assgined, CHECK_TEI or REMOVE_TEI
++                                                  pri_error(pri, "Double assgined TEI!\n");
++                                              }
++                                              if (pri->ri == ((unsigned short) (h->u.data[1] << 8) + h->u.data[2])) {
++                                                  if (pri->t202_timer[0]) {
++                                                      pri_schedule_del(pri, pri->t202_timer[0]);
++                                                      pri->t202_timer[0] = 0;
++                                                  }
++                                                  pri->tei = h->u.data[4] >> 1; 
++                                                  pri->ri = 0;
++                                                  if (pri->debug & PRI_DEBUG_Q921_STATE)
++                                                      pri_message(pri, "received TEI assign TEI = %d ri=%d\n",pri->tei,(unsigned short) (h->u.data[1] << 8) + h->u.data[2]);
++                                                  pri->sabme_retrans[teio] = 0;
++                                                  q921_send_sabme_now(pri, pri->tei);
++                                              }
++                                          break;
++                                          case Q921_TEI_ID_REMOVE:
++                                              pri_error(pri, "TEI remove TEI = %d\n",(h->u.data[4] >> 1));
++                                              if (pri->localtype != BRI_CPE_PTMP)
++                                                  break;
++                                              if (((h->u.data[4] >> 1) == Q921_TEI_GROUP) || (pri->tei == (h->u.data[4] >> 1))){ 
++                                                  if (pri->debug & PRI_DEBUG_Q921_STATE)
++                                                      pri_message(pri, "received TEI remove TEI = %d\n",pri->tei);
++                                                  pri->tei = 0;
++                                                  pri->ri = 0;
++                                                  // get a new TEI
++                                                  q921_reset(pri, 0, 1);
++                                                  q921_send_teireq(pri);
++                                              }
++                                          break;
++                                          case Q921_TEI_ID_REQUEST:
++                                              if (pri->localtype != BRI_NETWORK_PTMP)
++                                                  break;
++                                              
++                                              tei = h->u.data[4] >> 1;
++                                              if (tei != Q921_TEI_GROUP) {
++                                                  pri_message(pri, "got TEI request for unavailable TEI..\n");
++                                                  q921_send_teidenied(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),h->u.data[4] >> 1);
++                                                  break;
++                                              }
++                                              
++                                              for (tei=0;tei<Q921_MAX_TEIS;tei++) {
++                                                  if (pri->q921_teis[tei] == 0) {
++                                                      pri->q921_teis[tei] = 1;
++                                                      break;
++                                                  }
++                                              }
++                                              if (tei < Q921_MAX_TEIS) {
++                                                  q921_send_teiassign(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),tei + Q921_TEI_BASE);
++                                              } else {
++                                                  pri_error(pri, "no TEI available. starting TEI recovery procedure. dont worry!\n");
++                                                  q921_tei_recovery(pri, 127);
++                                                  
++                                              }
++                                          break;
++                                          case Q921_TEI_ID_CHK_REQ:
++                                              if (pri->localtype != BRI_CPE_PTMP)
++                                                  break;
++                                                  if ((((h->u.data[4] >> 1) == Q921_TEI_GROUP) || ((h->u.data[4] >> 1) == 0) || ((h->u.data[4] >> 1) == pri->tei)) && (pri->tei > 0)) {
++                                                      pri_message(pri, "received TEI check request for TEI = %d\n",h->u.data[4] >> 1);
++                                                      q921_send_teichkresp(pri, pri->tei);
++                                                  }
++                                          break;
++                                          case Q921_TEI_ID_CHK_RES:
++                                              if (pri->localtype != BRI_NETWORK_PTMP)
++                                                  break;
++                                                  teio = (h->u.data[4] >> 1) - Q921_TEI_BASE;
++                                                  if ((teio < 0) || (teio >= Q921_MAX_TEIS)) break;
++                                                  if (pri->q921_tei_check[teio] == 1) {
++                                                      pri->q921_tei_check_ri[teio] = (h->u.data[1] << 8) + h->u.data[2];
++                                                      pri->q921_tei_check[teio] = 0;
++                                                  } else {
++                                                      // d a t
++                                                      pri_error(pri, "double assgined tei for tei %d teio %d\n", h->u.data[4] >> 1, teio);
++                                                      pri->q921_tei_check[teio] = 0;
++                                                      q921_start_tei(pri, h->u.data[4] >> 1);
++                                                  }
++                                          break;
++                                          default:
++                                              pri_message(pri, "Ri = %d TEI msg = %x TEI = %x\n", (h->u.data[1] << 8) + h->u.data[2], h->u.data[3], h->u.data[4] >> 1);
++                                      } 
++                                      break;
++                                      case Q931_PROTOCOL_DISCRIMINATOR:
++                                          if (pri->localtype == BRI_CPE_PTMP) {
++                                          res = q931_receive(pri, (q931_h *)h->u.data, len-3, h->h.tei);
++                                          /* Send an RR if one wasn't sent already */
++                                          if (pri->v_na[teio] != pri->v_r[teio]) 
++                                              q921_rr(pri, 0, 0, pri->tei);
++                                          if (res == -1) {
++                                              return NULL;
++                                          }
++                                          if (res & Q931_RES_HAVEEVENT)
++                                              return &pri->ev;
++                                          }
++                                      break;
++                                  }
++                              } else {
++                                  pri_message(pri, "XXX Unnumbered Information not implemented XXX\n");
++                              }
+                       }
+                       break;
+               case 2:
+                       if (pri->debug &  PRI_DEBUG_Q921_STATE)
+                               pri_message(pri, "-- Got Disconnect from peer.\n");
++                      if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) {
++                          q921_send_dm(pri, 1, h->h.tei);
++                          return NULL;
++                      }
+                       /* Acknowledge */
+-                      q921_send_ua(pri, h->u.p_f);
+-                      ev = q921_dchannel_down(pri);
+-                      q921_start(pri, 0);
++                      q921_send_ua(pri, h->u.p_f, h->h.tei);
++                      ev = q921_dchannel_down(pri, h->h.tei);
++                      if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) {
++                          /* release layer 2 */
++                          return NULL;
++                      }
++                      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){
++                          q921_start(pri, 0, 0);
++                      }
+                       return ev;
+               case 3:
+                       if (h->u.m2 == 3) {
+@@ -866,17 +1755,26 @@
+                                       }
+                               }
+                               /* Send Unnumbered Acknowledgement */
+-                              q921_send_ua(pri, h->u.p_f);
+-                              return q921_dchannel_up(pri);
++                              q921_send_ua(pri, h->u.p_f, h->h.tei);
++                              return q921_dchannel_up(pri, h->h.tei);
+                       } else if (h->u.m2 == 0) {
+                                       /* It's a UA */
+-                              if (pri->q921_state == Q921_AWAITING_ESTABLISH) {
++                              if (pri->q921_state[teio] == Q921_AWAITING_ESTABLISH) {
+                                       if (pri->debug & PRI_DEBUG_Q921_STATE) {
+                                               pri_message(pri, "-- Got UA from %s peer  Link up.\n", h->h.c_r ? "cpe" : "network");
+                                       }
+-                                      return q921_dchannel_up(pri);
+-                              } else 
+-                                      pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state);
++                                      return q921_dchannel_up(pri, h->h.tei);
++                              } else {
++                                      pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state[teio]);
++                                      if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE)) {
++                                          q921_reset(pri, h->h.tei, 1);
++                                          q921_send_teiverify(pri, h->h.tei);
++                                      } else {
++                                          /* send DM */
++                                      //    q921_send_dm(pri, 1, h->h.tei);
++                                          q921_reset(pri, h->h.tei, 1);
++                                      }
++                              }
+                       } else 
+                               pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2);
+                       break;
+@@ -901,19 +1799,42 @@
+       /* Discard FCS */
+       len -= 2;
+       
+-      if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP)
+-              q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
+-
+       /* Check some reject conditions -- Start by rejecting improper ea's */
+       if (h->h.ea1 || !(h->h.ea2))
+               return NULL;
++      if ((pri->localtype == PRI_CPE) || (pri->localtype == PRI_NETWORK)) {
++          /* Check for broadcasts - not yet handled (for PRI) */
++          if (h->h.tei == Q921_TEI_GROUP) {
++              return NULL;
++          }
++      } else if ((pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) {
++          if ((h->h.tei != pri->tei) && (h->h.tei != Q921_TEI_GROUP)) {
++              return NULL;
++          }
++      } else if (pri->localtype == BRI_NETWORK_PTMP) {
++          /* discard anything from a strange TEI (strange == not assigned by us or the broadcast tei) */
++          if (((h->h.tei < Q921_TEI_BASE) || (h->h.tei > Q921_TEI_BASE + Q921_MAX_TEIS)) && (h->h.tei != Q921_TEI_GROUP)) {
++              if (pri->debug & PRI_DEBUG_Q921_DUMP)
++                  pri_message(pri, "Received a Q.921 message from strange/unassigned TEI %d.\n");
++              return NULL;
++          } else {
++              if ((pri->q921_teis[h->h.tei - Q921_TEI_BASE] != 1) && (h->h.tei != Q921_TEI_GROUP)) {
++                  if (pri->debug & PRI_DEBUG_Q921_DUMP)
++                      pri_message(pri, "Received a Q.921 message from unassigned TEI %d.. Sending DM and assigning.\n", h->h.tei);
++                  // send DM 
++                  q921_send_dm(pri, 1, h->h.tei);
++                  pri->q921_teis[h->h.tei - Q921_TEI_BASE] = 1; 
++              }
++          }
++      }    
++  
++      if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP)
++              q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
+-      /* Check for broadcasts - not yet handled */
+-      if (h->h.tei == Q921_TEI_GROUP)
+-              return NULL;
++      if (pri->localtype != BRI_NETWORK_PTMP) {
+       /* Check for SAPIs we don't yet handle */
+-      if ((h->h.sapi != pri->sapi) || (h->h.tei != pri->tei)) {
++          if (((h->h.sapi != pri->sapi) && (h->h.sapi != Q921_SAPI_LAYER2_MANAGEMENT)) || ((h->h.tei != pri->tei) && (h->h.tei != Q921_TEI_GROUP) )) {
+ #ifdef PROCESS_SUBCHANNELS
+               /* If it's not us, try any subchannels we have */
+               if (pri->subchannel)
+@@ -921,10 +1842,16 @@
+               else 
+ #endif
+                       return NULL;
+-
++          }
+       }
+       ev = __q921_receive_qualified(pri, h, len);
+-      reschedule_t203(pri);
++
++// Q921_GROUP_TEI
++      if (pri->localtype == BRI_CPE_PTMP) {
++          reschedule_t203(pri, pri->tei);
++      } else {
++          reschedule_t203(pri, h->h.tei);
++      }
+       return ev;
+ }
+@@ -938,14 +1865,58 @@
+       return e;
+ }
+-void q921_start(struct pri *pri, int now)
++static void q921_start_tei(struct pri *pri, int tei)
+ {
+-      if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) {
+-              pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n");
+-              return;
++ int teio=tei - Q921_TEI_BASE;
++ if (pri->localtype != BRI_NETWORK_PTMP) { return; }
++ if (((teio < 0) || (teio > Q921_MAX_TEIS))) { teio=0; }
++ pri->q921_teis[teio] = 0;
++ q921_send_teiremove(pri, tei);
++ q921_reset(pri,tei,1);
++}
++
++void q921_start(struct pri *pri, int now, int tei)
++{
++      int i=0;
++/*    if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) {
++              pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n");
++              return;
++      } */
++      /* Reset our interface */
++      if (pri->localtype != BRI_NETWORK_PTMP) {
++          q921_reset(pri,0,1);
++      }
++      /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */
++      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE) || (pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_CPE)) { 
++          pri->sabme_retrans[0] = 0;
++          q921_send_sabme(pri, now, 0);
++      }
++      
++      if (pri->localtype == BRI_NETWORK_PTMP) { 
++          if (tei == 0) {
++              // initial start or complete restart
++              q921_send_teiremove(pri, 127);
++              pri->dchanup = 0;
++              for (i=0;i<Q921_MAX_TEIS;i++) {
++                  q921_start_tei(pri,Q921_TEI_BASE+i);
++              }
++              /* clean up those TEIs */
++//            pri_schedule_event2(pri, 10000, q921_invoke_tei_recovery, pri, 127 );
++          } else if ((tei >= Q921_TEI_BASE) && (tei < Q921_TEI_BASE + Q921_MAX_TEIS)){
++              // restart of a single p2p datalink
++              q921_start_tei(pri,tei);
++          }
++      } 
++      if (pri->localtype == BRI_CPE_PTMP){ 
++          if (tei == 0) {
++#ifdef RELAX_TRB
++              /* let's get a TEI */
++              q921_send_teireq(pri);
++#endif
++          } else {
++              /* save the planet by recycling */
++              pri->sabme_retrans[0] = 0;
++              q921_send_sabme(pri, now, tei);         
++          }
+       }
+-      /* Reset our interface */
+-      q921_reset(pri);
+-      /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */
+-      q921_send_sabme(pri, now);
+ }
+diff -urN libpri-1.2.2.orig/q931.c libpri-1.2.2/q931.c
+--- libpri-1.2.2.orig/q931.c   2006-01-17 14:43:18.000000000 +0100
++++ libpri-1.2.2/q931.c        2006-01-27 05:41:13.000000000 +0100
+@@ -1,10 +1,12 @@
+ /*
+  * libpri: An implementation of Primary Rate ISDN
+  *
+- * Written by Mark Spencer <markster@digium.com>
++ * Written by Mark Spencer <markster@linux-support.net>
+  *
+- * Copyright (C) 2001-2005, Digium
++ * Copyright (C) 2001, Linux Support Services, Inc.
+  * All Rights Reserved.
++ * Copyright (C) 2003,2004,2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -21,7 +23,7 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+  *
+  */
+-
++ 
+ #include "compat.h"
+ #include "libpri.h"
+ #include "pri_internal.h"
+@@ -31,6 +33,7 @@
+ #include <unistd.h>
+ #include <stdlib.h>
++#include <time.h>
+ #include <string.h>
+ #include <stdio.h>
+ #include <limits.h>
+@@ -205,6 +208,14 @@
+ #define LOC_INTERNATIONAL_NETWORK     0x7
+ #define LOC_NETWORK_BEYOND_INTERWORKING       0xa
++struct q921_call {
++ int tei;     
++ int proc;            
++ int channel; 
++ q921_call *next;
++};
++
++
+ static char *ie2str(int ie);
+ static char *msg2str(int msg);
+@@ -241,6 +252,7 @@
+ static void call_init(struct q931_call *c)
+ {
+       memset(c, 0, sizeof(*c));
++      c->con_acked = 0;
+       c->alive = 0;
+       c->sendhangupack = 0;
+       c->forceinvert = -1;    
+@@ -253,6 +265,10 @@
+       c->next = NULL;
+       c->sentchannel = 0;
+       c->newcall = 1;
++      c->t303timer = 0;
++      c->t303running = 0;
++      c->aoc = 0;
++      c->phones = NULL;
+       c->ourcallstate = Q931_CALL_STATE_NULL;
+       c->peercallstate = Q931_CALL_STATE_NULL;
+ }
+@@ -272,14 +288,17 @@
+ {     
+       int x;
+       int pos=0;
+-#ifdef NO_BRI_SUPPORT
+-      if (!ie->data[0] & 0x20) {
+-              pri_error(pri, "!! Not PRI type!?\n");
+-              return -1;
++      if ((pri->localtype != PRI_CPE) && (pri->localtype != PRI_NETWORK)) {
++ //           pri_error(pri, "!! BRI type %d!?\n",ie->data[0] & 0x03);
++              call->channelno = ie->data[0] & 0x03;
++              if (call->channelno == 3) {
++                  call->channelno = -1; // any channel
++              }
++              return 0;
+       }
+-#endif
+ #ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
+-      switch (ie->data[0] & 3) {
++      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++          switch (ie->data[0] & 3) {
+               case 0:
+                       call->justsignalling = 1;
+                       break;
+@@ -288,6 +307,7 @@
+               default:
+                       pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3);
+                       return -1;
++          }
+       }
+ #endif
+       if (ie->data[0] & 0x08)
+@@ -349,10 +369,16 @@
+       }
+               
+       /* Start with standard stuff */
+-      if (pri->switchtype == PRI_SWITCH_GR303_TMC)
++      if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+               ie->data[pos] = 0x69;
+-      else
++      } else {
++          if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
+               ie->data[pos] = 0xa1;
++          } else {
++              // BRI
++              ie->data[pos] = 0x80;
++          }
++      }
+       /* Add exclusive flag if necessary */
+       if (call->chanflags & FLAG_EXCLUSIVE)
+               ie->data[pos] |= 0x08;
+@@ -369,6 +395,7 @@
+       } else
+               pos++;
+       if ((call->channelno > -1) || (call->slotmap != -1)) {
++          if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
+               /* We'll have the octet 8.2 and 8.3's present */
+               ie->data[pos++] = 0x83;
+               if (call->channelno > -1) {
+@@ -384,11 +411,43 @@
+                       ie->data[pos++] = (call->slotmap & 0xff);
+                       return pos + 2;
+               }
+-      }
++          } else {
++              // BRI
++              // pri_error(pri, "channelno %d, ds1no %d data %d\n",call->channelno,call->ds1no,ie->data[pos-1]);
++              if (pri->localtype == BRI_CPE_PTMP) {
++                  if (msgtype == Q931_SETUP) {
++                      // network, you decide!
++                      if (call->channelno > -1) {
++ //                       ie->data[pos-1] = 0x83;
++                          ie->data[pos-1] = 0x80 | call->channelno;
++                      }
++                  } else {
++                      if (call->channelno > -1) {
++                          ie->data[pos-1] |= call->channelno;
++                      }
++                  }
++              } else {
++                  if (call->channelno > -1) {
++                      ie->data[pos-1] |= call->channelno;
++                  }
++              }
++              return pos + 2;
++          }   
++         } else {
++          if (pri->localtype == BRI_CPE) {
++              ie->data[pos++] = 0x80 | 3;
++              return pos + 2;
++          }
++      }       
++
+       if (call->ds1no > 0) {
+               /* We're done */
+               return pos + 2;
+       }
++      if (msgtype == Q931_RESTART_ACKNOWLEDGE) {
++          /* restart complete interface! */
++          return 0;
++      }       
+       pri_error(pri, "!! No channel map, no channel, and no ds1?  What am I supposed to identify?\n");
+       return -1;
+ }
+@@ -734,8 +793,12 @@
+       return code2str(pres, press, sizeof(press) / sizeof(press[0]));
+ }
+-static void q931_get_number(unsigned char *num, int maxlen, unsigned char *src, int len)
++static void q931_get_number(char *num, int maxlen, unsigned char *src, int len)
+ {
++      if (len < 0) {
++          pri_error(NULL, "q931_get_number received invalid len = %d\n", len);
++          return;
++      }
+       if (len > maxlen - 1) {
+               num[0] = 0;
+               return;
+@@ -746,50 +809,75 @@
+ static FUNC_DUMP(dump_called_party_number)
+ {
+-      unsigned char cnum[256];
+-
+-      q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+-      pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d  TON: %s (%d)  NPI: %s (%d) '%s' ]\n",
+-              prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
++      char cnum[256];
++      if (len >= 3) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++          pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d  TON: %s (%d)  NPI: %s (%d) '%s' ]\n",
++                  prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
++      } else {
++          pri_error(pri, "Called Number (len=%2d) too short.\n", len);
++      }
+ }
+ static FUNC_DUMP(dump_called_party_subaddr)
+ {
+-      unsigned char cnum[256];
+-      q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+-      pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d  Type: %s (%d) O: %d '%s' ]\n",
+-              prefix, len, ie->data[0] >> 7,
+-              subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+-              (ie->data[0] & 0x08) >> 3, cnum);
++      char cnum[256];
++      if (len >= 3) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++          pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d  Type: %s (%d) O: %d '%s' ]\n",
++              prefix, len, ie->data[0] >> 7,
++              subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
++              (ie->data[0] & 0x08) >> 3, cnum);
++      } else {
++          pri_error(pri, "Called Party Subaddress (len=%2d) too short.\n", len);
++      }
+ }
+ static FUNC_DUMP(dump_calling_party_number)
+ {
+-      unsigned char cnum[256];
+-      if (ie->data[0] & 0x80)
+-              q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+-      else
+-              q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+-      pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d  TON: %s (%d)  NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+-      if (ie->data[0] & 0x80)
+-              pri_message(pri, "%c                           Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
+-      else
+-              pri_message(pri, "%c                           Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++      char cnum[256];
++      if ((ie->data[0] & 0x80) && (len >= 3)) {
++              q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++              pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d  TON: %s (%d)  NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++              pri_message(pri, "%c                           Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
++      } else if (len >= 4) {
++              q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++              pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d  TON: %s (%d)  NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++              pri_message(pri, "%c                           Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++      } else {
++          pri_error(pri, "Calling Party Number (len=%2d) too short.\n", len);
++      }
+ }
+ static FUNC_DUMP(dump_calling_party_subaddr)
+ {
+-      unsigned char cnum[256];
+-      q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+-      pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d  Type: %s (%d) O: %d '%s' ]\n",
+-              prefix, len, ie->data[0] >> 7,
+-              subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+-              (ie->data[0] & 0x08) >> 3, cnum);
++      char cnum[256];
++      if (len >= 4) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++          pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d  Type: %s (%d) O: %d '%s' ]\n",
++              prefix, len, ie->data[0] >> 7,
++              subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
++              (ie->data[0] & 0x08) >> 3, cnum);
++      } else {
++          pri_error(pri, "Calling Party Subaddress (len=%2d) too short.\n", len);
++      }
++}
++
++static FUNC_DUMP(dump_colp)
++{
++      char cnum[256];
++      if (len >= 4) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++          pri_message(pri, "%c COLP (len=%2d) [ Ext: %d  TON: %s (%d)  NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++          pri_message(pri, "%c                           Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++      } else {
++          pri_error(pri, "COLP (len=%2d) too short.\n", len);
++      }
+ }
+ static FUNC_DUMP(dump_redirecting_number)
+ {
+-      unsigned char cnum[256];
++      char cnum[256];
+       int i = 0;
+       /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+          walking through all bytes until one with ext bit (8) set to 1 */
+@@ -810,13 +898,17 @@
+               }
+       }
+       while(!(ie->data[i++]& 0x80));
+-      q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+-      pri_message(pri, " '%s' ]\n", cnum);
++      if ((ie->len - i) >= 0) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
++          pri_message(pri, " '%s' ]\n", cnum);
++      } else {
++          pri_error(pri, "Redirecting Number (len=%2d) too short.\n", len);
++      }
+ }
+ static FUNC_DUMP(dump_connected_number)
+ {
+-      unsigned char cnum[256];
++      char cnum[256];
+       int i = 0;
+       /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+          walking through all bytes until one with ext bit (8) set to 1 */
+@@ -833,8 +925,12 @@
+               }
+       }
+       while(!(ie->data[i++]& 0x80));
+-      q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+-      pri_message(pri, " '%s' ]\n", cnum);
++      if ((ie->len - i) >= 0) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
++          pri_message(pri, " '%s' ]\n", cnum);
++      } else {
++          pri_error(pri, "Connected Number (len=%2d) too short.\n", len);
++      }
+ }
+@@ -858,7 +954,7 @@
+               }
+       }
+       while(!(ie->data[i++] & 0x80));
+-      q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
++      q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
+       return 0;
+ }
+@@ -866,7 +962,7 @@
+ {
+       if (order > 1)
+               return 0;
+-      if (call->redirectingnum && *call->redirectingnum) {
++      if (call->redirectingnum && strlen(call->redirectingnum)) {
+               ie->data[0] = call->redirectingplan;
+               ie->data[1] = call->redirectingpres;
+               ie->data[2] = (call->redirectingreason & 0x0f) | 0x80;
+@@ -878,67 +974,90 @@
+ static FUNC_DUMP(dump_redirecting_subaddr)
+ {
+-      unsigned char cnum[256];
+-      q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+-      pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d  Type: %s (%d) O: %d '%s' ]\n",
+-              prefix, len, ie->data[0] >> 7,
+-              subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+-              (ie->data[0] & 0x08) >> 3, cnum);
++      char cnum[256];
++      if (len >= 4) {
++          q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++          pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d  Type: %s (%d) O: %d '%s' ]\n",
++              prefix, len, ie->data[0] >> 7,
++              subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
++              (ie->data[0] & 0x08) >> 3, cnum);
++      } else {
++          pri_error(pri, "Redirecting Subaddress (len=%2d) too short.\n", len);
++      }
+ }
+ static FUNC_RECV(receive_calling_party_subaddr)
+ {
+       /* copy digits to call->callingsubaddr */
+-      q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 2, len - 4);
++      if (len >= 4) {
++          q931_get_number(call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 2, len - 4);
++      } else {
++          pri_error(call->pri, "Calling Party Subaddress (len=%2d) too short.\n", len);
++      }
+       return 0;
+ }
+ static FUNC_RECV(receive_called_party_number)
+ {
+-      /* copy digits to call->callednum */
+-      q931_get_number((unsigned char *) call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
+-      call->calledplan = ie->data[0] & 0x7f;
++      /* copy digits to call->callednum or call->digits */
++      if (len >= 3) {
++          if (msgtype == Q931_INFORMATION) {
++              q931_get_number(call->digits, sizeof(call->digits), ie->data + 1, len - 3);
++          } else {
++              q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
++          }
++          call->calledplan = ie->data[0] & 0x7f;
++      } else {
++          pri_error(call->pri, "Called Party Number (len=%2d) too short.\n", len);
++      }
+       return 0;
+ }
+ static FUNC_SEND(transmit_called_party_number)
+ {
+       ie->data[0] = 0x80 | call->calledplan;
+-      if (*call->callednum)
++      if (strlen(call->callednum)) 
+               memcpy(ie->data + 1, call->callednum, strlen(call->callednum));
+       return strlen(call->callednum) + 3;
+ }
+ static FUNC_RECV(receive_calling_party_number)
+ {
+-      u_int8_t *data;
+-      size_t length;
+-        
+-      if (ie->data[0] & 0x80) {
+-              data = ie->data + 1;
+-              length = len - 3;
+-              call->callerpres = 0; /* PI presentation allowed SI user-provided, not screened */        
+-      } else {
+-              data = ie->data + 2;
+-              length = len - 4;
+-              call->callerpres = ie->data[1] & 0x7f;
+-      }
+-
+-      if (call->callerpres == PRES_ALLOWED_NETWORK_NUMBER ||
+-              call->callerpres == PRES_PROHIB_NETWORK_NUMBER) {
+-              q931_get_number((u_int8_t *)call->callerani, sizeof(call->callerani), data, length);
+-              call->callerplanani = ie->data[0] & 0x7f;
+-
+-              if (!*call->callernum) { /*Copy ANI to CallerID if CallerID is not already set */
+-                      libpri_copy_string(call->callernum, call->callerani, sizeof(call->callernum));
+-                      call->callerplan = call->callerplanani;
+-              }
+-              
+-      } else {
+-              q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length);
+-              call->callerplan = ie->data[0] & 0x7f;
+-      }
++/// callerani!!
++      if (strlen(call->callernum)) {
++          call->callerplanuser = ie->data[0] & 0x7f;
++      } else {
++          call->callerplan = ie->data[0] & 0x7f;
++      }
++        if (ie->data[0] & 0x80) {
++        if (len >= 3) {
++           if (strlen(call->callernum)) {
++              // got A NUM already (this is not 100% correct, but the network should do it this way to protect bad implementations
++               q931_get_number(call->callerani, sizeof(call->callerani), ie->data + 1, len - 3);
++              call->callerpresuser = 0; /* PI presentation allowed
++                                 SI user-provided, not screened */        
++          } else {
++               q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 1, len - 3);
++               call->callerpres = 0; /* PI presentation allowed
++                                 SI user-provided, not screened */        
++          }
++        } else {
++              pri_error(call->pri, "Calling Party Number (len=%2d) too short.\n", len);
++        }
++          } else {
++        if (len >= 4) {
++           if (strlen(call->callernum)) {
++              q931_get_number(call->callerani, sizeof(call->callerani), ie->data + 2, len - 4);
++               call->callerpresuser = ie->data[1] & 0x7f;
++            } else {
++               q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 2, len - 4);
++               call->callerpres = ie->data[1] & 0x7f;
++          }
++        } else {
++              pri_error(call->pri, "Calling Party Number (len=%2d) too short.\n", len);
++        }
++        }
+       return 0;
+ }
+@@ -946,7 +1065,7 @@
+ {
+       ie->data[0] = call->callerplan;
+       ie->data[1] = 0x80 | call->callerpres;
+-      if (*call->callernum) 
++      if (strlen(call->callernum)) 
+               memcpy(ie->data + 2, call->callernum, strlen(call->callernum));
+       return strlen(call->callernum) + 4;
+ }
+@@ -964,11 +1083,58 @@
+ static FUNC_RECV(receive_user_user)
+ {        
+         call->useruserprotocoldisc = ie->data[0] & 0xff;
+-        if (call->useruserprotocoldisc == 4) /* IA5 */
+-          q931_get_number((unsigned char *) call->useruserinfo, sizeof(call->useruserinfo), ie->data + 1, len - 3);
++        if (call->useruserprotocoldisc == 4) { /* IA5 */
++          if (len >= 3) {
++              q931_get_number(call->useruserinfo, sizeof(call->useruserinfo), ie->data + 1, len - 3);
++          } else {
++              pri_error(call->pri, "User-User Information (len=%2d) too short.\n", len);
++          }
++      }
+       return 0;
+ }
++static FUNC_RECV(receive_call_identity)
++{
++      if (len >= 2) {
++          q931_get_number(call->callid, sizeof(call->callid), ie->data, len - 2);
++      } else {
++          pri_error(call->pri, "Call Identity (len=%2d) too short.\n", len);
++      }
++      return 0;
++}
++  
++static FUNC_SEND(transmit_call_identity)
++{
++      if (strlen(call->callid)) 
++              memcpy(ie->data , call->callid, strlen(call->callid));
++      return strlen(call->callednum) + 3;
++}
++
++static FUNC_RECV(receive_high_layer_compat)
++{
++      return 0;
++}
++  
++static FUNC_SEND(transmit_high_layer_compat)
++{
++    if (call->transcapability != PRI_TRANS_CAP_RESTRICTED_DIGITAL && call->transcapability != PRI_TRANS_CAP_DIGITAL && call->transcapability != PRI_TRANS_CAP_DIGITAL_W_TONES) {
++      ie->data[0] = 0x91;
++      ie->data[1] = 0x81;
++      return 4;
++    }
++    return 0;
++}
++
++static FUNC_DUMP(dump_high_layer_compat)
++{
++      int x;
++      pri_message(pri, "%c High-layer compatibilty (len=%2d) [ ", prefix, len);
++      for (x=0;x<ie->len;x++) 
++              pri_message(pri, "0x%02X ", ie->data[x]);
++      pri_message(pri, " ]\n");
++}
++
++
+ static FUNC_SEND(transmit_user_user)
+ {        
+       int datalen = strlen(call->useruserinfo);
+@@ -1050,22 +1216,41 @@
+               data++;
+               len--;
+       }
+-      q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2);
++      if (msgtype == Q931_SETUP) {
++          /* we treat display IEs in the SETUP msg as callername */
++          if (len >= 2) {
++              q931_get_number(call->callername, sizeof(call->callername), data, len - 2);
++          } else {
++              pri_error(call->pri, "Display (len=%2d) too short.\n", len);
++          }
++      } else {
++          /* in other msgs we will pass it as text to chan_zap */
++          if (len >= 2) {
++              q931_get_number(call->display, sizeof(call->display), data, len - 2);
++          } else {
++              pri_error(call->pri, "Display (len=%2d) too short.\n", len);
++          }
++      }
+       return 0;
+ }
+ static FUNC_SEND(transmit_display)
+ {
+       int i;
+-      if ((pri->switchtype != PRI_SWITCH_NI1) && (pri->switchtype != PRI_SWITCH_QSIG) 
+-                      && *call->callername) {
++      int cpe = pri->localtype == BRI_CPE || pri->localtype == BRI_CPE_PTMP || pri->localtype == PRI_CPE;
++      if ((pri->switchtype != PRI_SWITCH_NI1) && (pri->switchtype != PRI_SWITCH_QSIG) && strlen(call->callername) && !cpe) {
+               i = 0;
+               if(pri->switchtype != PRI_SWITCH_EUROISDN_E1) {
+                       ie->data[0] = 0xb1;
+                       ++i;
+               }
+-              memcpy(ie->data + i, call->callername, strlen(call->callername));
+-              return 2 + i + strlen(call->callername);
++              if (msgtype == Q931_SETUP_ACKNOWLEDGE) {
++                  memcpy(ie->data + i, call->display, strlen(call->display));
++                  return 2 + i + strlen(call->display);
++              } else {
++                  memcpy(ie->data + i, call->callername, strlen(call->callername));
++                  return 2 + i + strlen(call->callername);
++              }
+       }
+       return 0;
+ }
+@@ -1112,6 +1297,111 @@
+       return 0;
+ }
++ #if 0
++  static FUNC_RECV(receive_facility_kpj)
++   {
++      unsigned char cpt_tag, cp_len, invoke_id_tag, invoke_id_len, operation_value_len, operation_value_tag;
++      unsigned char arg_len = 0;
++      unsigned char pos = 0;
++      short invoke_id = 0, operation_value = 0;
++      if ((ie->data[pos++] & 0x1F) == 0x11) {
++          /* service discriminator == supplementary services */
++          cpt_tag = ie->data[pos++] & 0x1F;
++          cp_len = ie->data[pos++];
++          switch (cpt_tag) {
++              case 1: /* invoke */
++                      invoke_id_tag = ie->data[pos++];
++                      if (invoke_id_tag != 0x02) {
++                      //    pri_error(call->pri, "invoke id tag != 0x02\n");
++                          break;
++                      }
++                      invoke_id_len = ie->data[pos++]; // 4
++                      while (invoke_id_len > 0) {
++                          invoke_id = (invoke_id << 8) | (ie->data[pos++] & 0xFF);
++                          invoke_id_len--;
++                      }
++                      operation_value_tag = ie->data[pos++];
++                      if (operation_value_tag != 0x02) {
++                      //    pri_error(call->pri, "operation value tag != 0x02\n");
++                          break;
++                      }
++                      operation_value_len = ie->data[pos++];
++                      while (operation_value_len > 0) {
++                          operation_value = (operation_value << 8) | (ie->data[pos++] & 0xFF);
++                          operation_value_len--;
++                      }
++                      arg_len = ie->len - pos;
++                      switch (operation_value) {
++                          case 0x06:  /* ECT execute */
++                                      call->facility = operation_value;
++                                      break;
++                          case 0x0D:  /* call deflection */
++                                      call->facility = operation_value;
++                                      /* dirty hack! */
++                                      arg_len -= 6;
++                                      if (arg_len > 0) {
++                                          pos += 6;
++                                          q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + pos, arg_len);
++                                      }
++                                      /* now retrieve the number */
++                                      break;
++                          case 0x22:  /* AOC-D */
++                                      break;
++                          case 0x24:  /* AOC-E */
++                                      break;
++                      }
++                      break;
++              case 2: /* return result */
++                      break;
++              case 3: /* return error */
++                      break;
++              case 4: /* reject */
++                      break;
++          }
++      } else {
++          /* OLD DIRTY ULAW HACK */
++          if (ie->len < 14) {
++              pri_error(call->pri, "!! Facility message shorter than 14 bytes\n");
++              return 0;
++          }
++          if (ie->data[13] + 14 == ie->len) {
++              q931_get_number(call->callername, sizeof(call->callername) - 1, ie->data + 14, ie->len - 14);
++          } 
++          call->facility = 0x0;
++      }
++      return 0;
++   }
++   
++  static FUNC_SEND(transmit_facility_kpj)
++  {
++      int i = 0;
++      return i;
++      if (call->aoc && (pri->switchtype == PRI_SWITCH_EUROISDN_E1) && ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP) || (pri->localtype == PRI_NETWORK))) {
++          ie->data[0] = 0x90;  /* PP remote operations */
++          ie->data[i++] = 0x00; /* component tag */
++          ie->data[i++] = 0x02; /* invoke id tag */
++          ie->data[i++] = 0x02; /* invoke id len */
++          ie->data[i++] = 0x34; /* invoke id */
++          ie->data[i++] = 0x56; /* invoke id */
++          ie->data[i++] = 0x02; /* operation value tag */
++          ie->data[i++] = 0x01; /* operation value len */
++          switch (msgtype) {
++              case Q931_SETUP:
++                  ie->data[i++] = 0x26; /* operation value AOC-S */
++                  break;
++              case Q931_DISCONNECT:
++                  ie->data[i++] = 0x24; /* operation value AOC-E */
++                  break;
++              default:
++                  ie->data[i++] = 0x22; /* operation value AOC-D */
++                  break;
++          }
++          // ARGUMENTS!       
++      }
++  //  return 2 + i;
++  }
++#endif
++
+ static FUNC_SEND(transmit_facility)
+ {
+       struct apdu_event *tmp;
+@@ -1138,6 +1428,182 @@
+       return i + 2;
+ }
++#if 0
++static FUNC_SEND(transmit_facility)
++{
++      int i = 0, j, first_i, compsp = 0;
++      struct rose_component *comp, *compstk[10];
++      unsigned char namelen = strlen(call->callername);
++
++      if ((pri->switchtype == PRI_SWITCH_NI2) && (namelen > 15))
++              namelen = 15; /* According to GR-1367, for NI2 switches it can't be > 15 characters */
++      if ((namelen > 0) && ((pri->switchtype == PRI_SWITCH_QSIG) ||
++                      ((pri->switchtype == PRI_SWITCH_NI2) && (pri->localtype == PRI_NETWORK)))) {
++              do {
++                      first_i = i;
++                      ie->data[i] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
++                      i++;
++                      /* Interpretation component */
++                      ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, ie->data, i, 0x00 /* Discard unrecognized invokes */);
++
++                      /* Invoke ID */
++                      ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i);
++                      ASN1_PUSH(compstk, compsp, comp);
++
++                      /* Invoke component contents */
++                      /*      Invoke ID */
++                      ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke);
++
++                      /*      Operation Tag */
++                      ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, SS_CNID_CALLINGNAME);
++
++                      /* Arugement Tag */
++                      j = asn1_string_encode(ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE, &ie->data[i], len - i, 15, call->callername, namelen);
++                      if (j < 0) {
++                              i = first_i;
++                              break;
++                      }
++                      i += j;
++
++                      /* Fix length of stacked components */
++                      while(compsp > 0) {
++                              ASN1_FIXUP(compstk, compsp, ie->data, i);
++                      }
++              } while (0);
++      }
++      if (/*(pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&*/ call->redirectingnum && strlen(call->redirectingnum)) {
++              if (!(first_i = i)) {
++                      /* Add protocol information header */
++                      ie->data[i++] = 0x80 | Q932_PROTOCOL_ROSE;
++              }
++
++              /* ROSE invoke component */
++              ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i);
++              ASN1_PUSH(compstk, compsp, comp);
++
++              /* ROSE invokeId component */
++              ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke);
++
++              /* ROSE operationId component */
++              ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ROSE_DIVERTING_LEG_INFORMATION2);
++
++              /* ROSE ARGUMENT component */
++              ASN1_ADD_SIMPLE(comp, 0x30, ie->data, i);
++              ASN1_PUSH(compstk, compsp, comp);
++
++              /* ROSE DivertingLegInformation2.diversionCounter component */
++              /* Always is 1 because other isn't available in the current design */
++              ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, 1);
++
++              /* ROSE DivertingLegInformation2.diversionReason component */
++              ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, redirectingreason_from_q931(pri, call->redirectingreason));
++
++              /* ROSE DivertingLegInformation2.divertingNr component */
++              ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
++              ASN1_PUSH(compstk, compsp, comp);
++
++              /* Redirecting information always not screened */
++              switch(call->redirectingpres) {
++              case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
++              case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
++                      if (call->redirectingnum && strlen(call->redirectingnum)) {
++                              ASN1_ADD_SIMPLE(comp, 0xA0, ie->data, i);
++                              ASN1_PUSH(compstk, compsp, comp);
++
++                              /* NPI of redirected number is not supported in the current design */
++                              ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
++                              ASN1_PUSH(compstk, compsp, comp);
++
++                              ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
++
++                              j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
++                              if (j < 0) {
++                                      i = first_i;
++                                      goto finish2;
++                              }
++                              i += j;
++                              ASN1_FIXUP(compstk, compsp, ie->data, i);
++                              ASN1_FIXUP(compstk, compsp, ie->data, i);
++                              break;
++                      }
++                      /* fall through */
++              case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++              case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++                      ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++                      break;
++              /* Don't know how to handle this */
++              case PRES_ALLOWED_NETWORK_NUMBER:
++              case PRES_PROHIB_NETWORK_NUMBER:
++              case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
++              case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++                      ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++                      break;
++              default:
++                      pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
++              case PRES_NUMBER_NOT_AVAILABLE:
++                      ASN1_ADD_SIMPLE(comp, 0x82, ie->data, i);
++                      break;
++              }
++              ASN1_FIXUP(compstk, compsp, ie->data, i);
++
++              /* ROSE DivertingLegInformation2.originalCalledNr component */
++              /* This information isn't supported by current design - duplicate divertingNr */
++              ASN1_ADD_SIMPLE(comp, 0xA2, ie->data, i);
++              ASN1_PUSH(compstk, compsp, comp);
++
++              /* Redirecting information always not screened */
++              switch(call->redirectingpres) {
++              case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
++              case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
++                      if (call->redirectingnum && strlen(call->redirectingnum)) {
++                              ASN1_ADD_SIMPLE(comp, 0xA0, ie->data, i);
++                              ASN1_PUSH(compstk, compsp, comp);
++
++                              ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
++                              ASN1_PUSH(compstk, compsp, comp);
++
++                              ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
++
++                              j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
++                              if (j < 0) {
++                                      i = first_i;
++                                      goto finish2;
++                              }
++                              i += j;
++                              ASN1_FIXUP(compstk, compsp, ie->data, i);
++                              ASN1_FIXUP(compstk, compsp, ie->data, i);
++                              break;
++                      }
++                      /* fall through */
++              case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++              case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++                      ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++                      break;
++              /* Don't know how to handle this */
++              case PRES_ALLOWED_NETWORK_NUMBER:
++              case PRES_PROHIB_NETWORK_NUMBER:
++              case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
++              case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++                      ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++                      break;
++              default:
++                      pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
++              case PRES_NUMBER_NOT_AVAILABLE:
++                      ASN1_ADD_SIMPLE(comp, 0x82, ie->data, i);
++                      break;
++              }
++              ASN1_FIXUP(compstk, compsp, ie->data, i);
++
++              /* Fix length of stacked components */
++              while(compsp > 0) {
++                      ASN1_FIXUP(compstk, compsp, ie->data, i);
++              }
++      }
++finish2:
++      return (i ? i+2 : 0);
++}
++#endif
++
+ static FUNC_RECV(receive_facility)
+ {
+       int i = 0;
+@@ -1346,6 +1812,7 @@
+       pri_message(pri, " ]\n");
+ }
++
+ static FUNC_DUMP(dump_time_date)
+ {
+       pri_message(pri, "%c Time Date (len=%2d) [ ", prefix, len);
+@@ -1366,39 +1833,60 @@
+ static FUNC_DUMP(dump_keypad_facility)
+ {
+-      char tmp[64];
++      char tmp[64] = "";
+       
+       if (ie->len == 0 || ie->len > sizeof(tmp))
+               return;
+       
+-      libpri_copy_string(tmp, (char *) ie->data, sizeof(tmp));
++      strncpy(tmp, (char *) ie->data, sizeof(tmp));
+       pri_message(pri, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp );
+ }
+ static FUNC_RECV(receive_keypad_facility)
+ {
+-      int mylen;
++      int mylen = 0;
+       if (ie->len == 0)
+               return -1;
+       if (ie->len > (sizeof(call->digitbuf) - 1))
+-              mylen = (sizeof(call->digitbuf) - 1);
++              mylen = sizeof(call->digitbuf) - 1;
+       else
+               mylen = ie->len;
+-      memcpy(call->digitbuf, ie->data, mylen);
++      strncpy(call->digitbuf, (char *) ie->data, mylen);
+-      call->digitbuf[mylen] = 0;
++      /* I must be really neurotic */
++      call->digitbuf[sizeof(call->digitbuf)-1] = '\0';
+       return 0;
+ }
++static FUNC_RECV(receive_time_date)
++{
++    return 0;
++}
++
++static FUNC_SEND(transmit_time_date) {
++    time_t now;
++    struct tm *timedate;
++    time(&now);
++    timedate = localtime(&now);
++    ie->data[0] = timedate->tm_year - 100; // 1900+
++    ie->data[1] = timedate->tm_mon + 1;
++    ie->data[2] = timedate->tm_mday;
++    ie->data[3] = timedate->tm_hour;
++    ie->data[4] = timedate->tm_min;
++    return 7;
++}
++
++
++
+ static FUNC_DUMP(dump_display)
+ {
+       int x, y;
+       char *buf = malloc(len + 1);
+-      char tmp[80];
++      char tmp[80]="";
+       if (buf) {
+               x=y=0;
+               if ((x < ie->len) && (ie->data[x] & 0x80)) {
+@@ -1413,7 +1901,7 @@
+       }
+ }
+-static void dump_ie_data(unsigned char *c, int len)
++static void dump_ie_data(struct pri *pri, unsigned char *c, int len)
+ {
+       char tmp[1024] = "";
+       int x=0;
+@@ -1423,7 +1911,7 @@
+                   ((*c >= 'a') && (*c <= 'z')) ||
+                   ((*c >= '0') && (*c <= '9'))) {
+                       if (!lastascii) {
+-                              if (*tmp) { 
++                              if (strlen(tmp)) { 
+                                       tmp[x++] = ',';
+                                       tmp[x++] = ' ';
+                               }
+@@ -1435,7 +1923,7 @@
+                       if (lastascii) {
+                               tmp[x++] = '\'';
+                       }
+-                      if (*tmp) { 
++                      if (strlen(tmp)) { 
+                               tmp[x++] = ',';
+                               tmp[x++] = ' ';
+                       }
+@@ -1448,14 +1936,14 @@
+       }
+       if (lastascii)
+               tmp[x++] = '\'';
+-      pri_message(NULL, tmp);
++      pri_message(pri, tmp);
+ }
+ static FUNC_DUMP(dump_facility)
+ {
+       pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
+-      dump_ie_data(ie->data, ie->len);
+-      pri_message(NULL, " ]\n");
++      dump_ie_data(pri, ie->data, ie->len);
++      pri_message(pri, " ]\n");
+ }
+ static FUNC_DUMP(dump_network_spec_fac)
+@@ -1465,7 +1953,7 @@
+               pri_message(pri, code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
+       }
+       else
+-              dump_ie_data(ie->data, ie->len);
++              dump_ie_data(pri, ie->data, ie->len);
+       pri_message(pri, " ]\n");
+ }
+@@ -1933,7 +2421,7 @@
+       { 0, Q931_TRANSIT_NET_SELECT, "Transit Network Selection" },
+       { 1, Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator },
+       { 0, Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" },
+-      { 0, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" },
++      { 1, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" , dump_high_layer_compat, receive_high_layer_compat, transmit_high_layer_compat },
+       { 1, Q931_PACKET_SIZE, "Packet Size" },
+       { 1, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility },
+       { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" },
+@@ -1942,11 +2430,11 @@
+       { 1, Q931_IE_INFO_REQUEST, "Feature Request" },
+       { 1, Q931_IE_FEATURE_IND, "Feature Indication" },
+       { 1, Q931_IE_SEGMENTED_MSG, "Segmented Message" },
+-      { 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity },
++      { 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity, receive_call_identity, transmit_call_identity },
+       { 1, Q931_IE_ENDPOINT_ID, "Endpoint Identification" },
+       { 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
+       { 1, Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
+-      { 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
++      { 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date, receive_time_date, transmit_time_date },
+       { 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility", dump_keypad_facility, receive_keypad_facility },
+       { 0, Q931_IE_SIGNAL, "Signal", dump_signal },
+       { 1, Q931_IE_SWITCHHOOK, "Switch-hook" },
+@@ -1954,6 +2442,7 @@
+       { 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" },
+       { 1, Q931_IE_CALL_STATUS, "Call Status" },
+       { 1, Q931_IE_CHANGE_STATUS, "Change Status" },
++      { 1, Q931_COLP, "Connect Line ID Presentation", dump_colp},
+       { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number },
+       { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number },
+       { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number },
+@@ -2024,7 +2513,7 @@
+ {
+       if ((ie->ie & 0x80) != 0)
+               return 1;
+-      else
++      else 
+               return 2 + ie->len;
+ }
+@@ -2054,10 +2543,10 @@
+                       break;
+               case 1:
+                       cr = h->crv[0];
+-                      if (cr & 0x80) {
++              /*      if (cr & 0x80) {
+                               cr &= ~0x80;
+                               cr |= 0x8000;
+-                      }
++                      } */
+                       break;
+               default:
+                       pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
+@@ -2071,14 +2560,14 @@
+       int full_ie = Q931_FULL_IE(codeset, ie->ie);
+       int base_ie;
+-      pri_message(NULL, "%c [", prefix);
+-      pri_message(NULL, "%02x", ie->ie);
++      pri_message(pri, "%c [", prefix);
++      pri_message(pri, "%02x", ie->ie);
+       if (!(ie->ie & 0x80)) {
+-              pri_message(NULL, " %02x", ielen(ie)-2);
++              pri_message(pri, " %02x", ielen(ie)-2);
+               for (x = 0; x + 2 < ielen(ie); ++x)
+-                      pri_message(NULL, " %02x", ie->data[x]);
++                      pri_message(pri, " %02x", ie->data[x]);
+       }
+-      pri_message(NULL, "]\n");
++      pri_message(pri, "]\n");
+       /* Special treatment for shifts */
+       if((full_ie & 0xf0) == Q931_LOCKING_SHIFT)
+@@ -2098,14 +2587,46 @@
+       pri_error(pri, "!! %c Unknown IE %d (len = %d)\n", prefix, base_ie, ielen(ie));
+ }
+-static q931_call *q931_getcall(struct pri *pri, int cr)
++static q921_call *q921_getcall(struct pri *pri, struct q931_call *c, int tei)
++{
++      q921_call *cur;
++      cur = c->phones;
++      while(cur) {
++          if (cur->tei == tei) {
++                  return cur;
++          } 
++          cur = cur->next;
++      }
++      /* No call exists, make a new one */
++      if (pri->debug & PRI_DEBUG_Q921_STATE)
++              pri_message(pri, "-- Making new q921 call for cref %d tei %d\n", c->cr, tei);
++      cur = malloc(sizeof(struct q921_call));
++      memset(cur, 0, sizeof(cur));
++      cur->tei = tei;
++      cur->proc = 0;
++      cur->channel = -1;
++      cur->next = c->phones;
++      c->phones = cur;
++      return cur;
++}
++
++static q931_call *q931_getcall(struct pri *pri, int cr, int tei)
+ {
+       q931_call *cur, *prev;
+       cur = *pri->callpool;
+       prev = NULL;
+       while(cur) {
+-              if (cur->cr == cr)
+-                      return cur;
++              if ((pri->localtype == BRI_NETWORK_PTMP) && (tei >= 0)) {
++                  // hmm...ok, we might be the 1st responding to the setup
++                  // or it is really our call
++                  if ((cur->cr == cr) && ((cur->tei == tei) || (cur->tei == 127)))
++                          return cur;
++                  // or we might not be the 1st responding, then we need to clone
++                  // the call struct to hangup properly
++              } else {
++                  if (cur->cr == cr)
++                          return cur;
++              }
+               prev = cur;
+               cur = cur->next;
+       }
+@@ -2118,6 +2639,7 @@
+               /* Call reference */
+               cur->cr = cr;
+               cur->pri = pri;
++              cur->tei = tei;
+               /* Append to end of list */
+               if (prev)
+                       prev->next = cur;
+@@ -2133,24 +2655,42 @@
+       do {
+               cur = *pri->callpool;
+               pri->cref++;
+-              if (pri->cref > 32767)
+-                      pri->cref = 1;
++              if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++                  if (pri->cref > 32767)
++                          pri->cref = 1;
++              } else {
++                  // BRI
++                  if (pri->cref > 255)
++                          pri->cref = 1;
++              }
+               while(cur) {
+-                      if (cur->cr == (0x8000 | pri->cref))
+-                              break;
++                      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++                          if (cur->cr == (0x8000 | pri->cref))
++                                  break;
++                      } else {
++                          // BRIs have only 1 bye cref
++                          if (cur->cr == (0x80 | pri->cref))
++                                  break;
++                      }
+                       cur = cur->next;
+               }
+       } while(cur);
+-      return q931_getcall(pri, pri->cref | 0x8000);
++      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++          return q931_getcall(pri, pri->cref | 0x8000, 0);
++      } else {
++          // BRI
++          return q931_getcall(pri, pri->cref | 0x80, 0);
++      }
+ }
+-static void q931_destroy(struct pri *pri, int cr, q931_call *c)
++static void q931_destroy(struct pri *pri, int cr, q931_call *c, int tei)
+ {
+       q931_call *cur, *prev;
+       prev = NULL;
+       cur = *pri->callpool;
+       while(cur) {
+-              if ((c && (cur == c)) || (!c && (cur->cr == cr))) {
++//            if ((c && (cur == c)) || (!c && (cur->cr == cr))) {
++              if ((c && (cur == c)) || (!c && ((cur->cr == cr) && ((pri->localtype != BRI_NETWORK_PTMP) || (cur->tei == tei))))) {
+                       if (prev)
+                               prev->next = cur->next;
+                       else
+@@ -2159,6 +2699,8 @@
+                               pri_message(pri, "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
+                       if (cur->retranstimer)
+                               pri_schedule_del(pri, cur->retranstimer);
++                      if (cur->t303timer)
++                              pri_schedule_del(pri, cur->t303timer);
+                       pri_call_apdu_queue_cleanup(cur);
+                       free(cur);
+                       return;
+@@ -2169,16 +2711,16 @@
+       pri_error(pri, "Can't destroy call %d!\n", cr);
+ }
+-static void q931_destroycall(struct pri *pri, int cr)
++static void q931_destroycall(struct pri *pri, int cr, int tei)
+ {
+-      return q931_destroy(pri, cr, NULL);
++      return q931_destroy(pri, cr, NULL, tei);
+ }
+ void __q931_destroycall(struct pri *pri, q931_call *c) 
+ {
+       if (pri && c)
+-              q931_destroy(pri,0, c);
++              q931_destroy(pri,0, c, c->tei);
+       return;
+ }
+@@ -2290,6 +2832,10 @@
+ {
+       unsigned int x;
+       int full_ie = Q931_FULL_IE(codeset, ie->ie);
++      if (ielen(ie) > Q931_IE_MAX_LEN) {
++          pri_error(pri, "!! Invalid IE length %d (len = %d)\n", full_ie, ielen(ie));
++          return -1;
++      }
+       if (pri->debug & PRI_DEBUG_Q931_STATE)
+               pri_message(pri, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
+       for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
+@@ -2307,21 +2853,36 @@
+       return -1;
+ }
+-static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len)
++static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len, int briflag)
+ {
+       /* Returns header and message header and modifies length in place */
+       q931_h *h = (q931_h *)buf;
+-      q931_mh * mh = (q931_mh *)(h->contents + 2);
++      q931_mh *mh;
+       h->pd = pri->protodisc;
+       h->x0 = 0;              /* Reserved 0 */
+-      h->crlen = 2;   /* Two bytes of Call Reference.  Invert the top bit to make it from our sense */
+-      if (call->cr || call->forceinvert) {
++
++      if (briflag == 1) {
++          mh = (q931_mh *)(h->contents + 1);
++          h->crlen = 1;       /* One bytes of Call Reference.  Invert the top bit to make it from our sense */
++          if (call->cr || call->forceinvert) {
++              h->crv[0] = (call->cr ^ 0x80);
++          } else {
++              /* Unless of course this has no call reference */
++              h->crv[0] = 0;
++          }
++          *len -= 4;
++      } else {
++          mh = (q931_mh *)(h->contents + 2);
++                  h->crlen = 2;       /* Two bytes of Call Reference.  Invert the top bit to make it from our sense */
++          if (call->cr || call->forceinvert) {
+               h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8;
+               h->crv[1] = (call->cr & 0xff);
+-      } else {
++          } else {
+               /* Unless of course this has no call reference */
+               h->crv[0] = 0;
+               h->crv[1] = 0;
++          }
++          *len -= 5;
+       }
+       if (pri->subchannel) {
+               /* On GR-303, top bit is always 0 */
+@@ -2330,13 +2891,23 @@
+       mh->f = 0;
+       *hb = h;
+       *mhb = mh;
+-      *len -= 5;
+-      
+ }
+-static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr)
++static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr, int tei)
+ {
+-      q921_transmit_iframe(pri, h, len, cr);
++      q931_mh *mh;
++      if (pri->localtype == BRI_NETWORK_PTMP) {
++          mh = (q931_mh *)(h->contents + 1);
++          if (mh->msg == Q931_SETUP) {
++              q921_transmit_uframe(pri, h, len, cr, tei);
++          } else {
++              q921_transmit_iframe(pri, h, len, cr, tei);
++          }
++      } else if (pri->localtype == BRI_CPE_PTMP) {
++          q921_transmit_iframe(pri, h, len, cr, pri->tei);
++      } else {
++          q921_transmit_iframe(pri, h, len, cr, tei);
++      }
+       /* The transmit operation might dump the q921 header, so logging the q931
+          message body after the transmit puts the sections of the message in the
+          right order in the log */
+@@ -2362,7 +2933,11 @@
+       
+       memset(buf, 0, sizeof(buf));
+       len = sizeof(buf);
+-      init_header(pri, c, buf, &h, &mh, &len);
++      if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++          init_header(pri, c, buf, &h, &mh, &len, 0);
++      } else {
++          init_header(pri, c, buf, &h, &mh, &len, 1);
++      }
+       mh->msg = msgtype;
+       x=0;
+       codeset = 0;
+@@ -2397,11 +2972,34 @@
+       }
+       /* Invert the logic */
+       len = sizeof(buf) - len;
+-      q931_xmit(pri, h, len, 1);
++      if (pri->localtype == BRI_CPE_PTMP) {
++          q931_xmit(pri, h, len, 1, pri->tei);
++      } else {
++          q931_xmit(pri, h, len, 1, c->tei);
++      }
+       c->acked = 1;
+       return 0;
+ }
++static int facility_ies[] = { Q931_IE_FACILITY, -1 };
++
++#if 0
++int q931_facility_kpj(struct pri *pri, q931_call *c, int operation, char *arguments)
++{
++      switch (operation) {
++          case 0x26:  c->aoc = 1;
++                      break;
++          case 0x24:  c->aoc = 1;
++                      break;
++          case 0x22:  c->aoc = 1;
++                      break;
++          default:
++              return -1;
++      }
++      return send_message(pri, c, Q931_FACILITY, facility_ies);
++}
++#endif
++
+ static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 };
+ static int q931_status(struct pri *pri, q931_call *c, int cause)
+@@ -2439,17 +3037,45 @@
+       return send_message(pri, c, Q931_INFORMATION, information_ies);
+ }
++static int information_display_ies[] = { Q931_DISPLAY, -1 };
++
++int q931_information_display(struct pri *pri, q931_call *c, char *display)
++{
++      int res=0;
++      char temp[256];
++      if (!display) return -1;
++      strncpy(temp, c->callername, sizeof(temp));
++      strncpy(c->callername, display, sizeof(c->callername));
++      res = send_message(pri, c, Q931_INFORMATION, information_display_ies);
++      strncpy(c->callername, temp, sizeof(c->callername));
++      return res;
++}
++
++int q931_add_display(struct pri *pri, q931_call *c, char *display)
++{
++      strncpy(c->display, display, sizeof(c->display));
++      return 0;
++}
++
++/* static int information_special_ies[] = { Q931_IE_SPECIAL, -1 };
++static int q931_information_special(struct pri *pri, q931_call *c)
++{
++      return send_message(pri, c, Q931_FACILITY, information_special_ies);
++}
++*/
++
++
+ static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
+ static int restart_ack(struct pri *pri, q931_call *c)
+ {
+       c->ourcallstate = Q931_CALL_STATE_NULL;
+       c->peercallstate = Q931_CALL_STATE_NULL;
++        c->chanflags &= ~FLAG_PREFERRED;
++        c->chanflags |= FLAG_EXCLUSIVE;
+       return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
+ }
+-static int facility_ies[] = { Q931_IE_FACILITY, -1 };
+-
+ int q931_facility(struct pri*pri, q931_call *c)
+ {
+       return send_message(pri, c, Q931_FACILITY, facility_ies);
+@@ -2463,7 +3089,6 @@
+               if ((info > 0x2) || (info < 0x00))
+                       return 0;
+       }
+-
+       if (info >= 0)
+               c->notify = info & 0x7F;
+       else
+@@ -2506,6 +3131,8 @@
+ int q931_call_proceeding(struct pri *pri, q931_call *c, int channel, int info)
+ {
++      // never send two PROCEEDINGs!
++      if (c->proc > 0) return 0;              
+       if (channel) { 
+               c->ds1no = (channel & 0xff00) >> 8;
+               c->ds1explicit = (channel & 0x10000) >> 16;
+@@ -2532,8 +3159,14 @@
+ static int alerting_ies[] = { -1 };
+ #endif
++// static int alerting_BRI_ies[] = { -1 };
++
+ int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
+ {
++      // never send two ALERTINGs!
++      if (c->alert > 0) return 0;             
++      // XXX novo vox hack
++//    if ((!c->proc) && (pri->localtype != BRI_CPE_PTMP))
+       if (!c->proc) 
+               q931_call_proceeding(pri, c, channel, 0);
+       if (info) {
+@@ -2544,11 +3177,127 @@
+               c->progressmask = 0;
+       c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED;
+       c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED;
++      c->alert = 1;
+       c->alive = 1;
+       return send_message(pri, c, Q931_ALERTING, alerting_ies);
++/*    if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++          return send_message(pri, c, Q931_ALERTING, alerting_ies);
++      } else {
++          if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP)) {
++              return send_message(pri, c, Q931_ALERTING, alerting_ies);
++          } else {
++              // no PROGRESS_IND for BRI please
++              return send_message(pri, c, Q931_ALERTING, alerting_BRI_ies);
++          }
++      } */
++}
++
++static int hold_acknowledge_ies[] = { -1 };
++
++int q931_hold_acknowledge(struct pri *pri, q931_call *c)
++{
++      return send_message(pri, c, Q931_HOLD_ACKNOWLEDGE, hold_acknowledge_ies);
++}
++
++static int hold_reject_ies[] = { Q931_CAUSE, -1 };
++
++int q931_hold_reject(struct pri *pri, q931_call *c)
++{
++      c->cause = 12;
++      c->causecode = CODE_CCITT;
++      c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++      return send_message(pri, c, Q931_HOLD_REJECT, hold_reject_ies);
++}
++
++static int retrieve_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 };
++
++int q931_retrieve_acknowledge(struct pri *pri, q931_call *c, int channel)
++{
++      if (channel)
++              c->channelno = channel;
++      c->chanflags &= ~FLAG_PREFERRED;
++      c->chanflags |= FLAG_EXCLUSIVE;
++      return send_message(pri, c, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_acknowledge_ies);
++}
++
++static int retrieve_reject_ies[] = { -1 };
++
++int q931_retrieve_reject(struct pri *pri, q931_call *c)
++{
++      return send_message(pri, c, Q931_RETRIEVE_REJECT, retrieve_reject_ies);
++}
++
++static int suspend_acknowledge_ies[] = { Q931_DISPLAY, -1 };
++
++int q931_suspend_acknowledge(struct pri *pri, q931_call *c, char *display)
++{
++      char tempcallername[256];
++      int res;
++      c->ourcallstate = Q931_CALL_STATE_NULL;
++      c->peercallstate = Q931_CALL_STATE_NULL;
++      strncpy(tempcallername,c->callername,sizeof(tempcallername));
++      strncpy(c->callername,display,sizeof(c->callername));
++      res = send_message(pri, c, Q931_SUSPEND_ACKNOWLEDGE, suspend_acknowledge_ies);
++      strncpy(c->callername,tempcallername,sizeof(c->callername));
++      __q931_destroycall(pri, c);
++      return res;
++}
++
++static int suspend_reject_ies[] = { Q931_DISPLAY, Q931_CAUSE, -1 };
++
++int q931_suspend_reject(struct pri *pri, q931_call *c, char *display)
++{
++      char tempcallername[256];
++      int res;
++      strncpy(tempcallername,c->callername,sizeof(tempcallername));
++      strncpy(c->callername,display,sizeof(c->callername));
++      c->cause = 12;
++      c->causecode = CODE_CCITT;
++      c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++      res = send_message(pri, c, Q931_SUSPEND_REJECT, suspend_reject_ies);
++      strncpy(c->callername,tempcallername,sizeof(c->callername));
++      return res;
++}
++
++static int resume_reject_ies[] = { Q931_CAUSE, Q931_DISPLAY,  -1 };
++
++int q931_resume_reject(struct pri *pri, q931_call *c, char *display)
++{
++      char tempcallername[256];
++      int res;
++      c->cause = 12;
++      c->causecode = CODE_CCITT;
++      c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++      strncpy(tempcallername,c->callername,sizeof(tempcallername));
++      strncpy(c->callername,display,sizeof(c->callername));
++      res = send_message(pri, c, Q931_RESUME_REJECT, resume_reject_ies);
++      strncpy(c->callername,tempcallername,sizeof(c->callername));
++      return res;
++}
++
++static int resume_acknowledge_ies[] = { Q931_CHANNEL_IDENT, Q931_DISPLAY,  -1 };
++
++int q931_resume_acknowledge(struct pri *pri, q931_call *c, int channel, char *display)
++{
++      char tempcallername[256];
++      int res;
++      if (channel)
++              c->channelno = channel;
++      c->chanflags &= ~FLAG_PREFERRED;
++      c->chanflags |= FLAG_EXCLUSIVE;
++      c->alive = 1;
++      c->ourcallstate = Q931_CALL_STATE_ACTIVE;
++      c->peercallstate = Q931_CALL_STATE_ACTIVE;
++      strncpy(tempcallername,c->callername,sizeof(tempcallername));
++      strncpy(c->callername,display,sizeof(c->callername));
++      res = send_message(pri, c, Q931_RESUME_ACKNOWLEDGE, resume_acknowledge_ies);
++      strncpy(c->callername,tempcallername,sizeof(c->callername));
++      return res;
+ }
+-static int connect_ies[] = {  Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
++
++static int connect_ies[] = {  Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, Q931_DISPLAY, -1 };
++static int connect_NET_ies[] = {  Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, Q931_IE_TIME_DATE, -1 };
+  
+ int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
+ {
+@@ -2569,9 +3318,36 @@
+       c->ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
+       c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
+       c->alive = 1;
++      if (pri->localtype == BRI_NETWORK_PTMP) {
++              c->progloc = LOC_PRIV_NET_LOCAL_USER;
++              c->progcode = CODE_CCITT;
++              c->progress = Q931_PROG_INBAND_AVAILABLE;
++      }
+       return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
+ }
++static void pri_setup_response_timeout(void *data)
++{
++      struct q931_call *c = data;
++      struct pri *pri = NULL;
++      if (!c) return;
++      pri = c->pri;
++      if (!pri) return;
++      c->alive = 1;
++      c->cause = PRI_CAUSE_NO_USER_RESPONSE;
++      if (pri->debug & PRI_DEBUG_Q931_STATE)
++              pri_message(pri, "No response to SETUP message\n");
++      pri->schedev = 1;
++      pri->ev.e = PRI_EVENT_HANGUP;
++      pri->ev.hangup.channel = c->channelno;
++      pri->ev.hangup.cref = c->cr;
++      pri->ev.hangup.aoc_units = -1;
++//    pri->ev.hangup.cause = c->cause;
++      pri->ev.hangup.cause = PRI_CAUSE_SWITCH_CONGESTION;
++      pri->ev.hangup.call = c;
++      q931_hangup(pri, c, c->cause);
++}
++
+ static void pri_connect_timeout(void *data)
+ {
+       struct q931_call *c = data;
+@@ -2624,6 +3400,7 @@
+ int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
+ {
++      int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP;
+       if (channel) { 
+               c->ds1no = (channel & 0xff00) >> 8;
+               c->ds1explicit = (channel & 0x10000) >> 16;
+@@ -2638,16 +3415,29 @@
+               c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
+       } else
+               c->progressmask = 0;
+-      c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
++      if (network) {
++              /* WE decide when the call is up and active */
++              c->ourcallstate = Q931_CALL_STATE_ACTIVE;
++      } else {
++          c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
++      }
+       c->peercallstate = Q931_CALL_STATE_ACTIVE;
+       c->alive = 1;
++      c->con_acked = 0;
+       /* Setup timer */
+       if (c->retranstimer)
+               pri_schedule_del(pri, c->retranstimer);
+       c->retranstimer = 0;
+-      if ((pri->localtype == PRI_CPE) && (!pri->subchannel))
++      if (!network && (!pri->subchannel)) {
++              /* make sure that CPEs get a CONNECT_ACKNOWLEDGE */
+               c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c);
+-      return send_message(pri, c, Q931_CONNECT, connect_ies);
++      }
++      if ((pri->localtype != PRI_CPE) && (pri->localtype != BRI_CPE) && (pri->localtype != BRI_CPE_PTMP)) {
++          // networks may send datetime
++          return send_message(pri, c, Q931_CONNECT, connect_NET_ies);
++      } else {
++          return send_message(pri, c, Q931_CONNECT, connect_ies);
++      }
+ }
+ static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 };
+@@ -2681,7 +3471,7 @@
+ int q931_restart(struct pri *pri, int channel)
+ {
+       struct q931_call *c;
+-      c = q931_getcall(pri, 0 | 0x8000);
++      c = q931_getcall(pri, 0 | 0x8000, 0);
+       if (!c)
+               return -1;
+       if (!channel)
+@@ -2718,9 +3508,15 @@
+               return 0;
+ }
++//static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_DISPLAY, Q931_PROGRESS_INDICATOR,
++//     Q931_IE_SIGNAL, Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 };
++
+ static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, Q931_DISPLAY, Q931_IE_USER_USER,
+       Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_REDIRECTING_NUMBER, Q931_SENDING_COMPLETE, Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, -1 };
++static int setup_bri_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, Q931_DISPLAY, Q931_IE_USER_USER,
++      Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_REDIRECTING_NUMBER, Q931_SENDING_COMPLETE, Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, Q931_HIGH_LAYER_COMPAT, -1 };
++
+ static int gr303_setup_ies[] =  { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 };
+ static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 };
+@@ -2728,7 +3524,12 @@
+ int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
+ {
+       int res;
+-      
++
++      if (pri->localtype == BRI_NETWORK_PTMP) {
++          c->tei = 127;
++      } else {
++          c->tei = 0;
++      }
+       
+       c->transcapability = req->transmode;
+       c->transmoderate = TRANS_MODE_64_CIRCUIT;
+@@ -2754,12 +3555,12 @@
+       else if (c->channelno)
+               c->chanflags = FLAG_PREFERRED;
+       if (req->caller) {
+-              libpri_copy_string(c->callernum, req->caller, sizeof(c->callernum));
++              strncpy(c->callernum, req->caller, sizeof(c->callernum) - 1);
+               c->callerplan = req->callerplan;
+               if (req->callername)
+-                      libpri_copy_string(c->callername, req->callername, sizeof(c->callername));
++                      strncpy(c->callername, req->callername, sizeof(c->callername) - 1);
+               else
+-                      c->callername[0] = '\0';
++                      strcpy(c->callername, "");
+               if ((pri->switchtype == PRI_SWITCH_DMS100) ||
+                   (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
+                       /* Doesn't like certain presentation types */
+@@ -2768,13 +3569,13 @@
+               }
+               c->callerpres = req->callerpres;
+       } else {
+-              c->callernum[0] = '\0';
+-              c->callername[0] = '\0';
++              strcpy(c->callernum, "");
++              strcpy(c->callername, "");
+               c->callerplan = PRI_UNKNOWN;
+               c->callerpres = PRES_NUMBER_NOT_AVAILABLE;
+       }
+       if (req->redirectingnum) {
+-              libpri_copy_string(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum));
++              strncpy(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum) - 1);
+               c->redirectingplan = req->redirectingplan;
+               if ((pri->switchtype == PRI_SWITCH_DMS100) ||
+                   (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
+@@ -2785,13 +3586,13 @@
+               c->redirectingpres = req->redirectingpres;
+               c->redirectingreason = req->redirectingreason;
+       } else {
+-              c->redirectingnum[0] = '\0';
++              strcpy(c->redirectingnum, "");
+               c->redirectingplan = PRI_UNKNOWN;
+               c->redirectingpres = PRES_NUMBER_NOT_AVAILABLE;
+               c->redirectingreason = PRI_REDIR_UNKNOWN;
+       }
+       if (req->called) {
+-              libpri_copy_string(c->callednum, req->called, sizeof(c->callednum));
++              strncpy(c->callednum, req->called, sizeof(c->callednum) - 1);
+               c->calledplan = req->calledplan;
+       } else
+               return -1;
+@@ -2812,14 +3613,19 @@
+               res = send_message(pri, c, Q931_SETUP, gr303_setup_ies);
+       else if (c->justsignalling)
+               res = send_message(pri, c, Q931_SETUP, cis_setup_ies);
++      else if (pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP) 
++              res = send_message(pri, c, Q931_SETUP, setup_bri_ies);
+       else
+               res = send_message(pri, c, Q931_SETUP, setup_ies);
++
+       if (!res) {
+               c->alive = 1;
+               /* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */
+               c->sendhangupack = 1;
+               c->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
+               c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;     
++              c->t303timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T303], pri_setup_response_timeout, c);
++              c->t303running = 1;
+       }
+       return res;
+       
+@@ -2835,7 +3641,11 @@
+       if (cause > -1) {
+               c->cause = cause;
+               c->causecode = CODE_CCITT;
+-              c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++              if ((pri->localtype == PRI_NETWORK) || (pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP)) {
++                  c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++              } else {
++                  c->causeloc = LOC_USER;
++              }
+               /* release_ies has CAUSE in it */
+               res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies);
+       } else
+@@ -2860,6 +3670,117 @@
+       return 0;
+ }
++/* here we cleanly hangup the phones that responded to our call but didnt get the call  */
++int q921_hangup(struct pri *pri, q931_call *c, int tei)
++{
++ q921_call *cur,*prev;
++ int tc;
++ int ttei;
++ int res=0;
++
++ if (!pri || !c)
++    return -1;
++ 
++ if (pri->localtype != BRI_NETWORK_PTMP){
++      return 0;
++ }
++//    pri_error(pri, "q921_hangup(%d, %d)\n", c->cr, tei);
++
++ if (tei == 127) {
++      tei = c->tei;
++ }
++//    pri_error(pri, "tei %d\n", tei);
++
++ cur = c->phones;
++ 
++ tc = c->cause;
++ ttei = c->tei;
++ while (cur) {
++      if (cur->tei != tei) {
++          c->cause = PRI_CAUSE_NORMAL_CLEARING;
++          c->tei = cur->tei;
++          if (pri->debug & PRI_DEBUG_Q921_STATE)
++              pri_message(pri, "sending RELEASE for TEI %d\n", cur->tei);
++          send_message(pri, c, Q931_RELEASE, release_ies);
++      }
++      prev = cur;
++      cur = cur->next;
++      if (prev) {
++          free(prev);
++          prev = NULL;
++      }
++ }
++     c->phones = NULL;
++     c->tei = ttei;
++     c->cause = tc;
++
++ if (c->tei == 127) {
++      q931_destroycall(pri, c->cr, c->tei);
++      // make sure * frees the channel
++/*    pri_error(pri, "returning PRI_EVENT_HANGUP_ACK\n");
++      res = Q931_RES_HAVEEVENT;
++      pri->ev.hangup.channel = c->channelno;
++      pri->ev.e = PRI_EVENT_HANGUP_ACK;   */
++ } 
++ return res; 
++}
++
++/* here we handle release_completes from the phones 
++    because some (elmeg) phones do not send a disconnect
++    message when the phone is busy */
++int q921_handle_hangup(struct pri *pri, q931_call *c, int tei)
++{
++     q921_call *cur,*match,*prev=NULL;
++     int left=0;
++     int res=0;
++     
++     if (!pri || !c)
++      return -1;
++ 
++     if (pri->localtype != BRI_NETWORK_PTMP){
++      return 0;
++     }
++ 
++     cur = c->phones;
++     
++     while (cur) {
++      if (cur->tei == tei) {
++          match = cur;
++          if (prev) {
++              prev->next = cur->next;
++              cur = prev;
++          } else {
++              c->phones = cur->next;
++          }
++          free(match);
++      }
++      prev = cur;
++      if (cur) cur = cur->next;
++     }
++ 
++     cur = c->phones;
++     
++     while (cur) {
++      left++;
++      cur = cur->next;
++     }
++     
++     // if all phones have signalled busy AND the timer is not running anymore!
++     if ((left==0) && (c->cause == PRI_CAUSE_USER_BUSY) && (c->t303running == 0)) {
++ //   pri_error(pri, "q921_handle_hangup(%d, %d, %d)\n", c->cr, tei, c->tei);
++      // make sure * frees the channel
++      res = Q931_RES_HAVEEVENT;
++      pri->ev.hangup.cause = PRI_CAUSE_USER_BUSY;
++      pri->ev.hangup.channel = c->channelno | (c->ds1no << 8);
++      pri->ev.hangup.cref = c->cr;                    
++      pri->ev.hangup.call = c;
++      pri->ev.e = PRI_EVENT_HANGUP; 
++     } 
++     return res; 
++ }
++
++ 
++
+ int q931_hangup(struct pri *pri, q931_call *c, int cause)
+ {
+       int disconnect = 1;
+@@ -2871,7 +3792,7 @@
+       /* If mandatory IE was missing, insist upon that cause code */
+       if (c->cause == PRI_CAUSE_MANDATORY_IE_MISSING)
+               cause = c->cause;
+-      if (cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81) {
++      if (cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81 || cause == 17) {
+               /* We'll send RELEASE_COMPLETE with these causes */
+               disconnect = 0;
+               release_compl = 1;
+@@ -2885,7 +3806,7 @@
+       case Q931_CALL_STATE_NULL:
+               if (c->peercallstate == Q931_CALL_STATE_NULL)
+                       /* free the resources if we receive or send REL_COMPL */
+-                      q931_destroycall(pri, c->cr);
++                      q931_destroycall(pri, c->cr, c->tei);
+               else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST)
+                       q931_release_complete(pri,c,cause);
+               break;
+@@ -2911,6 +3832,11 @@
+               /* received SETUP_ACKNOWLEDGE */
+               /* send DISCONNECT in general */
+               if (c->peercallstate != Q931_CALL_STATE_NULL && c->peercallstate != Q931_CALL_STATE_DISCONNECT_REQUEST && c->peercallstate != Q931_CALL_STATE_DISCONNECT_INDICATION && c->peercallstate != Q931_CALL_STATE_RELEASE_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART) {
++                      if (pri->localtype == BRI_NETWORK_PTMP) {
++                          if (c->tei == 127) {
++                              break;
++                          }
++                      } 
+                       if (disconnect)
+                               q931_disconnect(pri,c,cause);
+                       else if (release_compl)
+@@ -2926,8 +3852,14 @@
+               break;
+       case Q931_CALL_STATE_DISCONNECT_INDICATION:
+               /* received DISCONNECT */
++              if (pri->localtype == BRI_NETWORK_PTMP) {
++                  if (c->tei == 127) {
++                      break;
++                  }
++              } 
+               if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) {
+                       c->alive = 1;
++//                pri_error(pri, "sending release to %d\n", c->tei);
+                       q931_release(pri,c,cause);
+               }
+               break;
+@@ -2941,19 +3873,17 @@
+               pri_error(pri, "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
+               break;
+       default:
+-              pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n",
+-                        c->ourcallstate,
+-                        callstate2str(c->ourcallstate),
+-                        callstate2str(c->peercallstate));
++              pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
+               return -1;
+       }
+       /* we did handle hangup properly at this point */
+       return 0;
+ }
+-int q931_receive(struct pri *pri, q931_h *h, int len)
++int q931_receive(struct pri *pri, q931_h *h, int len, int tei)
+ {
+       q931_mh *mh;
++      q921_call *l2c;
+       q931_call *c;
+       q931_ie *ie;
+       unsigned int x;
+@@ -2965,6 +3895,7 @@
+       int codeset, cur_codeset;
+       int last_ie[8];
+       struct apdu_event *cur = NULL;
++      int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP;
+       memset(last_ie, 0, sizeof(last_ie));
+       if (pri->debug & PRI_DEBUG_Q931_DUMP)
+@@ -2978,13 +3909,13 @@
+                  KLUDGE this by changing byte 4 from a 0xf (SERVICE) 
+                  to a 0x7 (SERVICE ACKNOWLEDGE) */
+               h->raw[h->crlen + 2] -= 0x8;
+-              q931_xmit(pri, h, len, 1);
++              q931_xmit(pri, h, len, 1, tei);
+               return 0;
+       } else if (h->pd != pri->protodisc) {
+               pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
+               return 0;
+       }
+-      c = q931_getcall(pri, q931_cr(h));
++      c = q931_getcall(pri, q931_cr(h), tei);
+       if (!c) {
+               pri_error(pri, "Unable to locate call %d\n", q931_cr(h));
+               return -1;
+@@ -3002,11 +3933,12 @@
+               c->ri = -1;
+               break;
+       case Q931_FACILITY:
+-              c->callername[0] = '\0';
++              strcpy(c->callername, "");
+               break;
+       case Q931_SETUP:
+               if (pri->debug & PRI_DEBUG_Q931_STATE)
+                       pri_message(pri, "-- Processing Q.931 Call Setup\n");
++              c->tei = tei;
+               c->channelno = -1;
+               c->slotmap = -1;
+               c->chanflags = 0;
+@@ -3022,33 +3954,49 @@
+               c->calledplan = -1;
+               c->callerplan = -1;
+               c->callerpres = -1;
+-              c->callernum[0] = '\0';
+-              c->callednum[0] = '\0';
+-              c->callername[0] = '\0';
++              strcpy(c->callernum, "");
++              strcpy(c->callednum, "");
++              strcpy(c->callername, "");
+               c->callerani[0] = '\0';
+               c->callerplanani = -1;
+-              c->redirectingplan = -1;
+-              c->redirectingpres = -1;
+-              c->redirectingreason = -1;
+-              c->origcalledplan = -1;
+-              c->origcalledpres = -1;
+-              c->origredirectingreason = -1;
+-              c->redirectingnum[0] = '\0';
+-              c->origcallednum[0] = '\0';
+-              c->redirectingname[0] = '\0';
+-              c->origcalledname[0] = '\0';
+-              c->useruserprotocoldisc = -1; 
+-              c->useruserinfo[0] = '\0';
++                c->redirectingplan = -1;
++                c->redirectingpres = -1;
++                c->redirectingreason = -1;
++                c->origcalledplan = -1;
++                c->origcalledpres = -1;
++                c->origredirectingreason = -1;
++              strcpy(c->redirectingnum, "");
++              strcpy(c->origcallednum, "");
++              strcpy(c->redirectingname, "");
++              strcpy(c->origcalledname, "");
++                c->useruserprotocoldisc = -1; 
++              strcpy(c->useruserinfo, "");
+               c->complete = 0;
+               c->nonisdn = 0;
+               c->aoc_units = -1;
+-              /* Fall through */
++              strcpy(c->digits, "");
++              strcpy(c->display, "");
++              c->progress = -1;
++              c->progressmask = 0;
++              break;
+       case Q931_CONNECT:
++              if (c->t303timer) {
++                  c->t303running = 0;
++                  pri_schedule_del(pri, c->t303timer);
++              }
++              c->useruserinfo[0] = '\0';
++              c->t303timer = 0;
++              c->progress = -1;
++              break;
+       case Q931_ALERTING:
+       case Q931_PROGRESS:
+-              c->useruserinfo[0] = '\0';
+-              c->cause = -1;
++              c->useruserinfo[0] = '\0';
+       case Q931_CALL_PROCEEDING:
++              if (c->t303timer) {
++                  c->t303running = 0;
++                  pri_schedule_del(pri, c->t303timer);
++              }
++              c->t303timer = 0;
+               c->progress = -1;
+               c->progressmask = 0;
+               break;
+@@ -3063,16 +4011,21 @@
+               c->causecode = -1;
+               c->causeloc = -1;
+               c->aoc_units = -1;
++              c->useruserinfo[0] = '\0';
+               if (c->retranstimer)
+                       pri_schedule_del(pri, c->retranstimer);
+               c->retranstimer = 0;
+-              c->useruserinfo[0] = '\0';
++              if (c->t303timer) {
++                  c->t303running = 0;
++                  pri_schedule_del(pri, c->t303timer);
++              }
++              c->t303timer = 0;
+               break;
+       case Q931_RELEASE_COMPLETE:
+               if (c->retranstimer)
+-                      pri_schedule_del(pri, c->retranstimer);
++                  pri_schedule_del(pri, c->retranstimer);
+               c->retranstimer = 0;
+-              c->useruserinfo[0] = '\0';
++              c->useruserinfo[0] = '\0';
+       case Q931_STATUS:
+               c->cause = -1;
+               c->causecode = -1;
+@@ -3089,22 +4042,32 @@
+       case Q931_STATUS_ENQUIRY:
+               break;
+       case Q931_SETUP_ACKNOWLEDGE:
++              if (c->t303timer) {
++                  c->t303running = 0;
++                  pri_schedule_del(pri, c->t303timer);
++              }
++              c->t303timer = 0;
+               break;
+       case Q931_NOTIFY:
+               break;
++      case Q931_HOLD:
++              break;
++      case Q931_RETRIEVE:
++              break;
++      case Q931_RESUME:
++              c->tei = tei;
++              break;
++      case Q931_SUSPEND:
++              break;
+       case Q931_USER_INFORMATION:
+       case Q931_SEGMENT:
+       case Q931_CONGESTION_CONTROL:
+-      case Q931_HOLD:
+       case Q931_HOLD_ACKNOWLEDGE:
+       case Q931_HOLD_REJECT:
+-      case Q931_RETRIEVE:
+       case Q931_RETRIEVE_ACKNOWLEDGE:
+       case Q931_RETRIEVE_REJECT:
+-      case Q931_RESUME:
+       case Q931_RESUME_ACKNOWLEDGE:
+       case Q931_RESUME_REJECT:
+-      case Q931_SUSPEND:
+       case Q931_SUSPEND_ACKNOWLEDGE:
+       case Q931_SUSPEND_REJECT:
+               pri_error(pri, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+@@ -3113,7 +4076,7 @@
+               pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+               q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
+               if (c->newcall) 
+-                      q931_destroycall(pri,c->cr);
++                      q931_destroycall(pri,c->cr,c->tei);
+               return -1;
+       }
+       memset(mandies, 0, sizeof(mandies));
+@@ -3193,12 +4156,19 @@
+       missingmand = 0;
+       for (x=0;x<MAX_MAND_IES;x++) {
+               if (mandies[x]) {
+-                      /* check if there is no channel identification when we're configured as network -> that's not an error */
+-                      if (((pri->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) &&
+-                           ((mh->msg != Q931_PROGRESS) || (mandies[x] != Q931_PROGRESS_INDICATOR))) {
+-                              pri_error(pri, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
+-                              missingmand++;
++                  /* check if there is no channel identification when we're configured as network -> that's not an error */
++                  if (network) {
++                      if (((mh->msg == Q931_SETUP) && (mandies[x] == Q931_CHANNEL_IDENT)) ||
++                           ((mh->msg == Q931_PROGRESS) && (mandies[x] == Q931_PROGRESS_INDICATOR))) {
++                          /* according to ets 300 102-1 a progress indicator is mandatory, but so what? ;-)  */
++                      } else {
++                          pri_error(pri, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
++                          missingmand++;
+                       }
++                  } else {
++                      pri_error(pri, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
++                      missingmand++;
++                  }
+               }
+       }
+       
+@@ -3207,7 +4177,7 @@
+       case Q931_RESTART:
+               if (missingmand) {
+                       q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+-                      q931_destroycall(pri, c->cr);
++                      q931_destroycall(pri, c->cr, c->tei);
+                       break;
+               }
+               c->ourcallstate = Q931_CALL_STATE_RESTART;
+@@ -3225,6 +4195,7 @@
+               }
+               /* Must be new call */
+               if (!c->newcall) {
++                      pri_error(pri, "received SETUP message for call that is not a new call (retransmission). \n");
+                       break;
+               }
+               if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN)
+@@ -3242,27 +4213,31 @@
+               pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+               pri->ev.ring.callingpres = c->callerpres;
+               pri->ev.ring.callingplan = c->callerplan;
+-              pri->ev.ring.callingplanani = c->callerplanani;
+               pri->ev.ring.callingplanrdnis = c->redirectingplan;
+               pri->ev.ring.callingplanorigcalled = c->origcalledplan;
+               pri->ev.ring.ani2 = c->ani2;
+-              libpri_copy_string(pri->ev.ring.callingani, c->callerani, sizeof(pri->ev.ring.callingani));
+-              libpri_copy_string(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum));
+-              libpri_copy_string(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname));
++              pri->ev.ring.callingplanani = c->callerplanani;
++              strncpy(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum) - 1);
++              strncpy(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname) - 1);
+               pri->ev.ring.calledplan = c->calledplan;
+-              libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr));
+-              libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum));
+-              libpri_copy_string(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname));
+-              libpri_copy_string(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum));
+-                libpri_copy_string(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum));
+-                libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname));
+-                libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
++              strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1);
++              if (!strlen(c->callednum) && strlen(c->digitbuf)) {
++                  strncpy(pri->ev.ring.callednum, c->digitbuf, sizeof(pri->ev.ring.callednum) - 1);
++              } else {
++                  strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
++              }
++              strncpy(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname) - 1);
++              strncpy(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum) - 1);
++                strncpy(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum) - 1);
++                strncpy(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname) - 1);
++                strncpy(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo) - 1);
+               c->useruserinfo[0] = '\0';
+               pri->ev.ring.redirectingreason = c->redirectingreason;
+               pri->ev.ring.origredirectingreason = c->origredirectingreason;
+               pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE);
+-              pri->ev.ring.cref = c->cr;
++              pri->ev.ring.tei = c->tei;
+               pri->ev.ring.call = c;
++              pri->ev.ring.cref = c->cr;
+               pri->ev.ring.layer1 = c->userl1;
+               pri->ev.ring.complete = c->complete; 
+               pri->ev.ring.ctype = c->transcapability;
+@@ -3275,6 +4250,9 @@
+                       q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+                       break;
+               }
++              if (pri->localtype == BRI_NETWORK_PTMP) {
++                  l2c = q921_getcall(pri, c, tei);
++              }
+               c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED;
+               c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
+               pri->ev.e = PRI_EVENT_RINGING;
+@@ -3295,17 +4273,24 @@
+                       q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE);
+                       break;
+               }
++              /* TEI got the call */
++              c->tei = tei;
+               c->ourcallstate = Q931_CALL_STATE_ACTIVE;
+               c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
+               pri->ev.e = PRI_EVENT_ANSWER;
+               pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+               pri->ev.answer.cref = c->cr;
+               pri->ev.answer.call = c;
++              pri->ev.answer.tei = c->tei;
+               pri->ev.answer.progress = c->progress;
+               pri->ev.answer.progressmask = c->progressmask;
+                 libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
+               c->useruserinfo[0] = '\0';
+               q931_connect_acknowledge(pri, c);
++              if (pri->localtype == BRI_NETWORK_PTMP) {
++                  /* Release all other TEIs */
++                  q921_hangup(pri, c, tei);
++              }
+               if (c->justsignalling) {  /* Make sure WE release when we initiatie a signalling only connection */
+                       q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
+                       break;
+@@ -3313,23 +4298,43 @@
+                       return Q931_RES_HAVEEVENT;
+       case Q931_FACILITY:
+               if (c->newcall) {
+-                      q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+-                      break;
+-              }
+-              pri->ev.e = PRI_EVENT_FACNAME;
+-              libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname));
+-              libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum));
+-              pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+-              pri->ev.facname.cref = c->cr;
+-              pri->ev.facname.call = c;
+-#if 0
+-              pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum);
+-#endif
++                      if ((pri->localtype == PRI_CPE) || (pri->localtype == PRI_NETWORK)) {
++                          q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++                      } else {
++                          // BRI uses the dummy cref for sservices like ccnr
++                      }
++                      break;
++              }
++              if (c->facility > 0) {
++                  pri->ev.e = PRI_EVENT_FACILITY;
++                  pri->ev.facility.channel = c->channelno | (c->ds1no << 8);
++                  pri->ev.facility.cref = c->cr;
++                  pri->ev.facility.tei = c->tei;
++                  pri->ev.facility.call = c; 
++                  switch (c->facility) {
++                      case 0x06: /* ECT execute */
++                              pri->ev.facility.operation = 0x06; 
++                          break;
++                      case 0x0D: /* CD */
++                              pri->ev.facility.operation = 0x0D; 
++                              strncpy(pri->ev.facility.forwardnum, c->redirectingnum,  sizeof(pri->ev.facility.forwardnum) - 1);
++                          break;
++                      default:
++                              pri->ev.facility.operation = c->facility; 
++                  }
++              } else {
++                  pri->ev.e = PRI_EVENT_FACNAME;
++                  strncpy(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname) - 1);
++                  strncpy(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingname) - 1);
++                  pri->ev.facname.channel = c->channelno | (c->ds1no << 8);
++                  pri->ev.facname.cref = c->cr;
++                  pri->ev.facname.call = c; 
++              }
+               return Q931_RES_HAVEEVENT;
+       case Q931_PROGRESS:
+               if (missingmand) {
+                       q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+-                      q931_destroycall(pri, c->cr);
++                      q931_destroycall(pri, c->cr, c->tei);
+                       break;
+               }
+               pri->ev.e = PRI_EVENT_PROGRESS;
+@@ -3347,6 +4352,11 @@
+                       q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
+                       break;
+               }
++              if (pri->localtype == BRI_NETWORK_PTMP) {
++                  l2c = q921_getcall(pri, c, tei);
++                  l2c->proc = 1;
++                  l2c->channel = c->channelno;
++              }
+               pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+               if (mh->msg == Q931_CALL_PROCEEDING) {
+                       pri->ev.e = PRI_EVENT_PROCEEDING;
+@@ -3364,16 +4374,21 @@
+                       break;
+               }
+               if (c->ourcallstate != Q931_CALL_STATE_CONNECT_REQUEST) {
++                  if ((c->ourcallstate == Q931_CALL_STATE_ACTIVE) && (c->con_acked == 0) && (network)) {
++                      /* sending a CONNECT_ACKNOWLEDGE is optional for CPEs */
++                  } else {
+                       q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
+-                      break;
++                  }
++                  break;
+               }
+               c->ourcallstate = Q931_CALL_STATE_ACTIVE;
+               c->peercallstate = Q931_CALL_STATE_ACTIVE;
++              c->con_acked = 1;
+               break;
+       case Q931_STATUS:
+               if (missingmand) {
+                       q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+-                      q931_destroycall(pri, c->cr);
++                      q931_destroycall(pri, c->cr, c->tei);
+                       break;
+               }
+               if (c->newcall) {
+@@ -3410,31 +4425,69 @@
+                       if (res)
+                               return res;
+               }
+-              break;
++              if (c->peercallstate != c->sugcallstate) {
++                  pri_error(pri, "updating callstate, peercallstate %d to %d\n", c->peercallstate, c->sugcallstate);
++                  c->peercallstate = c->sugcallstate;
++                  if (c->sugcallstate != Q931_CALL_STATE_ACTIVE) {
++                        /* pass hangup to upper layer! */
++                        if (c->alive) {
++                                pri->ev.e = PRI_EVENT_HANGUP;
++                                res = Q931_RES_HAVEEVENT;
++                                c->alive = 0;
++                        } else if (c->sendhangupack) {
++                                res = Q931_RES_HAVEEVENT;
++                                pri->ev.e = PRI_EVENT_HANGUP_ACK;
++                                q931_hangup(pri, c, c->cause);
++                        } else {
++                                q931_hangup(pri, c, c->cause);
++                                res = 0;
++                      if (res)
++                              return res;
++                        }
++                  }
++                }
++                break;
+       case Q931_RELEASE_COMPLETE:
+-              c->ourcallstate = Q931_CALL_STATE_NULL;
+-              c->peercallstate = Q931_CALL_STATE_NULL;
+-              pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+-              pri->ev.hangup.cref = c->cr;                    
+-              pri->ev.hangup.cause = c->cause;                
+-              pri->ev.hangup.call = c;                        
+-                libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
+-              c->useruserinfo[0] = '\0';
+-              /* Free resources */
+-              if (c->alive) {
+-                      pri->ev.e = PRI_EVENT_HANGUP;
+-                      res = Q931_RES_HAVEEVENT;
+-                      c->alive = 0;
+-              } else if (c->sendhangupack) {
+-                      res = Q931_RES_HAVEEVENT;
+-                      pri->ev.e = PRI_EVENT_HANGUP_ACK;
+-                      pri_hangup(pri, c, c->cause);
+-              } else
+-                      res = 0;
+-              if (res)
+-                      return res;
+-              else
+-                      q931_hangup(pri,c,c->cause);
++              if (pri->localtype != BRI_NETWORK_PTMP) {
++                  /* only stop the T303 timer if WE are not a BRI PTMP network */
++                  if (c->t303timer) {
++                      c->t303running = 0;
++                      pri_schedule_del(pri, c->t303timer);
++                      c->t303timer = 0;
++                  }
++              }
++
++              if ((pri->localtype != BRI_NETWORK_PTMP) || (c->tei == tei)) {
++                  c->ourcallstate = Q931_CALL_STATE_NULL;
++                  c->peercallstate = Q931_CALL_STATE_NULL;
++                  pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
++                  pri->ev.hangup.cref = c->cr;                        
++                  pri->ev.hangup.cause = c->cause;                    
++                  pri->ev.hangup.call = c;                            
++                  libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
++                  c->useruserinfo[0] = '\0';
++                  /* Free resources */
++                  if (c->alive) {
++                      pri->ev.e = PRI_EVENT_HANGUP;
++                      res = Q931_RES_HAVEEVENT;
++                      c->alive = 0;
++                  } else if (c->sendhangupack) {
++                      res = Q931_RES_HAVEEVENT;
++                      pri->ev.e = PRI_EVENT_HANGUP_ACK;
++                      pri_hangup(pri, c, c->cause);
++                  } else
++                      res = 0;
++                  if (res)
++                      return res;
++                  else
++                      q931_hangup(pri,c,c->cause);
++              } else {
++                  // BRI_NET_PTMP
++                  // ignoring relase_complete
++                  res = q921_handle_hangup(pri,c,tei);
++                  if (res)
++                      return res;
++              }
+               break;
+       case Q931_RELEASE:
+               if (missingmand) {
+@@ -3450,6 +4503,7 @@
+               pri->ev.e = PRI_EVENT_HANGUP;
+               pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+               pri->ev.hangup.cref = c->cr;
++              pri->ev.hangup.tei = c->tei;
+               pri->ev.hangup.cause = c->cause;
+               pri->ev.hangup.call = c;
+               pri->ev.hangup.aoc_units = c->aoc_units;
+@@ -3478,8 +4532,14 @@
+               pri->ev.e = PRI_EVENT_HANGUP_REQ;
+               pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+               pri->ev.hangup.cref = c->cr;
++              pri->ev.hangup.tei = c->tei;
+               pri->ev.hangup.cause = c->cause;
+               pri->ev.hangup.call = c;
++              if (c->progressmask & PRI_PROG_INBAND_AVAILABLE) {
++                  pri->ev.hangup.inband_progress = 1;
++              } else {
++                  pri->ev.hangup.inband_progress = 0;
++              }
+               pri->ev.hangup.aoc_units = c->aoc_units;
+               if (c->alive)
+                       return Q931_RES_HAVEEVENT;
+@@ -3505,14 +4565,14 @@
+                       pri->ev.e = PRI_EVENT_KEYPAD_DIGIT;
+                       pri->ev.digit.call = c;
+                       pri->ev.digit.channel = c->channelno | (c->ds1no << 8);
+-                      libpri_copy_string(pri->ev.digit.digits, c->digitbuf, sizeof(pri->ev.digit.digits));
++                      strncpy(pri->ev.digit.digits, c->digitbuf, sizeof(pri->ev.digit.digits));
+                       return Q931_RES_HAVEEVENT;
+               }
+               pri->ev.e = PRI_EVENT_INFO_RECEIVED;
+               pri->ev.ring.call = c;
+               pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+-              libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum));
+-              libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr));
++              strncpy(pri->ev.ring.callednum, c->digits, sizeof(pri->ev.ring.callednum) - 1);
++              strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1);
+               pri->ev.ring.complete = c->complete;    /* this covers IE 33 (Sending Complete) */
+               return Q931_RES_HAVEEVENT;
+       case Q931_STATUS_ENQUIRY:
+@@ -3530,7 +4590,7 @@
+               c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
+               pri->ev.e = PRI_EVENT_SETUP_ACK;
+               pri->ev.setup_ack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+-
++              pri->ev.setup_ack.call = c;
+               cur = c->apdus;
+               while (cur) {
+                       if (!cur->sent && cur->message == Q931_FACILITY) {
+@@ -3546,19 +4606,53 @@
+               pri->ev.notify.channel = c->channelno;
+               pri->ev.notify.info = c->notify;
+               return Q931_RES_HAVEEVENT;
++      case Q931_HOLD:
++              pri->ev.e = PRI_EVENT_HOLD_REQ;
++              pri->ev.hold_req.call = c;
++              pri->ev.hold_req.cref = c->cr;
++              pri->ev.hold_req.tei = c->tei;
++              pri->ev.hold_req.channel = c->channelno;
++              return Q931_RES_HAVEEVENT;
++              break;
++      case Q931_RETRIEVE:
++              pri->ev.e = PRI_EVENT_RETRIEVE_REQ;
++              pri->ev.retrieve_req.call = c;
++              pri->ev.retrieve_req.cref = c->cr;
++              pri->ev.retrieve_req.tei = c->tei;
++              pri->ev.retrieve_req.channel = c->channelno;
++              return Q931_RES_HAVEEVENT;
++              break;
++      case Q931_SUSPEND:
++              pri->ev.e = PRI_EVENT_SUSPEND_REQ;
++              pri->ev.suspend_req.call = c;
++              pri->ev.suspend_req.cref = c->cr;
++              pri->ev.suspend_req.tei = c->tei;
++              pri->ev.suspend_req.channel = c->channelno;
++              strncpy(pri->ev.suspend_req.callid, c->callid, sizeof(pri->ev.suspend_req.callid) - 1);
++              return Q931_RES_HAVEEVENT;
++              break;
++      case Q931_RESUME:
++              if (pri->localtype == BRI_NETWORK_PTMP) {
++                  l2c = q921_getcall(pri, c, tei);
++              }
++              c->newcall = 0;
++              pri->ev.e = PRI_EVENT_RESUME_REQ;
++              pri->ev.resume_req.call = c;
++              pri->ev.resume_req.cref = c->cr;
++              pri->ev.resume_req.tei = c->tei;
++              pri->ev.resume_req.channel = c->channelno;
++              strncpy(pri->ev.resume_req.callid, c->callid, sizeof(pri->ev.resume_req.callid) - 1);
++              return Q931_RES_HAVEEVENT;
++              break;
+       case Q931_USER_INFORMATION:
+       case Q931_SEGMENT:
+       case Q931_CONGESTION_CONTROL:
+-      case Q931_HOLD:
+       case Q931_HOLD_ACKNOWLEDGE:
+       case Q931_HOLD_REJECT:
+-      case Q931_RETRIEVE:
+       case Q931_RETRIEVE_ACKNOWLEDGE:
+       case Q931_RETRIEVE_REJECT:
+-      case Q931_RESUME:
+       case Q931_RESUME_ACKNOWLEDGE:
+       case Q931_RESUME_REJECT:
+-      case Q931_SUSPEND:
+       case Q931_SUSPEND_ACKNOWLEDGE:
+       case Q931_SUSPEND_REJECT:
+               pri_error(pri, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+@@ -3568,7 +4662,7 @@
+               pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+               q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
+               if (c->newcall) 
+-                      q931_destroycall(pri,c->cr);
++                      q931_destroycall(pri,c->cr,c->tei);
+               return -1;
+       }
+       return 0;
diff --git a/src/patches/asterisk-1.2.4-zaptel-bristuff-0.3.0-PRE-1l.patch b/src/patches/asterisk-1.2.4-zaptel-bristuff-0.3.0-PRE-1l.patch
new file mode 100644 (file)
index 0000000..96783c0
--- /dev/null
@@ -0,0 +1,167 @@
+diff -ur zaptel-1.2.3.orig/zaptel.c zaptel-1.2.3/zaptel.c
+--- zaptel-1.2.3.orig/zaptel.c 2005-12-17 03:04:05.000000000 +0100
++++ zaptel-1.2.3/zaptel.c      2006-01-31 09:28:29.000000000 +0100
+@@ -4913,11 +4913,40 @@
+                                       *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+                               }
+                               bytes -= left;
++#ifdef CONFIG_ZAPATA_BRI_DCHANS
++                      } else if (ms->flags & ZT_FLAG_BRIDCHAN) {
++                          /*
++                           * Let's get this right, we want to transmit complete frames only.
++                           * The card driver will do the dirty HDLC work for us.
++                           * txb (transmit buffer) is supposed to be big enough to store one frame
++                           * we will make this as big as the D fifo (1KB or 2KB)
++                           */
++
++                          /* there are 'left' bytes in the user buffer left to transmit */
++                          left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf] - 2;
++                          if (left > ms->maxbytes2transmit) {
++                              memcpy(txb, buf + ms->writeidx[ms->outwritebuf], ms->maxbytes2transmit);
++                              ms->writeidx[ms->outwritebuf] += ms->maxbytes2transmit;
++                              txb += ms->maxbytes2transmit;
++                              ms->bytes2transmit = ms->maxbytes2transmit;
++                              ms->eoftx = 0;
++                          } else {
++                              memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
++                              ms->writeidx[ms->outwritebuf] += left + 2;
++                              txb += left;
++                              ms->bytes2transmit = left;
++                              ms->eoftx = 1;
++                          }
++                          bytes = 0;
++#endif
+                       } else {
+                               memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
+                               ms->writeidx[ms->outwritebuf]+=left;
+                               txb += left;
+                               bytes -= left;
++#if defined(CONFIG_ZAPATA_BRI_DCHANS) 
++                              ms->bytes2transmit=ZT_CHUNKSIZE;
++#endif
+                       }
+                       /* Check buffer status */
+                       if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) {
+@@ -4962,6 +4991,17 @@
+                               /* Transmit a flag if this is an HDLC channel */
+                               if (ms->flags & ZT_FLAG_HDLC)
+                                       fasthdlc_tx_frame_nocheck(&ms->txhdlc);
++#if defined(CONFIG_ZAPATA_BRI_DCHANS) 
++                              if(ms->flags & ZT_FLAG_BRIDCHAN) { 
++                      //          if (ms->bytes2transmit > 0) {
++                                      // txb += 2;
++                                      // ms->bytes2transmit -= 2;
++                                      bytes=0;
++                                      ms->eoftx = 1;
++//                                    printk(KERN_CRIT "zaptel EOF(%d) bytes2transmit %d\n",ms->eoftx,ms->bytes2transmit);
++                      //          }
++                              }
++#endif
+ #ifdef CONFIG_ZAPATA_NET
+                               if (ms->flags & ZT_FLAG_NETDEV)
+                                       netif_wake_queue(ztchan_to_dev(ms));
+@@ -4972,7 +5012,7 @@
+                                       tasklet_schedule(&ms->ppp_calls);
+                               }
+ #endif
+-                      }
++                      } 
+               } else if (ms->curtone && !(ms->flags & ZT_FLAG_PSEUDO)) {
+                       left = ms->curtone->tonesamples - ms->tonep;
+                       if (left > bytes)
+@@ -5018,6 +5058,10 @@
+                               memset(txb, 0xFF, bytes);
+                       }
+                       bytes = 0;
++#if defined(CONFIG_ZAPATA_BRI_DCHANS) 
++              } else if(ms->flags & ZT_FLAG_BRIDCHAN) { 
++                  bytes = 0;
++#endif
+               } else {
+                       memset(txb, ZT_LIN2X(0, ms), bytes);    /* Lastly we use silence on telephony channels */
+                       bytes = 0;
+@@ -5743,6 +5787,13 @@
+       int left, x;
+       int bytes = ZT_CHUNKSIZE;
++#if defined(CONFIG_ZAPATA_BRI_DCHANS) 
++      if (ms->flags & ZT_FLAG_BRIDCHAN) {
++          bytes = ms->bytes2receive;
++          if (bytes < 1) return;
++//        printk(KERN_CRIT "bytes2receive %d\n",ms->bytes2receive);
++      }
++#endif
+       while(bytes) {
+ #if defined(CONFIG_ZAPATA_NET)  || defined(CONFIG_ZAPATA_PPP)
+@@ -5801,6 +5852,19 @@
+                                               }
+                                       }
+                               }
++#ifdef CONFIG_ZAPATA_BRI_DCHANS
++                      } else if (ms->flags & ZT_FLAG_BRIDCHAN) {
++                          memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
++                          rxb += left;
++                          ms->readidx[ms->inreadbuf] += left;
++                          bytes -= left;
++                          if (ms->eofrx == 1) {
++                              eof=1;
++                          }
++//                        printk(KERN_CRIT "receiving %d bytes\n",ms->bytes2receive);
++                          ms->bytes2receive = 0;
++                          ms->eofrx = 0;
++#endif
+                       } else {
+                               /* Not HDLC */
+                               memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
+diff -ur zaptel-1.2.3.orig/zaptel.h zaptel-1.2.3/zaptel.h
+--- zaptel-1.2.3.orig/zaptel.h 2005-12-17 03:04:05.000000000 +0100
++++ zaptel-1.2.3/zaptel.h      2006-01-31 09:28:29.000000000 +0100
+@@ -994,6 +994,13 @@
+       int do_ppp_error;
+       struct sk_buff_head ppp_rq;
+ #endif
++#ifdef CONFIG_ZAPATA_BRI_DCHANS
++      int bytes2receive;
++      int maxbytes2transmit; /* size of the tx buffer in the card driver */
++      int bytes2transmit;
++      int eofrx;
++      int eoftx;
++#endif
+       spinlock_t lock;
+       char name[40];          /* Name */
+       /* Specified by zaptel */
+@@ -1068,7 +1075,7 @@
+       int             txbufpolicy;                    /* Buffer policy */
+       int             rxbufpolicy;                    /* Buffer policy */
+       int             txdisable;                              /* Disable transmitter */
+-      int     rxdisable;                              /* Disable receiver */
++      int             rxdisable;                              /* Disable receiver */
+       
+       
+       /* Tone zone stuff */
+@@ -1231,6 +1238,10 @@
+ #define ZT_FLAG_T1PPP                 (1 << 15)
+ #define ZT_FLAG_SIGFREEZE             (1 << 16)       /* Freeze signalling */
++#if defined(CONFIG_ZAPATA_BRI_DCHANS) 
++#define ZT_FLAG_BRIDCHAN              (1 << 17)
++#endif
++
+ struct zt_span {
+       spinlock_t lock;
+       void *pvt;                      /* Private stuff */
+diff -ur zaptel-1.2.3.orig/zconfig.h zaptel-1.2.3/zconfig.h
+--- zaptel-1.2.3.orig/zconfig.h        2005-11-29 19:42:08.000000000 +0100
++++ zaptel-1.2.3/zconfig.h     2006-01-31 09:28:29.000000000 +0100
+@@ -152,4 +152,10 @@
+  */
+ /* #define FXSFLASH */
++/*
++ * Uncomment the following for BRI D channels
++ *
++ */
++#define CONFIG_ZAPATA_BRI_DCHANS
++
+ #endif