--- asterisk-1.2.12.1.dfsg.orig/channels/chan_phone.c +++ asterisk-1.2.12.1.dfsg/channels/chan_phone.c @@ -37,9 +37,6 @@ #include /* Still use some IXJ specific stuff */ #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -# include -#endif #include #include "asterisk.h" --- asterisk-1.2.12.1.dfsg.orig/debian/control +++ asterisk-1.2.12.1.dfsg/debian/control @@ -0,0 +1,164 @@ +Source: asterisk +Priority: optional +Section: comm +Maintainer: Debian VoIP Team +Uploaders: Mark Purcell , Kilian Krause , Jose Carlos Garcia Sogo , Santiago Garcia Mantinan , Simon Richter , Tzafrir Cohen +Standards-Version: 3.6.1 +Build-Depends: debhelper (>= 4.0.4), sed (>= 3.95), zlib1g-dev, libreadline5-dev, libgsm1-dev, libssl-dev, libzap-dev, libtonezone-dev (>= 1:1.2.3-1), bison, libasound2-dev, postgresql-dev, unixodbc-dev, libpri-dev (>= 1.2.3-1), dpatch (>= 2.0.10), zaptel-source (>= 1:1.2.3-1), autotools-dev, libnewt-dev, libsqlite-dev, libspeex-dev, graphviz, libcurl3-dev, doxygen, gsfonts, libpopt-dev, libopenh323-dev (>= 1.17.4-1) + +Package: asterisk +Architecture: all +Section: comm +Depends: asterisk-classic (>= ${source:Version}) | asterisk-bristuff (>= ${source:Version}), adduser (>= 3.63) +Conflicts: asterisk-oh323 (<= 0.6.6pre3-3) +Suggests: gnomemeeting, ekiga, ohphone, kphone, asterisk-doc, asterisk-dev, asterisk-rate-engine +Description: Open Source Private Branch Exchange (PBX) + Asterisk is an Open Source PBX and telephony toolkit. It is, in a + sense, middleware between Internet and telephony channels on the bottom, + and Internet and telephony applications at the top. + . + Asterisk can be used with Voice over IP (SIP, H.323, IAX) standards, or the + Public Switched Telephone Network (PSTN) through Supported Hardware. + . + Supported hardware: + . + * All Wildcard (tm) products from Digium (http://www.digium.com) + * QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net) + * Full Duplex Sound Card supported by Linux + * Adtran Atlas 800 Plus + * ISDN4Linux compatible ISDN card + * Tormenta Dual T1 card (http://www.bsdtelephony.com.mx) + * CAPI compatible ISDN cards can be run using the add-on package chan-capi + . + This Debian package includes the sample configuration, with demonstration + extensions, etc + . + Website: http://www.asterisk.org. + +Package: asterisk-classic +Architecture: any +Section: comm +Depends: ${shlibs:Depends}, asterisk (= ${source:Version}), asterisk-config (= ${source:Version}) | asterisk-config-custom, adduser (>= 3.63), asterisk-sounds-main (>= 1:1.0.2) +Conflicts: asterisk-bristuff +Description: Open Source Private Branch Exchange (PBX) - original Digium version + Asterisk is an Open Source PBX and telephony toolkit. It is, in a + sense, middleware between Internet and telephony channels on the bottom, + and Internet and telephony applications at the top. + . + Asterisk can be used with Voice over IP (SIP, H.323, IAX) standards, or the + Public Switched Telephone Network (PSTN) through Supported Hardware. + . + Supported hardware: + . + * All Wildcard (tm) products from Digium (http://www.digium.com) + * QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net) + * Full Duplex Sound Card supported by Linux + * Adtran Atlas 800 Plus + * ISDN4Linux compatible ISDN card + * Tormenta Dual T1 card (http://www.bsdtelephony.com.mx) + * CAPI compatible ISDN cards can be run using the add-on package chan-capi + . + This Debian package includes the sample configuration, with demonstration + extensions, etc + . + Website: http://www.asterisk.org. + +Package: asterisk-bristuff +Architecture: any +Section: comm +Depends: ${shlibs:Depends}, asterisk (= ${source:Version}), asterisk-config (= ${source:Version}) | asterisk-config-custom, adduser (>= 3.63), asterisk-sounds-main (>= 1:1.0.2) +Conflicts: asterisk-classic +Description: Open Source Private Branch Exchange (PBX) - BRIstuff-enabled version + Asterisk is an Open Source PBX and telephony toolkit. It is, in a + sense, middleware between Internet and telephony channels on the bottom, + and Internet and telephony applications at the top. + . + The BRIstuff patch from www.junghanns.net enables support from certain + hardware like HFC ISDN cards which are mainly consumer hardware. + . + Asterisk can be used with Voice over IP (SIP, H.323, IAX) standards, or the + Public Switched Telephone Network (PSTN) through Supported Hardware. + . + Supported hardware: + . + * All Wildcard (tm) products from Digium (http://www.digium.com) + * QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net) + * Full Duplex Sound Card supported by Linux + * Adtran Atlas 800 Plus + * ISDN4Linux compatible ISDN card + * Tormenta Dual T1 card (http://www.bsdtelephony.com.mx) + * CAPI compatible ISDN cards can be run using the add-on package chan-capi + . + This Debian package includes the sample configuration, with demonstration + extensions, etc + . + Website: http://www.asterisk.org. + +Package: asterisk-h323 +Architecture: any +Recommends: asterisk, asterisk-oh323 +Replaces: asterisk (<= 1:1.0.2-2) +Section: comm +Depends: ${shlibs:Depends} +Description: asterisk H.323 VoIP channel + This package provided h323 support for the Asterisk Open Source PBX system. + . + It was separated out into its own package to avoid having the main package + depend on the many openh323 dependencies. + +Package: asterisk-doc +Recommends: asterisk +Conflicts: asterisk (<=0.1.12-3) +Replaces: asterisk (<=0.1.12-3) +Section: doc +Architecture: all +Description: documentation for asterisk + Asterisk is an Open Source PBX and telephony toolkit. + . + This package contains the source documentation needed if you wish to + extend the asterisk package. + +Package: asterisk-dev +Architecture: all +Recommends: asterisk +Conflicts: asterisk (<=0.1.12-3) +Replaces: asterisk (<=0.1.12-3) +Section: devel +Description: development files for asterisk + Asterisk is an Open Source PBX and telephony toolkit. + . + This package contains the include files used if you wish to compile a + package which requires asterisk source file headers. + +Package: asterisk-sounds-main +Architecture: all +Recommends: asterisk +Conflicts: asterisk (<=0.1.12-3), asterisk-sounds (<= 1:1.0.2-1) +Replaces: asterisk (<=0.4.0-5), asterisk-sounds (<= 1:1.0.2-1), asterisk-sounds-extra +Section: comm +Description: sound files for asterisk + Asterisk is an Open Source PBX and telephony toolkit. + . + This package contains the default sound files for operation of asterisk + +Package: asterisk-web-vmail +Recommends: asterisk +Architecture: all +Depends: httpd-cgi, libapache-dbi-perl | libdbi-perl +Section: comm +Description: Web-based (CGI) voice mail interface for Asterisk + Asterisk is an Open Source PBX and telephony toolkit. + . + This package contains a web-based interface for the voice-mail system + +Package: asterisk-config +Recommends: asterisk +Depends: adduser (>= 3.63) +Replaces: asterisk (<= 1:1.0.2-2) +Conflicts: asterisk-config-custom +Architecture: all +Section: comm +Description: config files for asterisk + Asterisk is an Open Source PBX and telephony toolkit. + . + This package contains the default configuration files of Asterisk. --- asterisk-1.2.12.1.dfsg.orig/debian/autosupport.8 +++ asterisk-1.2.12.1.dfsg/debian/autosupport.8 @@ -0,0 +1,41 @@ +.TH AUTOSUPPORT 8 "Jul 5th, 2005" "Asterisk" "Linux Programmer's Manual" +.SH NAME +.B autosupport +\(em interactive script to provide Digium[tm]'s support with information +.SH SYNOPSIS +.PP +.B autosupport + +.SH DESCRIPTION +.B autoasupport +is a script that is normally run by a user contacting Digium's support +to automate gathering support information. + +It will probe the system for some configuration and run-time information, +and will also prompt the user for some optional access information (IP +address, login and password). + +The information is written to /root/digiuminfo which the user is expected +to attach to a support ticket to Digium. + +The script must be run as root as it reads Asterisk's configuration and +the disk information using hdparm(8). + +.SH FILES +.B /root/digiuminfo +.RS +The output of the script goes there +.RE + +.SH SEE ALSO +asterisk(8) + +.SH "AUTHOR" +autosupport was written by John Bigelow . +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-dev.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-dev.install @@ -0,0 +1 @@ +usr/include/asterisk --- asterisk-1.2.12.1.dfsg.orig/debian/rules +++ asterisk-1.2.12.1.dfsg/debian/rules @@ -0,0 +1,241 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# This file is public domain software, originally written by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=4 + +export DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +export DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) + confflags += --build $(DEB_HOST_GNU_TYPE) +else + confflags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE) +endif + +export PROC := $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU) + +MAKEFLAGS = OPTIMIZE=-O2 MAKECMDGOALS=dont-optimize + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +export OPENH323DIR=/usr/share/openh323 +export PWLIBDIR=/usr/share/pwlib + +include /usr/share/dpatch/dpatch.make + +DEBVERSION:=$(shell head -n 1 debian/changelog \ + | sed -e 's/^[^(]*(\([^)]*\)).*/\1/') +UPVERSION:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//' -e 's/.dfsg$$//') + +FILENAME := asterisk_$(UPVERSION).dfsg.orig.tar.gz +UPFILENAME := asterisk_$(UPVERSION).orig.tar.gz +URL := http://ftp2.digium.com/pub/asterisk/releases/asterisk-$(UPVERSION).tar.gz + + +check-sounds: + ( [ ! -f sounds/fpm-calm-river.mp3 ] && \ + [ ! -f sounds/fpm-sunshine.mp3 ] && \ + [ ! -f sounds/fpm-world-mix.mp3 ] ) || \ + (echo "WARNING: fpm sounds must to be removed from sources before packaging." ; false ) + touch $@ + +BRISTUFF_DIR=debian/build/asterisk-bristuff +config.status: check-sounds patch-stamp + dh_testdir + # Add here commands to configure the package. + touch .cleancount + - (cd editline ; \ + if [ -f config.sub.old ]; then \ + rm -f config.sub; \ + else \ + mv config.sub config.sub.old; \ + fi; \ + if [ -f config.guess.old ]; then \ + rm -f config.guess; \ + else \ + mv config.guess config.guess.old; \ + fi; \ + ln -s /usr/share/misc/config.sub config.sub; \ + ln -s /usr/share/misc/config.guess config.guess; \ + cd ..) + + cd editline;./configure $(confflags) + touch $@ + +debian/build/asterisk-bristuff/config.status: config.status check-sounds patch-stamp + # get ourselves a copy of the source to build bristuff in... + rm -rf $(BRISTUFF_DIR) + mkdir -p $(BRISTUFF_DIR) + tar cf - --exclude ./debian . | (cd $(BRISTUFF_DIR); tar xf -) + #ls -1d * .version .cleancount|grep -v debian|grep -v ^.$$|xargs cp -alt debian/build/asterisk-bristuff + set -e; cd $(BRISTUFF_DIR) ; \ + patch -p1 <../../patches/bristuff.dpatch ; \ + patch -p1 <../../patches/libpri_bristuffed.dpatch + + cd $(BRISTUFF_DIR)/editline; ./configure $(confflags) + touch $@ + +build-arch: build-arch-stamp +build-arch-stamp: config.status debian/build/asterisk-bristuff/config.status + dh_testdir + + # Add here command to compile/build the package. + $(MAKE) $(MAKEFLAGS) + $(MAKE) $(MAKEFLAGS) -C channels/h323 opt + $(MAKE) $(MAKEFLAGS) -C $(BRISTUFF_DIR) + + touch $@ + +build-indep: build-indep-stamp +build-indep-stamp: config.status + dh_testdir + + # Add here command to compile/build the arch indep package. + # It's ok not to do anything here, if you don't need to build + # anything for this package. + #/usr/bin/docbook-to-man debian/asterisk.sgml > asterisk.1 +ifndef ASTERISK_NO_DOCS + $(MAKE) progdocs +endif + + touch $@ + + +build: build-arch build-indep + +clean: cleaned unpatch +cleaned: + dh_testdir + dh_testroot + + # Add here commands to clean up after the build process. + -test -d channels/h323 && $(MAKE) -C channels/h323 clean + -$(RM) -f channels/h323/libchanh323.a + -$(MAKE) clean + -$(RM) -rf debian/build + -$(RM) utils/streamplayer + #-$(RM) -f fxstest ztmonitor ztspeed zttest + -$(RM) -fR doc/api agi/eagi-test agi/eagi-sphinx-test + -$(RM) debian/asterisk.8.gz + -(test -d editline &&cd editline; \ + if [ -f config.sub.old ]; then \ + mv config.sub.old config.sub; \ + fi; \ + if [ -f config.guess.old ]; then \ + mv config.guess.old config.guess; \ + fi; \ + cd ..) + -test -d configs && chmod -x configs/*.sample + -$(RM) -f build-arch-stamp build-indep-stamp config.status check-sounds + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs var/run/asterisk + + # Add here commands to install the package into debian/ + $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install samples + cp channels/h323/h323.conf.sample $(CURDIR)/debian/tmp/etc/asterisk/h323.conf + mkdir -p $(CURDIR)/debian/tmp/etc/default/ + cp debian/asterisk.default $(CURDIR)/debian/tmp/etc/default/asterisk + mkdir -p $(CURDIR)/debian/tmp/usr/lib/cgi-bin/asterisk/ + cp contrib/scripts/vmail.cgi $(CURDIR)/debian/tmp/usr/lib/cgi-bin/asterisk/ + chmod +x $(CURDIR)/debian/tmp/usr/lib/cgi-bin/asterisk/vmail.cgi + $(RM) -f $(CURDIR)/debian/tmp/usr/sbin/{stereorize,streamplayer} + # override some default configurations. Leave the original ones + # in the sample configs: + cp -a debian/ast_config/* $(CURDIR)/debian/tmp/etc/asterisk + + mkdir -p $(CURDIR)/debian/asterisk/usr/share/asterisk/bin + cp debian/asterisk_fix $(CURDIR)/debian/asterisk/usr/share/asterisk/bin + chmod +x $(CURDIR)/debian/asterisk/usr/share/asterisk/bin/asterisk_fix + + mkdir -p $(CURDIR)/debian/tmp/usr/share/asterisk/firmware/iax + + # bristuff + $(MAKE) -C $(BRISTUFF_DIR) DESTDIR=$(CURDIR)/debian/tmp/bristuff install + mkdir -p $(CURDIR)/debian/tmp/bristuff/etc/default/ + cp debian/asterisk.default $(CURDIR)/debian/tmp/bristuff/etc/default/asterisk + $(RM) -f $(CURDIR)/debian/tmp/bristuff/usr/sbin/{stereorize,streamplayer} + dh_install --sourcedir=debian/tmp + + install -m 644 include/asterisk.h $(CURDIR)/debian/asterisk-dev/usr/include/asterisk.h + +# Build architecture-independent files here. +binary-indep: build install + dh_testdir -i + dh_testroot -i + dh_installlogrotate -i + dh_installinit -i -- defaults 21 + dh_installdocs -i -XREADME.cygwin + dh_installexamples -i -XCVS + dh_installcron -i + dh_installchangelogs ChangeLog -i + dh_link -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir -a + dh_testroot -a + dh_installdocs -a + dh_installman -pasterisk-classic -pasterisk-bristuff *.[1-8] debian/*.1 debian/*.8 + dh_installexamples -a -XCVS + dh_installchangelogs ChangeLog -a + dh_strip -a + dh_link -a + dh_compress -a + dh_fixperms -a + dh_installdeb -a + #rm debian/asterisk/usr/lib/asterisk/modules/pbx_gtkconsole.so + rm -f debian/asterisk-classic/usr/lib/asterisk/modules/chan_h323.so + rm -f debian/asterisk-bristuff/usr/lib/asterisk/modules/chan_h323.so + rm -f debian/asterisk-bristuff/usr/lib/asterisk/modules/*_capi*.so + dh_makeshlibs -a + dh_shlibdeps -a + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +print-version: + @@echo "Debian version: $(DEBVERSION)" + @@echo "Upstream version: $(UPVERSION)" + +get-orig-source: + @@dh_testdir + @@[ -d ../tarballs/. ]||mkdir -p ../tarballs + @@echo Downloading $(UPFILENAME) from $(URL) ... + @@wget -N -nv -T10 -t3 -O ../tarballs/$(UPFILENAME) $(URL) + @@echo Repacking as DFSG-free... + @@mkdir -p ../tarballs/asterisk-$(UPVERSION).tmp/ + @@cd ../tarballs/asterisk-$(UPVERSION).tmp ; \ + tar xfz ../$(UPFILENAME) + @@find ../tarballs/asterisk-$(UPVERSION).tmp -type f -name 'fpm-*.mp3'|xargs -r rm + @@rm -rf ../tarballs/asterisk-$(UPVERSION).tmp/asterisk-$(UPVERSION)/codecs/ilbc + @@rm -rf ../tarballs/asterisk-$(UPVERSION).tmp/asterisk-$(UPVERSION)/contrib/firmware/ + @@cd ../tarballs/asterisk-$(UPVERSION).tmp ; \ + tar cfz ../$(FILENAME) * + @@echo Cleaning up... + @@$(RM) -rf ../tarballs/asterisk-$(UPVERSION).tmp/ + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install clean patch unpatch --- asterisk-1.2.12.1.dfsg.orig/debian/NEWS.Debian +++ asterisk-1.2.12.1.dfsg/debian/NEWS.Debian @@ -0,0 +1,10 @@ +Debian asterisk-xxx.dfsg.tar.gz +=============================== +The Debian version of the upstream asterisk source has had the fpm Music on Hold +removed as this music has only been licenced for use within asterisk which is +incompatible with the Debian Free Software Guildlines +. Please drop your alternative +Music on Hold into the directory /usr/share/asterisk/mohmp3/ + +The iLBC codec library code has been removed from the Debian asterisk +package as it does not conform with the DFSG. --- asterisk-1.2.12.1.dfsg.orig/debian/watch +++ asterisk-1.2.12.1.dfsg/debian/watch @@ -0,0 +1,7 @@ +# format version number, currently 2; this line is compulsory! +version=2 + +# Full-site-with-pattern [Version [Action]] +opts=dversionmangle=s/\.dfsg// \ + http://ftp.digium.com/pub/asterisk/asterisk-([\d.].*[\d])\.tar\.gz \ + debian svn-upgrade --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk.default +++ asterisk-1.2.12.1.dfsg/debian/asterisk.default @@ -0,0 +1,25 @@ +# This file allows you to alter the configuration of the Asterisk +# init.d script +# +# RUNASTERISK: run asterisk upon boot. Should be set to "yes" once you have +# setup your configuration. +RUNASTERISK=no +# +# +# AST_REALTIME: if set to anything other than "no", asterisk will run in +# real-time priority (pass '-p' to asterisk). un-rem the +# following line to disable asterisk from running in real-time +# priority +#AST_REALTIME=yes +# +# PARAMS: extra parameters to pass to asterisk +# The example here may help you in debugging, but is +# *not**intended**for**production**use*. +# When you give -G *only* that group will be used, +# else all groups of the asterisk user. +#PARAMS="-D -g -vvv" +# +# +# RUNASTSAFE: run safe_asterisk rather than asterisk (will auto-restart upon +# crash) +#RUNASTSAFE=yes --- asterisk-1.2.12.1.dfsg.orig/debian/changelog +++ asterisk-1.2.12.1.dfsg/debian/changelog @@ -0,0 +1,1333 @@ +asterisk (1:1.2.12.1.dfsg-1ubuntu1.2) edgy-security; urgency=low + + * SECURITY UPDATE: Fix security issue fixed in Asterisk 1.2.16 + * References: + http://asterisk.org/node/48319 + http://svn.digium.com/view/asterisk/branches/1.2/channels/chan_sip.c?r1=56230&r2=57475 + https://launchpad.net/ubuntu/edgy/+source/asterisk/+bug/89863 + + -- Martin Jürgens Mon, 5 Mar 2007 16:51:12 +0100 + +asterisk (1:1.2.12.1.dfsg-1ubuntu1.1) edgy-security; urgency=low + + * SECURITY UPDATE: Fix an integer signedness problem. + * References: + CVE 2006-5444 + https://bugs.launchpad.net/distros/ubuntu/+source/asterisk/+bug/66912 + * Fixed typo in Asterisk's initscript + + -- Martin Jürgens Wed, 29 Nov 2006 17:02:43 +0100 + +asterisk (1:1.2.12.1.dfsg-1ubuntu1) edgy; urgency=low + + * Merge from Debian sid. + * debian/asterisk.init: + - create /var/run/ directory if necessary and set proper permissions + * Remove dependency on linux/compiler.h + + -- Soren Hansen Thu, 28 Sep 2006 18:15:25 +0200 + +asterisk (1:1.2.12.1.dfsg-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * New upstream release + * bristuff.dpatch: version adapted. + * apprecord_sprintf.dpatch removed: already applied. + + [ Mark Purcell ] + * binary blob in asterisk-classic package (Closes: #386361) + * Cleanup bristuff.dpatch + + -- Mark Purcell Sun, 24 Sep 2006 14:45:58 +0100 + +asterisk (1:1.2.11.dfsg-1) unstable; urgency=high + + [ Tzafrir Cohen] + * apprecord_sprintf.dpatch: fix format string issue in app_record.so . + + [ Mark Purcell ] + * New Upstream Release + * Urgency high as fixes CVE-2006-4346 + * CVE-2006-4346: Asterisk MGCP AUEP Response Handling Buffer + Overflow (Closes: Bug#385060) + * Please package Asterisk 1.2.11 and Zaptel 1.2.8 (Closes: #384283) + * Better error handling on init.d reload, if asterisk isn't running + * Lintian cleanup: not-binnmuable-any-depends-all + * Lintian cleanup: not-binnmuable-all-depends-any + * Use restart in asterisk_fix + + -- Mark Purcell Sat, 2 Sep 2006 13:01:02 +0100 + +asterisk (1:1.2.10.dfsg-3ubuntu1) edgy; urgency=low + + * Merge from debian sid. + * Same changes as 1:1.2.10.dfsg-1ubuntu1 + + -- Soren Hansen Wed, 23 Aug 2006 01:23:02 +0200 + +asterisk (1:1.2.10.dfsg-3) unstable; urgency=low + + [ Kilian Krause ] + * Add iaxy.bin to asterisk debs to have working IAX support. + * asterisk_fix is included on the main asterisk package + (Closes: Bug#287025, Bug#360233, Bug#381861) + * Various fixes to asterisk_fix + + [ Mark Purcell ] + * Remove Build-Depends: libgtk1.2-dev (only for asterisk-gtk) + * export PROC := $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU) + * asterisk-{classic-bristuff} Depends: asterisk + * asterisk_fix needs to fix /var/run/asterisk + * Move doc/asterisk -> asterisk-doc package + + [ Tzafrir Cohen] + * New upstream release (Closes: #385060). + * bristuff 0.3.0-PRE-1s (adapted to asterisk 1.2.11). + + -- Mark Purcell Thu, 17 Aug 2006 20:31:02 +0100 + +asterisk (1:1.2.10.dfsg-2) unstable; urgency=high + + * IAX2 channel driver security patch [CVE-2006-2898] + - CVE-2006-2898: Denial of service in Asterisk (Closes: #380054) + + -- Mark Purcell Thu, 27 Jul 2006 08:09:47 +0100 + +asterisk (1:1.2.10.dfsg-1ubuntu1) edgy; urgency=low + + * Resynchronized with Debian unstable + * debian/asterisk.init: + - create /var/run/ directory if necessary and set proper permissions + * Remove dependency on linux/compiler.h + + -- Soren Hansen Mon, 24 Jul 2006 14:27:25 +0200 + +asterisk (1:1.2.10.dfsg-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * New upstream release. + * bristuff.dpatch updated for the new version. + * dfsg tarball also removes ilbc. + * Cleanups to asterisk_fix + + [ Mark Purcell ] + * Build-Depends: libpri-dev (>= 1.2.3-1) + * Fixes: + - Please package version 1.2.9.1 (Closes: #372527) + + -- Mark Purcell Mon, 17 Jul 2006 21:15:50 +0100 + +asterisk (1:1.2.9.1.dfsg-1) unstable; urgency=high + + * New upstream release. [CVE-2006-2898] + + [ Mark Purcell ] + * Update debian/watch for numeric upstream versions + + [ Kilian Krause ] + * Remove unused correct_pid.dpatch (has apparently been fixed with 1.2 + upstream) + * debian/patches/100_nonroot.dpatch, debian/patches/20_Makefile.dpatch, + debian/patches/25_subdirs_Makefiles.dpatch: Remove unused patches + + [ Tzafrir Cohen ] + * reunite init.d and logrotate scripts in the package asterisk + * Re-add correct_pid_display.dpatch + * bristuff 0.3.0-PRE1s (gsm functionality missing: needs libgstam) + * sys_readline.dpatch: Realine support in the CLI. TODO: tab completion + * sys_editline.dpatch: alternativly, simply use the system version of + editline (not used). + * func_odbc_12.dpatch: backport of func_odbc (Closes: #364633) + * brazilian_syntax.dpatch (using "pt_BR") + * vm_he.dpatch: Hebrew in app_voicemail + * The data_dir patch also moves agi-bin/ and firmware/ + * option_detach: using -F instead of -D (the same as upstream) + * asterisk.init: added "zaptel-fix" to unload and reload zaptel modules + + -- Kilian Krause Fri, 16 Jun 2006 18:04:50 +0000 + +asterisk (1:1.2.7.1.dfsg-3) unstable; urgency=high + + * Urgency high as this is a security fix [CVE-2006-2898] + * Added 99_CVE-2006-2898.dpatch from Joey Schulze + - Fixes: Bug in the IAX2 channel allows remote attackers to craft + a denial of service. + + -- Mark Purcell Tue, 13 Jun 2006 05:11:44 +0100 + +asterisk (1:1.2.7.1.dfsg-2ubuntu3) dapper; urgency=low + + * debian/*.init: + - Change the ownership of the pid file again. + (Closes: Malone ##45952). + + -- Chuck Short Thu, 25 May 2006 20:27:00 -0400 + +asterisk (1:1.2.7.1.dfsg-2ubuntu2) dapper; urgency=low + + * debian/*.init + - Change the ownership of the pid file. + (Closes: Malone #45952). + + -- Chuck Short Mon, 22 May 2006 14:00:27 -0400 + +asterisk (1:1.2.7.1.dfsg-2ubuntu1) dapper; urgency=low + + * Resynchronized with Debian, only Ubuntu changes: + - debian/*.init: + - create /var/run/ directory if necessary. + + -- Daniel Holbach Thu, 18 May 2006 10:21:06 +0200 + +asterisk (1:1.2.7.1.dfsg-2) unstable; urgency=high + + [ Kilian Krause ] + * Urgency bumped since 1.2.7 is a security update [CVE-2006-1827] + (Closes: #364195) + + [ Mark Purcell ] + * Previous Upload also fixes: + - cannot install - directories not created (Closes: #360233) + - package uninstallable (Closes: #359970) + * Update postinst to fix: fails to upgrade when /etc/asterisk/voicemail.conf + is deleted (Closes: #360220) + * Link debian/asterisk-bristuff.asterisk.{logrotate,init} & + provide debian/asterisk-classic.asterisk.logfile + - Fixes: init.d and logrotate.d conflicts (Closes: #360181) + + -- Mark Purcell Sun, 23 Apr 2006 13:26:29 +0100 + +asterisk (1:1.2.7.1.dfsg-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * New upstream release. + * nomarch.dpatch: removed the patching to internal libgsm, as we don't use + it (and it broke in this version) + * bristuff.dpatch: based on the patch from bristuff-0.3.0-PRE1n + * bristuff.dpatch: A small fix in chan_sip.c + * bristuff.dpatch: Disabling "libgsm" until it is renamed + * 30_ast-data-dir.dpatch: the symlink sounds/voicemail is now gone + * rules: do fail if bristuff patching hasfailed + * zap_restart.dpatch: allow restarting zaptel channel with "zap restart" + * backport_playdtmf.dpatch: a harmless backport (no impact if not used) + * completed the merge of logrotate and init.d scripts + + [ Lionel Elie Mamane ] + * When not running asterisk, do it successfully, not by failure. + (closes: #360234) + * Create /var/log/asterisk/cdr-csv, not cdr-cvs. + + [ Mark Purcell ] + * Update debian/control for asterisk-h323 package description + * Create /var/spool/asterisk & /var/lib/asterisk in debian/*.postinst + * New upstream release. Fixes: + - Version 1.2.5 is out (Closes: #355299) + - since 1.2.0 no chan_modem (Closes: #343232) + - Undefined symbol in chan_zap.so (Closes: #339559) + - Unapplying patches fail (Closes: #345676) + - utils.c:619 tvfix: warning negative timestamp... (Closes: #347929) + - creates /.asterisk_history on reboot (Closes: #307218) + * h323 modules can be unstable so dont load my default + * Cleanup debian/patches to remove obsolete/ old patches + + -- Mark Purcell Fri, 21 Apr 2006 17:33:31 +0100 + +asterisk (1:1.2.6.dfsg-1) unstable; urgency=low + + * New upstream release. (Closes: #355299) + * correct_pid_display.dpatch: adjusted to 1.2.6 + * 30_ast-data-dir.dpatch: adjusted to 1.2.6 + * debian/control: Add adduser to depends of asterisk-config to shut up + lintian. + * rules: no need to copy config to the bristuff install + * rules: but use cp -a for ast_config, as there may be subdirs. + + -- Tzafrir Cohen Mon, 10 Apr 2006 19:00:12 +0300 + +asterisk (1:1.2.4.dfsg-7) unstable; urgency=low + + * Recompile to fix missing asterisk-config from last binNMU round + (Closes: #356712, #358413, #355524, #358145) + * postinstall: Add /var/spool/asterisk/meetme if nonexistant. + (Closes: #355046) + * asterisk.init: Install both asterisk-classic and asterisk-bristuff with + /etc/init.d/asterisk (Closes: #354729) + * logroate: create /var/log/asterisk/cdr-custom/ as well as cdr-csv + (Closes: #355048) + * logrotate: share location of logrotate file as /etc/logrotate.d/asterisk + for both classic and bristuff version (Closes: #356712) + * delete chan_capi modules from bristuff + * Move postinstall and postrm to asterisk-classsic, asterisk-bristuff and + asterisk-config. (Closes: #355524) + + -- Kilian Krause Thu, 30 Mar 2006 11:55:03 +0200 + +asterisk (1:1.2.4.dfsg-6) unstable; urgency=low + + * Add chan_h323 back with new Atlas_devel3 OpenH323. + + -- Kilian Krause Sat, 18 Feb 2006 17:55:24 +0000 + +asterisk (1:1.2.4.dfsg-5) unstable; urgency=low + + * Fix install of asterisk-bristuff with dh_install. + + -- Kilian Krause Tue, 14 Feb 2006 20:23:56 +0100 + +asterisk (1:1.2.4.dfsg-4) unstable; urgency=low + + * Create missing /var/spool/asterisk/voicemail in postinst (Closes: #352586) + + -- Kilian Krause Sun, 12 Feb 2006 22:51:50 +0100 + +asterisk (1:1.2.4.dfsg-3) unstable; urgency=low + + * Fix asterisk-bristuff install target to catch correct versions. + + -- Kilian Krause Sun, 12 Feb 2006 12:34:31 +0000 + +asterisk (1:1.2.4.dfsg-2) unstable; urgency=low + + * update to bristuff 0.3.0-PRE-1k + + -- Kilian Krause Thu, 9 Feb 2006 18:12:08 +0000 + +asterisk (1:1.2.4.dfsg-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * Fix PID display (Closes: #338646) + * changes to the init.d script (Tzafrir) + * debian/ast_config/ place here configurutaion files that will override + the defaults from the source, though not get into the sample documentation + dir + * debian/ast_config/manager.conf: asterisk does listen onthe manager by + default, but only on localhost. Other packages need not edit manager.conf + to get a manager acount + * bristuff 0.3.0-PRE-1f + * option_detach.dpatch: Adds option -D: always daemonize (even with -v,-d) + (conflicts with bristuff, though) + * ukcid.dpatch: UK Caller ID patch for the X100P. (Closes: #302380) + + [ Kilian Krause ] + * New upstream release. (Closes: #350905) + * Bumping depends on libpri and zaptel to according 1.2 versions. + * Build-Depends on libpri1.2 since new ABI caused new package name. + * Removed alternatives from Build-Depends since sbuild will only take first + anyway to ensure constant rebuilds. + * Add a noload for chan_capi by default, so that we d not stop loading when + no CAPI is installed. (Closes: #328835) + * Include smsq by adding Build-Depends on libpopt-dev (Closes: #348090) + + -- Kilian Krause Sun, 5 Feb 2006 11:44:28 +0100 + +asterisk (1:1.2.1.dfsg-3) unstable; urgency=low + + * Remove -msoft-float from compile flags to fix compilation on arm. + (Closes: #343154) + * Provide nonexistant dirs before running chown on them. (Closes: #341810) + * Depend on Perl module in libapache-dbi-perl or libdbi-perl or web-vmail + (Closes: #337448) + * Fix permissions on voicemail.conf. (Closes: #304615) + * Build-Depend on gsfonts to have Helvetica font for doxygen + (Closes: #343079) + + -- Kilian Krause Mon, 2 Jan 2006 00:15:59 +0000 + +asterisk (1:1.2.1.dfsg-2) unstable; urgency=low + + [ Tzafrir Cohen ] + * bristuff 0.3.0-PRE-1d . Still disabled by default + * libpri_bristuffed.dpatch: link chan_zap with libpri-bristuffed.so.1 + * Use asterisk(8) as a man page for rasterisk + * Removing binary steroize: can be done with soxmix of package sox. + * Removing binary streamplay: can be done with netcat + + [ Kilian Krause ] + * Fix asterisk-dev to include asterisk.h + + -- Tzafrir Cohen Sat, 31 Dec 2005 21:17:44 +0200 + +asterisk (1:1.2.1.dfsg-1) unstable; urgency=low + + * New upstream release + - Please package asterisk 1.2.1 (Closes: #342463) + * Temporary disable bristuff for upstream release + * sip-1.914.dpatch merged upstream + + -- Mark Purcell Wed, 7 Dec 2005 21:59:20 +0000 + +asterisk (1:1.2.0.dfsg-6) unstable; urgency=low + + * Add Build-Depends: libcurl3-dev | libcurl-dev + - Should build-depend on libcurl3-dev (Closes: #341363) + * Add Build-Depends: doxygen + - Missing build-dependency on doxygen (Closes: #341362) + * Build-Depends: adduser (>= 3.63) + * disable chan_zap building (in channels makefile) against old + libmfcr2 (Closes: #342139) + * seperate api docs and configuration samples (Closes: #341395) + * Add sip-1.913.dpatch; SIP error 400 on outgoing calls (Closes: #340574) + + -- Mark Purcell Mon, 5 Dec 2005 23:49:40 +0000 + +asterisk (1:1.2.0.dfsg-5) unstable; urgency=low + + [ Tzafrir Cohen ] + * Added bristuff 0.3.0-PRE1 + + [ Mark Purcell ] + * asterisk-sounds-main Replaces: asterisk-sounds-extra + - asterisk-sounds-{main,extra}: file conflict (Closes: #339791) + + -- Mark Purcell Thu, 1 Dec 2005 17:37:13 +0000 + +asterisk (1:1.2.0.dfsg-4) unstable; urgency=low + + * Fix 50_debian-libgsm.dpatch to apply correctly + - asterisk - FTBFS: Tries to build a i386 assembler file (Closes: + #340102) + + -- Mark Purcell Mon, 21 Nov 2005 19:56:03 +0000 + +asterisk (1:1.2.0.dfsg-3) unstable; urgency=low + + * Remove -march to fix FTBFS. (Closes: #338753) + + -- Kilian Krause Sat, 19 Nov 2005 19:36:31 +0000 + +asterisk (1:1.2.0.dfsg-2) unstable; urgency=low + + * libreadline4-dev is superseeded by libreadline5-dev. Fixed build-depends. + + -- Kilian Krause Sat, 19 Nov 2005 12:12:51 +0000 + +asterisk (1:1.2.0.dfsg-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Thu, 17 Nov 2005 18:17:02 +0000 + +asterisk (1:1.2.0-rc2.dfsg-1) experimental; urgency=low + + * New upstream release + + -- Mark Purcell Sun, 13 Nov 2005 17:58:08 +0000 + +asterisk (1:1.2.0-rc1.dfsg-1) experimental; urgency=low + + * New upstream release + * Suggests: asterisk-rate-engine + * debian/rules touch .cleancount (upstream bug?) + + -- Mark Purcell Wed, 9 Nov 2005 22:05:30 +0000 + +asterisk (1:1.2.0-beta2.dfsg-3) experimental; urgency=low + + * Fix debian/patches/30_ast-data-dir with /var/run/asterisk. Thanks + Alessandro Polverini + + -- Mark Purcell Tue, 8 Nov 2005 22:00:29 +0000 + +asterisk (1:1.2.0-beta2.dfsg-2) experimental; urgency=low + + * Copyright audit into debian/copyright (Closes: #331318) + * Please package 1.2 beta 2 (Closes: #336749) + + -- Mark Purcell Mon, 7 Nov 2005 22:58:27 +0000 + +asterisk (1:1.2.0-beta2.dfsg-1) experimental; urgency=low + + * New upstream release + * Update Build-Depends: libpri1 >= 1.2.0-beta2 + * Remove Build-Depends: doxygen. Takes too long for experimental ;-) + + -- Mark Purcell Tue, 1 Nov 2005 22:27:43 +0000 + +asterisk (1:1.2.0-beta1.dfsg-1) experimental; urgency=low + + [ Tzafrir Cohen ] + * recreated system_libgsm patch, http://bugs.digium.com/view.php?id=5434 + * Added public key from Junction Networks (pubkey_jnctn.dpatch). + Any other keys for IAX providers we can add? + * updating to a beta of Asterisk 1.2 + * added defaults_debian.dpatch to set pathes + * BuildDepends on graphviz + * disabled most patches: still need to review them + * What about h323? + * deleted from patches/00list a number of patches that should not go in + + [ Mark Purcell ] + * Fix: old-fsf-address-in-copyright-file + * Please package version 1.2 betas (Closes: #325268) + + -- Mark Purcell Thu, 20 Oct 2005 19:42:14 +0100 + +asterisk (1:1.0.9.dfsg-6) UNRELEASED; urgency=low + + * Fix memleak bug (http://bugs.digium.com/view.php?id=4318) + * Fix depends to adduser 3.64 (Closes: #326198) + + -- Kilian Krause Wed, 7 Sep 2005 21:22:40 +0200 + +asterisk (1:1.0.9.dfsg-5) unstable; urgency=low + + [ Kilian Krause ] + * debian/control: fix GCI to read CGI. (Closes: #311291) + + [ Mark Purcell ] + * /var/lib/dpkg/info/asterisk.postinst: line 22: adduser: command not + found (Closes: #322115) + * debian/patches/chan-modem.dpatch from Simon Peter + - chan_modem.c should set default read & write format (Closes: + #303903) + * apply patch from Jérôme Warnier + - Asterisk autosupport script not recognized as such (Closes: #316799) + * Updated debian/postrm: + - 'apt-get --purge remove asterisk' removes configuration files from + another package (Closes: #318455) + + -- Mark Purcell Tue, 9 Aug 2005 22:07:13 +0100 + +asterisk (1:1.0.9.dfsg-4) unstable; urgency=low + + * Cleanup bristuff to build under gcc4, thanks for the suggestions + - Closes: #318337: FTBFS. channel.c:64: error: static declaration of + 'uniquelock' follows non-static declaration + + -- Mark Purcell Fri, 22 Jul 2005 10:28:15 +1000 + +asterisk (1:1.0.9.dfsg-3) unstable; urgency=low + + * Cleanup 70_debian-libpe-fe.dpatch to check in Makefile + * Enable bristuff-0.2.0-RC8j.dpatch + * Remove debian/patches/08_debian-zaptel.dpatch as it is no longer + needed with new zaptel-source package + * Cleanup debian/patches/ + * Conflicts: asterisk-oh323 (<= 0.6.6pre3-3) + - Closes: #318189: asterisk-oh323: chan_oh323.so cannot find symbol + and Asterisk crashes + - Closes: #318216: chan_oh323.so symbols + * Cleanup postinit error: adduser asterisk audio; adduser asterisk + dialout + * Incorporate suggestions from Tzafrir Cohen + - postinst script has an error + - modified astdir patch, so it won't conflict with bristuff patch + - typo in the debian/asterisk.default: s/exra/extra/ + - build-depends both on zaptel-source (>= 1.0.6) and simply + on zaptel-source, The latter is probably unnecessary + - man pages for the other executables in the package + + -- Mark Purcell Thu, 14 Jul 2005 07:22:59 +0100 + +asterisk (1:1.0.9.dfsg-2) unstable; urgency=low + + * Closes: #301490: Please add patch for Italian syntax + * Closes: #305734: On PowerPC, hanging up on voicemail causes non-stop + log messages + + -- Mark Purcell Fri, 1 Jul 2005 23:24:53 +0100 + +asterisk (1:1.0.9.dfsg-1) unstable; urgency=low + + * New upstream release + - Closes: #315578: New version of asterisk and bristuff released + * Remove BRI patch while we work on it, to allow 1.0.9 to unstable + + -- Mark Purcell Fri, 1 Jul 2005 22:38:24 +0100 + +asterisk (1:1.0.8.dfsg-1) UNRELEASED; urgency=low + + * (NOT RELEASED YET) New upstream release + + -- Mark Purcell Fri, 24 Jun 2005 23:25:02 +0100 + +asterisk (1:1.0.7.dfsg.1-4) unstable; urgency=low + + * debian/control: fixed build-depends on sed's version greater than Woody. + (Closes: #308885) + + -- Kilian Krause Sat, 21 May 2005 14:15:03 +0200 + +asterisk (1:1.0.7.dfsg.1-3) unstable; urgency=low + + * Jose Carlos + + Fix a typo in NEWS.Readme + + debian/postint: Add asterisk user to dialout group too. This is needed + for asterisk to have enoug permissions to access zaptel devices. + + debian/control: allow a local asterisk-config-local package to satisfy + dependencies. Conflict with asterisk-config + + -- Jose Carlos Garcia Sogo Sun, 8 May 2005 22:06:44 +0200 + +asterisk (1:1.0.7.dfsg.1-2) unstable; urgency=low + + * Mark Purcell + + Update debian/watch to use svn-upgrade + * Kilian Krause + + debian/asterisk.init: fixed restart problem with breaking up after stop. + + debian/asterisk.init: fixed reference to WRAPPER_DEAMON which is only + DEAMON for us. (Closes:#300707) + + -- Kilian Krause Mon, 21 Mar 2005 10:59:01 +0100 + +asterisk (1:1.0.7.dfsg.1-1) unstable; urgency=low + + * New upstream release (Ensure non-dfsg MOH is not included in orig.tar) + + -- Mark Purcell Sun, 20 Mar 2005 10:30:44 +0000 + +asterisk (1:1.0.7-1) unstable; urgency=low + + * New upstream release. (Closes: #300403) + + Fixed music on hold. (Closes: #300370) + * Re-enabled speex codec. (Closes: #300373) + * As asterisk-h323 is empty, we are no longer depending on openh323, so + we don't have build conflicts between asterisk and zaptel. (Closes: #287260) + * debian/rules: Fixed duplicate execution of configure and unrepresentable + changes to source. (Closes: #299184) + * debian/patches/80_skinny.dpatch: removed. Incorporated in the 1.0.7 + release. + * debian/patches/97_bristuff.dpatch: fixed problems to build on AMD64 with + gcc-4.0 (Closes: #297561) + + -- Kilian Krause Sat, 19 Mar 2005 22:26:45 +0100 + +asterisk (1:1.0.6-2) unstable; urgency=low + + * fixed location of sounds dir in addmailbox (Closes: #298769) + + -- Kilian Krause Wed, 9 Mar 2005 22:09:05 +0100 + +asterisk (1:1.0.6-1) unstable; urgency=low + + * New upstream release. (asterisk 1.0.6, bristuff RC7k, Closes: #298128) + * debian/control: explicitly depend on zlib1g-dev. (Closes: #296967) + * Make sure we have the newer asterisk-config to not conflict + /etc/default/asterisk. (Closes: #297719) + * as there is no longer a conflict with libnewt-dev, it was added to the + build deps for astman + * debian/control: add astman and cdr_sqlite (Closes: #259342) + * asterisk.default, asterisk.init: removed hack to load zaphfc correctly. + We'll leave this to zaptel and it's modprobe.d features. + + -- Kilian Krause Sat, 5 Mar 2005 20:03:42 +0100 + +asterisk (1:1.0.5-4) unstable; urgency=low + + * debian/patches/00list,debian/control: Enable bristuff RC7f by default. + * debian/asterisk.init, debian/asterisk.default: Cleanup zaphfc preloading + as inspired by Tzafrir Cohen. + * debian/control: Remove speex as B-D, it's broken when imported from + debian. Added autotools-dev for editline. + * deiban/rules: fix asterisk.8.gz error in lintian. Bring new autotools for + editline's configure. + * reintroduce chan_zap (Closes: #296656) + + -- Kilian Krause Thu, 24 Feb 2005 01:24:45 +0100 + +asterisk (1:1.0.5-3) unstable; urgency=low + + * debian/patches/08_debian-zaptel.dpatch, debian/control: fixed zaptel.h + include to take zaptel-source's version. + * debian/patches/97_bristuff.dpatch: + include bristuff from junghanns.net (not enabled by default now, would + close: #286797). We need libpri and zaptel with bristuff patch first. + * 18_debian-libedit.dpatch: removed due to command history problem. + (Closes:#281690) + * debian/asterisk.init: Added grace timeout of 2 secs before hard shutting + down running daemons to don't scatter incorrect warnings. Don't run the + asterisk daemon unless RUNASTERISK=yes. (Will not bind ports from chroots) + * debian/asterisk-config.default: Disabled autostart - especially when + installing in chroots this was quite annoying. + * debian/rules: Remove the asterisk.8.gz recompression. (Closes: #295220) + * debian/README.Debian: Added first version. Thanks to Tzafrir Cohen for the + template! (Closes: #270072) + * debian/asterisk.deafult: moved the /etc/default to the asterisk package, + as /etc/init.d/asterisk in there needs it. + * debian/80_skinny.dpatch: Added + http://bugs.digium.com/bug_view_page.php?bug_id=0003496. Thanks to Johan + Thelmén . (Closes:#295658) + * debian/control: remove chan_h323 from being built for now. For now it's + being replaced by asterisk-oh323 until chan_h323 does build and work ok + with latest OpenH323 again. + + -- Kilian Krause Mon, 21 Feb 2005 23:13:57 +0100 + +asterisk (1:1.0.5-2) unstable; urgency=low + + * Debian VoIP Team upload. + * asterisk.init, asterisk-config.default: probably fixed start-as-user-with- + multiple-groups-problem. + * patches/40_initgroups.dpatch: added patch from Florian Weimer + . Thanks! (Closes: #293124) + * debian/postinst: Make asterisk user's home /var/lib/asterisk upon user + request. + * debian/control: Bump libpri build-depends to 1.0.4-1. (Closes: #293990) + + -- Kilian Krause Tue, 8 Feb 2005 11:40:43 +0100 + +asterisk (1:1.0.5-1) unstable; urgency=low + + * Debian VoIP Team upload. + * New upstream release. + + * Kilian Krause: + - debian/asterisk.init: fixed multiple GID problem when starting asterisk (as + reported by Raoul Bönisch and Simon Peter). Unfortunatelly this does + remove the chance to run as real-time prio. + - debian/asterisk.init: fixed stale stop by using start-stop-server after + soft shutdown (Closes: #263879) + - debian/asterisk.init: Fixed running as root problem for #279052. At least + through the /etc/init.d/asterisk you won't be able to run asterisk as + root (not even with another username). (Closes: #279052) + - debian/asterisk.init: Added switch to run asterisk via safe_asterisk + optionally for automatic restart (Closes: #266805) + - debian/patches/01_security_hotfix_287851.dpatch: Removed, as is + incorporated in 1.0.4 upstream release. + + * Jose Carlos + - debian/rules: add a check at build time for fpm sounds. If they exist, + abort, as we must remember to remove those from sources in each new + upstream release. + - debian/patches: 20_Makefile.dpatch: updated + + -- Jose Carlos Garcia Sogo Fri, 28 Jan 2005 23:31:14 +0100 + +asterisk (1:1.0.3-2) unstable; urgency=low + + * Apply missing 25_subdirs_Makefile patch. + + -- Jose Carlos Garcia Sogo Sat, 15 Jan 2005 18:23:40 +0100 + +asterisk (1:1.0.3-1) unstable; urgency=high + + * Debian VoIP Team upload. + * New upstream version. (Closes: #284889) + + * Kilian Krause: + - ACK NMU. (Thanks Steve!): + + debian/patches/01_security_hotfix_287851.dpatch: Patched to + fix logging strings vulnerability. (Closes: #287851) + + * Jose Carlos Garcia Sogo + - Using again dpatch. + - debian/patches: populated with different patches. + - 08_debian-zaptel: Using zaptel.h file from version 1:1.0.0-2 of + zaptel-source package. + - removed sounds licensed from FreePlayMusic from source, + as the license for them is not DFSG compliant (Closes: #288429) + - applied patch to make asterisk compile on amd64 with + gcc-4.0 (Closes: #288831) + - debian/asterisk.init: + + Changed how daemon is restarted in init file. (Closes: #287025) + + Using -r in checks in init file. (Closes: #287456) + - debian/asterisk-config.default + + Run by default as group asterisk. + - Fix some lintian warnings and errors: + + Description: should start with lowercase letter. + + Bumped Standars-Version to 3.6.1. No changes needed. + + Removed duplicate dependencies. + + Recompress asterisk.8 manpage with max level (--best option) + + -- Jose Carlos Garcia Sogo Sat, 15 Jan 2005 13:11:49 +0100 + +asterisk (1:1.0.2-3.1) unstable; urgency=high + + * Non-maintainer upload. + * High-urgency upload for sarge-targetted RC bugfix + * Fix multiple format string vulnerabilities, reported by Jan + Niehusmann. Closes: #287851. + + -- Steve Langasek Sat, 8 Jan 2005 02:54:45 -0800 + +asterisk (1:1.0.2-3) unstable; urgency=low + + * Closes: #281524: running asterisk with realtime priority + * Include changes from Tzafrir Cohen + + -- Mark Purcell Thu, 2 Dec 2004 02:10:12 +1100 + +asterisk (1:1.0.2-2) unstable; urgency=low + + * fixup init.d/asterisk to logger reload. Thanks Daniel Pocock + * Closes: #260575: chan_zap.so: undefined symbol + * Build-Depends: libpri1 >= 0.6 + * Closes: #279905: dependency issue breaks voicemail setup + * Build-Depends: asterisk-sounds-main (>= 1.0.2) + * Closes: #269942: package Debian asterisk-sounds + * Rename asterisk-sounds to asterisk-sounds-main to avoid upstream + conflict + * Closes: #277404: Please split out GTK console + * Split off asterisk-gtk-console package to contain all X11 + dependancies + + -- Mark Purcell Sat, 6 Nov 2004 13:20:33 +1100 + +asterisk (1:1.0.2-1) unstable; urgency=low + + * New upstream release + * Closes: #279540: Please package newer version of asterisk + * Closes: #275808: logrotate errors and emails + + -- Mark Purcell Thu, 4 Nov 2004 18:19:09 +1100 + +asterisk (1:1.0.1-2) unstable; urgency=low + + * Closes: #275808: logrotate errors and emails + * Add init.d/asterisk logger-reload|extensions-reload options & use + logger reload in asterisk.logrotate. Thanks Daniel Pocock + + -- Mark Purcell Wed, 13 Oct 2004 22:31:22 +1000 + +asterisk (1:1.0.1-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Wed, 6 Oct 2004 14:39:12 +1000 + +asterisk (1:1.0.0-4) unstable; urgency=high + + * Urgency high for sarge release + * Closes: #273570: asterisk-sounds: sounds/letters directory is missing + + -- Mark Purcell Wed, 29 Sep 2004 07:48:16 +1000 + +asterisk (1:1.0.0-3) unstable; urgency=low + + * Closes: #273780: under ALSA, infinite-loops immediately on + installation + * Comment out autoload of chan_oss from modules.conf + * Closes: #272999: asterisk_1:0.9.1+1.0RC2-2_hppa: FTBFS: + [anaFilter.o] Error 1 + * Version 1.0.0 now builds on hppa + * Closes: #273576: chan_zap.so module is missing + * check for ../include/linux/zaptel.h in channels/Makefile + * Closes: #273572: Music on hold has wrong default directory + * refer to correct /usr/share/asterisk/mohmp3 directory + + -- Mark Purcell Tue, 28 Sep 2004 23:06:03 +1000 + +asterisk (1:1.0.0-2) unstable; urgency=medium + + * Rebuild with zaptel.h_1.0.0 and libpri-dev_1.0.0 + + -- Mark Purcell Sun, 26 Sep 2004 08:32:11 +1000 + +asterisk (1:1.0.0-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Fri, 24 Sep 2004 20:23:31 +1000 + +asterisk (1:0.9.1+1.0RC2-2) unstable; urgency=low + + * Use asterisk.8.gz man page + * Remove back PROC optomizations from Makefile, enable build on hppa + + -- Mark Purcell Thu, 23 Sep 2004 18:20:45 +1000 + +asterisk (1:0.9.1+1.0RC2-1) unstable; urgency=low + + * New upstream release + * Back out dpatch (Makes new upstream release straight forward) + + -- Mark Purcell Thu, 23 Sep 2004 08:35:08 +1000 + +asterisk (1:0.9.1+1.0RC1-9) unstable; urgency=low + + * Breakup monolithic patch into components. + + -- Mark Purcell Wed, 22 Sep 2004 18:47:31 +1000 + +asterisk (1:0.9.1+1.0RC1-8) unstable; urgency=medium + + * debian/patches/11_makefile-sanitize.dpatch: fixed patch to make gsm + work again. (Closes: #266167) + + -- Kilian Krause Tue, 17 Aug 2004 15:34:21 +0200 + +asterisk (1:0.9.1+1.0RC1-7) unstable; urgency=low + + * debian/rules, debian/patches/10_rollup-1.0-1.dpatch, + debian/patches/11_makefile-sanitize.dpatch: Incorporate fixes proposed by + Thiemo Seufer . + Should fix the FTBFS on hppa. + + -- Kilian Krause Sun, 15 Aug 2004 20:16:26 +0200 + +asterisk (1:0.9.1+1.0RC1-6) unstable; urgency=low + + * debian/control: suggest gnomemeeting. (At least tell people, which clients + they need) Also add dpatch as Build-Dep. (Closes: #265036) + * Closes: #262011: SIP cancels fail due to Request-URI mismatch + * debian/patches/20_chan_sip.dpatch: Apply chan_sip patch from Jan Niehusmann + + -- Kilian Krause Sat, 14 Aug 2004 14:05:36 +0000 + +asterisk (1:0.9.1+1.0RC1-5) unstable; urgency=low + + * debian/control: make sure we're rebuilding with rtti enabled openh323 + * debian/rules: make svn-buildpacakge not choke on failing clean target + + -- Kilian Krause Mon, 9 Aug 2004 14:37:38 +0200 + +asterisk (1:0.9.1+1.0RC1-4) unstable; urgency=low + + * Cleanup wierd .diff.gz file + + -- Mark Purcell Wed, 28 Jul 2004 19:00:32 +1000 + +asterisk (1:0.9.1+1.0RC1-3) unstable; urgency=low + + * Rebuild with existing libtonezone1 + + -- Mark Purcell Wed, 28 Jul 2004 18:10:52 +1000 + +asterisk (1:0.9.1+1.0RC1-2) unstable; urgency=low + + * Cleanup codecs/ilbc/Makefile to remove -march sillyness (which is + already defined above anyway + * Debian already has libedit.a Don't build, fails on mips anyway due to old config.guess + + -- Mark Purcell Wed, 21 Jul 2004 19:21:51 +1000 + +asterisk (1:0.9.1+1.0RC1-1) unstable; urgency=low + + * New upstream release (Closes: Bug#260370) + * Closes: #247401: doesn't upgrade cleanly - initscript + problems ? + + -- Mark Purcell Tue, 20 Jul 2004 19:20:37 +1000 + +asterisk (1:0.9.1-3) unstable; urgency=low + + * allow init.d/asterisk distribution via GPL + * Remove -I/usr/include/ptlib/unix from h323 Makefile, Thanks Ray + Dassen (Closes: Bug#259564) + * Closes: #259572: Unmet dependencies + * Maintainer: Debian VoIP Team + Uploaders: Mark Purcell , + Kilian Krause , + Jose Carlos Garcia Sogo , + Goedson Teixeira Paixao , + Santiago Garcia Mantinan + * Next step. Get this all back into svn! + + -- Mark Purcell Sun, 18 Jul 2004 10:40:22 +1000 + +asterisk (1:0.9.1-2) unstable; urgency=low + + * Rebuild with libopenh323-dev (1.12.2-4) from sarge for H.323 support + + -- Mark Purcell Wed, 14 Jul 2004 18:35:42 +1000 + +asterisk (1:0.9.1-1) unstable; urgency=low + + * New upstream release. Previous version WAS tagged as 1.0 in CVS :-( + * Closes: #249046: no ring indication + * Closes: #254654: init.d/asterisk restart kills asterisk + * Build-Depends: libgtk1.2-dev, libspeex-dev (Closes: Bug#253639) + * Turn off broken H.323 support (Closes: Bug#255662) + * Closes: #250302: Package description is slightly outdated and + incorrect + * Closes: #255685: Syntax error in configuration file, + /etc/asterisk/sip.conf + * Closes: #228722: please add postgres support for asterisk + + -- Mark Purcell Sat, 3 Jul 2004 22:47:41 +1000 + +asterisk (1.0-2) unstable; urgency=low + + * Rebuild for new libopenh323-dev + + -- Mark Purcell Sat, 3 Jul 2004 21:56:58 +1000 + +asterisk (1.0-2) unstable; urgency=low + + * Merged 1.0-1 and 0.9.0-2 + + -- Jose Carlos Garcia Sogo Tue, 8 Jun 2004 00:10:16 +0200 + +asterisk (1.0-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Mon, 31 May 2004 21:51:18 +1000 + +asterisk (0.9.0-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Sun, 18 Apr 2004 22:51:59 +1000 + +asterisk (0.7.2-4) unstable; urgency=low + + * Update channels/h323/Makefile Closes: #235010: + asterisk_0.7.2-3(unstable/sparc): arch-dependent CFLAGS + + -- Mark Purcell Fri, 27 Feb 2004 12:14:26 +1100 + +asterisk (0.7.2-3) unstable; urgency=low + + * Add Build-Depends: libopenh323-dev (Closes: Bug#233649) + + -- Mark Purcell Tue, 24 Feb 2004 11:55:57 +1100 + +asterisk (0.7.2-2) unstable; urgency=low + + * Build-Depends: libpri-dev (Closes:Bug#199548) + * Include Suggests: rate-engine + + -- Mark Purcell Thu, 5 Feb 2004 17:26:02 +1100 + +asterisk (0.7.2-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Thu, 5 Feb 2004 16:25:28 +1100 + +asterisk (0.7.1-3) unstable; urgency=low + + * Build with libopenh323 support (Closes: Bug#195233) + * Include Suggests: ohphone + + -- Mark Purcell Tue, 3 Feb 2004 08:47:47 +1100 + +asterisk (0.7.1-2) unstable; urgency=low + + * Remove ppc fixup in codecs/lpc10/Makefile again. Prevents build on + ia64, mk68 et al + + -- Mark Purcell Fri, 16 Jan 2004 11:46:57 +1100 + +asterisk (0.7.1-1) unstable; urgency=low + + * New upstream release + * i686 optomised build + + -- Mark Purcell Thu, 15 Jan 2004 23:06:01 +1100 + +asterisk (0.7.0-1) unstable; urgency=low + + * LCA2004 release. Thanks Internode for the wireless access + * New upstream release + * Clean up bad symlinks in vm (Closes: Bug#220714) + * Apply restart gracefully patch from Nick Estes (Closes: Bug#217004) + * Fixup permission/ ownership problems in /etc/asterisk (Closes: + Bug#216995) + * Fixup master call log issues (Closes: Bug#217003) + * Remove Build-Depends: libmysql-dev - see doc/README.mysql (Closes: + Bug#222255) + * Build with include/linux/zaptel.h from zaptel-0.8.0.tar.gz + * Include Build-Depends: postgresql-dev + * Include Build-Depends: unixodbc-dev + + -- Mark Purcell Wed, 14 Jan 2004 10:10:02 +1100 + +asterisk (0.5.0-3) unstable; urgency=low + + * Remove Suggests: gnophone (Orphaned and removed) + * Clean up bad symlinks in vm (Closes: Bug#220714) + * Apply restart gracefully patch from Nick Estes (Closes: Bug#217004) + * Fixup permission/ ownership problems in /etc/asterisk (Closes: + Bug#216995) + * Fixup master call log issues (Closes: Bug#217003) + + -- Mark Purcell Tue, 13 Jan 2004 21:01:16 +1100 + +asterisk (0.5.0-2) unstable; urgency=low + + * Build-Depends: debhelper (>= 4.0.4) (Closes: Bug#216725) + + -- Mark Purcell Fri, 31 Oct 2003 06:59:11 +1100 + +asterisk (0.5.0-1) unstable; urgency=low + + * New upstream release (Closes: Bug#196761) + * Build with include/linux/zaptel.h from zaptel-0.7.0.tar.gz + + -- Mark Purcell Tue, 16 Sep 2003 23:40:05 +1000 + +asterisk (0.4.0-6) unstable; urgency=low + + * Include dh_install in debian/rules (Closes: Bug#207879) + + -- Mark Purcell Wed, 10 Sep 2003 23:07:37 +1000 + +asterisk (0.4.0-5) unstable; urgency=low + + * Rebuild for libnewt-utf8-0 (NOT AVAILABLE) + * Build-Depend: libnewt-dev + + -- Mark Purcell Sat, 5 Jul 2003 15:17:57 +1000 + +asterisk (0.4.0-4) unstable; urgency=low + + * include Build-Depends: libgtk1.2-dev (Closes: Bug#194489) + + -- Mark Purcell Sat, 5 Jul 2003 15:12:02 +1000 + +asterisk (0.4.0-3) unstable; urgency=low + + * Rebuild for libtonezone-0.60, libzaptel-0.60 + * Change codecs/codec_gsm.c:#include (Closes: Bug#190082) + * Start after isdnactivecards debian/rules dh_installinit (Closes: + Bug#191062) + * Change to Build-Depends: libnetw-utf8-dev + * Update Tormenta URL in debian/control + + -- Mark Purcell Sat, 10 May 2003 16:58:03 +1000 + +asterisk (0.4.0-2) unstable; urgency=low + + * Remove ppc 'fixup' in codecs/lpc10/Makefile (Closes: Bug#189743) + * Updated description (Closes: Bug#168779) + + -- Mark Purcell Sun, 20 Apr 2003 08:37:49 +1000 + +asterisk (0.4.0-1) unstable; urgency=low + + * New upstream release + * cdr/Makefile CFLAGS+=-fPIC -DPIC (Closes: Bug#188915) + * Include include/linux/zaptel.h from zaptel-0.6.0.tar.gz + + -- Mark Purcell Sat, 19 Apr 2003 21:11:45 +1000 + +asterisk (0.3.0-2) unstable; urgency=low + + * Build-Depends: libmysqlclient-dev, libgtk2.0-dev (Closes: Bug#188188) + + -- Mark Purcell Thu, 10 Apr 2003 20:08:38 +1000 + +asterisk (0.3.0-1) unstable; urgency=low + + * New upstream release + * channels/chan_zap_new.c is depreciated + * Debian patches to upstream Makefile are a lot cleaner!! + * Update /etc/init.d/asterisk stop to use 'stop now' command + * Hack AST_DATA_DIR to provide asterisk-sounds under /usr/share/asterisk + * `chown asterisk.asterisk /var/lib/asterisk` on install + * Remove dh_undocumented + * chan_oss failing again :-( + * Force Depends: libspeex1 (dpkg-shlibs bug?) + + -- Mark Purcell Tue, 8 Apr 2003 21:27:52 +1000 + +asterisk (0.2.0-cvs20030103-3) unstable; urgency=low + + * Include Build-Depends: libasounds2-dev + * Update channels/Makefile to include Debian zaptel.h dir (Closes: Bug#178868) + * Thanks to mdz for the new libzap-dev and other patches + + -- Mark Purcell Sat, 8 Mar 2003 15:45:40 +1100 + +asterisk (0.2.0-cvs20030103-2) unstable; urgency=low + + * Revert -march in codecs/lpc10/Makefile + + -- Mark Purcell Sat, 25 Jan 2003 08:38:51 +1100 + +asterisk (0.2.0-cvs20030103-1) unstable; urgency=low + + * New upstream release + * Use invoke-rc.d in logrotate script (Closes: Bug#174633) + + -- Mark Purcell Fri, 24 Jan 2003 21:57:43 +1100 + +asterisk (0.2.0-4) unstable; urgency=low + + * Add Build-Depends: bison (Closes: Bug#169312) + + -- Mark Purcell Sun, 17 Nov 2002 09:03:01 +1100 + +asterisk (0.2.0-3) unstable; urgency=low + + * Fixed bison problems. ThanksMartijn + * Move gethostname in app_voicemail.c (Closes: Bug#168936) + * Move 0.2.0 to unstable. If you have OSS problems use asterisk/testing. + + -- Mark Purcell Fri, 15 Nov 2002 20:36:03 +1100 + +asterisk (0.2.0-2) experimental; urgency=low + + * Incorporate changes from mdz (Remove graphviz, build astman) + * Force Build-Deps: bison-1.35 :( + + -- Mark Purcell Sat, 26 Oct 2002 12:59:12 +1000 + +asterisk (0.2.0-1) experimental; urgency=low + + * New upstream release (Closes: Bug#163852) + * Uploaded to experimental as I am having problems with the chan_oss driver + which is a critial component. + + -- Mark Purcell Wed, 9 Oct 2002 08:02:38 +1000 + +asterisk (0.1.12-5) unstable; urgency=low + + * Remove chown against /var/lib/asterisk (Closes: Bug#154774) + * Fixup vm symlink (Closes: Bug#158800) + * Fixup location of iaxtel.pub keys + + -- Mark Purcell Sun, 8 Sep 2002 20:56:24 +1000 + +asterisk (0.1.12-4) unstable; urgency=low + + * Seperate into indep packages; asterisk, asterisk-[sounds,dev,doc] + * Sounds & images from /var/lib/asterisk to FHS compliant /usr/share/asterisk + * Remove DEBUG options from normal build + * Include Build-Depends: doxygen + + -- Mark Purcell Wed, 24 Jul 2002 15:07:51 +1000 + +asterisk (0.1.12-3) unstable; urgency=low + + * Update Description + * Use dpkg-architecture to set processor optimisations (Closes: #153175) + + -- Mark Purcell Wed, 17 Jul 2002 21:23:33 +1000 + +asterisk (0.1.12-2) unstable; urgency=low + + * Fixup build check for /etc/asterisk + + -- Mark Purcell Tue, 9 Jul 2002 07:32:17 +1000 + +asterisk (0.1.12-1) unstable; urgency=low + + * New upstream release + * Fixup typo in /etc/init.d/asterisk + * Include [cdr_mysql.so] => (MySQL CDR Backend) + * Use excellent init.d script idea from Sim IJskes + * Fixup broken postinst & postinst scripts + + -- Mark Purcell Mon, 8 Jul 2002 23:07:27 +1000 + +asterisk (0.1.11-5) unstable; urgency=low + + * Include zaptel support (Closes: Bug#151274) + + -- Mark Purcell Fri, 5 Jul 2002 23:59:17 +1000 + +asterisk (0.1.11-4) unstable; urgency=low + + * Add init.d from Matt Zimmerman (Closes: Bug#150573) + * More updates from Matt Zimmerman: (Closes: Bug#151201) + - place socket and fifo in /var/run/asterisk instead of /var/run + - fix mkfifo call (bug uncovered by running as non-root), patch + sent upstream also + - create postinst with necessary adduser and chown calls + * Install logrotate from Matt Zimmerman (Closes: Bug#151198) + * Disable geteuid check to allow running as non-root + * Add asterisk to audio group by default + + -- Mark Purcell Sat, 29 Jun 2002 01:34:56 +1000 + +asterisk (0.1.11-3) unstable; urgency=high + + * Update cdr/Makefile to include CFLAGS+=-fPIC -DPIC (Closes: Bug#144052) + + -- Mark Purcell Sat, 27 Apr 2002 21:19:32 +1000 + +asterisk (0.1.11-2) unstable; urgency=low + + * Move from non-us to main/comm + * Update copyright file to reflect upstream CVS LICENCE change to permit + linking with OpenSSL/ OpenH323 (Closes: Bug#141164) + + -- Mark Purcell Fri, 19 Apr 2002 20:11:58 +1000 + +asterisk (0.1.11-1) unstable; urgency=low + + * New upstream release + * Update debian/control + * Include README.cdr & README.iax + + -- Mark Purcell Mon, 18 Mar 2002 15:46:39 +1100 + +asterisk (0.1.10-3) unstable; urgency=low + + * Include CFLAGS+=-fPIC -DPIC in res/Makefile for hppa build + + -- Mark Purcell Fri, 1 Mar 2002 20:58:02 +1100 + +asterisk (0.1.10-2) unstable; urgency=low + + * Change Build-Depends: libssl-dev (Closes: Bug#134821) + + -- Mark Purcell Wed, 20 Feb 2002 22:28:35 +1100 + +asterisk (0.1.10-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Wed, 20 Feb 2002 22:28:00 +1100 + +asterisk (0.1.9-5) unstable; urgency=low + + * Better make that Architecture: any if I want this to autobuild :-) + + -- Mark Purcell Wed, 2 Jan 2002 13:00:09 +1100 + +asterisk (0.1.9-4) unstable; urgency=low + + * Exclude MMX optimsed asm codecs/gsm/src/k6opt.s to enable non-x86 & + non-k6 builds (Closes: Bug#127225) + + -- Mark Purcell Wed, 2 Jan 2002 12:59:38 +1100 + +asterisk (0.1.9-3) unstable; urgency=low + + * New maintainer (Closes: Bug#123497) + * Set Arch to i386 as this contains x86 assember code + + -- Mark Purcell Sat, 29 Dec 2001 10:25:21 +1100 + +asterisk (0.1.9-2) unstable; urgency=high + + * apps/Makefile, codecs/gsm/Makefile: Missed an -mpentium in CFLAGS. + Closes: #126552. + + -- Matej Vela Thu, 27 Dec 2001 04:00:50 +0100 + +asterisk (0.1.9-1) unstable; urgency=medium + + * QA upload. + * New upstream version. + * Package is orphaned; maintainer set to Debian QA Group. + * debian/postrm: Ensure correct exit status. Closes: #105523. + * debian/control: s/API's/APIs/ Closes: #124423. + * debian/conffiles: Already handled by debhelper; removed. + * Conforms to Standards version 3.5.6: + * debian/copyright: Include module licensing exception and GSM and + ADPCM copyrights. + * debian/rules: + * Use dh_undocumented rather than a verbatim copy of undocumented.7. + * Pass ChangeLog to dh_installchangelogs. + * Support DEB_BUILD_OPTIONS. + + -- Matej Vela Tue, 25 Dec 2001 19:16:48 +0100 + +asterisk (0.1.6-1.2) unstable; urgency=low + + * NMU + * Fix makefiles, add -fPIC to builds. Closes: #104779 + + -- LaMont Jones Sun, 15 Jul 2001 15:15:46 -0600 + +asterisk (0.1.6-1.1) unstable; urgency=low + + * NMU with permission of Raphael Bossek. + * Corrected an error in channels/adtranvofr.h that prevented + big endian from compiling. (closes: #87273, #89868, #93913) + * Added build dependencies. + * Added the location of the upstream source to debian/copyright. + + -- Adrian Bunk Tue, 15 May 2001 00:22:31 +0200 + +asterisk (0.1.6-1) unstable; urgency=low + + * New upstream version. + + -- Raphael Bossek Mon, 19 Feb 2001 15:48:43 +0100 + --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-config.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-config.install @@ -0,0 +1 @@ +etc/asterisk --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-classic.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-classic.install @@ -0,0 +1,4 @@ +usr/lib/asterisk +usr/sbin +var/lib/asterisk +usr/share/asterisk/firmware/iax --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-bristuff.links +++ asterisk-1.2.12.1.dfsg/debian/asterisk-bristuff.links @@ -0,0 +1 @@ +usr/share/man/man8/asterisk.8 usr/share/man/man8/rasterisk.8 --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-gtk-console.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-gtk-console.install @@ -0,0 +1 @@ +usr/lib/asterisk/modules/pbx_gtkconsole.so --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-config.postinst +++ asterisk-1.2.12.1.dfsg/debian/asterisk-config.postinst @@ -0,0 +1,37 @@ +#! /bin/sh + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# + +case "$1" in + configure) + if [ -x /usr/share/asterisk/bin/asterisk_fix ]; then + /usr/share/asterisk/bin/asterisk_fix + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-doc.docs +++ asterisk-1.2.12.1.dfsg/debian/asterisk-doc.docs @@ -0,0 +1,10 @@ +BUGS +asterisk.sgml +README +CREDITS +HARDWARE +SECURITY +doc/* +contrib +images/*.gif +images/*.jpg --- asterisk-1.2.12.1.dfsg.orig/debian/README.Debian +++ asterisk-1.2.12.1.dfsg/debian/README.Debian @@ -0,0 +1,61 @@ +Welcome to the world of telephone switch owners. Asterisk is a quite powerful +and probably one of the feature-richest open-source PBXes out there. To get you +a brief impression where to start tweaking, we've included this doc. (Thanks to +Tzafrir Cohen for a proposal of this) + +File Locations +============== +See /etc/asterisk/asterisk.conf for pathnames. All the configuration is done +from the *.conf files there. + +Sounds reside at /usr/share/asterisk/sounds. Voicemail mailboxes are below +/var/spool/asterisk/voicemail using symlinks. + +User, Groups, Permissions +========================= +By default the package will create user and group 'asterisk' and will run as +them. It will optionally run with real-time priority (-p). It will also add +itself to the group audio to enable the daemon to access sound cards. Running +as root is disabled in /etc/init.d/asterisk for security reasons. If you use +zaptel devices (like zaphfc too), you need to set permissions on /dev/zap to +root.dialout or whatever other group you like and add the asterisk user to that +group. Then make sure all the devicenodes below /dev/zap/ are 660 or asterisk +will not have any access still. When no -G is given to the asterisk PARAMS, +then asterisk will automatically initialize all groups of the asterisk user. + +To change those values you can edit /etc/default/asterisk. You need to set +RUNASTERISK=yes to make asterisk autostart upon boot. + +init.d Script Commands +====================== +In addition to reload, that runs the asterisk CLI command 'reload' there +are also extensions-reload ('extensions reload') and logger-reload +('logger-reload') to load only parts of the configuration file. + +Asterisk supports a number of non-default paramters at startup. For debugging +it is often useful to run 'asterisk -U asterisk -vvvgc' from the console. Add +more -v for even higher verbosity. You can attach a remote console to a running +asterisk daemon with 'asterisk -vcr'. When testing, make sure to use the "-U +asterisk", or asterisk may write files with root ownership. In that case you +might not be able to restart the daemon without altering permissions to the +files first. + + +Getting started with config and more features +============================================= +Of course the default config is far from a plug'n'play for every environment. +You need to setup a proper dialplan in extensions.conf, remove the demo entries +and maybe remove FreeWorldDialup too in case you don't participate there. For +more info on how to setup a proper dialplan, fax, enum and configuration of +asterisk, please checkout + http://www.voip-info.org/wiki-Asterisk+quickstart + http://www.voip-info.org/wiki-Asterisk+config+files +or the larger HowTos at: + http://www.automated.it/guidetoasterisk.htm +or + http://www.asteriskdocs.org/ (Asterisk Handbook) + + +Enjoy your PBX! + +Kilian Krause (for the pkg-voip team) --- asterisk-1.2.12.1.dfsg.orig/debian/safe_asterisk.8 +++ asterisk-1.2.12.1.dfsg/debian/safe_asterisk.8 @@ -0,0 +1,62 @@ +.TH SAFE_ASTERISK 8 "Jun 30th, 2005" "Asterisk" "Linux Programmer's Manual" +.SH NAME +.B safe_asterisk +\(em A wrapper to run the asterisk executable in a loop +.SH SYNOPSIS +.PP +.B safe_asterisk +.I [ asterisk_params ] + +.SH DESCRIPTION +.B safe_asterisk +is a script that runs asterisk in a loop, which can be useful if you +fear asterisk may crash. + +The script does not run in the background like a standard service. Rather, +it runs in its own linux virtual console (9, by default). +It also uses the option '-c' of asterisk(8) to avoid detaching asterisk +from that terminal. + +safe_asterisk also runs asterisk with unlimited core file size, and thus +asterisk will dump core in case of a crash. + +To get a "picture" of console 9, from another terminal (e.g: from a +remote shell session) you can use: + + screendump 9 + +The init script of the Debian package should be able to run safe_asterisk +as the asterisk service, if so configured. See coments in +/etc/default/asterisk + +.SH FILES +.B /tmp +.RS +safe_asterisk runs in that directory, rather than in / as usual. +.RE + +.B /tmp/core +.RS +If core files were generated there, they may be +.RE + +.SH BUGS +While showing the output on a console is useful, using screen(1) as +the terminal may be better. + +The script does not read configuration from standard location under /etc + +It uses fixed locations under /tmp , and thus may be exposed to a +symlink attacks. + +.SH SEE ALSO +asterisk(8), screendump(9) + +.SH "AUTHOR" +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk_fix +++ asterisk-1.2.12.1.dfsg/debian/asterisk_fix @@ -0,0 +1,83 @@ +#! /bin/sh + +if getent passwd asterisk >/dev/null ;then + # Some halfbaked Sarge versions needed their home dir fixed: + if [ "`getent passwd asterisk|awk -F: '{print $6}'`" = \ + "/var/run/asterisk" ];then + usermod -d /var/lib/asterisk asterisk + fi +else + adduser_extra_opts="" + # Cosmetic noise reduction + if [ -d "/var/lib/asterisk" ]; then + adduser_extra_opts="--no-create-home" + fi + adduser --system --group --home /var/lib/asterisk \ + $adduser_extra_opts \ + --gecos "Asterisk PBX daemon" asterisk +fi + +for group in dialout audio; do + if groups asterisk | grep -w -q -v $group; then + adduser asterisk $group + fi +done + +# Make sure all (possibly) used dirs exist and is owned by asterisk + +# /var/run/asterisk is not yet handled by init.d :-( +# (/var/run/asterisk is handled in sysV script /etc/init.d/asterisk) + +dirs=" + /var/log/asterisk + /var/spool/asterisk + /var/lib/asterisk + /var/run/asterisk + /etc/asterisk +" + +subdirs=" + /var/log/asterisk/cdr-csv + /var/log/asterisk/cdr-custom + /var/spool/asterisk/dictate + /var/spool/asterisk/meetme + /var/spool/asterisk/monitor + /var/spool/asterisk/monitor + /var/spool/asterisk/system + /var/spool/asterisk/tmp + /var/spool/asterisk/voicemail +" + +for dir in $subdirs $dirs; do + mkdir -p "$dir" +done + +for dir in $dirs; do + chown -R asterisk: "$dir" +done + + +################################### +# this part should be reviewed, but it's basically trial and error +# code i wrote to make freepbx work. better solutions are welcomed. + +# files need to be RW by the group +# dirs need to a+rx +chmod -R 0660 /etc/asterisk/ +find /etc/asterisk/ -type d | xargs chmod ug+rx + +#chmod g+s /etc/asterisk/ + +# this is needed because othewise sqlite cannot write to the DB +#chmod -R 0660 /var/lib/asterisk/ + +#################################### +# If asterisk in running, reload it +# otherwise start it +if [ -f "/etc/init.d/asterisk" ];then + if [ -f /var/run/asterisk/asterisk.pid ];then + invoke-rc.d asterisk reload || exit $? + else + invoke-rc.d asterisk restart || exit $? + fi +fi --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-bristuff.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-bristuff.install @@ -0,0 +1,5 @@ +bristuff/usr/lib/asterisk usr/lib/ +bristuff/usr/sbin usr/ +bristuff/usr/share/man usr/share/ +bristuff/var/lib/asterisk var/lib/ +usr/share/asterisk/firmware/iax/ --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk.logrotate +++ asterisk-1.2.12.1.dfsg/debian/asterisk.logrotate @@ -0,0 +1,9 @@ +/var/log/asterisk/cdr-custom/Master.csv /var/log/asterisk/debug /var/log/asterisk/event_log /var/log/asterisk/messages { + weekly + missingok + rotate 4 + sharedscripts + postrotate + /usr/sbin/invoke-rc.d asterisk logger-reload + endscript +} --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-sounds-main.docs +++ asterisk-1.2.12.1.dfsg/debian/asterisk-sounds-main.docs @@ -0,0 +1 @@ +sounds.txt --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-classic.links +++ asterisk-1.2.12.1.dfsg/debian/asterisk-classic.links @@ -0,0 +1 @@ +usr/share/man/man8/asterisk.8 usr/share/man/man8/rasterisk.8 --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk.postrm +++ asterisk-1.2.12.1.dfsg/debian/asterisk.postrm @@ -0,0 +1,9 @@ +#! /bin/sh -e + +if [ "$1" = purge ]; then + userdel -r asterisk 2>/dev/null || true + rm -fR /var/log/asterisk + +fi + +#DEBHELPER# --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-sounds.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-sounds.install @@ -0,0 +1,3 @@ +usr/share/asterisk/sounds +usr/share/asterisk/mohmp3 +var/spool/asterisk --- asterisk-1.2.12.1.dfsg.orig/debian/patches/apprecord_sprintf.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/apprecord_sprintf.dpatch @@ -0,0 +1,105 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## apprecord_sprintf.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Fix format string issue in app_record. +## DP: http://bugs.digium.com/view.php?id=7811 + +@DPATCH@ +diff -urNad asterisk-1.2.10.dfsg/apps/app_record.c /tmp/dpep.UF8vRx/asterisk-1.2.10.dfsg/apps/app_record.c +--- asterisk-1.2.10.dfsg/apps/app_record.c 2005-11-29 20:24:39.000000000 +0200 ++++ /tmp/dpep.UF8vRx/asterisk-1.2.10.dfsg/apps/app_record.c 2006-08-30 21:43:35.007704143 +0300 +@@ -70,6 +70,34 @@ + "If the user should hangup during a recording, all data will be lost and the\n" + "application will teminate. \n"; + ++static char *filename_add_count(const char *fn, int count) ++{ ++ char *realname; ++ char *tmp; ++ char cnt[32]; ++ size_t i; ++ int can_subst = 1; ++ ++ snprintf(cnt, sizeof(cnt), "%d", count); ++ tmp = realname = malloc(strlen(fn) + strlen(cnt) + 1); ++ ++ while( *fn ) ++ { ++ if (*fn == '%' && can_subst && fn[1] == 'd') { ++ strcpy(tmp, cnt); ++ tmp+=strlen(tmp); ++ can_subst = 0; ++ fn++; ++ } else { ++ *tmp = *fn; ++ tmp++; ++ } ++ fn++; ++ } ++ return realname; ++} ++ ++ + STANDARD_LOCAL_USER; + + LOCAL_USER_DECL; +@@ -82,7 +110,7 @@ + char *filename, *ext = NULL, *silstr, *maxstr, *options; + char *vdata, *p; + int i = 0; +- char tmp[256]; ++ char *realfilename = NULL; + + struct ast_filestream *s = '\0'; + struct localuser *u; +@@ -177,23 +205,24 @@ + option_quiet = 1; + } + } +- + /* done parsing */ + + /* these are to allow the use of the %d in the config file for a wild card of sort to + create a new file with the inputed name scheme */ + if (percentflag) { +- do { +- snprintf(tmp, sizeof(tmp), filename, count); ++ realfilename = filename_add_count(filename, count); ++ count++; ++ while ( ast_fileexists(realfilename, ext, chan->language) != -1 ) ++ { ++ free(realfilename); ++ realfilename = filename_add_count(filename, count); + count++; +- } while ( ast_fileexists(tmp, ext, chan->language) != -1 ); +- pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); ++ } ++ pbx_builtin_setvar_helper(chan, "RECORDED_FILE", realfilename); + } else +- strncpy(tmp, filename, sizeof(tmp)-1); ++ realfilename = strdup(filename); + /* end of routine mentioned */ + +- +- + if (chan->_state != AST_STATE_UP) { + if (option_skip) { + /* At the user's option, skip if the line is not up */ +@@ -242,7 +271,7 @@ + + + flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; +- s = ast_writefile( tmp, ext, NULL, flags , 0, 0644); ++ s = ast_writefile( realfilename, ext, NULL, flags , 0, 0644); + + if (!s) { + ast_log(LOG_WARNING, "Could not create file %s\n", filename); +@@ -337,6 +366,7 @@ + if (sildet) + ast_dsp_free(sildet); + } ++ free(realfilename); + + LOCAL_USER_REMOVE(u); + --- asterisk-1.2.12.1.dfsg.orig/debian/patches/func_odbc_12.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/func_odbc_12.dpatch @@ -0,0 +1,908 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## func_odbc_12.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: The backport of func_odbc from +## DP: http://svncommunity.digium.com/svn/func_odbc/1.2/ , revision 9 +## DP: Code will be merged into trunk in 1.4. + +@DPATCH@ +diff -urNad asterisk-1.2.7.1.dfsg/configs/func_odbc.conf.sample /tmp/dpep.PgBRQP/asterisk-1.2.7.1.dfsg/configs/func_odbc.conf.sample +--- asterisk-1.2.7.1.dfsg/configs/func_odbc.conf.sample 1970-01-01 02:00:00.000000000 +0200 ++++ /tmp/dpep.PgBRQP/asterisk-1.2.7.1.dfsg/configs/func_odbc.conf.sample 2006-05-16 11:04:22.885412107 +0300 +@@ -0,0 +1,38 @@ ++; ++; func_odbc.conf ++; ++; Each context is a separately defined function. By convention, all ++; functions are entirely uppercase, so the defined contexts should also ++; be all-uppercase, but there is nothing that enforces this. All functions ++; are case-sensitive, however. ++; ++; For substitution, you have ${ARG1}, ${ARG2} ... ${ARGn} ++; for the arguments to each SQL statement. ++; ++; In addition, for write statements, you have ${VAL1}, ${VAL2} ... ${VALn} ++; parsed, just like arguments, for the values. In addition, if you want the ++; whole value, never mind the parsing, you can get that with ${VALUE}. ++; ++; ++; If you have data which may potentially contain single ticks, you may wish ++; to use the dialplan function SQL_ESC() to escape the data prior to its ++; inclusion in the SQL statement. ++ ++ ++; ODBC_SQL - Allow an SQL statement to be built entirely in the dialplan ++[SQL] ++dsn=mysql1 ++read=${ARG1} ++ ++; ODBC_ANTIGF - A blacklist. ++[ANTIGF] ++dsn=mysql1 ++read=SELECT COUNT(*) FROM exgirlfriends WHERE callerid='${SQL_ESC(${ARG1})}' ++ ++; ODBC_PRESENCE - Retrieve and update presence ++[PRESENCE] ++dsn=mysql1 ++read=SELECT location FROM presence WHERE id='${SQL_ESC(${ARG1})}' ++write=UPDATE presence SET location='${SQL_ESC(${VAL1})}' WHERE id='${SQL_ESC(${ARG1})}' ++;prefix=OFFICE ; Changes this function from ODBC_PRESENCE to OFFICE_PRESENCE ++ +diff -urNad asterisk-1.2.7.1.dfsg/funcs/func_array.c /tmp/dpep.PgBRQP/asterisk-1.2.7.1.dfsg/funcs/func_array.c +--- asterisk-1.2.7.1.dfsg/funcs/func_array.c 1970-01-01 02:00:00.000000000 +0200 ++++ /tmp/dpep.PgBRQP/asterisk-1.2.7.1.dfsg/funcs/func_array.c 2006-05-16 11:00:46.455618304 +0300 +@@ -0,0 +1,191 @@ ++/* ++ * Asterisk -- An open source telephony toolkit. ++ * ++ * Copyright (C) 2005, Tilghman Lesher. ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2. See the LICENSE file ++ * at the top of the source tree. ++ */ ++ ++/*! \file ++ * ++ * \brief ARRAY dialplan function ++ * ++ * \author Tilghman Lesher ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "asterisk.h" ++ ++ASTERISK_FILE_VERSION(__FILE__, "$Revision: 20003 $") ++ ++#include "asterisk/module.h" ++#include "asterisk/channel.h" ++#include "asterisk/pbx.h" ++#include "asterisk/logger.h" ++#include "asterisk/utils.h" ++#include "asterisk/app.h" ++#include "asterisk/localtime.h" ++ ++AST_MUTEX_DEFINE_STATIC(local_lock); ++static int use_count = 0; ++ ++static unsigned int trunk_app_separate_args(char *buf, char delim, char **array, int arraylen) ++{ ++ int argc; ++ char *scan; ++ int paren = 0, quote = 0; ++ ++ if (!buf || !array || !arraylen) ++ return 0; ++ ++ memset(array, 0, arraylen * sizeof(*array)); ++ ++ scan = buf; ++ ++ for (argc = 0; *scan && (argc < arraylen - 1); argc++) { ++ array[argc] = scan; ++ for (; *scan; scan++) { ++ if (*scan == '(') ++ paren++; ++ else if (*scan == ')') { ++ if (paren) ++ paren--; ++ } else if (*scan == '"') { ++ quote = quote ? 0 : 1; ++ /* Remove quote character from argument */ ++ memmove(scan, scan + 1, strlen(scan)); ++ scan--; ++ } else if (*scan == '\\') { ++ /* Literal character, don't parse */ ++ memmove(scan, scan + 1, strlen(scan)); ++ } else if ((*scan == delim) && !paren && !quote) { ++ *scan++ = '\0'; ++ break; ++ } ++ } ++ } ++ ++ if (*scan) ++ array[argc++] = scan; ++ ++ return argc; ++} ++ ++static void array(struct ast_channel *chan, char *cmd, char *var, const char *value) ++{ ++ AST_DECLARE_APP_ARGS(arg1, ++ AST_APP_ARG(var)[100]; ++ ); ++ AST_DECLARE_APP_ARGS(arg2, ++ AST_APP_ARG(val)[100]; ++ ); ++ char *value2; ++ int i; ++ ++ value2 = ast_strdupa(value); ++ if (!var || !value2) ++ return; ++ ++ ast_mutex_lock(&local_lock); ++ use_count++; ++ ast_mutex_unlock(&local_lock); ++ ++ /* The functions this will generally be used with are SORT and ODBC_*, which ++ * both return comma-delimited lists. However, if somebody uses literal lists, ++ * their commas will be translated to vertical bars by the load, and I don't ++ * want them to be surprised by the result. Hence, we prefer commas as the ++ * delimiter, but we'll fall back to vertical bars if commas aren't found. ++ */ ++ ast_log(LOG_DEBUG, "array (%s=%s)\n", var, value2); ++ if (strchr(var, ',')) ++ arg1.argc = trunk_app_separate_args(var, ',', arg1.argv, (sizeof(arg1) - sizeof(arg1.argc)) / sizeof(arg1.argv[0])); ++ else ++ arg1.argc = trunk_app_separate_args(var, '|', arg1.argv, (sizeof(arg1) - sizeof(arg1.argc)) / sizeof(arg1.argv[0])); ++ ++ if (strchr(value2, ',')) ++ arg2.argc = trunk_app_separate_args(value2, ',', arg2.argv, (sizeof(arg2) - sizeof(arg2.argc)) / sizeof(arg2.argv[0])); ++ else ++ arg2.argc = trunk_app_separate_args(value2, '|', arg2.argv, (sizeof(arg2) - sizeof(arg2.argc)) / sizeof(arg2.argv[0])); ++ ++ for (i = 0; i < arg1.argc; i++) { ++ ast_log(LOG_DEBUG, "array set value (%s=%s)\n", arg1.var[i], ++ arg2.val[i]); ++ if (i < arg2.argc) { ++ pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]); ++ } else { ++ /* We could unset the variable, by passing a NULL, but due to ++ * pushvar semantics, that could create some undesired behavior. */ ++ pbx_builtin_setvar_helper(chan, arg1.var[i], ""); ++ } ++ } ++ ++ ast_mutex_lock(&local_lock); ++ use_count--; ++ ast_mutex_unlock(&local_lock); ++ ++ return; ++} ++ ++static struct ast_custom_function array_function = { ++ .name = "ARRAY", ++ .synopsis = "Allows setting multiple variables at once", ++ .syntax = "ARRAY(var1[,var2[...][,varN]])", ++ .write = array, ++ .desc = ++ "The comma-separated list passed as a value to which the function is set will\n" ++ "be interpreted as a set of values to which the comma-separated list of\n" ++ "variable names in the argument should be set.\n" ++ "Hence, Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2\n" ++ "Note: remember to either backslash your commas in extensions.conf or quote the\n" ++ "entire argument, since Set can take multiple arguments itself.\n", ++}; ++ ++static char *tdesc = "String handling dialplan functions"; ++ ++int unload_module(void) ++{ ++ int res = 0; ++ ++ res |= ast_custom_function_unregister(&array_function); ++ sched_yield(); /* Any remaining process gets time to clear out. Increases safety if a force unload is attempted. */ ++ ++ return res; ++} ++ ++int load_module(void) ++{ ++ int res = 0; ++ ++ res |= ast_custom_function_register(&array_function); ++ ++ return res; ++} ++ ++char *description(void) ++{ ++ return tdesc; ++} ++ ++int usecount(void) ++{ ++ return use_count; ++} ++ ++char *key(void) ++{ ++ return ASTERISK_GPL_KEY; ++} ++ +diff -urNad asterisk-1.2.7.1.dfsg/funcs/func_odbc.c /tmp/dpep.PgBRQP/asterisk-1.2.7.1.dfsg/funcs/func_odbc.c +--- asterisk-1.2.7.1.dfsg/funcs/func_odbc.c 1970-01-01 02:00:00.000000000 +0200 ++++ /tmp/dpep.PgBRQP/asterisk-1.2.7.1.dfsg/funcs/func_odbc.c 2006-05-16 11:01:01.417565099 +0300 +@@ -0,0 +1,658 @@ ++/* ++ * Asterisk -- An open source telephony toolkit. ++ * ++ * Copyright (c) 2005 Tilghman Lesher ++ * ++ * Tilghman Lesher ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2. See the LICENSE file ++ * at the top of the source tree. ++ */ ++ ++/*! ++ * \file ++ * ++ * \brief ODBC lookups ++ * ++ * \author Tilghman Lesher ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "asterisk.h" ++ ++ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7 $") ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *tdesc = "ODBC lookups"; ++ ++static char *config = "func_odbc.conf"; ++ ++struct acf_odbc_query { ++ AST_LIST_ENTRY(acf_odbc_query) list; ++ char dsn[30]; ++ char sql_read[2048]; ++ char sql_write[2048]; ++ struct ast_custom_function *acf; ++}; ++ ++AST_LIST_HEAD_STATIC(queries, acf_odbc_query); ++ ++#ifdef NEEDTRACE ++static void acf_odbc_error(SQLHSTMT stmt, int res) ++{ ++ char state[10] = "", diagnostic[256] = ""; ++ SQLINTEGER nativeerror = 0; ++ SQLSMALLINT diagbytes = 0; ++ SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); ++ ast_log(LOG_WARNING, "SQL return value %d: error %s: %s (len %d)\n", res, state, diagnostic, diagbytes); ++} ++#endif ++ ++/* ++ * Master control routine ++ */ ++static void acf_odbc_write(struct ast_channel *chan, char *cmd, char *data, const char *value) ++{ ++ odbc_obj *obj; ++ struct acf_odbc_query *query; ++ char *s, *t, *arg, buf[2048]="", varname[15]; ++ int res, argcount=0, valcount=0, i, retry=0; ++ struct ast_channel *ast; ++ SQLHSTMT stmt; ++ SQLINTEGER nativeerror=0, numfields=0, rows=0; ++ SQLSMALLINT diagbytes=0; ++ unsigned char state[10], diagnostic[256]; ++#ifdef NEEDTRACE ++ SQLINTEGER enable = 1; ++ char *tracefile = "/tmp/odbc.trace"; ++#endif ++ ++ AST_LIST_LOCK(&queries); ++ AST_LIST_TRAVERSE(&queries, query, list) { ++ if (!strcmp(query->acf->name, cmd)) { ++ break; ++ } ++ } ++ ++ if (!query) { ++ ast_log(LOG_ERROR, "No such function '%s'\n", cmd); ++ AST_LIST_UNLOCK(&queries); ++ return; ++ } ++ ++ obj = fetch_odbc_obj(query->dsn, 0); ++ ++ if (!obj) { ++ ast_log(LOG_ERROR, "No such DSN registered: %s (check res_odbc.conf)\n", query->dsn); ++ AST_LIST_UNLOCK(&queries); ++ return; ++ } ++ ++ /* Parse our arguments */ ++ s = ast_strdupa(data); ++ if (value) { ++ t = ast_strdupa(value); ++ } else { ++ t = ""; ++ } ++ ++ if (!s || !t) { ++ ast_log(LOG_ERROR, "Out of memory\n"); ++ AST_LIST_UNLOCK(&queries); ++ return; ++ } ++ ++ /* XXX You might be tempted to change this section into using ++ * pbx_builtin_pushvar_helper(). However, note that if you try ++ * to set a NULL (like for VALUE), then nothing gets set, and the ++ * value doesn't get masked out. Even worse, when you subsequently ++ * try to remove the value you just set, you'll wind up unsetting ++ * the previous value (which is wholly undesireable). Hence, this ++ * has to remain the way it is done here. XXX ++ */ ++ ++ /* Save old arguments as variables in a fake channel */ ++ ast = ast_channel_alloc(0); ++ while ((arg = strsep(&s, "|"))) { ++ argcount++; ++ snprintf(varname, sizeof(varname), "ARG%d", argcount); ++ pbx_builtin_setvar_helper(ast, varname, pbx_builtin_getvar_helper(chan, varname)); ++ pbx_builtin_setvar_helper(chan, varname, arg); ++ } ++ ++ /* Parse values, just like arguments */ ++ while ((arg = strsep(&t, "|"))) { ++ valcount++; ++ snprintf(varname, sizeof(varname), "VAL%d", valcount); ++ pbx_builtin_setvar_helper(ast, varname, pbx_builtin_getvar_helper(chan, varname)); ++ pbx_builtin_setvar_helper(chan, varname, arg); ++ } ++ ++ /* Additionally set the value as a whole */ ++ /* Note that pbx_builtin_setvar_helper will quite happily take a NULL for the 3rd argument */ ++ pbx_builtin_setvar_helper(ast, "VALUE", pbx_builtin_getvar_helper(chan, "VALUE")); ++ pbx_builtin_setvar_helper(chan, "VALUE", value); ++ ++ pbx_substitute_variables_helper(chan, query->sql_write, buf, sizeof(buf) - 1); ++ ++ /* Restore prior values */ ++ for (i=1; i<=argcount; i++) { ++ snprintf(varname, sizeof(varname), "ARG%d", argcount); ++ pbx_builtin_setvar_helper(chan, varname, pbx_builtin_getvar_helper(ast, varname)); ++ } ++ ++ for (i=1; i<=valcount; i++) { ++ snprintf(varname, sizeof(varname), "VAL%d", argcount); ++ pbx_builtin_setvar_helper(chan, varname, pbx_builtin_getvar_helper(ast, varname)); ++ } ++ pbx_builtin_setvar_helper(chan, "VALUE", pbx_builtin_getvar_helper(ast, "VALUE")); ++ ++ ast_channel_free(ast); ++ AST_LIST_UNLOCK(&queries); ++ ++retry_write: ++#ifdef NEEDTRACE ++ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); ++ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); ++#endif ++ ++ res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); ++ pbx_builtin_setvar_helper(chan, "ODBCROWS", "-1"); ++ return; ++ } ++ ++ res = SQLPrepare(stmt, (unsigned char *)buf, SQL_NTS); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", buf); ++ SQLFreeHandle (SQL_HANDLE_STMT, stmt); ++ pbx_builtin_setvar_helper(chan, "ODBCROWS", "-1"); ++ return; ++ } ++ ++ res = SQLExecute(stmt); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ if (res == SQL_ERROR) { ++ SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); ++ for (i = 0; i <= numfields; i++) { ++ SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); ++ ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); ++ if (i > 10) { ++ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); ++ break; ++ } ++ } ++ } ++ SQLFreeHandle(SQL_HANDLE_STMT, stmt); ++ odbc_obj_disconnect(obj); ++ /* All handles are now invalid (after a disconnect), so we gotta redo all handles */ ++ odbc_obj_connect(obj); ++ if (!retry) { ++ retry = 1; ++ goto retry_write; ++ } ++ rows = -1; ++ } else { ++ /* Rows affected */ ++ SQLRowCount(stmt, &rows); ++ } ++ ++ /* Output the affected rows, for all cases. In the event of failure, we ++ * flag this as -1 rows. Note that this is different from 0 affected rows ++ * which would be the case if we succeeded in our query, but the values did ++ * not change. */ ++ snprintf(varname, sizeof(varname), "%d", (int)rows); ++ pbx_builtin_setvar_helper(chan, "ODBCROWS", varname); ++ ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", buf); ++ } ++ ++ SQLFreeHandle(SQL_HANDLE_STMT, stmt); ++} ++ ++static char *acf_odbc_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) ++{ ++ odbc_obj *obj; ++ struct acf_odbc_query *query; ++ char *s, *arg, sql[2048] = "", varname[15]; ++ int count=0, res, x, buflen = 0; ++ SQLHSTMT stmt; ++ SQLSMALLINT colcount=0; ++ SQLINTEGER indicator; ++#ifdef NEEDTRACE ++ SQLINTEGER enable = 1; ++ char *tracefile = "/tmp/odbc.trace"; ++#endif ++ ++ AST_LIST_LOCK(&queries); ++ AST_LIST_TRAVERSE(&queries, query, list) { ++ if (!strcmp(query->acf->name, cmd)) { ++ break; ++ } ++ } ++ ++ if (!query) { ++ ast_log(LOG_ERROR, "No such function '%s'\n", cmd); ++ AST_LIST_UNLOCK(&queries); ++ return ""; ++ } ++ ++ obj = fetch_odbc_obj(query->dsn, 0); ++ ++ if (!obj) { ++ ast_log(LOG_ERROR, "No such DSN registered: %s (check res_odbc.conf)\n", query->dsn); ++ AST_LIST_UNLOCK(&queries); ++ return ""; ++ } ++ ++#ifdef NEEDTRACE ++ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER); ++ SQLSetConnectAttr(obj->con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile)); ++#endif ++ ++ /* Parse our arguments */ ++ if (!(s = ast_strdupa(data))) { ++ AST_LIST_UNLOCK(&queries); ++ return ""; ++ } ++ ++ while ((arg = strsep(&s, "|"))) { ++ count++; ++ snprintf(varname, sizeof(varname), "ARG%d", count); ++ /* arg is by definition non-NULL, so this works, here */ ++ pbx_builtin_pushvar_helper(chan, varname, arg); ++ } ++ ++ pbx_substitute_variables_helper(chan, query->sql_read, sql, sizeof(sql) - 1); ++ ++ /* Restore prior values */ ++ for (x = 1; x <= count; x++) { ++ snprintf(varname, sizeof(varname), "ARG%d", x); ++ pbx_builtin_setvar_helper(chan, varname, NULL); ++ } ++ ++ AST_LIST_UNLOCK(&queries); ++ ++ res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); ++ return ""; ++ } ++ ++ res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); ++ SQLFreeHandle (SQL_HANDLE_STMT, stmt); ++ return ""; ++ } ++ ++ res = odbc_smart_execute(obj, stmt); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); ++ SQLFreeHandle (SQL_HANDLE_STMT, stmt); ++ return ""; ++ } ++ ++ res = SQLNumResultCols(stmt, &colcount); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); ++ SQLFreeHandle (SQL_HANDLE_STMT, stmt); ++ return ""; ++ } ++ ++ memset(buf, 0, len); ++ ++ res = SQLFetch(stmt); ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ if (res == SQL_NO_DATA) { ++ if (option_verbose > 3) { ++ ast_verbose(VERBOSE_PREFIX_4 "Found no rows [%s]\n", sql); ++ } ++ } else if (option_verbose > 3) { ++ ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql); ++ } ++ goto acf_out; ++ } ++ ++ for (x = 0; x < colcount; x++) { ++ int i; ++ char coldata[256]; ++ ++ buflen = strlen(buf); ++ res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata, sizeof(coldata), &indicator); ++ if (indicator == SQL_NULL_DATA) { ++ coldata[0] = '\0'; ++ res = SQL_SUCCESS; ++ } ++ ++ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { ++ ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); ++ SQLFreeHandle(SQL_HANDLE_STMT, stmt); ++ return ""; ++ } ++ ++ /* Copy data, encoding '\' and ',' for the argument parser */ ++ for (i = 0; i < sizeof(coldata); i++) { ++ if (coldata[i] == '\\' || coldata[i] == ',') { ++ buf[buflen++] = '\\'; ++ } ++ buf[buflen++] = coldata[i]; ++ ++ if (buflen >= len - 2) { ++ buf[buflen >= len ? len - 1 : buflen] = '\0'; ++ break; ++ } ++ ++ if (coldata[i] == '\0') ++ break; ++ } ++ ++ buf[buflen - 1] = ','; ++ } ++ /* Trim trailing comma */ ++ buf[buflen - 1] = '\0'; ++ ++acf_out: ++ SQLFreeHandle(SQL_HANDLE_STMT, stmt); ++ return buf; ++} ++ ++static char *acf_escape(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) ++{ ++ char *in, *out = buf; ++ for (in = data; *in && out - buf < len; in++) { ++ if (*in == '\'') { ++ *out = '\''; ++ out++; ++ } ++ *out = *in; ++ out++; ++ } ++ *out = '\0'; ++ return buf; ++} ++ ++static struct ast_custom_function escape_function = { ++ .name = "SQL_ESC", ++ .synopsis = "Escapes single ticks for use in SQL statements", ++ .syntax = "SQL_ESC()", ++ .desc = ++"Used in SQL templates to escape data which may contain single ticks (') which\n" ++"are otherwise used to delimit data. For example:\n" ++"SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'\n", ++ .read = acf_escape, ++ .write = NULL, ++}; ++ ++ ++ ++static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query) ++{ ++ char *tmp; ++ ++ if (!cfg || !catg) { ++ return -1; ++ } ++ ++ *query = calloc(1, sizeof(struct acf_odbc_query)); ++ if (! (*query)) ++ return -1; ++ ++ if ((tmp = ast_variable_retrieve(cfg, catg, "dsn"))) { ++ ast_copy_string((*query)->dsn, tmp, sizeof((*query)->dsn)); ++ } else { ++ return -1; ++ } ++ ++ if ((tmp = ast_variable_retrieve(cfg, catg, "read"))) { ++ ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); ++ } ++ ++ if ((tmp = ast_variable_retrieve(cfg, catg, "write"))) { ++ ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); ++ } ++ ++ (*query)->acf = calloc(1, sizeof(struct ast_custom_function)); ++ if (! (*query)->acf) { ++ free(*query); ++ return -1; ++ } ++ ++ if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { ++ asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg); ++ } else { ++ asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg); ++ } ++ ++ if (!((*query)->acf->name)) { ++ free((*query)->acf); ++ free(*query); ++ return -1; ++ } ++ ++ asprintf((char **)&((*query)->acf->syntax), "%s([...[,]])", (*query)->acf->name); ++ ++ if (!((*query)->acf->syntax)) { ++ free((char *)(*query)->acf->name); ++ free((*query)->acf); ++ free(*query); ++ return -1; ++ } ++ ++ (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; ++ if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { ++ asprintf((char **)&((*query)->acf->desc), ++ "Runs the following query, as defined in func_odbc.conf, performing\n" ++ "substitution of the arguments into the query as specified by ${ARG1},\n" ++ "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" ++ "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" ++ "\nRead:\n%s\n\nWrite:\n%s\n", ++ (*query)->sql_read, ++ (*query)->sql_write); ++ } else if (!ast_strlen_zero((*query)->sql_read)) { ++ asprintf((char **)&((*query)->acf->desc), ++ "Runs the following query, as defined in func_odbc.conf, performing\n" ++ "substitution of the arguments into the query as specified by ${ARG1},\n" ++ "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", ++ (*query)->sql_read); ++ } else if (!ast_strlen_zero((*query)->sql_write)) { ++ asprintf((char **)&((*query)->acf->desc), ++ "Runs the following query, as defined in func_odbc.conf, performing\n" ++ "substitution of the arguments into the query as specified by ${ARG1},\n" ++ "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" ++ "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" ++ "This function may only be set.\nSQL:\n%s\n", ++ (*query)->sql_write); ++ } ++ ++ /* Could be out of memory, or could be we have neither sql_read nor sql_write */ ++ if (! ((*query)->acf->desc)) { ++ free((char *)(*query)->acf->syntax); ++ free((char *)(*query)->acf->name); ++ free((*query)->acf); ++ free(*query); ++ return -1; ++ } ++ ++ if (ast_strlen_zero((*query)->sql_read)) { ++ (*query)->acf->read = NULL; ++ } else { ++ (*query)->acf->read = acf_odbc_read; ++ } ++ ++ if (ast_strlen_zero((*query)->sql_write)) { ++ (*query)->acf->write = NULL; ++ } else { ++ (*query)->acf->write = acf_odbc_write; ++ } ++ ++ return 0; ++} ++ ++static int free_acf_query(struct acf_odbc_query *query) ++{ ++ if (query) { ++ if (query->acf) { ++ if (query->acf->name) ++ free(query->acf->name); ++ if (query->acf->syntax) ++ free(query->acf->syntax); ++ if (query->acf->desc) ++ free(query->acf->desc); ++ free(query->acf); ++ } ++ free(query); ++ } ++ return 0; ++} ++ ++static int odbc_load_module(void) ++{ ++ int res = 0; ++ struct ast_config *cfg; ++ char *catg; ++ ++ AST_LIST_LOCK(&queries); ++ ++ cfg = ast_config_load(config); ++ if (!cfg) { ++ ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); ++ AST_LIST_UNLOCK(&queries); ++ return -1; ++ } ++ ++ for (catg = ast_category_browse(cfg, NULL); ++ catg; ++ catg = ast_category_browse(cfg, catg)) { ++ struct acf_odbc_query *query = NULL; ++ ++ if (init_acf_query(cfg, catg, &query)) { ++ ast_log(LOG_ERROR, "Out of memory\n"); ++ free_acf_query(query); ++ } else { ++ AST_LIST_INSERT_HEAD(&queries, query, list); ++ ast_custom_function_register(query->acf); ++ } ++ } ++ ++ ast_config_destroy(cfg); ++ ast_custom_function_register(&escape_function); ++ ++ AST_LIST_UNLOCK(&queries); ++ return res; ++} ++ ++static int odbc_unload_module(void) ++{ ++ struct acf_odbc_query *query; ++ ++ AST_LIST_LOCK(&queries); ++ while (!AST_LIST_EMPTY(&queries)) { ++ query = AST_LIST_REMOVE_HEAD(&queries, list); ++ ast_custom_function_unregister(query->acf); ++ free_acf_query(query); ++ } ++ ++ ast_custom_function_unregister(&escape_function); ++ ++ /* Allow any threads waiting for this lock to pass (avoids a race) */ ++ AST_LIST_UNLOCK(&queries); ++ AST_LIST_LOCK(&queries); ++ ++ AST_LIST_UNLOCK(&queries); ++ return 0; ++} ++ ++int reload(void) ++{ ++ int res = 0; ++ struct ast_config *cfg; ++ struct acf_odbc_query *oldquery; ++ char *catg; ++ ++ AST_LIST_LOCK(&queries); ++ ++ while (!AST_LIST_EMPTY(&queries)) { ++ oldquery = AST_LIST_REMOVE_HEAD(&queries, list); ++ ast_custom_function_unregister(oldquery->acf); ++ free_acf_query(oldquery); ++ } ++ ++ cfg = ast_config_load(config); ++ if (!cfg) { ++ ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); ++ goto reload_out; ++ } ++ ++ for (catg = ast_category_browse(cfg, NULL); ++ catg; ++ catg = ast_category_browse(cfg, catg)) { ++ struct acf_odbc_query *query = NULL; ++ ++ if (init_acf_query(cfg, catg, &query)) { ++ ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); ++ } else { ++ AST_LIST_INSERT_HEAD(&queries, query, list); ++ ast_custom_function_register(query->acf); ++ } ++ } ++ ++ ast_config_destroy(cfg); ++reload_out: ++ AST_LIST_UNLOCK(&queries); ++ return res; ++} ++ ++int unload_module(void) ++{ ++ return odbc_unload_module(); ++} ++ ++int load_module(void) ++{ ++ return odbc_load_module(); ++} ++ ++char *description(void) ++{ ++ return tdesc; ++} ++ ++int usecount(void) ++{ ++ if (! ast_mutex_trylock(&(&queries)->lock)) { ++ ast_mutex_unlock(&(&queries)->lock); ++ return 0; ++ } else { ++ return 1; ++ } ++} ++ ++char *key() ++{ ++ return ASTERISK_GPL_KEY; ++} --- asterisk-1.2.12.1.dfsg.orig/debian/patches/option_detach.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/option_detach.dpatch @@ -0,0 +1,58 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## option_detach.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: when running asterisk -F: detach, even if -v or -d was given +## -- applied upstream as -F option to *force* forking +## -- in trunk (will be 1.4.x) + +@DPATCH@ +diff -urNad asterisk/asterisk.c /tmp/dpep.ahsnFR/asterisk/asterisk.c +--- asterisk/asterisk.c 2006-01-07 15:19:34.000000000 +0200 ++++ /tmp/dpep.ahsnFR/asterisk/asterisk.c 2006-01-07 23:18:59.000000000 +0200 +@@ -147,6 +147,7 @@ + int option_nofork=0; /*!< Do not fork */ + int option_quiet=0; /*!< Keep quiet */ + int option_console=0; /*!< Console mode, no background */ ++int option_daemonize=0; /*!< Daemonize. Ever if -v or -d */ + int option_highpriority=0; /*!< Run in realtime Linux priority */ + int option_remote=0; /*!< Remote CLI */ + int option_exec=0; /*!< */ +@@ -1833,6 +1834,7 @@ + printf(" -G Run as a group other than the caller\n"); + printf(" -U Run as a user other than the caller\n"); + printf(" -c Provide console CLI\n"); ++ printf(" -F Force Fork even if -v or -d were given\n"); + printf(" -d Enable extra debugging\n"); + printf(" -f Do not fork\n"); + printf(" -g Dump core in case of a crash\n"); +@@ -2048,7 +2050,7 @@ + } + */ + /* Check for options */ +- while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:L:M:")) != -1) { ++ while((c=getopt(argc, argv, "tThfdvVqprRgcFinx:U:G:C:L:M:")) != -1) { + switch(c) { + case 'd': + option_debug++; +@@ -2058,6 +2060,9 @@ + option_console++; + option_nofork++; + break; ++ case 'F': ++ option_daemonize++; ++ break; + case 'f': + option_nofork++; + break; +@@ -2250,7 +2255,9 @@ + } else + ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno)); + +- if (!option_verbose && !option_debug && !option_nofork && !option_console) { ++ if (option_daemonize || ++ (!option_verbose && !option_debug && !option_nofork && !option_console) ++ ) { + daemon(0,0); + /* Blindly re-write pid file since we are forking */ + unlink((char *)ast_config_AST_PID); --- asterisk-1.2.12.1.dfsg.orig/debian/patches/sys_readline.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/sys_readline.dpatch @@ -0,0 +1,404 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## sys_readline.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Use readline for the CLI. partially works. + +@DPATCH@ +diff -urNad asterisk-1.2.9.1.dfsg/asterisk.c /tmp/dpep.eom8T2/asterisk-1.2.9.1.dfsg/asterisk.c +--- asterisk-1.2.9.1.dfsg/asterisk.c 2006-08-11 10:31:42.000000000 +0300 ++++ /tmp/dpep.eom8T2/asterisk-1.2.9.1.dfsg/asterisk.c 2006-08-11 10:28:15.000000000 +0300 +@@ -114,7 +114,12 @@ + #include "asterisk/file.h" + #include "asterisk/io.h" + #include "asterisk/lock.h" ++#ifdef SYS_READLINE ++#include ++#include ++#else /* SYS_READLINE */ + #include "editline/histedit.h" ++#endif /* SYS_READLINE */ + #include "asterisk/config.h" + #include "asterisk/version.h" + #include "asterisk/linkedlists.h" +@@ -198,17 +203,23 @@ + time_t ast_startuptime; + time_t ast_lastreloadtime; + ++#ifdef SYS_READLINE ++static const char * rl_readline_name = "asterisk"; ++#else + static History *el_hist = NULL; + static EditLine *el = NULL; ++#endif /* SYS_READLINE */ + static char *remotehostname; + + struct console consoles[AST_MAX_CONNECTS]; + + char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE; + ++#ifndef SYS_READLINE + static int ast_el_add_history(char *); + static int ast_el_read_history(char *); + static int ast_el_write_history(char *); ++#endif /* SYS_READLINE */ + + char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH]; + char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH]; +@@ -719,6 +730,15 @@ + ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); + return 0; + } ++#ifdef SYS_READLINE ++ /* If we use readline, we'll use its main loop, and non-blocking ++ * reads */ ++ if (0 != fcntl(ast_consock, F_SETFL, O_NONBLOCK)) { ++ ast_log(LOG_WARNING, "Unable to set socket non-blocking: %s\n", ++ strerror(errno)); ++ return 0; ++ } ++#endif + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_LOCAL; + ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)); +@@ -891,11 +911,15 @@ + if (getenv("HOME")) + snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); + if (!ast_strlen_zero(filename)) ++#ifdef SYS_READLINE ++ write_history(filename); ++#else /* SYS_READLINE */ + ast_el_write_history(filename); + if (el != NULL) + el_end(el); + if (el_hist != NULL) + history_end(el_hist); ++#endif /* SYS_READLINE */ + } + if (option_verbose) + ast_verbose("Executing last minute cleanups\n"); +@@ -1003,7 +1027,11 @@ + fflush(stdout); + /* Called when readline data is available */ + if (s && !ast_all_zeros(s)) ++#ifdef SYS_READLINE ++ add_history(s); ++#else /* SYS_READLINE */ + ast_el_add_history(s); ++#endif /* SYS_READLINE */ + /* Give the console access to the shell */ + if (s) { + /* The real handler for bang */ +@@ -1023,7 +1051,11 @@ + int ret = 0; + /* Called when readline data is available */ + if (s && !ast_all_zeros(s)) ++#ifdef SYS_READLINE ++ add_history(s); ++#else /* SYS_READLINE */ + ast_el_add_history(s); ++#endif /* SYS_READLINE */ + /* Give the console access to the shell */ + if (s) { + /* The real handler for bang */ +@@ -1255,7 +1287,73 @@ + #endif /* ! LOW_MEMORY */ + }; + ++ ++static void attempt_reconnect(void) ++{ ++ int tries; ++ int reconnects_per_second = 20; ++ fprintf(stderr, "Attempting to reconnect for 30 seconds\n"); ++ for (tries=0;tries<30 * reconnects_per_second;tries++) { ++ if (ast_tryconnect()) { ++ fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries); ++ printf(term_quit()); ++ WELCOME_MESSAGE; ++ break; ++ } else { ++ usleep(1000000 / reconnects_per_second); ++ } ++ } ++ if (tries >= 30 * reconnects_per_second) { ++ fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n"); ++ quit_handler(0, 0, 0, 0); ++ } ++} ++ ++/* Called by readline every 0.1 seconds or so from its main loop. */ ++static int ast_rl_event_hook(void) ++{ ++#ifdef SYS_READLINE ++ int res; ++ char buf[512]; ++ ++ res = read(ast_consock, buf, sizeof(buf) - 1); ++ /* if the remote side disappears exit */ ++ if ((res == -1) && (errno == EAGAIN)) ++ return 0; /* There was nothing to read. Maybe next time. */ ++ ++ if (res < 1) { ++ fprintf(stderr, "\nDisconnected from Asterisk server: %s.\n", ++ strerror(errno)); ++ if (!option_reconnect) { ++ quit_handler(0, 0, 0, 0); ++ } else { ++ attempt_reconnect(); ++ } ++ /* never reached */ ++ } ++ ++ buf[res] = '\0'; ++ ++ /* Let's assume we always get complete lines in read-s */ ++ fputc('\r', rl_outstream); /* to beginning of line... */ ++ /* suppress an excessive linefeed: */ ++ fputs(buf, rl_outstream); /* The text itself */ ++ if (option_exec) ++ return 0; ++ /* and refresh readline's prompt */ ++ rl_forced_update_display(); ++ ++ return 0; ++#endif ++} ++ ++#ifdef SYS_READLINE ++/* TODO: this #define means we're doing something wrong. */ ++#define CC_REFRESH 4 ++static int ast_rl_read_char(char *cp) ++#else + static int ast_el_read_char(EditLine *el, char *cp) ++#endif + { + int num_read=0; + int lastpos=0; +@@ -1334,13 +1432,15 @@ + return (0); + } + +-static char *cli_prompt(EditLine *el) ++static char *cli_prompt(void) + { + static char prompt[200]; + char *pfmt; + int color_used=0; + char term_code[20]; + ++ if (option_exec) ++ return ""; + if ((pfmt = getenv("ASTERISK_PROMPT"))) { + char *t = pfmt, *p = prompt; + memset(prompt, 0, sizeof(prompt)); +@@ -1479,6 +1579,45 @@ + return(prompt); + } + ++#ifdef SYS_READLINE ++#define AST_RL_COMPL_BUFLEN (2048) ++static char* ast_rl_completion_function(const char *text, int state) ++{ ++ char buf[AST_RL_COMPL_BUFLEN]; ++ int len, res; ++ char *resbuf; ++ ++ //fprintf(stderr, "\nINPUT: %3d, \"%s\"\n", state, text); ++ if (! option_remote ) ++ return ast_cli_generator(rl_line_buffer, (char*)text, state); ++ ++ /* option_remote is set */ ++ snprintf(buf, sizeof(buf),"_command complete \"%s\" \"%s\" %d", ++ rl_line_buffer, text, state); ++ //fprintf(stderr, "\nSEND: \"%s\"\n", buf); ++ fdprint(ast_consock, buf); ++ res = read(ast_consock, buf, sizeof(buf)); ++ if (res <= 0) { ++ //fprintf(stderr,"\nREAD ERROR: %d, (%d: %s)\n", ++ // res, errno, strerror(errno)); ++ return NULL; ++ } ++ buf[res] = '\0'; ++ if (! strncmp(buf,"NULL\n",5)) ++ return NULL; ++ if (buf[0] == '\0') ++ return NULL; ++ //fprintf(stderr, "\nGOT: %3d, \"%s\"\n", res, buf); ++ ++ /* buf now contains the result word */ ++ len = strlen(buf)+1; ++ resbuf = malloc(len); ++ if (!resbuf) ++ return NULL; ++ ast_copy_string(resbuf, buf, len); ++ return resbuf; ++} ++#else /* SYS_READLINE */ + static char **ast_el_strtoarr(char *buf) + { + char **match_list = NULL, *retstr; +@@ -1756,6 +1895,23 @@ + + return ret; + } ++#endif /* SYS_READLINE */ ++ ++static void ast_rl_initialize(void) ++{ ++ static int initilized = 0; ++ /* ignore races for the moment */ ++ if (!initilized) { ++ rl_initialize(); ++ //rl_set_prompt(cli_prompt()); ++ rl_readline_name = cli_prompt(); ++ rl_event_hook = ast_rl_event_hook; ++ //rl_attempted_completion_function = ast_rl_completion_function; ++ rl_completion_entry_function = ast_rl_completion_function; ++ //fprintf(stderr, "===INITILIZING READLINE==[%s]====\n", cli_prompt()); ++ initilized = 1; ++ } ++} + + static void ast_remotecontrol(char * data) + { +@@ -1770,7 +1926,7 @@ + char *stringp=NULL; + + char *ebuf; +- int num = 0; ++ //int num = 0; + + read(ast_consock, buf, sizeof(buf)); + if (data) +@@ -1795,6 +1951,9 @@ + remotehostname = hostname; + if (getenv("HOME")) + snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); ++#ifdef SYS_READLINE ++ ast_rl_initialize(); ++#else /* SYS_READLINE */ + if (el_hist == NULL || el == NULL) + ast_el_initialize(); + +@@ -1802,7 +1961,8 @@ + + if (!ast_strlen_zero(filename)) + ast_el_read_history(filename); +- ++#endif /* SYS_READLINE */ ++ + if (option_exec && data) { /* hack to print output then exit if asterisk -rx is used */ + char tempchar; + #ifdef __Darwin__ +@@ -1814,12 +1974,20 @@ + ast_el_read_char(el, &tempchar); + } + #else ++#ifdef SYS_READLINE ++ while (!ast_rl_read_char(&tempchar)); ++#else /* SYS_READLINE */ + while (!ast_el_read_char(el, &tempchar)); ++#endif /* SYS_READLINE */ + #endif + return; + } + for(;;) { ++#ifdef SYS_READLINE ++ ebuf = readline(cli_prompt()); ++#else /* SYS_READLINE */ + ebuf = (char *)el_gets(el, &num); ++#endif /* SYS_READLINE */ + + if (!ast_strlen_zero(ebuf)) { + if (ebuf[strlen(ebuf)-1] == '\n') +@@ -2029,7 +2197,7 @@ + int x; + FILE *f; + sigset_t sigs; +- int num; ++ //int num; + int is_child_of_nonroot=0; + char *buf; + char *runuser=NULL, *rungroup=NULL; +@@ -2227,6 +2395,10 @@ + ast_log(LOG_WARNING, "Unable to initialize supplementary group list for %s\n", runuser); + exit(1); + } ++ if (!rungroup && initgroups(runuser, pw->pw_gid)) { ++ ast_log(LOG_WARNING, "Unable to initialize supplementary group list for %s\n", runuser); ++ exit(1); ++ } + if (setuid(pw->pw_uid)) { + ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser); + exit(1); +@@ -2260,11 +2432,15 @@ + + + if (option_console) { ++#ifdef SYS_READLINE ++ ast_rl_initialize(); ++#else + if (el_hist == NULL || el == NULL) + ast_el_initialize(); + + if (!ast_strlen_zero(filename)) + ast_el_read_history(filename); ++#endif /* SYS_READLINE */ + } + + if (ast_tryconnect()) { +@@ -2442,7 +2619,8 @@ + set_title(title); + + for (;;) { +- buf = (char *)el_gets(el, &num); ++ //buf = (char *)el_gets(el, &num); ++ buf = readline(cli_prompt()); + if (buf) { + if (buf[strlen(buf)-1] == '\n') + buf[strlen(buf)-1] = '\0'; +diff -urNad asterisk-1.2.9.1.dfsg/cli.c /tmp/dpep.eom8T2/asterisk-1.2.9.1.dfsg/cli.c +--- asterisk-1.2.9.1.dfsg/cli.c 2006-08-11 10:31:41.000000000 +0300 ++++ /tmp/dpep.eom8T2/asterisk-1.2.9.1.dfsg/cli.c 2006-08-11 10:31:45.000000000 +0300 +@@ -44,7 +44,15 @@ + #include "asterisk/utils.h" + #include "asterisk/lock.h" + /* For rl_filename_completion */ ++#ifndef SYS_READLINE + #include "editline/readline/readline.h" ++#else ++# ifdef SYS_READLINE_EDIT ++# include ++# else ++# include ++# endif ++#endif + /* For module directory */ + #include "asterisk/version.h" + +diff -urNad asterisk-1.2.9.1.dfsg/Makefile /tmp/dpep.eom8T2/asterisk-1.2.9.1.dfsg/Makefile +--- asterisk-1.2.9.1.dfsg/Makefile 2006-08-11 10:31:42.000000000 +0300 ++++ /tmp/dpep.eom8T2/asterisk-1.2.9.1.dfsg/Makefile 2006-08-11 10:31:45.000000000 +0300 +@@ -306,7 +306,11 @@ + + endif # WITHOUT_ZAPTEL + +-LIBEDIT=editline/libedit.a ++#LIBEDIT=editline/libedit.a ++#LIBS+=-ledit ++LIBS+=-lreadline ++ASTCFLAGS+=-DSYS_READLINE ++#ASTCFLAGS+=-DSYS_READLINE_EDIT + + ifneq ($(wildcard .version),) + ASTERISKVERSION:=$(shell cat .version) +@@ -511,7 +515,7 @@ + cygwin_a: + $(MAKE) -C cygwin all + +-asterisk: $(CYGLOADER) editline/libedit.a db1-ast/libdb1.a stdtime/libtime.a $(OBJS) ++asterisk: $(CYGLOADER) db1-ast/libdb1.a stdtime/libtime.a $(OBJS) + build_tools/make_build_h > include/asterisk/build.h.tmp + if cmp -s include/asterisk/build.h.tmp include/asterisk/build.h ; then echo ; else \ + mv include/asterisk/build.h.tmp include/asterisk/build.h ; \ --- asterisk-1.2.12.1.dfsg.orig/debian/patches/libpri_bristuffed.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/libpri_bristuffed.dpatch @@ -0,0 +1,28 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## libpri_bristuffed.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: use libpri-bristuffed instead of libpri for building chan_zap. +## DP: libpri-bristuffed is a debian-specific name for a copy of libpri +## DP: with the bristuff patch. + +@DPATCH@ +diff -urNad asterisk-1.2.1.dfsg/channels/Makefile /tmp/dpep.ozZKXW/asterisk-1.2.1.dfsg/channels/Makefile +--- asterisk-1.2.1.dfsg/channels/Makefile 2005-12-31 16:06:04.000000000 +0200 ++++ /tmp/dpep.ozZKXW/asterisk-1.2.1.dfsg/channels/Makefile 2005-12-31 16:07:39.000000000 +0200 +@@ -91,10 +91,15 @@ + CHANNEL_LIBS+=chan_alsa.so + endif + ++ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libpri-bristuffed.so.1),) ++ CFLAGS+=-DZAPATA_PRI -I/usr/include/bristuffed ++ ZAPPRI=-lpri-bristuffed ++else + ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libpri.so.1)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/lib/libpri.so.1),) + CFLAGS+=-DZAPATA_PRI + ZAPPRI=-lpri + endif ++endif + + ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libmfcr2.so.1)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/lib/libmfcr2.so.1),) + CFLAGS+=-DZAPATA_R2 --- asterisk-1.2.12.1.dfsg.orig/debian/patches/patch.CVE-2006-5444.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/patch.CVE-2006-5444.dpatch @@ -0,0 +1,21 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## patch.CVE-2006-5444.dpatch by Martin Jürgens +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Fixes an integer signedness problem. + +@DPATCH@ +diff -urNad asterisk-1.2.12.1.dfsg~/channels/chan_skinny.c asterisk-1.2.12.1.dfsg/channels/chan_skinny.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_skinny.c 2006-08-30 20:59:44.000000000 +0200 ++++ asterisk-1.2.12.1.dfsg/channels/chan_skinny.c 2006-11-29 17:00:32.000000000 +0100 +@@ -2863,6 +2863,10 @@ + return -1; + } + dlen = letohl(*(int *)s->inbuf); ++ if (dlen < 0) { ++ ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n"); ++ return -1; ++ } + if (dlen+8 > sizeof(s->inbuf)) { + dlen = sizeof(s->inbuf) - 8; + } --- asterisk-1.2.12.1.dfsg.orig/debian/patches/backport_playdtmf.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/backport_playdtmf.dpatch @@ -0,0 +1,69 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## ukcid.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: A backport of playdtmf. See http://bugs.digium.com/view.php?id=6682 +## DP: patch: svn diff -r 10646:13356 http://svn.digium.com/svn/asterisk/team/oej/test-this-branch/apps/app_senddtmf.c +## DP: From: http://www.lusyn.com/asterisk/patches.html + +@DPATCH@ +Index: app_senddtmf.c +=================================================================== +--- asterisk-old/apps/app_senddtmf.c (revision 10646) ++++ asterisk-new/apps/app_senddtmf.c (revision 13356) +@@ -43,6 +43,7 @@ + #include "asterisk/options.h" + #include "asterisk/utils.h" + #include "asterisk/app.h" ++#include "asterisk/manager.h" + + static char *tdesc = "Send DTMF digits Application"; + +@@ -93,11 +94,39 @@ + return res; + } + ++static char mandescr_playdtmf[] = ++ "Description: Plays a DTMF digit on the specified channel.\n" ++ "Variables: (all are required)\n" ++ "Channel: Channel name to send digit to\n" ++ "Digit: The dtmf digit to play\n"; ++ ++static int manager_play_dtmf(struct mansession *s, struct message *m) ++{ ++ char *channel, *digit; ++ ++ channel = astman_get_header(m, "Channel"); ++ digit = astman_get_header(m, "Digit"); ++ struct ast_channel *chan = ast_get_channel_by_name_locked(channel); ++ if (chan == NULL) { ++ astman_send_error(s, m, "No such channel"); ++ return 0; ++ } ++ if (digit == NULL) { ++ astman_send_error(s, m, "No digit specified"); ++ return 0; ++ } ++ ast_senddigit(chan, *digit); ++ ast_mutex_unlock(&chan->lock); ++ astman_send_ack(s, m, "DTMF successfully sent"); ++ return 0; ++} ++ + int unload_module(void) + { + int res; + + res = ast_unregister_application(app); ++ res |= ast_manager_unregister("playDTMF"); + + STANDARD_HANGUP_LOCALUSERS; + +@@ -106,6 +135,7 @@ + + int load_module(void) + { ++ ast_manager_register2( "playDTMF", EVENT_FLAG_AGENT, manager_play_dtmf, "Play DTMF signal on a specific channel.", mandescr_playdtmf); + return ast_register_application(app, senddtmf_exec, synopsis, descrip); + } + --- asterisk-1.2.12.1.dfsg.orig/debian/patches/patch.CVE-2006-2898.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/patch.CVE-2006-2898.dpatch @@ -0,0 +1,19 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 99_CVE-2006-2898.dpatch by Joey Schulze +## +## DP: Bug in the IAX2 channel allows remote attackers to craft +## DP: a denial of service. + +@DPATCH@ +diff -urNad asterisk-1.2.10.dfsg~/channels/chan_iax2.c asterisk-1.2.10.dfsg/channels/chan_iax2.c +--- asterisk-1.2.10.dfsg~/channels/chan_iax2.c 2006-07-12 16:23:59.000000000 +0100 ++++ asterisk-1.2.10.dfsg/channels/chan_iax2.c 2006-07-27 08:17:52.000000000 +0100 +@@ -6531,7 +6531,7 @@ + if (iaxdebug && (res >= sizeof(*fh))) + iax_showframe(NULL, fh, 1, &sin, res - sizeof(*fh)); + #endif +- if (ntohs(mh->callno) & IAX_FLAG_FULL) { ++ if ((res >= sizeof(*fh)) && ntohs(mh->callno) & IAX_FLAG_FULL) { + if (res < sizeof(*fh)) { + ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a full frame but is too short\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); + return 1; --- asterisk-1.2.12.1.dfsg.orig/debian/patches/pubkey_jnctn.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/pubkey_jnctn.dpatch @@ -0,0 +1,19 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## pubkey_jnctn.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Public key for Junction Networks. From http://www.jnctn.net/jnctn.pub +## DP: at Wed, 12 Oct 2005 23:35:06 +0200 +## DP: See also http://www.junctionnetworks.com/Asterisk-config.htm + +@DPATCH@ +diff -urNad asterisk-1.1.9.0beta1.dfsg.1/keys/jnctn.pub /tmp/dpep.mnlLru/asterisk-1.1.9.0beta1.dfsg.1/keys/jnctn.pub +--- asterisk-1.1.9.0beta1.dfsg.1/keys/jnctn.pub 1970-01-01 02:00:00.000000000 +0200 ++++ /tmp/dpep.mnlLru/asterisk-1.1.9.0beta1.dfsg.1/keys/jnctn.pub 2005-10-12 23:35:32.236727110 +0200 +@@ -0,0 +1,6 @@ ++-----BEGIN PUBLIC KEY----- ++MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDWaDv4190BpeL5K+Yuq5Q7+vPs ++FVrkibbIp+Io1gCQ6CGZJbR0kUZvTdf58bBdG0zqf6azFN8XPaNz9PVLDl+KgHwU ++3Ilu//eX8ph8Wu+Oxs/ymi/hzKm+Cd6aty94zYuqiegc0KdrjvU5TLQAkIQpiB6k ++CvuIm0R0XXQjj3R7LwIDAQAB ++-----END PUBLIC KEY----- --- asterisk-1.2.12.1.dfsg.orig/debian/patches/ukcid.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/ukcid.dpatch @@ -0,0 +1,167 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## ukcid.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Support for UK Caller-ID in X100P cards: asterisk part. +## DP: From: http://www.lusyn.com/asterisk/patches.html + +@DPATCH@ +diff -urNad asterisk/channels/chan_zap.c /tmp/dpep.KK0kwq/asterisk/channels/chan_zap.c +--- asterisk/channels/chan_zap.c 2006-01-06 00:40:59.000000000 +0200 ++++ /tmp/dpep.KK0kwq/asterisk/channels/chan_zap.c 2006-01-08 02:17:08.000000000 +0200 +@@ -951,6 +951,14 @@ + return 0; + } + ++static int zt_get_history(int fd, void *buf, int buf_size) ++{ ++ struct zt_history hist; ++ hist.buf=buf; ++ hist.len=buf_size; ++ return ioctl(fd, ZT_GET_HISTORY, &hist); ++} ++ + static int alloc_sub(struct zt_pvt *p, int x) + { + ZT_BUFFERINFO bi; +@@ -5787,6 +5795,120 @@ + } + } + #endif ++ /* If we're using an X100P in the UK, caller ID needs to be extracted from ++ * the history buffer */ ++ if (p->use_callerid && p->cid_start == CID_START_USEHIST) { ++ ast_log(LOG_DEBUG,"Using history buffer to extract UK caller ID\n"); ++ cs = callerid_new(cid_signalling); ++ if (cs) { ++ unsigned char cidbuf[16384]; ++ res=0; ++ ++ res = zt_get_history(p->subs[index].zfd,cidbuf,sizeof(cidbuf)); ++ if(res<0) { ++ ast_log(LOG_ERROR,"zt_get_history failed: %s\n", strerror(errno)); ++ } else { ++ res=callerid_feed(cs,cidbuf,sizeof(cidbuf),AST_LAW(p)); ++ if (res < 0) { ++ ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno)); ++ } ++ } ++ ++ if(res==1) { ++ callerid_get(cs, &name, &number, &flags); ++ if (option_debug) ++ ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags); ++ } ++ } ++ if (p->usedistinctiveringdetection == 1) { ++#if 1 ++ bump_gains(p); ++#endif ++ len = 0; ++ distMatches = 0; ++ /* Clear the current ring data array so we dont have old data in it. */ ++ for (receivedRingT=0; receivedRingT < 3; receivedRingT++) { ++ curRingData[receivedRingT] = 0; ++ } ++ receivedRingT = 0; ++ counter = 0; ++ counter1 = 0; ++ /* Check to see if context is what it should be, if not set to be. */ ++ if (strcmp(p->context,p->defcontext) != 0) { ++ strncpy(p->context, p->defcontext, sizeof(p->context)-1); ++ strncpy(chan->context,p->defcontext,sizeof(chan->context)-1); ++ } ++ ++ for(;;) { ++ i = ZT_IOMUX_READ | ZT_IOMUX_SIGEVENT; ++ if ((res = ioctl(p->subs[index].zfd, ZT_IOMUX, &i))) { ++ ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); ++ callerid_free(cs); ++ ast_hangup(chan); ++ return NULL; ++ } ++ if (i & ZT_IOMUX_SIGEVENT) { ++ res = zt_get_event(p->subs[index].zfd); ++ ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res)); ++ res = 0; ++ /* Let us detect distinctive ring */ ++ ++ curRingData[receivedRingT] = p->ringt; ++ ++ if (p->ringt < ringt_base/2) ++ break; ++ ++receivedRingT; /* Increment the ringT counter so we can match it against ++ values in zapata.conf for distinctive ring */ ++ } else if (i & ZT_IOMUX_READ) { ++ res = read(p->subs[index].zfd, buf, sizeof(buf)); ++ if (res < 0) { ++ if (errno != ELAST) { ++ ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno)); ++ callerid_free(cs); ++ ast_hangup(chan); ++ return NULL; ++ } ++ break; ++ } ++ if (p->ringt) ++ p->ringt--; ++ if (p->ringt == 1) { ++ res = -1; ++ break; ++ } ++ } ++ } ++ if(option_verbose > 2) ++ /* this only shows up if you have n of the dring patterns filled in */ ++ ast_verbose( VERBOSE_PREFIX_3 "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]); ++ ++ for (counter=0; counter < 3; counter++) { ++ /* Check to see if the rings we received match any of the ones in zapata.conf for this ++ channel */ ++ distMatches = 0; ++ for (counter1=0; counter1 < 3; counter1++) { ++ if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1]+10) && curRingData[counter1] >= ++ (p->drings.ringnum[counter].ring[counter1]-10)) { ++ distMatches++; ++ } ++ } ++ if (distMatches == 3) { ++ /* The ring matches, set the context to whatever is for distinctive ring.. */ ++ strncpy(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)-1); ++ strncpy(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)-1); ++ if(option_verbose > 2) ++ ast_verbose( VERBOSE_PREFIX_3 "Distinctive Ring matched context %s\n",p->context); ++ break; ++ } ++ } ++ } ++ /* Restore linear mode (if appropriate) for Caller*ID processing */ ++ zt_setlinear(p->subs[index].zfd, p->subs[index].linear); ++#if 1 ++ restore_gains(p); ++#endif ++ } ++ + /* If we want caller id, we're in a prering state due to a polarity reversal + * and we're set to use a polarity reversal to trigger the start of caller id, + * grab the caller id and wait for ringing to start... */ +@@ -10299,6 +10421,8 @@ + cid_start = CID_START_RING; + else if (!strcasecmp(v->value, "polarity")) + cid_start = CID_START_POLARITY; ++ else if (!strcasecmp(v->value, "usehist")) ++ cid_start = CID_START_USEHIST; + else if (ast_true(v->value)) + cid_start = CID_START_RING; + } else if (!strcasecmp(v->name, "threewaycalling")) { +diff -urNad asterisk/include/asterisk/callerid.h /tmp/dpep.KK0kwq/asterisk/include/asterisk/callerid.h +--- asterisk/include/asterisk/callerid.h 2006-01-06 00:41:06.000000000 +0200 ++++ /tmp/dpep.KK0kwq/asterisk/include/asterisk/callerid.h 2006-01-08 02:17:08.000000000 +0200 +@@ -44,6 +44,7 @@ + + #define CID_START_RING 1 + #define CID_START_POLARITY 2 ++#define CID_START_USEHIST 3 + + + #define AST_LIN2X(a) ((codec == AST_FORMAT_ALAW) ? (AST_LIN2A(a)) : (AST_LIN2MU(a))) --- asterisk-1.2.12.1.dfsg.orig/debian/patches/chanzap_disable_r2.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/chanzap_disable_r2.dpatch @@ -0,0 +1,23 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## chanzap_disable_r2.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: disable the nunfunctional support for R2 in chan_zap +## -- applied upstream for trunk (1.4.x) + +@DPATCH@ +diff -urNad asterisk-1.2.0.dfsg/channels/Makefile /tmp/dpep.54ZD6D/asterisk-1.2.0.dfsg/channels/Makefile +--- asterisk-1.2.0.dfsg/channels/Makefile 2005-12-05 21:44:28.371543279 +0200 ++++ /tmp/dpep.54ZD6D/asterisk-1.2.0.dfsg/channels/Makefile 2005-12-05 21:47:56.185734969 +0200 +@@ -95,11 +95,6 @@ + ZAPPRI=-lpri + endif + +-ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libmfcr2.so.1)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/lib/libmfcr2.so.1),) +- CFLAGS+=-DZAPATA_R2 +- ZAPR2=-lmfcr2 +-endif +- + ALSA_SRC=chan_alsa.c + + ifneq ($(wildcard alsa-monitor.h),) --- asterisk-1.2.12.1.dfsg.orig/debian/patches/30_ast-data-dir.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/30_ast-data-dir.dpatch @@ -0,0 +1,282 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## ast_data_dir.dpatch by Mark Purcell +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Patch to make Asterisk conform with the Linux File System Hierarchy Standard (FHS) +## DP: Places read-only architecture-independent data under /usr/share/asterisk (autoconf --datadir) +## DP: not /var/lib/asterisk +## -- is applied upstream for 1.2 + +@DPATCH@ +diff -urNad asterisk-1.2.7.1.dfsg/asterisk.c /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/asterisk.c +--- asterisk-1.2.7.1.dfsg/asterisk.c 2006-05-13 18:14:15.970288503 +0300 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/asterisk.c 2006-05-13 18:14:16.228355957 +0300 +@@ -216,6 +216,7 @@ + char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH]; + char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH]; + char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH]; ++char ast_config_AST_DATA_DIR[AST_CONFIG_MAX_PATH]; + char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH]; + char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH]; + char ast_config_AST_DB[AST_CONFIG_MAX_PATH]; +@@ -1882,6 +1883,7 @@ + ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR)); + snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR); + ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR)); ++ ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR)); + ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR)); + ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR)); + ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB)); +@@ -1918,6 +1920,8 @@ + ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR)); + snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value); + snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value); ++ } else if (!strcasecmp(v->name, "astdatadir")) { ++ ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR)); + } else if (!strcasecmp(v->name, "astlogdir")) { + ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR)); + } else if (!strcasecmp(v->name, "astagidir")) { +diff -urNad asterisk-1.2.7.1.dfsg/build_tools/make_defaults_h /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/build_tools/make_defaults_h +--- asterisk-1.2.7.1.dfsg/build_tools/make_defaults_h 2005-06-20 20:26:08.000000000 +0300 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/build_tools/make_defaults_h 2006-05-13 18:14:16.228355957 +0300 +@@ -11,6 +11,7 @@ + #define AST_MODULE_DIR "${INSTALL_PATH}${MODULES_DIR}" + #define AST_SPOOL_DIR "${INSTALL_PATH}${ASTSPOOLDIR}" + #define AST_VAR_DIR "${INSTALL_PATH}${ASTVARLIBDIR}" ++#define AST_DATA_DIR "${INSTALL_PATH}${ASTDATADIR}" + #define AST_LOG_DIR "${INSTALL_PATH}${ASTLOGDIR}" + #define AST_AGI_DIR "${INSTALL_PATH}${AGI_DIR}" + #define AST_KEY_DIR "${INSTALL_PATH}${ASTVARLIBDIR}/keys" +@@ -19,7 +20,7 @@ + + #define AST_CONFIG_FILE "${INSTALL_PATH}${ASTCONFPATH}" + +-#define AST_SOUNDS "${INSTALL_PATH}${ASTVARLIBDIR}/sounds" +-#define AST_IMAGES "${INSTALL_PATH}${ASTVARLIBDIR}/images" ++#define AST_SOUNDS "${INSTALL_PATH}${ASTDATADIR}/sounds" ++#define AST_IMAGES "${INSTALL_PATH}${ASTDATADIR}/images" + + END +diff -urNad asterisk-1.2.7.1.dfsg/channels/chan_iax2.c /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/channels/chan_iax2.c +--- asterisk-1.2.7.1.dfsg/channels/chan_iax2.c 2006-03-31 22:11:26.000000000 +0300 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/channels/chan_iax2.c 2006-05-13 18:27:17.074963284 +0300 +@@ -1367,7 +1367,7 @@ + cur = cur->next; + } + /* Now that we've freed them, load the new ones */ +- snprintf(dir, sizeof(dir), "%s/firmware/iax", (char *)ast_config_AST_VAR_DIR); ++ snprintf(dir, sizeof(dir), "%s/firmware/iax", (char *)ast_config_AST_DATA_DIR); + fwd = opendir(dir); + if (fwd) { + while((de = readdir(fwd))) { +diff -urNad asterisk-1.2.7.1.dfsg/configs/musiconhold.conf.sample /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/configs/musiconhold.conf.sample +--- asterisk-1.2.7.1.dfsg/configs/musiconhold.conf.sample 2005-11-29 20:24:39.000000000 +0200 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/configs/musiconhold.conf.sample 2006-05-13 18:14:16.228355957 +0300 +@@ -4,7 +4,7 @@ + + [default] + mode=quietmp3 +-directory=/var/lib/asterisk/mohmp3 ++directory=/usr/share/asterisk/mohmp3 + + ; valid mode options: + ; quietmp3 -- default +diff -urNad asterisk-1.2.7.1.dfsg/file.c /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/file.c +--- asterisk-1.2.7.1.dfsg/file.c 2006-01-10 00:07:26.000000000 +0200 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/file.c 2006-05-13 18:14:16.228355957 +0300 +@@ -313,7 +313,7 @@ + } else { + char tmp[AST_CONFIG_MAX_PATH] = ""; + +- snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds"); ++ snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_DATA_DIR, "sounds"); + fnsize = strlen(tmp) + strlen(filename) + strlen(type) + 3; + fn = malloc(fnsize); + if (fn) +diff -urNad asterisk-1.2.7.1.dfsg/image.c /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/image.c +--- asterisk-1.2.7.1.dfsg/image.c 2006-03-24 16:48:11.000000000 +0200 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/image.c 2006-05-13 18:14:16.228355957 +0300 +@@ -108,9 +108,9 @@ + snprintf(buf, len, "%s.%s", filename, ext); + } else { + if (preflang && strlen(preflang)) +- snprintf(buf, len, "%s/%s/%s-%s.%s", ast_config_AST_VAR_DIR, "images", filename, preflang, ext); ++ snprintf(buf, len, "%s/%s/%s-%s.%s", ast_config_AST_DATA_DIR, "images", filename, preflang, ext); + else +- snprintf(buf, len, "%s/%s/%s.%s", ast_config_AST_VAR_DIR, "images", filename, ext); ++ snprintf(buf, len, "%s/%s/%s.%s", ast_config_AST_DATA_DIR, "images", filename, ext); + } + } + +diff -urNad asterisk-1.2.7.1.dfsg/include/asterisk.h /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/include/asterisk.h +--- asterisk-1.2.7.1.dfsg/include/asterisk.h 2005-11-30 05:37:37.000000000 +0200 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/include/asterisk.h 2006-05-13 18:14:16.228355957 +0300 +@@ -29,6 +29,7 @@ + extern char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH]; + extern char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH]; + extern char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH]; ++extern char ast_config_AST_DATA_DIR[AST_CONFIG_MAX_PATH]; + extern char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH]; + extern char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH]; + extern char ast_config_AST_DB[AST_CONFIG_MAX_PATH]; +diff -urNad asterisk-1.2.7.1.dfsg/Makefile /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/Makefile +--- asterisk-1.2.7.1.dfsg/Makefile 2006-04-12 00:58:47.000000000 +0300 ++++ /tmp/dpep.um4nZ3/asterisk-1.2.7.1.dfsg/Makefile 2006-05-13 18:26:34.253802810 +0300 +@@ -110,6 +110,7 @@ + ifneq ($(OSARCH),SunOS) + ASTLIBDIR=$(INSTALL_PREFIX)/usr/lib/asterisk + ASTVARLIBDIR=$(INSTALL_PREFIX)/var/lib/asterisk ++ ASTDATADIR=$(INSTALL_PREFIX)/usr/share/asterisk + ASTETCDIR=$(INSTALL_PREFIX)/etc/asterisk + ASTSPOOLDIR=$(INSTALL_PREFIX)/var/spool/asterisk + ASTLOGDIR=$(INSTALL_PREFIX)/var/log/asterisk +@@ -117,10 +118,10 @@ + ASTCONFPATH=$(ASTETCDIR)/asterisk.conf + ASTBINDIR=$(INSTALL_PREFIX)/usr/bin + ASTSBINDIR=$(INSTALL_PREFIX)/usr/sbin +- ASTVARRUNDIR=$(INSTALL_PREFIX)/var/run ++ ASTVARRUNDIR=$(INSTALL_PREFIX)/var/run/asterisk + ASTMANDIR=$(INSTALL_PREFIX)/usr/share/man + MODULES_DIR=$(ASTLIBDIR)/modules +- AGI_DIR=$(ASTVARLIBDIR)/agi-bin ++ AGI_DIR=$(ASTDATADIR)/agi-bin + else + ASTLIBDIR=$(INSTALL_PREFIX)/opt/asterisk/lib + ASTVARLIBDIR=$(INSTALL_PREFIX)/var/opt/asterisk/lib +@@ -136,6 +137,7 @@ + MODULES_DIR=$(ASTLIBDIR)/modules + AGI_DIR=$(ASTVARLIBDIR)/agi-bin + endif ++FIRMWARE_DIR=$(ASTDATADIR)/firmware + + ASTCFLAGS= + +@@ -542,38 +544,38 @@ + + datafiles: all + if [ x`$(ID) -un` = xroot ]; then sh mkpkgconfig $(DESTDIR)/usr/lib/pkgconfig; fi +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/digits +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/priv-callerintros ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds/digits ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds/priv-callerintros + for x in sounds/digits/*.gsm; do \ + if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds/digits ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/sounds/digits ; \ + else \ + echo "No description for $$x"; \ + exit 1; \ + fi; \ + done +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/dictate ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds/dictate + for x in sounds/dictate/*.gsm; do \ + if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds/dictate ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/sounds/dictate ; \ + else \ + echo "No description for $$x"; \ + exit 1; \ + fi; \ + done +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/letters ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds/letters + for x in sounds/letters/*.gsm; do \ + if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds/letters ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/sounds/letters ; \ + else \ + echo "No description for $$x"; \ + exit 1; \ + fi; \ + done +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds/phonetic ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds/phonetic + for x in sounds/phonetic/*.gsm; do \ + if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds/phonetic ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/sounds/phonetic ; \ + else \ + echo "No description for $$x"; \ + exit 1; \ +@@ -581,16 +583,16 @@ + done + for x in sounds/demo-* sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-* sounds/auth-* sounds/privacy-* sounds/queue-* sounds/spy-* sounds/priv-* sounds/screen-* sounds/hello-*; do \ + if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/sounds ; \ + else \ + echo "No description for $$x"; \ + exit 1; \ + fi; \ + done +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/mohmp3 +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/images ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/mohmp3 ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/images + for x in images/*.jpg; do \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/images ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/images ; \ + done + mkdir -p $(DESTDIR)$(AGI_DIR) + +@@ -626,6 +628,7 @@ + mkdir -p $(DESTDIR)$(ASTETCDIR) + mkdir -p $(DESTDIR)$(ASTBINDIR) + mkdir -p $(DESTDIR)$(ASTVARRUNDIR) ++ mkdir -p $(DESTDIR)$(ASTDATADIR) + mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail + mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/dictate + mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/system +@@ -648,12 +651,12 @@ + if [ -n "$(OLDHEADERS)" ]; then \ + rm -f $(addprefix $(DESTDIR)$(ASTHEADERDIR)/,$(OLDHEADERS)) ;\ + fi +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds + mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-csv + mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-custom + mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/keys +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/firmware +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/firmware/iax ++ mkdir -p $(DESTDIR)$(FIRMWARE_DIR) ++ mkdir -p $(DESTDIR)$(FIRMWARE_DIR)/iax + mkdir -p $(DESTDIR)$(ASTMANDIR)/man8 + $(INSTALL) -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTVARLIBDIR)/keys + $(INSTALL) -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTVARLIBDIR)/keys +@@ -662,7 +665,7 @@ + $(INSTALL) -m 644 contrib/scripts/autosupport.8 $(DESTDIR)$(ASTMANDIR)/man8 + $(INSTALL) -m 644 contrib/scripts/safe_asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8 + if [ -d contrib/firmware/iax ]; then \ +- $(INSTALL) -m 644 contrib/firmware/iax/iaxy.bin $(DESTDIR)$(ASTVARLIBDIR)/firmware/iax/iaxy.bin; \ ++ $(INSTALL) -m 644 contrib/firmware/iax/iaxy.bin $(DESTDIR)$(FIRMWARE_DIR)/iax/iaxy.bin; \ + else \ + echo "You need to do cvs update -d not just cvs update" ; \ + fi +@@ -764,10 +767,10 @@ + else \ + echo "Skipping asterisk.conf creation"; \ + fi +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds ; \ ++ mkdir -p $(DESTDIR)$(ASTDATADIR)/sounds ; \ + for x in sounds/demo-*; do \ + if $(GREP) -q "^%`basename $$x`%" sounds.txt; then \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/sounds ; \ ++ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/sounds ; \ + else \ + echo "No description for $$x"; \ + exit 1; \ +@@ -781,11 +784,11 @@ + mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/INBOX + :> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/unavail.gsm + for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isunavail; do \ +- cat $(DESTDIR)$(ASTVARLIBDIR)/sounds/$$x.gsm >> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/unavail.gsm ; \ ++ cat $(DESTDIR)$(ASTDATADIR)/sounds/$$x.gsm >> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/unavail.gsm ; \ + done + :> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/busy.gsm + for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isonphone; do \ +- cat $(DESTDIR)$(ASTVARLIBDIR)/sounds/$$x.gsm >> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/busy.gsm ; \ ++ cat $(DESTDIR)$(ASTDATADIR)/sounds/$$x.gsm >> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/busy.gsm ; \ + done + + webvmail: --- asterisk-1.2.12.1.dfsg.orig/debian/patches/95_conf_sample.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/95_conf_sample.dpatch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## conf_sample.dpatch by Jose Carlos Garcia Sogo +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad asterisk-1.2.7.1.dfsg~/configs/modules.conf.sample asterisk-1.2.7.1.dfsg/configs/modules.conf.sample +--- asterisk-1.2.7.1.dfsg~/configs/modules.conf.sample 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.7.1.dfsg/configs/modules.conf.sample 2006-04-21 17:28:48.000000000 +0100 +@@ -45,7 +45,10 @@ + ; By default, load OSS only (automatically) and do not load ALSA + ; + noload => chan_alsa.so +-;noload => chan_oss.so ++noload => chan_oss.so ++; ++; h323 modules can be unstable so don't load by default ++noload => chan_h323.so + ; + ; Module names listed in "global" section will have symbols globally + ; exported to modules loaded after them. --- asterisk-1.2.12.1.dfsg.orig/debian/patches/bristuff.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/bristuff.dpatch @@ -0,0 +1,14817 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## bristuff.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: bristuff support in asterisk: asterisk.patch from bristuff-0.3.0-PRE-1s +## DP: cygdef.h removed ;-) + +@DPATCH@ +diff -urNad asterisk-1.2.12.1.dfsg~/.version.rej asterisk-1.2.12.1.dfsg/.version.rej +--- asterisk-1.2.12.1.dfsg~/.version.rej 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/.version.rej 2006-09-23 18:07:45.000000000 +0100 +@@ -0,0 +1,5 @@ ++*************** ++*** 1 **** ++- 1.2.12 ++--- 1 ---- +++ 1.2.12-BRIstuffed-0.3.0-PRE-1s +diff -urNad asterisk-1.2.12.1.dfsg~/HARDWARE asterisk-1.2.12.1.dfsg/HARDWARE +--- asterisk-1.2.12.1.dfsg~/HARDWARE 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/HARDWARE 2006-09-23 18:07:45.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 ++ ++ * uno/duo/quad GSM PCI - 1/2/4 channel GSM interface cards ++ + Non-zaptel compatible hardware + ============================== + +diff -urNad asterisk-1.2.12.1.dfsg~/LICENSE asterisk-1.2.12.1.dfsg/LICENSE +--- asterisk-1.2.12.1.dfsg~/LICENSE 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/LICENSE 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/Makefile asterisk-1.2.12.1.dfsg/Makefile +--- asterisk-1.2.12.1.dfsg~/Makefile 2006-09-06 21:09:10.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/Makefile 2006-09-23 18:07:45.000000000 +0100 +@@ -772,6 +772,9 @@ + echo ";astctlowner = root" ; \ + echo ";astctlgroup = apache" ; \ + echo ";astctl = asterisk.ctl" ; \ ++ echo "[options]" ; \ ++ echo "uniquename = `hostname`" ;\ ++ echo "silence_suppression = yes" ;\ + ) > $(DESTDIR)$(ASTCONFPATH) ; \ + else \ + echo "Skipping asterisk.conf creation"; \ +diff -urNad asterisk-1.2.12.1.dfsg~/README asterisk-1.2.12.1.dfsg/README +--- asterisk-1.2.12.1.dfsg~/README 2006-03-03 08:12:33.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/README 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/README.chan_capi asterisk-1.2.12.1.dfsg/README.chan_capi +--- asterisk-1.2.12.1.dfsg~/README.chan_capi 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/README.chan_capi 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/agi/Makefile asterisk-1.2.12.1.dfsg/agi/Makefile +--- asterisk-1.2.12.1.dfsg~/agi/Makefile 2006-03-28 21:22:05.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/agi/Makefile 2006-09-23 18:07:45.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+=-DNO_AST_MM + +@@ -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 -urNad asterisk-1.2.12.1.dfsg~/agi/xagi-test.c asterisk-1.2.12.1.dfsg/agi/xagi-test.c +--- asterisk-1.2.12.1.dfsg~/agi/xagi-test.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/agi/xagi-test.c 2006-09-23 18:07:45.000000000 +0100 +@@ -0,0 +1,175 @@ ++/* ++ * 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; ++ } ++ astresp[strlen(astresp) - 1] = '\0'; ++ fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp); ++ return; ++ } ++ 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; ++ 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 -urNad asterisk-1.2.12.1.dfsg~/apps/Makefile asterisk-1.2.12.1.dfsg/apps/Makefile +--- asterisk-1.2.12.1.dfsg~/apps/Makefile 2006-04-30 14:38:22.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/Makefile 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_callingpres.c asterisk-1.2.12.1.dfsg/apps/app_callingpres.c +--- asterisk-1.2.12.1.dfsg~/apps/app_callingpres.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_callingpres.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_capiCD.c asterisk-1.2.12.1.dfsg/apps/app_capiCD.c +--- asterisk-1.2.12.1.dfsg~/apps/app_capiCD.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_capiCD.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_capiECT.c asterisk-1.2.12.1.dfsg/apps/app_capiECT.c +--- asterisk-1.2.12.1.dfsg~/apps/app_capiECT.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_capiECT.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_capiNoES.c asterisk-1.2.12.1.dfsg/apps/app_capiNoES.c +--- asterisk-1.2.12.1.dfsg~/apps/app_capiNoES.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_capiNoES.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_chanisavail.c asterisk-1.2.12.1.dfsg/apps/app_chanisavail.c +--- asterisk-1.2.12.1.dfsg~/apps/app_chanisavail.c 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/apps/app_chanisavail.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_chanspy.c asterisk-1.2.12.1.dfsg/apps/app_chanspy.c +--- asterisk-1.2.12.1.dfsg~/apps/app_chanspy.c 2006-09-05 21:02:48.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_chanspy.c 2006-09-23 18:07:45.000000000 +0100 +@@ -55,6 +55,7 @@ + + static const char *synopsis = "Listen to the audio of an active channel\n"; + static const char *app = "ChanSpy"; ++static const char *app2 = "ChanSpyChan"; + static const char *desc = + " ChanSpy([chanprefix][|options]): This application is used to listen to the\n" + "audio from an active Asterisk channel. This includes the audio coming in and\n" +@@ -142,6 +143,19 @@ + return ret; + } + ++static struct ast_channel *local_get_channel_uniqueid(char *uniqueid) ++{ ++ struct ast_channel *chan = NULL; ++ if (uniqueid) { ++ ast_mutex_lock(&modlock); ++ if ((chan = ast_get_channel_by_uniqueid_locked(uniqueid))) { ++ ast_mutex_unlock(&chan->lock); ++ } ++ ast_mutex_unlock(&modlock); ++ } ++ return chan; ++} ++ + static void *spy_alloc(struct ast_channel *chan, void *data) + { + /* just store the data pointer in the channel structure */ +@@ -545,11 +559,87 @@ + ALL_DONE(u, res); + } + ++static int chanspychan_exec(struct ast_channel *chan, void *data) ++{ ++ struct localuser *u; ++ struct ast_channel *peer=NULL; ++ char *args, ++ *uniqueid = NULL, ++ *argv[5]; ++ int res = -1, ++ volfactor = 0, ++ argc = 0, ++ oldrf = 0, ++ oldwf = 0, ++ fd = 0; ++ signed char zero_volume = 0; ++ ++ if (!(args = ast_strdupa((char *)data))) { ++ ast_log(LOG_ERROR, "Out of memory!\n"); ++ return -1; ++ } ++ ++ LOCAL_USER_ADD(u); ++ ++ oldrf = chan->readformat; ++ oldwf = chan->writeformat; ++ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { ++ ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); ++ LOCAL_USER_REMOVE(u); ++ return -1; ++ } ++ ++ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { ++ ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); ++ LOCAL_USER_REMOVE(u); ++ return -1; ++ } ++ ++ ++ if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { ++ uniqueid = argv[0]; ++ if (ast_strlen_zero(uniqueid)) { ++ LOCAL_USER_REMOVE(u); ++ return -1; ++ } ++ } ++ ++ ast_answer(chan); ++ ++ ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ ++ ++ peer = local_get_channel_uniqueid(uniqueid); ++ if (peer && (peer != chan) && !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) { ++ res = channel_spy(chan, peer, &volfactor, fd); ++ } else { ++ ast_log(LOG_NOTICE, "no channel found with uniqueid %s\n", uniqueid); ++ } ++ ++ if (fd > 0) { ++ close(fd); ++ } ++ ++ if (oldrf && ast_set_read_format(chan, oldrf) < 0) { ++ ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); ++ } ++ ++ if (oldwf && ast_set_write_format(chan, oldwf) < 0) { ++ ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); ++ } ++ ++ ast_clear_flag(chan, AST_FLAG_SPYING); ++ ++ ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); ++ ++ ALL_DONE(u, res); ++} ++ + int unload_module(void) + { + int res; + +- res = ast_unregister_application(app); ++ ast_unregister_application(app); ++ res = ast_unregister_application(app2); + + STANDARD_HANGUP_LOCALUSERS; + +@@ -558,7 +648,8 @@ + + int load_module(void) + { +- return ast_register_application(app, chanspy_exec, synopsis, desc); ++ ast_register_application(app, chanspy_exec, synopsis, desc); ++ return ast_register_application(app2, chanspychan_exec, synopsis, desc); + } + + char *description(void) +diff -urNad asterisk-1.2.12.1.dfsg~/apps/app_devstate.c asterisk-1.2.12.1.dfsg/apps/app_devstate.c +--- asterisk-1.2.12.1.dfsg~/apps/app_devstate.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_devstate.c 2006-09-23 18:07:45.000000000 +0100 +@@ -0,0 +1,225 @@ ++/* ++ * 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) && (argc != 5)) ++ 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 if (argc == 5) { ++ ast_log(LOG_NOTICE, "devname %s cid %s cidname %s\n", devName, argv[3], argv[4]); ++ ast_device_state_changed_literal(devName, argv[3], argv[4]); ++ } 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 *cid_num = astman_get_header(m, "CallerID"); ++ char *cid_name = astman_get_header(m, "CallerIDName"); ++ 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_device_state_changed_literal(devName, cid_num, cid_name); ++ 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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_dial.c asterisk-1.2.12.1.dfsg/apps/app_dial.c +--- asterisk-1.2.12.1.dfsg~/apps/app_dial.c 2006-08-05 07:37:59.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_dial.c 2006-09-23 18:07:45.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/causes.h" + #include "asterisk/manager.h" + #include "asterisk/privacy.h" ++#include "asterisk/transcap.h" + + static char *tdesc = "Dialing Application"; + +@@ -116,7 +121,8 @@ + " action post answer options in conjunction with this option.\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" +@@ -163,8 +169,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" +@@ -215,6 +224,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) +@@ -253,6 +264,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), +@@ -390,7 +403,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 */ +@@ -469,7 +482,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 +@@ -587,12 +600,18 @@ + HANDLE_CAUSE(AST_CAUSE_CONGESTION, in); + break; + case AST_CONTROL_RINGING: +- if (option_verbose > 2) +- ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); +- if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) { +- ast_indicate(in, AST_CONTROL_RINGING); +- (*sentringing)++; +- } ++ if (ast_test_flag(peerflags, OPT_CALLBACK_INIT)) { ++ if (option_verbose > 2) ++ ast_verbose( VERBOSE_PREFIX_3 "%s is ringing, hanging up.\n", o->chan->name); ++ return NULL; ++ } else { ++ if (option_verbose > 2) ++ ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); ++ if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) { ++ ast_indicate(in, AST_CONTROL_RINGING); ++ (*sentringing)++; ++ } ++ } + break; + case AST_CONTROL_PROGRESS: + if (option_verbose > 2) +@@ -767,6 +786,7 @@ + int digit = 0, result = 0; + time_t start_time, answer_time, end_time; + struct ast_app *app = NULL; ++/* char *aoceunits; */ + + char *parse; + AST_DECLARE_APP_ARGS(args, +@@ -940,13 +960,13 @@ + } + + if( privdb_val == AST_PRIVACY_DENY ) { +- strcpy(status, "NOANSWER"); ++ 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 ) { +- strcpy(status, "DONTCALL"); ++ 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); + } +@@ -954,7 +974,7 @@ + goto out; /* Is this right? */ + } + else if( privdb_val == AST_PRIVACY_TORTURE ) { +- strcpy(status, "TORTURE"); ++ 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); + } +@@ -1008,7 +1028,7 @@ + /* If a channel group has been specified, get it for use when we create peer channels */ + outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"); + +- ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP); ++ ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP| OPT_CALLBACK_INIT | OPT_NOINBAND); + cur = args.peers; + do { + /* Remember where to start next time */ +@@ -1050,7 +1070,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)); +@@ -1081,7 +1101,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 +@@ -1194,7 +1214,7 @@ + + if (outgoing) { + /* Our status will at least be NOANSWER */ +- strcpy(status, "NOANSWER"); ++ ast_copy_string(status, "NOANSWER", sizeof(status)); + if (ast_test_flag(outgoing, OPT_MUSICBACK)) { + moh=1; + ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]); +@@ -1202,8 +1222,11 @@ + ast_indicate(chan, AST_CONTROL_RINGING); + sentringing++; + } +- } else +- strcpy(status, "CHANUNAVAIL"); ++ } else { ++ ast_copy_string(status, "CHANUNAVAIL", sizeof(status)); ++ /* 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); +@@ -1568,18 +1591,22 @@ + ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING); + if (play_to_callee) + ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING); +- if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER)) ++ ++ if ((chan->transfercapability != AST_TRANS_CAP_DIGITAL) && (chan->transfercapability != AST_TRANS_CAP_RESTRICTED_DIGITAL)) { ++ /* only non-digital calls are allowed to go through userspace */ ++ if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER)) + ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); +- if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER)) ++ if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER)) + ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); +- if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP)) ++ if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP)) + ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); +- if (ast_test_flag(peerflags, OPT_CALLER_HANGUP)) ++ if (ast_test_flag(peerflags, OPT_CALLER_HANGUP)) + ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); +- if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR)) ++ if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR)) + ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); +- if (ast_test_flag(peerflags, OPT_CALLER_MONITOR)) ++ if (ast_test_flag(peerflags, OPT_CALLER_MONITOR)) + ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); ++ } + + config.timelimit = timelimit; + config.play_warning = play_warning; +@@ -1615,7 +1642,15 @@ + } + snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time)); + pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast); +- ++ ++ /* forward AOC-E units from peer, if possible */ ++/* aoceunits = pbx_builtin_getvar_helper(peer, "AOCEUNITS"); ++ ++ if (aoceunits) { ++ snprintf(toast, sizeof(toast), "%d", atoi(aoceunits)); ++ pbx_builtin_setvar_helper(chan, "AOCEUNITS", toast); ++ } */ ++ + if (res != AST_PBX_NO_HANGUP_PEER) { + if (!chan->_softhangup) + chan->hangupcause = peer->hangupcause; +diff -urNad asterisk-1.2.12.1.dfsg~/apps/app_directed_pickup.c asterisk-1.2.12.1.dfsg/apps/app_directed_pickup.c +--- asterisk-1.2.12.1.dfsg~/apps/app_directed_pickup.c 2006-04-06 18:00:10.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_directed_pickup.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_meetme.c asterisk-1.2.12.1.dfsg/apps/app_meetme.c +--- asterisk-1.2.12.1.dfsg~/apps/app_meetme.c 2006-09-11 22:47:23.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_meetme.c 2006-09-23 18:09:26.000000000 +0100 +@@ -458,7 +458,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 { +@@ -828,9 +828,10 @@ + char exitcontext[AST_MAX_CONTEXT] = ""; + char recordingtmp[AST_MAX_EXTENSION] = ""; + int dtmf, opt_waitmarked_timeout = 0; ++ int dyna_buff = CONF_SIZE; + time_t timeout = 0; + 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) { +@@ -1004,7 +1005,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; +@@ -1292,6 +1293,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); +@@ -1526,7 +1535,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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_milliwatt.c asterisk-1.2.12.1.dfsg/apps/app_milliwatt.c +--- asterisk-1.2.12.1.dfsg~/apps/app_milliwatt.c 2006-01-19 04:17:45.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/apps/app_milliwatt.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_page.c asterisk-1.2.12.1.dfsg/apps/app_page.c +--- asterisk-1.2.12.1.dfsg~/apps/app_page.c 2006-09-11 22:47:23.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_page.c 2006-09-23 18:07:45.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, NULL); ++ "MeetMe", cd->meetmeopts, NULL, 0, 0, cd->cidnum, cd->cidname, cd->variables, NULL, NULL, NULL); + free(cd); + return NULL; + } +diff -urNad asterisk-1.2.12.1.dfsg~/apps/app_parkandannounce.c asterisk-1.2.12.1.dfsg/apps/app_parkandannounce.c +--- asterisk-1.2.12.1.dfsg~/apps/app_parkandannounce.c 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/apps/app_parkandannounce.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_pickup.c asterisk-1.2.12.1.dfsg/apps/app_pickup.c +--- asterisk-1.2.12.1.dfsg~/apps/app_pickup.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_pickup.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_queue.c asterisk-1.2.12.1.dfsg/apps/app_queue.c +--- asterisk-1.2.12.1.dfsg~/apps/app_queue.c 2006-09-03 18:38:22.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_queue.c 2006-09-23 18:07:45.000000000 +0100 +@@ -526,7 +526,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 */ +@@ -1509,7 +1509,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); +@@ -1821,7 +1821,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) { +@@ -2365,14 +2365,14 @@ + else + which = peer; + if (monitorfilename) +- ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); ++ ast_monitor_start(which, qe->parent->monfmt, monitorfilename, NULL, NULL, 1 ); + else if (qe->chan->cdr) +- ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); ++ ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, NULL, NULL, 1 ); + else { + /* Last ditch effort -- no CDR, make up something */ + char tmpid[256]; + snprintf(tmpid, sizeof(tmpid), "chan-%x", rand()); +- ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); ++ ast_monitor_start(which, qe->parent->monfmt, tmpid, NULL, NULL, 1 ); + } + if (qe->parent->monjoin) + ast_monitor_setjoinfiles(which, 1); +diff -urNad asterisk-1.2.12.1.dfsg~/apps/app_readfile.c asterisk-1.2.12.1.dfsg/apps/app_readfile.c +--- asterisk-1.2.12.1.dfsg~/apps/app_readfile.c 2006-03-23 20:13:48.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/apps/app_readfile.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_segfault.c asterisk-1.2.12.1.dfsg/apps/app_segfault.c +--- asterisk-1.2.12.1.dfsg~/apps/app_segfault.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_segfault.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/apps/app_zapras.c asterisk-1.2.12.1.dfsg/apps/app_zapras.c +--- asterisk-1.2.12.1.dfsg~/apps/app_zapras.c 2006-07-12 14:54:10.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_zapras.c 2006-09-23 18:07:45.000000000 +0100 +@@ -180,7 +180,7 @@ + } + } + /* Throw back into audio mode */ +- x = 1; ++ x = 0; + ioctl(chan->fds[0], ZT_AUDIOMODE, &x); + + /* Restore saved values */ +diff -urNad asterisk-1.2.12.1.dfsg~/apps/app_zapras.c.orig asterisk-1.2.12.1.dfsg/apps/app_zapras.c.orig +--- asterisk-1.2.12.1.dfsg~/apps/app_zapras.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/apps/app_zapras.c.orig 2006-09-23 18:07:45.000000000 +0100 +@@ -0,0 +1,274 @@ ++/* ++ * Asterisk -- An open source telephony toolkit. ++ * ++ * Copyright (C) 1999 - 2005, Digium, Inc. ++ * ++ * Mark Spencer ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2. See the LICENSE file ++ * at the top of the source tree. ++ */ ++ ++/*! \file ++ * ++ * \brief Execute an ISDN RAS ++ * ++ * \ingroup applications ++ */ ++ ++#include ++#include ++#ifdef __linux__ ++#include ++#else ++#include ++#endif /* __linux__ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Need some zaptel help here */ ++#ifdef __linux__ ++#include ++#else ++#include ++#endif /* __linux__ */ ++ ++#include "asterisk.h" ++ ++ASTERISK_FILE_VERSION(__FILE__, "$Revision: 37419 $") ++ ++#include "asterisk/lock.h" ++#include "asterisk/file.h" ++#include "asterisk/logger.h" ++#include "asterisk/channel.h" ++#include "asterisk/pbx.h" ++#include "asterisk/module.h" ++#include "asterisk/options.h" ++ ++static char *tdesc = "Zap RAS Application"; ++ ++static char *app = "ZapRAS"; ++ ++static char *synopsis = "Executes Zaptel ISDN RAS application"; ++ ++static char *descrip = ++" ZapRAS(args): Executes a RAS server using pppd on the given channel.\n" ++"The channel must be a clear channel (i.e. PRI source) and a Zaptel\n" ++"channel to be able to use this function (No modem emulation is included).\n" ++"Your pppd must be patched to be zaptel aware. Arguments should be\n" ++"separated by | characters.\n"; ++ ++STANDARD_LOCAL_USER; ++ ++LOCAL_USER_DECL; ++ ++#define PPP_MAX_ARGS 32 ++#define PPP_EXEC "/usr/sbin/pppd" ++ ++static pid_t spawn_ras(struct ast_channel *chan, char *args) ++{ ++ pid_t pid; ++ int x; ++ char *c; ++ ++ char *argv[PPP_MAX_ARGS]; ++ int argc = 0; ++ char *stringp=NULL; ++ ++ /* Start by forking */ ++ pid = fork(); ++ if (pid) ++ return pid; ++ ++ /* Execute RAS on File handles */ ++ dup2(chan->fds[0], STDIN_FILENO); ++ ++ /* Drop high priority */ ++ if (option_highpriority) ++ ast_set_priority(0); ++ ++ /* Close other file descriptors */ ++ for (x=STDERR_FILENO + 1;x<1024;x++) ++ close(x); ++ ++ /* Restore original signal handlers */ ++ for (x=0;xfds[0], ZT_GET_BUFINFO, &savebi); ++ if(res) { ++ ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name); ++ return; ++ } ++ ++ pid = spawn_ras(chan, args); ++ if (pid < 0) { ++ ast_log(LOG_WARNING, "Failed to spawn RAS\n"); ++ } else { ++ for (;;) { ++ res = wait4(pid, &status, WNOHANG, NULL); ++ if (!res) { ++ /* Check for hangup */ ++ if (chan->_softhangup && !signalled) { ++ ast_log(LOG_DEBUG, "Channel '%s' hungup. Signalling RAS at %d to die...\n", chan->name, pid); ++ kill(pid, SIGTERM); ++ signalled=1; ++ } ++ /* Try again */ ++ sleep(1); ++ continue; ++ } ++ if (res < 0) { ++ ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno)); ++ } ++ if (option_verbose > 2) { ++ if (WIFEXITED(status)) { ++ ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with status %d\n", chan->name, WEXITSTATUS(status)); ++ } else if (WIFSIGNALED(status)) { ++ ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with signal %d\n", ++ chan->name, WTERMSIG(status)); ++ } else { ++ ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated weirdly.\n", chan->name); ++ } ++ } ++ /* Throw back into audio mode */ ++ x = 1; ++ ioctl(chan->fds[0], ZT_AUDIOMODE, &x); ++ ++ /* Restore saved values */ ++ res = ioctl(chan->fds[0], ZT_SET_BUFINFO, &savebi); ++ if (res < 0) { ++ ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name); ++ } ++ break; ++ } ++ } ++} ++ ++static int zapras_exec(struct ast_channel *chan, void *data) ++{ ++ int res=-1; ++ char *args; ++ struct localuser *u; ++ ZT_PARAMS ztp; ++ ++ if (!data) ++ data = ""; ++ ++ LOCAL_USER_ADD(u); ++ ++ args = ast_strdupa(data); ++ if (!args) { ++ ast_log(LOG_ERROR, "Out of memory\n"); ++ LOCAL_USER_REMOVE(u); ++ return -1; ++ } ++ ++ /* Answer the channel if it's not up */ ++ if (chan->_state != AST_STATE_UP) ++ ast_answer(chan); ++ if (strcasecmp(chan->type, "Zap")) { ++ /* If it's not a zap channel, we're done. Wait a couple of ++ seconds and then hangup... */ ++ if (option_verbose > 1) ++ ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a Zap channel\n", chan->name); ++ sleep(2); ++ } else { ++ memset(&ztp, 0, sizeof(ztp)); ++ if (ioctl(chan->fds[0], ZT_GET_PARAMS, &ztp)) { ++ ast_log(LOG_WARNING, "Unable to get zaptel parameters\n"); ++ } else if (ztp.sigtype != ZT_SIG_CLEAR) { ++ if (option_verbose > 1) ++ ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a clear channel\n", chan->name); ++ } else { ++ /* Everything should be okay. Run PPP. */ ++ if (option_verbose > 2) ++ ast_verbose(VERBOSE_PREFIX_3 "Starting RAS on %s\n", chan->name); ++ /* Execute RAS */ ++ run_ras(chan, args); ++ } ++ } ++ LOCAL_USER_REMOVE(u); ++ return res; ++} ++ ++int unload_module(void) ++{ ++ int res; ++ ++ res = ast_unregister_application(app); ++ ++ STANDARD_HANGUP_LOCALUSERS; ++ ++ return res; ++} ++ ++int load_module(void) ++{ ++ return ast_register_application(app, zapras_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 -urNad asterisk-1.2.12.1.dfsg~/asterisk.c asterisk-1.2.12.1.dfsg/asterisk.c +--- asterisk-1.2.12.1.dfsg~/asterisk.c 2006-08-21 23:34:26.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/asterisk.c 2006-09-23 18:07:45.000000000 +0100 +@@ -228,6 +228,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; +@@ -1877,6 +1878,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) { +@@ -1991,6 +1993,8 @@ + /* What group to run as */ + } else if (!strcasecmp(v->name, "rungroup")) { + ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP)); ++ } else if (!strcasecmp(v->name, "uniquename")) { ++ strncpy(ast_config_AST_SYMBOLIC_NAME,v->value,sizeof(ast_config_AST_SYMBOLIC_NAME)); + } + v = v->next; + } +diff -urNad asterisk-1.2.12.1.dfsg~/build_tools/make_defaults_h asterisk-1.2.12.1.dfsg/build_tools/make_defaults_h +--- asterisk-1.2.12.1.dfsg~/build_tools/make_defaults_h 2005-06-20 18:26:08.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/build_tools/make_defaults_h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/channel.c asterisk-1.2.12.1.dfsg/channel.c +--- asterisk-1.2.12.1.dfsg~/channel.c 2006-09-09 21:24:19.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channel.c 2006-09-23 18:07:45.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) +@@ -2423,7 +2452,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; +@@ -2431,7 +2460,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) +@@ -2445,6 +2474,7 @@ + } + ast_set_callerid(chan, cid_num, cid_name, cid_num); + ++ chan->cid.cid_pres = callingpres; + if (!ast_call(chan, data, 0)) { + res = 1; /* in case chan->_state is already AST_STATE_UP */ + while (timeout && (chan->_state != AST_STATE_UP)) { +@@ -2468,6 +2498,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; +@@ -2537,12 +2568,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; +@@ -2579,6 +2610,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" +@@ -2854,6 +2886,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]; +@@ -2995,7 +3050,7 @@ + ast_copy_string(clone->name, masqn, sizeof(clone->name)); + + /* Notify any managers of the change, first the masq then the other */ +- manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", newn, masqn, clone->uniqueid); ++ manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\nNewUniqueid: %s\r\n", newn, masqn, clone->uniqueid, original->uniqueid); + manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", orig, newn, original->uniqueid); + + /* Swap the technlogies */ +@@ -3243,15 +3298,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" +@@ -3267,6 +3321,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) + { +@@ -3443,6 +3501,7 @@ + char caller_warning = 0; + char callee_warning = 0; + ++ + if (c0->_bridge) { + ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", + c0->name, c0->_bridge->name); +@@ -3453,6 +3512,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 -urNad asterisk-1.2.12.1.dfsg~/channels/Makefile asterisk-1.2.12.1.dfsg/channels/Makefile +--- asterisk-1.2.12.1.dfsg~/channels/Makefile 2006-08-17 22:57:19.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/Makefile 2006-09-23 18:07:45.000000000 +0100 +@@ -102,6 +102,11 @@ + ZAPR2=-lmfcr2 + endif + ++ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libgsmat.so.1)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/lib/libgsmat.so.1),) ++ CFLAGS+=-DZAPATA_GSM ++ ZAPGSM=-lgsmat ++endif ++ + ALSA_SRC=chan_alsa.c + + ifneq ($(wildcard alsa-monitor.h),) +@@ -122,6 +127,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 +@@ -204,7 +238,7 @@ + $(CC) -c $(CFLAGS) -o chan_zap.o chan_zap.c + + chan_zap.so: chan_zap.o +- $(CC) $(SOLINK) -o $@ $< $(ZAPPRI) $(ZAPR2) -ltonezone ++ $(CC) $(SOLINK) -o $@ $< $(ZAPPRI) $(ZAPGSM) $(ZAPR2) -ltonezone + + chan_sip.so: chan_sip.o + $(CC) $(SOLINK) -o $@ ${CYGSOLINK} chan_sip.o ${CYGSOLIB} +@@ -220,6 +254,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 -urNad asterisk-1.2.12.1.dfsg~/channels/chan_agent.c asterisk-1.2.12.1.dfsg/channels/chan_agent.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_agent.c 2006-09-06 19:16:41.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/chan_agent.c 2006-09-23 18:07:45.000000000 +0100 +@@ -440,7 +440,7 @@ + if ((pointer = strchr(filename, '.'))) + *pointer = '-'; + snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename); +- ast_monitor_start(ast, recordformat, tmp, needlock); ++ ast_monitor_start(ast, recordformat, tmp, NULL, NULL, needlock); + ast_monitor_setjoinfiles(ast, 1); + snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext); + #if 0 +@@ -1336,7 +1336,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 -urNad asterisk-1.2.12.1.dfsg~/channels/chan_capi.c asterisk-1.2.12.1.dfsg/channels/chan_capi.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_capi.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/chan_capi.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/channels/chan_features.c asterisk-1.2.12.1.dfsg/channels/chan_features.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_features.c 2006-08-30 19:59:44.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/chan_features.c 2006-09-23 18:07:45.000000000 +0100 +@@ -427,7 +427,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 -urNad asterisk-1.2.12.1.dfsg~/channels/chan_iax2.c asterisk-1.2.12.1.dfsg/channels/chan_iax2.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_iax2.c 2006-09-06 16:55:20.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/chan_iax2.c 2006-09-23 18:07:45.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. +@@ -3096,7 +3099,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); +@@ -3148,7 +3151,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; + } + +diff -urNad asterisk-1.2.12.1.dfsg~/channels/chan_sip.c asterisk-1.2.12.1.dfsg/channels/chan_sip.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_sip.c 2006-09-09 13:14:03.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/chan_sip.c 2006-09-23 18:07:45.000000000 +0100 +@@ -603,6 +603,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 */ +@@ -626,6 +627,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[SIP_LEN_CONTACT]; /*!< 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? */ +@@ -645,6 +647,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[SIP_LEN_CONTACT]; /*!< REAL! Original requested URI */ + char okcontacturi[SIP_LEN_CONTACT]; /*!< URI from the 200 OK on INVITE */ + char peersecret[256]; /*!< Password */ + char peermd5secret[256]; +@@ -768,6 +771,9 @@ + int callingpres; /*!< Calling id presentation */ + int inUse; /*!< Number of calls in use */ + int call_limit; /*!< Limit of concurrent calls */ ++ int max_regs; /*!< Limit of concurrent registrations */ ++ int subpeer; /*!< Peer entry used for multiple registrations */ ++ char reg_callid[80]; /*!< Call-ID used for registration */ + char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/ + char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox setting for MWI checks */ + char language[MAX_LANGUAGE]; /*!< Default language for prompts */ +@@ -928,7 +934,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 */ +@@ -1320,7 +1326,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 */ +@@ -3169,16 +3175,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 +@@ -4156,6 +4176,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)) +@@ -4922,13 +4943,15 @@ + 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 (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) { + /* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */ + snprintf(to, sizeof(to), ";tag=%s", p->uri, p->theirtag); + } else if (p->options && p->options->vxml_url) { + /* If there is a VXML URL append it to the SIP 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); + } +@@ -4985,6 +5008,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); +@@ -5059,8 +5087,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); +@@ -5204,10 +5231,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; +@@ -6034,8 +6070,10 @@ + p->expire = -1; + pvt->expiry = expiry; + snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port), expiry, p->username, p->fullcontact); +- if (!ast_test_flag((&p->flags_page2), SIP_PAGE2_RT_FROMCONTACT)) ++ if (!ast_test_flag((&p->flags_page2), SIP_PAGE2_RT_FROMCONTACT)) { ++ // ast_log(LOG_NOTICE, "updating SIP/Registry for peer %s with data %s\n", p->name, data); + ast_db_put("SIP/Registry", p->name, data); ++ } + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Registered\r\n", p->name); + if (inaddrcmp(&p->addr, &oldsin)) { + sip_poke_peer(p); +@@ -6426,7 +6464,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; + +@@ -6445,7 +6483,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); +@@ -6471,7 +6509,13 @@ + char *name, *c; + char *t; + char *domain; +- ++ char *callid; ++ struct sip_peer *clone; ++ char clone_name[256]; ++ int found = 0; ++ struct sip_peer *recycle_peer = NULL; ++ char peer_name[256]; ++ + /* Terminate URI */ + t = uri; + while(*t && (*t > 32) && (*t != ';')) +@@ -6520,9 +6564,68 @@ + if (!ast_test_flag(&peer->flags_page2, SIP_PAGE2_DYNAMIC)) { + ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name); + } else { ++ callid = get_header(req, "Call-ID"); ++ ast_copy_string(peer_name, peer->name, sizeof(peer_name)); ++ if (peer->max_regs > 1) { ++ int i = 0; ++ /* check if peer matches callid */ ++ if ((peer->expire > -1) && (!strncmp(peer->reg_callid, callid, strlen(callid)))) { ++ // ast_log(LOG_NOTICE, "peer->reg_callid %s, req->callid %s found in peer\n", peer->reg_callid, callid); ++ found++; ++ } else { ++ /* otherwise check subpeers for callid */ ++ for (i=0; imax_regs - 1; i++) { ++ snprintf(clone_name, sizeof(clone_name), "%s@%d", peer->name, i); ++ // ast_log(LOG_NOTICE, "checking subpeer %s\n", clone_name); ++ clone = find_peer(clone_name, NULL, 1); ++ if (clone && (clone->expire > -1)) { ++ if (!strncmp(clone->reg_callid, callid, strlen(callid))) { ++ // ast_log(LOG_NOTICE, "clone->reg_callid %s, req->callid %s found in subpeer\n", clone->reg_callid, callid); ++ found++; ++ peer = clone; ++ break; ++ } ++ } ++ } ++ } ++ if (!found) { ++ // ast_log(LOG_NOTICE, "did not find callid in peer or subpeer\n"); ++ /* choose the next best peer or subpeer (that means: find the peer with the smalles expiry time */ ++ if (peer->expire == -1) { ++ recycle_peer = peer; ++ // ast_log(LOG_NOTICE, "peer %s expiry %d\n", peer->name, peer->expire); ++ } else { ++ for (i=0; imax_regs - 1; i++) { ++ snprintf(clone_name, sizeof(clone_name), "%s@%d", peer->name, i); ++ clone = find_peer(clone_name, NULL, 1); ++ if (clone) { ++ if (clone->expire == -1) { ++ recycle_peer = clone; ++ break; ++ } ++ // ast_log(LOG_NOTICE, "clone %s expiry %d\n", clone->name, clone->expire); ++ } ++ } ++ } ++ if (recycle_peer) { ++ peer = recycle_peer; ++ ast_copy_string(peer_name, peer->name, sizeof(peer_name)); ++ // ast_log(LOG_NOTICE, "recycling peer %s\n", peer->name); ++ if (peer->subpeer) { ++ i = strchr(peer_name, '@') - peer_name; ++ if (i < sizeof(peer_name)) ++ peer_name[i] = '\0'; ++ // ast_log(LOG_NOTICE, "i = %d\n", i); ++ } ++ } else { ++ /* deny registration */ ++ peer_name[0] = '\0'; ++ } ++ } ++ } + ast_copy_flags(p, peer, SIP_NAT); + transmit_response(p, "100 Trying", req); +- if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri, 0, ignore))) { ++ if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), peer_name, peer->secret, peer->md5secret, SIP_REGISTER, uri, 0, ignore))) { + sip_cancel_destroy(p); + switch (parse_register_contact(p, peer, req)) { + case PARSE_REGISTER_FAILED: +@@ -6542,6 +6645,7 @@ + transmit_response_with_date(p, "200 OK", req); + peer->lastmsgssent = -1; + res = 0; ++ ast_copy_string(peer->reg_callid, callid, sizeof(peer->reg_callid)); + break; + } + } +@@ -6890,6 +6994,11 @@ + /* XXX The refer_to could contain a call on an entirely different machine, requiring an + INVITE with a replaces header -anthm XXX */ + /* The only way to find out is to use the dialplan - oej */ ++ ast_copy_string(sip_pvt->refer_to, refer_to, sizeof(sip_pvt->refer_to)); ++ ast_copy_string(sip_pvt->referred_by, referred_by, sizeof(sip_pvt->referred_by)); ++ ast_copy_string(sip_pvt->refer_contact, h_contact, sizeof(sip_pvt->refer_contact)); ++ ast_copy_string(sip_pvt->refer_replaces, replace_callid, sizeof(sip_pvt->referred_by)); ++ return 2; + } + } else if (ast_exists_extension(NULL, transfercontext, refer_to, 1, NULL) || !strcmp(refer_to, ast_parking_ext())) { + /* This is an unsupervised transfer (blind transfer) */ +@@ -7611,6 +7720,8 @@ + int peers_offline = 0; + char *id; + char idtext[256] = ""; ++ char *tmp; ++ int i = 0; + + if (s) { /* Manager - get ActionID */ + id = astman_get_header(m,"ActionID"); +@@ -7653,6 +7764,7 @@ + else + ast_copy_string(name, iterator->name, sizeof(name)); + ++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) { + pstatus = peer_status(iterator, status, sizeof(status)); + if (pstatus) + peers_online++; +@@ -7669,14 +7781,24 @@ + } + } + +- snprintf(srch, sizeof(srch), FORMAT, name, ++ } ++ /* multiple registration, peer used ? */ ++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) { ++ snprintf(srch, sizeof(srch), FORMAT, name, + iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)", + ast_test_flag(&iterator->flags_page2, SIP_PAGE2_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ + (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ + iterator->ha ? " A " : " ", /* permit/deny */ + ntohs(iterator->addr.sin_port), status); ++ } + + if (!s) {/* Normal CLI list */ ++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) { ++ if (iterator->subpeer == 1) { ++ tmp = strchr(name, '@'); ++ i = tmp - name; ++ name[i] = '\0'; ++ } + ast_cli(fd, FORMAT, name, + iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)", + ast_test_flag(&iterator->flags_page2, SIP_PAGE2_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ +@@ -7684,6 +7806,7 @@ + iterator->ha ? " A " : " ", /* permit/deny */ + + ntohs(iterator->addr.sin_port), status); ++ } + } else { /* Manager format */ + /* The names here need to be the same as other channels */ + ast_cli(fd, +@@ -7709,7 +7832,9 @@ + + ASTOBJ_UNLOCK(iterator); + +- total_peers++; ++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) { ++ total_peers++; ++ } + } while(0) ); + + if (!s) { +@@ -8744,6 +8869,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") || +@@ -8807,6 +8933,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)) { +@@ -8906,12 +9045,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; + +@@ -8928,41 +9118,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[]) + { +@@ -9627,7 +9789,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 (find_sdp(req)) { + process_sdp(p, req); +@@ -10457,9 +10619,18 @@ + /* This is a call to ourself. Send ourselves an error code and stop + processing immediately, as SIP really has no good mechanism for + being able to call yourself */ +- transmit_response(p, "482 Loop Detected", req); +- /* We do NOT destroy p here, so that our response will be accepted */ +- return 0; ++/* char tmp[256] = "", *uri; ++ if (req->rlPart2) ++ ast_copy_string(tmp, req->rlPart2, sizeof(tmp)); ++ uri = get_in_brackets(tmp); ++ if (strcmp(p->uri, uri)) { ++ ast_log(LOG_NOTICE, "SPIRAL DETECTED p->uri: %s uri: %s\n", p->uri, uri); ++ } else { ++ ast_log(LOG_NOTICE, "LOOP DETECTED p->uri: %s uri: %s\n", p->uri, uri);*/ ++ transmit_response(p, "482 Loop Detected", req); ++ /* We do NOT destroy p here, so that our response will be accepted */ ++ return 0; ++/* }*/ + } + if (!ignore) { + /* Use this as the basis */ +@@ -10691,6 +10862,7 @@ + struct ast_channel *c=NULL; + int res; + struct ast_channel *transfer_to; ++ struct sip_pvt *rp; /* replace call */ + + if (option_debug > 2) + ast_log(LOG_DEBUG, "SIP call transfer received for call %s (REFER)!\n", p->callid); +@@ -10699,9 +10871,73 @@ + res = get_refer_info(p, req); + if (res < 0) + transmit_response(p, "603 Declined", req); +- else if (res > 0) ++ else if (res == 1) + transmit_response(p, "484 Address Incomplete", req); +- else { ++ else if (res == 2) { ++ transmit_response(p, "202 Accepted", req); ++ rp = sip_alloc(NULL, NULL, 0, SIP_INVITE); ++ if (!rp) { ++ return -1; ++ } ++ rp->capability = global_capability; ++ ++ build_route(rp, req, 0); ++ if (option_verbose > 3) ++ ast_log(LOG_NOTICE, "got REFER for callid %s TO %s CONTACT %s replacing callid %s (tohost %s, p->route %s, rp->route %s)\n", p->callid, p->refer_to, p->refer_contact, p->refer_replaces, p->tohost, p->route->hop, rp->route->hop); ++ if (create_addr(rp, p->tohost)) { ++ sip_destroy(rp); ++ return -1; ++ } ++ ++ if (ast_sip_ouraddrfor(&rp->sa.sin_addr,&rp->ourip)) { ++ memcpy(&rp->ourip, &__ourip, sizeof(rp->ourip)); ++ } ++ build_via(rp, rp->via, sizeof(rp->via)); ++ build_callid(rp->callid, sizeof(rp->callid) - 1, rp->ourip, rp->fromdomain); ++ ++ ast_log(LOG_NOTICE, "1\n"); ++ rp->prefcodec = p->prefcodec; ++ rp->jointcapability = rp->capability; ++ rp->rtp = p->rtp; ++ p->rtp = NULL; ++ if (!ast_strlen_zero(p->refer_to)) { ++ ast_copy_string(rp->username, p->refer_to, sizeof(rp->username)); ++ rp->fullcontact[0] = '\0'; ++ } ++ if (!ast_strlen_zero(p->refer_replaces)) { ++ ast_copy_string(rp->refer_replaces, p->refer_replaces, sizeof(rp->refer_replaces)); ++ } ++ ast_log(LOG_NOTICE, "2\n"); ++ ast_set_flag(rp, SIP_OUTGOING); ++ ++ ast_log(LOG_NOTICE, "3\n"); ++ ++ if (p->owner) { ++ c = p->owner; ++// ast_copy_string(rp->cid_num, c->cid.cid_num, sizeof(rp->cid_num)); ++// ast_copy_string(rp->cid_name, c->cid.cid_name, sizeof(rp->cid_name)); ++ ast_log(LOG_NOTICE, "4\n"); ++ c->tech_pvt = rp; ++ rp->owner = c; ++ ast_log(LOG_NOTICE, "5\n"); ++ ast_mutex_unlock(&c->lock); ++ } ++ p->owner = NULL; ++ ast_log(LOG_NOTICE, "6\n"); ++ ++ transmit_invite(rp, SIP_INVITE, 1, 2); ++ if (rp->maxtime) { ++ /* Initialize auto-congest time */ ++ rp->initid = ast_sched_add(sched, rp->maxtime * 4, auto_congest, rp); ++ } ++ ++ transmit_notify_with_sipfrag(p, seqno); ++ ++ /* Always increment on a BYE */ ++ transmit_request_with_auth(p, SIP_BYE, 0, 1, 1); ++ ast_set_flag(p, SIP_ALREADYGONE); ++ return 0; ++ } else { /* res == 0 */ + int nobye = 0; + if (!ignore) { + if (p->refer_call) { +@@ -11034,7 +11270,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, +@@ -11228,6 +11464,8 @@ + res = handle_request_options(p, req, debug); + break; + case SIP_INVITE: ++ /* XXX quick fix for xfers */ ++ ast_copy_string(p->tohost, ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), sizeof(p->tohost)); + res = handle_request_invite(p, req, debug, ignore, seqno, sin, recount, e); + break; + case SIP_REFER: +@@ -11348,7 +11586,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)) { +@@ -11685,6 +11923,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:--- +@@ -12222,6 +12506,7 @@ + + peer->expire = -1; + peer->pokeexpire = -1; ++ peer->max_regs = 1; + ast_copy_string(peer->name, name, sizeof(peer->name)); + ast_copy_flags(peer, &global_flags, SIP_FLAGS_TO_COPY); + strcpy(peer->context, default_context); +@@ -12267,7 +12552,9 @@ + + if (peer) { + /* Already in the list, remove it and it will be added back (or FREE'd) */ +- found++; ++ if (peer->max_regs == 1) { ++ found++; ++ } + } else { + peer = malloc(sizeof(*peer)); + if (peer) { +@@ -12279,6 +12566,7 @@ + ASTOBJ_INIT(peer); + peer->expire = -1; + peer->pokeexpire = -1; ++ peer->max_regs = 1; + } else { + ast_log(LOG_WARNING, "Can't allocate SIP peer memory\n"); + } +@@ -12424,6 +12712,10 @@ + peer->call_limit = atoi(v->value); + if (peer->call_limit < 0) + peer->call_limit = 0; ++ } else if (!strcasecmp(v->name, "registrations")) { ++ peer->max_regs = atoi(v->value); ++ if (peer->max_regs < 0) ++ peer->max_regs = 0; + } else if (!strcasecmp(v->name, "amaflags")) { + format = ast_cdr_amaflags2int(v->value); + if (format < 0) { +@@ -12819,8 +13111,24 @@ + if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) { + peer = build_peer(cat, ast_variable_browse(cfg, cat), 0); + if (peer) { +- ASTOBJ_CONTAINER_LINK(&peerl,peer); +- ASTOBJ_UNREF(peer, sip_destroy_peer); ++ if (peer->max_regs > 1) { ++ int i = 0; ++ int clones = peer->max_regs - 1; ++ struct sip_peer *clone = NULL; ++ char clone_name[sizeof(clone->name)]; ++ /* clone clone clone */ ++ for (i=0;isubpeer = 1; ++ ASTOBJ_CONTAINER_LINK(&peerl,clone); ++ ASTOBJ_UNREF(clone, sip_destroy_peer); ++ } ++ } ++ } ++ ASTOBJ_CONTAINER_LINK(&peerl,peer); ++ ASTOBJ_UNREF(peer, sip_destroy_peer); + } + } else if (strcasecmp(utype, "user")) { + ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, "sip.conf"); +@@ -13418,6 +13726,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(); +@@ -13448,6 +13758,7 @@ + + ast_rtp_proto_unregister(&sip_rtp); + ++ ast_manager_unregister("SIPNotify"); + ast_manager_unregister("SIPpeers"); + ast_manager_unregister("SIPshowpeer"); + +diff -urNad asterisk-1.2.12.1.dfsg~/channels/chan_zap.c asterisk-1.2.12.1.dfsg/channels/chan_zap.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_zap.c 2006-08-25 16:21:18.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/channels/chan_zap.c 2006-09-23 18:07:45.000000000 +0100 +@@ -11,6 +11,10 @@ + * the project provides a web site, mailing lists and IRC + * channels for your use. + * ++ * Copyright (C) 2003-2006 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. +@@ -65,6 +69,9 @@ + #ifdef ZAPATA_R2 + #include + #endif ++#ifdef ZAPATA_GSM ++#include ++#endif + + #include "asterisk.h" + +@@ -96,6 +103,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" +@@ -173,6 +181,7 @@ + #define SIG_FXOGS ZT_SIG_FXOGS + #define SIG_FXOKS ZT_SIG_FXOKS + #define SIG_PRI ZT_SIG_CLEAR ++#define SIG_GSM (0x100000 | ZT_SIG_CLEAR) + #define SIG_R2 ZT_SIG_CAS + #define SIG_SF ZT_SIG_SF + #define SIG_SFWINK (0x0100000 | ZT_SIG_SF) +@@ -183,7 +192,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 +210,11 @@ + static char defaultcic[64] = ""; + static char defaultozz[64] = ""; + ++static char nocid[256] = "No CID available"; ++static char withheldcid[256] = "CID withheld"; ++static char gsm_modem_pin[20]; ++static char gsm_modem_exten[AST_MAX_EXTENSION]; ++ + static char language[MAX_LANGUAGE] = ""; + static char musicclass[MAX_MUSICCLASS] = ""; + static char progzone[10]= ""; +@@ -287,6 +301,7 @@ + static int cur_priexclusive = 0; + + static int priindication_oob = 0; ++static int pritransfer = 0; + + #ifdef ZAPATA_PRI + static int minunused = 2; +@@ -294,6 +309,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 +321,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 +341,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; + +@@ -389,6 +399,18 @@ + + struct zt_pvt; + ++#ifdef ZAPATA_GSM ++struct zt_gsm { ++ pthread_t master; ++ ast_mutex_t lock; /* Mutex */ ++ int fd; ++ int span; ++ struct gsm_modul *modul; ++ char pin[256]; ++ char exten[AST_MAX_EXTENSION]; /* Where to idle extra calls */ ++ struct zt_pvt *pvt; ++}; ++#endif + + #ifdef ZAPATA_R2 + static int r2prot = -1; +@@ -403,6 +425,28 @@ + #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 +460,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 +481,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 +489,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 +611,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 +625,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 +665,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]; +@@ -672,10 +726,15 @@ + int polarityonanswerdelay; + struct timeval polaritydelaytv; + int sendcalleridafter; ++#ifdef ZAPATA_GSM ++ struct zt_gsm gsm; ++#endif + #ifdef ZAPATA_PRI + 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 +760,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 +781,7 @@ + .indicate = zt_indicate, + .fixup = zt_fixup, + .setoption = zt_setoption, ++ .devicestate = zt_devicestate + }; + + #ifdef ZAPATA_PRI +@@ -730,6 +793,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; +@@ -777,6 +847,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; +@@ -1179,6 +1355,8 @@ + return "GR-303 Signalling with FXOKS"; + case SIG_GR303FXSKS: + return "GR-303 Signalling with FXSKS"; ++ case SIG_GSM: ++ return "GSM Signalling"; + case 0: + return "Pseudo Signalling"; + default: +@@ -1379,12 +1557,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) { +@@ -1410,7 +1592,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) +@@ -1590,7 +1772,7 @@ + { + int x, y, res; + x = muted; +- if (p->sig == SIG_PRI) { ++ if ((p->sig == SIG_PRI) || (p->sig == SIG_GSM)) { + y = 1; + res = ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &y); + if (res) +@@ -1772,7 +1954,12 @@ + 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); ++ } ++ + + switch(p->sig) { + case SIG_FXOLS: +@@ -1996,6 +2183,26 @@ + case SIG_PRI: + /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */ + p->dialdest[0] = '\0'; ++ disable_dtmf_detect(p); ++ break; ++ case SIG_GSM: ++#ifdef ZAPATA_GSM ++ if (p->gsm.modul) { ++ c = strchr(dest, '/'); ++ if (c) ++ c++; ++ else ++ c = dest; ++ ast_mutex_lock(&p->gsm.lock); ++ if (gsm_dial(p->gsm.modul, p->use_callingpres ? ast->cid.cid_pres : 0, c)) { ++ ast_log(LOG_WARNING, "dialing failed on channel %d\n", p->channel); ++ ast_mutex_unlock(&p->gsm.lock); ++ ast_mutex_unlock(&p->lock); ++ return -1; ++ } ++ ast_mutex_unlock(&p->gsm.lock); ++ } ++#endif + break; + default: + ast_log(LOG_DEBUG, "not yet implemented\n"); +@@ -2014,6 +2221,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++; +@@ -2031,6 +2244,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'); +@@ -2054,6 +2268,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); +@@ -2083,7 +2299,7 @@ + pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1); + pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability, + (p->digital ? -1 : +- ((p->law == ZT_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW))); ++ ((p->law == ZT_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)), ast->lowlayercompat); + if (p->pri->facilityenable) + pri_facility_enable(p->pri->pri); + +@@ -2284,8 +2500,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", +@@ -2341,8 +2559,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; +@@ -2439,6 +2656,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; +@@ -2475,19 +2693,61 @@ + if (p->call && (!p->bearer || (p->bearer->call == p->call))) { + if (!pri_grab(p, p->pri)) { + if (p->alreadyhungup) { ++/* char *aoc = pbx_builtin_getvar_helper(ast,"AOCEUNITS"); ++ int iaoc = aoc ? atoi(aoc) : -1; ++ char *aocpm = pbx_builtin_getvar_helper(ast,"AOCEUNITSPERMIN"); ++ int iaocpm = aocpm ? atoi(aocpm) : -1; ++ ++ if (iaocpm > -1) { ++ if (ast->cdr) { ++ long bill_sec = ast->cdr->billsec; ++ long bill_min = 0; ++ if (bill_sec > 0) { ++ bill_min = bill_sec / 60; ++ if (bill_min < 1) bill_min = 1; ++ } ++ iaoc = bill_min * iaocpm; ++ } else { ++ ast_log(LOG_NOTICE, "no cdr \n"); ++ } ++ } else { ++ ast_log(LOG_NOTICE, "iaocpm %d \n", iaocpm); ++ } ++*/ + ast_log(LOG_DEBUG, "Already hungup... Calling hangup once, and clearing call\n"); + + #ifdef SUPPORT_USERUSER + pri_call_set_useruser(p->call, useruser); + #endif + +- pri_hangup(p->pri->pri, p->call, -1); ++ pri_hangup(p->pri->pri, p->call, -1, -1); + p->call = NULL; + if (p->bearer) + p->bearer->call = NULL; + } else { + char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE"); + int icause = ast->hangupcause ? ast->hangupcause : -1; ++/* char *aoc = pbx_builtin_getvar_helper(ast,"AOCEUNITS"); ++ int iaoc = aoc ? atoi(aoc) : -1; ++ char *aocpm = pbx_builtin_getvar_helper(ast,"AOCEUNITSPERMIN"); ++ int iaocpm = aocpm ? atoi(aocpm) : -1; ++ ++ if (iaocpm > -1) { ++ if (ast->cdr) { ++ long bill_sec = ast->cdr->billsec; ++ long bill_min = 0; ++ if (bill_sec > 0) { ++ bill_min = bill_sec / 60; ++ if (bill_min < 1) bill_min = 1; ++ } ++ iaoc = bill_min * iaocpm; ++ } else { ++ ast_log(LOG_NOTICE, "no cdr \n"); ++ } ++ } else { ++ ast_log(LOG_NOTICE, "iaocpm %d \n", iaocpm); ++ } ++*/ + ast_log(LOG_DEBUG, "Not yet hungup... Calling hangup once with icause, and clearing call\n"); + + #ifdef SUPPORT_USERUSER +@@ -2501,7 +2761,28 @@ + if (atoi(cause)) + icause = atoi(cause); + } +- pri_hangup(p->pri->pri, p->call, icause); ++ ++ pri_hangup(p->pri->pri, p->call, icause, -1); ++ ++ /* 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; /* Note, in pri_hangup() libpri will already override the cause */ ++ } ++ } ++ ++ 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"); +@@ -2529,7 +2810,13 @@ + + } + #endif +- if (p->sig && (p->sig != SIG_PRI) && (p->sig != SIG_R2)) ++#ifdef ZAPATA_GSM ++ if (p->gsm.modul) { ++ if (!p->alreadyhungup) ++ gsm_hangup(p->gsm.modul); ++ } ++#endif ++ if (p->sig && (p->sig != SIG_PRI) && (p->sig != SIG_R2) && (p->sig != SIG_GSM)) + res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_ONHOOK); + if (res < 0) { + ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name); +@@ -2698,10 +2985,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 +@@ -2711,6 +3002,13 @@ + ast_log(LOG_WARNING, "R2 Answer call failed :( on %s\n", ast->name); + break; + #endif ++#ifdef ZAPATA_GSM ++ case SIG_GSM: ++ if (p->gsm.modul) { ++ gsm_answer(p->gsm.modul); ++ } ++ break; ++#endif + case 0: + ast_mutex_unlock(&p->lock); + return 0; +@@ -3277,6 +3575,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) { +@@ -3637,7 +3944,7 @@ + if (p->call) { + if (p->pri && p->pri->pri) { + if (!pri_grab(p, p->pri)) { +- pri_hangup(p->pri->pri, p->call, -1); ++ pri_hangup(p->pri->pri, p->call, -1, -1); + pri_destroycall(p->pri->pri, p->call); + p->call = NULL; + pri_rel(p->pri); +@@ -4600,7 +4907,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 +4919,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->sig==SIG_PRI && p->pri && p->pri->overlapdial && 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; + } +@@ -4661,8 +4969,10 @@ + pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten); + if (ast_async_goto(ast, target_context, "fax", 1)) + ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context); +- } else +- ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); ++ } else { ++ if (option_verbose > 2) ++ ast_verbose(VERBOSE_PREFIX_3 "Fax detected, but no fax extension\n"); ++ } + } else + ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); + } else +@@ -4748,7 +5058,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 +5131,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 +5213,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 +5398,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; + } +@@ -5229,6 +5545,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); +@@ -5247,10 +5564,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 +@@ -6345,18 +6669,44 @@ + break; + case ZT_EVENT_NOALARM: + i->inalarm = 0; ++#ifdef ZAPATA_PRI ++ if (i->pri) { ++ if ((i->pri->nodetype == BRI_CPE_PTMP) || (i->pri->nodetype == BRI_CPE_PTMP)) { ++ /* dont annoy BRI TE mode users with layer2layer alarms */ ++ } else { ++ ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel); ++ manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", ++ "Channel: %d\r\n", i->channel); ++ } ++ } ++#else + ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel); + manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", + "Channel: %d\r\n", i->channel); ++#endif + break; + case ZT_EVENT_ALARM: + i->inalarm = 1; + res = get_alarms(i); ++#ifdef ZAPATA_PRI ++ if (i->pri) { ++ if ((i->pri->nodetype == BRI_CPE_PTMP) || (i->pri->nodetype == BRI_CPE_PTMP)) { ++ /* dont annoy BRI TE mode users with layer2layer alarms */ ++ } else { ++ ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", i->channel, alarm2str(res)); ++ manager_event(EVENT_FLAG_SYSTEM, "Alarm", ++ "Alarm: %s\r\n" ++ "Channel: %d\r\n", ++ alarm2str(res), i->channel); ++ } ++ } ++#else + ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", i->channel, alarm2str(res)); + manager_event(EVENT_FLAG_SYSTEM, "Alarm", + "Alarm: %s\r\n" + "Channel: %d\r\n", + alarm2str(res), i->channel); ++#endif + /* fall thru intentionally */ + case ZT_EVENT_ONHOOK: + if (i->radio) break; +@@ -6396,8 +6746,10 @@ + zt_set_hook(i->subs[SUB_REAL].zfd, ZT_ONHOOK); + break; + case SIG_PRI: +- zt_disable_ec(i); +- res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, -1); ++ if (event != ZT_EVENT_ALARM) { ++ zt_disable_ec(i); ++ res = tone_zone_play_tone(i->subs[SUB_REAL].zfd, -1); ++ } + break; + default: + ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel); +@@ -6720,6 +7072,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; + } +@@ -6807,6 +7161,10 @@ + + #endif + ++#ifdef ZAPATA_GSM ++static void *gsm_dchannel(void *vgsm); ++#endif ++ + static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_pri *pri, int reloading) + { + /* Make a zt_pvt structure for this interface (or CRV if "pri" is specified) */ +@@ -6965,6 +7323,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 +7355,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 +7374,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)); +@@ -7023,6 +7402,36 @@ + tmp->prioffset = 0; + } + #endif ++#ifdef ZAPATA_GSM ++ if (signalling == SIG_GSM) { ++ struct zt_bufferinfo bi; ++ ast_mutex_init(&tmp->gsm.lock); ++ strncpy(tmp->gsm.pin, gsm_modem_pin, sizeof(tmp->gsm.pin) - 1); ++ strncpy(tmp->gsm.exten, gsm_modem_exten, sizeof(tmp->gsm.exten) - 1); ++ snprintf(fn, sizeof(fn), "%d", channel + 1); ++ /* Open non-blocking */ ++ tmp->gsm.fd = zt_open(fn); ++ bi.txbufpolicy = ZT_POLICY_IMMEDIATE; ++ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; ++ bi.numbufs = 16; ++ bi.bufsize = 1024; ++ if (ioctl(tmp->gsm.fd, ZT_SET_BUFINFO, &bi)) { ++ ast_log(LOG_ERROR, "Unable to set buffer info on channel '%s': %s\n", fn, strerror(errno)); ++ return NULL; ++ } ++ tmp->gsm.pvt = tmp; ++ tmp->gsm.span = tmp->span; ++ tmp->gsm.modul = gsm_new(tmp->gsm.fd, 0, tmp->gsm.pin, tmp->span, tmp->channel); ++ if (ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, tmp->channel)) { ++ ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d: %s\n", tmp->channel, strerror(errno)); ++ destroy_zt_pvt(&tmp); ++ return NULL; ++ } ++ if (ast_pthread_create(&tmp->gsm.master, NULL, gsm_dchannel, &tmp->gsm)) { ++ zt_close(tmp->gsm.fd); ++ } ++ } ++#endif + #ifdef ZAPATA_R2 + if (signalling == SIG_R2) { + if (r2prot < 0) { +@@ -7156,6 +7565,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 +7839,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 +7886,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 +8046,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); + } +@@ -7669,12 +8084,174 @@ + *cause = AST_CAUSE_BUSY; + } else if (groupmatched) { + *cause = AST_CAUSE_CONGESTION; ++ } else { ++ *cause = AST_CAUSE_CONGESTION; + } + } + + return tmp; + } + ++#ifdef ZAPATA_GSM ++static void handle_gsm_event(struct zt_gsm *gsm, gsm_event *e) ++{ ++ struct ast_channel *c = NULL; ++ int law = ZT_LAW_ALAW; ++ int res = 0; ++ ++ switch(e->e) { ++ case GSM_EVENT_DCHAN_UP: ++ if (option_verbose > 2) ++ ast_verbose(VERBOSE_PREFIX_3 "GSM Span %d registered to network!\n", gsm->span); ++ break; ++ case GSM_EVENT_DCHAN_DOWN: ++ if (option_verbose > 2) ++ ast_verbose(VERBOSE_PREFIX_3 "GSM Span %d unregistered from network!\n", gsm->span); ++ break; ++ case GSM_EVENT_RING: ++ ast_mutex_lock(&gsm->pvt->lock); ++ if (!ast_strlen_zero(e->ring.callingnum)) { ++ strncpy(gsm->pvt->cid_num, e->ring.callingnum, sizeof(gsm->pvt->cid_num) - 1); ++ } else { ++ strncpy(gsm->pvt->cid_name, withheldcid, sizeof(gsm->pvt->cid_name)); ++ } ++ if (!ast_strlen_zero(gsm->exten)) { ++ strncpy(gsm->pvt->exten, gsm->exten, sizeof(gsm->pvt->exten) - 1); ++ } else { ++ gsm->pvt->exten[0] = 's'; ++ gsm->pvt->exten[1] = '\0'; ++ } ++ c = zt_new(gsm->pvt, AST_STATE_RING, 1, SUB_REAL, ZT_LAW_ALAW, AST_TRANS_CAP_SPEECH); ++ if (c) { ++ if (option_verbose > 2) ++ ast_verbose(VERBOSE_PREFIX_3 "Ring on channel %d (from %s to %s)\n", e->ring.channel, e->ring.callingnum, gsm->exten); ++ gsm->pvt->owner = c; ++ if (ioctl(gsm->pvt->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &law) == -1) ++ ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d\n", gsm->pvt->channel, law); ++ res = zt_setlaw(gsm->pvt->subs[SUB_REAL].zfd, law); ++ res = set_actual_gain(gsm->pvt->subs[SUB_REAL].zfd, 0, gsm->pvt->rxgain, gsm->pvt->txgain, law); ++ if (res < 0) { ++ ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", gsm->pvt->channel); ++// } else { ++// ast_log(LOG_NOTICE, "tx gain %f rx gain %f law %d pvt->law %d\n", gsm->pvt->txgain, gsm->pvt->rxgain, law, gsm->pvt->law); ++ } ++ } ++ ast_mutex_unlock(&gsm->pvt->lock); ++ break; ++ case GSM_EVENT_HANGUP: ++ ast_verbose(VERBOSE_PREFIX_3 "Got hang up on channel %d\n", e->hangup.channel); ++ ast_mutex_lock(&gsm->pvt->lock); ++ gsm->pvt->alreadyhungup = 1; ++ if (gsm->pvt->owner) { ++ gsm->pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV; ++ } ++ ast_mutex_unlock(&gsm->pvt->lock); ++ break; ++ case GSM_EVENT_ALERTING: ++ ast_mutex_lock(&gsm->pvt->lock); ++ gsm->pvt->subs[SUB_REAL].needringing =1; ++ ast_mutex_unlock(&gsm->pvt->lock); ++ break; ++ case GSM_EVENT_ANSWER: ++ ast_mutex_lock(&gsm->pvt->lock); ++ gsm->pvt->dialing = 0; ++ gsm->pvt->subs[SUB_REAL].needanswer =1; ++ gsm->pvt->ignoredtmf = 0; ++ ast_mutex_unlock(&gsm->pvt->lock); ++ break; ++ case GSM_EVENT_PIN_REQUIRED: ++ gsm_send_pin(gsm->modul, gsm->pin); ++ break; ++ case GSM_EVENT_SM_RECEIVED: ++ ast_verbose(VERBOSE_PREFIX_3 "SMS received on span %d. PDU: %s\n", gsm->span, e->sm_received.pdu); ++ break; ++ default: ++ ast_log(LOG_WARNING,"!! Unknown GSM event %d !!\n", e->e); ++ } ++} ++ ++static void *gsm_dchannel(void *vgsm) ++{ ++ struct zt_gsm *gsm = vgsm; ++ gsm_event *e; ++ struct timeval tv = {0,0}, *next; ++ fd_set rfds, efds; ++ int res,x; ++ ++ if (!gsm) return NULL; ++ ++ if (!gsm->modul) { ++ fprintf(stderr, "No gsm_mod\n"); ++ return NULL; ++ } ++ gsm_set_debug(gsm->modul, GSM_DEBUG_NONE); ++ for (;;) { ++ ++ /* Run the D-Channel */ ++ FD_ZERO(&rfds); ++ FD_ZERO(&efds); ++ FD_SET(gsm->fd, &rfds); ++ FD_SET(gsm->fd, &efds); ++ ++ if ((next = gsm_schedule_next(gsm->modul))) { ++ gettimeofday(&tv, NULL); ++ tv.tv_sec = next->tv_sec - tv.tv_sec; ++ tv.tv_usec = next->tv_usec - tv.tv_usec; ++ if (tv.tv_usec < 0) { ++ tv.tv_usec += 1000000; ++ tv.tv_sec -= 1; ++ } ++ if (tv.tv_sec < 0) { ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ } ++ } ++ res = select(gsm->fd + 1, &rfds, NULL, &efds, next ? &tv : NULL); ++ e = NULL; ++ ++ ast_mutex_lock(&gsm->lock); ++ if (!res) { ++ e = gsm_schedule_run(gsm->modul); ++ } else if (res > 0) { ++ e = gsm_check_event(gsm->modul, 1); ++ } else if (errno == ELAST) { ++ res = ioctl(gsm->fd, ZT_GETEVENT, &x); ++ printf("Got Zaptel event: %d\n", x); ++ } else if (errno != EINTR) ++ fprintf(stderr, "Error (%d) on select: %s\n", ELAST, strerror(errno)); ++ ++ if (!e) { ++ e = gsm_check_event(gsm->modul, 0); ++ } ++ ++ if (e) { ++ handle_gsm_event(gsm, e); ++ } ++ ast_mutex_unlock(&gsm->lock); ++ ++ res = ioctl(gsm->fd, ZT_GETEVENT, &x); ++ ++ if (!res && x) { ++ switch (x) { ++ case ZT_EVENT_NOALARM: ++ ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", gsm->span); ++ usleep(1000); ++ gsm_restart(gsm->modul); ++ break; ++ case ZT_EVENT_ALARM: ++ ast_log(LOG_NOTICE, "Alarm detected on span %d\n", gsm->span); ++ break; ++ default: ++ fprintf(stderr, "Got event on GSM interface: %d\n", x); ++ } ++ } ++ ++ ++ } ++ return NULL; ++} ++ ++#endif + + #ifdef ZAPATA_PRI + static struct zt_pvt *pri_find_crv(struct zt_pri *pri, int crv) +@@ -7689,6 +8266,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 +8349,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 +8365,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 +8379,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 +8457,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; + } + +@@ -7848,86 +8518,33 @@ + #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); ++ ast_log(LOG_WARNING, "%d %s", span, s); ++} + +- if (pridebugfd >= 0) +- write(pridebugfd, s, strlen(s)); ++#ifdef ZAPATA_GSM ++static void zt_gsm_message(char *s, int channel) ++{ ++ ast_verbose("GSM %d: %s", channel, s); ++} + +- ast_mutex_unlock(&pridebugfdlock); ++static void zt_gsm_error(char *s, int channel) ++{ ++ ast_log(LOG_WARNING, "GSM %d: %s", channel, s); + } ++#endif + + 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) && +@@ -8010,6 +8627,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; +@@ -8190,15 +8833,44 @@ + /* Check for an event */ + x = 0; + res = ioctl(pri->fds[which], ZT_GETEVENT, &x); +- if (x) ++ if ((pri->nodetype != BRI_CPE) && (pri->nodetype != BRI_CPE_PTMP)) { ++ /* dont annoy BRI TE mode users with layer2layer alarms */ ++ if (x) + ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span); ++ } + /* Keep track of alarm state */ + 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) { ++ 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) +@@ -8210,8 +8882,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); +@@ -8219,32 +8890,102 @@ + 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); ++ p->call = NULL; ++ } ++ } 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++) { +@@ -8252,19 +8993,29 @@ + if (p) { + 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->call = NULL; ++ if (p->owner) { ++ if (p->owner->_state != AST_STATE_UP) { ++ // pri_hangup(p->pri->pri, p->call, -1); ++ pri_destroycall(p->pri->pri, p->call); ++ p->call = NULL; ++ p->owner->_softhangup |= AST_SOFTHANGUP_DEV; ++ p->inalarm = 1; ++ } ++ } else { ++ pri_destroycall(p->pri->pri, p->call); ++ p->call = NULL; ++ p->inalarm = 1; ++ } + } else + ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n"); + } + if (p->realcall) { +- pri_hangup_all(p->realcall, pri); +- } else if (p->owner) +- p->owner->_softhangup |= AST_SOFTHANGUP_DEV; +- p->inalarm = 1; ++ pri_hangup_all(p->realcall, pri); ++ p->inalarm = 1; ++ } + } + } ++ } + } + break; + case PRI_EVENT_RESTART: +@@ -8299,8 +9050,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); +@@ -8334,7 +9085,6 @@ + } + } + break; +- + case PRI_EVENT_INFO_RECEIVED: + chanpos = pri_find_principle(pri, e->ring.channel); + if (chanpos < 0) { +@@ -8343,9 +9093,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; +@@ -8357,6 +9109,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); + } +@@ -8364,39 +9124,58 @@ + 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, -1); ++ 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; ++ 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; ++ /* XXX destroy the call here, so we can accept the retransmission as a new call */ ++ pri_destroycall(pri->pri, e->ring.call); + } +- } +- if (chanpos > -1) + 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)); +@@ -8410,13 +9189,14 @@ + ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span); + } else + ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span); +- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE); ++ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE, -1); + if (crv) + ast_mutex_unlock(&crv->lock); + ast_mutex_unlock(&pri->pvts[chanpos]->lock); + 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) { +@@ -8441,29 +9221,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)) { +@@ -8482,23 +9311,39 @@ + 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->pvts[chanpos]->proceeding = 1; + 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); +@@ -8506,14 +9351,31 @@ + /* Set bearer and such */ + pri_assign_bearer(crv, pri, pri->pvts[chanpos]); + c = zt_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype); ++ if (c && (e->ring.lowlayercompat[0] > 0)) { ++ memcpy(c->lowlayercompat, e->ring.lowlayercompat, sizeof(c->lowlayercompat)); ++ } + pri->pvts[chanpos]->owner = &inuse; + 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); ++ if (c && (e->ring.lowlayercompat[0] > 0)) { ++ memcpy(c->lowlayercompat, e->ring.lowlayercompat, sizeof(c->lowlayercompat)); ++ } ++ 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", tmpstr); ++ } + if(e->ring.ani2 >= 0) { + snprintf(ani2str, 5, "%.2d", e->ring.ani2); + pbx_builtin_setvar_helper(c, "ANI2", ani2str); +@@ -8533,8 +9395,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", +@@ -8542,14 +9404,18 @@ + if (c) + ast_hangup(c); + else { +- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION); ++ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION, -1); + pri->pvts[chanpos]->call = NULL; + } + } + } 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); ++ if (c && (e->ring.lowlayercompat[0] > 0)) { ++ memcpy(c->lowlayercompat, e->ring.lowlayercompat, sizeof(c->lowlayercompat)); ++ } + ast_mutex_lock(&pri->lock); + if (c) { + char calledtonstr[10]; +@@ -8570,23 +9436,40 @@ + 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); +- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION); ++ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION, -1); + pri->pvts[chanpos]->call = NULL; + } + } + } 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, + pri->pvts[chanpos]->prioffset, pri->span); +- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED); ++ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED, -1); + pri->pvts[chanpos]->call = NULL; + pri->pvts[chanpos]->exten[0] = '\0'; + } +@@ -8594,7 +9477,7 @@ + ast_mutex_unlock(&crv->lock); + ast_mutex_unlock(&pri->pvts[chanpos]->lock); + } else +- pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL); ++ pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL, -1); + break; + case PRI_EVENT_RINGING: + chanpos = pri_find_principle(pri, e->ringing.channel); +@@ -8612,7 +9495,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 +@@ -8641,9 +9524,16 @@ + } + 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->hangupcause = AST_CAUSE_USER_BUSY; ++ 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 +@@ -8690,6 +9580,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, }; + +@@ -8740,6 +9636,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) { +@@ -8755,6 +9940,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. +@@ -8784,11 +9970,16 @@ + 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); ++ enable_dtmf_detect(pri->pvts[chanpos]); + } 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 +@@ -8837,23 +10028,32 @@ + } + } + 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_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause, -1); + 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 (e->hangup.aoc_units > -1) { ++ if (pri->pvts[chanpos]->owner) { ++ char tmpstr[256]; ++ snprintf(tmpstr, sizeof(tmpstr), "%d", (int)e->hangup.aoc_units); ++ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "AOCEUNITS", tmpstr); ++ } + 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"); ++ } + + #ifdef SUPPORT_USERUSER + if (!ast_strlen_zero(e->hangup.useruserinfo)) { +@@ -8863,8 +10063,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, -1); ++ 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; +@@ -8874,17 +10086,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, -1); ++ } 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: +@@ -8903,20 +10123,87 @@ + } + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup request\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); +- if (e->hangup.aoc_units > -1) +- 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 (e->hangup.aoc_units > -1) { ++ if (pri->pvts[chanpos]->owner) { ++ char tmpstr[256]; ++ snprintf(tmpstr, sizeof(tmpstr), "%d", (int)e->hangup.aoc_units); ++ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "AOCEUNITS", tmpstr); ++ } ++ 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, -1); ++ onhold = NULL; ++ } ++ ast_mutex_unlock(&pri->pvts[chanpos]->lock); ++ break; ++ } else { ++ pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause, -1); ++ pri->pvts[chanpos]->call = NULL; ++ pri->pvts[chanpos]->tei = -1; ++ } ++ } ++ } + } else { +- pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause); ++ pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause, -1); + 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 +@@ -8927,9 +10214,37 @@ + + 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, -1); ++ 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)) { ++ if (e->hangup.aoc_units > -1) { ++ char tmpstr[256]; ++ snprintf(tmpstr, sizeof(tmpstr), "%d", (int)e->hangup.aoc_units); ++ pbx_builtin_setvar_helper(pri->pvts[chanpos]->owner, "AOCEUNITS", tmpstr); ++ 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"); ++ } ++ pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause; ++ ast_channel_setwhentohangup(pri->pvts[chanpos]->owner, 5); ++ } + break; + case PRI_EVENT_HANGUP_ACK: + chanpos = pri_find_principle(pri, e->hangup.channel); +@@ -8943,6 +10258,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) +@@ -8956,7 +10272,9 @@ + #endif + + ast_mutex_unlock(&pri->pvts[chanpos]->lock); ++ } + } ++ } + } + break; + case PRI_EVENT_CONFIG_ERR: +@@ -9048,10 +10366,22 @@ + ast_mutex_lock(&pri->pvts[chanpos]->lock); + switch(e->notify.info) { + case PRI_NOTIFY_REMOTE_HOLD: ++ if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) { ++ ast_log(LOG_DEBUG, "Received REMOTE_HOLD notification on NETWORK channel. Starting MoH\n"); ++ ast_moh_start(ast_bridged_channel(pri->pvts[chanpos]->owner), NULL); ++ } else { ++ ast_log(LOG_DEBUG, "Received REMOTE_HOLD notification on CPE channel. Not Starting MoH\n"); ++ } + f.subclass = AST_CONTROL_HOLD; + zap_queue_frame(pri->pvts[chanpos], &f, pri); + break; + case PRI_NOTIFY_REMOTE_RETRIEVAL: ++ if ((pri->nodetype == BRI_NETWORK_PTMP) || (pri->nodetype == BRI_NETWORK)) { ++ ast_log(LOG_DEBUG, "Received REMOTE_RETRIEVAL notification on NETWORK channel. Stopping MoH\n"); ++ ast_moh_stop(ast_bridged_channel(pri->pvts[chanpos]->owner)); ++ } else { ++ ast_log(LOG_DEBUG, "Received REMOTE_RETRIEVAL notification on CPE channel.\n"); ++ } + f.subclass = AST_CONTROL_UNHOLD; + zap_queue_frame(pri->pvts[chanpos], &f, pri); + break; +@@ -9059,6 +10389,77 @@ + 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, -1); ++ 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, -1); ++ 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, -1); ++ } else if (e->facility.operation == 0x0D) { ++ ast_log(LOG_NOTICE, "call deflection to %s requested.\n", e->facility.forwardnum); ++ ast_mutex_lock(&pri->pvts[chanpos]->lock); ++ /* transfer */ ++ if (pri->pvts[chanpos]->owner) { ++ snprintf(pri->pvts[chanpos]->owner->call_forward, sizeof(pri->pvts[chanpos]->owner->call_forward), "Local/%s@%s", e->facility.forwardnum, pri->pvts[chanpos]->owner->context); ++ } ++ ast_mutex_unlock(&pri->pvts[chanpos]->lock); ++ } 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); + } +@@ -9120,7 +10521,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; +@@ -9189,39 +10590,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; +@@ -9253,6 +10692,7 @@ + + + ++ + static int handle_pri_no_debug(int fd, int argc, char *argv[]) + { + int span; +@@ -9359,36 +10799,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"; +@@ -9405,6 +10815,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 }, +@@ -9412,19 +10834,282 @@ + "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 char *zapCD_tdesc = "Call Deflection"; ++static char *zapCD_app = "zapCD"; ++static char *zapCD_synopsis = "Call Deflection"; ++ ++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 *zapInband_tdesc = "Inband Call Progress (pre-answer)"; ++static char *zapInband_app = "zapInband"; ++static char *zapInband_synopsis = "Inband Call Progress"; ++ ++static int app_zapInband(struct ast_channel *chan, void *data) ++{ ++ struct zt_pvt *p = chan->tech_pvt; ++ ++ return pri_acknowledge(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 1); ++} + #endif /* ZAPATA_PRI */ + + ++#ifdef ZAPATA_GSM ++static int handle_gsm_debug_helper(int fd, int channel, int debug) ++{ ++/* gsm debug channel */ ++ struct zt_pvt *pvt = NULL; ++ if (channel < 1) { ++ ast_cli(fd, "Invalid channel %d. Should be a number.\n", channel); ++ return RESULT_SUCCESS; ++ } ++ pvt = iflist; ++ while (pvt) { ++ if (pvt->channel == channel) { ++ ast_mutex_lock(&pvt->lock); ++ gsm_set_debug(pvt->gsm.modul, debug); ++ ast_mutex_unlock(&pvt->lock); ++ ast_cli(fd, "%s debugging on channel %d\n", debug ? "Enabled":"Disabled", channel); ++ return RESULT_SUCCESS; ++ } ++ pvt = pvt->next; ++ } ++ ++ ast_cli(fd, "No GSM running on channel %d\n", channel); ++ return RESULT_SUCCESS; ++} ++ ++ ++ ++static int handle_gsm_debug(int fd, int argc, char *argv[]) ++{ ++/* gsm debug channel */ ++ int channel; ++ if (argc < 4) { ++ return RESULT_SHOWUSAGE; ++ } ++ channel = atoi(argv[3]); ++ return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_AT); ++} ++ ++static int handle_gsm_no_debug(int fd, int argc, char *argv[]) ++{ ++/* gsm no debug channel */ ++ int channel; ++ if (argc < 5) { ++ return RESULT_SHOWUSAGE; ++ } ++ channel = atoi(argv[4]); ++ return handle_gsm_debug_helper(fd, channel, GSM_DEBUG_NONE); ++} ++ ++static char gsm_debug_help[] = ++ "Usage: gsm debug channel \n" ++ " Enables debugging on a given GSM channel\n"; ++ ++static char gsm_no_debug_help[] = ++ "Usage: gsm no debug channel \n" ++ " Disables debugging on a given GSM channel\n"; ++ ++static struct ast_cli_entry zap_gsm_cli[] = { ++ { { "gsm", "debug", "channel", NULL }, handle_gsm_debug, ++ "Enables GSM debugging on a channel", gsm_debug_help }, ++ { { "gsm", "no", "debug", "channel", NULL }, handle_gsm_no_debug, ++ "Disables GSM debugging on a channel", gsm_no_debug_help}, ++}; ++ ++ ++ ++static char gsm_send_pdu_help[] = ++ "Usage: gsm send pdu \n" ++ " Sends a PDU on a GSM channel\n"; ++ ++ ++static int handle_gsm_send_pdu(int fd, int argc, char *argv[]) ++{ ++/* gsm send sms */ ++ int channel; ++ int len; ++ struct zt_pvt *pvt = NULL; ++ if (argc < 6) { ++ return RESULT_SHOWUSAGE; ++ } ++ channel = atoi(argv[3]); ++ if (channel < 1) { ++ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]); ++ return RESULT_SUCCESS; ++ } ++ len = atoi(argv[4]); ++ if (len < 1) { ++ ast_cli(fd, "Invalid length %s. Should be a number.\n", argv[4]); ++ return RESULT_SUCCESS; ++ } ++ pvt = iflist; ++ while (pvt) { ++ if (pvt->channel == channel) { ++ if (pvt->owner) { ++ ast_cli(fd, "Channel in use.\n"); ++ return RESULT_FAILURE; ++ } else { ++ ast_mutex_lock(&pvt->lock); ++ gsm_sms_send_pdu(pvt->gsm.modul, argv[5], len); ++ ast_mutex_unlock(&pvt->lock); ++ return RESULT_SUCCESS; ++ } ++ } ++ pvt = pvt->next; ++ } ++ ++ return RESULT_SUCCESS; ++} ++ ++static struct ast_cli_entry gsm_send_pdu = { ++ { "gsm", "send", "pdu", NULL }, handle_gsm_send_pdu, "Sends a SM on a GSM channel", gsm_send_pdu_help, complete_span_4 }; ++ ++ ++static char gsm_send_sms_help[] = ++ "Usage: gsm send sms \n" ++ " Sends a SM on a GSM channel\n"; ++ ++ ++static int handle_gsm_send_sms(int fd, int argc, char *argv[]) ++{ ++/* gsm send sms */ ++ int channel; ++ struct zt_pvt *pvt = NULL; ++ if (argc < 6) { ++ return RESULT_SHOWUSAGE; ++ } ++ channel = atoi(argv[3]); ++ if (channel < 1) { ++ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]); ++ return RESULT_SUCCESS; ++ } ++ pvt = iflist; ++ while (pvt) { ++ if (pvt->channel == channel) { ++ if (pvt->owner) { ++ ast_cli(fd, "Channel in use.\n"); ++ return RESULT_FAILURE; ++ } else { ++ ast_mutex_lock(&pvt->lock); ++ gsm_sms_send_text(pvt->gsm.modul, argv[4], argv[5]); ++ ast_mutex_unlock(&pvt->lock); ++ return RESULT_SUCCESS; ++ } ++ } ++ pvt = pvt->next; ++ } ++ ++ return RESULT_SUCCESS; ++} ++ ++static struct ast_cli_entry gsm_send_sms = { ++ { "gsm", "send", "sms", NULL }, handle_gsm_send_sms, "Sends a SM on a GSM channel", gsm_send_sms_help, complete_span_4 }; ++ ++static char gsm_show_status_help[] = ++ "Usage: gsm show status >\n" ++ " Displays status information about the GSM channel.\n"; ++ ++ ++static int handle_gsm_show_status(int fd, int argc, char *argv[]) ++{ ++ int channel; ++ struct zt_pvt *pvt = NULL; ++ if (argc < 4) { ++ return RESULT_SHOWUSAGE; ++ } ++ channel = atoi(argv[3]); ++ if (channel < 1) { ++ ast_cli(fd, "Invalid channel %s. Should be a number.\n", argv[3]); ++ return RESULT_SUCCESS; ++ } ++ pvt = iflist; ++ while (pvt) { ++ if (pvt->channel == channel) { ++ if (pvt->owner) { ++ ast_cli(fd, "Channel in use.\n"); ++ return RESULT_FAILURE; ++ } else { ++ ast_mutex_lock(&pvt->lock); ++ gsm_request_status(pvt->gsm.modul); ++ ast_mutex_unlock(&pvt->lock); ++ return RESULT_SUCCESS; ++ } ++ } ++ pvt = pvt->next; ++ } ++ ++ return RESULT_SUCCESS; ++} ++ ++static struct ast_cli_entry gsm_show_status = { ++ { "gsm", "show", "status", NULL }, handle_gsm_show_status, "Displays status information about the GSM channel.", gsm_show_status_help, complete_span_4 }; ++ ++#endif /* ZAPATA_GSM */ ++ ++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[]) + { +@@ -10036,6 +11721,14 @@ + pthread_cancel(pris[i].master); + } + ast_cli_unregister_multiple(zap_pri_cli, sizeof(zap_pri_cli) / sizeof(zap_pri_cli[0])); ++ ast_unregister_application(zapCD_app); ++ ast_unregister_application(zapInband_app); ++#endif ++#ifdef ZAPATA_GSM ++ ast_cli_unregister_multiple(zap_gsm_cli, sizeof(zap_gsm_cli) / sizeof(zap_gsm_cli[0])); ++ ast_cli_unregister(&gsm_send_sms); ++ ast_cli_unregister(&gsm_send_pdu); ++ ast_cli_unregister(&gsm_show_status); + #endif + #ifdef ZAPATA_R2 + ast_cli_unregister_multiple(zap_r2_cli, sizeof(zap_r2_cli) / sizeof(zap_r2_cli[0])); +@@ -10047,6 +11740,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 */ +@@ -10405,8 +12099,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; + } +@@ -10592,12 +12286,33 @@ + 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")) { + cur_signalling = SIG_R2; + cur_radio = 0; + #endif ++#ifdef ZAPATA_GSM ++ } else if (!strcasecmp(v->value, "gsm")) { ++ cur_signalling = SIG_GSM; ++ cur_radio = 0; ++#endif + } else { + ast_log(LOG_ERROR, "Unknown signalling method '%s'\n", v->value); + } +@@ -10680,8 +12395,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); +@@ -10695,6 +12422,14 @@ + 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, "pin")) { ++ ast_copy_string(gsm_modem_pin, v->value, sizeof(gsm_modem_pin) - 1); ++ } else if (!strcasecmp(v->name, "exten")) { ++ ast_copy_string(gsm_modem_exten, v->value, sizeof(gsm_modem_exten) - 1); + } else if (!strcasecmp(v->name, "resetinterval")) { + if (!strcasecmp(v->value, "never")) + resetinterval = -1; +@@ -10711,6 +12446,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")) { +@@ -10896,6 +12633,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 +@@ -10976,6 +12760,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 -urNad asterisk-1.2.12.1.dfsg~/codecs/codec_ilbc.c asterisk-1.2.12.1.dfsg/codecs/codec_ilbc.c +--- asterisk-1.2.12.1.dfsg~/codecs/codec_ilbc.c 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/codecs/codec_ilbc.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/configs/capi.conf.sample asterisk-1.2.12.1.dfsg/configs/capi.conf.sample +--- asterisk-1.2.12.1.dfsg~/configs/capi.conf.sample 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/configs/capi.conf.sample 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/configs/modules.conf.sample asterisk-1.2.12.1.dfsg/configs/modules.conf.sample +--- asterisk-1.2.12.1.dfsg~/configs/modules.conf.sample 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/configs/modules.conf.sample 2006-09-23 18:07:45.000000000 +0100 +@@ -51,3 +51,4 @@ + ; exported to modules loaded after them. + ; + [global] ++chan_capi.so=yes +diff -urNad asterisk-1.2.12.1.dfsg~/configs/watchdog.conf.sample asterisk-1.2.12.1.dfsg/configs/watchdog.conf.sample +--- asterisk-1.2.12.1.dfsg~/configs/watchdog.conf.sample 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/configs/watchdog.conf.sample 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/configs/zapata.conf.sample asterisk-1.2.12.1.dfsg/configs/zapata.conf.sample +--- asterisk-1.2.12.1.dfsg~/configs/zapata.conf.sample 2006-09-11 17:39:06.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/configs/zapata.conf.sample 2006-09-23 18:07:45.000000000 +0100 +@@ -123,9 +123,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 -urNad asterisk-1.2.12.1.dfsg~/db.c asterisk-1.2.12.1.dfsg/db.c +--- asterisk-1.2.12.1.dfsg~/db.c 2006-01-09 18:09:53.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/db.c 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/devicestate.c asterisk-1.2.12.1.dfsg/devicestate.c +--- asterisk-1.2.12.1.dfsg~/devicestate.c 2006-02-10 20:38:59.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/devicestate.c 2006-09-23 18:07:45.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,11 +232,17 @@ + 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 */ +@@ -240,7 +254,7 @@ + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); +- return __ast_device_state_changed_literal(buf); ++ return __ast_device_state_changed_literal(buf, NULL, NULL); + } + + /*--- do_devstate_changes: Go through the dev state change queue and update changes in the dev state thread */ +@@ -255,7 +269,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 -urNad asterisk-1.2.12.1.dfsg~/doc/README.asterisk.conf asterisk-1.2.12.1.dfsg/doc/README.asterisk.conf +--- asterisk-1.2.12.1.dfsg~/doc/README.asterisk.conf 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/doc/README.asterisk.conf 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/editline/cygdef.h asterisk-1.2.12.1.dfsg/editline/cygdef.h +--- asterisk-1.2.12.1.dfsg~/editline/cygdef.h 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/editline/cygdef.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/agi.h asterisk-1.2.12.1.dfsg/include/asterisk/agi.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/agi.h 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/agi.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/chan_capi.h asterisk-1.2.12.1.dfsg/include/asterisk/chan_capi.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/chan_capi.h 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/chan_capi.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/chan_capi_app.h asterisk-1.2.12.1.dfsg/include/asterisk/chan_capi_app.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/chan_capi_app.h 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/chan_capi_app.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/channel.h asterisk-1.2.12.1.dfsg/include/asterisk/channel.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/channel.h 2006-06-01 21:27:50.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/channel.h 2006-09-23 18:07:45.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 +@@ -381,7 +384,7 @@ + unsigned int fout; + + /* Unique Channel Identifier */ +- char uniqueid[32]; ++ char uniqueid[AST_MAX_UNIQUEID]; + + /* Why is the channel hanged up */ + int hangupcause; +@@ -398,6 +401,12 @@ + /*! ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */ + unsigned short transfercapability; + ++ /*! ISDN Low Layer Compatibility */ ++ char lowlayercompat[16]; ++ ++ /*! ISDN High Layer Compatibility */ ++ char highlayercompat[4]; ++ + struct ast_frame *readq; + int alertpipe[2]; + /*! Write translation path */ +@@ -534,6 +543,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); + +@@ -570,7 +584,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 +@@ -585,9 +599,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. +@@ -840,6 +854,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 +@@ -910,6 +928,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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/devicestate.h asterisk-1.2.12.1.dfsg/include/asterisk/devicestate.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/devicestate.h 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/devicestate.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/features.h asterisk-1.2.12.1.dfsg/include/asterisk/features.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/features.h 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/features.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/manager.h asterisk-1.2.12.1.dfsg/include/asterisk/manager.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/manager.h 2006-02-11 18:15:00.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/manager.h 2006-09-23 18:07:45.000000000 +0100 +@@ -54,6 +54,7 @@ + #define EVENT_FLAG_COMMAND (1 << 4) /* Ability to read/set commands */ + #define EVENT_FLAG_AGENT (1 << 5) /* Ability to read/set agent info */ + #define EVENT_FLAG_USER (1 << 6) /* Ability to read/set user info */ ++#define EVENT_FLAG_EXTENSIONSTATUS (1 << 7) /* ExtensionStatus events */ + + /* Export manager structures */ + #define AST_MAX_MANHEADERS 80 +diff -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/monitor.h asterisk-1.2.12.1.dfsg/include/asterisk/monitor.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/monitor.h 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/monitor.h 2006-09-23 18:07:45.000000000 +0100 +@@ -35,6 +35,8 @@ + char write_filename[FILENAME_MAX]; + char filename_base[FILENAME_MAX]; + int filename_changed; ++ char target_url[FILENAME_MAX]; ++ char target_script[FILENAME_MAX]; + char *format; + int joinfiles; + int (*stop)(struct ast_channel *chan, int need_lock); +@@ -42,7 +44,7 @@ + + /* Start monitoring a channel */ + int ast_monitor_start(struct ast_channel *chan, const char *format_spec, +- const char *fname_base, int need_lock ); ++ const char *fname_base, const char *target_url, const char *target_script, int need_lock ); + + /* Stop monitoring a channel */ + int ast_monitor_stop(struct ast_channel *chan, int need_lock); +diff -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/pbx.h asterisk-1.2.12.1.dfsg/include/asterisk/pbx.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/pbx.h 2006-03-29 20:11:18.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/pbx.h 2006-09-23 18:07:45.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, const char *account, 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, const char *account, 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, const char *account, 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, const char *account, struct ast_channel **locked_channel, char *uniqueid); + + /* Evaluate a condition for non-falseness and return a boolean */ + int pbx_checkcondition(char *condition); +@@ -659,7 +661,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, char *cid_num, char *cid_name); + + #if defined(__cplusplus) || defined(c_plusplus) + } +diff -urNad asterisk-1.2.12.1.dfsg~/include/asterisk/xlaw.h asterisk-1.2.12.1.dfsg/include/asterisk/xlaw.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk/xlaw.h 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/include/asterisk/xlaw.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/include/asterisk.h asterisk-1.2.12.1.dfsg/include/asterisk.h +--- asterisk-1.2.12.1.dfsg~/include/asterisk.h 2005-11-30 03:37:37.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/include/asterisk.h 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/manager.c asterisk-1.2.12.1.dfsg/manager.c +--- asterisk-1.2.12.1.dfsg~/manager.c 2006-02-11 18:15:00.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/manager.c 2006-09-23 18:07:45.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[AST_MAX_MANHEADER_LEN]; +@@ -76,6 +80,8 @@ + char idtext[AST_MAX_MANHEADER_LEN]; + char account[AST_MAX_ACCOUNT_CODE]; + int priority; ++ int callingpres; ++ char uniqueid[64]; + struct ast_variable *vars; + }; + +@@ -99,6 +105,7 @@ + { EVENT_FLAG_COMMAND, "command" }, + { EVENT_FLAG_AGENT, "agent" }, + { EVENT_FLAG_USER, "user" }, ++ { EVENT_FLAG_EXTENSIONSTATUS, "extensionstatus" }, + { -1, "all" }, + { 0, "none" }, + }; +@@ -657,11 +664,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; +@@ -760,6 +773,7 @@ + } + + ++ + /*! \brief action_status: Manager "status" command to show channels */ + /* Needs documentation... */ + static int action_status(struct mansession *s, struct message *m) +@@ -866,32 +880,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(priority2, "%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) +@@ -937,15 +969,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, in->account, &chan); ++ in->vars, in->account, &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, in->account, &chan); ++ in->vars, in->account, &chan, in->uniqueid); + } + if (!res) + manager_event(EVENT_FLAG_CALL, +@@ -956,7 +988,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", +@@ -966,7 +998,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) +@@ -999,6 +1031,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"); +@@ -1007,12 +1040,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; +@@ -1028,6 +1064,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, '/'); +@@ -1048,6 +1088,7 @@ + if (ast_strlen_zero(l)) + l = NULL; + } ++ uniqueid = ast_alloc_uniqueid(); + if (ast_true(async)) { + struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper)); + if (!fast) { +@@ -1068,8 +1109,10 @@ + ast_copy_string(fast->context, context, sizeof(fast->context)); + ast_copy_string(fast->exten, exten, sizeof(fast->exten)); + ast_copy_string(fast->account, account, sizeof(fast->account)); ++ 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)) { +@@ -1079,19 +1122,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, account, NULL); ++ res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, cpresi, l, n, vars, account, 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, account, NULL); ++ res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, cpresi, l, n, vars, account, 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; + } + +@@ -1565,10 +1617,12 @@ + 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) + { ++ char hint[256] = ""; ++ ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten); + /* 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_EXTENSIONSTATUS, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\nCallerID: \"%s\" <%s>\r\nHint: %s\r\n", exten, context, state, cid_num, cid_name, hint); + return 0; + } + +diff -urNad asterisk-1.2.12.1.dfsg~/pbx/pbx_spool.c asterisk-1.2.12.1.dfsg/pbx/pbx_spool.c +--- asterisk-1.2.12.1.dfsg~/pbx/pbx_spool.c 2006-02-11 18:15:00.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/pbx/pbx_spool.c 2006-09-23 18:07:45.000000000 +0100 +@@ -259,11 +259,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, o->account, 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, o->account, 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, o->account, 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, o->account, NULL, NULL); + } + if (res) { + ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason); +diff -urNad asterisk-1.2.12.1.dfsg~/pbx.c asterisk-1.2.12.1.dfsg/pbx.c +--- asterisk-1.2.12.1.dfsg~/pbx.c 2006-08-24 20:41:26.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/pbx.c 2006-09-23 18:07:45.000000000 +0100 +@@ -353,7 +353,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, +@@ -1883,7 +1884,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, char *cid_num, char *cid_name) + { + struct ast_hint *hint; + struct ast_state_cb *cblist; +@@ -1911,11 +1912,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; +@@ -2156,7 +2157,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; +@@ -3777,7 +3778,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 { +@@ -4981,7 +4982,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, const char *account, 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, const char *account, struct ast_channel **channel, char *uniqueid) + { + struct ast_channel *chan; + struct async_stat *as; +@@ -4991,7 +4992,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) +@@ -5093,7 +5094,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) +@@ -5139,7 +5140,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; +@@ -5155,7 +5156,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, const char *account, 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, const char *account, struct ast_channel **locked_channel, char *uniqueid) + { + struct ast_channel *chan; + struct async_stat *as; +@@ -5175,7 +5176,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); +@@ -5262,7 +5263,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; +@@ -5551,6 +5553,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; +@@ -6205,6 +6210,9 @@ + return -1; + } + } ++ if (chan->_state != AST_STATE_UP) { ++ ast_answer(chan); ++ } + return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options); + } + +@@ -6212,8 +6220,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; + } + +@@ -6221,8 +6233,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; + } + +@@ -6230,8 +6246,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 -urNad asterisk-1.2.12.1.dfsg~/res/Makefile asterisk-1.2.12.1.dfsg/res/Makefile +--- asterisk-1.2.12.1.dfsg~/res/Makefile 2005-11-29 18:24:39.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/res/Makefile 2006-09-23 18:07:45.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 -urNad asterisk-1.2.12.1.dfsg~/res/res_agi.c asterisk-1.2.12.1.dfsg/res/res_agi.c +--- asterisk-1.2.12.1.dfsg~/res/res_agi.c 2006-09-06 21:02:59.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/res/res_agi.c 2006-09-23 18:07:45.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" +@@ -92,6 +98,8 @@ + " hangup, or 0 on non-hangup exit. \n" + "Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n" + "on file descriptor 3\n\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; +@@ -225,13 +233,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; +@@ -276,6 +285,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)); +@@ -293,15 +329,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); + + /* Execute script */ +@@ -317,6 +357,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]); +@@ -325,6 +368,9 @@ + /* [PHM 12/18/03] */ + close(audio[0]); + } ++ if (efd2) { ++ close(audio2[1]); ++ } + + *opid = pid; + return 0; +@@ -355,7 +401,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 : ""); +@@ -387,7 +433,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; +@@ -563,7 +609,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; +@@ -623,7 +669,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; +@@ -635,7 +681,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; +@@ -662,7 +708,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); +@@ -682,7 +728,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); +@@ -699,7 +745,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); +@@ -789,7 +835,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); +@@ -816,7 +862,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) +@@ -1854,7 +1900,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) */ +@@ -1868,10 +1919,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 */ +@@ -1882,13 +1945,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 */ +@@ -1910,6 +1984,7 @@ + if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) { + break; + } ++ } + } else { + if (--retry <= 0) { + ast_log(LOG_WARNING, "No channel, no fd?\n"); +@@ -2016,6 +2091,7 @@ + int argc = 0; + int fds[2]; + int efd = -1; ++ int efd2 = -1; + int pid; + char *stringp; + AGI agi; +@@ -2041,16 +2117,19 @@ + } + } + #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); + if (fds[1] != fds[0]) + close(fds[1]); + if (efd > -1) + close(efd); ++ if (efd2 > -1) ++ close(efd2); + } + LOCAL_USER_REMOVE(u); + return res; +@@ -2084,6 +2163,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); +@@ -2113,6 +2221,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); +@@ -2126,6 +2235,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 -urNad asterisk-1.2.12.1.dfsg~/res/res_features.c asterisk-1.2.12.1.dfsg/res/res_features.c +--- asterisk-1.2.12.1.dfsg~/res/res_features.c 2006-08-02 00:07:06.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/res/res_features.c 2006-09-23 18:07:45.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 ? 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) +@@ -909,7 +976,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; + +@@ -919,10 +986,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) + { +@@ -1021,7 +1099,7 @@ + return res; + + while ((tok = strsep(&tmp, "#")) != NULL) { +- feature = find_feature(tok); ++ feature = ast_find_feature(tok); + + if (feature) { + /* Feature is up for consideration */ +@@ -1074,7 +1152,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); +@@ -1099,7 +1177,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)) { +@@ -1553,9 +1631,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) +@@ -1598,9 +1677,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*/ +@@ -1687,6 +1767,282 @@ + 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)) ++ ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); ++ else ++ ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); ++ 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; +@@ -1735,9 +2091,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); +@@ -1905,12 +2262,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; +@@ -1926,6 +2284,416 @@ + 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 autoanswer_reregister_extensions(void) ++{ ++ struct aauser *cur; ++ struct ast_context *con; ++ char exten[AST_MAX_EXTENSION]; ++ char args[AST_MAX_EXTENSION]; ++ ++ ast_mutex_lock(&autoanswer_lock); ++ ++ cur=aalot; ++ while(cur) { ++ con = ast_context_find(cur->context); ++ if (!con) { ++ con = ast_context_create(NULL,cur->context, registrar); ++ if (!con) { ++ ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context); ++ } ++ } ++ if (con) { ++ snprintf(exten, sizeof(exten), "%s", cur->exten); ++ snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten); ++ ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar); ++ } ++ cur = cur->next; ++ } ++ ++ ast_mutex_unlock(&autoanswer_lock); ++} ++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)) ++ ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); ++ else ++ ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); ++ 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) + { +@@ -2080,7 +2848,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) { +@@ -2142,6 +2910,7 @@ + } + + int reload(void) { ++ autoanswer_reregister_extensions(); + return load_config(); + } + +@@ -2155,14 +2924,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; + } + +@@ -2173,7 +2950,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 -urNad asterisk-1.2.12.1.dfsg~/res/res_monitor.c asterisk-1.2.12.1.dfsg/res/res_monitor.c +--- asterisk-1.2.12.1.dfsg~/res/res_monitor.c 2006-03-02 19:05:40.000000000 +0000 ++++ asterisk-1.2.12.1.dfsg/res/res_monitor.c 2006-09-23 18:07:45.000000000 +0100 +@@ -90,7 +90,7 @@ + + /* Start monitoring a channel */ + int ast_monitor_start( struct ast_channel *chan, const char *format_spec, +- const char *fname_base, int need_lock) ++ const char *fname_base, const char *target_url, const char *target_script, int need_lock) + { + int res = 0; + char tmp[256]; +@@ -122,6 +122,11 @@ + } + memset(monitor, 0, sizeof(struct ast_channel_monitor)); + ++ if (target_url) ++ ast_copy_string(monitor->target_url, target_url, sizeof(monitor->target_url)); ++ if (target_script) ++ ast_copy_string(monitor->target_script, target_script, sizeof(monitor->target_script)); ++ + /* Determine file names */ + if (!ast_strlen_zero(fname_base)) { + int directory = strchr(fname_base, '/') ? 1 : 0; +@@ -257,6 +262,8 @@ + if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) { + char tmp[1024]; + char tmp2[1024]; ++ char tmp3[1024]; ++ int result; + char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format; + char *name = chan->monitor->filename_base; + int directory = strchr(name, '/') ? 1 : 0; +@@ -278,9 +285,19 @@ + snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name); /* remove legs when done mixing */ + ast_copy_string(tmp, tmp2, sizeof(tmp)); + } +- ast_log(LOG_DEBUG,"monitor executing %s\n",tmp); +- if (ast_safe_system(tmp) == -1) ++ if (!ast_strlen_zero(chan->monitor->target_script) && !ast_strlen_zero(chan->monitor->target_url)) { ++ snprintf(tmp3,sizeof(tmp3), "( %s& nice -19 %s \"%s/%s.%s\" \"%s\" ) &",tmp, chan->monitor->target_script , dir, name, format, chan->monitor->target_url); ++ ast_copy_string(tmp, tmp3, sizeof(tmp)); ++ } ++ ast_log(LOG_NOTICE,"monitor executing %s\n",tmp); ++ result = ast_safe_system(tmp); ++ if (result == -1) + ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); ++ manager_event(EVENT_FLAG_CALL, "MonitorStopped", ++ "Channel: %s\r\n" ++ "Uniqueid: %s\r\n" ++ "Result: %d\r\n" ++ ,chan->name, chan->uniqueid, result); + } + + free(chan->monitor->format); +@@ -392,7 +409,7 @@ + return 0; + } + +- res = ast_monitor_start(chan, format, fname_base, 1); ++ res = ast_monitor_start(chan, format, fname_base, NULL, NULL, 1); + if (res < 0) + res = ast_monitor_change_fname(chan, fname_base, 1); + ast_monitor_setjoinfiles(chan, joinfiles); +@@ -428,19 +445,30 @@ + { + struct ast_channel *c = NULL; + char *name = astman_get_header(m, "Channel"); ++ char *uniqueid = astman_get_header(m, "Uniqueid"); + char *fname = astman_get_header(m, "File"); + char *format = astman_get_header(m, "Format"); + char *mix = astman_get_header(m, "Mix"); ++ char *target_url = astman_get_header(m, "TargetURL"); ++ char *target_script = astman_get_header(m, "TargetScript"); + char *d; + +- if (ast_strlen_zero(name)) { +- astman_send_error(s, m, "No channel specified"); ++ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) { ++ astman_send_error(s, m, "No channel/uniqueid specified"); + return 0; + } +- c = ast_get_channel_by_name_locked(name); +- if (!c) { ++ if (!ast_strlen_zero(uniqueid)) { ++ c = ast_get_channel_by_uniqueid_locked(uniqueid); ++ if (!c) { ++ astman_send_error(s, m, "No such uniqueid"); ++ return 0; ++ } ++ } else { ++ c = ast_get_channel_by_name_locked(name); ++ if (!c) { + astman_send_error(s, m, "No such channel"); + return 0; ++ } + } + + if (ast_strlen_zero(fname)) { +@@ -457,7 +485,7 @@ + if ((d=strchr(fname, '/'))) *d='-'; + } + +- if (ast_monitor_start(c, format, fname, 1)) { ++ if (ast_monitor_start(c, format, fname, target_url, target_script, 1)) { + if (ast_monitor_change_fname(c, fname, 1)) { + astman_send_error(s, m, "Could not start monitoring channel"); + ast_mutex_unlock(&c->lock); +@@ -483,16 +511,26 @@ + { + struct ast_channel *c = NULL; + char *name = astman_get_header(m, "Channel"); ++ char *uniqueid = astman_get_header(m, "Uniqueid"); + int res; +- if (ast_strlen_zero(name)) { +- astman_send_error(s, m, "No channel specified"); ++ if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) { ++ astman_send_error(s, m, "No channel/uniqueid specified"); + return 0; + } +- c = ast_get_channel_by_name_locked(name); +- if (!c) { ++ if (!ast_strlen_zero(uniqueid)) { ++ c = ast_get_channel_by_uniqueid_locked(uniqueid); ++ if (!c) { ++ astman_send_error(s, m, "No such uniqueid"); ++ return 0; ++ } ++ } else { ++ c = ast_get_channel_by_name_locked(name); ++ if (!c) { + astman_send_error(s, m, "No such channel"); + return 0; ++ } + } ++ + res = ast_monitor_stop(c, 1); + ast_mutex_unlock(&c->lock); + if (res) { +diff -urNad asterisk-1.2.12.1.dfsg~/res/res_watchdog.c asterisk-1.2.12.1.dfsg/res/res_watchdog.c +--- asterisk-1.2.12.1.dfsg~/res/res_watchdog.c 1970-01-01 01:00:00.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/res/res_watchdog.c 2006-09-23 18:07:45.000000000 +0100 +@@ -0,0 +1,149 @@ ++/* ++ * 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); ++ close(dogs->fd); ++ 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 -urNad asterisk-1.2.12.1.dfsg~/rtp.c asterisk-1.2.12.1.dfsg/rtp.c +--- asterisk-1.2.12.1.dfsg~/rtp.c 2006-09-01 18:35:06.000000000 +0100 ++++ asterisk-1.2.12.1.dfsg/rtp.c 2006-09-23 18:07:45.000000000 +0100 +@@ -445,6 +445,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, --- asterisk-1.2.12.1.dfsg.orig/debian/patches/18_debian-libedit.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/18_debian-libedit.dpatch @@ -0,0 +1,48 @@ +#! /bin/sh -e +## debian-libedit.dpatch by Mark Purcell +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Patch asterisk to use installed libedit + +if [ $# -lt 1 ]; then + echo "`basename $0`: script expects -patch|-unpatch as argument" >&2 + exit 1 +fi + +[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts +patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}" + +case "$1" in + -patch) patch -p1 ${patch_opts} < $0;; + -unpatch) patch -R -p1 ${patch_opts} < $0;; + *) + echo "`basename $0`: script expects -patch|-unpatch as argument" >&2 + exit 1;; +esac + +exit 0 + +@DPATCH@ + +--- asterisk-0.9.1+1.0RC2.orig/Makefile ++++ asterisk-0.9.1+1.0RC2/Makefile +@@ -256,7 +260,7 @@ + exit 1; \ + fi + +-asterisk: editline/libedit.a db1-ast/libdb1.a stdtime/libtime.a $(OBJS) ++asterisk: db1-ast/libdb1.a stdtime/libtime.a $(OBJS) + $(CC) $(DEBUG) -o asterisk $(ASTLINK) $(OBJS) $(LIBEDIT) db1-ast/libdb1.a stdtime/libtime.a $(LIBS) + + muted: muted.o +--- asterisk-0.9.1+1.0RC2.orig/cli.c ++++ asterisk-0.9.1+1.0RC2/cli.c +@@ -27,7 +27,7 @@ + #include + #include + /* For rl_filename_completion */ +-#include "editline/readline/readline.h" ++#include "readline/readline.h" + /* For module directory */ + #include "asterisk.h" + #include "build.h" --- asterisk-1.2.12.1.dfsg.orig/debian/patches/zap_restart.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/zap_restart.dpatch @@ -0,0 +1,80 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## zap_restart.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Adds a CLI command "zap restart" that destroys all zaptel channels and +## DP: re-loads zaptel configuration from scratch. +## DP: Thus we have a "reload" for zaptel +## -- applied upstream in trunk (1.4.x) + +@DPATCH@ +--- asterisk-1.2.6/channels/chan_zap.c 2006-04-09 02:40:48.000000000 +0300 ++++ asterisk-new/channels/chan_zap.c 2006-04-09 04:15:46.000000000 +0300 +@@ -9656,6 +9656,47 @@ + return RESULT_FAILURE; + } + ++static int setup_zap(int reload); ++static int zap_restart(void) ++{ ++ if (option_verbose > 0) ++ ast_verbose(VERBOSE_PREFIX_1 "Destroying channels and reloading zaptel configuration.\n"); ++ while (iflist) { ++ if (option_debug) ++ ast_log(LOG_DEBUG, "Destroying zaptel channel no. %d\n", iflist->channel); ++ /* Also updates iflist: */ ++ destroy_channel(NULL, iflist, 1); ++ } ++ if (option_debug) ++ ast_log(LOG_DEBUG, "Channels destroyed. Now re-reading config.\n"); ++ if (setup_zap(0) != 0) { ++ ast_log(LOG_WARNING, "Reload channels from zap config failed!\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++static int zap_restart_cmd(int fd, int argc, char **argv) ++{ ++ if (argc != 2) { ++ return RESULT_SHOWUSAGE; ++ } ++ ++ if (zap_restart() != 0) ++ return RESULT_FAILURE; ++ return RESULT_SUCCESS; ++} ++ ++static int action_zaprestart(struct mansession *s, struct message *m) ++{ ++ if (zap_restart() != 0) { ++ astman_send_error(s, m, "Failed rereading zaptel configuration"); ++ return 1; ++ } ++ astman_send_ack(s, m, "ZapRestart: Success"); ++ return 0; ++} ++ + static int zap_show_channels(int fd, int argc, char **argv) + { + #define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s\n" +@@ -9965,6 +10005,10 @@ + "Usage: zap destroy channel \n" + " DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not\n"; + ++static char zap_restart_usage[] = ++ "Usage: zap restart\n" ++ " fully restarts the zaptel channels: destroys them all and then re-reads from config.\n"; ++ + static struct ast_cli_entry zap_cli[] = { + { { "zap", "show", "cadences", NULL }, handle_zap_show_cadences, + "List cadences", zap_show_cadences_help }, +@@ -9974,6 +10018,8 @@ + "Show information on a channel", show_channel_usage }, + { {"zap", "destroy", "channel", NULL}, zap_destroy_channel, + "Destroy a channel", destroy_channel_usage }, ++ { {"zap", "restart", NULL}, zap_restart_cmd, ++ "Fully restart zaptel channels", zap_restart_usage }, + { {"zap", "show", "status", NULL}, zap_show_status, + "Show all Zaptel cards status", zap_show_status_usage }, + }; --- asterisk-1.2.12.1.dfsg.orig/debian/patches/00list +++ asterisk-1.2.12.1.dfsg/debian/patches/00list @@ -0,0 +1,21 @@ +patch.CVE-2006-2898.dpatch +# ukcid probably conflicts with bristuff +ukcid +option_detach +30_ast-data-dir.dpatch +40_initgroups.dpatch +50_debian-libgsm.dpatch +95_conf_sample.dpatch +98_fpm-sounds.dpatch +#sys_readline +func_odbc_12 +brazilian_syntax +vm_he +pubkey_jnctn +nomarch +chanzap_disable_r2.dpatch +correct_pid_display +zap_restart +backport_playdtmf +patch.CVE-2006-5444.dpatch +patch.1.2.16-security.dpatch --- asterisk-1.2.12.1.dfsg.orig/debian/patches/correct_pid_display.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/correct_pid_display.dpatch @@ -0,0 +1,24 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## correct_ps_display.dpatch by Kilian Krause +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Display the correct pid in the asterisk console. Closes: 338646 +## DP: Upstream bug: #7098 . Fixed in 1.4 and in 1.2 branch (remove on 1.2.8) +@DPATCH@ +diff -Naur asterisk-1.2.1.dfsg.1/asterisk.c asterisk-1.2.1.dfsg.1.patched/asterisk.c +--- asterisk-1.2.1.dfsg.1/asterisk.c 2005-11-16 13:36:55.308985128 -0600 ++++ asterisk-1.2.1.dfsg.1.patched/asterisk.c 2005-11-16 13:37:10.426686888 -0600 +@@ -2170,11 +2170,12 @@ + + if (!option_verbose && !option_debug && !option_nofork && !option_console) { + daemon(0,0); ++ ast_mainpid = getpid(); + /* Blindly re-write pid file since we are forking */ + unlink((char *)ast_config_AST_PID); + f = fopen((char *)ast_config_AST_PID, "w"); + if (f) { +- fprintf(f, "%d\n", (int)getpid()); ++ fprintf(f, "%d\n", ast_mainpid); + fclose(f); + } else + ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno)); --- asterisk-1.2.12.1.dfsg.orig/debian/patches/nomarch.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/nomarch.dpatch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## nomarch.dpatch by Kilian Krause +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Don't optimize for i686 anywhere +## -- upstream will move to configure with 1.4 + +@DPATCH@ +diff -urNad asterisk-1.2.0.dfsg~/Makefile asterisk-1.2.0.dfsg/Makefile +--- asterisk-1.2.0.dfsg~/Makefile 2005-11-19 19:30:42.000000000 +0000 ++++ asterisk-1.2.0.dfsg/Makefile 2005-11-19 19:30:51.000000000 +0000 +@@ -227,10 +227,6 @@ + ASTCFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib + endif + +-ifneq ($(PROC),ultrasparc) +- ASTCFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi) +-endif +- + ifeq ($(PROC),ppc) + ASTCFLAGS+=-fsigned-char + endif --- asterisk-1.2.12.1.dfsg.orig/debian/patches/98_fpm-sounds.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/98_fpm-sounds.dpatch @@ -0,0 +1,21 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 110_fpm-sounds.dpatch by Jose Carlos Garcia Sogo +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Don't try to install non-dfsg sounds from source + +@DPATCH@ +diff -urNad asterisk-1.2.0-beta2.dfsg~/Makefile asterisk-1.2.0-beta2.dfsg/Makefile +--- asterisk-1.2.0-beta2.dfsg~/Makefile 2005-11-01 21:07:13.000000000 +0000 ++++ asterisk-1.2.0-beta2.dfsg/Makefile 2005-11-01 21:08:15.000000000 +0000 +@@ -735,10 +735,6 @@ + exit 1; \ + fi; \ + done +- mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/mohmp3 ; \ +- for x in sounds/*.mp3; do \ +- $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTVARLIBDIR)/mohmp3 ; \ +- done + rm -f $(DESTDIR)$(ASTVARLIBDIR)/mohmp3/sample-hold.mp3 + mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/INBOX + :> $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/unavail.gsm --- asterisk-1.2.12.1.dfsg.orig/debian/patches/40_initgroups.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/40_initgroups.dpatch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 40_initgroups.dpatch by Kilian Krause +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: does initialize groups of asterisk user if no -G is given. +## -- applied upstream for 1.2 + +@DPATCH@ +diff -urN asterisk-1.0.5.orig/asterisk.c asterisk-1.0.5/asterisk.c +--- asterisk-1.0.5.orig/asterisk.c 2005-01-15 20:58:41.000000000 +0100 ++++ asterisk-1.0.5/asterisk.c 2005-02-03 22:56:55.000000000 +0100 +@@ -1719,6 +1719,10 @@ + ast_log(LOG_WARNING, "No such user '%s'!\n", runuser); + exit(1); + } ++ if (!rungroup && initgroups(runuser, pw->pw_gid)) { ++ ast_log(LOG_WARNING, "Unable to initialize supplementary group list for %s\n", runuser); ++ exit(1); ++ } + if (setuid(pw->pw_uid)) { + ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser); + exit(1); --- asterisk-1.2.12.1.dfsg.orig/debian/patches/sys_editline.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/sys_editline.dpatch @@ -0,0 +1,29 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## sys_readline.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Use the system copy of editline + +@DPATCH@ +diff -urNad asterisk-1.2.7.1.dfsg/Makefile /tmp/dpep.nfcwXR/asterisk-1.2.7.1.dfsg/Makefile +--- asterisk-1.2.7.1.dfsg/Makefile 2006-04-12 00:58:47.000000000 +0300 ++++ /tmp/dpep.nfcwXR/asterisk-1.2.7.1.dfsg/Makefile 2006-05-13 22:54:43.051344312 +0300 +@@ -305,7 +305,8 @@ + + endif # WITHOUT_ZAPTEL + +-LIBEDIT=editline/libedit.a ++#LIBEDIT=editline/libedit.a ++LIBS+=-ledit + + ifneq ($(wildcard .version),) + ASTERISKVERSION:=$(shell cat .version) +@@ -513,7 +514,7 @@ + cygwin_a: + $(MAKE) -C cygwin all + +-asterisk: $(CYGLOADER) editline/libedit.a db1-ast/libdb1.a stdtime/libtime.a $(OBJS) ++asterisk: $(CYGLOADER) db1-ast/libdb1.a stdtime/libtime.a $(OBJS) + build_tools/make_build_h > include/asterisk/build.h.tmp + if cmp -s include/asterisk/build.h.tmp include/asterisk/build.h ; then echo ; else \ + mv include/asterisk/build.h.tmp include/asterisk/build.h ; \ --- asterisk-1.2.12.1.dfsg.orig/debian/patches/vm_he.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/vm_he.dpatch @@ -0,0 +1,27 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## vm_he.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Add Hebrew support to the voicemail app. + +@DPATCH@ +diff -urNad asterisk-1.2.7.1.dfsg/apps/app_voicemail.c /tmp/dpep.9UOJxZ/asterisk-1.2.7.1.dfsg/apps/app_voicemail.c +--- asterisk-1.2.7.1.dfsg/apps/app_voicemail.c 2006-04-12 01:24:46.000000000 +0300 ++++ /tmp/dpep.9UOJxZ/asterisk-1.2.7.1.dfsg/apps/app_voicemail.c 2006-05-19 08:00:31.550220449 +0300 +@@ -154,6 +154,7 @@ + \arg \b gr - Greek + \arg \b no - Norwegian + \arg \b se - Swedish ++ \arg \b he - Hebrew + + German requires the following additional soundfile: + \arg \b 1F einE (feminine) +@@ -3667,6 +3668,8 @@ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL); + else if (!strcasecmp(chan->language,"nl")) /* DUTCH syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL); ++ else if (!strcasecmp(chan->language,"he")) /* HEBREW syntax */ ++ res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' HM", NULL); + else if (!strcasecmp(chan->language,"it")) /* ITALIAN syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL); + else if (!strcasecmp(chan->language,"gr")) --- asterisk-1.2.12.1.dfsg.orig/debian/patches/50_debian-libgsm.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/50_debian-libgsm.dpatch @@ -0,0 +1,59 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## codecs_Makefile.dpatch by Mark Purcell +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Use installed libgsm if availble + +@DPATCH@ +diff -urNad asterisk-1.2.0.dfsg~/codecs/codec_gsm.c asterisk-1.2.0.dfsg/codecs/codec_gsm.c +--- asterisk-1.2.0.dfsg~/codecs/codec_gsm.c 2005-11-06 15:09:46.000000000 +0000 ++++ asterisk-1.2.0.dfsg/codecs/codec_gsm.c 2005-11-21 19:52:33.000000000 +0000 +@@ -45,7 +45,7 @@ + #include "asterisk/logger.h" + #include "asterisk/channel.h" + +-#include "gsm/inc/gsm.h" ++#include + #include "../formats/msgsm.h" + + /* Sample frame data */ +diff -urNad asterisk-1.2.0.dfsg~/codecs/Makefile asterisk-1.2.0.dfsg/codecs/Makefile +--- asterisk-1.2.0.dfsg~/codecs/Makefile 2005-11-08 04:13:18.000000000 +0000 ++++ asterisk-1.2.0.dfsg/codecs/Makefile 2005-11-21 19:53:31.000000000 +0000 +@@ -60,8 +60,9 @@ + endif + + +-LIBGSM=gsm/lib/libgsm.a +-LIBGSMT=gsm/lib/libgsm.a ++LIBGSM=-lgsm ++# We don't build libgsm but use the system's one. ++LIBGSMT= + LIBLPC10=lpc10/liblpc10.a + + ifeq ($(findstring BSD,${OSARCH}),BSD) +diff -urNad asterisk-1.2.0.dfsg~/formats/Makefile asterisk-1.2.0.dfsg/formats/Makefile +--- asterisk-1.2.0.dfsg~/formats/Makefile 2005-11-01 21:53:30.000000000 +0000 ++++ asterisk-1.2.0.dfsg/formats/Makefile 2005-11-21 19:54:10.000000000 +0000 +@@ -33,8 +33,6 @@ + CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib + endif + +-GSMLIB=../codecs/gsm/lib/libgsm.a +- + ifeq (${OSARCH},CYGWIN) + CYGSOLINK=-Wl,--out-implib=lib$@.a -Wl,--export-all-symbols + CYGSOLIB=-L.. -L. -lasterisk.dll +@@ -53,6 +51,12 @@ + include .depend + endif + ++format_gsm.so : format_gsm.o ++ $(CC) $(SOLINK) -o $@ $< -lgsm ++ ++format_wav_gsm.so : format_wav_gsm.o ++ $(CC) $(SOLINK) -o $@ $< -lgsm ++ + format_mp3.so : format_mp3.o + $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lm + --- asterisk-1.2.12.1.dfsg.orig/debian/patches/patch.1.2.16-security.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/patch.1.2.16-security.dpatch @@ -0,0 +1,23 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## patch.1.2.16-security.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad asterisk-1.2.12.1.dfsg~/channels/chan_sip.c asterisk-1.2.12.1.dfsg/channels/chan_sip.c +--- asterisk-1.2.12.1.dfsg~/channels/chan_sip.c 2006-09-09 14:14:03.000000000 +0200 ++++ asterisk-1.2.12.1.dfsg/channels/chan_sip.c 2007-03-05 16:50:00.000000000 +0100 +@@ -11222,6 +11222,12 @@ + } + } + ++ if (!e && (p->method == SIP_INVITE || p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER)) { ++ transmit_response(p, "503 Server error", req); ++ ast_set_flag(p, SIP_NEEDDESTROY); ++ return -1; ++ } ++ + /* Handle various incoming SIP methods in requests */ + switch (p->method) { + case SIP_OPTIONS: --- asterisk-1.2.12.1.dfsg.orig/debian/patches/brazilian_syntax.dpatch +++ asterisk-1.2.12.1.dfsg/debian/patches/brazilian_syntax.dpatch @@ -0,0 +1,535 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## brazilian_syntax.dpatch by Celso Fassoni +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Brazilian portuguese syntax for VoiceMail() and Say* apps +## DP: at Wed Apr 26 17:25:54 BRT 2006 + +@DPATCH@ +diff -urNad asterisk-1.2.6.dfsg/ asterisk-1.2.6.dfsg.new/ +--- asterisk-1.2.6.dfsg/apps/app_sayunixtime.c 2006-05-15 11:26:14.778183712 -0300 ++++ asterisk-1.2.6.dfsg.new/apps/app_sayunixtime.c 2006-05-15 11:26:19.002541512 -0300 +@@ -85,6 +85,8 @@ + format = "A dBY HMS"; + } else if ( !strcasecmp(chan->language, "de" ) ) { + format = "A dBY HMS"; ++ } else if ( !strcasecmp(chan->language, "pt_BR" ) ) { ++ format = "Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HMS"; + } else { + format = "ABdY 'digits/at' IMp"; + } +--- asterisk-1.2.6.dfsg/apps/app_voicemail.c 2006-05-15 11:11:54.159017712 -0300 ++++ asterisk-1.2.6.dfsg.new/apps/app_voicemail.c 2006-05-15 11:11:58.390374448 -0300 +@@ -144,6 +144,7 @@ + /*! \page vmlang Voicemail Language Syntaxes Supported + + \par Syntaxes supported, not really language codes. ++ \arg \b pt_BR - Brazilian Portuguese + \arg \b en - English + \arg \b de - German + \arg \b es - Spanish +@@ -3669,6 +3670,8 @@ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL); + else if (!strcasecmp(chan->language,"gr")) + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL); ++ else if (!strcasecmp(chan->language,"pt_BR")) ++ res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL); + else + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL); + #if 0 +@@ -3965,7 +3968,7 @@ + { + int cmd; + +- if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt")) { /* Italian, Spanish, French or Portuguese syntax */ ++ if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) { /* Italian, Spanish, French or Portuguese syntax */ + cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */ + if (cmd) + return cmd; +@@ -4297,6 +4300,54 @@ + return res; + } + ++/* BRAZILIAN PORTUGUESE syntax */ ++static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) { ++ /* Introduce messages they have */ ++ int res; ++ if (!vms->oldmessages && !vms->newmessages) { ++ res = ast_play_and_wait(chan, "vm-nomessages"); ++ return res; ++ } ++ else { ++ res = ast_play_and_wait(chan, "vm-youhave"); ++ } ++ if (vms->newmessages) { ++ if (!res) ++ res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f"); ++ if ((vms->newmessages == 1)) { ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-message"); ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-INBOXs"); ++ } ++ else { ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-messages"); ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-INBOX"); ++ } ++ if (vms->oldmessages && !res) ++ res = ast_play_and_wait(chan, "vm-and"); ++ } ++ if (vms->oldmessages) { ++ if (!res) ++ res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f"); ++ if (vms->oldmessages == 1) { ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-message"); ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-Olds"); ++ } ++ else { ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-messages"); ++ if (!res) ++ res = ast_play_and_wait(chan, "vm-Old"); ++ } ++ } ++ return res; ++} ++ + /* FRENCH syntax */ + static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms) + { +@@ -4530,6 +4581,8 @@ + return vm_intro_nl(chan, vms); + } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE syntax */ + return vm_intro_pt(chan, vms); ++ } else if (!strcasecmp(chan->language, "pt_BR")) { /* BRAZILIAN PORTUGUESE syntax */ ++ return vm_intro_pt_BR(chan, vms); + } else if (!strcasecmp(chan->language, "cz")) { /* CZECH syntax */ + return vm_intro_cz(chan, vms); + } else if (!strcasecmp(chan->language, "gr")) { /* GREEK syntax */ +@@ -4938,7 +4991,7 @@ + return vm_browse_messages_es(chan, vms, vmu); + } else if (!strcasecmp(chan->language, "it")) { /* ITALIAN */ + return vm_browse_messages_it(chan, vms, vmu); +- } else if (!strcasecmp(chan->language, "pt")) { /* PORTUGUESE */ ++ } else if (!strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) { /* PORTUGUESE */ + return vm_browse_messages_pt(chan, vms, vmu); + } else if (!strcasecmp(chan->language, "gr")){ + return vm_browse_messages_gr(chan, vms, vmu); /* GREEK */ +--- asterisk-1.2.6.dfsg/say.c 2006-05-15 11:11:46.544175344 -0300 ++++ asterisk-1.2.6.dfsg.new/say.c 2006-05-15 11:12:01.613884400 -0300 +@@ -384,6 +384,7 @@ + static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang); ++static int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + +@@ -392,6 +393,7 @@ + static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang); ++static int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); + +@@ -437,7 +439,7 @@ + return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */ + return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd)); +- } else if (!strcasecmp(language, "pt") ) { /* Portuguese syntax */ ++ } else if (!strcasecmp(language, "pt") || !strcasecmp(language, "pt_BR")) { /* Portuguese syntax */ + return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */ + return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd)); +@@ -2006,6 +2008,10 @@ + (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) ) + playh = 1; + num = num % 1000000; ++ } else { ++ /** Protection: number is to big **/ ++ ast_log(LOG_WARNING, "Number '%d' is too big to say.", num); ++ res = -1; + } + if (!res) { + if (!ast_streamfile(chan, fn, language)) { +@@ -2728,7 +2734,7 @@ + return(ast_say_date_fr(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ + return(ast_say_date_nl(chan, t, ints, lang)); +- } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ ++ } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) { /* Portuguese syntax */ + return(ast_say_date_pt(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ + return(ast_say_date_gr(chan, t, ints, lang)); +@@ -2963,7 +2969,7 @@ + return(ast_say_date_with_format_it(chan, time, ints, lang, format, timezone)); + } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ + return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone)); +- } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ ++ } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) { /* Portuguese syntax */ + return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone)); + } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ + return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone)); +@@ -3835,8 +3841,12 @@ + break; + case 'm': + /* First - Twelfth */ +- snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); +- res = wait_file(chan,ints,nextmsg,lang); ++ if (!strcasecmp(lang, "pt_BR")) { ++ res = ast_say_number(chan, tm.tm_mon+1, ints, lang, (char *) NULL); ++ } else { ++ snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); ++ res = wait_file(chan,ints,nextmsg,lang); ++ } + break; + case 'd': + case 'e': +@@ -4671,66 +4681,126 @@ + case 'I': + case 'l': + /* 12-Hour */ +- if (tm.tm_hour == 0) { +- if (format[offset] == 'I') +- res = wait_file(chan, ints, "digits/pt-ah", lang); +- if (!res) +- res = wait_file(chan, ints, "digits/pt-meianoite", lang); +- } +- else if (tm.tm_hour == 12) { +- if (format[offset] == 'I') +- res = wait_file(chan, ints, "digits/pt-ao", lang); +- if (!res) +- res = wait_file(chan, ints, "digits/pt-meiodia", lang); +- } +- else { +- if (format[offset] == 'I') { +- res = wait_file(chan, ints, "digits/pt-ah", lang); +- if ((tm.tm_hour % 12) != 1) +- if (!res) +- res = wait_file(chan, ints, "digits/pt-sss", lang); +- } +- if (!res) +- res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); ++ if (!strcasecmp(lang, "pt_BR")) { ++ if (tm.tm_hour == 0) { ++ if (format[offset] == 'I') ++ res = wait_file(chan, ints, "digits/pt-a", lang); ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-meianoite", lang); ++ } else if (tm.tm_hour == 12) { ++ if (format[offset] == 'I') ++ res = wait_file(chan, ints, "digits/pt-ao", lang); ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-meiodia", lang); ++ } else { ++ if (format[offset] == 'I') { ++ if ((tm.tm_hour % 12) != 1) ++ res = wait_file(chan, ints, "digits/pt-as", lang); ++ else ++ res = wait_file(chan, ints, "digits/pt-a", lang); ++ } ++ if (!res) ++ res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); ++ if ((!res) && (format[offset] == 'I')) ++ res = ast_say_date_with_format(chan, time, ints, lang, "P", timezone); ++ } ++ } else { ++ if (tm.tm_hour == 0) { ++ if (format[offset] == 'I') ++ res = wait_file(chan, ints, "digits/pt-ah", lang); ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-meianoite", lang); ++ } ++ else if (tm.tm_hour == 12) { ++ if (format[offset] == 'I') ++ res = wait_file(chan, ints, "digits/pt-ao", lang); ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-meiodia", lang); ++ } ++ else { ++ if (format[offset] == 'I') { ++ res = wait_file(chan, ints, "digits/pt-ah", lang); ++ if ((tm.tm_hour % 12) != 1) ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-sss", lang); ++ } ++ if (!res) ++ res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); ++ } + } + break; + case 'H': + case 'k': + /* 24-Hour */ +- res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); +- if (!res) { +- if (tm.tm_hour != 0) { +- int remainder = tm.tm_hour; +- if (tm.tm_hour > 20) { +- res = wait_file(chan,ints, "digits/20",lang); +- remainder -= 20; ++ if (!strcasecmp(lang, "pt_BR")) { ++ res = ast_say_number(chan, tm.tm_hour, ints, lang, "f"); ++ if ((!res) && (format[offset] == 'H')) { ++ if (tm.tm_hour > 1) { ++ res = wait_file(chan,ints,"digits/hours",lang); ++ } else { ++ res = wait_file(chan,ints,"digits/hour",lang); + } +- if (!res) { +- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); +- res = wait_file(chan,ints,nextmsg,lang); ++ } ++ } else { ++ res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); ++ if (!res) { ++ if (tm.tm_hour != 0) { ++ int remainder = tm.tm_hour; ++ if (tm.tm_hour > 20) { ++ res = wait_file(chan,ints, "digits/20",lang); ++ remainder -= 20; ++ } ++ if (!res) { ++ snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); ++ res = wait_file(chan,ints,nextmsg,lang); ++ } + } + } + } + break; + case 'M': + /* Minute */ +- if (tm.tm_min == 0) { +- res = wait_file(chan, ints, "digits/pt-hora", lang); +- if (tm.tm_hour != 1) ++ if (!strcasecmp(lang, "pt_BR")) { ++ res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); ++ if (!res) { ++ if (tm.tm_min > 1) { ++ res = wait_file(chan,ints,"digits/minutes",lang); ++ } else { ++ res = wait_file(chan,ints,"digits/minute",lang); ++ } ++ } ++ } else { ++ if (tm.tm_min == 0) { ++ res = wait_file(chan, ints, "digits/pt-hora", lang); ++ if (tm.tm_hour != 1) ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-sss", lang); } else { ++ res = wait_file(chan,ints,"digits/pt-e",lang); + if (!res) +- res = wait_file(chan, ints, "digits/pt-sss", lang); } else { +- res = wait_file(chan,ints,"digits/pt-e",lang); +- if (!res) +- res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); ++ res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); ++ } + } + break; + case 'P': + case 'p': + /* AM/PM */ +- if (tm.tm_hour > 12) +- res = wait_file(chan, ints, "digits/p-m", lang); +- else if (tm.tm_hour && tm.tm_hour < 12) +- res = wait_file(chan, ints, "digits/a-m", lang); ++ if (!strcasecmp(lang, "pt_BR")) { ++ if ((tm.tm_hour != 0) && (tm.tm_hour != 12)) { ++ res = wait_file(chan, ints, "digits/pt-da", lang); ++ if (!res) { ++ if ((tm.tm_hour >= 0) && (tm.tm_hour < 12)) ++ res = wait_file(chan, ints, "digits/morning", lang); ++ else if ((tm.tm_hour >= 12) && (tm.tm_hour < 18)) ++ res = wait_file(chan, ints, "digits/afternoon", lang); ++ else res = wait_file(chan, ints, "digits/night", lang); ++ } ++ } ++ } else { ++ if (tm.tm_hour > 12) ++ res = wait_file(chan, ints, "digits/p-m", lang); ++ else if (tm.tm_hour && tm.tm_hour < 12) ++ res = wait_file(chan, ints, "digits/a-m", lang); ++ } + break; + case 'Q': + /* Shorthand for "Today", "Yesterday", or ABdY */ +@@ -4785,30 +4855,41 @@ + break; + case 'S': + /* Seconds */ +- if (tm.tm_sec == 0) { +- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); +- res = wait_file(chan,ints,nextmsg,lang); +- } else if (tm.tm_sec < 10) { +- res = wait_file(chan,ints, "digits/oh",lang); ++ if (!strcasecmp(lang, "pt_BR")) { ++ res = ast_say_number(chan, tm.tm_sec, ints, lang, NULL); + if (!res) { +- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); +- res = wait_file(chan,ints,nextmsg,lang); ++ if (tm.tm_sec > 1) { ++ res = wait_file(chan,ints,"digits/seconds",lang); ++ } else { ++ res = wait_file(chan,ints,"digits/second",lang); ++ } + } +- } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { +- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); +- res = wait_file(chan,ints,nextmsg,lang); + } else { +- int ten, one; +- ten = (tm.tm_sec / 10) * 10; +- one = (tm.tm_sec % 10); +- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); +- res = wait_file(chan,ints,nextmsg,lang); +- if (!res) { +- /* Fifty, not fifty-zero */ +- if (one != 0) { +- snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); ++ if (tm.tm_sec == 0) { ++ snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); ++ res = wait_file(chan,ints,nextmsg,lang); ++ } else if (tm.tm_sec < 10) { ++ res = wait_file(chan,ints, "digits/oh",lang); ++ if (!res) { ++ snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } ++ } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { ++ snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); ++ res = wait_file(chan,ints,nextmsg,lang); ++ } else { ++ int ten, one; ++ ten = (tm.tm_sec / 10) * 10; ++ one = (tm.tm_sec % 10); ++ snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); ++ res = wait_file(chan,ints,nextmsg,lang); ++ if (!res) { ++ /* Fifty, not fifty-zero */ ++ if (one != 0) { ++ snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); ++ res = wait_file(chan,ints,nextmsg,lang); ++ } ++ } + } + } + break; +@@ -5104,6 +5185,8 @@ + return(ast_say_time_nl(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_time_pt(chan, t, ints, lang)); ++ } else if (!strcasecmp(lang, "pt_BR") ) { /* Brazilian Portuguese syntax */ ++ return(ast_say_time_pt_BR(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ + return(ast_say_time_tw(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ +@@ -5241,6 +5324,34 @@ + return res; + } + ++/* Brazilian Portuguese syntax */ ++int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang) ++{ ++ struct tm tm; ++ int res = 0; ++ localtime_r(&t,&tm); ++ ++ res = ast_say_number(chan, tm.tm_hour, ints, lang, "f"); ++ if (!res) { ++ if (tm.tm_hour > 1) ++ res = wait_file(chan, ints, "digits/hours", lang); ++ else ++ res = wait_file(chan, ints, "digits/hour", lang); ++ } ++ if ((!res) && (tm.tm_min)) { ++ res = wait_file(chan, ints, "digits/pt-e", lang); ++ if (!res) ++ res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); ++ if (!res) { ++ if (tm.tm_min > 1) ++ res = wait_file(chan, ints, "digits/minutes", lang); ++ else ++ res = wait_file(chan, ints, "digits/minute", lang); ++ } ++ } ++ return res; ++} ++ + /* Taiwanese syntax */ + int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang) + { +@@ -5293,6 +5404,8 @@ + return(ast_say_datetime_nl(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_datetime_pt(chan, t, ints, lang)); ++ } else if (!strcasecmp(lang, "pt_BR") ) { /* Brazilian Portuguese syntax */ ++ return(ast_say_datetime_pt_BR(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ + return(ast_say_datetime_tw(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ +@@ -5502,6 +5615,18 @@ + return res; + } + ++/* Brazilian Portuguese syntax */ ++int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang) ++{ ++ struct tm tm; ++ int res = 0; ++ localtime_r(&t,&tm); ++ res = ast_say_date(chan, t, ints, lang); ++ if (!res) ++ res = ast_say_time(chan, t, ints, lang); ++ return res; ++} ++ + /* Taiwanese syntax */ + int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang) + { +@@ -5566,7 +5691,7 @@ + return(ast_say_datetime_from_now_en(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "fr") ) { /* French syntax */ + return(ast_say_datetime_from_now_fr(chan, t, ints, lang)); +- } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ ++ } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) { /* Portuguese syntax */ + return(ast_say_datetime_from_now_pt(chan, t, ints, lang)); + } + +@@ -5685,14 +5810,24 @@ + if (!res) + res = wait_file(chan, ints, fn, lang); + } /* Otherwise, it was today */ +- snprintf(fn, sizeof(fn), "digits/pt-ah"); +- if (!res) +- res = wait_file(chan, ints, fn, lang); +- if (tm.tm_hour != 1) +- if (!res) +- res = wait_file(chan, ints, "digits/pt-sss", lang); +- if (!res) +- res = ast_say_time(chan, t, ints, lang); ++ if (!strcasecmp(lang, "pt_BR")) { ++ if (tm.tm_hour > 1) { ++ snprintf(fn, sizeof(fn), "digits/pt-as"); ++ } else { ++ snprintf(fn, sizeof(fn), "digits/pt-a"); ++ } ++ if (!res) ++ res = wait_file(chan, ints, fn, lang); ++ } else { ++ snprintf(fn, sizeof(fn), "digits/pt-ah"); ++ if (!res) ++ res = wait_file(chan, ints, fn, lang); ++ if (tm.tm_hour != 1) ++ if (!res) ++ res = wait_file(chan, ints, "digits/pt-sss", lang); ++ if (!res) ++ res = ast_say_time(chan, t, ints, lang); ++ } + return res; + } --- asterisk-1.2.12.1.dfsg.orig/debian/copyright +++ asterisk-1.2.12.1.dfsg/debian/copyright @@ -0,0 +1,229 @@ +This package was debianized by Mark Purcell on +Fri Apr 19 19:58:40 EST 2002 + +Asterisk downloaded from http://www.asterisk.org +Bristuff downloaded from http://www.junghanns.net/asterisk/ + +Upstream Authors: Asterisk: Mark Spencer + Bristuff: Klaus-Peter Junghanns + +Debian asterisk-xxx.dfsg.tar.gz +=============================== + * The Debian version of the upstream asterisk source has had the fpm Music +on Hold removed as this music has only been licenced for use within +asterisk which is incompatible with the Debian Free Software Guildlines (DFSG) +. + + * The iLBC codec library code has been removed from the Debian asterisk +package as it does not conform with the DFSG. + + * The contrib/firmware/iax/iaxy.bin binary firmware without source has been removed. + +Copyright: + +Copyright (C) 2001-2004 Digium and others.... + + This package 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; version 2 dated June, 1991. + + This package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + MA 02110-1301, USA. + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. + + Asterisk is distributed under GNU General Public License. The GPL also + must apply to all loadable modules as well, except as defined below. + + Digium, Inc. (formerly Linux Support Services) retains copyright to all + of the core Asterisk system, and therefore can grant, at its sole discretion, + the ability for companies, individuals, or organizations to create proprietary + or Open Source (but non-GPL'd) modules which may be dynamically linked at + runtime with the portions of Asterisk which fall under our copyright + umbrella, or are distributed under more flexible licenses than GPL + + If you wish to use our code in other GPL programs, don't worry -- there + is no requirement that you provide the same exemption in your GPL'd + products (although if you've written a module for Asterisk we would + strongly encourage you to make the same excemption that we do). + + Specific permission is also granted to OpenSSL and OpenH323 to link to + Asterisk. + + If you have any questions, whatsoever, regarding our licensing policy, + please contact us. + + The 'Asterisk' name and logos are trademarks owned by Digium, Inc., + and use of them is subject to our trademark licensing policies. If you + wish to use these trademarks for purposes other than simple + redistribution of Asterisk source code obtained from Digium, you + should contact our licensing department to determine the necessary + steps you must take. + + If you have any questions regarding our licensing policy, please + contact us: + + +1.877.546.8963 (via telephone in the USA) + +1.256.428.6000 (via telephone outside the USA) + +1.256.864.0464 (via FAX inside or outside the USA) + IAX2/misery.digium.com/6000 (via IAX2) + licensing@digium.com (via email) + + Digium, Inc. + 150 West Park Loop + Suite 100 + Huntsville, AL 35806 + USA + +Other source code in Asterisk: + + GSM source: + + Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, + Technische Universitaet Berlin + + Any use of this software is permitted provided that this notice is not + removed and that neither the authors nor the Technische Universitaet Berlin + are deemed to have made any representations as to the suitability of this + software for any purpose nor are held responsible for any defects of + this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + + As a matter of courtesy, the authors request to be informed about uses + this software has found, about bugs in this software, and about any + improvements that may be of general interest. + + Berlin, 28.11.1994 + Jutta Degener + Carsten Bormann + + ADPCM source: + + Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The + Netherlands. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appear in all copies and that + both that copyright notice and this permission notice appear in + supporting documentation, and that the names of Stichting Mathematisch + Centrum or CWI not be used in advertising or publicity pertaining to + distribution of the software without specific, written prior permission. + + STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO + THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE + FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + Bristuff: + + * 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. + +Other portions of code: + +aescrypt.c: Copyright (c) 2003, Dr Brian Gladman , Worcester, UK. +aeskey.c: Copyright (c) 2003, Dr Brian Gladman , Worcester, UK. +dlfcn.c:Copyright (c) 2002 Jorge Acereda & + Peter O'Gorman +dns.c: * Copyright (C) 1999 - 2005 Thorsten Lockert +dnsmgr.c: * Copyright (C) 2005, Kevin P. Fleming +dsp.c: Copyright (C) 2001 Steve Underwood +indications.c: * Copyright (C) 2002, Pauline Middelink +jitterbuf.c: * Copyright (C) 2004-2005, Horizon Wimba, Inc. +jitterbuf.h: * Copyright (C) 2004-2005, Horizon Wimba, Inc. +md5.c: * written by Colin Plumb in 1993, no copyright is claimed. +plc.c: * Copyright (C) 2004 Steve Underwood +poll.c: Copyright (c) 1995-2002 Brian M. Clapper +slinfactory.c: * Copyright (C) 2005, Anthony Minessale II. +apps/app_alarmreceiver.c: * Copyright (C) 2004 - 2005 Steve Rodgers +apps/app_chanspy.c: * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com) +apps/app_controlplayback.c: * Copyright (C) 1999 - 2005, Digium, Inc. +apps/app_curl.c: * Copyright (C) 2004 - 2005, Tilghman Lesher +apps/app_cut.c: * Copyright (c) 2003 Tilghman Lesher. All rights reserved. +apps/app_db.c: * Copyright (C) 2003, Jefferson Noxon +apps/app_dictate.c: * Copyright (C) 2005, Anthony Minessale II +apps/app_directed_pickup.c: * Copyright (C) 2005, Joshua Colp +apps/app_dumpchan.c: * Copyright (C) 2004 - 2005, Anthony Minessale II. +apps/app_eval.c: * Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved. +apps/app_exec.c: * Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved. +apps/app_festival.c: * Copyright (C) 2002, Christos Ricudis +apps/app_forkcdr.c: * Copyright (C) 1999 - 2005, Anthony Minessale anthmct@yahoo.com +apps/app_hasnewvoicemail.c: * Changes Copyright (c) 2004 - 2005 Todd Freeman +apps/app_hasnewvoicemail.c: * Copyright (c) 2003 Tilghman Lesher. All rights reserved. +apps/app_math.c: * Copyright (C) 2004 - 2005, Andy Powell +apps/app_md5.c: * Copyright (C) 2005, Olle E. Johansson, Edvina.net +apps/app_mixmonitor.c: * Copyright (C) 2005, Anthony Minessale II +apps/app_random.c: * Copyright (c) 2003 - 2005 Tilghman Lesher. All rights reserved. +apps/app_rpt.c: * Copyright (C) 2002-2005, Jim Dixon, WB6NIL +apps/app_sayunixtime.c: * Copyright (c) 2003 Tilghman Lesher. All rights reserved. +apps/app_settransfercapability.c: * Copyright (C) 2005, Frank Sautter, levigo holding gmbh, www.levigo.de +apps/app_skel.c: * Copyright (C) , +apps/app_sms.c: * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium +apps/app_sql_postgres.c: * Copyright (C) 2002, Christos Ricudis +apps/app_verbose.c: * Copyright (c) 2004 - 2005 Tilghman Lesher. All rights reserved. +apps/app_while.c: * Copyright 2004 - 2005, Anthony Minessale +cdr/cdr_sqlite.c: * Copyright (C) 2004 - 2005, Holger Schurig +cdr/cdr_tds.c: Copyright (C) 1994, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. +channels/chan_misdn.c: * Copyright (C) 2004, Christian Richter +channels/chan_misdn_config.c: * Copyright (C) 2005, Christian Richter +channels/chan_modem_bestdata.c: * Copyright (C) 1999, Mark Spencer and 2001 Jim Dixon +channels/chan_vpb.c: * Copyright (C) 2003, Paul Bagyenda +channels/chan_vpb.c: * Copyright (C) 2004 - 2005, Ben Kramer +channels/DialTone.h: * Copyright (C) 1999, Mark Spencer +channels/Makefile:# Copyright (C) 1999-2005, Mark Spencer +codecs/codec_ilbc.c: * The iLBC code is from The IETF code base and is copyright The Internet Society (2004) +doc/README.backtrace:Copyright 2004 Free Software Foundation, Inc. +editline/: * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. +editline/editline.3:.\" Copyright (c) 1997-1999 The NetBSD Foundation, Inc. +editline/install-sh:# Copyright 1991 by the Massachusetts Institute of Technology +formats/format_au.c: * Copyright (C) 2005, Andriy Pylypenko +formats/format_g726.c: * Copyright (c) 2004 - 2005, inAccess Networks +formats/format_ogg_vorbis.c: * Copyright (C) 2005, Jeff Ollie +formats/format_sln.c: * Copyright (C) 1999 - 2005, Anthony Minessale +funcs/func_cdr.c: * Portions Copyright (C) 2005, Anthony Minessale II +funcs/func_db.c: * Copyright (C) 2005, Russell Bryant +funcs/func_db.c: * Copyright (C) 2003, Jefferson Noxon +funcs/func_logic.c: * Portions Copyright (C) 2005, Anthony Minessale II +funcs/func_math.c: * Copyright (C) 2004 - 2005, Andy Powell +funcs/func_md5.c: * Copyright (C) 2005, Olle E. Johansson, Edvina.net +funcs/func_md5.c: * Copyright (C) 2005, Russell Bryant +funcs/func_strings.c: * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved. +funcs/func_strings.c: * Portions Copyright (C) 2005, Anthony Minessale II +res/res_config_odbc.c: * Copyright (C) 2004 - 2005 Anthony Minessale II +res/res_indications.c: * Copyright (C) 2002, Pauline Middelink +res/res_odbc.c: * Copyright (C) 2004 - 2005 Anthony Minessale II +utils/smsq.c: * Copyright (C) 2004 - 2005 Adrian Kennard +utils/streamplayer.c: fprintf(stderr, "Copyright (C) 2005 -- Russell Bryant -- Digium, Inc.\n\n"); +channels/misdn/: * Copyright (C) 2004, Christian Richter +codecs/ilbc/: Copyright (C) The Internet Society (2004). +contrib/scripts/managerproxy.pl:# Copyright (c) 2004 David C. Troy <dave@popvox.com> +contrib/scripts/retrieve_extensions_from_sql.pl:# Copyright: 2004 Peter Nixon +db1-ast/*/*: * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. +editline/np/: * Copyright (c) 1998 The NetBSD Foundation, Inc. +editline/np/strlcat.c: * Copyright (c) 1998 Todd C. Miller +include/asterisk/aes.h: Copyright (c) 2003, Dr Brian Gladman , Worcester, UK. +include/asterisk/dlfcn-compat.h:Copyright (c) 2002 Jorge Acereda & + Peter O'Gorman +include/asterisk/plc.h: * Copyright (C) 2004 Steve Underwood +include/asterisk/poll-compat.h: Copyright (c) 1995-2002 Brian M. Clapper +include/asterisk/res_odbc.h: * Copyright (C) 2004 - 2005, Anthony Minessale II +include/asterisk/slinfactory.h: * Copyright (C) 2005, Anthony Minessale II --- asterisk-1.2.12.1.dfsg.orig/debian/examples +++ asterisk-1.2.12.1.dfsg/debian/examples @@ -0,0 +1,4 @@ +sample.call +configs/* +muted.conf.sample +agi/agi-test.agi --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-web-vmail.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-web-vmail.install @@ -0,0 +1 @@ +usr/lib/cgi-bin/asterisk/vmail.cgi --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk.init +++ asterisk-1.2.12.1.dfsg/debian/asterisk.init @@ -0,0 +1,183 @@ +#! /bin/sh +# +# asterisk start the asterisk PBX +# (c) Mark Purcell +# May be distributed under the terms of this General Public License +# +# Based on: +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# +# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +NAME=asterisk +USER=$NAME +GROUP=$USER +DAEMON=/usr/sbin/$NAME +DESC="Asterisk PBX" +PIDFILE="/var/run/asterisk/asterisk.pid" +ASTSAFE_PIDFILE="/var/run/asterisk/asterisk_safe.pid" + +# by default: use real-time priority +PARAMS="" +AST_REALTIME="yes" +RUNASTERISK="no" +if [ -r /etc/default/$NAME ]; then . /etc/default/$NAME; fi + +if [ "$RUNASTERISK" != "yes" ];then + echo "Asterisk not yet configured. Edit /etc/default/asterisk first." + exit 0 +fi + +if [ "$AST_REALTIME" != "no" ] +then + PARAMS="$PARAMS -p" +fi + +if [ "x$USER" = "x" ] +then + echo "Error: empty USER name" + exit 1 +fi +if [ `id -u "$USER"` = 0 ] +then + echo "Starting as root not supported." + exit 1 +fi +PARAMS="$PARAMS -U $USER" + +if [ "x$AST_DEBUG_PARAMS" = x ] +then + AST_DEBUG_PARAMS=-cvvvvvddddd +fi +if [ "$RUNASTSAFE" = "yes" ];then + # The value of WRAPPER_DAEMON in can be set in /etc/default/asterisk + WRAPPER_DAEMON=${WRAPPER_DAEMON:-/usr/sbin/safe_asterisk} + REALDAEMON="$WRAPPER_DAEMON" +else + REALDAEMON="$DAEMON" +fi + +test -x $DAEMON || exit 0 + +set -e + +if [ ! -e `dirname $PIDFILE` ];then + mkdir `dirname $PIDFILE` + chown asterisk.asterisk `dirname $PIDFILE` +fi + +status() { + plist=`ps auxw | grep "$DAEMON" | grep -v grep | awk '{print $2}' | tr '\012' ' '` + if [ "$plist" = "" ]; then + echo "$DESC is stopped" + return 1 + else + echo "$DESC is running: $plist" + return 0 + fi +} + +case "$1" in + debug) + # we add too many special parameters that I don't want to skip + # accidentally. I'm afraid that skipping -U once may cause + # confusing results. I also want to maintain the user's choice + # of -p + echo "Debugging $DESC: " + $DAEMON $PARAMS $AST_DEBUG_PARAMS + exit 0 + ;; + start) + if status > /dev/null; then + echo "$DESC is already running. Use restart." + exit 0 + fi + echo -n "Starting $DESC: " + if [ "$RUNASTSAFE" != "yes" ];then + # TODO: what if we cought the wrapper just as its asterisk + # was killed? status should check for the wrapper if we're in + # "safe mode" + if status > /dev/null; then + echo "$DESC is already running. Use restart." + exit 0 + fi + start-stop-daemon --start --group $GROUP --pidfile "$PIDFILE" \ + --exec $REALDAEMON -- $PARAMS + else + start-stop-daemon --start --group $GROUP --make-pidfile \ + --pidfile "$ASTSAFE_PIDFILE" \ + --exec $REALDAEMON -- $PARAMS + fi + + + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + if [ "$RUNASTSAFE" = "yes" ];then + # hopefully this will work. Untested + $REALDAEMON -rx 'stop now' > /dev/null || true + else + # Try gracefully. + # this may hang in some cases. Specifically, when the asterisk + # processes is stopped. No bother to worry about cleanup: + # it will either fail or die when asterisk dies. + ( $DAEMON -rx 'stop now' > /dev/null 2>&1 & ) & + fi + echo -n "$NAME" + ## giving a small grace time to shut down cleanly. + #sleep 2 # you can add timeouts in the comma + if [ "$RUNASTSAFE" = "yes" ];then + start-stop-daemon --quiet --pidfile $ASTSAFE_PIDFILE --oknodo \ + --stop + fi + # just making sure it's really, really dead. + # KILL is necessary just in case there's an asterisk -r in the background + start-stop-daemon --stop --quiet --oknodo --retry=0/2/TERM/2/KILL/5 --exec $DAEMON + echo "." + ;; + reload) + echo "Reloading $DESC configuration files." + $DAEMON -rx 'reload' || true + ;; + logger-reload) + $DAEMON -rx 'logger reload' || true + ;; + extensions-reload) + echo "Reloading $DESC configuration files." + $DAEMON -rx 'extensions reload' || true + ;; + restart|force-reload) + $0 stop + $0 start + ;; + status) + status + exit $? + ;; + zaptel-fix) + echo "Unloading and reloading loading Asterisk and Zaptel:" + $0 stop + /etc/init.d/zaptel unload + # load modules from /etc/modules. This will break if you count on + # discover/hotplug + /etc/init.d/module-init-tools + /etc/init.d/zaptel start + $0 start + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|status|debug|logger-reload|extensions-reload|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-h323.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-h323.install @@ -0,0 +1 @@ +usr/lib/asterisk/modules/chan_h323.so --- asterisk-1.2.12.1.dfsg.orig/debian/astgenkey.8 +++ asterisk-1.2.12.1.dfsg/debian/astgenkey.8 @@ -0,0 +1,129 @@ +.\" $Header: /aolnet/dev/src/CVS/sgml/docbook-to-man/cmd/docbook-to-man.sh,v 1.1.1.1 1998/11/13 21:31:59 db3l Exp $ +.\" +.\" transcript compatibility for postscript use. +.\" +.\" synopsis: .P! +.\" +.de P! +.fl +\!!1 setgray +.fl +\\&.\" +.fl +\!!0 setgray +.fl \" force out current output buffer +\!!save /psv exch def currentpoint translate 0 0 moveto +\!!/showpage{}def +.fl \" prolog +.sy sed \-e 's/^/!/' \\$1\" bring in postscript file +\!!psv restore +. +.de pF +.ie \\*(f1 .ds f1 \\n(.f +.el .ie \\*(f2 .ds f2 \\n(.f +.el .ie \\*(f3 .ds f3 \\n(.f +.el .ie \\*(f4 .ds f4 \\n(.f +.el .tm ? font overflow +.ft \\$1 +.. +.de fP +.ie !\\*(f4 \{\ +. ft \\*(f4 +. ds f4\" +' br \} +.el .ie !\\*(f3 \{\ +. ft \\*(f3 +. ds f3\" +' br \} +.el .ie !\\*(f2 \{\ +. ft \\*(f2 +. ds f2\" +' br \} +.el .ie !\\*(f1 \{\ +. ft \\*(f1 +. ds f1\" +' br \} +.el .tm ? font underflow +.. +.ds f1\" +.ds f2\" +.ds f3\" +.ds f4\" +'\" t +.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n +.TH ASTGENKEY 8 "May 14th, 2005" "Asterisk" "Linux Programmer's Manual" +.SH NAME +.B astgenkey +-- generates keys for for Asterisk IAX2 RSA authentication +.SH SYNOPSIS +.PP +.B astgenkey +[ -q ] [ -n ] [ \fIkeyname\fP ] + +.SH DESCRIPTION +.B genzaptelconf +This script generates an RSA private and public key pair in PEM format +for use by Asterisk. The private key should be kept a secret, as it can +be used to fake your system's identity. Thus by default (without the +option +.I -n +) the script will create a passphrase-encrypted copy of your secret key: +without entering the passphrase you won't be able to use it. + +However if you want to use such a key with Asterisk, you'll have to start +it interactively, because the scripts that start asterisk can't use that +encrypted key. + +The key is identified by a name. If you don't write the name on the +command-line you'll be prompted for one. The outputs of the script are: + +.I name\fB.pub +.RS +The public key: not secret. Send this to the other side. +.RE + +.I name\fB.key +.RS +The private key: secret. +.RE + +Those files should be copied to +.I /var/lib/asterisk/keys + +(The private key: on your system. The public key: on other systems) + +To see the currently-installed keys from the asterisk CLI, use the command + +.RS +show keys +.RE + +.SH OPTIONS +.B -q +.RS +Run quietly. +.RE + +.B -n +.RS +Don't encrypt the private key. +.RE + +.SH FILES +.I /var/lib/asterisk/keys +.RS +.RE + +.SH "SEE ALSO" +asterisk(8), genrsa(1), rsa(1), + +http://www.voip-info.org/wiki-Asterisk+iax+rsa+auth + +.SH "AUTHOR" +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- asterisk-1.2.12.1.dfsg.orig/debian/ast_config/manager.conf +++ asterisk-1.2.12.1.dfsg/debian/ast_config/manager.conf @@ -0,0 +1,16 @@ +; +; Asterisk Call Management support +; + +; By default asterisk will listen on localhost only. +[general] +enabled = yes +port = 5038 +bindaddr = 127.0.0.1 + +; No access is allowed by default. +; To set a password, create a file in /etc/asterisk/manager.d +; use creative permission games to allow other serivces to create their own +; files +#include "manager.d/*.conf" + --- asterisk-1.2.12.1.dfsg.orig/debian/ast_config/asterisk.conf +++ asterisk-1.2.12.1.dfsg/debian/ast_config/asterisk.conf @@ -0,0 +1,8 @@ +[global] +astetcdir => /etc/asterisk +astmoddir => /usr/lib/asterisk/modules +astvarlibdir => /var/lib/asterisk +astagidir => /usr/share/asterisk/agi-bin +astspooldir => /var/spool/asterisk +astrundir => /var/run/asterisk +astlogdir => /var/log/asterisk --- asterisk-1.2.12.1.dfsg.orig/debian/ast_config/modules.conf +++ asterisk-1.2.12.1.dfsg/debian/ast_config/modules.conf @@ -0,0 +1,54 @@ +; +; Asterisk configuration file +; +; Module Loader configuration file +; + +[modules] +autoload=yes +; +; Any modules that need to be loaded before the Asterisk core has been +; initialized (just after the logger has been initialized) can be loaded +; using 'preload'. This will frequently be needed if you wish to map all +; module configuration files into Realtime storage, since the Realtime +; driver will need to be loaded before the modules using those configuration +; files are initialized. +; +; An example of loading ODBC support would be: +;preload => res_odbc.so +;preload => res_config_odbc.so +; +; If you want, load the GTK console right away. +; Don't load the KDE console since +; it's not as sophisticated right now. +; +noload => pbx_gtkconsole.so +;load => pbx_gtkconsole.so +noload => pbx_kdeconsole.so +; +; Intercom application is obsoleted by +; chan_oss. Don't load it. +; +noload => app_intercom.so +; +; The 'modem' channel driver and its subdrivers are +; obsolete, don't load them. +; +noload => chan_modem.so +noload => chan_modem_aopen.so +noload => chan_modem_bestdata.so +noload => chan_modem_i4l.so +noload => chan_capi.so +; +load => res_musiconhold.so +; +; Load either OSS or ALSA, not both +; By default, load OSS only (automatically) and do not load ALSA +; +noload => chan_alsa.so +;noload => chan_oss.so +; +; Module names listed in "global" section will have symbols globally +; exported to modules loaded after them. +; +[global] --- asterisk-1.2.12.1.dfsg.orig/debian/astman.1 +++ asterisk-1.2.12.1.dfsg/debian/astman.1 @@ -0,0 +1,102 @@ +.\" $Header: /aolnet/dev/src/CVS/sgml/docbook-to-man/cmd/docbook-to-man.sh,v 1.1.1.1 1998/11/13 21:31:59 db3l Exp $ +.\" +.\" transcript compatibility for postscript use. +.\" +.\" synopsis: .P! +.\" +.de P! +.fl +\!!1 setgray +.fl +\\&.\" +.fl +\!!0 setgray +.fl \" force out current output buffer +\!!save /psv exch def currentpoint translate 0 0 moveto +\!!/showpage{}def +.fl \" prolog +.sy sed \-e 's/^/!/' \\$1\" bring in postscript file +\!!psv restore +. +.de pF +.ie \\*(f1 .ds f1 \\n(.f +.el .ie \\*(f2 .ds f2 \\n(.f +.el .ie \\*(f3 .ds f3 \\n(.f +.el .ie \\*(f4 .ds f4 \\n(.f +.el .tm ? font overflow +.ft \\$1 +.. +.de fP +.ie !\\*(f4 \{\ +. ft \\*(f4 +. ds f4\" +' br \} +.el .ie !\\*(f3 \{\ +. ft \\*(f3 +. ds f3\" +' br \} +.el .ie !\\*(f2 \{\ +. ft \\*(f2 +. ds f2\" +' br \} +.el .ie !\\*(f1 \{\ +. ft \\*(f1 +. ds f1\" +' br \} +.el .tm ? font underflow +.. +.ds f1\" +.ds f2\" +.ds f3\" +.ds f4\" +'\" t +.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n +.TH ASTMAN 1 "Jun 12th, 2005" "astman" "Linux Programmer's Manual" +.SH NAME +.B astman +-- a client to asterisk's manager interface +.SH SYNOPSIS +.PP +.B astman +.I hostname + +.SH DESCRIPTION +.B astman +This program is a full-screen (terminal) client for Asterisk's manager +interface. + +.SH OPTIONS +.B hostname + +The host name or IP address to connect to (TCP port 5038). If astman +fails to connect it will exit immidiately. + +.SH USAGE +If \fBastman\fR has successfully cunnected to the manager port it will +prompt the user for a username and a secret (password) for the manager +interface on the remote Asterisk manager interface. It will then be able +to report existing channels (calls). You will then be able to redirect +calls to or terminate them. + +.SH "SEE ALSO" +asterisk(8) + +http://www.voip-info.org/wiki-Asterisk+astman + +.SH BUGS +The hostname does not default to localhost. + +Impossible to use a port other than 5038. + +The username and password cannot be defined from the command-line. + +I mean, what's the point in a man page if the syntax is so simple? + +.SH "AUTHOR" +This manual page was written by Tzafrir Cohen +Permission is granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-sounds-main.install +++ asterisk-1.2.12.1.dfsg/debian/asterisk-sounds-main.install @@ -0,0 +1,2 @@ +usr/share/asterisk/sounds +usr/share/asterisk/mohmp3 --- asterisk-1.2.12.1.dfsg.orig/debian/asterisk-doc.examples +++ asterisk-1.2.12.1.dfsg/debian/asterisk-doc.examples @@ -0,0 +1,4 @@ +sample.call +configs/* +muted.conf.sample +agi/agi-test.agi