From: ms Date: Fri, 14 Apr 2006 23:12:47 +0000 (+0000) Subject: Hinzugefügt: X-Git-Tag: v2.3-beta1~1152 X-Git-Url: http://git.ipfire.org/?p=ipfire-2.x.git;a=commitdiff_plain;h=5e69ef1ac31ea7ecd4d5f2d833424a61addc4302 Hinzugefügt: * 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 --- diff --git a/doc/packages-list.txt b/doc/packages-list.txt index bd1d335066..b2ab7cd283 100644 --- a/doc/packages-list.txt +++ b/doc/packages-list.txt @@ -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 @@ -93,10 +95,12 @@ * 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 @@ -153,6 +157,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 @@ -165,6 +170,7 @@ * tar-1.13.25 * tcpdump-3.8.3 * texinfo-4.7 + * tiff-3.8.2 * traceroute-1.4a12 * uClibc-0.9.26 * unzip552 @@ -175,4 +181,5 @@ * 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 index 0000000000..8c4bf7a839 --- /dev/null +++ b/lfs/asterisk @@ -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 # +# # +############################################################################### + +############################################################################### +# 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) + diff --git a/lfs/busybox b/lfs/busybox index 7df7c6196d..a9027c4515 100644 --- a/lfs/busybox +++ b/lfs/busybox @@ -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 index 0000000000..c2cabcab6d --- /dev/null +++ b/lfs/edonkeyclc @@ -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 # +# # +# 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 index 0000000000..658d6a2f47 --- /dev/null +++ b/lfs/libtiff @@ -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 # +# # +# 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 index 0000000000..338c2f8326 --- /dev/null +++ b/lfs/libxml2 @@ -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 # +# # +# 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) diff --git a/lfs/postfix b/lfs/postfix index 35244734f8..b92f78ba74 100644 --- a/lfs/postfix +++ b/lfs/postfix @@ -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 index 0000000000..83c0e3bc9f --- /dev/null +++ b/lfs/spandsp @@ -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 # +# # +# 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 5f47f1a2f1..40b49da9ad 100644 --- 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 index 0000000000..e69de29bb2 diff --git a/src/paks/asterisk/ROOTFILES b/src/paks/asterisk/ROOTFILES new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/paks/asterisk/install.sh b/src/paks/asterisk/install.sh new file mode 100644 index 0000000000..3a9ce551bf --- /dev/null +++ b/src/paks/asterisk/install.sh @@ -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 index 0000000000..ad6122665e --- /dev/null +++ b/src/paks/asterisk/uninstall.sh @@ -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 index 0000000000..e69de29bb2 diff --git a/src/paks/edonkeyclc/ROOTFILES b/src/paks/edonkeyclc/ROOTFILES new file mode 100644 index 0000000000..3714bb5eab --- /dev/null +++ b/src/paks/edonkeyclc/ROOTFILES @@ -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 index 0000000000..3a9ce551bf --- /dev/null +++ b/src/paks/edonkeyclc/install.sh @@ -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 index 0000000000..ad6122665e --- /dev/null +++ b/src/paks/edonkeyclc/uninstall.sh @@ -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 index 0000000000..e69de29bb2 diff --git a/src/paks/libtiff/ROOTFILES b/src/paks/libtiff/ROOTFILES new file mode 100644 index 0000000000..87ac9f8648 --- /dev/null +++ b/src/paks/libtiff/ROOTFILES @@ -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 index 0000000000..3a9ce551bf --- /dev/null +++ b/src/paks/libtiff/install.sh @@ -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 index 0000000000..ad6122665e --- /dev/null +++ b/src/paks/libtiff/uninstall.sh @@ -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 index 0000000000..e69de29bb2 diff --git a/src/paks/libxml2/ROOTFILES b/src/paks/libxml2/ROOTFILES new file mode 100644 index 0000000000..e9f76b0293 --- /dev/null +++ b/src/paks/libxml2/ROOTFILES @@ -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 index 0000000000..3a9ce551bf --- /dev/null +++ b/src/paks/libxml2/install.sh @@ -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 index 0000000000..ad6122665e --- /dev/null +++ b/src/paks/libxml2/uninstall.sh @@ -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 index 0000000000..e69de29bb2 diff --git a/src/paks/spandsp/ROOTFILES b/src/paks/spandsp/ROOTFILES new file mode 100644 index 0000000000..4689120101 --- /dev/null +++ b/src/paks/spandsp/ROOTFILES @@ -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 index 0000000000..3a9ce551bf --- /dev/null +++ b/src/paks/spandsp/install.sh @@ -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 index 0000000000..ad6122665e --- /dev/null +++ b/src/paks/spandsp/uninstall.sh @@ -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 index 0000000000..5cbd642641 --- /dev/null +++ b/src/patches/asterisk-1.2.4-iax2-bristuff-0.3.0-PRE-1l.patch @@ -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;xcallno) 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 : ""); + 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(®q, 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 : ""); ++ 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(®threadid, NULL, auth_thread, ®q); ++} ++ + 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(®q.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(®q.lock); ++ ast_cond_init(®q.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 - Asterisk Author ++ * Matthew Boehm - MySQL RealTime Driver Author ++ * ++ * res_config_mysql.c ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 index 0000000000..05aa370966 --- /dev/null +++ b/src/patches/asterisk-1.2.4-ipfire-bristuff-0.3.0-PRE-1l.patch @@ -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 ++ ++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 ++Florian Overkamp ++Gareth Watts ++Jeff Noxon ++Petr Michalek ++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/[@]:[b|B]) ++ ++ now it is: Dial(CAPI/g/[b|B]) ++ or: Dial(CAPI/contr/[b|B]) ++ ++ 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 ++ * ++ * based on eagi-test.c ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef SOLARIS ++#include ++#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 ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 ++ * ++ * This program is free software and may be modified and ++ * distributed under the terms of the GNU Public License. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++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 ++ * ++ * This program is free software and may be modified and ++ * distributed under the terms of the GNU Public License. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++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 ++ * ++ * This program is free software and may be modified and ++ * distributed under the terms of the GNU Public License. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++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 ++ * + * 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 ++ * ++ * Copyright (C) 2004, Florian Overkamp ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 ++ * ++ * This program is free software and may be modified and ++ * distributed under the terms of the GNU Public License. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) ++#include ++#else ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++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; // DOH ++ ++ // 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)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;jdatalen;j++) { ++ buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]]; ++ } ++#else ++ for (j=0;jdatalen;j++) { ++ buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; ++ } ++#endif ++#else ++ if ((i->doES == 1)) { ++ for (j=0;jdatalen;j++) { ++ buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ]; ++ txavg += abs( capiXLAW2INT(reversebits[ ((unsigned char*)fsmooth->data)[j]]) ); ++ } ++ txavg = txavg/j; ++ for(j=0;jtxavg[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;jdatalen;j++) { ++ buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]]; ++ } ++#else ++ for (j=0;jdatalen;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)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;ji->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;ji->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]]; ++ } ++#else ++ for (j=0;ji->g.rxgains[(unsigned char)b3buf[AST_FRIENDLY_OFFSET + j]]]; ++ } ++#else ++ for (j=0;jc->_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)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;ilock)); ++ 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 ++ * + * 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, "\n"); + ast_build_string(&t, &maxbytes, "\n", p->dialogver++, full ? "full":"partial", mto); +- if ((state & AST_EXTENSION_RINGING) && global_notifyringing) +- ast_build_string(&t, &maxbytes, "\n", p->exten); +- else ++ if ((state & AST_EXTENSION_RINGING) && global_notifyringing) { ++ ast_build_string(&t, &maxbytes, "\n", p->exten); ++ if (cid_num) { ++ ast_build_string(&t, &maxbytes, "%s\n", p->exten, p->exten, mfrom); ++ if (cid_name && !ast_strlen_zero(cid_name)) { ++ ast_build_string(&t, &maxbytes, "sip:%s@%s\n", cid_name, cid_num, p->fromdomain, ast_pickup_ext(), p->exten, p->fromdomain); ++ } else { ++ ast_build_string(&t, &maxbytes, "sip:%s@%s\n", cid_num, cid_num, p->fromdomain, ast_pickup_ext(), p->exten, p->fromdomain); ++ } ++ } ++ } else { + ast_build_string(&t, &maxbytes, "\n", p->exten); ++ } + ast_build_string(&t, &maxbytes, "%s\n", statestring); + ast_build_string(&t, &maxbytes, "\n\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; iexten); 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: The peer name you want to send a NOTIFY to.\n" ++" Type: The notify type (see sip_notify.conf).\n" ++" ActionID: 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: missing.\n"); ++ return 0; ++ } ++ notify_type = astman_get_header(m,"Type"); ++ if (ast_strlen_zero(notify_type)) { ++ astman_send_error(s, m, "Type: 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 ++ * ++ * + * 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;dpri->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;xnumchans;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;xnumchans;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; inumchans; 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; inumchans; 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; inumchans; 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; inumchans; 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; inumchans; 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; inumchans; 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 : "", ++ 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 : "", + 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;xpvts[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;xpvts[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= 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 \n" + " Enables debugging on a given PRI span\n"; +@@ -9409,6 +10432,18 @@ + "Usage: pri show span \n" + " Displays PRI Information\n"; + ++static char bri_debug_help[] = ++ "Usage: bri debug span \n" ++ " Enables debugging on a given BRI span\n"; ++ ++static char bri_no_debug_help[] = ++ "Usage: bri no debug span \n" ++ " Disables debugging on a given BRI span\n"; ++ ++static char bri_really_debug_help[] = ++ "Usage: bri intensive debug 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;xtech_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 ++#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 ++ * ++ * 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 ++ * ++ * 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 + #include + #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 ++ * + * 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 : ""); ++ in->idtext, in->tech, in->data, in->context, in->exten, reason, in->uniqueid ? in->uniqueid : (chan ? chan->uniqueid : "")); + 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 : ""); ++ in->idtext, in->tech, in->data, in->context, in->exten, reason, in->uniqueid ? in->uniqueid : (chan ? chan->uniqueid : "")); + + /* 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 ++ * + * 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 ++ * + * 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 : "") +- ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "") ++ ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : ""), 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 : "") +- ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "") ++ ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : ""), 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 : "") +- ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "") ++ ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : ""), 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;xchan->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;xchan->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 : "") +- ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "") ++ ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : ""), 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;xchan->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;xchan->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 ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 index 0000000000..a74496406f --- /dev/null +++ b/src/patches/asterisk-1.2.4-libpri-bristuff-0.3.0-PRE-1l.patch @@ -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 ++libpri: An implementation of Primate Rate ISDN (and BRI ISDN) ++ ++Written by Mark Spencer ++Modified for BRI support by Klaus-Peter Junghanns + + 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 ++ * Written by Mark Spencer + * +- * 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 +- * +- * 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 ++ 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;jlen;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 ++ * Written by Mark Spencer + * +- * 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 ++ * Written by Mark Spencer + * +- * 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 +- + #include "libpri.h" + #include "pri_internal.h" ++#include + + + static int maxsched = 0; +@@ -36,7 +35,7 @@ + int x; + struct timeval tv; + for (x=1;xpri_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;xpri_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;xpri_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;xpri_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 ++ * Written by Mark Spencer + * +- * 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 ++ * Written by Mark Spencer + * +- * 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 + * + * 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 + #include + #include +@@ -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;iq921_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;iq921_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;teiq921_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_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 ++ * Written by Mark Spencer + * +- * 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 + * + * 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 + #include ++#include + #include + #include + #include +@@ -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;xlen;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;xcontents + 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 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 index 0000000000..96783c046c --- /dev/null +++ b/src/patches/asterisk-1.2.4-zaptel-bristuff-0.3.0-PRE-1l.patch @@ -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