From 2ecfae295feb533e2b3ce1a0aff085e8417bbf09 Mon Sep 17 00:00:00 2001 From: Michael Mason Date: Tue, 31 Mar 2009 22:09:04 +0000 Subject: unstable/hypermail moved to testing/hypermail. replaces old version --- testing/hypermail/APKBUILD | 13 +++--- testing/hypermail/mdir2mbox.lua | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 testing/hypermail/mdir2mbox.lua (limited to 'testing') diff --git a/testing/hypermail/APKBUILD b/testing/hypermail/APKBUILD index 06ddf011cd..6e4f412374 100644 --- a/testing/hypermail/APKBUILD +++ b/testing/hypermail/APKBUILD @@ -1,15 +1,16 @@ # Contributor: Michael Mason pkgname=hypermail -pkgver=2.1.8 +pkgver=2.2.0 pkgrel=0 pkgdesc="Mail Archiver" -url="http://www.hypermail.org" +url="http://www.hypermail-project.org" license="GPL" -depends="uclibc pcre" +depends="uclibc pcre lua" makedepends="pcre-dev bison" install= subpackages="" -source="http://www.hypermail.org/dist/$pkgname-$pkgver.tar.gz" +source="http://www.hypermail-project.org/$pkgname-$pkgver.tar.gz + mdir2mbox.lua" build() { cd "$srcdir/$pkgname-$pkgver" @@ -27,7 +28,9 @@ build() { install -m755 -D archive/rdmsg "$pkgdir"/usr/bin/rdmsg install -m755 -D archive/msg2archive "$pkgdir"/usr/bin/msgarchive install -m755 -D src/hypermail "$pkgdir"/usr/bin/hypermail + install -m755 -D "$srcdir"/mdir2mbox.lua "$pkgdir"/usr/bin/mdir2mbox.lua } -md5sums="bacd95589f2f3ca426631461fd9237dd hypermail-2.1.8.tar.gz" +md5sums="a064e36780ee41409c8c973f9c69927f hypermail-2.2.0.tar.gz +079b00d4ea667a0efd6fd370b1a4d5d8 mdir2mbox.lua" diff --git a/testing/hypermail/mdir2mbox.lua b/testing/hypermail/mdir2mbox.lua new file mode 100644 index 0000000000..dd883e02db --- /dev/null +++ b/testing/hypermail/mdir2mbox.lua @@ -0,0 +1,96 @@ +#!/usr/bin/lua +-- This script takes a mlmmj archive "maildir format" directory and +-- writes out an mbox formatted file to stdout +-- Copyright (c) 2009 N. Angelacos under the GPL 2 License + +require "posix" + +-- command line parser, or exit +check_command_line = function () + local source_dir = arg[1] + local source_time = arg[2] + + if (source_dir == nil ) then + io.stderr:write("mdir2mbox source_dir [hours]\n" .. + "Writes an mbox formatted file to stdout from the files in source_dir\n" .. + "If [hours] is given, then only files newer then [hours] are processed\n") + os.exit(-1) + end + + if (posix.stat(source_dir, "type") ~= "directory") then + io.stderr:write(source_dir .. " is not a directory\n") + os.exit(-1) + end + + return source_dir, source_time +end + +-- Get candidates +get_candidates = function (source, hours) + local all = posix.dir(source) + local candidates = {} + local timestamp = 0 + + if (hours) then + timestamp = os.time() - hours * 3600 + end + + for k,v in ipairs(all) do + local st = posix.stat(source .. "/" .. v) + if (st) and (st.type == "regular") and (st.mtime > timestamp) then + table.insert(candidates,source .. "/" .. v) + end + end + + return candidates +end + +file_to_mbox = function (path) + local fh = io.open(path) + if (fh == nil) then + return + end + local headers = "" + local l = "" + -- get headers + repeat + headers = headers .. l + l = (fh:read("*l") or "" ) .. "\n" + until (#l == 1) + + local from = string.match("\n" .. headers, "\nFrom: ([^\n]*)") + if from == nil then + from = string.match("\n" .. headers, "\nReply-To: ([^\n]*)") + end + if from == nil then + from = "" + end + from = string.match(from, "<([^>]*)>") or string.match(from, "([^ ]*)") + + + local date = string.match("\n" .. headers, "\nDate: ([^\n]*)") + if date == nil then + date = os.date ("%c", posix.stat(path, "mtime")) + end + local weekday,day,month,year,time,offset = string.match(date, "([^,]*), +(%d+) (%a+) (%d+) ([%d:]*) ([%d]*)") + + print ("From " .. from .. " " .. string.format("%s %s %s %s %s", weekday, month, day, time, year, offset )) + print (headers) + + -- get rest of message + repeat + local foo = fh:read("*l") + if foo then + print(foo) + end + until (foo == nil) + +fh:close() +end + +candidates = get_candidates(check_command_line ()) + +for k,v in ipairs(candidates) do + file_to_mbox(v) +end +print ("") -- cgit v1.2.3 From 699f00910ff8c6183a3e8f0dee2d966689e8277c Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Tue, 7 Apr 2009 20:27:00 +0000 Subject: testing/dahdi-linux: rebuild with module symvers --- testing/dahdi-linux/APKBUILD | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'testing') diff --git a/testing/dahdi-linux/APKBUILD b/testing/dahdi-linux/APKBUILD index dea3090f00..2930a7d659 100644 --- a/testing/dahdi-linux/APKBUILD +++ b/testing/dahdi-linux/APKBUILD @@ -4,7 +4,7 @@ pkgname=dahdi-linux _kernflavor=grsec _kernver=2.6.28.9 pkgver=2.1.0.4 -pkgrel=3 +pkgrel=4 pkgdesc="Digium Asterisk Hardware Device Interface drivers" url="http://www.asterisk.org" license="GPL" @@ -26,7 +26,8 @@ build() { local ksrc="/usr/src/linux-$_kernver-$_kernflavor" mkdir -p "$kout" cd "$kout" - cp /usr/share/linux-grsec/config .config + cp /boot/config-grsec .config + cp /boot/Module.symvers-grsec Module.symvers make -C $ksrc O=$PWD silentoldconfig || return 1 make modules_prepare -- cgit v1.2.3 From 0cf28b3f21e699fed107490e6f23d60f594c8939 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 8 Apr 2009 08:37:27 +0000 Subject: testing/dahdi-linux: recompiled for Pentium-classic kernel --- testing/dahdi-linux/APKBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'testing') diff --git a/testing/dahdi-linux/APKBUILD b/testing/dahdi-linux/APKBUILD index 2930a7d659..1ef6c4af1d 100644 --- a/testing/dahdi-linux/APKBUILD +++ b/testing/dahdi-linux/APKBUILD @@ -4,7 +4,7 @@ pkgname=dahdi-linux _kernflavor=grsec _kernver=2.6.28.9 pkgver=2.1.0.4 -pkgrel=4 +pkgrel=5 pkgdesc="Digium Asterisk Hardware Device Interface drivers" url="http://www.asterisk.org" license="GPL" -- cgit v1.2.3 From 8f7626476d0d76494687954a9986912496f87c1e Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Thu, 9 Apr 2009 10:32:38 +0300 Subject: testing/asterisk: update to newer snapshot --- testing/asterisk/APKBUILD | 10 +- .../asterisk/asterisk-03-1.6.1-rc1-i14292.patch | 106423 ------------------ .../asterisk-03-1.6.2.0-beta1-to-r186562.patch | 41697 +++++++ testing/asterisk/asterisk-07-issue14068.patch | 1423 + 4 files changed, 43126 insertions(+), 106427 deletions(-) delete mode 100644 testing/asterisk/asterisk-03-1.6.1-rc1-i14292.patch create mode 100644 testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch create mode 100644 testing/asterisk/asterisk-07-issue14068.patch (limited to 'testing') diff --git a/testing/asterisk/APKBUILD b/testing/asterisk/APKBUILD index 22b70b4c79..39fde65acb 100644 --- a/testing/asterisk/APKBUILD +++ b/testing/asterisk/APKBUILD @@ -1,7 +1,7 @@ # Contributor: Timo Teras # Maintainer: Timo Teras pkgname=asterisk -pkgver=1.6.1-rc1 +pkgver=1.6.2.0-beta1 pkgrel=1 pkgdesc="Asterisk: A Module Open Source PBX System" url="http://www.asterisk.org/" @@ -14,10 +14,11 @@ subpackages="$pkgname-dev $pkgname-doc $pkgname-pgsql $pkgname-odbc" source="http://downloads.digium.com/pub/asterisk/releases/$pkgname-$pkgver.tar.gz asterisk-01-1.6.0-gsm-pic.patch asterisk-02-1.6.0-uclibc.patch - asterisk-03-1.6.1-rc1-i14292.patch + asterisk-03-1.6.2.0-beta1-to-r186562.patch asterisk-04-1.6.0-beta7.1-caps-uclibc.patch asterisk-05-1.6.1-glob-uclibc.patch asterisk-06-overlapped-enum.patch + asterisk-07-issue14068.patch asterisk.pre-install asterisk.post-install asterisk.initd @@ -78,13 +79,14 @@ odbc() { } -md5sums="29f7285b673d52b49d91c8e797acbbb0 asterisk-1.6.1-rc1.tar.gz +md5sums="1a44f295fc9e72d19da7f42d095e6c60 asterisk-1.6.2.0-beta1.tar.gz 97b39fd9777a2521d4f9f095482b7ac2 asterisk-01-1.6.0-gsm-pic.patch 53b0b2a1527972722a50c8c5b560e63e asterisk-02-1.6.0-uclibc.patch -0ea488c4f4412b160b91e5f9bda0498b asterisk-03-1.6.1-rc1-i14292.patch +9f5d2412feea58ed49e2dff5cfd1fb8f asterisk-03-1.6.2.0-beta1-to-r186562.patch 929f740db7043b4553544ebcc7315c91 asterisk-04-1.6.0-beta7.1-caps-uclibc.patch c37928e95ebef36aad097accfdbbfcb8 asterisk-05-1.6.1-glob-uclibc.patch 1b49f980e56dc7ce493a046eadff3545 asterisk-06-overlapped-enum.patch +95bdc48553cc18c9d3807ac96956fc8a asterisk-07-issue14068.patch b4a97cb1ec3cc3f71a10ce8c067ab430 asterisk.pre-install 2188be223f93923e04a8e812cf54e97c asterisk.post-install bbcd152417bb7c838b25cb6007db91da asterisk.initd diff --git a/testing/asterisk/asterisk-03-1.6.1-rc1-i14292.patch b/testing/asterisk/asterisk-03-1.6.1-rc1-i14292.patch deleted file mode 100644 index b61de722d3..0000000000 --- a/testing/asterisk/asterisk-03-1.6.1-rc1-i14292.patch +++ /dev/null @@ -1,106423 +0,0 @@ -Index: .version -=================================================================== ---- a/.version (.../tags/1.6.1-rc1) (revision 178988) -+++ b/.version (.../team/group/issue14292) (revision 178988) -@@ -1 +1 @@ --1.6.1-rc1 -+1.6.1-rc1-issue14292 -Index: .lastclean -Index: build_tools/cflags-devmode.xml -=================================================================== ---- a/build_tools/cflags-devmode.xml (.../tags/1.6.1-rc1) (revision 178988) -+++ b/build_tools/cflags-devmode.xml (.../team/group/issue14292) (revision 178988) -@@ -18,4 +18,6 @@ - - - -+ -+ - -Index: build_tools/cflags.xml -=================================================================== ---- a/build_tools/cflags.xml (.../tags/1.6.1-rc1) (revision 178988) -+++ b/build_tools/cflags.xml (.../team/group/issue14292) (revision 178988) -@@ -22,7 +22,6 @@ - no - - -- yes - G711_NEW_ALGORITHM - - -Index: build_tools/menuselect-deps.in -=================================================================== ---- a/build_tools/menuselect-deps.in (.../tags/1.6.1-rc1) (revision 178988) -+++ b/build_tools/menuselect-deps.in (.../team/group/issue14292) (revision 178988) -@@ -1,8 +1,9 @@ --ASOUND=@PBX_ALSA@ -+ALSA=@PBX_ALSA@ - CRYPTO=@PBX_CRYPTO@ - CURL=@PBX_CURL@ - DAHDI=@PBX_DAHDI@ - FREETDS=@PBX_FREETDS@ -+GENERIC_ODBC=@PBX_GENERIC_ODBC@ - GMIME=@PBX_GMIME@ - GNU_LD=@GNU_LD@ - GSM=@PBX_GSM@ -@@ -13,6 +14,7 @@ - ICONV=@PBX_ICONV@ - IKSEMEL=@PBX_IKSEMEL@ - IMAP_TK=@PBX_IMAP_TK@ -+IODBC=@PBX_IODBC@ - ISDNNET=@PBX_ISDNNET@ - IXJUSER=@PBX_IXJUSER@ - JACK=@PBX_JACK@ -@@ -26,7 +28,7 @@ - OGG=@PBX_OGG@ - OPENH323=@PBX_OPENH323@ - OSPTK=@PBX_OSPTK@ --OSSAUDIO=@PBX_OSS@ -+OSS=@PBX_OSS@ - PGSQL=@PBX_PGSQL@ - POPT=@PBX_POPT@ - PORTAUDIO=@PBX_PORTAUDIO@ -@@ -41,12 +43,13 @@ - SQLITE3=@PBX_SQLITE3@ - SQLITE=@PBX_SQLITE@ - SS7=@PBX_SS7@ --SSL=@PBX_OPENSSL@ -+OPENSSL=@PBX_OPENSSL@ - SUPPSERV=@PBX_SUPPSERV@ - TONEZONE=@PBX_TONEZONE@ - UNIXODBC=@PBX_UNIXODBC@ - USB=@PBX_USB@ - VORBIS=@PBX_VORBIS@ --VPBAPI=@PBX_VPB@ --WINARCH=@WINARCH@ -+VPB=@PBX_VPB@ -+WINARCH=@PBX_WINARCH@ - ZLIB=@PBX_ZLIB@ -+TIMERFD=@PBX_TIMERFD@ -Index: build_tools/get_documentation -=================================================================== ---- a/build_tools/get_documentation (.../tags/1.6.1-rc1) (revision 0) -+++ b/build_tools/get_documentation (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,3 @@ -+/\/\*\*\* DOCUMENTATION/ {printit=1; next} -+/\*\*\*\// {if (printit) exit} -+// {if (printit) print} - -Property changes on: build_tools/get_documentation -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: build_tools/make_buildopts_h -=================================================================== ---- a/build_tools/make_buildopts_h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/build_tools/make_buildopts_h (.../team/group/issue14292) (revision 178988) -@@ -30,5 +30,4 @@ - BUILDSUM=`echo ${TMP} | ${MD5} | cut -c1-32` - - echo "#define AST_BUILDOPT_SUM \"${BUILDSUM}\"" -- - echo "#define AST_BUILDOPTS \"${BUILDOPTS}\"" -Index: phoneprov/polycom.xml -=================================================================== ---- a/phoneprov/polycom.xml (.../tags/1.6.1-rc1) (revision 178988) -+++ b/phoneprov/polycom.xml (.../team/group/issue14292) (revision 178988) -@@ -26,7 +26,7 @@ - - - -- -+ - - - -Index: phoneprov/polycom_line.xml -=================================================================== ---- a/phoneprov/polycom_line.xml (.../tags/1.6.1-rc1) (revision 178988) -+++ b/phoneprov/polycom_line.xml (.../team/group/issue14292) (revision 178988) -@@ -1 +1 @@ --reg.${LINE}.displayName="${DISPLAY_NAME}" reg.${LINE}.address="${USERNAME}" reg.${LINE}.label="${LABEL}" reg.${LINE}.type="private" reg.${LINE}.thirdPartyName="" reg.${LINE}.auth.userId="${USERNAME}" reg.${LINE}.auth.password="${SECRET}" reg.${LINE}.server.1.address="${SERVER}" reg.${LINE}.server.1.port="${SERVER_PORT}" reg.${LINE}.server.1.transport="DNSnaptr" reg.${LINE}.server.1.expires="300" reg.${LINE}.server.1.register="1" reg.${LINE}.server.1.retryTimeOut="" reg.${LINE}.server.1.retryMaxCount="" reg.${LINE}.server.1.expires.lineSeize="" reg.${LINE}.acd-login-logout="0" reg.${LINE}.acd-agent-available="0" reg.${LINE}.ringType="2" reg.${LINE}.lineKeys="1" reg.${LINE}.callsPerLineKey="1" -+reg.${LINE}.displayName="${DISPLAY_NAME}" reg.${LINE}.address="${USERNAME}" reg.${LINE}.label="${LABEL}" reg.${LINE}.type="private" reg.${LINE}.thirdPartyName="" reg.${LINE}.auth.userId="${USERNAME}" reg.${LINE}.auth.password="${SECRET}" reg.${LINE}.server.1.address="${SERVER}" reg.${LINE}.server.1.port="${SERVER_PORT}" reg.${LINE}.server.1.transport="DNSnaptr" reg.${LINE}.server.1.expires="300" reg.${LINE}.server.1.register="1" reg.${LINE}.server.1.retryTimeOut="" reg.${LINE}.server.1.retryMaxCount="" reg.${LINE}.server.1.expires.lineSeize="" reg.${LINE}.acd-login-logout="0" reg.${LINE}.acd-agent-available="0" reg.${LINE}.ringType="2" reg.${LINE}.lineKeys="${LINEKEYS}" reg.${LINE}.callsPerLineKey="1" -Index: phoneprov/000000000000.cfg -=================================================================== ---- a/phoneprov/000000000000.cfg (.../tags/1.6.1-rc1) (revision 178988) -+++ b/phoneprov/000000000000.cfg (.../team/group/issue14292) (revision 178988) -@@ -1,2 +1,2 @@ - -- -+ -Index: configure -=================================================================== ---- a/configure (.../tags/1.6.1-rc1) (revision 178988) -+++ b/configure (.../team/group/issue14292) (revision 178988) -@@ -1,5 +1,5 @@ - #! /bin/sh --# From configure.ac Revision: 163170 . -+# From configure.ac Revision: 177162 . - # Guess values for system-dependent variables and create Makefiles. - # Generated by GNU Autoconf 2.61 for asterisk 1.6. - # -@@ -683,7 +683,7 @@ - HOST_VENDOR - HOST_OS - OSARCH --WINARCH -+PBX_WINARCH - UNAME - PBX_OSREV - CXX -@@ -710,8 +710,10 @@ - LN - DOT - WGET -+CURL - RUBBER - KPATHSEA -+XMLSTARLET - FETCH - DOWNLOAD - SOXMIX -@@ -785,6 +787,14 @@ - IMAP_TK_INCLUDE - IMAP_TK_DIR - PBX_IMAP_TK -+INOTIFY_LIB -+INOTIFY_INCLUDE -+INOTIFY_DIR -+PBX_INOTIFY -+IODBC_LIB -+IODBC_INCLUDE -+IODBC_DIR -+PBX_IODBC - ISDNNET_LIB - ISDNNET_INCLUDE - ISDNNET_DIR -@@ -797,6 +807,10 @@ - LDAP_INCLUDE - LDAP_DIR - PBX_LDAP -+LIBXML2_LIB -+LIBXML2_INCLUDE -+LIBXML2_DIR -+PBX_LIBXML2 - LTDL_LIB - LTDL_INCLUDE - LTDL_DIR -@@ -825,10 +839,6 @@ - NEWT_INCLUDE - NEWT_DIR - PBX_NEWT --UNIXODBC_LIB --UNIXODBC_INCLUDE --UNIXODBC_DIR --PBX_UNIXODBC - OGG_LIB - OGG_INCLUDE - OGG_DIR -@@ -937,6 +947,10 @@ - TONEZONE_INCLUDE - TONEZONE_DIR - PBX_TONEZONE -+UNIXODBC_LIB -+UNIXODBC_INCLUDE -+UNIXODBC_DIR -+PBX_UNIXODBC - USB_LIB - USB_INCLUDE - USB_DIR -@@ -957,8 +971,13 @@ - ZLIB_INCLUDE - ZLIB_DIR - PBX_ZLIB -+TIMERFD_LIB -+TIMERFD_INCLUDE -+TIMERFD_DIR -+PBX_TIMERFD - ALLOCA - LIBOBJS -+PBX_WORKING_FORK - POW_LIB - HAS_POLL - PBX_PTHREAD_RWLOCK_INITIALIZER -@@ -971,7 +990,9 @@ - AST_SHADOW_WARNINGS - PBX_RTLD_NOLOAD - PBX_IP_MTU_DISCOVER -+PBX_DAHDI_HALF_FULL - GSM_INTERNAL -+CONFIG_LIBXML2 - PBX_MISDN_FAC_RESULT - PBX_MISDN_FAC_ERROR - CONFIG_NETSNMP -@@ -997,6 +1018,9 @@ - CONFIG_GTK - PKGCONFIG - CURL_CONFIG -+GENERIC_ODBC_LIB -+GENERIC_ODBC_INCLUDE -+PBX_GENERIC_ODBC - LTLIBOBJS' - ac_subst_files='' - ac_precious_vars='build_alias -@@ -1586,9 +1610,10 @@ - Optional Features: - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] -- --enable-dev-mode Turn on developer mode -+ --enable-dev-mode Turn on developer mode - --disable-largefile omit support for large files -- --enable-internal-poll Use Asterisk's poll implementation -+ --enable-internal-poll Use Asterisk's poll implementation -+ --disable-xmldoc Explicity disable XML documentation - - Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] -@@ -1611,9 +1636,12 @@ - --with-iconv=PATH use Iconv Library files in PATH - --with-iksemel=PATH use Iksemel Jabber Library files in PATH - --with-imap=PATH use UW IMAP Toolkit files in PATH -+ --with-inotify=PATH use inotify support files in PATH -+ --with-iodbc=PATH use iODBC files in PATH - --with-isdnnet=PATH use ISDN4Linux Library files in PATH - --with-jack=PATH use Jack Audio Connection Kit files in PATH - --with-ldap=PATH use OpenLDAP files in PATH -+ --with-libxml2=PATH use LibXML2 files in PATH - --with-ltdl=PATH use libtool files in PATH - --with-lua=PATH use Lua files in PATH - --with-misdn=PATH use mISDN User Library files in PATH -@@ -1621,7 +1649,6 @@ - --with-ncurses=PATH use ncurses files in PATH - --with-netsnmp=PATH use Net-SNMP files in PATH - --with-newt=PATH use newt files in PATH -- --with-odbc=PATH use unixODBC files in PATH - --with-ogg=PATH use OGG files in PATH - --with-osptk=PATH use OSP Toolkit files in PATH - --with-oss=PATH use Open Sound System files in PATH -@@ -1650,11 +1677,13 @@ - --with-termcap=PATH use Termcap files in PATH - --with-tinfo=PATH use Term Info files in PATH - --with-tonezone=PATH use tonezone files in PATH -+ --with-unixodbc=PATH use unixODBC files in PATH - --with-usb=PATH use usb files in PATH - --with-vorbis=PATH use Vorbis files in PATH - --with-vpb=PATH use Voicetronix API files in PATH - --with-x11=PATH use X11 support files in PATH - --with-z=PATH use zlib files in PATH -+ --with-timerfd=PATH use timerfd files in PATH - - Some influential environment variables: - CC C compiler command -@@ -4058,7 +4087,19 @@ - CPPFLAGS=-I/usr/local/include - LDFLAGS=-L/usr/local/lib - ;; -- -+ openbsd*) -+ ac_default_prefix=/usr/local -+ if test ${prefix} = '/usr/local' || test ${prefix} = 'NONE'; then -+ if test ${sysconfdir} = '${prefix}/etc'; then -+ sysconfdir=/etc -+ fi -+ if test ${mandir} = '${prefix}/man'; then -+ mandir=/usr/share/man -+ fi -+ fi -+ CPPFLAGS=-I/usr/local/include -+ LDFLAGS=-L/usr/local/lib -+ ;; - *) - ac_default_prefix=/usr - if test ${prefix} = '/usr' || test ${prefix} = 'NONE'; then -@@ -4096,7 +4137,7 @@ - - - --WINARCH=0 -+PBX_WINARCH=0 - - case "${host_os}" in - freebsd*) -@@ -4113,11 +4154,11 @@ - ;; - mingw32) - OSARCH=mingw32 -- WINARCH=1 -+ PBX_WINARCH=1 - ;; - cygwin) - OSARCH=cygwin -- WINARCH=1 -+ PBX_WINARCH=1 - ;; - *) - OSARCH=${host_os} -@@ -6140,6 +6181,7 @@ - done - echo "$ac_script" | sed 99q >conftest.sed - $as_unset ac_script || ac_script= -+ - # Extract the first word of "sed gsed" to use in msg output - if test -z "$SED"; then - set dummy sed gsed; ac_prog_name=$2 -@@ -7215,6 +7257,47 @@ - fi - - -+# Extract the first word of "curl", so it can be a program name with args. -+set dummy curl; ac_word=$2 -+{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -+if test "${ac_cv_path_CURL+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ case $CURL in -+ [\\/]* | ?:[\\/]*) -+ ac_cv_path_CURL="$CURL" # Let the user override the test with a path. -+ ;; -+ *) -+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+for as_dir in $PATH -+do -+ IFS=$as_save_IFS -+ test -z "$as_dir" && as_dir=. -+ for ac_exec_ext in '' $ac_executable_extensions; do -+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then -+ ac_cv_path_CURL="$as_dir/$ac_word$ac_exec_ext" -+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 -+ break 2 -+ fi -+done -+done -+IFS=$as_save_IFS -+ -+ test -z "$ac_cv_path_CURL" && ac_cv_path_CURL=":" -+ ;; -+esac -+fi -+CURL=$ac_cv_path_CURL -+if test -n "$CURL"; then -+ { echo "$as_me:$LINENO: result: $CURL" >&5 -+echo "${ECHO_T}$CURL" >&6; } -+else -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+fi -+ -+ - # Extract the first word of "rubber", so it can be a program name with args. - set dummy rubber; ac_word=$2 - { echo "$as_me:$LINENO: checking for $ac_word" >&5 -@@ -7297,8 +7380,51 @@ - fi - - -+# Extract the first word of "xmlstarlet", so it can be a program name with args. -+set dummy xmlstarlet; ac_word=$2 -+{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -+if test "${ac_cv_path_XMLSTARLET+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ case $XMLSTARLET in -+ [\\/]* | ?:[\\/]*) -+ ac_cv_path_XMLSTARLET="$XMLSTARLET" # Let the user override the test with a path. -+ ;; -+ *) -+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+for as_dir in $PATH -+do -+ IFS=$as_save_IFS -+ test -z "$as_dir" && as_dir=. -+ for ac_exec_ext in '' $ac_executable_extensions; do -+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then -+ ac_cv_path_XMLSTARLET="$as_dir/$ac_word$ac_exec_ext" -+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 -+ break 2 -+ fi -+done -+done -+IFS=$as_save_IFS -+ -+ test -z "$ac_cv_path_XMLSTARLET" && ac_cv_path_XMLSTARLET=":" -+ ;; -+esac -+fi -+XMLSTARLET=$ac_cv_path_XMLSTARLET -+if test -n "$XMLSTARLET"; then -+ { echo "$as_me:$LINENO: result: $XMLSTARLET" >&5 -+echo "${ECHO_T}$XMLSTARLET" >&6; } -+else -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+fi -+ -+ - if test "${WGET}" != ":" ; then - DOWNLOAD=${WGET} -+else if test "${CURL}" != ":" ; then -+ DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" - else - # Extract the first word of "fetch", so it can be a program name with args. - set dummy fetch; ac_word=$2 -@@ -7343,6 +7469,7 @@ - - DOWNLOAD=${FETCH} - fi -+fi - - - if test -n "$ac_tool_prefix"; then -@@ -7959,6 +8086,7 @@ - - ALSA_DESCRIP="Advanced Linux Sound Architecture" - ALSA_OPTION="asound" -+ PBX_ALSA=0 - - # Check whether --with-asound was given. - if test "${with_asound+set}" = set; then -@@ -7966,6 +8094,9 @@ - case ${withval} in - n|no) - USE_ALSA=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_ALSA=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} ALSA" -@@ -7978,7 +8109,6 @@ - - fi - -- PBX_ALSA=0 - - - -@@ -7990,6 +8120,7 @@ - - BKTR_DESCRIP="Stack Backtrace support" - BKTR_OPTION="execinfo" -+ PBX_BKTR=0 - - # Check whether --with-execinfo was given. - if test "${with_execinfo+set}" = set; then -@@ -7997,6 +8128,9 @@ - case ${withval} in - n|no) - USE_BKTR=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_BKTR=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} BKTR" -@@ -8009,7 +8143,6 @@ - - fi - -- PBX_BKTR=0 - - - -@@ -8018,6 +8151,7 @@ - - CAP_DESCRIP="POSIX 1.e capabilities" - CAP_OPTION="cap" -+ PBX_CAP=0 - - # Check whether --with-cap was given. - if test "${with_cap+set}" = set; then -@@ -8025,6 +8159,9 @@ - case ${withval} in - n|no) - USE_CAP=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_CAP=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} CAP" -@@ -8037,7 +8174,6 @@ - - fi - -- PBX_CAP=0 - - - -@@ -8046,6 +8182,7 @@ - - CURL_DESCRIP="cURL" - CURL_OPTION="curl" -+ PBX_CURL=0 - - # Check whether --with-curl was given. - if test "${with_curl+set}" = set; then -@@ -8053,6 +8190,9 @@ - case ${withval} in - n|no) - USE_CURL=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_CURL=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} CURL" -@@ -8065,7 +8205,6 @@ - - fi - -- PBX_CURL=0 - - - -@@ -8074,6 +8213,7 @@ - - CURSES_DESCRIP="curses" - CURSES_OPTION="curses" -+ PBX_CURSES=0 - - # Check whether --with-curses was given. - if test "${with_curses+set}" = set; then -@@ -8081,6 +8221,9 @@ - case ${withval} in - n|no) - USE_CURSES=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_CURSES=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} CURSES" -@@ -8093,7 +8236,6 @@ - - fi - -- PBX_CURSES=0 - - - -@@ -8102,6 +8244,7 @@ - - CRYPTO_DESCRIP="OpenSSL Cryptography support" - CRYPTO_OPTION="crypto" -+ PBX_CRYPTO=0 - - # Check whether --with-crypto was given. - if test "${with_crypto+set}" = set; then -@@ -8109,6 +8252,9 @@ - case ${withval} in - n|no) - USE_CRYPTO=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_CRYPTO=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} CRYPTO" -@@ -8121,7 +8267,6 @@ - - fi - -- PBX_CRYPTO=0 - - - -@@ -8130,6 +8275,7 @@ - - DAHDI_DESCRIP="DAHDI" - DAHDI_OPTION="dahdi" -+ PBX_DAHDI=0 - - # Check whether --with-dahdi was given. - if test "${with_dahdi+set}" = set; then -@@ -8137,6 +8283,9 @@ - case ${withval} in - n|no) - USE_DAHDI=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_DAHDI=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} DAHDI" -@@ -8149,7 +8298,6 @@ - - fi - -- PBX_DAHDI=0 - - - -@@ -8158,6 +8306,7 @@ - - FFMPEG_DESCRIP="Ffmpeg and avcodec library" - FFMPEG_OPTION="avcodec" -+ PBX_FFMPEG=0 - - # Check whether --with-avcodec was given. - if test "${with_avcodec+set}" = set; then -@@ -8165,6 +8314,9 @@ - case ${withval} in - n|no) - USE_FFMPEG=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_FFMPEG=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} FFMPEG" -@@ -8177,7 +8329,6 @@ - - fi - -- PBX_FFMPEG=0 - - - -@@ -8186,6 +8337,7 @@ - - GSM_DESCRIP="External GSM library" - GSM_OPTION="gsm" -+ PBX_GSM=0 - - # Check whether --with-gsm was given. - if test "${with_gsm+set}" = set; then -@@ -8193,6 +8345,9 @@ - case ${withval} in - n|no) - USE_GSM=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_GSM=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} GSM" -@@ -8205,7 +8360,6 @@ - - fi - -- PBX_GSM=0 - - - -@@ -8214,6 +8368,7 @@ - - GTK_DESCRIP="gtk libraries" - GTK_OPTION="gtk" -+ PBX_GTK=0 - - # Check whether --with-gtk was given. - if test "${with_gtk+set}" = set; then -@@ -8221,6 +8376,9 @@ - case ${withval} in - n|no) - USE_GTK=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_GTK=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} GTK" -@@ -8233,7 +8391,6 @@ - - fi - -- PBX_GTK=0 - - - -@@ -8242,6 +8399,7 @@ - - GTK2_DESCRIP="gtk2 libraries" - GTK2_OPTION="gtk2" -+ PBX_GTK2=0 - - # Check whether --with-gtk2 was given. - if test "${with_gtk2+set}" = set; then -@@ -8249,6 +8407,9 @@ - case ${withval} in - n|no) - USE_GTK2=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_GTK2=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} GTK2" -@@ -8261,7 +8422,6 @@ - - fi - -- PBX_GTK2=0 - - - -@@ -8270,6 +8430,7 @@ - - GMIME_DESCRIP="GMime library" - GMIME_OPTION="gmime" -+ PBX_GMIME=0 - - # Check whether --with-gmime was given. - if test "${with_gmime+set}" = set; then -@@ -8277,6 +8438,9 @@ - case ${withval} in - n|no) - USE_GMIME=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_GMIME=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} GMIME" -@@ -8289,7 +8453,6 @@ - - fi - -- PBX_GMIME=0 - - - -@@ -8298,6 +8461,7 @@ - - HOARD_DESCRIP="Hoard Memory Allocator" - HOARD_OPTION="hoard" -+ PBX_HOARD=0 - - # Check whether --with-hoard was given. - if test "${with_hoard+set}" = set; then -@@ -8305,6 +8469,9 @@ - case ${withval} in - n|no) - USE_HOARD=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_HOARD=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} HOARD" -@@ -8317,7 +8484,6 @@ - - fi - -- PBX_HOARD=0 - - - -@@ -8326,6 +8492,7 @@ - - ICONV_DESCRIP="Iconv Library" - ICONV_OPTION="iconv" -+ PBX_ICONV=0 - - # Check whether --with-iconv was given. - if test "${with_iconv+set}" = set; then -@@ -8333,6 +8500,9 @@ - case ${withval} in - n|no) - USE_ICONV=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_ICONV=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} ICONV" -@@ -8345,7 +8515,6 @@ - - fi - -- PBX_ICONV=0 - - - -@@ -8354,6 +8523,7 @@ - - IKSEMEL_DESCRIP="Iksemel Jabber Library" - IKSEMEL_OPTION="iksemel" -+ PBX_IKSEMEL=0 - - # Check whether --with-iksemel was given. - if test "${with_iksemel+set}" = set; then -@@ -8361,6 +8531,9 @@ - case ${withval} in - n|no) - USE_IKSEMEL=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_IKSEMEL=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} IKSEMEL" -@@ -8373,7 +8546,6 @@ - - fi - -- PBX_IKSEMEL=0 - - - -@@ -8382,6 +8554,7 @@ - - IMAP_TK_DESCRIP="UW IMAP Toolkit" - IMAP_TK_OPTION="imap" -+ PBX_IMAP_TK=0 - - # Check whether --with-imap was given. - if test "${with_imap+set}" = set; then -@@ -8389,6 +8562,9 @@ - case ${withval} in - n|no) - USE_IMAP_TK=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_IMAP_TK=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} IMAP_TK" -@@ -8401,15 +8577,77 @@ - - fi - -- PBX_IMAP_TK=0 - - - - - - -+ INOTIFY_DESCRIP="inotify support" -+ INOTIFY_OPTION="inotify" -+ PBX_INOTIFY=0 -+ -+# Check whether --with-inotify was given. -+if test "${with_inotify+set}" = set; then -+ withval=$with_inotify; -+ case ${withval} in -+ n|no) -+ USE_INOTIFY=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_INOTIFY=-1 -+ ;; -+ y|ye|yes) -+ ac_mandatory_list="${ac_mandatory_list} INOTIFY" -+ ;; -+ *) -+ INOTIFY_DIR="${withval}" -+ ac_mandatory_list="${ac_mandatory_list} INOTIFY" -+ ;; -+ esac -+ -+fi -+ -+ -+ -+ -+ -+ -+ -+ IODBC_DESCRIP="iODBC" -+ IODBC_OPTION="iodbc" -+ PBX_IODBC=0 -+ -+# Check whether --with-iodbc was given. -+if test "${with_iodbc+set}" = set; then -+ withval=$with_iodbc; -+ case ${withval} in -+ n|no) -+ USE_IODBC=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_IODBC=-1 -+ ;; -+ y|ye|yes) -+ ac_mandatory_list="${ac_mandatory_list} IODBC" -+ ;; -+ *) -+ IODBC_DIR="${withval}" -+ ac_mandatory_list="${ac_mandatory_list} IODBC" -+ ;; -+ esac -+ -+fi -+ -+ -+ -+ -+ -+ -+ - ISDNNET_DESCRIP="ISDN4Linux Library" - ISDNNET_OPTION="isdnnet" -+ PBX_ISDNNET=0 - - # Check whether --with-isdnnet was given. - if test "${with_isdnnet+set}" = set; then -@@ -8417,6 +8655,9 @@ - case ${withval} in - n|no) - USE_ISDNNET=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_ISDNNET=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} ISDNNET" -@@ -8429,7 +8670,6 @@ - - fi - -- PBX_ISDNNET=0 - - - -@@ -8438,6 +8678,7 @@ - - JACK_DESCRIP="Jack Audio Connection Kit" - JACK_OPTION="jack" -+ PBX_JACK=0 - - # Check whether --with-jack was given. - if test "${with_jack+set}" = set; then -@@ -8445,6 +8686,9 @@ - case ${withval} in - n|no) - USE_JACK=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_JACK=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} JACK" -@@ -8457,7 +8701,6 @@ - - fi - -- PBX_JACK=0 - - - -@@ -8466,6 +8709,7 @@ - - LDAP_DESCRIP="OpenLDAP" - LDAP_OPTION="ldap" -+ PBX_LDAP=0 - - # Check whether --with-ldap was given. - if test "${with_ldap+set}" = set; then -@@ -8473,6 +8717,9 @@ - case ${withval} in - n|no) - USE_LDAP=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_LDAP=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} LDAP" -@@ -8485,15 +8732,46 @@ - - fi - -- PBX_LDAP=0 - - - - - - -+ LIBXML2_DESCRIP="LibXML2" -+ LIBXML2_OPTION="libxml2" -+ PBX_LIBXML2=0 -+ -+# Check whether --with-libxml2 was given. -+if test "${with_libxml2+set}" = set; then -+ withval=$with_libxml2; -+ case ${withval} in -+ n|no) -+ USE_LIBXML2=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_LIBXML2=-1 -+ ;; -+ y|ye|yes) -+ ac_mandatory_list="${ac_mandatory_list} LIBXML2" -+ ;; -+ *) -+ LIBXML2_DIR="${withval}" -+ ac_mandatory_list="${ac_mandatory_list} LIBXML2" -+ ;; -+ esac -+ -+fi -+ -+ -+ -+ -+ -+ -+ - LTDL_DESCRIP="libtool" - LTDL_OPTION="ltdl" -+ PBX_LTDL=0 - - # Check whether --with-ltdl was given. - if test "${with_ltdl+set}" = set; then -@@ -8501,6 +8779,9 @@ - case ${withval} in - n|no) - USE_LTDL=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_LTDL=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} LTDL" -@@ -8513,7 +8794,6 @@ - - fi - -- PBX_LTDL=0 - - - -@@ -8522,6 +8802,7 @@ - - LUA_DESCRIP="Lua" - LUA_OPTION="lua" -+ PBX_LUA=0 - - # Check whether --with-lua was given. - if test "${with_lua+set}" = set; then -@@ -8529,6 +8810,9 @@ - case ${withval} in - n|no) - USE_LUA=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_LUA=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} LUA" -@@ -8541,7 +8825,6 @@ - - fi - -- PBX_LUA=0 - - - -@@ -8550,6 +8833,7 @@ - - MISDN_DESCRIP="mISDN User Library" - MISDN_OPTION="misdn" -+ PBX_MISDN=0 - - # Check whether --with-misdn was given. - if test "${with_misdn+set}" = set; then -@@ -8557,6 +8841,9 @@ - case ${withval} in - n|no) - USE_MISDN=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_MISDN=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} MISDN" -@@ -8569,7 +8856,6 @@ - - fi - -- PBX_MISDN=0 - - - -@@ -8578,6 +8864,7 @@ - - NBS_DESCRIP="Network Broadcast Sound" - NBS_OPTION="nbs" -+ PBX_NBS=0 - - # Check whether --with-nbs was given. - if test "${with_nbs+set}" = set; then -@@ -8585,6 +8872,9 @@ - case ${withval} in - n|no) - USE_NBS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_NBS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} NBS" -@@ -8597,7 +8887,6 @@ - - fi - -- PBX_NBS=0 - - - -@@ -8606,6 +8895,7 @@ - - NCURSES_DESCRIP="ncurses" - NCURSES_OPTION="ncurses" -+ PBX_NCURSES=0 - - # Check whether --with-ncurses was given. - if test "${with_ncurses+set}" = set; then -@@ -8613,6 +8903,9 @@ - case ${withval} in - n|no) - USE_NCURSES=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_NCURSES=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} NCURSES" -@@ -8625,7 +8918,6 @@ - - fi - -- PBX_NCURSES=0 - - - -@@ -8634,6 +8926,7 @@ - - NETSNMP_DESCRIP="Net-SNMP" - NETSNMP_OPTION="netsnmp" -+ PBX_NETSNMP=0 - - # Check whether --with-netsnmp was given. - if test "${with_netsnmp+set}" = set; then -@@ -8641,6 +8934,9 @@ - case ${withval} in - n|no) - USE_NETSNMP=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_NETSNMP=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} NETSNMP" -@@ -8653,7 +8949,6 @@ - - fi - -- PBX_NETSNMP=0 - - - -@@ -8662,6 +8957,7 @@ - - NEWT_DESCRIP="newt" - NEWT_OPTION="newt" -+ PBX_NEWT=0 - - # Check whether --with-newt was given. - if test "${with_newt+set}" = set; then -@@ -8669,6 +8965,9 @@ - case ${withval} in - n|no) - USE_NEWT=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_NEWT=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} NEWT" -@@ -8681,43 +8980,15 @@ - - fi - -- PBX_NEWT=0 - - - - - - -- UNIXODBC_DESCRIP="unixODBC" -- UNIXODBC_OPTION="odbc" -- --# Check whether --with-odbc was given. --if test "${with_odbc+set}" = set; then -- withval=$with_odbc; -- case ${withval} in -- n|no) -- USE_UNIXODBC=no -- ;; -- y|ye|yes) -- ac_mandatory_list="${ac_mandatory_list} UNIXODBC" -- ;; -- *) -- UNIXODBC_DIR="${withval}" -- ac_mandatory_list="${ac_mandatory_list} UNIXODBC" -- ;; -- esac -- --fi -- -- PBX_UNIXODBC=0 -- -- -- -- -- -- - OGG_DESCRIP="OGG" - OGG_OPTION="ogg" -+ PBX_OGG=0 - - # Check whether --with-ogg was given. - if test "${with_ogg+set}" = set; then -@@ -8725,6 +8996,9 @@ - case ${withval} in - n|no) - USE_OGG=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_OGG=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OGG" -@@ -8737,7 +9011,6 @@ - - fi - -- PBX_OGG=0 - - - -@@ -8746,6 +9019,7 @@ - - OSPTK_DESCRIP="OSP Toolkit" - OSPTK_OPTION="osptk" -+ PBX_OSPTK=0 - - # Check whether --with-osptk was given. - if test "${with_osptk+set}" = set; then -@@ -8753,6 +9027,9 @@ - case ${withval} in - n|no) - USE_OSPTK=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_OSPTK=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OSPTK" -@@ -8765,7 +9042,6 @@ - - fi - -- PBX_OSPTK=0 - - - -@@ -8774,6 +9050,7 @@ - - OSS_DESCRIP="Open Sound System" - OSS_OPTION="oss" -+ PBX_OSS=0 - - # Check whether --with-oss was given. - if test "${with_oss+set}" = set; then -@@ -8781,6 +9058,9 @@ - case ${withval} in - n|no) - USE_OSS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_OSS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OSS" -@@ -8793,7 +9073,6 @@ - - fi - -- PBX_OSS=0 - - - -@@ -8802,6 +9081,7 @@ - - PGSQL_DESCRIP="PostgreSQL" - PGSQL_OPTION="postgres" -+ PBX_PGSQL=0 - - # Check whether --with-postgres was given. - if test "${with_postgres+set}" = set; then -@@ -8809,6 +9089,9 @@ - case ${withval} in - n|no) - USE_PGSQL=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_PGSQL=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} PGSQL" -@@ -8821,7 +9104,6 @@ - - fi - -- PBX_PGSQL=0 - - - -@@ -8830,6 +9112,7 @@ - - POPT_DESCRIP="popt" - POPT_OPTION="popt" -+ PBX_POPT=0 - - # Check whether --with-popt was given. - if test "${with_popt+set}" = set; then -@@ -8837,6 +9120,9 @@ - case ${withval} in - n|no) - USE_POPT=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_POPT=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} POPT" -@@ -8849,7 +9135,6 @@ - - fi - -- PBX_POPT=0 - - - -@@ -8858,6 +9143,7 @@ - - PORTAUDIO_DESCRIP="PortAudio" - PORTAUDIO_OPTION="portaudio" -+ PBX_PORTAUDIO=0 - - # Check whether --with-portaudio was given. - if test "${with_portaudio+set}" = set; then -@@ -8865,6 +9151,9 @@ - case ${withval} in - n|no) - USE_PORTAUDIO=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_PORTAUDIO=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} PORTAUDIO" -@@ -8877,7 +9166,6 @@ - - fi - -- PBX_PORTAUDIO=0 - - - -@@ -8886,6 +9174,7 @@ - - PRI_DESCRIP="ISDN PRI" - PRI_OPTION="pri" -+ PBX_PRI=0 - - # Check whether --with-pri was given. - if test "${with_pri+set}" = set; then -@@ -8893,6 +9182,9 @@ - case ${withval} in - n|no) - USE_PRI=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_PRI=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} PRI" -@@ -8905,7 +9197,6 @@ - - fi - -- PBX_PRI=0 - - - -@@ -8914,6 +9205,7 @@ - - RESAMPLE_DESCRIP="LIBRESAMPLE" - RESAMPLE_OPTION="resample" -+ PBX_RESAMPLE=0 - - # Check whether --with-resample was given. - if test "${with_resample+set}" = set; then -@@ -8921,6 +9213,9 @@ - case ${withval} in - n|no) - USE_RESAMPLE=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_RESAMPLE=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} RESAMPLE" -@@ -8933,7 +9228,6 @@ - - fi - -- PBX_RESAMPLE=0 - - - -@@ -8942,6 +9236,7 @@ - - SPANDSP_DESCRIP="SPANDSP" - SPANDSP_OPTION="spandsp" -+ PBX_SPANDSP=0 - - # Check whether --with-spandsp was given. - if test "${with_spandsp+set}" = set; then -@@ -8949,6 +9244,9 @@ - case ${withval} in - n|no) - USE_SPANDSP=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SPANDSP=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SPANDSP" -@@ -8961,7 +9259,6 @@ - - fi - -- PBX_SPANDSP=0 - - - -@@ -8970,6 +9267,7 @@ - - SS7_DESCRIP="ISDN SS7" - SS7_OPTION="ss7" -+ PBX_SS7=0 - - # Check whether --with-ss7 was given. - if test "${with_ss7+set}" = set; then -@@ -8977,6 +9275,9 @@ - case ${withval} in - n|no) - USE_SS7=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SS7=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SS7" -@@ -8989,7 +9290,6 @@ - - fi - -- PBX_SS7=0 - - - -@@ -8998,6 +9298,7 @@ - - PWLIB_DESCRIP="PWlib" - PWLIB_OPTION="pwlib" -+ PBX_PWLIB=0 - - # Check whether --with-pwlib was given. - if test "${with_pwlib+set}" = set; then -@@ -9005,6 +9306,9 @@ - case ${withval} in - n|no) - USE_PWLIB=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_PWLIB=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} PWLIB" -@@ -9017,7 +9321,6 @@ - - fi - -- PBX_PWLIB=0 - - - -@@ -9026,6 +9329,7 @@ - - OPENH323_DESCRIP="OpenH323" - OPENH323_OPTION="h323" -+ PBX_OPENH323=0 - - # Check whether --with-h323 was given. - if test "${with_h323+set}" = set; then -@@ -9033,6 +9337,9 @@ - case ${withval} in - n|no) - USE_OPENH323=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_OPENH323=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OPENH323" -@@ -9045,7 +9352,6 @@ - - fi - -- PBX_OPENH323=0 - - - -@@ -9054,6 +9360,7 @@ - - RADIUS_DESCRIP="Radius Client" - RADIUS_OPTION="radius" -+ PBX_RADIUS=0 - - # Check whether --with-radius was given. - if test "${with_radius+set}" = set; then -@@ -9061,6 +9368,9 @@ - case ${withval} in - n|no) - USE_RADIUS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_RADIUS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} RADIUS" -@@ -9073,7 +9383,6 @@ - - fi - -- PBX_RADIUS=0 - - - -@@ -9082,6 +9391,7 @@ - - SDL_DESCRIP="Sdl" - SDL_OPTION="sdl" -+ PBX_SDL=0 - - # Check whether --with-sdl was given. - if test "${with_sdl+set}" = set; then -@@ -9089,6 +9399,9 @@ - case ${withval} in - n|no) - USE_SDL=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SDL=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SDL" -@@ -9101,7 +9414,6 @@ - - fi - -- PBX_SDL=0 - - - -@@ -9110,6 +9422,7 @@ - - SDL_IMAGE_DESCRIP="Sdl Image library" - SDL_IMAGE_OPTION="SDL_image" -+ PBX_SDL_IMAGE=0 - - # Check whether --with-SDL_image was given. - if test "${with_SDL_image+set}" = set; then -@@ -9117,6 +9430,9 @@ - case ${withval} in - n|no) - USE_SDL_IMAGE=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SDL_IMAGE=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SDL_IMAGE" -@@ -9129,7 +9445,6 @@ - - fi - -- PBX_SDL_IMAGE=0 - - - -@@ -9138,6 +9453,7 @@ - - OPENAIS_DESCRIP="OpenAIS" - OPENAIS_OPTION="openais" -+ PBX_OPENAIS=0 - - # Check whether --with-openais was given. - if test "${with_openais+set}" = set; then -@@ -9145,6 +9461,9 @@ - case ${withval} in - n|no) - USE_OPENAIS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_OPENAIS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OPENAIS" -@@ -9157,7 +9476,6 @@ - - fi - -- PBX_OPENAIS=0 - - - -@@ -9166,6 +9484,7 @@ - - SPEEX_DESCRIP="Speex" - SPEEX_OPTION="speex" -+ PBX_SPEEX=0 - - # Check whether --with-speex was given. - if test "${with_speex+set}" = set; then -@@ -9173,6 +9492,9 @@ - case ${withval} in - n|no) - USE_SPEEX=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SPEEX=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SPEEX" -@@ -9185,7 +9507,6 @@ - - fi - -- PBX_SPEEX=0 - - - -@@ -9194,6 +9515,7 @@ - - SPEEX_PREPROCESS_DESCRIP="Speex preprocess routines" - SPEEX_PREPROCESS_OPTION="speex" -+ PBX_SPEEX_PREPROCESS=0 - - # Check whether --with-speex was given. - if test "${with_speex+set}" = set; then -@@ -9201,6 +9523,9 @@ - case ${withval} in - n|no) - USE_SPEEX_PREPROCESS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SPEEX_PREPROCESS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SPEEX_PREPROCESS" -@@ -9213,7 +9538,6 @@ - - fi - -- PBX_SPEEX_PREPROCESS=0 - - - -@@ -9222,6 +9546,7 @@ - - SPEEXDSP_DESCRIP="Speexdsp" - SPEEXDSP_OPTION="speexdsp" -+ PBX_SPEEXDSP=0 - - # Check whether --with-speexdsp was given. - if test "${with_speexdsp+set}" = set; then -@@ -9229,6 +9554,9 @@ - case ${withval} in - n|no) - USE_SPEEXDSP=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SPEEXDSP=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SPEEXDSP" -@@ -9241,7 +9569,6 @@ - - fi - -- PBX_SPEEXDSP=0 - - - -@@ -9250,6 +9577,7 @@ - - SQLITE_DESCRIP="SQLite" - SQLITE_OPTION="sqlite" -+ PBX_SQLITE=0 - - # Check whether --with-sqlite was given. - if test "${with_sqlite+set}" = set; then -@@ -9257,6 +9585,9 @@ - case ${withval} in - n|no) - USE_SQLITE=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SQLITE=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SQLITE" -@@ -9269,7 +9600,6 @@ - - fi - -- PBX_SQLITE=0 - - - -@@ -9278,6 +9608,7 @@ - - SQLITE3_DESCRIP="SQLite" - SQLITE3_OPTION="sqlite3" -+ PBX_SQLITE3=0 - - # Check whether --with-sqlite3 was given. - if test "${with_sqlite3+set}" = set; then -@@ -9285,6 +9616,9 @@ - case ${withval} in - n|no) - USE_SQLITE3=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SQLITE3=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SQLITE3" -@@ -9297,7 +9631,6 @@ - - fi - -- PBX_SQLITE3=0 - - - -@@ -9306,6 +9639,7 @@ - - SUPPSERV_DESCRIP="mISDN Supplemental Services" - SUPPSERV_OPTION="suppserv" -+ PBX_SUPPSERV=0 - - # Check whether --with-suppserv was given. - if test "${with_suppserv+set}" = set; then -@@ -9313,6 +9647,9 @@ - case ${withval} in - n|no) - USE_SUPPSERV=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_SUPPSERV=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} SUPPSERV" -@@ -9325,7 +9662,6 @@ - - fi - -- PBX_SUPPSERV=0 - - - -@@ -9334,6 +9670,7 @@ - - OPENSSL_DESCRIP="OpenSSL Secure Sockets Layer support" - OPENSSL_OPTION="ssl" -+ PBX_OPENSSL=0 - - # Check whether --with-ssl was given. - if test "${with_ssl+set}" = set; then -@@ -9341,6 +9678,9 @@ - case ${withval} in - n|no) - USE_OPENSSL=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_OPENSSL=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} OPENSSL" -@@ -9353,7 +9693,6 @@ - - fi - -- PBX_OPENSSL=0 - - - -@@ -9362,6 +9701,7 @@ - - FREETDS_DESCRIP="FreeTDS" - FREETDS_OPTION="tds" -+ PBX_FREETDS=0 - - # Check whether --with-tds was given. - if test "${with_tds+set}" = set; then -@@ -9369,6 +9709,9 @@ - case ${withval} in - n|no) - USE_FREETDS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_FREETDS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} FREETDS" -@@ -9381,7 +9724,6 @@ - - fi - -- PBX_FREETDS=0 - - - -@@ -9390,6 +9732,7 @@ - - TERMCAP_DESCRIP="Termcap" - TERMCAP_OPTION="termcap" -+ PBX_TERMCAP=0 - - # Check whether --with-termcap was given. - if test "${with_termcap+set}" = set; then -@@ -9397,6 +9740,9 @@ - case ${withval} in - n|no) - USE_TERMCAP=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_TERMCAP=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} TERMCAP" -@@ -9409,7 +9755,6 @@ - - fi - -- PBX_TERMCAP=0 - - - -@@ -9418,6 +9763,7 @@ - - TINFO_DESCRIP="Term Info" - TINFO_OPTION="tinfo" -+ PBX_TINFO=0 - - # Check whether --with-tinfo was given. - if test "${with_tinfo+set}" = set; then -@@ -9425,6 +9771,9 @@ - case ${withval} in - n|no) - USE_TINFO=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_TINFO=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} TINFO" -@@ -9437,7 +9786,6 @@ - - fi - -- PBX_TINFO=0 - - - -@@ -9446,6 +9794,7 @@ - - TONEZONE_DESCRIP="tonezone" - TONEZONE_OPTION="tonezone" -+ PBX_TONEZONE=0 - - # Check whether --with-tonezone was given. - if test "${with_tonezone+set}" = set; then -@@ -9453,6 +9802,9 @@ - case ${withval} in - n|no) - USE_TONEZONE=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_TONEZONE=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} TONEZONE" -@@ -9465,15 +9817,46 @@ - - fi - -- PBX_TONEZONE=0 - - - - - - -+ UNIXODBC_DESCRIP="unixODBC" -+ UNIXODBC_OPTION="unixodbc" -+ PBX_UNIXODBC=0 -+ -+# Check whether --with-unixodbc was given. -+if test "${with_unixodbc+set}" = set; then -+ withval=$with_unixodbc; -+ case ${withval} in -+ n|no) -+ USE_UNIXODBC=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_UNIXODBC=-1 -+ ;; -+ y|ye|yes) -+ ac_mandatory_list="${ac_mandatory_list} UNIXODBC" -+ ;; -+ *) -+ UNIXODBC_DIR="${withval}" -+ ac_mandatory_list="${ac_mandatory_list} UNIXODBC" -+ ;; -+ esac -+ -+fi -+ -+ -+ -+ -+ -+ -+ - USB_DESCRIP="usb" - USB_OPTION="usb" -+ PBX_USB=0 - - # Check whether --with-usb was given. - if test "${with_usb+set}" = set; then -@@ -9481,6 +9864,9 @@ - case ${withval} in - n|no) - USE_USB=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_USB=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} USB" -@@ -9493,7 +9879,6 @@ - - fi - -- PBX_USB=0 - - - -@@ -9502,6 +9887,7 @@ - - VORBIS_DESCRIP="Vorbis" - VORBIS_OPTION="vorbis" -+ PBX_VORBIS=0 - - # Check whether --with-vorbis was given. - if test "${with_vorbis+set}" = set; then -@@ -9509,6 +9895,9 @@ - case ${withval} in - n|no) - USE_VORBIS=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_VORBIS=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} VORBIS" -@@ -9521,7 +9910,6 @@ - - fi - -- PBX_VORBIS=0 - - - -@@ -9530,6 +9918,7 @@ - - VPB_DESCRIP="Voicetronix API" - VPB_OPTION="vpb" -+ PBX_VPB=0 - - # Check whether --with-vpb was given. - if test "${with_vpb+set}" = set; then -@@ -9537,6 +9926,9 @@ - case ${withval} in - n|no) - USE_VPB=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_VPB=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} VPB" -@@ -9549,7 +9941,6 @@ - - fi - -- PBX_VPB=0 - - - -@@ -9558,6 +9949,7 @@ - - X11_DESCRIP="X11 support" - X11_OPTION="x11" -+ PBX_X11=0 - - # Check whether --with-x11 was given. - if test "${with_x11+set}" = set; then -@@ -9565,6 +9957,9 @@ - case ${withval} in - n|no) - USE_X11=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_X11=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} X11" -@@ -9577,7 +9972,6 @@ - - fi - -- PBX_X11=0 - - - -@@ -9586,6 +9980,7 @@ - - ZLIB_DESCRIP="zlib" - ZLIB_OPTION="z" -+ PBX_ZLIB=0 - - # Check whether --with-z was given. - if test "${with_z+set}" = set; then -@@ -9593,6 +9988,9 @@ - case ${withval} in - n|no) - USE_ZLIB=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_ZLIB=-1 - ;; - y|ye|yes) - ac_mandatory_list="${ac_mandatory_list} ZLIB" -@@ -9605,13 +10003,43 @@ - - fi - -- PBX_ZLIB=0 - - - - - - -+ TIMERFD_DESCRIP="timerfd" -+ TIMERFD_OPTION="timerfd" -+ PBX_TIMERFD=0 -+ -+# Check whether --with-timerfd was given. -+if test "${with_timerfd+set}" = set; then -+ withval=$with_timerfd; -+ case ${withval} in -+ n|no) -+ USE_TIMERFD=no -+ # -1 is a magic value used by menuselect to know that the package -+ # was disabled, other than 'not found' -+ PBX_TIMERFD=-1 -+ ;; -+ y|ye|yes) -+ ac_mandatory_list="${ac_mandatory_list} TIMERFD" -+ ;; -+ *) -+ TIMERFD_DIR="${withval}" -+ ac_mandatory_list="${ac_mandatory_list} TIMERFD" -+ ;; -+ esac -+ -+fi -+ -+ -+ -+ -+ -+ -+ - # check for basic system features and functionality before - # checking for package libraries - -@@ -12973,6 +13401,8 @@ - #define HAVE_WORKING_FORK 1 - _ACEOF - -+ PBX_WORKING_FORK=1 -+ - fi - - { echo "$as_me:$LINENO: checking for _LARGEFILE_SOURCE value needed for large files" >&5 -@@ -15332,7 +15762,11 @@ - - - --for ac_func in asprintf atexit dup2 endpwent ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtol strtoq unsetenv utime vasprintf -+ -+ -+ -+ -+for ac_func in asprintf atexit closefrom dup2 endpwent ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtol strtoq unsetenv utime vasprintf getpeereid sysctl swapctl - do - as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` - { echo "$as_me:$LINENO: checking for $ac_func" >&5 -@@ -16787,6 +17221,9 @@ - echo $ECHO_N "checking for compiler 'attribute pure' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -16832,17 +17269,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_pure 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute malloc' support" >&5 - echo $ECHO_N "checking for compiler 'attribute malloc' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -16888,17 +17381,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_malloc 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute const' support" >&5 - echo $ECHO_N "checking for compiler 'attribute const' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -16944,17 +17493,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_const 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute unused' support" >&5 - echo $ECHO_N "checking for compiler 'attribute unused' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -17000,17 +17605,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_unused 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute always_inline' support" >&5 - echo $ECHO_N "checking for compiler 'attribute always_inline' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -17056,17 +17717,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_always_inline 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute deprecated' support" >&5 - echo $ECHO_N "checking for compiler 'attribute deprecated' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -17112,17 +17829,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_deprecated 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute sentinel' support" >&5 - echo $ECHO_N "checking for compiler 'attribute sentinel' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -17168,17 +17941,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_sentinel 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute warn_unused_result' support" >&5 - echo $ECHO_N "checking for compiler 'attribute warn_unused_result' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -17224,17 +18053,73 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_warn_unused_result 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ - { echo "$as_me:$LINENO: checking for compiler 'attribute weak' support" >&5 - echo $ECHO_N "checking for compiler 'attribute weak' support... $ECHO_C" >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ - _ACEOF -@@ -17280,13 +18165,290 @@ - - { echo "$as_me:$LINENO: result: no" >&5 - echo "${ECHO_T}no" >&6; } -+ - fi - - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ - -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_weak 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ - CFLAGS="$saved_CFLAGS" - - -+ -+{ echo "$as_me:$LINENO: checking for compiler 'attribute weak_import' support" >&5 -+echo $ECHO_N "checking for compiler 'attribute weak_import' support... $ECHO_C" >&6; } -+saved_CFLAGS="$CFLAGS" -+CFLAGS="$CFLAGS -Werror" -+ -+if test "x" = "x" -+then -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__((weak_import)) *test(void *muffin, ...) {} -+int -+main () -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_weak_import 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__(()) *test(void *muffin, ...) {} -+int -+main () -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_weak_import 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ -+CFLAGS="$saved_CFLAGS" -+ -+ -+ -+{ echo "$as_me:$LINENO: checking for compiler 'attribute alias' support" >&5 -+echo $ECHO_N "checking for compiler 'attribute alias' support... $ECHO_C" >&6; } -+saved_CFLAGS="$CFLAGS" -+CFLAGS="$CFLAGS -Werror" -+ -+if test "xalias("foo")" = "x" -+then -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__((alias)) *test(void *muffin, ...) {} -+int -+main () -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_alias 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+else -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+void __attribute__((alias("foo"))) *test(void *muffin, ...) {} -+int -+main () -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_ATTRIBUTE_alias 1 -+_ACEOF -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+fi -+ -+CFLAGS="$saved_CFLAGS" -+ -+ -+ - { echo "$as_me:$LINENO: checking for -ffunction-sections support" >&5 - echo $ECHO_N "checking for -ffunction-sections support... $ECHO_C" >&6; } - saved_CFLAGS="${CFLAGS}" -@@ -19358,6 +20520,159 @@ - - - -+ -+ if test "x${PBX_DAHDI_HALF_FULL}" != "x1"; then -+ { echo "$as_me:$LINENO: checking for DAHDI_POLICY_HALF_FULL in dahdi/user.h" >&5 -+echo $ECHO_N "checking for DAHDI_POLICY_HALF_FULL in dahdi/user.h... $ECHO_C" >&6; } -+ saved_cppflags="${CPPFLAGS}" -+ if test "x${DAHDI_HALF_FULL_DIR}" != "x"; then -+ DAHDI_HALF_FULL_INCLUDE="-I${DAHDI_HALF_FULL_DIR}/include" -+ fi -+ CPPFLAGS="${CPPFLAGS} ${DAHDI_HALF_FULL_INCLUDE}" -+ -+ cat >conftest.$ac_ext <<_ACEOF -+ /* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+int -+main () -+{ -+#if defined(DAHDI_POLICY_HALF_FULL) -+ int foo = 0; -+ #else -+ int foo = bar; -+ #endif -+ 0 -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ PBX_DAHDI_HALF_FULL=1 -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_DAHDI_HALF_FULL 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_DAHDI_HALF_FULL_VERSION -+_ACEOF -+ -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ -+ -+ -+ -+ if test "x${PBX_DAHDI_LINEREVERSE_VMWI}" != "x1" -a "${USE_DAHDI_LINEREVERSE_VMWI}" != "no"; then -+ if test "xenhanced dahdi vmwi support" != "x"; then -+ { echo "$as_me:$LINENO: checking for enhanced dahdi vmwi support" >&5 -+echo $ECHO_N "checking for enhanced dahdi vmwi support... $ECHO_C" >&6; } -+ else -+ { echo "$as_me:$LINENO: checking if \"struct dahdi_vmwi_info booger\" compiles using dahdi/user.h" >&5 -+echo $ECHO_N "checking if \"struct dahdi_vmwi_info booger\" compiles using dahdi/user.h... $ECHO_C" >&6; } -+ fi -+ saved_cppflags="${CPPFLAGS}" -+ if test "x${DAHDI_LINEREVERSE_VMWI_DIR}" != "x"; then -+ DAHDI_LINEREVERSE_VMWI_INCLUDE="-I${DAHDI_LINEREVERSE_VMWI_DIR}/include" -+ fi -+ CPPFLAGS="${CPPFLAGS} ${DAHDI_LINEREVERSE_VMWI_INCLUDE}" -+ -+ cat >conftest.$ac_ext <<_ACEOF -+ /* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+int -+main () -+{ -+ struct dahdi_vmwi_info booger; -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ PBX_DAHDI_LINEREVERSE_VMWI=1 -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_DAHDI_LINEREVERSE_VMWI 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_DAHDI_LINEREVERSE_VMWI_VERSION -+_ACEOF -+ -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ -+ - # BSD might not have exp2, and/or log2 - - if test "x${PBX_EXP2L}" != "x1" -a "${USE_EXP2L}" != "no"; then -@@ -31442,6 +32757,81 @@ - fi - - -+ if test "x${PBX_TIMERFD}" != "x1" -a "${USE_TIMERFD}" != "no"; then -+ if test "xtimerfd support" != "x"; then -+ { echo "$as_me:$LINENO: checking for timerfd support" >&5 -+echo $ECHO_N "checking for timerfd support... $ECHO_C" >&6; } -+ else -+ { echo "$as_me:$LINENO: checking if \"timerfd_create(0,0); timerfd_settime(0,0,NULL,NULL);\" compiles using sys/timerfd.h" >&5 -+echo $ECHO_N "checking if \"timerfd_create(0,0); timerfd_settime(0,0,NULL,NULL);\" compiles using sys/timerfd.h... $ECHO_C" >&6; } -+ fi -+ saved_cppflags="${CPPFLAGS}" -+ if test "x${TIMERFD_DIR}" != "x"; then -+ TIMERFD_INCLUDE="-I${TIMERFD_DIR}/include" -+ fi -+ CPPFLAGS="${CPPFLAGS} ${TIMERFD_INCLUDE}" -+ -+ cat >conftest.$ac_ext <<_ACEOF -+ /* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+int -+main () -+{ -+ timerfd_create(0,0); timerfd_settime(0,0,NULL,NULL);; -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ { echo "$as_me:$LINENO: result: yes" >&5 -+echo "${ECHO_T}yes" >&6; } -+ PBX_TIMERFD=1 -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_TIMERFD 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_TIMERFD_VERSION -+_ACEOF -+ -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ -+ - GSM_INTERNAL="yes" - - GSM_SYSTEM="yes" -@@ -33502,6 +34892,530 @@ - fi - - -+if test "x${PBX_IODBC}" != "x1" -a "${USE_IODBC}" != "no"; then -+ pbxlibdir="" -+ # if --with-IODBC=DIR has been specified, use it. -+ if test "x${IODBC_DIR}" != "x"; then -+ if test -d ${IODBC_DIR}/lib; then -+ pbxlibdir="-L${IODBC_DIR}/lib" -+ else -+ pbxlibdir="-L${IODBC_DIR}" -+ fi -+ fi -+ pbxfuncname="SQLConnect" -+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers -+ AST_IODBC_FOUND=yes -+ else -+ as_ac_Lib=`echo "ac_cv_lib_iodbc_${pbxfuncname}" | $as_tr_sh` -+{ echo "$as_me:$LINENO: checking for ${pbxfuncname} in -liodbc" >&5 -+echo $ECHO_N "checking for ${pbxfuncname} in -liodbc... $ECHO_C" >&6; } -+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-liodbc ${pbxlibdir} -lpthread $LIBS" -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ${pbxfuncname} (); -+int -+main () -+{ -+return ${pbxfuncname} (); -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ eval "$as_ac_Lib=yes" -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ eval "$as_ac_Lib=no" -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+ac_res=`eval echo '${'$as_ac_Lib'}'` -+ { echo "$as_me:$LINENO: result: $ac_res" >&5 -+echo "${ECHO_T}$ac_res" >&6; } -+if test `eval echo '${'$as_ac_Lib'}'` = yes; then -+ AST_IODBC_FOUND=yes -+else -+ AST_IODBC_FOUND=no -+fi -+ -+ fi -+ -+ # now check for the header. -+ if test "${AST_IODBC_FOUND}" = "yes"; then -+ IODBC_LIB="${pbxlibdir} -liodbc -lpthread" -+ # if --with-IODBC=DIR has been specified, use it. -+ if test "x${IODBC_DIR}" != "x"; then -+ IODBC_INCLUDE="-I${IODBC_DIR}/include" -+ fi -+ IODBC_INCLUDE="${IODBC_INCLUDE} " -+ if test "xsql.h" = "x" ; then # no header, assume found -+ IODBC_HEADER_FOUND="1" -+ else # check for the header -+ saved_cppflags="${CPPFLAGS}" -+ CPPFLAGS="${CPPFLAGS} ${IODBC_INCLUDE}" -+ if test "${ac_cv_header_sql_h+set}" = set; then -+ { echo "$as_me:$LINENO: checking for sql.h" >&5 -+echo $ECHO_N "checking for sql.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_sql_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_sql_h" >&5 -+echo "${ECHO_T}$ac_cv_header_sql_h" >&6; } -+else -+ # Is the header compilable? -+{ echo "$as_me:$LINENO: checking sql.h usability" >&5 -+echo $ECHO_N "checking sql.h usability... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+$ac_includes_default -+#include -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ ac_header_compiler=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_compiler=no -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -+echo "${ECHO_T}$ac_header_compiler" >&6; } -+ -+# Is the header present? -+{ echo "$as_me:$LINENO: checking sql.h presence" >&5 -+echo $ECHO_N "checking sql.h presence... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+_ACEOF -+if { (ac_try="$ac_cpp conftest.$ac_ext" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } >/dev/null && { -+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || -+ test ! -s conftest.err -+ }; then -+ ac_header_preproc=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_preproc=no -+fi -+ -+rm -f conftest.err conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -+echo "${ECHO_T}$ac_header_preproc" >&6; } -+ -+# So? What about this header? -+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in -+ yes:no: ) -+ { echo "$as_me:$LINENO: WARNING: sql.h: accepted by the compiler, rejected by the preprocessor!" >&5 -+echo "$as_me: WARNING: sql.h: accepted by the compiler, rejected by the preprocessor!" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sql.h: proceeding with the compiler's result" >&5 -+echo "$as_me: WARNING: sql.h: proceeding with the compiler's result" >&2;} -+ ac_header_preproc=yes -+ ;; -+ no:yes:* ) -+ { echo "$as_me:$LINENO: WARNING: sql.h: present but cannot be compiled" >&5 -+echo "$as_me: WARNING: sql.h: present but cannot be compiled" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sql.h: check for missing prerequisite headers?" >&5 -+echo "$as_me: WARNING: sql.h: check for missing prerequisite headers?" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sql.h: see the Autoconf documentation" >&5 -+echo "$as_me: WARNING: sql.h: see the Autoconf documentation" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sql.h: section \"Present But Cannot Be Compiled\"" >&5 -+echo "$as_me: WARNING: sql.h: section \"Present But Cannot Be Compiled\"" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sql.h: proceeding with the preprocessor's result" >&5 -+echo "$as_me: WARNING: sql.h: proceeding with the preprocessor's result" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sql.h: in the future, the compiler will take precedence" >&5 -+echo "$as_me: WARNING: sql.h: in the future, the compiler will take precedence" >&2;} -+ ( cat <<\_ASBOX -+## ------------------------------- ## -+## Report this to www.asterisk.org ## -+## ------------------------------- ## -+_ASBOX -+ ) | sed "s/^/$as_me: WARNING: /" >&2 -+ ;; -+esac -+{ echo "$as_me:$LINENO: checking for sql.h" >&5 -+echo $ECHO_N "checking for sql.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_sql_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_cv_header_sql_h=$ac_header_preproc -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_sql_h" >&5 -+echo "${ECHO_T}$ac_cv_header_sql_h" >&6; } -+ -+fi -+if test $ac_cv_header_sql_h = yes; then -+ IODBC_HEADER_FOUND=1 -+else -+ IODBC_HEADER_FOUND=0 -+fi -+ -+ -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ if test "x${IODBC_HEADER_FOUND}" = "x0" ; then -+ IODBC_LIB="" -+ IODBC_INCLUDE="" -+ else -+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library -+ IODBC_LIB="" -+ fi -+ PBX_IODBC=1 -+ # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_IODBC 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_IODBC_VERSION -+_ACEOF -+ -+ fi -+ fi -+fi -+ -+ -+ -+if test "x${PBX_INOTIFY}" != "x1" -a "${USE_INOTIFY}" != "no"; then -+ pbxlibdir="" -+ # if --with-INOTIFY=DIR has been specified, use it. -+ if test "x${INOTIFY_DIR}" != "x"; then -+ if test -d ${INOTIFY_DIR}/lib; then -+ pbxlibdir="-L${INOTIFY_DIR}/lib" -+ else -+ pbxlibdir="-L${INOTIFY_DIR}" -+ fi -+ fi -+ pbxfuncname="inotify_init" -+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers -+ AST_INOTIFY_FOUND=yes -+ else -+ as_ac_Lib=`echo "ac_cv_lib_c_${pbxfuncname}" | $as_tr_sh` -+{ echo "$as_me:$LINENO: checking for ${pbxfuncname} in -lc" >&5 -+echo $ECHO_N "checking for ${pbxfuncname} in -lc... $ECHO_C" >&6; } -+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lc ${pbxlibdir} $LIBS" -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ${pbxfuncname} (); -+int -+main () -+{ -+return ${pbxfuncname} (); -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ eval "$as_ac_Lib=yes" -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ eval "$as_ac_Lib=no" -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+ac_res=`eval echo '${'$as_ac_Lib'}'` -+ { echo "$as_me:$LINENO: result: $ac_res" >&5 -+echo "${ECHO_T}$ac_res" >&6; } -+if test `eval echo '${'$as_ac_Lib'}'` = yes; then -+ AST_INOTIFY_FOUND=yes -+else -+ AST_INOTIFY_FOUND=no -+fi -+ -+ fi -+ -+ # now check for the header. -+ if test "${AST_INOTIFY_FOUND}" = "yes"; then -+ INOTIFY_LIB="${pbxlibdir} -lc " -+ # if --with-INOTIFY=DIR has been specified, use it. -+ if test "x${INOTIFY_DIR}" != "x"; then -+ INOTIFY_INCLUDE="-I${INOTIFY_DIR}/include" -+ fi -+ INOTIFY_INCLUDE="${INOTIFY_INCLUDE} " -+ if test "xsys/inotify.h" = "x" ; then # no header, assume found -+ INOTIFY_HEADER_FOUND="1" -+ else # check for the header -+ saved_cppflags="${CPPFLAGS}" -+ CPPFLAGS="${CPPFLAGS} ${INOTIFY_INCLUDE}" -+ if test "${ac_cv_header_sys_inotify_h+set}" = set; then -+ { echo "$as_me:$LINENO: checking for sys/inotify.h" >&5 -+echo $ECHO_N "checking for sys/inotify.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_sys_inotify_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_sys_inotify_h" >&5 -+echo "${ECHO_T}$ac_cv_header_sys_inotify_h" >&6; } -+else -+ # Is the header compilable? -+{ echo "$as_me:$LINENO: checking sys/inotify.h usability" >&5 -+echo $ECHO_N "checking sys/inotify.h usability... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+$ac_includes_default -+#include -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ ac_header_compiler=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_compiler=no -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -+echo "${ECHO_T}$ac_header_compiler" >&6; } -+ -+# Is the header present? -+{ echo "$as_me:$LINENO: checking sys/inotify.h presence" >&5 -+echo $ECHO_N "checking sys/inotify.h presence... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+_ACEOF -+if { (ac_try="$ac_cpp conftest.$ac_ext" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } >/dev/null && { -+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || -+ test ! -s conftest.err -+ }; then -+ ac_header_preproc=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_preproc=no -+fi -+ -+rm -f conftest.err conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -+echo "${ECHO_T}$ac_header_preproc" >&6; } -+ -+# So? What about this header? -+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in -+ yes:no: ) -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: accepted by the compiler, rejected by the preprocessor!" >&5 -+echo "$as_me: WARNING: sys/inotify.h: accepted by the compiler, rejected by the preprocessor!" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: proceeding with the compiler's result" >&5 -+echo "$as_me: WARNING: sys/inotify.h: proceeding with the compiler's result" >&2;} -+ ac_header_preproc=yes -+ ;; -+ no:yes:* ) -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: present but cannot be compiled" >&5 -+echo "$as_me: WARNING: sys/inotify.h: present but cannot be compiled" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: check for missing prerequisite headers?" >&5 -+echo "$as_me: WARNING: sys/inotify.h: check for missing prerequisite headers?" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: see the Autoconf documentation" >&5 -+echo "$as_me: WARNING: sys/inotify.h: see the Autoconf documentation" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: section \"Present But Cannot Be Compiled\"" >&5 -+echo "$as_me: WARNING: sys/inotify.h: section \"Present But Cannot Be Compiled\"" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: proceeding with the preprocessor's result" >&5 -+echo "$as_me: WARNING: sys/inotify.h: proceeding with the preprocessor's result" >&2;} -+ { echo "$as_me:$LINENO: WARNING: sys/inotify.h: in the future, the compiler will take precedence" >&5 -+echo "$as_me: WARNING: sys/inotify.h: in the future, the compiler will take precedence" >&2;} -+ ( cat <<\_ASBOX -+## ------------------------------- ## -+## Report this to www.asterisk.org ## -+## ------------------------------- ## -+_ASBOX -+ ) | sed "s/^/$as_me: WARNING: /" >&2 -+ ;; -+esac -+{ echo "$as_me:$LINENO: checking for sys/inotify.h" >&5 -+echo $ECHO_N "checking for sys/inotify.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_sys_inotify_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_cv_header_sys_inotify_h=$ac_header_preproc -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_sys_inotify_h" >&5 -+echo "${ECHO_T}$ac_cv_header_sys_inotify_h" >&6; } -+ -+fi -+if test $ac_cv_header_sys_inotify_h = yes; then -+ INOTIFY_HEADER_FOUND=1 -+else -+ INOTIFY_HEADER_FOUND=0 -+fi -+ -+ -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ if test "x${INOTIFY_HEADER_FOUND}" = "x0" ; then -+ INOTIFY_LIB="" -+ INOTIFY_INCLUDE="" -+ else -+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library -+ INOTIFY_LIB="" -+ fi -+ PBX_INOTIFY=1 -+ # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_INOTIFY 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_INOTIFY_VERSION -+_ACEOF -+ -+ fi -+ fi -+fi -+ -+ -+ - if test "x${PBX_JACK}" != "x1" -a "${USE_JACK}" != "no"; then - pbxlibdir="" - # if --with-JACK=DIR has been specified, use it. -@@ -34288,7 +36202,213 @@ - fi - - -+# Check whether --enable-xmldoc was given. -+if test "${enable_xmldoc+set}" = set; then -+ enableval=$enable_xmldoc; case "${enableval}" in -+ y|ye|yes) disable_xmldoc=no ;; -+ n|no) disable_xmldoc=yes ;; -+ *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --disable-xmldoc" >&5 -+echo "$as_me: error: bad value ${enableval} for --disable-xmldoc" >&2;} -+ { (exit 1); exit 1; }; } ;; -+ esac -+else -+ disable_xmldoc=no -+fi - -+ -+if test "${disable_xmldoc}" != "yes"; then -+ -+ if test "x${PBX_LIBXML2}" != "x1" -a "${USE_LIBXML2}" != "no"; then -+ PBX_LIBXML2=0 -+ if test -n "$ac_tool_prefix"; then -+ # Extract the first word of "${ac_tool_prefix}xml2-config", so it can be a program name with args. -+set dummy ${ac_tool_prefix}xml2-config; ac_word=$2 -+{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -+if test "${ac_cv_prog_CONFIG_LIBXML2+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ if test -n "$CONFIG_LIBXML2"; then -+ ac_cv_prog_CONFIG_LIBXML2="$CONFIG_LIBXML2" # Let the user override the test. -+else -+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+for as_dir in $PATH -+do -+ IFS=$as_save_IFS -+ test -z "$as_dir" && as_dir=. -+ for ac_exec_ext in '' $ac_executable_extensions; do -+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then -+ ac_cv_prog_CONFIG_LIBXML2="${ac_tool_prefix}xml2-config" -+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 -+ break 2 -+ fi -+done -+done -+IFS=$as_save_IFS -+ -+fi -+fi -+CONFIG_LIBXML2=$ac_cv_prog_CONFIG_LIBXML2 -+if test -n "$CONFIG_LIBXML2"; then -+ { echo "$as_me:$LINENO: result: $CONFIG_LIBXML2" >&5 -+echo "${ECHO_T}$CONFIG_LIBXML2" >&6; } -+else -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+fi -+ -+ -+fi -+if test -z "$ac_cv_prog_CONFIG_LIBXML2"; then -+ ac_ct_CONFIG_LIBXML2=$CONFIG_LIBXML2 -+ # Extract the first word of "xml2-config", so it can be a program name with args. -+set dummy xml2-config; ac_word=$2 -+{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -+if test "${ac_cv_prog_ac_ct_CONFIG_LIBXML2+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ if test -n "$ac_ct_CONFIG_LIBXML2"; then -+ ac_cv_prog_ac_ct_CONFIG_LIBXML2="$ac_ct_CONFIG_LIBXML2" # Let the user override the test. -+else -+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -+for as_dir in $PATH -+do -+ IFS=$as_save_IFS -+ test -z "$as_dir" && as_dir=. -+ for ac_exec_ext in '' $ac_executable_extensions; do -+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then -+ ac_cv_prog_ac_ct_CONFIG_LIBXML2="xml2-config" -+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 -+ break 2 -+ fi -+done -+done -+IFS=$as_save_IFS -+ -+fi -+fi -+ac_ct_CONFIG_LIBXML2=$ac_cv_prog_ac_ct_CONFIG_LIBXML2 -+if test -n "$ac_ct_CONFIG_LIBXML2"; then -+ { echo "$as_me:$LINENO: result: $ac_ct_CONFIG_LIBXML2" >&5 -+echo "${ECHO_T}$ac_ct_CONFIG_LIBXML2" >&6; } -+else -+ { echo "$as_me:$LINENO: result: no" >&5 -+echo "${ECHO_T}no" >&6; } -+fi -+ -+ if test "x$ac_ct_CONFIG_LIBXML2" = x; then -+ CONFIG_LIBXML2="No" -+ else -+ case $cross_compiling:$ac_tool_warned in -+yes:) -+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -+whose name does not start with the host triplet. If you think this -+configuration is useful to you, please write to autoconf@gnu.org." >&5 -+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -+whose name does not start with the host triplet. If you think this -+configuration is useful to you, please write to autoconf@gnu.org." >&2;} -+ac_tool_warned=yes ;; -+esac -+ CONFIG_LIBXML2=$ac_ct_CONFIG_LIBXML2 -+ fi -+else -+ CONFIG_LIBXML2="$ac_cv_prog_CONFIG_LIBXML2" -+fi -+ -+ if test ! "x${CONFIG_LIBXML2}" = xNo; then -+ if test x"" = x ; then A=--cflags ; else A="" ; fi -+ LIBXML2_INCLUDE=$(${CONFIG_LIBXML2} $A) -+ if test x"" = x ; then A=--libs ; else A="" ; fi -+ LIBXML2_LIB=$(${CONFIG_LIBXML2} $A) -+ if test x"#include -+ #include " != x ; then -+ saved_cppflags="${CPPFLAGS}" -+ if test "x${LIBXML2_DIR}" != "x"; then -+ LIBXML2_INCLUDE="-I${LIBXML2_DIR}/include" -+ fi -+ CPPFLAGS="${CPPFLAGS} ${LIBXML2_INCLUDE}" -+ -+ saved_ldflags="${LDFLAGS}" -+ LDFLAGS="${LIBXML2_LIB}" -+ -+ cat >conftest.$ac_ext <<_ACEOF -+ /* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ #include -+ #include -+int -+main () -+{ -+ LIBXML_TEST_VERSION; -+ -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ PBX_LIBXML2=1 -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_LIBXML2 1 -+_ACEOF -+ -+ -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ -+ -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+ CPPFLAGS="${saved_cppflags}" -+ LDFLAGS="${saved_ldflags}" -+ else -+ PBX_LIBXML2=1 -+ -+cat >>confdefs.h <<\_ACEOF -+#define HAVE_LIBXML2 1 -+_ACEOF -+ -+ fi -+ fi -+ fi -+ -+ if test "${PBX_LIBXML2}" != 1; then -+ { echo "$as_me:$LINENO: *** XML documentation will not be available because the 'libxml2' development package is missing." >&5 -+echo "$as_me: *** XML documentation will not be available because the 'libxml2' development package is missing." >&6;} -+ { echo "$as_me:$LINENO: *** Please run the 'configure' script with the '--disable-xmldoc' parameter option" >&5 -+echo "$as_me: *** Please run the 'configure' script with the '--disable-xmldoc' parameter option" >&6;} -+ { echo "$as_me:$LINENO: *** or install the 'libxml2' development package." >&5 -+echo "$as_me: *** or install the 'libxml2' development package." >&6;} -+ exit 1 -+ fi -+fi -+ -+ - if test "x${PBX_MISDN}" != "x1" -a "${USE_MISDN}" != "no"; then - pbxlibdir="" - # if --with-MISDN=DIR has been specified, use it. -@@ -39284,6 +41404,268 @@ - - - -+if test "x${PBX_PRI_PROG_W_CAUSE}" != "x1" -a "${USE_PRI_PROG_W_CAUSE}" != "no"; then -+ pbxlibdir="" -+ # if --with-PRI_PROG_W_CAUSE=DIR has been specified, use it. -+ if test "x${PRI_PROG_W_CAUSE_DIR}" != "x"; then -+ if test -d ${PRI_PROG_W_CAUSE_DIR}/lib; then -+ pbxlibdir="-L${PRI_PROG_W_CAUSE_DIR}/lib" -+ else -+ pbxlibdir="-L${PRI_PROG_W_CAUSE_DIR}" -+ fi -+ fi -+ pbxfuncname="pri_progress_with_cause" -+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers -+ AST_PRI_PROG_W_CAUSE_FOUND=yes -+ else -+ as_ac_Lib=`echo "ac_cv_lib_pri_${pbxfuncname}" | $as_tr_sh` -+{ echo "$as_me:$LINENO: checking for ${pbxfuncname} in -lpri" >&5 -+echo $ECHO_N "checking for ${pbxfuncname} in -lpri... $ECHO_C" >&6; } -+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lpri ${pbxlibdir} $LIBS" -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ${pbxfuncname} (); -+int -+main () -+{ -+return ${pbxfuncname} (); -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ eval "$as_ac_Lib=yes" -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ eval "$as_ac_Lib=no" -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+ac_res=`eval echo '${'$as_ac_Lib'}'` -+ { echo "$as_me:$LINENO: result: $ac_res" >&5 -+echo "${ECHO_T}$ac_res" >&6; } -+if test `eval echo '${'$as_ac_Lib'}'` = yes; then -+ AST_PRI_PROG_W_CAUSE_FOUND=yes -+else -+ AST_PRI_PROG_W_CAUSE_FOUND=no -+fi -+ -+ fi -+ -+ # now check for the header. -+ if test "${AST_PRI_PROG_W_CAUSE_FOUND}" = "yes"; then -+ PRI_PROG_W_CAUSE_LIB="${pbxlibdir} -lpri " -+ # if --with-PRI_PROG_W_CAUSE=DIR has been specified, use it. -+ if test "x${PRI_PROG_W_CAUSE_DIR}" != "x"; then -+ PRI_PROG_W_CAUSE_INCLUDE="-I${PRI_PROG_W_CAUSE_DIR}/include" -+ fi -+ PRI_PROG_W_CAUSE_INCLUDE="${PRI_PROG_W_CAUSE_INCLUDE} " -+ if test "xlibpri.h" = "x" ; then # no header, assume found -+ PRI_PROG_W_CAUSE_HEADER_FOUND="1" -+ else # check for the header -+ saved_cppflags="${CPPFLAGS}" -+ CPPFLAGS="${CPPFLAGS} ${PRI_PROG_W_CAUSE_INCLUDE}" -+ if test "${ac_cv_header_libpri_h+set}" = set; then -+ { echo "$as_me:$LINENO: checking for libpri.h" >&5 -+echo $ECHO_N "checking for libpri.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_libpri_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_libpri_h" >&5 -+echo "${ECHO_T}$ac_cv_header_libpri_h" >&6; } -+else -+ # Is the header compilable? -+{ echo "$as_me:$LINENO: checking libpri.h usability" >&5 -+echo $ECHO_N "checking libpri.h usability... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+$ac_includes_default -+#include -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ ac_header_compiler=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_compiler=no -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -+echo "${ECHO_T}$ac_header_compiler" >&6; } -+ -+# Is the header present? -+{ echo "$as_me:$LINENO: checking libpri.h presence" >&5 -+echo $ECHO_N "checking libpri.h presence... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+_ACEOF -+if { (ac_try="$ac_cpp conftest.$ac_ext" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } >/dev/null && { -+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || -+ test ! -s conftest.err -+ }; then -+ ac_header_preproc=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_preproc=no -+fi -+ -+rm -f conftest.err conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -+echo "${ECHO_T}$ac_header_preproc" >&6; } -+ -+# So? What about this header? -+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in -+ yes:no: ) -+ { echo "$as_me:$LINENO: WARNING: libpri.h: accepted by the compiler, rejected by the preprocessor!" >&5 -+echo "$as_me: WARNING: libpri.h: accepted by the compiler, rejected by the preprocessor!" >&2;} -+ { echo "$as_me:$LINENO: WARNING: libpri.h: proceeding with the compiler's result" >&5 -+echo "$as_me: WARNING: libpri.h: proceeding with the compiler's result" >&2;} -+ ac_header_preproc=yes -+ ;; -+ no:yes:* ) -+ { echo "$as_me:$LINENO: WARNING: libpri.h: present but cannot be compiled" >&5 -+echo "$as_me: WARNING: libpri.h: present but cannot be compiled" >&2;} -+ { echo "$as_me:$LINENO: WARNING: libpri.h: check for missing prerequisite headers?" >&5 -+echo "$as_me: WARNING: libpri.h: check for missing prerequisite headers?" >&2;} -+ { echo "$as_me:$LINENO: WARNING: libpri.h: see the Autoconf documentation" >&5 -+echo "$as_me: WARNING: libpri.h: see the Autoconf documentation" >&2;} -+ { echo "$as_me:$LINENO: WARNING: libpri.h: section \"Present But Cannot Be Compiled\"" >&5 -+echo "$as_me: WARNING: libpri.h: section \"Present But Cannot Be Compiled\"" >&2;} -+ { echo "$as_me:$LINENO: WARNING: libpri.h: proceeding with the preprocessor's result" >&5 -+echo "$as_me: WARNING: libpri.h: proceeding with the preprocessor's result" >&2;} -+ { echo "$as_me:$LINENO: WARNING: libpri.h: in the future, the compiler will take precedence" >&5 -+echo "$as_me: WARNING: libpri.h: in the future, the compiler will take precedence" >&2;} -+ ( cat <<\_ASBOX -+## ------------------------------- ## -+## Report this to www.asterisk.org ## -+## ------------------------------- ## -+_ASBOX -+ ) | sed "s/^/$as_me: WARNING: /" >&2 -+ ;; -+esac -+{ echo "$as_me:$LINENO: checking for libpri.h" >&5 -+echo $ECHO_N "checking for libpri.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_libpri_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_cv_header_libpri_h=$ac_header_preproc -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_libpri_h" >&5 -+echo "${ECHO_T}$ac_cv_header_libpri_h" >&6; } -+ -+fi -+if test $ac_cv_header_libpri_h = yes; then -+ PRI_PROG_W_CAUSE_HEADER_FOUND=1 -+else -+ PRI_PROG_W_CAUSE_HEADER_FOUND=0 -+fi -+ -+ -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ if test "x${PRI_PROG_W_CAUSE_HEADER_FOUND}" = "x0" ; then -+ PRI_PROG_W_CAUSE_LIB="" -+ PRI_PROG_W_CAUSE_INCLUDE="" -+ else -+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library -+ PRI_PROG_W_CAUSE_LIB="" -+ fi -+ PBX_PRI_PROG_W_CAUSE=1 -+ # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_PRI_PROG_W_CAUSE 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_PRI_PROG_W_CAUSE_VERSION -+_ACEOF -+ -+ fi -+ fi -+fi -+ -+ -+ - if test "x${PBX_PRI_INBANDDISCONNECT}" != "x1" -a "${USE_PRI_INBANDDISCONNECT}" != "no"; then - pbxlibdir="" - # if --with-PRI_INBANDDISCONNECT=DIR has been specified, use it. -@@ -41335,7 +43717,7 @@ - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR --for as_dir in /usr/local/bin -+for as_dir in /usr/local/bin$PATH_SEPARATOR/usr/local/share/pwlib/make - do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. -@@ -41362,51 +43744,12 @@ - fi - - -- if test "${PTLIB_CONFIG:-unset}" = "unset" ; then -- # Extract the first word of "ptlib-config", so it can be a program name with args. --set dummy ptlib-config; ac_word=$2 --{ echo "$as_me:$LINENO: checking for $ac_word" >&5 --echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } --if test "${ac_cv_path_PTLIB_CONFIG+set}" = set; then -- echo $ECHO_N "(cached) $ECHO_C" >&6 --else -- case $PTLIB_CONFIG in -- [\\/]* | ?:[\\/]*) -- ac_cv_path_PTLIB_CONFIG="$PTLIB_CONFIG" # Let the user override the test with a path. -- ;; -- *) -- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR --for as_dir in /usr/local/share/pwlib/make --do -- IFS=$as_save_IFS -- test -z "$as_dir" && as_dir=. -- for ac_exec_ext in '' $ac_executable_extensions; do -- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then -- ac_cv_path_PTLIB_CONFIG="$as_dir/$ac_word$ac_exec_ext" -- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 -- break 2 -- fi --done --done --IFS=$as_save_IFS -- -- ;; --esac --fi --PTLIB_CONFIG=$ac_cv_path_PTLIB_CONFIG --if test -n "$PTLIB_CONFIG"; then -- { echo "$as_me:$LINENO: result: $PTLIB_CONFIG" >&5 --echo "${ECHO_T}$PTLIB_CONFIG" >&6; } --else -- { echo "$as_me:$LINENO: result: no" >&5 --echo "${ECHO_T}no" >&6; } --fi -- -- -- fi - PWLIB_INCDIR="/usr/local/include" -- PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir` -+ PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir 2>/dev/null` - if test "${PWLIB_LIBDIR:-unset}" = "unset"; then -+ PWLIB_LIBDIR=`${PTLIB_CONFIG} --ptlibdir 2>/dev/null` -+ fi -+ if test "${PWLIB_LIBDIR:-unset}" = "unset"; then - if test "x$LIB64" != "x"; then - PWLIB_LIBDIR="/usr/local/lib64" - else -@@ -41565,7 +43908,7 @@ - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR --for as_dir in /usr/share/pwlib/make -+for as_dir in /usr/bin$PATH_SEPARATOR/usr/share/pwlib/make - do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. -@@ -41593,8 +43936,11 @@ - - - PWLIB_INCDIR="/usr/include" -- PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir` -+ PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir 2>/dev/null` - if test "${PWLIB_LIBDIR:-unset}" = "unset"; then -+ PWLIB_LIBDIR=`${PTLIB_CONFIG} --ptlibdir 2>/dev/null` -+ fi -+ if test "${PWLIB_LIBDIR:-unset}" = "unset"; then - if test "x$LIB64" != "x"; then - PWLIB_LIBDIR="/usr/lib64" - else -@@ -41662,8 +44008,14 @@ - - - -+ if test "xP[WT]LIB_VERSION" != "x"; then -+ VNAME="P[WT]LIB_VERSION" -+ else -+ VNAME="PWLIB_VERSION" -+ fi -+ - if test "${HAS_PWLIB:-unset}" != "unset"; then -- PWLIB_VERSION=`grep "PWLIB_VERSION" ${PWLIB_INCDIR}/ptbuildopts.h | sed -e 's/[[:space:]]\{1,\}/ /g' | cut -f3 -d ' ' | sed -e 's/"//g'` -+ PWLIB_VERSION=`grep "$VNAME" ${PWLIB_INCDIR}/ptbuildopts.h | sed -e 's/[[:space:]]\{1,\}/ /g' | cut -f3 -d ' ' | sed -e 's/"//g'` - PWLIB_MAJOR_VERSION=`echo ${PWLIB_VERSION} | cut -f1 -d.` - PWLIB_MINOR_VERSION=`echo ${PWLIB_VERSION} | cut -f2 -d.` - PWLIB_BUILD_NUMBER=`echo ${PWLIB_VERSION} | cut -f3 -d.` -@@ -41804,7 +44156,7 @@ - int - main () - { --BOOL q = PTime::IsDaylightSavings(); -+int q = (int) PTime::IsDaylightSavings(); - ; - return 0; - } -@@ -42610,8 +44962,14 @@ - - - -+ if test "x" != "x"; then -+ VNAME="" -+ else -+ VNAME="OPENH323_VERSION" -+ fi -+ - if test "${HAS_OPENH323:-unset}" != "unset"; then -- OPENH323_VERSION=`grep "OPENH323_VERSION" ${OPENH323_INCDIR}/openh323buildopts.h | sed -e 's/[[:space:]]\{1,\}/ /g' | cut -f3 -d ' ' | sed -e 's/"//g'` -+ OPENH323_VERSION=`grep "$VNAME" ${OPENH323_INCDIR}/openh323buildopts.h | sed -e 's/[[:space:]]\{1,\}/ /g' | cut -f3 -d ' ' | sed -e 's/"//g'` - OPENH323_MAJOR_VERSION=`echo ${OPENH323_VERSION} | cut -f1 -d.` - OPENH323_MINOR_VERSION=`echo ${OPENH323_VERSION} | cut -f2 -d.` - OPENH323_BUILD_NUMBER=`echo ${OPENH323_VERSION} | cut -f3 -d.` -@@ -47537,6 +49895,8 @@ - fi - - -+if test "${OSARCH}" = "OpenBSD"; -+then - - if test "x${PBX_VORBIS}" != "x1" -a "${USE_VORBIS}" != "no"; then - pbxlibdir="" -@@ -47559,6 +49919,268 @@ - echo $ECHO_N "(cached) $ECHO_C" >&6 - else - ac_check_lib_save_LIBS=$LIBS -+LIBS="-lvorbis ${pbxlibdir} -lm -lvorbisenc -logg $LIBS" -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char ${pbxfuncname} (); -+int -+main () -+{ -+return ${pbxfuncname} (); -+ ; -+ return 0; -+} -+_ACEOF -+rm -f conftest.$ac_objext conftest$ac_exeext -+if { (ac_try="$ac_link" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_link") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest$ac_exeext && -+ $as_test_x conftest$ac_exeext; then -+ eval "$as_ac_Lib=yes" -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ eval "$as_ac_Lib=no" -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+ac_res=`eval echo '${'$as_ac_Lib'}'` -+ { echo "$as_me:$LINENO: result: $ac_res" >&5 -+echo "${ECHO_T}$ac_res" >&6; } -+if test `eval echo '${'$as_ac_Lib'}'` = yes; then -+ AST_VORBIS_FOUND=yes -+else -+ AST_VORBIS_FOUND=no -+fi -+ -+ fi -+ -+ # now check for the header. -+ if test "${AST_VORBIS_FOUND}" = "yes"; then -+ VORBIS_LIB="${pbxlibdir} -lvorbis -lm -lvorbisenc -logg" -+ # if --with-VORBIS=DIR has been specified, use it. -+ if test "x${VORBIS_DIR}" != "x"; then -+ VORBIS_INCLUDE="-I${VORBIS_DIR}/include" -+ fi -+ VORBIS_INCLUDE="${VORBIS_INCLUDE} " -+ if test "xvorbis/codec.h" = "x" ; then # no header, assume found -+ VORBIS_HEADER_FOUND="1" -+ else # check for the header -+ saved_cppflags="${CPPFLAGS}" -+ CPPFLAGS="${CPPFLAGS} ${VORBIS_INCLUDE}" -+ if test "${ac_cv_header_vorbis_codec_h+set}" = set; then -+ { echo "$as_me:$LINENO: checking for vorbis/codec.h" >&5 -+echo $ECHO_N "checking for vorbis/codec.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_vorbis_codec_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_vorbis_codec_h" >&5 -+echo "${ECHO_T}$ac_cv_header_vorbis_codec_h" >&6; } -+else -+ # Is the header compilable? -+{ echo "$as_me:$LINENO: checking vorbis/codec.h usability" >&5 -+echo $ECHO_N "checking vorbis/codec.h usability... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+$ac_includes_default -+#include -+_ACEOF -+rm -f conftest.$ac_objext -+if { (ac_try="$ac_compile" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_compile") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } && { -+ test -z "$ac_c_werror_flag" || -+ test ! -s conftest.err -+ } && test -s conftest.$ac_objext; then -+ ac_header_compiler=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_compiler=no -+fi -+ -+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -+echo "${ECHO_T}$ac_header_compiler" >&6; } -+ -+# Is the header present? -+{ echo "$as_me:$LINENO: checking vorbis/codec.h presence" >&5 -+echo $ECHO_N "checking vorbis/codec.h presence... $ECHO_C" >&6; } -+cat >conftest.$ac_ext <<_ACEOF -+/* confdefs.h. */ -+_ACEOF -+cat confdefs.h >>conftest.$ac_ext -+cat >>conftest.$ac_ext <<_ACEOF -+/* end confdefs.h. */ -+#include -+_ACEOF -+if { (ac_try="$ac_cpp conftest.$ac_ext" -+case "(($ac_try" in -+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; -+ *) ac_try_echo=$ac_try;; -+esac -+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 -+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 -+ ac_status=$? -+ grep -v '^ *+' conftest.er1 >conftest.err -+ rm -f conftest.er1 -+ cat conftest.err >&5 -+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 -+ (exit $ac_status); } >/dev/null && { -+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || -+ test ! -s conftest.err -+ }; then -+ ac_header_preproc=yes -+else -+ echo "$as_me: failed program was:" >&5 -+sed 's/^/| /' conftest.$ac_ext >&5 -+ -+ ac_header_preproc=no -+fi -+ -+rm -f conftest.err conftest.$ac_ext -+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -+echo "${ECHO_T}$ac_header_preproc" >&6; } -+ -+# So? What about this header? -+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in -+ yes:no: ) -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: accepted by the compiler, rejected by the preprocessor!" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: accepted by the compiler, rejected by the preprocessor!" >&2;} -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: proceeding with the compiler's result" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: proceeding with the compiler's result" >&2;} -+ ac_header_preproc=yes -+ ;; -+ no:yes:* ) -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: present but cannot be compiled" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: present but cannot be compiled" >&2;} -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: check for missing prerequisite headers?" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: check for missing prerequisite headers?" >&2;} -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: see the Autoconf documentation" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: see the Autoconf documentation" >&2;} -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: section \"Present But Cannot Be Compiled\"" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: section \"Present But Cannot Be Compiled\"" >&2;} -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: proceeding with the preprocessor's result" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: proceeding with the preprocessor's result" >&2;} -+ { echo "$as_me:$LINENO: WARNING: vorbis/codec.h: in the future, the compiler will take precedence" >&5 -+echo "$as_me: WARNING: vorbis/codec.h: in the future, the compiler will take precedence" >&2;} -+ ( cat <<\_ASBOX -+## ------------------------------- ## -+## Report this to www.asterisk.org ## -+## ------------------------------- ## -+_ASBOX -+ ) | sed "s/^/$as_me: WARNING: /" >&2 -+ ;; -+esac -+{ echo "$as_me:$LINENO: checking for vorbis/codec.h" >&5 -+echo $ECHO_N "checking for vorbis/codec.h... $ECHO_C" >&6; } -+if test "${ac_cv_header_vorbis_codec_h+set}" = set; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_cv_header_vorbis_codec_h=$ac_header_preproc -+fi -+{ echo "$as_me:$LINENO: result: $ac_cv_header_vorbis_codec_h" >&5 -+echo "${ECHO_T}$ac_cv_header_vorbis_codec_h" >&6; } -+ -+fi -+if test $ac_cv_header_vorbis_codec_h = yes; then -+ VORBIS_HEADER_FOUND=1 -+else -+ VORBIS_HEADER_FOUND=0 -+fi -+ -+ -+ CPPFLAGS="${saved_cppflags}" -+ fi -+ if test "x${VORBIS_HEADER_FOUND}" = "x0" ; then -+ VORBIS_LIB="" -+ VORBIS_INCLUDE="" -+ else -+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library -+ VORBIS_LIB="" -+ fi -+ PBX_VORBIS=1 -+ # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_VORBIS 1 -+_ACEOF -+ -+ -+cat >>confdefs.h <<_ACEOF -+#define HAVE_VORBIS_VERSION -+_ACEOF -+ -+ fi -+ fi -+fi -+ -+else -+ -+if test "x${PBX_VORBIS}" != "x1" -a "${USE_VORBIS}" != "no"; then -+ pbxlibdir="" -+ # if --with-VORBIS=DIR has been specified, use it. -+ if test "x${VORBIS_DIR}" != "x"; then -+ if test -d ${VORBIS_DIR}/lib; then -+ pbxlibdir="-L${VORBIS_DIR}/lib" -+ else -+ pbxlibdir="-L${VORBIS_DIR}" -+ fi -+ fi -+ pbxfuncname="vorbis_info_init" -+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers -+ AST_VORBIS_FOUND=yes -+ else -+ as_ac_Lib=`echo "ac_cv_lib_vorbis_${pbxfuncname}" | $as_tr_sh` -+{ echo "$as_me:$LINENO: checking for ${pbxfuncname} in -lvorbis" >&5 -+echo $ECHO_N "checking for ${pbxfuncname} in -lvorbis... $ECHO_C" >&6; } -+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then -+ echo $ECHO_N "(cached) $ECHO_C" >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS - LIBS="-lvorbis ${pbxlibdir} -lm -lvorbisenc $LIBS" - cat >conftest.$ac_ext <<_ACEOF - /* confdefs.h. */ -@@ -47798,6 +50420,7 @@ - fi - fi - -+fi - - ac_ext=cpp - ac_cpp='$CXXCPP $CPPFLAGS' -@@ -50375,6 +52998,25 @@ - fi - fi - -+# build a GENERIC_ODBC result based on the presence of either UnixODBC (preferred) -+# or iODBC -+ -+PBX_GENERIC_ODBC=0 -+ -+if test "${PBX_UNIXODBC}" = 1; then -+ PBX_GENERIC_ODBC=1 -+ GENERIC_ODBC_LIB="${UNIXODBC_LIB}" -+ GENERIC_ODBC_INCLUDE="${UNIXODBC_INCLUDE}" -+elif test "${PBX_IODBC}" = 1; then -+ PBX_GENERIC_ODBC=1 -+ GENERIC_ODBC_LIB="${IODBC_LIB}" -+ GENERIC_ODBC_INCLUDE="${IODBC_INCLUDE}" -+fi -+ -+ -+ -+ -+ - ac_config_files="$ac_config_files build_tools/menuselect-deps makeopts channels/h323/Makefile" - - -@@ -50404,6 +53046,16 @@ - echo "${ECHO_T}ok" >&6; } - - -+if test -f build_tools/menuselect-deps; then -+ # extract old values of all PBX_ variables from menuselect-deps -+ # and preserve them so that menuselect can determine whether -+ # any previously-met dependencies are no longer met and warn -+ # the user appropriately -+ while IFS="=:" read var val old_val; do -+ eval "PBX_${var}=\${PBX_${var}}:${val}" -+ done < build_tools/menuselect-deps -+fi -+ - cat >confcache <<\_ACEOF - # This file is a shell script that caches the results of configure - # tests run on this system so they can be shared between configure -@@ -51086,7 +53738,7 @@ - HOST_VENDOR!$HOST_VENDOR$ac_delim - HOST_OS!$HOST_OS$ac_delim - OSARCH!$OSARCH$ac_delim --WINARCH!$WINARCH$ac_delim -+PBX_WINARCH!$PBX_WINARCH$ac_delim - UNAME!$UNAME$ac_delim - PBX_OSREV!$PBX_OSREV$ac_delim - CXX!$CXX$ac_delim -@@ -51113,12 +53765,12 @@ - LN!$LN$ac_delim - DOT!$DOT$ac_delim - WGET!$WGET$ac_delim -+CURL!$CURL$ac_delim - RUBBER!$RUBBER$ac_delim - KPATHSEA!$KPATHSEA$ac_delim -+XMLSTARLET!$XMLSTARLET$ac_delim - FETCH!$FETCH$ac_delim - DOWNLOAD!$DOWNLOAD$ac_delim --SOXMIX!$SOXMIX$ac_delim --MD5!$MD5$ac_delim - _ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then -@@ -51160,6 +53812,8 @@ - ac_delim='%!_!# ' - for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -+SOXMIX!$SOXMIX$ac_delim -+MD5!$MD5$ac_delim - acx_pthread_config!$acx_pthread_config$ac_delim - PTHREAD_CC!$PTHREAD_CC$ac_delim - PTHREAD_LIBS!$PTHREAD_LIBS$ac_delim -@@ -51229,6 +53883,14 @@ - IMAP_TK_INCLUDE!$IMAP_TK_INCLUDE$ac_delim - IMAP_TK_DIR!$IMAP_TK_DIR$ac_delim - PBX_IMAP_TK!$PBX_IMAP_TK$ac_delim -+INOTIFY_LIB!$INOTIFY_LIB$ac_delim -+INOTIFY_INCLUDE!$INOTIFY_INCLUDE$ac_delim -+INOTIFY_DIR!$INOTIFY_DIR$ac_delim -+PBX_INOTIFY!$PBX_INOTIFY$ac_delim -+IODBC_LIB!$IODBC_LIB$ac_delim -+IODBC_INCLUDE!$IODBC_INCLUDE$ac_delim -+IODBC_DIR!$IODBC_DIR$ac_delim -+PBX_IODBC!$PBX_IODBC$ac_delim - ISDNNET_LIB!$ISDNNET_LIB$ac_delim - ISDNNET_INCLUDE!$ISDNNET_INCLUDE$ac_delim - ISDNNET_DIR!$ISDNNET_DIR$ac_delim -@@ -51241,22 +53903,12 @@ - LDAP_INCLUDE!$LDAP_INCLUDE$ac_delim - LDAP_DIR!$LDAP_DIR$ac_delim - PBX_LDAP!$PBX_LDAP$ac_delim -+LIBXML2_LIB!$LIBXML2_LIB$ac_delim -+LIBXML2_INCLUDE!$LIBXML2_INCLUDE$ac_delim -+LIBXML2_DIR!$LIBXML2_DIR$ac_delim -+PBX_LIBXML2!$PBX_LIBXML2$ac_delim - LTDL_LIB!$LTDL_LIB$ac_delim - LTDL_INCLUDE!$LTDL_INCLUDE$ac_delim --LTDL_DIR!$LTDL_DIR$ac_delim --PBX_LTDL!$PBX_LTDL$ac_delim --LUA_LIB!$LUA_LIB$ac_delim --LUA_INCLUDE!$LUA_INCLUDE$ac_delim --LUA_DIR!$LUA_DIR$ac_delim --PBX_LUA!$PBX_LUA$ac_delim --MISDN_LIB!$MISDN_LIB$ac_delim --MISDN_INCLUDE!$MISDN_INCLUDE$ac_delim --MISDN_DIR!$MISDN_DIR$ac_delim --PBX_MISDN!$PBX_MISDN$ac_delim --NBS_LIB!$NBS_LIB$ac_delim --NBS_INCLUDE!$NBS_INCLUDE$ac_delim --NBS_DIR!$NBS_DIR$ac_delim --PBX_NBS!$PBX_NBS$ac_delim - _ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then -@@ -51298,6 +53950,20 @@ - ac_delim='%!_!# ' - for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -+LTDL_DIR!$LTDL_DIR$ac_delim -+PBX_LTDL!$PBX_LTDL$ac_delim -+LUA_LIB!$LUA_LIB$ac_delim -+LUA_INCLUDE!$LUA_INCLUDE$ac_delim -+LUA_DIR!$LUA_DIR$ac_delim -+PBX_LUA!$PBX_LUA$ac_delim -+MISDN_LIB!$MISDN_LIB$ac_delim -+MISDN_INCLUDE!$MISDN_INCLUDE$ac_delim -+MISDN_DIR!$MISDN_DIR$ac_delim -+PBX_MISDN!$PBX_MISDN$ac_delim -+NBS_LIB!$NBS_LIB$ac_delim -+NBS_INCLUDE!$NBS_INCLUDE$ac_delim -+NBS_DIR!$NBS_DIR$ac_delim -+PBX_NBS!$PBX_NBS$ac_delim - NCURSES_LIB!$NCURSES_LIB$ac_delim - NCURSES_INCLUDE!$NCURSES_INCLUDE$ac_delim - NCURSES_DIR!$NCURSES_DIR$ac_delim -@@ -51310,10 +53976,6 @@ - NEWT_INCLUDE!$NEWT_INCLUDE$ac_delim - NEWT_DIR!$NEWT_DIR$ac_delim - PBX_NEWT!$PBX_NEWT$ac_delim --UNIXODBC_LIB!$UNIXODBC_LIB$ac_delim --UNIXODBC_INCLUDE!$UNIXODBC_INCLUDE$ac_delim --UNIXODBC_DIR!$UNIXODBC_DIR$ac_delim --PBX_UNIXODBC!$PBX_UNIXODBC$ac_delim - OGG_LIB!$OGG_LIB$ac_delim - OGG_INCLUDE!$OGG_INCLUDE$ac_delim - OGG_DIR!$OGG_DIR$ac_delim -@@ -51385,16 +54047,6 @@ - SPEEX_PREPROCESS_LIB!$SPEEX_PREPROCESS_LIB$ac_delim - SPEEX_PREPROCESS_INCLUDE!$SPEEX_PREPROCESS_INCLUDE$ac_delim - SPEEX_PREPROCESS_DIR!$SPEEX_PREPROCESS_DIR$ac_delim --PBX_SPEEX_PREPROCESS!$PBX_SPEEX_PREPROCESS$ac_delim --SPEEXDSP_LIB!$SPEEXDSP_LIB$ac_delim --SPEEXDSP_INCLUDE!$SPEEXDSP_INCLUDE$ac_delim --SPEEXDSP_DIR!$SPEEXDSP_DIR$ac_delim --PBX_SPEEXDSP!$PBX_SPEEXDSP$ac_delim --SQLITE_LIB!$SQLITE_LIB$ac_delim --SQLITE_INCLUDE!$SQLITE_INCLUDE$ac_delim --SQLITE_DIR!$SQLITE_DIR$ac_delim --PBX_SQLITE!$PBX_SQLITE$ac_delim --SQLITE3_LIB!$SQLITE3_LIB$ac_delim - _ACEOF - - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then -@@ -51436,6 +54088,16 @@ - ac_delim='%!_!# ' - for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -+PBX_SPEEX_PREPROCESS!$PBX_SPEEX_PREPROCESS$ac_delim -+SPEEXDSP_LIB!$SPEEXDSP_LIB$ac_delim -+SPEEXDSP_INCLUDE!$SPEEXDSP_INCLUDE$ac_delim -+SPEEXDSP_DIR!$SPEEXDSP_DIR$ac_delim -+PBX_SPEEXDSP!$PBX_SPEEXDSP$ac_delim -+SQLITE_LIB!$SQLITE_LIB$ac_delim -+SQLITE_INCLUDE!$SQLITE_INCLUDE$ac_delim -+SQLITE_DIR!$SQLITE_DIR$ac_delim -+PBX_SQLITE!$PBX_SQLITE$ac_delim -+SQLITE3_LIB!$SQLITE3_LIB$ac_delim - SQLITE3_INCLUDE!$SQLITE3_INCLUDE$ac_delim - SQLITE3_DIR!$SQLITE3_DIR$ac_delim - PBX_SQLITE3!$PBX_SQLITE3$ac_delim -@@ -51463,6 +54125,10 @@ - TONEZONE_INCLUDE!$TONEZONE_INCLUDE$ac_delim - TONEZONE_DIR!$TONEZONE_DIR$ac_delim - PBX_TONEZONE!$PBX_TONEZONE$ac_delim -+UNIXODBC_LIB!$UNIXODBC_LIB$ac_delim -+UNIXODBC_INCLUDE!$UNIXODBC_INCLUDE$ac_delim -+UNIXODBC_DIR!$UNIXODBC_DIR$ac_delim -+PBX_UNIXODBC!$PBX_UNIXODBC$ac_delim - USB_LIB!$USB_LIB$ac_delim - USB_INCLUDE!$USB_INCLUDE$ac_delim - USB_DIR!$USB_DIR$ac_delim -@@ -51483,8 +54149,13 @@ - ZLIB_INCLUDE!$ZLIB_INCLUDE$ac_delim - ZLIB_DIR!$ZLIB_DIR$ac_delim - PBX_ZLIB!$PBX_ZLIB$ac_delim -+TIMERFD_LIB!$TIMERFD_LIB$ac_delim -+TIMERFD_INCLUDE!$TIMERFD_INCLUDE$ac_delim -+TIMERFD_DIR!$TIMERFD_DIR$ac_delim -+PBX_TIMERFD!$PBX_TIMERFD$ac_delim - ALLOCA!$ALLOCA$ac_delim - LIBOBJS!$LIBOBJS$ac_delim -+PBX_WORKING_FORK!$PBX_WORKING_FORK$ac_delim - POW_LIB!$POW_LIB$ac_delim - HAS_POLL!$HAS_POLL$ac_delim - PBX_PTHREAD_RWLOCK_INITIALIZER!$PBX_PTHREAD_RWLOCK_INITIALIZER$ac_delim -@@ -51497,7 +54168,9 @@ - AST_SHADOW_WARNINGS!$AST_SHADOW_WARNINGS$ac_delim - PBX_RTLD_NOLOAD!$PBX_RTLD_NOLOAD$ac_delim - PBX_IP_MTU_DISCOVER!$PBX_IP_MTU_DISCOVER$ac_delim -+PBX_DAHDI_HALF_FULL!$PBX_DAHDI_HALF_FULL$ac_delim - GSM_INTERNAL!$GSM_INTERNAL$ac_delim -+CONFIG_LIBXML2!$CONFIG_LIBXML2$ac_delim - PBX_MISDN_FAC_RESULT!$PBX_MISDN_FAC_RESULT$ac_delim - PBX_MISDN_FAC_ERROR!$PBX_MISDN_FAC_ERROR$ac_delim - CONFIG_NETSNMP!$CONFIG_NETSNMP$ac_delim -@@ -51512,6 +54185,47 @@ - OPENH323_LIBDIR!$OPENH323_LIBDIR$ac_delim - OPENH323_SUFFIX!$OPENH323_SUFFIX$ac_delim - OPENH323_BUILD!$OPENH323_BUILD$ac_delim -+_ACEOF -+ -+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then -+ break -+ elif $ac_last_try; then -+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} -+ { (exit 1); exit 1; }; } -+ else -+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! " -+ fi -+done -+ -+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` -+if test -n "$ac_eof"; then -+ ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` -+ ac_eof=`expr $ac_eof + 1` -+fi -+ -+cat >>$CONFIG_STATUS <<_ACEOF -+cat >"\$tmp/subs-4.sed" <<\CEOF$ac_eof -+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -+_ACEOF -+sed ' -+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g -+s/^/s,@/; s/!/@,|#_!!_#|/ -+:n -+t n -+s/'"$ac_delim"'$/,g/; t -+s/$/\\/; p -+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n -+' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF -+CEOF$ac_eof -+_ACEOF -+ -+ -+ac_delim='%!_!# ' -+for ac_last_try in false false false false false :; do -+ cat >conf$$subs.sed <<_ACEOF - PBX_AIS!$PBX_AIS$ac_delim - AIS_INCLUDE!$AIS_INCLUDE$ac_delim - AIS_LIB!$AIS_LIB$ac_delim -@@ -51523,10 +54237,13 @@ - CONFIG_GTK!$CONFIG_GTK$ac_delim - PKGCONFIG!$PKGCONFIG$ac_delim - CURL_CONFIG!$CURL_CONFIG$ac_delim -+GENERIC_ODBC_LIB!$GENERIC_ODBC_LIB$ac_delim -+GENERIC_ODBC_INCLUDE!$GENERIC_ODBC_INCLUDE$ac_delim -+PBX_GENERIC_ODBC!$PBX_GENERIC_ODBC$ac_delim - LTLIBOBJS!$LTLIBOBJS$ac_delim - _ACEOF - -- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 88; then -+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 15; then - break - elif $ac_last_try; then - { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -@@ -51544,7 +54261,7 @@ - fi - - cat >>$CONFIG_STATUS <<_ACEOF --cat >"\$tmp/subs-4.sed" <<\CEOF$ac_eof -+cat >"\$tmp/subs-5.sed" <<\CEOF$ac_eof - /@[a-zA-Z_][a-zA-Z_0-9]*@/!b end - _ACEOF - sed ' -@@ -51807,7 +54524,7 @@ - s&@abs_top_builddir@&$ac_abs_top_builddir&;t t - s&@INSTALL@&$ac_INSTALL&;t t - $ac_datarootdir_hack --" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" | sed -f "$tmp/subs-3.sed" | sed -f "$tmp/subs-4.sed" >$tmp/out -+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" | sed -f "$tmp/subs-3.sed" | sed -f "$tmp/subs-4.sed" | sed -f "$tmp/subs-5.sed" >$tmp/out - - test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && -Index: pbx/pbx_config.c -=================================================================== ---- a/pbx/pbx_config.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/pbx/pbx_config.c (.../team/group/issue14292) (revision 178988) -@@ -1398,11 +1398,41 @@ - if (overrideswitch_config) { - ast_free(overrideswitch_config); - } -- ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_pbx_config, ARRAY_LEN(cli_pbx_config)); - ast_context_destroy(NULL, registrar); - return 0; - } - -+/*!\note Protect against misparsing based upon commas in the middle of fields -+ * like character classes. We've taken steps to permit pretty much every other -+ * printable character in a character class, so properly handling a comma at -+ * this level is a natural extension. This is almost like the standard -+ * application parser in app.c, except that it handles square brackets. */ -+static char *pbx_strsep(char **destructible, const char *delim) -+{ -+ int square = 0; -+ char *res = *destructible; -+ for (; destructible && *destructible && **destructible; (*destructible)++) { -+ if (**destructible == '[' && !strchr(delim, '[')) { -+ square++; -+ } else if (**destructible == ']' && !strchr(delim, ']')) { -+ if (square) { -+ square--; -+ } -+ } else if (**destructible == '\\' && !strchr(delim, '\\')) { -+ (*destructible)++; -+ } else if (strchr(delim, **destructible) && !square) { -+ **destructible = '\0'; -+ (*destructible)++; -+ break; -+ } -+ } -+ if (destructible && *destructible && **destructible == '\0') { -+ *destructible = NULL; -+ } -+ return res; -+} -+ - static int pbx_load_config(const char *config_file) - { - struct ast_config *cfg; -@@ -1420,8 +1450,9 @@ - const char *aft; - const char *newpm, *ovsw; - struct ast_flags config_flags = { 0 }; -+ char lastextension[256]; - cfg = ast_config_load(config_file, config_flags); -- if (!cfg) -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) - return 0; - - /* Use existing config to populate the PBX table */ -@@ -1443,127 +1474,168 @@ - } - } - -- if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext"))) -- ast_copy_string(userscontext, cxt, sizeof(userscontext)); -- else -- ast_copy_string(userscontext, "default", sizeof(userscontext)); -+ ast_copy_string(userscontext, ast_variable_retrieve(cfg, "general", "userscontext") ?: "default", sizeof(userscontext)); - - for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) { - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); - pbx_builtin_setvar_helper(NULL, v->name, realvalue); - } -- for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) { -+ for (cxt = ast_category_browse(cfg, NULL); -+ cxt; -+ cxt = ast_category_browse(cfg, cxt)) { - /* All categories but "general" or "globals" are considered contexts */ -- if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) -+ if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) { - continue; -- con=ast_context_find_or_create(&local_contexts, local_table, cxt, registrar); -- if (con == NULL) -+ } -+ if (!(con = ast_context_find_or_create(&local_contexts, local_table, cxt, registrar))) { - continue; -+ } - -+ /* Reset continuation items at the beginning of each context */ -+ lastextension[0] = '\0'; -+ lastpri = -2; -+ - for (v = ast_variable_browse(cfg, cxt); v; v = v->next) { -- if (!strcasecmp(v->name, "exten")) { -- char *tc = ast_strdup(v->value); -- if (tc) { -- int ipri = -2; -- char realext[256]=""; -- char *plus, *firstp; -- char *pri, *appl, *data, *cidmatch; -- char *stringp = tc; -- char *ext = strsep(&stringp, ","); -- if (!ext) -- ext=""; -- pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1); -- cidmatch = strchr(realext, '/'); -- if (cidmatch) { -- *cidmatch++ = '\0'; -- ast_shrink_phone_number(cidmatch); -+ char *tc = NULL; -+ char realext[256] = ""; -+ char *stringp, *ext; -+ -+ if (!strncasecmp(v->name, "same", 4)) { -+ if (ast_strlen_zero(lastextension)) { -+ ast_log(LOG_ERROR, "No previous pattern in the first entry of context '%s' to match '%s'!\n", cxt, v->name); -+ continue; -+ } -+ if ((stringp = tc = ast_strdup(v->value))) { -+ ast_copy_string(realext, lastextension, sizeof(realext)); -+ goto process_extension; -+ } -+ } else if (!strcasecmp(v->name, "exten")) { -+ int ipri = -2; -+ char *plus, *firstp; -+ char *pri, *appl, *data, *cidmatch; -+ -+ if (!(stringp = tc = ast_strdup(v->value))) { -+ continue; -+ } -+ -+ ext = S_OR(pbx_strsep(&stringp, ","), ""); -+ pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1); -+ ast_copy_string(lastextension, realext, sizeof(lastextension)); -+process_extension: -+ if ((cidmatch = strchr(realext, '/'))) { -+ *cidmatch++ = '\0'; -+ ast_shrink_phone_number(cidmatch); -+ } -+ pri = S_OR(strsep(&stringp, ","), ""); -+ pri = ast_skip_blanks(pri); -+ pri = ast_trim_blanks(pri); -+ if ((label = strchr(pri, '('))) { -+ *label++ = '\0'; -+ if ((end = strchr(label, ')'))) { -+ *end = '\0'; -+ } else { -+ ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno); - } -- pri = strsep(&stringp, ","); -- if (!pri) -- pri=""; -- pri = ast_skip_blanks(pri); -- pri = ast_trim_blanks(pri); -- label = strchr(pri, '('); -- if (label) { -- *label++ = '\0'; -- end = strchr(label, ')'); -- if (end) -- *end = '\0'; -- else -- ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno); -+ } -+ if ((plus = strchr(pri, '+'))) { -+ *plus++ = '\0'; -+ } -+ if (!strcmp(pri,"hint")) { -+ ipri = PRIORITY_HINT; -+ } else if (!strcmp(pri, "next") || !strcmp(pri, "n")) { -+ if (lastpri > -2) { -+ ipri = lastpri + 1; -+ } else { -+ ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n"); - } -- plus = strchr(pri, '+'); -- if (plus) -- *plus++ = '\0'; -- if (!strcmp(pri,"hint")) -- ipri=PRIORITY_HINT; -- else if (!strcmp(pri, "next") || !strcmp(pri, "n")) { -- if (lastpri > -2) -- ipri = lastpri + 1; -- else -- ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n"); -- } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) { -- if (lastpri > -2) -- ipri = lastpri; -- else -- ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n"); -- } else if (sscanf(pri, "%d", &ipri) != 1 && -- (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) { -- ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno); -- ipri = 0; -+ } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) { -+ if (lastpri > -2) { -+ ipri = lastpri; -+ } else { -+ ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n"); - } -- appl = S_OR(stringp, ""); -- /* Find the first occurrence of '(' */ -- firstp = strchr(appl, '('); -- if (!firstp) { -- /* No arguments */ -- data = ""; -+ } else if (sscanf(pri, "%d", &ipri) != 1 && -+ (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) { -+ ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno); -+ ipri = 0; -+ } -+ appl = S_OR(stringp, ""); -+ /* Find the first occurrence of '(' */ -+ if (!(firstp = strchr(appl, '('))) { -+ /* No arguments */ -+ data = ""; -+ } else { -+ appl = strsep(&stringp, "("); -+ data = S_OR(stringp, ""); -+ if ((end = strrchr(data, ')'))) { -+ *end = '\0'; - } else { -- appl = strsep(&stringp, "("); -- data = stringp; -- end = strrchr(data, ')'); -- if ((end = strrchr(data, ')'))) { -- *end = '\0'; -- } else { -- ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data); -- } -+ ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data); - } -+ } - -- if (!data) -- data = ""; -- appl = ast_skip_blanks(appl); -- if (ipri) { -- if (plus) -- ipri += atoi(plus); -- lastpri = ipri; -- if (!ast_opt_dont_warn && !strcmp(realext, "_.")) -- ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno); -- if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, registrar)) { -- ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno); -- } -+ appl = ast_skip_blanks(appl); -+ if (ipri) { -+ if (plus) { -+ ipri += atoi(plus); - } -- free(tc); -+ lastpri = ipri; -+ if (!ast_opt_dont_warn && !strcmp(realext, "_.")) { -+ ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno); -+ } -+ if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, registrar)) { -+ ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno); -+ } - } -+ free(tc); - } else if (!strcasecmp(v->name, "include")) { - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); -- if (ast_context_add_include2(con, realvalue, registrar)) -- ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt); -+ if (ast_context_add_include2(con, realvalue, registrar)) { -+ switch (errno) { -+ case ENOMEM: -+ ast_log(LOG_WARNING, "Out of memory for context addition\n"); -+ break; -+ -+ case EBUSY: -+ ast_log(LOG_WARNING, "Failed to lock context(s) list, please try again later\n"); -+ break; -+ -+ case EEXIST: -+ ast_log(LOG_WARNING, "Context '%s' already included in '%s' context\n", -+ v->value, cxt); -+ break; -+ -+ case ENOENT: -+ case EINVAL: -+ ast_log(LOG_WARNING, "There is no existence of context '%s'\n", -+ errno == ENOENT ? v->value : cxt); -+ break; -+ -+ default: -+ ast_log(LOG_WARNING, "Failed to include '%s' in '%s' context\n", -+ v->value, cxt); -+ break; -+ } -+ } - } else if (!strcasecmp(v->name, "ignorepat")) { - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); -- if (ast_context_add_ignorepat2(con, realvalue, registrar)) -+ if (ast_context_add_ignorepat2(con, realvalue, registrar)) { - ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt); -+ } - } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) { - char *stringp = realvalue; - char *appl, *data; - -- if (!strcasecmp(v->name, "switch")) -+ if (!strcasecmp(v->name, "switch")) { - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); -- else -+ } else { - ast_copy_string(realvalue, v->value, sizeof(realvalue)); -+ } - appl = strsep(&stringp, "/"); - data = S_OR(stringp, ""); -- if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar)) -+ if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar)) { - ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt); -+ } - } else { - ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno); - } -@@ -1724,7 +1796,7 @@ - - if (static_config && !write_protect_config) - ast_cli_register(&cli_dialplan_save); -- ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_pbx_config, ARRAY_LEN(cli_pbx_config)); - - return AST_MODULE_LOAD_SUCCESS; - } -Index: pbx/pbx_ael.c -=================================================================== ---- a/pbx/pbx_ael.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/pbx/pbx_ael.c (.../team/group/issue14292) (revision 178988) -@@ -158,40 +158,6 @@ - } - - /* CLI interface */ --static char *handle_cli_ael_debug_multiple_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "ael debug [read|tokens|macros|contexts|off]"; -- e->usage = -- "Usage: ael debug [read|tokens|macros|contexts|off]\n" -- " Enable AEL read, token, macro, or context debugging,\n" -- " or disable all AEL debugging messages. Note: this\n" -- " currently does nothing.\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- -- if (a->argc != 3) -- return CLI_SHOWUSAGE; -- -- if (!strcasecmp(a->argv[2], "read")) -- aeldebug |= DEBUG_READ; -- else if (!strcasecmp(a->argv[2], "tokens")) -- aeldebug |= DEBUG_TOKENS; -- else if (!strcasecmp(a->argv[2], "macros")) -- aeldebug |= DEBUG_MACROS; -- else if (!strcasecmp(a->argv[2], "contexts")) -- aeldebug |= DEBUG_CONTEXTS; -- else if (!strcasecmp(a->argv[2], "off")) -- aeldebug = 0; -- else -- return CLI_SHOWUSAGE; -- -- return CLI_SUCCESS; --} -- - static char *handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { -@@ -245,22 +211,21 @@ - return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS); - } - --static struct ast_cli_entry cli_ael_debug_multiple_deprecated = AST_CLI_DEFINE(handle_cli_ael_debug_multiple_deprecated, "Enable AEL debugging flags"); - static struct ast_cli_entry cli_ael[] = { - AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"), -- AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags", .deprecate_cmd = &cli_ael_debug_multiple_deprecated) -+ AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags") - }; - - static int unload_module(void) - { - ast_context_destroy(NULL, registrar); -- ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael)); - return 0; - } - - static int load_module(void) - { -- ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael)); - return (pbx_load_module()); - } - -Index: pbx/pbx_realtime.c -=================================================================== ---- a/pbx/pbx_realtime.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/pbx/pbx_realtime.c (.../team/group/issue14292) (revision 178988) -@@ -46,6 +46,7 @@ - #include "asterisk/utils.h" - #include "asterisk/crypto.h" - #include "asterisk/astdb.h" -+#include "asterisk/app.h" - - #define MODE_MATCH 0 - #define MODE_MATCHMORE 1 -@@ -53,6 +54,14 @@ - - #define EXT_DATA_SIZE 256 - -+enum { -+ OPTION_PATTERNS_DISABLED = (1 << 0), -+} option_flags; -+ -+AST_APP_OPTIONS(switch_opts, { -+ AST_APP_OPTION('p', OPTION_PATTERNS_DISABLED), -+}); -+ - /* Realtime switch looks up extensions in the supplied realtime table. - - [context@][realtimetable][/options] -@@ -67,7 +76,7 @@ - */ - - --static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode) -+static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode, struct ast_flags flags) - { - struct ast_variable *var; - struct ast_config *cfg; -@@ -75,6 +84,12 @@ - char *ematch; - char rexten[AST_MAX_EXTENSION + 20]=""; - int match; -+ /* Optimization: since we don't support hints in realtime, it's silly to -+ * query for a hint here, since we won't actually do anything with it. -+ * This just wastes CPU time and resources. */ -+ if (priority < 0) { -+ return NULL; -+ } - snprintf(pri, sizeof(pri), "%d", priority); - switch(mode) { - case MODE_MATCHMORE: -@@ -91,7 +106,7 @@ - ast_copy_string(rexten, exten, sizeof(rexten)); - } - var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, SENTINEL); -- if (!var) { -+ if (!var && !ast_test_flag(&flags, OPTION_PATTERNS_DISABLED)) { - cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, SENTINEL); - if (cfg) { - char *cat = ast_category_browse(cfg, NULL); -@@ -125,8 +140,11 @@ - const char *ctx = NULL; - char *table; - struct ast_variable *var=NULL; -+ struct ast_flags flags = { 0, }; - char *buf = ast_strdupa(data); - if (buf) { -+ /* "Realtime" prefix is stripped off in the parent engine. The -+ * remaining string is: [[context@]table][/opts] */ - char *opts = strchr(buf, '/'); - if (opts) - *opts++ = '\0'; -@@ -137,7 +155,10 @@ - } - ctx = S_OR(ctx, context); - table = S_OR(table, "extensions"); -- var = realtime_switch_common(table, ctx, exten, priority, mode); -+ if (!ast_strlen_zero(opts)) { -+ ast_app_parse_options(switch_opts, &flags, NULL, opts); -+ } -+ var = realtime_switch_common(table, ctx, exten, priority, mode, flags); - } - return var; - } -Index: pbx/pbx_dundi.c -=================================================================== ---- a/pbx/pbx_dundi.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/pbx/pbx_dundi.c (.../team/group/issue14292) (revision 178988) -@@ -2192,30 +2192,6 @@ - return 0; - } - --static char *dundi_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "dundi [no] debug"; -- e->usage = -- "Usage: dundi [no] debug\n" -- " Enables/Disables dumping of DUNDi packets for debugging purposes\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- if (a->argc < 2 || a->argc > 3) -- return CLI_SHOWUSAGE; -- if (a->argc == 2) { -- dundidebug = 1; -- ast_cli(a->fd, "DUNDi Debugging Enabled\n"); -- } else { -- dundidebug = 0; -- ast_cli(a->fd, "DUNDi Debugging Disabled\n"); -- } -- return CLI_SUCCESS; --} -- - static char *dundi_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { -@@ -2242,32 +2218,6 @@ - return CLI_SUCCESS; - } - --static char *dundi_do_store_history_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "dundi [no] store history"; -- e->usage = -- "Usage: dundi [no] store history\n" -- " Enables/Disables storing of DUNDi requests and times for debugging\n" -- "purposes\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- if (a->argc < 3 || a->argc > 4) -- return CLI_SHOWUSAGE; -- -- if (a->argc == 3) { -- global_storehistory = 1; -- ast_cli(a->fd, "DUNDi History Storage Enabled\n"); -- } else { -- global_storehistory = 0; -- ast_cli(a->fd, "DUNDi History Storage Disabled\n"); -- } -- return CLI_SUCCESS; --} -- - static char *dundi_store_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { -@@ -2855,11 +2805,9 @@ - #undef FORMAT2 - } - --static struct ast_cli_entry cli_dundi_do_debug_deprecated = AST_CLI_DEFINE(dundi_do_debug_deprecated, "Enable/Disable DUNDi debugging"); --static struct ast_cli_entry cli_dundi_do_store_history_deprecated = AST_CLI_DEFINE(dundi_do_store_history_deprecated, "Enable/Disable DUNDi historic records"); - static struct ast_cli_entry cli_dundi[] = { -- AST_CLI_DEFINE(dundi_set_debug, "Enable/Disable DUNDi debugging", .deprecate_cmd = &cli_dundi_do_debug_deprecated), -- AST_CLI_DEFINE(dundi_store_history, "Enable/Disable DUNDi historic records", .deprecate_cmd = &cli_dundi_do_store_history_deprecated), -+ AST_CLI_DEFINE(dundi_set_debug, "Enable/Disable DUNDi debugging"), -+ AST_CLI_DEFINE(dundi_store_history, "Enable/Disable DUNDi historic records"), - AST_CLI_DEFINE(dundi_flush, "Flush DUNDi cache"), - AST_CLI_DEFINE(dundi_show_peers, "Show defined DUNDi peers"), - AST_CLI_DEFINE(dundi_show_trans, "Show active DUNDi transactions"), -@@ -4621,14 +4569,13 @@ - return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE); - } - --static struct ast_switch dundi_switch = --{ -- name: "DUNDi", -- description: "DUNDi Discovered Dialplan Switch", -- exists: dundi_exists, -- canmatch: dundi_canmatch, -- exec: dundi_exec, -- matchmore: dundi_matchmore, -+static struct ast_switch dundi_switch = { -+ .name = "DUNDi", -+ .description = "DUNDi Discovered Dialplan Switch", -+ .exists = dundi_exists, -+ .canmatch = dundi_canmatch, -+ .exec = dundi_exec, -+ .matchmore = dundi_matchmore, - }; - - static int set_config(char *config_file, struct sockaddr_in* sin, int reload) -@@ -4646,7 +4593,7 @@ - int globalpcmodel = 0; - dundi_eid testeid; - -- if (!(cfg = ast_config_load(config_file, config_flags))) { -+ if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Unable to load config %s\n", config_file); - return -1; - } -@@ -4792,7 +4739,7 @@ - pthread_join(previous_clearcachethreadid, NULL); - } - -- ast_cli_unregister_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_dundi, ARRAY_LEN(cli_dundi)); - ast_unregister_switch(&dundi_switch); - ast_custom_function_unregister(&dundi_function); - ast_custom_function_unregister(&dundi_query_function); -@@ -4860,7 +4807,7 @@ - return AST_MODULE_LOAD_FAILURE; - } - -- ast_cli_register_multiple(cli_dundi, sizeof(cli_dundi) / sizeof(*cli_dundi)); -+ ast_cli_register_multiple(cli_dundi, ARRAY_LEN(cli_dundi)); - if (ast_register_switch(&dundi_switch)) - ast_log(LOG_ERROR, "Unable to register DUNDi switch\n"); - ast_custom_function_register(&dundi_function); -Index: channels/h323/cisco-h225.cxx -=================================================================== ---- a/channels/h323/cisco-h225.cxx (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/cisco-h225.cxx (.../team/group/issue14292) (revision 178988) -@@ -61,7 +61,7 @@ - } - - --BOOL CISCO_H225_RedirectIEinfo::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_RedirectIEinfo::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -137,7 +137,7 @@ - } - - --BOOL CISCO_H225_ProgIndIEinfo::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_ProgIndIEinfo::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -217,7 +217,7 @@ - } - - --BOOL CISCO_H225_QsigNonStdInfo::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_QsigNonStdInfo::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -300,7 +300,7 @@ - } - - --BOOL CISCO_H225_CallMgrParam::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_CallMgrParam::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -379,7 +379,7 @@ - } - - --BOOL CISCO_H225_CallPreserveParam::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_CallPreserveParam::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -458,7 +458,7 @@ - } - - --BOOL CISCO_H225_CallSignallingParam::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_CallSignallingParam::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -535,7 +535,7 @@ - } - - --BOOL CISCO_H225_CommonParam::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_CommonParam::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -611,7 +611,7 @@ - } - - --BOOL CISCO_H225_ProgIndParam::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_ProgIndParam::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -687,7 +687,7 @@ - } - - --BOOL CISCO_H225_ProtoParam::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_ProtoParam::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -@@ -789,7 +789,7 @@ - } - - --BOOL CISCO_H225_H323_UU_NonStdInfo::Decode(PASN_Stream & strm) -+PBoolean CISCO_H225_H323_UU_NonStdInfo::Decode(PASN_Stream & strm) - { - if (!PreambleDecode(strm)) - return FALSE; -Index: channels/h323/compat_h323.cxx -=================================================================== ---- a/channels/h323/compat_h323.cxx (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/compat_h323.cxx (.../team/group/issue14292) (revision 178988) -@@ -38,12 +38,12 @@ - MyH323TransportTCP::MyH323TransportTCP( - H323EndPoint & endpoint, - PIPSocket::Address binding, -- BOOL listen) -+ PBoolean listen) - : H323TransportTCP(endpoint, binding, listen) - { - } - --BOOL MyH323TransportTCP::Connect() -+PBoolean MyH323TransportTCP::Connect() - { - if (IsListening()) - return TRUE; -@@ -91,7 +91,7 @@ - } - #endif - --BOOL MyH323TransportUDP::DiscoverGatekeeper(H323Gatekeeper &gk, H323RasPDU &pdu, const H323TransportAddress &address) -+PBoolean MyH323TransportUDP::DiscoverGatekeeper(H323Gatekeeper &gk, H323RasPDU &pdu, const H323TransportAddress &address) - { - PThread *thd = PThread::Current(); - -Index: channels/h323/caps_h323.cxx -=================================================================== ---- a/channels/h323/caps_h323.cxx (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/caps_h323.cxx (.../team/group/issue14292) (revision 178988) -@@ -159,7 +159,7 @@ - /* - * Capability: G.723.1 - */ --AST_G7231Capability::AST_G7231Capability(int rx_frames, BOOL annexA_) -+AST_G7231Capability::AST_G7231Capability(int rx_frames, PBoolean annexA_) - : H323AudioCapability(rx_frames, 4) - { - annexA = annexA_; -@@ -196,7 +196,7 @@ - return H245_AudioCapability::e_g7231; - } - --BOOL AST_G7231Capability::OnSendingPDU(H245_AudioCapability & cap, -+PBoolean AST_G7231Capability::OnSendingPDU(H245_AudioCapability & cap, - unsigned packetSize) const - { - cap.SetTag(H245_AudioCapability::e_g7231); -@@ -206,7 +206,7 @@ - return TRUE; - } - --BOOL AST_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap, -+PBoolean AST_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap, - unsigned & packetSize) - { - if (cap.GetTag() != H245_AudioCapability::e_g7231) { -@@ -299,7 +299,7 @@ - return H245_AudioCapability::e_gsmFullRate; - } - --BOOL AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap, -+PBoolean AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap, - unsigned packetSize) const - { - cap.SetTag(H245_AudioCapability::e_gsmFullRate); -@@ -310,7 +310,7 @@ - return TRUE; - } - --BOOL AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap, -+PBoolean AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap, - unsigned & packetSize) - { - if (cap.GetTag() != H245_AudioCapability::e_gsmFullRate) -Index: channels/h323/ast_h323.cxx -=================================================================== ---- a/channels/h323/ast_h323.cxx (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/ast_h323.cxx (.../team/group/issue14292) (revision 178988) -@@ -28,6 +28,9 @@ - * - * Version Info: $Id$ - */ -+ -+#include "asterisk.h" -+ - #include - - #include -@@ -63,8 +66,6 @@ - #include "cisco-h225.h" - #include "caps_h323.h" - --#include -- - #if PWLIB_MAJOR * 10000 + PWLIB_MINOR * 100 + PWLIB_BUILD >= 1 * 10000 + 12 * 100 + 0 - #define SKIP_PWLIB_PIPE_BUG_WORKAROUND 1 - #endif -@@ -331,7 +332,7 @@ - terminalType = e_GatewayOnly; - } - --BOOL MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason) -+PBoolean MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason) - { - if (h323debug) { - #ifdef PTRACING -@@ -343,7 +344,7 @@ - return H323EndPoint::ClearCall(token, reason); - } - --BOOL MyH323EndPoint::ClearCall(const PString & token) -+PBoolean MyH323EndPoint::ClearCall(const PString & token) - { - if (h323debug) { - cout << "\t-- ClearCall: Request to clear call with token " << token << endl; -@@ -371,7 +372,7 @@ - H323EndPoint::OnClosedLogicalChannel(connection, channel); - } - --BOOL MyH323EndPoint::OnConnectionForwarded(H323Connection & connection, -+PBoolean MyH323EndPoint::OnConnectionForwarded(H323Connection & connection, - const PString & forwardParty, - const H323SignalPDU & pdu) - { -@@ -381,7 +382,7 @@ - return FALSE; - } - --BOOL MyH323EndPoint::ForwardConnection(H323Connection & connection, -+PBoolean MyH323EndPoint::ForwardConnection(H323Connection & connection, - const PString & forwardParty, - const H323SignalPDU & pdu) - { -@@ -585,9 +586,9 @@ - return; - } - --BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu) -+PBoolean MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu) - { -- BOOL isInband; -+ PBoolean isInband; - unsigned pi; - - if (!H323Connection::OnReceivedProgress(pdu)) { -@@ -613,7 +614,7 @@ - return connectionState != ShuttingDownConnection; - } - --BOOL MyH323Connection::MySendProgress() -+PBoolean MyH323Connection::MySendProgress() - { - /* The code taken from H323Connection::AnsweringCall() but ALWAYS send - PROGRESS message, including slow start operations */ -@@ -693,7 +694,7 @@ - return ((pi || (fastStartState != FastStartDisabled)) ? AnswerCallDeferredWithMedia : AnswerCallDeferred); - } - --BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username) -+PBoolean MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username) - { - if (h323debug) { - cout << "\t=-= In OnAlerting for call " << GetCallReference() -@@ -702,7 +703,7 @@ - } - - if (on_progress) { -- BOOL isInband; -+ PBoolean isInband; - unsigned alertingPI; - - if (!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) { -@@ -726,7 +727,7 @@ - return connectionState != ShuttingDownConnection; - } - --void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming) -+void MyH323Connection::SetCallOptions(void *o, PBoolean isIncoming) - { - call_options_t *opts = (call_options_t *)o; - -@@ -757,7 +758,7 @@ - tunnelOptions = opts->tunnelOptions; - } - --void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming) -+void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, PBoolean isIncoming) - { - PString sourceE164; - PString destE164; -@@ -852,7 +853,7 @@ - } - - #ifdef TUNNELLING --static BOOL FetchInformationElements(Q931 &q931, const PBYTEArray &data) -+static PBoolean FetchInformationElements(Q931 &q931, const PBYTEArray &data) - { - PINDEX offset = 0; - -@@ -910,9 +911,9 @@ - return TRUE; - } - --static BOOL FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu) -+static PBoolean FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu) - { -- BOOL res = FALSE; -+ PBoolean res = FALSE; - const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu; - - if(uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) { -@@ -929,7 +930,7 @@ - CISCO_H225_H323_UU_NonStdInfo c; - PPER_Stream strm(data); - if (c.Decode(strm)) { -- BOOL haveIEs = FALSE; -+ PBoolean haveIEs = FALSE; - if (h323debug) - cout << setprecision(0) << "H323_UU_NonStdInfo = " << c << endl; - if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam)) { -@@ -954,19 +955,19 @@ - return res; - } - --static BOOL EmbedCiscoTunneledInfo(H323SignalPDU &pdu) -+static PBoolean EmbedCiscoTunneledInfo(H323SignalPDU &pdu) - { - static const struct { - Q931::InformationElementCodes ie; -- BOOL dontDelete; -+ PBoolean dontDelete; - } codes[] = { - { Q931::RedirectingNumberIE, }, - { Q931::FacilityIE, }, - // { Q931::CallingPartyNumberIE, TRUE }, - }; - -- BOOL res = FALSE; -- BOOL notRedirOnly = FALSE; -+ PBoolean res = FALSE; -+ PBoolean notRedirOnly = FALSE; - Q931 tmpQ931; - Q931 &q931 = pdu.GetQ931(); - -@@ -1024,9 +1025,9 @@ - - static const char OID_QSIG[] = "1.3.12.9"; - --static BOOL FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu) -+static PBoolean FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu) - { -- BOOL res = FALSE; -+ PBoolean res = FALSE; - const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu; - if (uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) { - const H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage; -@@ -1074,7 +1075,7 @@ - return NULL; - } - --static BOOL QSIGTunnelRequested(H323SignalPDU &pdu) -+static PBoolean QSIGTunnelRequested(H323SignalPDU &pdu) - { - H225_EndpointType *epType = GetEndpointType(pdu); - if (epType) { -@@ -1093,7 +1094,7 @@ - return FALSE; - } - --static BOOL EmbedQSIGTunneledInfo(H323SignalPDU &pdu) -+static PBoolean EmbedQSIGTunneledInfo(H323SignalPDU &pdu) - { - static const Q931::InformationElementCodes codes[] = - { Q931::RedirectingNumberIE, Q931::FacilityIE }; -@@ -1118,7 +1119,7 @@ - (*epType).m_supportedTunnelledProtocols.SetSize(0); - } - H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols; -- BOOL addQSIG = TRUE; -+ PBoolean addQSIG = TRUE; - for (int i = 0; i < protos.GetSize(); ++i) - { - if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) && -@@ -1150,7 +1151,7 @@ - return TRUE; - } - --BOOL MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu) -+PBoolean MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu) - { - if ((tunnelOptions & H323_TUNNEL_QSIG) || (remoteTunnelOptions & H323_TUNNEL_QSIG)) - EmbedQSIGTunneledInfo(pdu); -@@ -1161,7 +1162,7 @@ - } - - /* Handle tunneled messages */ --BOOL MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu) -+PBoolean MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu) - { - if (pdu.GetQ931().HasIE(Q931::UserUserIE)) { - Q931 tunneledInfo; -@@ -1196,7 +1197,7 @@ - } - #endif - --BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) -+PBoolean MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) - { - call_details_t cd; - -@@ -1232,7 +1233,7 @@ - return H323Connection::OnReceivedSignalSetup(setupPDU); - } - --BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) -+PBoolean MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) - { - call_details_t cd; - -@@ -1282,7 +1283,7 @@ - return H323Connection::OnSendSignalSetup(setupPDU); - } - --static BOOL BuildFastStartList(const H323Channel & channel, -+static PBoolean BuildFastStartList(const H323Channel & channel, - H225_ArrayOf_PASN_OctetString & array, - H323Channel::Directions reverseDirection) - { -@@ -1471,7 +1472,7 @@ - - signallingChannel->SetWriteTimeout(100); - -- BOOL connectFailed = !signallingChannel->Connect(); -+ PBoolean connectFailed = !signallingChannel->Connect(); - - // Lock while checking for shutting down. - if (!Lock()) -@@ -1546,14 +1547,14 @@ - setupPDU.GetQ931().GetCalledPartyNumber(remotePartyNumber); - - fastStartState = FastStartDisabled; -- BOOL set_lastPDUWasH245inSETUP = FALSE; -+ PBoolean set_lastPDUWasH245inSETUP = FALSE; - - if (h245Tunneling && doH245inSETUP) { - h245TunnelTxPDU = &setupPDU; - - // Try and start the master/slave and capability exchange through the tunnel - // Note: this used to be disallowed but is now allowed as of H323v4 -- BOOL ok = StartControlNegotiations(); -+ PBoolean ok = StartControlNegotiations(); - - h245TunnelTxPDU = NULL; - -@@ -1587,7 +1588,7 @@ - } - - --BOOL MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU) -+PBoolean MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU) - { - if (h323debug) { - cout << "\t-- Sending RELEASE COMPLETE" << endl; -@@ -1602,7 +1603,7 @@ - return H323Connection::OnSendReleaseComplete(releaseCompletePDU); - } - --BOOL MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu) -+PBoolean MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu) - { - if (h323debug) { - cout << "\t-- Received Facility message... " << endl; -@@ -1620,7 +1621,7 @@ - return H323Connection::OnReceivedReleaseComplete(pdu); - } - --BOOL MyH323Connection::OnClosingLogicalChannel(H323Channel & channel) -+PBoolean MyH323Connection::OnClosingLogicalChannel(H323Channel & channel) - { - if (h323debug) { - cout << "\t-- Closing logical channel..." << endl; -@@ -1693,7 +1694,7 @@ - on_setcapabilities(GetCallReference(), (const char *)callToken); - } - --BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps, -+PBoolean MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps, - const H245_MultiplexCapability * muxCap, - H245_TerminalCapabilitySetReject & reject) - { -@@ -1860,7 +1861,7 @@ - /** This callback function is invoked once upon creation of each - * channel for an H323 session - */ --BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel) -+PBoolean MyH323Connection::OnStartLogicalChannel(H323Channel & channel) - { - /* Increase the count of channels we have open */ - channelsOpen++; -@@ -2036,7 +2037,7 @@ - } - } - --BOOL MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address) -+PBoolean MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address) - { - // Check that it is an IP address, all we support at the moment - if (h245Address.GetTag() != H225_TransportAddress::e_ipAddress -@@ -2092,7 +2093,7 @@ - } - #endif - --void MyH323Connection::MyHoldCall(BOOL isHold) -+void MyH323Connection::MyHoldCall(PBoolean isHold) - { - if (((holdHandling & H323_HOLD_NOTIFY) != 0) || ((holdHandling & H323_HOLD_Q931ONLY) != 0)) { - PBYTEArray x ((const BYTE *)(isHold ? "\xF9" : "\xFA"), 1); -@@ -2155,7 +2156,7 @@ - } - } - --BOOL MyH323_ExternalRTPChannel::Start(void) -+PBoolean MyH323_ExternalRTPChannel::Start(void) - { - /* Call ancestor first */ - if (!H323_ExternalRTPChannel::Start()) { -@@ -2182,7 +2183,7 @@ - return TRUE; - } - --BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param) -+PBoolean MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param) - { - if (h323debug) { - cout << " MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl; -@@ -2580,7 +2581,7 @@ - int h323_soft_hangup(const char *data) - { - PString token(data); -- BOOL result; -+ PBoolean result; - cout << "Soft hangup" << endl; - result = endPoint->ClearCall(token); - return result; -@@ -2615,7 +2616,7 @@ - cout << "ERROR: No connection found, this is bad" << endl; - return -1; - } -- conn->MyHoldCall((BOOL)is_hold); -+ conn->MyHoldCall((PBoolean)is_hold); - conn->Unlock(); - return 0; - } -Index: channels/h323/README -=================================================================== ---- a/channels/h323/README (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/README (.../team/group/issue14292) (revision 178988) -@@ -76,7 +76,7 @@ - - Upgrading Asterisk - ----------------- --After you cvs update (or make update) Asterisk you have to go into -+After you svn update (or make update) Asterisk you have to go into - asterisk/channels/h323 and issue a make clean all, before compiling the - rest of asterisk. Doing this process every time you upgrade Asterisk - will ensure a sane build. -Index: channels/h323/chan_h323.h -=================================================================== ---- a/channels/h323/chan_h323.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/chan_h323.h (.../team/group/issue14292) (revision 178988) -@@ -26,6 +26,9 @@ - * Version Info: $Id$ - */ - -+#ifndef CHAN_H323_H -+#define CHAN_H323_H -+ - #include - - /* -@@ -207,10 +210,6 @@ - #define H323_DTMF_RFC2833_PT 101 - #define H323_DTMF_CISCO_PT 121 - --#ifndef BOOL --#define BOOL int --#endif -- - #ifdef __cplusplus - extern "C" { - #endif -@@ -267,3 +266,5 @@ - #ifdef __cplusplus - } - #endif -+ -+#endif -Index: channels/h323/cisco-h225.h -=================================================================== ---- a/channels/h323/cisco-h225.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/cisco-h225.h (.../team/group/issue14292) (revision 178988) -@@ -14,6 +14,7 @@ - #endif - - #include -+#include "ast_ptlib.h" - - // - // RedirectIEinfo -@@ -30,7 +31,7 @@ - PASN_OctetString m_redirectIE; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -55,7 +56,7 @@ - PASN_OctetString m_progIndIE; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -81,7 +82,7 @@ - PASN_OctetString m_rawMesg; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -107,7 +108,7 @@ - PASN_OctetString m_enterpriseID; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -132,7 +133,7 @@ - PASN_Boolean m_callPreserveIE; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -161,7 +162,7 @@ - PASN_OctetString m_connectedNumber; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -186,7 +187,7 @@ - CISCO_H225_RedirectIEinfo m_redirectIEinfo; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -211,7 +212,7 @@ - CISCO_H225_ProgIndIEinfo m_progIndIEinfo; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -236,7 +237,7 @@ - CISCO_H225_QsigNonStdInfo m_qsigNonStdInfo; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -@@ -281,7 +282,7 @@ - CISCO_H225_CallPreserveParam m_callPreserveParam; - - PINDEX GetDataLength() const; -- BOOL Decode(PASN_Stream & strm); -+ PBoolean Decode(PASN_Stream & strm); - void Encode(PASN_Stream & strm) const; - #ifndef PASN_NOPRINTON - void PrintOn(ostream & strm) const; -Index: channels/h323/ast_ptlib.h -=================================================================== ---- a/channels/h323/ast_ptlib.h (.../tags/1.6.1-rc1) (revision 0) -+++ b/channels/h323/ast_ptlib.h (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,34 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2009, Digium, Inc. -+ * -+ * 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. -+ */ -+ -+/* PTLib is Copyright (c) 2003 Equivalence Pty. Ltd. */ -+ -+/*! -+ * \file -+ * \brief PTLib compatibility with previous versions of OPAL/PTLib/PWLib -+ */ -+ -+#ifndef AST_PTLIB_H -+#define AST_PTLIB_H -+ -+#include -+#if !defined(P_USE_STANDARD_CXX_BOOL) && !defined(P_USE_INTEGER_BOOL) -+typedef BOOL PBoolean; -+#define PTrue TRUE -+#define PFalse FALSE -+#endif -+ -+#endif /* !defined AST_PTLIB_H */ - -Property changes on: channels/h323/ast_ptlib.h -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: channels/h323/compat_h323.h -=================================================================== ---- a/channels/h323/compat_h323.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/compat_h323.h (.../team/group/issue14292) (revision 178988) -@@ -14,11 +14,11 @@ - MyH323TransportTCP( - H323EndPoint & endpoint, ///< H323 End Point object - PIPSocket::Address binding = PIPSocket::GetDefaultIpAny(), ///< Local interface to use -- BOOL listen = FALSE ///< Flag for need to wait for remote to connect -+ PBoolean listen = FALSE ///< Flag for need to wait for remote to connect - ); - /**Connect to the remote party. - */ -- virtual BOOL Connect(); -+ virtual PBoolean Connect(); - }; - #else - #define MyH323TransportTCP H323TransportTCP -@@ -35,7 +35,7 @@ - WORD remotePort = 0): H323TransportUDP(endpoint, binding, localPort, remotePort) - { - } -- virtual BOOL DiscoverGatekeeper(H323Gatekeeper &, -+ virtual PBoolean DiscoverGatekeeper(H323Gatekeeper &, - H323RasPDU &, - const H323TransportAddress &); - protected: -@@ -43,8 +43,8 @@ - H323Gatekeeper *discoverGatekeeper; - H323RasPDU *discoverPDU; - const H323TransportAddress *discoverAddress; -- BOOL discoverResult; -- BOOL discoverReady; -+ PBoolean discoverResult; -+ PBoolean discoverReady; - PMutex discoverMutex; - }; - -Index: channels/h323/caps_h323.h -=================================================================== ---- a/channels/h323/caps_h323.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/caps_h323.h (.../team/group/issue14292) (revision 178988) -@@ -26,17 +26,17 @@ - PCLASSINFO(AST_G7231Capability, H323AudioCapability); - - public: -- AST_G7231Capability(int rx_frames = 7, BOOL annexA = TRUE); -+ AST_G7231Capability(int rx_frames = 7, PBoolean annexA = TRUE); - Comparison Compare(const PObject & obj) const; - virtual PObject * Clone() const; - virtual H323Codec * CreateCodec(H323Codec::Direction direction) const; - virtual unsigned GetSubType() const; - virtual PString GetFormatName() const; -- virtual BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const; -- virtual BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize); -+ virtual PBoolean OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const; -+ virtual PBoolean OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize); - - protected: -- BOOL annexA; -+ PBoolean annexA; - }; - - /**This class describes the (fake) G729 codec capability. -@@ -114,8 +114,8 @@ - /* Get the name of the media data format this class represents. */ - virtual PString GetFormatName() const; - -- BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const; -- BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize); -+ PBoolean OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const; -+ PBoolean OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize); - - protected: - int comfortNoise; -Index: channels/h323/ast_h323.h -=================================================================== ---- a/channels/h323/ast_h323.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/h323/ast_h323.h (.../team/group/issue14292) (revision 178988) -@@ -29,6 +29,8 @@ - #ifndef AST_H323_H - #define AST_H323_H - -+#include "ast_ptlib.h" -+ - #define VERSION(a,b,c) ((a)*10000+(b)*100+(c)) - - class MyH323EndPoint : public H323EndPoint -@@ -38,16 +40,16 @@ - public: - MyH323EndPoint(); - int MyMakeCall(const PString &, PString &, void *_callReference, void *_opts); -- BOOL ClearCall(const PString &, H323Connection::CallEndReason reason); -- BOOL ClearCall(const PString &); -+ PBoolean ClearCall(const PString &, H323Connection::CallEndReason reason); -+ PBoolean ClearCall(const PString &); - - void OnClosedLogicalChannel(H323Connection &, const H323Channel &); - void OnConnectionEstablished(H323Connection &, const PString &); - void OnConnectionCleared(H323Connection &, const PString &); - virtual H323Connection * CreateConnection(unsigned, void *, H323Transport *, H323SignalPDU *); - void SendUserTone(const PString &, char); -- BOOL OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &); -- BOOL ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &); -+ PBoolean OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &); -+ PBoolean ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &); - void SetEndpointTypeInfo( H225_EndpointType & info ) const; - void SetGateway(void); - PStringArray SupportedPrefixes; -@@ -69,31 +71,31 @@ - const H323SignalPDU &, - H323SignalPDU &); - void OnReceivedReleaseComplete(const H323SignalPDU &); -- BOOL OnAlerting(const H323SignalPDU &, const PString &); -- BOOL OnSendReleaseComplete(H323SignalPDU &); -- BOOL OnReceivedSignalSetup(const H323SignalPDU &); -- BOOL OnReceivedFacility(const H323SignalPDU &); -- BOOL OnSendSignalSetup(H323SignalPDU &); -- BOOL OnStartLogicalChannel(H323Channel &); -- BOOL OnClosingLogicalChannel(H323Channel &); -+ PBoolean OnAlerting(const H323SignalPDU &, const PString &); -+ PBoolean OnSendReleaseComplete(H323SignalPDU &); -+ PBoolean OnReceivedSignalSetup(const H323SignalPDU &); -+ PBoolean OnReceivedFacility(const H323SignalPDU &); -+ PBoolean OnSendSignalSetup(H323SignalPDU &); -+ PBoolean OnStartLogicalChannel(H323Channel &); -+ PBoolean OnClosingLogicalChannel(H323Channel &); - virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0); - virtual void OnUserInputTone(char, unsigned, unsigned, unsigned); - virtual void OnUserInputString(const PString &value); -- BOOL OnReceivedProgress(const H323SignalPDU &); -- BOOL MySendProgress(); -+ PBoolean OnReceivedProgress(const H323SignalPDU &); -+ PBoolean MySendProgress(); - void OnSendCapabilitySet(H245_TerminalCapabilitySet &); - void OnSetLocalCapabilities(); - void SetCapabilities(int, int, void *, int); -- BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *, -+ PBoolean OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *, - H245_TerminalCapabilitySetReject &); - void SetCause(int _cause) { cause = _cause; }; -- virtual BOOL StartControlChannel(const H225_TransportAddress & h245Address); -- void SetCallOptions(void *opts, BOOL isIncoming); -- void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming); -+ virtual PBoolean StartControlChannel(const H225_TransportAddress & h245Address); -+ void SetCallOptions(void *opts, PBoolean isIncoming); -+ void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, PBoolean isIncoming); - virtual H323Connection::CallEndReason SendSignalSetup(const PString&, const H323TransportAddress&); - #ifdef TUNNELLING -- virtual BOOL HandleSignalPDU(H323SignalPDU &pdu); -- BOOL EmbedTunneledInfo(H323SignalPDU &pdu); -+ virtual PBoolean HandleSignalPDU(H323SignalPDU &pdu); -+ PBoolean EmbedTunneledInfo(H323SignalPDU &pdu); - #endif - #ifdef H323_H450 - virtual void OnReceivedLocalCallHold(int linkedId); -@@ -112,7 +114,7 @@ - int transfer_capability; - - WORD sessionId; -- BOOL bridging; -+ PBoolean bridging; - #ifdef TUNNELLING - int remoteTunnelOptions; - int tunnelOptions; -@@ -141,8 +143,8 @@ - ~MyH323_ExternalRTPChannel(); - - /* Overrides */ -- BOOL Start(void); -- BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param); -+ PBoolean Start(void); -+ PBoolean OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param); - - protected: - BYTE payloadCode; -Index: channels/misdn_config.c -=================================================================== ---- a/channels/misdn_config.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/misdn_config.c (.../team/group/issue14292) (revision 178988) -@@ -132,85 +132,110 @@ - { "musicclass", MISDN_CFG_MUSICCLASS, MISDN_CTYPE_STR, "default", NONE, - "Sets the musiconhold class." }, - { "callerid", MISDN_CFG_CALLERID, MISDN_CTYPE_STR, "", NONE, -- "Sets the caller ID." }, -+ "Set the outgoing caller id to the value." }, - { "method", MISDN_CFG_METHOD, MISDN_CTYPE_STR, "standard", NONE, - "Sets the method to use for channel selection:\n" - "\t standard - always choose the first free channel with the lowest number\n" - "\t round_robin - use the round robin algorithm to select a channel. use this\n" - "\t if you want to balance your load." }, - { "dialplan", MISDN_CFG_DIALPLAN, MISDN_CTYPE_INT, "0", NONE, -- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n" -- "\n" -+ "Dialplan means Type Of Number in ISDN Terms\n" - "\tThere are different types of the dialplan:\n" - "\n" -- "\tdialplan -> outgoing Number\n" -- "\tlocaldialplan -> callerid\n" -- "\tcpndialplan -> connected party number\n" -+ "\tdialplan -> for outgoing call's dialed number\n" -+ "\tlocaldialplan -> for outgoing call's callerid\n" -+ "\t (if -1 is set use the value from the asterisk channel)\n" -+ "\tcpndialplan -> for incoming call's connected party number sent to caller\n" -+ "\t (if -1 is set use the value from the asterisk channel)\n" - "\n" - "\tdialplan options:\n" - "\n" - "\t0 - unknown\n" - "\t1 - International\n" - "\t2 - National\n" -- "\t4 - Subscriber\n" -- "\n" -- "\tThis setting is used for outgoing calls." }, -+ "\t4 - Subscriber" }, - { "localdialplan", MISDN_CFG_LOCALDIALPLAN, MISDN_CTYPE_INT, "0", NONE, -- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n" -- "\n" -+ "Dialplan means Type Of Number in ISDN Terms\n" - "\tThere are different types of the dialplan:\n" - "\n" -- "\tdialplan -> outgoing Number\n" -- "\tlocaldialplan -> callerid\n" -- "\tcpndialplan -> connected party number\n" -+ "\tdialplan -> for outgoing call's dialed number\n" -+ "\tlocaldialplan -> for outgoing call's callerid\n" -+ "\t (if -1 is set use the value from the asterisk channel)\n" -+ "\tcpndialplan -> for incoming call's connected party number sent to caller\n" -+ "\t (if -1 is set use the value from the asterisk channel)\n" - "\n" - "\tdialplan options:\n" - "\n" - "\t0 - unknown\n" - "\t1 - International\n" - "\t2 - National\n" -- "\t4 - Subscriber\n" -- "\n" -- "\tThis setting is used for outgoing calls." }, -+ "\t4 - Subscriber" }, - { "cpndialplan", MISDN_CFG_CPNDIALPLAN, MISDN_CTYPE_INT, "0", NONE, -- "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n" -- "\n" -+ "Dialplan means Type Of Number in ISDN Terms\n" - "\tThere are different types of the dialplan:\n" - "\n" -- "\tdialplan -> outgoing Number\n" -- "\tlocaldialplan -> callerid\n" -- "\tcpndialplan -> connected party number\n" -+ "\tdialplan -> for outgoing call's dialed number\n" -+ "\tlocaldialplan -> for outgoing call's callerid\n" -+ "\t (if -1 is set use the value from the asterisk channel)\n" -+ "\tcpndialplan -> for incoming call's connected party number sent to caller\n" -+ "\t (if -1 is set use the value from the asterisk channel)\n" - "\n" - "\tdialplan options:\n" - "\n" - "\t0 - unknown\n" - "\t1 - International\n" - "\t2 - National\n" -- "\t4 - Subscriber\n" -- "\n" -- "\tThis setting is used for outgoing calls." }, -- { "nationalprefix", MISDN_CFG_NATPREFIX, MISDN_CTYPE_STR, "0", NONE, -- "Prefix for national, this is put before the\n" -- "\toad if an according dialplan is set by the other end." }, -- { "internationalprefix", MISDN_CFG_INTERNATPREFIX, MISDN_CTYPE_STR, "00", NONE, -- "Prefix for international, this is put before the\n" -- "\toad if an according dialplan is set by the other end." }, -+ "\t4 - Subscriber" }, -+ { "unknownprefix", MISDN_CFG_TON_PREFIX_UNKNOWN, MISDN_CTYPE_STR, "", NONE, -+ "Prefix for unknown numbers, this is put before an incoming number\n" -+ "\tif its type-of-number is unknown." }, -+ { "internationalprefix", MISDN_CFG_TON_PREFIX_INTERNATIONAL, MISDN_CTYPE_STR, "00", NONE, -+ "Prefix for international numbers, this is put before an incoming number\n" -+ "\tif its type-of-number is international." }, -+ { "nationalprefix", MISDN_CFG_TON_PREFIX_NATIONAL, MISDN_CTYPE_STR, "0", NONE, -+ "Prefix for national numbers, this is put before an incoming number\n" -+ "\tif its type-of-number is national." }, -+ { "netspecificprefix", MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC, MISDN_CTYPE_STR, "", NONE, -+ "Prefix for network-specific numbers, this is put before an incoming number\n" -+ "\tif its type-of-number is network-specific." }, -+ { "subscriberprefix", MISDN_CFG_TON_PREFIX_SUBSCRIBER, MISDN_CTYPE_STR, "", NONE, -+ "Prefix for subscriber numbers, this is put before an incoming number\n" -+ "\tif its type-of-number is subscriber." }, -+ { "abbreviatedprefix", MISDN_CFG_TON_PREFIX_ABBREVIATED, MISDN_CTYPE_STR, "", NONE, -+ "Prefix for abbreviated numbers, this is put before an incoming number\n" -+ "\tif its type-of-number is abbreviated." }, - { "presentation", MISDN_CFG_PRES, MISDN_CTYPE_INT, "-1", NONE, - "These (presentation and screen) are the exact isdn screening and presentation\n" - "\tindicators.\n" -- "\tIf -1 is given for both values, the presentation indicators are used from\n" -- "\tAsterisks SetCallerPres application.\n" -+ "\tIf -1 is given for either value, the presentation indicators are used from\n" -+ "\tAsterisk's CALLERPRES function.\n" - "\n" -- "\tscreen=0, presentation=0 -> callerid presented not screened\n" -- "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" }, -+ "\tscreen=0, presentation=0 -> callerid presented\n" -+ "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" }, - { "screen", MISDN_CFG_SCREEN, MISDN_CTYPE_INT, "-1", NONE, - "These (presentation and screen) are the exact isdn screening and presentation\n" - "\tindicators.\n" -- "\tIf -1 is given for both values, the presentation indicators are used from\n" -- "\tAsterisks SetCallerPres application.\n" -+ "\tIf -1 is given for either value, the presentation indicators are used from\n" -+ "\tAsterisk's CALLERPRES function.\n" - "\n" -- "\tscreen=0, presentation=0 -> callerid presented not screened\n" -- "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" }, -+ "\tscreen=0, presentation=0 -> callerid presented\n" -+ "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" }, -+ { "display_connected", MISDN_CFG_DISPLAY_CONNECTED, MISDN_CTYPE_INT, "0", NONE, -+ "Put a display ie in the CONNECT message containing the following\n" -+ "\tinformation if it is available (nt port only):\n" -+ "\n" -+ "\t0 - Do not put the connected line information in the display ie.\n" -+ "\t1 - Put the available connected line name in the display ie.\n" -+ "\t2 - Put the available connected line number in the display ie.\n" -+ "\t3 - Put the available connected line name and number in the display ie." }, -+ { "display_setup", MISDN_CFG_DISPLAY_SETUP, MISDN_CTYPE_INT, "0", NONE, -+ "Put a display ie in the SETUP message containing the following\n" -+ "\tinformation if it is available (nt port only):\n" -+ "\n" -+ "\t0 - Do not put the caller information in the display ie.\n" -+ "\t1 - Put the available caller name in the display ie.\n" -+ "\t2 - Put the available caller number in the display ie.\n" -+ "\t3 - Put the available caller name and number in the display ie." }, - { "always_immediate", MISDN_CFG_ALWAYS_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE, - "Enable this to get into the s dialplan-extension.\n" - "\tThere you can use DigitTimeout if you can't or don't want to use\n" -@@ -219,7 +244,7 @@ - { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE, - "Enable this to prevent chan_misdn to generate the dialtone\n" - "\tThis makes only sense together with the always_immediate=yes option\n" -- "\tto generate your own dialtone with Playtones or so."}, -+ "\tto generate your own dialtone with Playtones or so." }, - { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE, - "Enable this if you want callers which called exactly the base\n" - "\tnumber (so no extension is set) to jump into the s extension.\n" -@@ -256,17 +281,17 @@ - #endif - #ifdef WITH_BEROEC - { "bnechocancel", MISDN_CFG_BNECHOCANCEL, MISDN_CTYPE_BOOLINT, "yes", 64, -- "echotail in ms (1-200)\n"}, -+ "echotail in ms (1-200)" }, - { "bnec_antihowl", MISDN_CFG_BNEC_ANTIHOWL, MISDN_CTYPE_INT, "0", NONE, -- "Use antihowl\n"}, -+ "Use antihowl" }, - { "bnec_nlp", MISDN_CFG_BNEC_NLP, MISDN_CTYPE_BOOL, "yes", NONE, -- "Nonlinear Processing (much faster adaption)"}, -+ "Nonlinear Processing (much faster adaption)" }, - { "bnec_zerocoeff", MISDN_CFG_BNEC_ZEROCOEFF, MISDN_CTYPE_BOOL, "no", NONE, -- "ZeroCoeffeciens\n"}, -+ "ZeroCoeffeciens" }, - { "bnec_tonedisabler", MISDN_CFG_BNEC_TD, MISDN_CTYPE_BOOL, "no", NONE, -- "Disable Tone\n"}, -+ "Disable Tone" }, - { "bnec_adaption", MISDN_CFG_BNEC_ADAPT, MISDN_CTYPE_INT, "1", NONE, -- "Adaption mode (0=no,1=full,2=fast)\n"}, -+ "Adaption mode (0=no,1=full,2=fast)" }, - #endif - { "need_more_infos", MISDN_CFG_NEED_MORE_INFOS, MISDN_CTYPE_BOOL, "0", NONE, - "Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n" -@@ -310,13 +335,13 @@ - { "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE, - "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." }, - { "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4, -- "Watches the layer 1. If the layer 1 is down, it tries to\n" -- "\tget it up. The timeout is given in seconds. with 0 as value it\n" -- "\tdoes not watch the l1 at all\n" -+ "Monitors L1 of the port. If L1 is down it tries\n" -+ "\tto bring it up. The polling timeout is given in seconds.\n" -+ "\tSetting the value to 0 disables monitoring L1 of the port.\n" - "\n" -- "\tThis option is only read at loading time of chan_misdn, which\n" -- "\tmeans you need to unload and load chan_misdn to change the value,\n" -- "\tan Asterisk restart should do the trick." }, -+ "\tThis option is only read at chan_misdn loading time.\n" -+ "\tYou need to unload and load chan_misdn to change the\n" -+ "\tvalue. An asterisk restart will also do the trick." }, - { "overlapdial", MISDN_CFG_OVERLAP_DIAL, MISDN_CTYPE_BOOLINT, "0", 4, - "Enables overlap dial for the given amount of seconds.\n" - "\tPossible values are positive integers or:\n" -@@ -1104,8 +1129,8 @@ - struct ast_variable *v; - struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; - -- if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags))) { -- ast_log(LOG_WARNING, "missing file: misdn.conf\n"); -+ if (!(cfg = ast_config_load2(config, "chan_misdn", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_WARNING, "missing or invalid file: misdn.conf\n"); - return -1; - } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) - return 0; -Index: channels/chan_usbradio.c -=================================================================== ---- a/channels/chan_usbradio.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_usbradio.c (.../team/group/issue14292) (revision 178988) -@@ -34,7 +34,7 @@ - */ - - /*** MODULEINFO -- ossaudio -+ oss - usb - no - ***/ -@@ -3524,7 +3524,7 @@ - o->txctcssadj = 200; - o->rxsquelchadj = 500; - o->devstr[0] = 0; -- if (cfg1) { -+ if (cfg1 && cfg1 != CONFIG_STATUS_FILEINVALID) { - for (v = ast_variable_browse(cfg1, o->name); v; v = v->next) { - - M_START((char *)v->name, (char *)v->value); -@@ -3958,9 +3958,9 @@ - - /* load config file */ - #ifdef NEW_ASTERISK -- if (!(cfg = ast_config_load(config,zeroflag))) { -+ if (!(cfg = ast_config_load(config,zeroflag)) || cfg == CONFIG_STATUS_FILEINVALID) { - #else -- if (!(cfg = ast_config_load(config))) { -+ if (!(cfg = ast_config_load(config))) || cfg == CONFIG_STATUS_FILEINVALID { - #endif - ast_log(LOG_NOTICE, "Unable to load config %s\n", config); - return AST_MODULE_LOAD_DECLINE; -@@ -3984,7 +3984,7 @@ - return AST_MODULE_LOAD_FAILURE; - } - -- ast_cli_register_multiple(cli_usbradio, sizeof(cli_usbradio) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_usbradio, ARRAY_LEN(cli_usbradio)); - - return AST_MODULE_LOAD_SUCCESS; - } -@@ -3997,7 +3997,7 @@ - ast_log(LOG_WARNING, "unload_module() called\n"); - - ast_channel_unregister(&usbradio_tech); -- ast_cli_unregister_multiple(cli_usbradio, sizeof(cli_usbradio) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_usbradio, ARRAY_LEN(cli_usbradio)); - - for (o = usbradio_default.next; o; o = o->next) { - -Index: channels/chan_jingle.c -=================================================================== ---- a/channels/chan_jingle.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_jingle.c (.../team/group/issue14292) (revision 178988) -@@ -1736,8 +1736,9 @@ - struct ast_flags config_flags = { 0 }; - - cfg = ast_config_load(JINGLE_CONFIG, config_flags); -- if (!cfg) -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { - return 0; -+ } - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); -Index: channels/iax2-parser.h -=================================================================== ---- a/channels/iax2-parser.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/iax2-parser.h (.../team/group/issue14292) (revision 178988) -@@ -109,8 +109,6 @@ - unsigned int sentyet:1; - /* Non-zero if should be sent to transfer peer */ - unsigned int transfer:1; -- /* Non-zero if should be sent to media peer */ -- unsigned int media:1; - /* Non-zero if this is the final message */ - unsigned int final:1; - /* Ingress or outgres */ -Index: channels/chan_dahdi.c -=================================================================== ---- a/channels/chan_dahdi.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_dahdi.c (.../team/group/issue14292) (revision 178988) -@@ -21,8 +21,8 @@ - * \brief DAHDI for Pseudo TDM - * - * \author Mark Spencer -- * -- * Connects to the DAHDI telephony library as well as -+ * -+ * Connects to the DAHDI telephony library as well as - * libpri. Libpri is optional and needed only if you are - * going to use ISDN connections. - * -@@ -101,6 +101,41 @@ - #include "asterisk/event.h" - #include "asterisk/devicestate.h" - -+/*** DOCUMENTATION -+ -+ -+ Send digits out of band over a PRI. -+ -+ -+ -+ -+ -+ This application will send the given string of digits in a Keypad -+ Facility IE over the current channel. -+ -+ -+ -+ -+ Send QSIG call rerouting facility over a PRI. -+ -+ -+ -+ Destination number. -+ -+ -+ Original called number. -+ -+ -+ Diversion reason, if not specified defaults to unknown -+ -+ -+ -+ This application will send a Callrerouting Facility IE over the -+ current channel. -+ -+ -+ ***/ -+ - #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */ - - static const char *lbostr[] = { -@@ -127,7 +162,7 @@ - /* define this to send PRI user-user information elements */ - #undef SUPPORT_USERUSER - --/*! -+/*! - * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when - * the user hangs up to reset the state machine so ring works properly. - * This is used to be able to support kewlstart by putting the zhone in -@@ -154,14 +189,14 @@ - - - /*! \brief Signaling types that need to use MF detection should be placed in this macro */ --#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB)) -+#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB)) - - static const char tdesc[] = "DAHDI Telephony Driver" - #ifdef HAVE_PRI -- " w/PRI" -+ " w/PRI" - #endif - #ifdef HAVE_SS7 -- " w/SS7" -+ " w/SS7" - #endif - ; - -@@ -217,7 +252,6 @@ - #define DAHDI_OVERLAPDIAL_INCOMING 2 - #define DAHDI_OVERLAPDIAL_BOTH (DAHDI_OVERLAPDIAL_INCOMING|DAHDI_OVERLAPDIAL_OUTGOING) - -- - #define CALLPROGRESS_PROGRESS 1 - #define CALLPROGRESS_FAX_OUTGOING 2 - #define CALLPROGRESS_FAX_INCOMING 4 -@@ -230,7 +264,9 @@ - - /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */ - static char mwimonitornotify[PATH_MAX] = ""; -+#ifndef HAVE_DAHDI_LINEREVERSE_VMWI - static int mwisend_rpas = 0; -+#endif - - static char progzone[10] = ""; - -@@ -262,7 +298,11 @@ - /*! \brief Protect the interface list (of dahdi_pvt's) */ - AST_MUTEX_DEFINE_STATIC(iflock); - -+/* QSIG channel mapping option types */ -+#define DAHDI_CHAN_MAPPING_PHYSICAL 0 -+#define DAHDI_CHAN_MAPPING_LOGICAL 1 - -+ - static int ifcount = 0; - - #ifdef HAVE_PRI -@@ -276,12 +316,9 @@ - /*! \brief This is the thread for the monitor which checks for input on the channels - which are not currently in use. */ - static pthread_t monitor_thread = AST_PTHREADT_NULL; --static ast_cond_t mwi_thread_complete; - static ast_cond_t ss_thread_complete; --AST_MUTEX_DEFINE_STATIC(mwi_thread_lock); - AST_MUTEX_DEFINE_STATIC(ss_thread_lock); - AST_MUTEX_DEFINE_STATIC(restart_lock); --static int mwi_thread_count = 0; - static int ss_thread_count = 0; - static int num_restart_pending = 0; - -@@ -299,6 +336,321 @@ - * event cache instead of checking the mailbox directly. */ - } - -+#if defined(HAVE_PRI) -+#define CC_TIMEOUT_PEERLINKCHANNELS 60 -+#define CC_MAX_PEERLINKCHANNELS 20*CC_TIMEOUT_PEERLINKCHANNELS -+AST_MUTEX_DEFINE_STATIC(peerlink_lock); -+static struct peerlink_s { -+ struct ast_channel *channel; -+ time_t age; -+} peerlinkchannel[CC_MAX_PEERLINKCHANNELS+1]; -+ -+ -+#define CC_IDLE 1 -+#define CC_WAIT_ACK 2 -+#define CC_INVOKED_A_RET 3 -+#define CC_WAIT_USER_A_ANSWER_N 4 -+ -+#define CCBS_SPAN(h) ((h) & 0xff) -+#define CCBS_CR(h) (((h) >> 16) & 0xffff) -+#define CCBS_HANDLE(s,r) ((s & 0xff) | ((r & 0xffff) << 16)) -+ -+struct ccbsnr_link { -+ unsigned int handle; -+ char type; -+ unsigned int state; -+ char callingnum[AST_MAX_EXTENSION]; -+ char callernum[AST_MAX_EXTENSION]; -+ char callername[AST_MAX_EXTENSION]; -+ char context[AST_MAX_CONTEXT]; -+ int priority; -+ q931_call *call; -+ struct ast_channel *peer; -+ time_t age; -+ struct ccbsnr_link *next; -+}; -+ -+static struct ccbsnr_link *ccbsnr_list = NULL; -+AST_MUTEX_DEFINE_STATIC(ccbsnr_lock); -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * remove too old CCBS/CCNR entries -+ * (must be called with ccbsnr_lock held) -+ */ -+static void del_old_ccbsnr(void) -+{ -+ struct ccbsnr_link *ccbsnr; -+ struct ccbsnr_link *tmp = NULL; -+ -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ if ((ccbsnr->age + 86400) < time(NULL)) { -+ ast_verb(3, "DAHDI: CCBS/CCNR handle=%d timeout.\n", ccbsnr->handle); -+ if (!tmp) { -+ ccbsnr_list = ccbsnr->next; -+ } else { -+ tmp->next = ccbsnr->next; -+ } -+ ast_free(ccbsnr); -+ break; -+ } -+ tmp = ccbsnr; -+ ccbsnr = ccbsnr->next; -+ } -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * return the pointer to ccbsnr structure by handle -+ */ -+static struct ccbsnr_link *ccbsnr_get_link(unsigned int handle, unsigned int *state) -+{ -+ struct ccbsnr_link *ret; -+ -+ if (state) { -+ *state = CC_IDLE; -+ } -+ -+ if (handle) { -+ ast_verb(3, "DAHDI: ccbsnr_get_link: handle=%x\n", handle); -+ } -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ -+ ret = ccbsnr_list; -+ while (ret) { -+ if ((handle) && (ret->handle == handle)) { -+ if (state) { -+ *state = ret->state; -+ } -+ break; -+ } -+ ret = ret->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+ -+ return ret; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static struct ccbsnr_link *ccbsnr_get_link_by_number(const char *callingnum, const char *callernum, unsigned int *state) -+{ -+ struct ccbsnr_link *ret; -+ -+ if (state) { -+ *state = CC_IDLE; -+ } -+ -+ if (callingnum && callernum) { -+ if (strlen(callingnum) && strlen(callernum)) { -+ ast_verb(3, -+ "DAHDI: ccbsnr_get_link_by_number: callingnum=%s callernum=%s\n", -+ callingnum, callernum); -+ } -+ } else { -+ return NULL; -+ } -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ -+ ret = ccbsnr_list; -+ while (ret) { -+ if (!strcmp(ret->callingnum, callingnum) && !strcmp(ret->callernum, callernum)) { -+ if (state) { -+ *state = ret->state; -+ } -+ break; -+ } -+ ret = ret->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+ -+ return ret; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * select CCBS/CCNR id -+ */ -+static struct ccbsnr_link *ccbsnr_select_link(unsigned int handle) -+{ -+ struct ccbsnr_link *ccbsnr; -+ struct ccbsnr_link *ret = NULL; -+ int ccbsnronprispan; -+ int cr; -+ -+ ast_verb(3, "DAHDI: ccbsnr_select_link: handle=%x\n", handle); -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ if ((ccbsnr->handle == handle) && (ccbsnr->state == CC_WAIT_ACK)) { -+ ccbsnr->state = CC_INVOKED_A_RET; -+ ret = ccbsnr; -+ -+ ccbsnronprispan = CCBS_SPAN(handle); -+ cr = CCBS_CR(handle); -+ ast_verb(3, -+ "DAHDI: request CCBS/NR span=%d type=%d cr =%x handle=%x state=%d (%s, %s, %s, %s, %d)\n", -+ ccbsnronprispan, ccbsnr->type, cr, handle, ccbsnr->state, -+ ccbsnr->callingnum, ccbsnr->callernum, ccbsnr->callername, -+ ccbsnr->context, ccbsnr->priority); -+ break; -+ } -+ ccbsnr = ccbsnr->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+ -+ return ret; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * a CCBS/CCNR link was removed -+ */ -+static void ccbsnr_del_link(unsigned int handle) -+{ -+ struct ccbsnr_link *ccbsnr; -+ struct ccbsnr_link *tmp = NULL; -+ int ccbsnronprispan; -+ int cr; -+ -+ ast_verb(3, "DAHDI: ccbsnr_del_link: handle=%x\n", handle); -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ if (ccbsnr->handle == handle) { -+ if (!tmp) { -+ ccbsnr_list = ccbsnr->next; -+ } else { -+ tmp->next = ccbsnr->next; -+ } -+ ccbsnronprispan = CCBS_SPAN(handle); -+ cr = CCBS_CR(handle); -+ -+ ast_verb(3, -+ "DAHDI: destroy CCBS/NR span=%d type=%d cr=%x handle=%x state=%d (%s, %s, %s, %s, %d)\n", -+ ccbsnronprispan, ccbsnr->type, cr, handle, ccbsnr->state, -+ ccbsnr->callingnum, ccbsnr->callernum, ccbsnr->callername, -+ ccbsnr->context, ccbsnr->priority); -+ -+ if (ccbsnr->call) { -+ ast_log(LOG_NOTICE, "call(%p) must be 'NULL'. Memory leak!\n", -+ ccbsnr->call); -+ } -+ -+ ast_free(ccbsnr); -+ break; -+ } -+ tmp = ccbsnr; -+ ccbsnr = ccbsnr->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * return the counter of ccbsnrlinks to callingnumber -+ */ -+static int ccbsnr_count_callingnum(const char *callingnum) -+{ -+ int count = 0; -+ struct ccbsnr_link *ccbsnr; -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ if (!strcmp(ccbsnr->callingnum, callingnum)) { -+ count++; -+ } -+ ccbsnr = ccbsnr->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+ -+ return count; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * Add a new peer link id -+ */ -+static int cc_add_peer_link_id(struct ast_channel *ast) -+{ -+ int i; -+ -+ ast_mutex_lock(&peerlink_lock); -+ for (i = 1; i <= CC_MAX_PEERLINKCHANNELS; i++) { -+ if (peerlinkchannel[i].channel == NULL) { -+ peerlinkchannel[i].channel = ast; -+ peerlinkchannel[i].age = time(NULL); -+ break; -+ } else { -+ /* remove too old entries */ -+ if ((peerlinkchannel[i].age + CC_TIMEOUT_PEERLINKCHANNELS) < time(NULL)) { -+ peerlinkchannel[i].channel = NULL; -+ ast_verb(4, "DAHDI: peerlink %d timeout-erase\n", i); -+ } -+ } -+ } -+ ast_mutex_unlock(&peerlink_lock); -+ if (i > CC_MAX_PEERLINKCHANNELS) { -+ return -1; -+ } -+ return i; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * Get and remove peer link id -+ */ -+static struct ast_channel *cc_get_peer_link_id(const char *p) -+{ -+ int id = -1; -+ struct ast_channel *ast = NULL; -+ -+ if (p) { -+ id = (int)strtol(p, NULL, 0); -+ } -+ -+ ast_mutex_lock(&peerlink_lock); -+ if ((id >= 1) && (id <= CC_MAX_PEERLINKCHANNELS)) { -+ ast = peerlinkchannel[id].channel; -+ peerlinkchannel[id].channel = NULL; -+ } -+ ast_verb(4, "DAHDI: peerlink %d allocated, peer is %s\n", id, -+ (ast) ? ast->name : "unlinked"); -+ ast_mutex_unlock(&peerlink_lock); -+ return ast; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static void cc_destroy_all_peer_link_id(void) -+{ -+ int i; -+ -+ ast_mutex_lock(&peerlink_lock); -+ for (i = 1; i <= CC_MAX_PEERLINKCHANNELS; i++) { -+ /* remove entries */ -+ peerlinkchannel[i].channel = NULL; -+ } -+ ast_mutex_unlock(&peerlink_lock); -+} -+#endif /* defined(HAVE_PRI) */ -+ -+ - /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */ - static inline int dahdi_get_event(int fd) - { -@@ -334,6 +686,10 @@ - - struct dahdi_pvt; - -+/*! -+ * \brief Configured ring timeout base. -+ * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists. -+ */ - static int ringt_base = DEFAULT_RINGT; - - #ifdef HAVE_SS7 -@@ -412,22 +768,31 @@ - int prilogicalspan; /*!< Logical span number within trunk group */ - int numchans; /*!< Num of channels we represent */ - int overlapdial; /*!< In overlap dialing mode */ -+ int qsigchannelmapping; /*!< QSIG channel mapping type */ -+ int discardremoteholdretrieval; /*!< shall remote hold or remote retrieval notifications be discarded? */ - int facilityenable; /*!< Enable facility IEs */ - struct pri *dchans[NUM_DCHANS]; /*!< Actual d-channels */ - int dchanavail[NUM_DCHANS]; /*!< Whether each channel is available */ - struct pri *pri; /*!< Currently active D-channel */ -+ /*! \brief TRUE if to dump PRI event info (Tested but never set) */ - int debug; - int fds[NUM_DCHANS]; /*!< FD's for d-channels */ -+ /*! \brief Value set but not used */ - int offset; -+ /*! \brief Span number put into user output messages */ - int span; -+ /*! \brief TRUE if span is being reset/restarted */ - int resetting; -+ /*! \brief Current position during a reset (-1 if not started) */ - int resetpos; - #ifdef HAVE_PRI_INBANDDISCONNECT - unsigned int inbanddisconnect:1; /*!< Should we support inband audio after receiving DISCONNECT? */ - #endif - time_t lastreset; /*!< time when unused channels were last reset */ - long resetinterval; /*!< Interval (in seconds) for resetting unused channels */ -+ /*! \brief ISDN signalling type (SIG_PRI, SIG_BRI, SIG_BRI_PTMP, etc...) */ - int sig; -+ unsigned int use_callingpres:1; /*!< used for no channel call */ - struct dahdi_pvt *pvts[MAX_CHANNELS]; /*!< Member channel pvt structs */ - struct dahdi_pvt *crvs; /*!< Member CRV structs */ - struct dahdi_pvt *crvend; /*!< Pointer to end of CRV structs */ -@@ -503,11 +868,32 @@ - - #define MAX_SLAVES 4 - -+/* States for sending MWI message -+ * First three states are required for send Ring Pulse Alert Signal -+ */ -+typedef enum { -+ MWI_SEND_NULL = 0, -+ MWI_SEND_SA, -+ MWI_SEND_SA_WAIT, -+ MWI_SEND_PAUSE, -+ MWI_SEND_SPILL, -+ MWI_SEND_CLEANUP, -+ MWI_SEND_DONE, -+} mwisend_states; -+ -+struct mwisend_info { -+ struct timeval pause; -+ mwisend_states mwisend_current; -+}; -+ - static struct dahdi_pvt { - ast_mutex_t lock; - struct ast_channel *owner; /*!< Our current active owner (if applicable) */ - /*!< Up to three channels can be associated with this call */ -- -+#if defined(HAVE_PRI) -+ int dummychannel; /*!< Flag for dummy Channel. used for ccbsnr (shellscript) */ -+#endif /* defined(HAVE_PRI) */ -+ - struct dahdi_subchannel sub_unused; /*!< Just a safety precaution */ - struct dahdi_subchannel subs[3]; /*!< Sub-channels */ - struct dahdi_confinfo saveconf; /*!< Saved conference info */ -@@ -515,181 +901,533 @@ - struct dahdi_pvt *slaves[MAX_SLAVES]; /*!< Slave to us (follows our conferencing) */ - struct dahdi_pvt *master; /*!< Master to us (we follow their conferencing) */ - int inconference; /*!< If our real should be in the conference */ -- -+ -+ int bufsize; /*!< Size of the buffers */ - int buf_no; /*!< Number of buffers */ - int buf_policy; /*!< Buffer policy */ -+ int faxbuf_no; /*!< Number of Fax buffers */ -+ int faxbuf_policy; /*!< Fax buffer policy */ - int sig; /*!< Signalling style */ -- int radio; /*!< radio type */ -+ /*! -+ * \brief Nonzero if the signaling type is sent over a radio. -+ * \note Set to a couple of nonzero values but it is only tested like a boolean. -+ */ -+ int radio; - int outsigmod; /*!< Outbound Signalling style (modifier) */ - int oprmode; /*!< "Operator Services" mode */ - struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */ -- float cid_rxgain; /*!< "Gain to apply during caller id */ -+ /*! \brief Amount of gain to increase during caller id */ -+ float cid_rxgain; -+ /*! \brief Rx gain set by chan_dahdi.conf */ - float rxgain; -+ /*! \brief Tx gain set by chan_dahdi.conf */ - float txgain; - int tonezone; /*!< tone zone for this chan, or -1 for default */ - struct dahdi_pvt *next; /*!< Next channel in list */ - struct dahdi_pvt *prev; /*!< Prev channel in list */ - - /* flags */ -+ -+ /*! -+ * \brief TRUE if ADSI (Analog Display Services Interface) available -+ * \note Set from the "adsi" value read in from chan_dahdi.conf -+ */ - unsigned int adsi:1; -+ /*! -+ * \brief TRUE if we can use a polarity reversal to mark when an outgoing -+ * call is answered by the remote party. -+ * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf -+ */ - unsigned int answeronpolarityswitch:1; -+ /*! -+ * \brief TRUE if busy detection is enabled. -+ * (Listens for the beep-beep busy pattern.) -+ * \note Set from the "busydetect" value read in from chan_dahdi.conf -+ */ - unsigned int busydetect:1; -+ /*! -+ * \brief TRUE if call return is enabled. -+ * (*69, if your dialplan doesn't catch this first) -+ * \note Set from the "callreturn" value read in from chan_dahdi.conf -+ */ - unsigned int callreturn:1; -+ /*! -+ * \brief TRUE if busy extensions will hear the call-waiting tone -+ * and can use hook-flash to switch between callers. -+ * \note Can be disabled by dialing *70. -+ * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf -+ */ - unsigned int callwaiting:1; -+ /*! -+ * \brief TRUE if send caller ID for Call Waiting -+ * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf -+ */ - unsigned int callwaitingcallerid:1; -+ /*! -+ * \brief TRUE if support for call forwarding enabled. -+ * Dial *72 to enable call forwarding. -+ * Dial *73 to disable call forwarding. -+ * \note Set from the "cancallforward" value read in from chan_dahdi.conf -+ */ - unsigned int cancallforward:1; -+ /*! -+ * \brief TRUE if support for call parking is enabled. -+ * \note Set from the "canpark" value read in from chan_dahdi.conf -+ */ - unsigned int canpark:1; -- unsigned int confirmanswer:1; /*!< Wait for '#' to confirm answer */ -+ /*! \brief TRUE if to wait for a DTMF digit to confirm answer */ -+ unsigned int confirmanswer:1; -+ /*! -+ * \brief TRUE if the channel is to be destroyed on hangup. -+ * (Used by pseudo channels.) -+ */ - unsigned int destroy:1; - unsigned int didtdd:1; /*!< flag to say its done it once */ -+ /*! \brief TRUE if analog type line dialed no digits in Dial() */ - unsigned int dialednone:1; -+ /*! \brief TRUE if in the process of dialing digits or sending something. */ - unsigned int dialing:1; -+ /*! \brief TRUE if the transfer capability of the call is digital. */ - unsigned int digital:1; -+ /*! \brief TRUE if Do-Not-Disturb is enabled. */ - unsigned int dnd:1; -+ /*! \brief XXX BOOLEAN Purpose??? */ - unsigned int echobreak:1; -+ /*! -+ * \brief TRUE if echo cancellation enabled when bridged. -+ * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf -+ * \note Disabled if the echo canceller is not setup. -+ */ - unsigned int echocanbridged:1; -+ /*! \brief TRUE if echo cancellation is turned on. */ - unsigned int echocanon:1; -- unsigned int faxhandled:1; /*!< Has a fax tone already been handled? */ -+ /*! \brief TRUE if a fax tone has already been handled. */ -+ unsigned int faxhandled:1; -+ /*! \brief TRUE if dynamic faxbuffers are configured for use, default is OFF */ -+ unsigned int usefaxbuffers:1; -+ /*! \brief TRUE while dynamic faxbuffers are in use */ -+ unsigned int faxbuffersinuse:1; -+ /*! \brief TRUE if over a radio and dahdi_read() has been called. */ - unsigned int firstradio:1; -+ /*! -+ * \brief TRUE if the call will be considered "hung up" on a polarity reversal. -+ * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf -+ */ - unsigned int hanguponpolarityswitch:1; -+ /*! \brief TRUE if DTMF detection needs to be done by hardware. */ - unsigned int hardwaredtmf:1; -+ /*! -+ * \brief TRUE if the outgoing caller ID is blocked/hidden. -+ * \note Caller ID can be disabled by dialing *67. -+ * \note Caller ID can be enabled by dialing *82. -+ * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf -+ */ - unsigned int hidecallerid:1; -- unsigned int hidecalleridname:1; /*!< Hide just the name not the number for legacy PBX use */ -+ /*! -+ * \brief TRUE if hide just the name not the number for legacy PBX use. -+ * \note Only applies to PRI channels. -+ * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf -+ */ -+ unsigned int hidecalleridname:1; -+ /*! \brief TRUE if DTMF detection is disabled. */ - unsigned int ignoredtmf:1; -- unsigned int immediate:1; /*!< Answer before getting digits? */ -+ /*! -+ * \brief TRUE if the channel should be answered immediately -+ * without attempting to gather any digits. -+ * \note Set from the "immediate" value read in from chan_dahdi.conf -+ */ -+ unsigned int immediate:1; -+ /*! \brief TRUE if in an alarm condition. */ - unsigned int inalarm:1; -- unsigned int mate:1; /*!< flag to say its in MATE mode */ -+ /*! \brief TRUE if TDD in MATE mode */ -+ unsigned int mate:1; -+ /*! \brief TRUE if we originated the call leg. */ - unsigned int outgoing:1; - /* unsigned int overlapdial:1; unused and potentially confusing */ -+ /*! -+ * \brief TRUE if busy extensions will hear the call-waiting tone -+ * and can use hook-flash to switch between callers. -+ * \note Set from the "callwaiting" value read in from chan_dahdi.conf -+ */ - unsigned int permcallwaiting:1; -- unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */ -+ /*! -+ * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden. -+ * \note Set from the "hidecallerid" value read in from chan_dahdi.conf -+ */ -+ unsigned int permhidecallerid:1; -+ /*! -+ * \brief TRUE if PRI congestion/busy indications are sent out-of-band. -+ * \note Set from the "priindication" value read in from chan_dahdi.conf -+ */ - unsigned int priindication_oob:1; -+ /*! -+ * \brief TRUE if PRI B channels are always exclusively selected. -+ * \note Set from the "priexclusive" value read in from chan_dahdi.conf -+ */ - unsigned int priexclusive:1; -+ /*! -+ * \brief TRUE if we will pulse dial. -+ * \note Set from the "pulsedial" value read in from chan_dahdi.conf -+ */ - unsigned int pulse:1; -- unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */ -+ /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */ -+ unsigned int pulsedial:1; - unsigned int restartpending:1; /*!< flag to ensure counted only once for restart */ -- unsigned int restrictcid:1; /*!< Whether restrict the callerid -> only send ANI */ -+ /*! -+ * \brief TRUE if caller ID is restricted. -+ * \note Set but not used. Should be deleted. Redundant with permhidecallerid. -+ * \note Set from the "restrictcid" value read in from chan_dahdi.conf -+ */ -+ unsigned int restrictcid:1; -+ /*! -+ * \brief TRUE if three way calling is enabled -+ * \note Set from the "threewaycalling" value read in from chan_dahdi.conf -+ */ - unsigned int threewaycalling:1; -+ /*! -+ * \brief TRUE if call transfer is enabled -+ * \note For FXS ports (either direct analog or over T1/E1): -+ * Support flash-hook call transfer -+ * \note For digital ports using ISDN PRI protocols: -+ * Support switch-side transfer (called 2BCT, RLT or other names) -+ * \note Set from the "transfer" value read in from chan_dahdi.conf -+ */ - unsigned int transfer:1; -- unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */ -- unsigned int use_callingpres:1; /*!< Whether to use the callingpres the calling switch sends */ -+ /*! -+ * \brief TRUE if caller ID is used on this channel. -+ * \note PRI and SS7 spans will save caller ID from the networking peer. -+ * \note FXS ports will generate the caller ID spill. -+ * \note FXO ports will listen for the caller ID spill. -+ * \note Set from the "usecallerid" value read in from chan_dahdi.conf -+ */ -+ unsigned int use_callerid:1; -+ /*! -+ * \brief TRUE if we will use the calling presentation setting -+ * from the Asterisk channel for outgoing calls. -+ * \note Only applies to PRI and SS7 channels. -+ * \note Set from the "usecallingpres" value read in from chan_dahdi.conf -+ */ -+ unsigned int use_callingpres:1; -+ /*! -+ * \brief TRUE if distinctive rings are to be detected. -+ * \note For FXO lines -+ * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf -+ */ - unsigned int usedistinctiveringdetection:1; -- unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */ -- unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */ -- unsigned int mwimonitor_neon:1; /*!< monitor this FXO port for neon type MWI indication from other end */ -- unsigned int mwimonitor_fsk:1; /*!< monitor this FXO port for fsk MWI indication from other end */ -- unsigned int mwimonitor_rpas:1; /*!< monitor this FXO port for rpas precursor to fsk MWI indication */ -- unsigned int mwimonitoractive:1; /*!< an MWI monitor thread is currently active */ -- unsigned int mwisendactive:1; /*!< a MWI message sending thread is active */ -- /* Channel state or unavilability flags */ -+ /*! -+ * \brief TRUE if we should use the callerid from incoming call on dahdi transfer. -+ * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf -+ */ -+ unsigned int dahditrcallerid:1; -+ /*! -+ * \brief TRUE if allowed to flash-transfer to busy channels. -+ * \note Set from the "transfertobusy" value read in from chan_dahdi.conf -+ */ -+ unsigned int transfertobusy:1; -+ /*! -+ * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end. -+ * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf -+ */ -+ unsigned int mwimonitor_neon:1; -+ /*! -+ * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end. -+ * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf -+ */ -+ unsigned int mwimonitor_fsk:1; -+ /*! -+ * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end. -+ * \note RPAS - Ring Pulse Alert Signal -+ * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf -+ */ -+ unsigned int mwimonitor_rpas:1; -+ /*! \brief TRUE if an MWI monitor thread is currently active */ -+ unsigned int mwimonitoractive:1; -+ /*! \brief TRUE if a MWI message sending thread is active */ -+ unsigned int mwisendactive:1; -+ /*! -+ * \brief TRUE if channel is out of reset and ready -+ * \note Set but not used. -+ */ - unsigned int inservice:1; -+ /*! -+ * \brief TRUE if the channel is locally blocked. -+ * \note Applies to SS7 channels. -+ */ - unsigned int locallyblocked:1; -+ /*! -+ * \brief TRUE if the channel is remotely blocked. -+ * \note Applies to SS7 channels. -+ */ - unsigned int remotelyblocked:1; - #if defined(HAVE_PRI) || defined(HAVE_SS7) -- unsigned int rlt:1; -+ /*! -+ * \brief XXX BOOLEAN Purpose??? -+ * \note Applies to SS7 channels. -+ */ -+ unsigned int rlt:1; -+ /*! \brief TRUE if channel is alerting/ringing */ - unsigned int alerting:1; -+ /*! \brief TRUE if the call has already gone/hungup */ - unsigned int alreadyhungup:1; -+ /*! -+ * \brief TRUE if this is an idle call -+ * \note Applies to PRI channels. -+ */ - unsigned int isidlecall:1; -+ /*! -+ * \brief TRUE if call is in a proceeding state. -+ * The call has started working its way through the network. -+ */ - unsigned int proceeding:1; -+ /*! \brief TRUE if the call has seen progress through the network. */ - unsigned int progress:1; -+ /*! -+ * \brief TRUE if this channel is being reset/restarted -+ * \note Applies to PRI channels. -+ */ - unsigned int resetting:1; -+ /*! -+ * \brief TRUE if this channel has received a SETUP_ACKNOWLEDGE -+ * \note Applies to PRI channels. -+ */ - unsigned int setup_ack:1; - #endif -- unsigned int use_smdi:1; /* Whether to use SMDI on this channel */ -- struct ast_smdi_interface *smdi_iface; /* The serial port to listen for SMDI data on */ -+#if defined(HAVE_PRI) -+ unsigned int ccringout:1; /*!< Append CC-Ringout facility */ -+#endif /* defined(HAVE_PRI) */ -+ /*! -+ * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled -+ * \note Set from the "usesmdi" value read in from chan_dahdi.conf -+ */ -+ unsigned int use_smdi:1; -+ struct mwisend_info mwisend_data; -+ /*! \brief The serial port to listen for SMDI data on */ -+ struct ast_smdi_interface *smdi_iface; - -+ /*! \brief Distinctive Ring data */ - struct dahdi_distRings drings; - -+ /*! -+ * \brief The configured context for incoming calls. -+ * \note The "context" string read in from chan_dahdi.conf -+ */ - char context[AST_MAX_CONTEXT]; -+ /*! -+ * \brief Saved context string. -+ */ - char defcontext[AST_MAX_CONTEXT]; -+ /*! \brief Extension to use in the dialplan. */ - char exten[AST_MAX_EXTENSION]; -+ /*! -+ * \brief Language configured for calls. -+ * \note The "language" string read in from chan_dahdi.conf -+ */ - char language[MAX_LANGUAGE]; -+ /*! -+ * \brief The configured music-on-hold class to use for calls. -+ * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf -+ */ - char mohinterpret[MAX_MUSICCLASS]; -+ /*! -+ * \brief Sugggested music-on-hold class for peer channel to use for calls. -+ * \note The "mohsuggest" string read in from chan_dahdi.conf -+ */ - char mohsuggest[MAX_MUSICCLASS]; - char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */ - #if defined(PRI_ANI) || defined(HAVE_SS7) -+ /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */ - char cid_ani[AST_MAX_EXTENSION]; - #endif -+ /*! \brief Automatic Number Identification code from PRI */ - int cid_ani2; -+ /*! \brief Caller ID number from an incoming call. */ - char cid_num[AST_MAX_EXTENSION]; -- int cid_ton; /*!< Type Of Number (TON) */ -+ /*! \brief Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise. */ -+ int cid_ton; -+ /*! \brief Caller ID name from an incoming call. */ - char cid_name[AST_MAX_EXTENSION]; -+ /*! \brief Last Caller ID number from an incoming call. */ - char lastcid_num[AST_MAX_EXTENSION]; -+ /*! \brief Last Caller ID name from an incoming call. */ - char lastcid_name[AST_MAX_EXTENSION]; - char *origcid_num; /*!< malloced original callerid */ - char *origcid_name; /*!< malloced original callerid */ -+ /*! \brief Call waiting number. */ - char callwait_num[AST_MAX_EXTENSION]; -+ /*! \brief Call waiting name. */ - char callwait_name[AST_MAX_EXTENSION]; -+ /*! \brief Redirecting Directory Number Information Service (RDNIS) number */ - char rdnis[AST_MAX_EXTENSION]; -+ /*! \brief Dialed Number Identifier */ - char dnid[AST_MAX_EXTENSION]; -+ /*! -+ * \brief Bitmapped groups this belongs to. -+ * \note The "group" bitmapped group string read in from chan_dahdi.conf -+ */ - ast_group_t group; -+ /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */ - int law; - int confno; /*!< Our conference */ - int confusers; /*!< Who is using our conference */ - int propconfno; /*!< Propagated conference number */ -+ /*! -+ * \brief Bitmapped call groups this belongs to. -+ * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf -+ */ - ast_group_t callgroup; -+ /*! -+ * \brief Bitmapped pickup groups this belongs to. -+ * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf -+ */ - ast_group_t pickupgroup; -+ /*! -+ * \brief Channel variable list with associated values to set when a channel is created. -+ * \note The "setvar" strings read in from chan_dahdi.conf -+ */ - struct ast_variable *vars; - int channel; /*!< Channel Number or CRV */ - int span; /*!< Span number */ - time_t guardtime; /*!< Must wait this much time before using for new call */ - int cid_signalling; /*!< CID signalling type bell202 or v23 */ - int cid_start; /*!< CID start indicator, polarity or ring */ -- int callingpres; /*!< The value of callling presentation that we're going to use when placing a PRI call */ -+ int callingpres; /*!< The value of calling presentation that we're going to use when placing a PRI call */ - int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */ - int cidcwexpire; /*!< When to expire our muting for CID/CW */ -+ /*! \brief Analog caller ID waveform sample buffer */ - unsigned char *cidspill; -+ /*! \brief Position in the cidspill buffer to send out next. */ - int cidpos; -+ /*! \brief Length of the cidspill buffer containing samples. */ - int cidlen; -+ /*! \brief Ring timeout timer?? */ - int ringt; -+ /*! -+ * \brief Ring timeout base. -+ * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf -+ */ - int ringt_base; -+ /*! -+ * \brief Number of most significant digits/characters to strip from the dialed number. -+ * \note Feature is deprecated. Use dialplan logic. -+ * \note The characters are stripped before the PRI TON/NPI prefix -+ * characters are processed. -+ */ - int stripmsd; -+ /*! \brief BOOLEAN. XXX Meaning what?? */ - int callwaitcas; -+ /*! \brief Number of call waiting rings. */ - int callwaitrings; -+ /*! \brief Echo cancel parameters. */ - struct { - struct dahdi_echocanparams head; - struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS]; - } echocancel; -+ /*! -+ * \brief Echo training time. 0 = disabled -+ * \note Set from the "echotraining" value read in from chan_dahdi.conf -+ */ - int echotraining; -+ /*! \brief Filled with 'w'. XXX Purpose?? */ - char echorest[20]; -+ /*! -+ * \brief Number of times to see "busy" tone before hanging up. -+ * \note Set from the "busycount" value read in from chan_dahdi.conf -+ */ - int busycount; -+ /*! -+ * \brief Length of "busy" tone on time. -+ * \note Set from the "busypattern" value read in from chan_dahdi.conf -+ */ - int busy_tonelength; -+ /*! -+ * \brief Length of "busy" tone off time. -+ * \note Set from the "busypattern" value read in from chan_dahdi.conf -+ */ - int busy_quietlength; -+ /*! -+ * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values. -+ * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf -+ */ - int callprogress; -+ /*! -+ * \brief Number of milliseconds to wait for dialtone. -+ * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf -+ */ -+ int waitfordialtone; -+ struct timeval waitingfordt; /*!< Time we started waiting for dialtone */ - struct timeval flashtime; /*!< Last flash-hook time */ -+ /*! \brief Opaque DSP configuration structure. */ - struct ast_dsp *dsp; -- int cref; /*!< Call reference number */ -+ //int cref; /*!< Call reference number (Not used) */ -+ /*! \brief DAHDI dial operation command struct for ioctl() call. */ - struct dahdi_dialoperation dop; - int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */ -+ /*! \brief Second part of SIG_FEATDMF_TA wink operation. */ - char finaldial[64]; - char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */ - int amaflags; /*!< AMA Flags */ - struct tdd_state *tdd; /*!< TDD flag */ -+ /*! \brief Accumulated call forwarding number. */ - char call_forward[AST_MAX_EXTENSION]; -+ /*! -+ * \brief Voice mailbox location. -+ * \note Set from the "mailbox" string read in from chan_dahdi.conf -+ */ - char mailbox[AST_MAX_EXTENSION]; -+ /*! \brief Opaque event subscription parameters for message waiting indication support. */ - struct ast_event_sub *mwi_event_sub; -+ /*! \brief Delayed dialing for E911. Overlap digits for ISDN. */ - char dialdest[256]; -+ /*! \brief Time the interface went on-hook. */ - int onhooktime; -+ /*! \brief TRUE if the FXS port is off-hook */ -+ int fxsoffhookstate; -+ /*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */ - int msgstate; -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ struct dahdi_vmwi_info mwisend_setting; /*!< Which VMWI methods to use */ -+ unsigned int mwisend_fsk: 1; /*! Variable for enabling FSK MWI handling in chan_dahdi */ -+ unsigned int mwisend_rpas:1; /*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */ -+#endif - int distinctivering; /*!< Which distinctivering to use */ - int cidrings; /*!< Which ring to deliver CID on */ - int dtmfrelax; /*!< whether to run in relaxed DTMF mode */ -+ /*! \brief Holding place for event injected from outside normal operation. */ - int fake_event; -+ /*! -+ * \brief Minimal time period (ms) between the answer polarity -+ * switch and hangup polarity switch. -+ */ - int polarityonanswerdelay; -+ /*! \brief Start delay time if polarityonanswerdelay is nonzero. */ - struct timeval polaritydelaytv; -+ /*! -+ * \brief Send caller ID after this many rings. -+ * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf -+ */ - int sendcalleridafter; - #ifdef HAVE_PRI -+ /*! \brief DAHDI PRI control parameters */ - struct dahdi_pri *pri; -+ /*! \brief XXX Purpose??? */ - struct dahdi_pvt *bearer; -+ /*! \brief XXX Purpose??? */ - struct dahdi_pvt *realcall; -+ /*! \brief Opaque libpri call control structure */ - q931_call *call; -+ /*! \brief Channel number in span. */ - int prioffset; -+ /*! \brief Logical span number within trunk group */ - int logicalspan; --#endif -+#endif -+ /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */ - int polarity; -+ /*! \brief DSP feature flags: DSP_FEATURE_xxx */ - int dsp_features; - #ifdef HAVE_SS7 -+ /*! \brief SS7 control parameters */ - struct dahdi_ss7 *ss7; -+ /*! \brief Opaque libss7 call control structure */ - struct isup_call *ss7call; - char charge_number[50]; - char gen_add_number[50]; -@@ -716,7 +1454,9 @@ - unsigned int dpc; /*!< CIC's DPC */ - unsigned int loopedback:1; - #endif -+ /*! \brief DTMF digit in progress. 0 when no digit in progress. */ - char begindigit; -+ /*! \brief TRUE if confrence is muted. */ - int muting; - } *iflist = NULL, *ifend = NULL; - -@@ -725,7 +1465,7 @@ - * Generally there is a field here for every possible configuration item. - * - * The state of fields is saved along the parsing and whenever a 'channel' -- * statement is reached, the current dahdi_chan_conf is used to configure the -+ * statement is reached, the current dahdi_chan_conf is used to configure the - * channel (struct dahdi_pvt) - * - * \see dahdi_chan_init for the default values. -@@ -742,11 +1482,16 @@ - struct dahdi_params timing; - int is_sig_auto; /*!< Use channel signalling from DAHDI? */ - -+ /*! -+ * \brief The serial port to listen for SMDI data on -+ * \note Set from the "smdiport" string read in from chan_dahdi.conf -+ */ - char smdi_port[SMDI_MAX_FILENAME_LEN]; - }; - - /*! returns a new dahdi_chan_conf with default values (by-value) */ --static struct dahdi_chan_conf dahdi_chan_conf_default(void) { -+static struct dahdi_chan_conf dahdi_chan_conf_default(void) -+{ - /* recall that if a field is not included here it is initialized - * to 0 or equivalent - */ -@@ -758,6 +1503,7 @@ - .dialplan = PRI_UNKNOWN + 1, - .localdialplan = PRI_NATIONAL_ISDN + 1, - .nodetype = PRI_CPE, -+ .qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL, - - .minunused = 2, - .idleext = "", -@@ -808,13 +1554,18 @@ - - .mailbox = "", - -- -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ .mwisend_fsk = 1, -+#endif - .polarityonanswerdelay = 600, - - .sendcalleridafter = DEFAULT_CIDRINGS, -- -+ - .buf_policy = DAHDI_POLICY_IMMEDIATE, -- .buf_no = numbufs -+ .buf_no = numbufs, -+ .usefaxbuffers = 0, -+ .faxbuf_policy = DAHDI_POLICY_IMMEDIATE, -+ .faxbuf_no = numbufs, - }, - .timing = { - .prewinktime = -1, -@@ -877,9 +1628,300 @@ - #define GET_CHANNEL(p) ((p)->channel) - #endif - -+#if defined(HAVE_PRI) -+static inline int pri_nochannel_grab(struct dahdi_pri *pri) -+{ -+ int res; -+ /* Grab the lock first */ -+ do { -+ res = ast_mutex_trylock(&pri->lock); -+ if (res) { -+ /* Release the lock and try again */ -+ usleep(1); -+ } -+ } while (res); -+ /* Then break the poll */ -+ pthread_kill(pri->master, SIGURG); -+ return 0; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * a new CCBS/CCNR id was received -+ */ -+static struct ccbsnr_link *ccbsnr_new_id(int callreference, int ccbsnronprispan, -+ q931_call *call, int type, char *callingnum, char *callernum, -+ char *callername, char *context, int priority, struct ast_channel *peer) -+{ -+ struct ccbsnr_link *ccbsnr; -+ -+ ccbsnr = ast_calloc(1, sizeof(*ccbsnr)); -+ if (!ccbsnr) { -+ ast_log(LOG_ERROR, "Unable to allocate CCBS/CCNR struct.\n"); -+ return NULL; -+ } -+ -+ ccbsnr->age = time(NULL); -+ ccbsnr->type = type; -+ ccbsnr->call = call; -+ ccbsnr->handle = CCBS_HANDLE(ccbsnronprispan,callreference); -+ ccbsnr->peer = peer; -+ ccbsnr->priority = priority; -+ ccbsnr->state = CC_WAIT_ACK; -+ ast_copy_string(ccbsnr->callingnum, callingnum, sizeof(ccbsnr->callingnum)); -+ ast_copy_string(ccbsnr->callernum, callernum, sizeof(ccbsnr->callernum)); -+ ast_copy_string(ccbsnr->callername, callername, sizeof(ccbsnr->callername)); -+ ast_copy_string(ccbsnr->context, context, sizeof(ccbsnr->context)); -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ del_old_ccbsnr(); -+ ccbsnr->next = ccbsnr_list; -+ ccbsnr_list = ccbsnr; -+ ast_mutex_unlock(&ccbsnr_lock); -+ -+ return ccbsnr; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * Clear CCBS/CCNR links -+ */ -+static void ccbsnr_clear_all(void) -+{ -+ struct ccbsnr_link *ccbsnr; -+ struct ccbsnr_link *tmp = NULL; -+ unsigned int span; -+ int cr; -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ tmp = ccbsnr; -+ ccbsnr = ccbsnr->next; -+ span = CCBS_SPAN(tmp->handle); -+ cr = CCBS_CR(tmp->handle); -+ ast_log(LOG_NOTICE, "ccbsnr_clear_all: ccbsnr found(%p) span %d\n", tmp, span); -+ ast_free(tmp); -+ } -+ -+ ccbsnr_list = NULL; -+ ast_mutex_unlock(&ccbsnr_lock); -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static void ccbsnr_destroy_all_of_span(struct dahdi_pri *pri) -+{ -+ int span = pri->span; -+ struct ccbsnr_link *ccbsnr; -+ struct ccbsnr_link *prev = NULL; -+ struct ccbsnr_link *tmp = NULL; -+ q931_call *call; -+ unsigned int ccbs_span; -+ int cr; -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ ccbs_span = CCBS_SPAN(ccbsnr->handle); -+ cr = CCBS_CR(ccbsnr->handle); -+ if (ccbs_span == span) { -+ ast_log(LOG_NOTICE, "ccbsnr found(%p) ccbs_span %d\n", ccbsnr, ccbs_span); -+ -+ tmp = ccbsnr; -+ if (!prev) { -+ ccbsnr_list = ccbsnr->next; -+ } else { -+ prev->next = ccbsnr->next; -+ } -+ ccbsnr = ccbsnr->next; -+ -+ if (tmp->call) { -+ call = pri_find_call(pri->pri, cr); -+ ast_log(LOG_NOTICE, "call found(%p)\n", call); -+ -+ if (call == tmp->call) { -+ ast_log(LOG_WARNING, "Q931Call(%p) cr(%x) found, hang it up it.\n", -+ call, cr); -+ -+ pri_call_set_cc_operation(call, PRI_CC_CANCEL); -+ pri_hangup(pri->pri, call, -1); -+ pri_destroycall(pri->pri, call); -+ } -+ } -+ ast_free(tmp); -+ ast_log(LOG_WARNING, "Free ccbsnr-link (%p) ccbs_span %d\n", tmp, ccbs_span); -+ } else { -+ prev = ccbsnr; -+ ccbsnr = ccbsnr->next; -+ } -+ } -+ -+ ast_mutex_unlock(&ccbsnr_lock); -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * Destroy CCBS/CCNR links -+ */ -+static void ccbsnr_destroy_all(void) -+{ -+ struct ccbsnr_link *ccbsnr; -+ struct ccbsnr_link *tmp = NULL; -+ q931_call *call; -+ struct dahdi_pri *pri; -+ unsigned int span; -+ int cr; -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ tmp = ccbsnr; -+ ccbsnr = ccbsnr->next; -+ span = CCBS_SPAN(tmp->handle); -+ cr = CCBS_CR(tmp->handle); -+ ast_log(LOG_NOTICE, "ccbsnr_destroy_all: ccbsnr found(%p) span %d\n", tmp, span); -+ -+ if (tmp->call) { -+ pri = &pris[span - 1]; -+ -+ if (pri_nochannel_grab(pri)) { -+ ast_log(LOG_ERROR, "Failed to grab PRI!\n"); -+ return; -+ } -+ -+ call = pri_find_call(pri->pri, cr); -+ ast_log(LOG_NOTICE, "ccbsnr_destroy_all: call found(%p)\n", call); -+ -+ if (call == tmp->call) { -+ ast_log(LOG_WARNING, -+ "ccbsnr_destroy_all(%p) cr(%x):Q931_call found, hang it up it.\n", -+ call, cr); -+ -+ pri_call_set_cc_operation(call, PRI_CC_CANCEL); -+ pri_hangup(pri->pri, call, -1); -+ } -+ -+ pri_rel(pri); -+ } -+ ast_free(tmp); -+ } -+ -+ ccbsnr_list = NULL; -+ ast_mutex_unlock(&ccbsnr_lock); -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+/* -+ * on an activated CCBS, the remote party is now free -+ */ -+static void ccbsnr_remote_user_free(unsigned int handle) -+{ -+ struct ast_channel *ast; -+ struct ccbsnr_link *ccbsnr; -+ int state = AST_STATE_DOWN; -+ struct dahdi_pvt *dummy; -+ -+ ast_verb(3, "ccbsnr_remote_user_free: handle %x\n", handle); -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ -+ ccbsnr = ccbsnr_list; -+ while (ccbsnr) { -+ if (ccbsnr->handle == handle) { -+ break; -+ } -+ ccbsnr = ccbsnr->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+ -+ if (!(ccbsnr)) { -+ ast_log(LOG_ERROR, "DAHDI: CCBS/CCBR reference not found!\n"); -+ return; -+ } -+ -+ ast = ast_channel_alloc(0, state, 0, 0, "", "", "", 0, 0); -+ if (!ast) { -+ ast_log(LOG_ERROR, "Unable to allocate channel!\n"); -+ return; -+ } -+ -+ ast->tech = &dahdi_tech; -+ dummy = ast_calloc(1,sizeof(*dummy)); -+ if (!dummy) { -+ ast_log(LOG_ERROR, "Unable to allocate dummy:struct dahdi_pvt!\n"); -+ return; -+ } -+ ast_mutex_init(&dummy->lock); -+ dummy->dummychannel = 1; -+ ast->tech_pvt = dummy; -+ ast_string_field_build(ast, name, "CCBSNR/%x", ccbsnr->handle); -+ -+ ast_verb(3, "ccbsnr_remote_user_free: ast=%p name=%s ast->_softhangup=%x ast->tech%p\n", -+ ast, ast->name, ast->_softhangup, ast->tech); -+ -+ ast->_softhangup = 0; -+ memset(&ast->whentohangup, 0, sizeof(ast->whentohangup)); -+ -+ ast->priority = ccbsnr->priority; -+ -+ if (ast->cid.cid_num) { -+ ast_free(ast->cid.cid_num); -+ } -+ ast->cid.cid_num = ast_strdup(ccbsnr->callernum); -+ -+ if (ast->cid.cid_dnid) { -+ ast_free(ast->cid.cid_dnid); -+ } -+ ast->cid.cid_name = ast_strdup(ccbsnr->callername); -+ -+ ast_copy_string(ast->context, ccbsnr->context, sizeof(ast->context)); -+ ast_copy_string(ast->exten, ccbsnr->callingnum, sizeof(ast->exten)); -+ -+ ast_setstate(ast, state); -+ ast_verb(3, "ccbsnr_remote_user_free: ast_pbx_start:ast %p cc-req(%d)\n", -+ ast, ccbsnr->type); -+ -+ if (ast_pbx_start(ast)) { -+ int ccbs_span; -+ struct dahdi_pri *ccbs_pri; -+ -+ pri_call_set_cc_operation(ccbsnr->call, PRI_CC_CANCEL); -+ -+ ccbs_span = CCBS_SPAN(ccbsnr->handle); -+ ccbs_pri = &pris[ccbs_span - 1]; -+ -+ if (pri_nochannel_grab(ccbs_pri)) { -+ ast_log(LOG_WARNING, "Failed to grab PRI!\n"); -+ return; -+ } -+ pri_hangup(ccbs_pri->pri, ccbsnr->call, -1); -+ pri_rel(ccbs_pri); -+ ccbsnr->call = NULL; -+ ccbsnr_del_link(ccbsnr->handle); -+ -+ ast_log(LOG_ERROR, "DAHDI: CCBS/CCNR: Unable to start pbx!\n"); -+ -+ return; -+ } else { -+ ast_verb(3, -+ "DAHDI-span%d: started PBX for CCBS/CCNR callback (context:%s/callingnum:%s/prio:%d)callernum:%s callername:%s peer=%p\n", -+ CCBS_SPAN(ccbsnr->handle), ccbsnr->context, ccbsnr->callingnum, -+ ccbsnr->priority, ccbsnr->callernum, ccbsnr->callername, ccbsnr->peer); -+ ccbsnr->state = CC_WAIT_USER_A_ANSWER_N; -+ } -+ -+ ast_module_ref(ast_module_info->self); -+} -+#endif /* defined(HAVE_PRI) */ -+ - struct dahdi_pvt *round_robin[32]; - --#ifdef HAVE_PRI -+#if defined(HAVE_PRI) - static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri) - { - int res; -@@ -895,14 +1937,16 @@ - pthread_kill(pri->master, SIGURG); - return 0; - } --#endif -+#endif /* defined(HAVE_PRI) */ - --#ifdef HAVE_SS7 -+#if defined(HAVE_SS7) - static inline void ss7_rel(struct dahdi_ss7 *ss7) - { - ast_mutex_unlock(&ss7->lock); - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri) - { - int res; -@@ -918,7 +1962,7 @@ - pthread_kill(pri->master, SIGURG); - return 0; - } --#endif -+#endif /* defined(HAVE_SS7) */ - #define NUM_CADENCE_MAX 25 - static int num_cadence = 4; - static int user_has_defined_cadences = 0; -@@ -967,16 +2011,12 @@ - return res; - } - --#ifdef HAVE_PRI - static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri) --#else --static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri) --#endif - { - #ifdef HAVE_PRI - if (pri) - ast_mutex_unlock(&pri->lock); --#endif -+#endif - for (;;) { - if (p->subs[a].owner) { - if (ast_channel_trylock(p->subs[a].owner)) { -@@ -992,7 +2032,7 @@ - #ifdef HAVE_PRI - if (pri) - ast_mutex_lock(&pri->lock); --#endif -+#endif - } - - static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *data) -@@ -1023,7 +2063,7 @@ - break; - } - } --#endif -+#endif - for (;;) { - if (p->owner) { - if (ast_channel_trylock(p->owner)) { -@@ -1055,8 +2095,7 @@ - break; - } - } -- --#endif -+#endif - } - - static int restore_gains(struct dahdi_pvt *p); -@@ -1081,9 +2120,9 @@ - p->subs[b].owner = towner; - p->subs[b].inthreeway = tinthreeway; - -- if (p->subs[a].owner) -+ if (p->subs[a].owner) - ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd); -- if (p->subs[b].owner) -+ if (p->subs[b].owner) - ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd); - wakeup_sub(p, a, NULL); - wakeup_sub(p, b, NULL); -@@ -1148,21 +2187,21 @@ - chan_pvt->subs[sub_num].dfd = -1; - } - --#ifdef HAVE_PRI -+#if defined(HAVE_PRI) - static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num) - { - dahdi_close(pri->fds[fd_num]); - pri->fds[fd_num] = -1; - } --#endif -+#endif /* defined(HAVE_PRI) */ - --#ifdef HAVE_SS7 -+#if defined(HAVE_SS7) - static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num) - { - dahdi_close(ss7->fds[fd_num]); - ss7->fds[fd_num] = -1; - } --#endif -+#endif /* defined(HAVE_SS7) */ - - static int dahdi_setlinear(int dfd, int linear) - { -@@ -1198,7 +2237,7 @@ - if (res < 0) { - ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno)); - } -- } else -+ } else - ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno)); - - if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) { -@@ -1249,7 +2288,7 @@ - struct dahdi_pvt *pvt; - int idx; - int dtmf = -1; -- -+ - pvt = chan->tech_pvt; - - ast_mutex_lock(&pvt->lock); -@@ -1260,7 +2299,7 @@ - goto out; - - #ifdef HAVE_PRI -- if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP)) -+ if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP)) - && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) { - if (pvt->setup_ack) { - if (!pri_grab(pvt, pvt->pri)) { -@@ -1312,11 +2351,11 @@ - int res = 0; - int idx; - int x; -- -+ - pvt = chan->tech_pvt; - - ast_mutex_lock(&pvt->lock); -- -+ - idx = dahdi_get_index(chan, pvt, 0); - - if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse) -@@ -1480,7 +2519,7 @@ - /* If the conference already exists, and we're already in it - don't bother doing anything */ - struct dahdi_confinfo zi; -- -+ - memset(&zi, 0, sizeof(zi)); - zi.chan = 0; - -@@ -1515,7 +2554,7 @@ - - static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c) - { -- /* If they're listening to our channel, they're ours */ -+ /* If they're listening to our channel, they're ours */ - if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON)) - return 1; - /* If they're a talker on our (allocated) conference, they're ours */ -@@ -1566,7 +2605,7 @@ - for (x = 0; x < MAX_SLAVES; x++) { - if (p->slaves[x]) { - if (slave) { -- /* Whoops already have a slave! No -+ /* Whoops already have a slave! No - slave native and stop right away */ - slave = NULL; - useslavenative = 0; -@@ -1681,7 +2720,7 @@ - ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n", p->channel, strerror(errno)); - } - res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel); -- if (res) { -+ if (res) { - ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno)); - } else { - p->echocanon = 1; -@@ -1695,7 +2734,7 @@ - { - int x; - int res; -- -+ - if (p && p->echocanon && p->echotraining) { - x = p->echotraining; - res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x); -@@ -2087,22 +3126,214 @@ - } - p->cidpos = 0; - send_callerid(p); -- -+ - return 0; - } - --#ifdef HAVE_SS7 -+#if defined(HAVE_SS7) - static unsigned char cid_pres2ss7pres(int cid_pres) - { - return (cid_pres >> 5) & 0x03; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static unsigned char cid_pres2ss7screen(int cid_pres) - { - return cid_pres & 0x03; - } --#endif -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_PRI) -+static enum AST_REDIRECTING_REASON pri_to_ast_reason(int pri_reason) -+{ -+ enum AST_REDIRECTING_REASON ast_reason; -+ -+ switch (pri_reason) { -+ case PRI_REDIR_FORWARD_ON_BUSY: -+ ast_reason = AST_REDIRECTING_REASON_USER_BUSY; -+ break; -+ case PRI_REDIR_FORWARD_ON_NO_REPLY: -+ ast_reason = AST_REDIRECTING_REASON_NO_ANSWER; -+ break; -+ case PRI_REDIR_DEFLECTION: -+ ast_reason = AST_REDIRECTING_REASON_DEFLECTION; -+ break; -+ case PRI_REDIR_UNCONDITIONAL: -+ ast_reason = AST_REDIRECTING_REASON_UNCONDITIONAL; -+ break; -+ case PRI_REDIR_UNKNOWN: -+ default: -+ ast_reason = AST_REDIRECTING_REASON_UNKNOWN; -+ break; -+ } /* end switch */ -+ -+ return ast_reason; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static int ast_to_pri_reason(enum AST_REDIRECTING_REASON ast_reason) -+{ -+ int pri_reason; -+ -+ switch (ast_reason) { -+ case AST_REDIRECTING_REASON_USER_BUSY: -+ pri_reason = PRI_REDIR_FORWARD_ON_BUSY; -+ break; -+ case AST_REDIRECTING_REASON_NO_ANSWER: -+ pri_reason = PRI_REDIR_FORWARD_ON_NO_REPLY; -+ break; -+ case AST_REDIRECTING_REASON_UNCONDITIONAL: -+ pri_reason = PRI_REDIR_UNCONDITIONAL; -+ break; -+ case AST_REDIRECTING_REASON_DEFLECTION: -+ pri_reason = PRI_REDIR_DEFLECTION; -+ break; -+ case AST_REDIRECTING_REASON_UNKNOWN: -+ default: -+ pri_reason = PRI_REDIR_UNKNOWN; -+ break; -+ } /* end switch */ -+ -+ return pri_reason; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static int pri_to_ast_presentation(int pri_presentation) -+{ -+ int ast_presentation; -+ -+ switch (pri_presentation) { -+ case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: -+ ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; -+ break; -+ case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: -+ ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; -+ break; -+ case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: -+ ast_presentation = AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN; -+ break; -+ case PRES_ALLOWED_NETWORK_NUMBER: -+ ast_presentation = AST_PRES_ALLOWED_NETWORK_NUMBER; -+ break; -+ case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: -+ ast_presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; -+ break; -+ case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: -+ ast_presentation = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; -+ break; -+ case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: -+ ast_presentation = AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN; -+ break; -+ case PRES_PROHIB_NETWORK_NUMBER: -+ ast_presentation = AST_PRES_PROHIB_NETWORK_NUMBER; -+ break; -+ case PRES_NUMBER_NOT_AVAILABLE: -+ ast_presentation = AST_PRES_NUMBER_NOT_AVAILABLE; -+ break; -+ default: -+ ast_presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; /* ?? */ -+ break; -+ } /* end switch */ -+ -+ return ast_presentation; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static int ast_to_pri_presentation(int ast_presentation) -+{ -+ int pri_presentation; -+ -+ switch (ast_presentation) { -+ case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: -+ pri_presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; -+ break; -+ case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: -+ pri_presentation = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; -+ break; -+ case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: -+ pri_presentation = PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN; -+ break; -+ case AST_PRES_ALLOWED_NETWORK_NUMBER: -+ pri_presentation = PRES_ALLOWED_NETWORK_NUMBER; -+ break; -+ case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: -+ pri_presentation = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; -+ break; -+ case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: -+ pri_presentation = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; -+ break; -+ case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: -+ pri_presentation = PRES_PROHIB_USER_NUMBER_FAILED_SCREEN; -+ break; -+ case AST_PRES_PROHIB_NETWORK_NUMBER: -+ pri_presentation = PRES_PROHIB_NETWORK_NUMBER; -+ break; -+ case AST_PRES_NUMBER_NOT_AVAILABLE: -+ pri_presentation = PRES_NUMBER_NOT_AVAILABLE; -+ break; -+ default: -+ pri_presentation = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; /* ?? */ -+ break; -+ } /* end switch */ -+ -+ return pri_presentation; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static enum AST_CONNECTED_LINE_UPDATE_SOURCE pri_to_ast_connected_line_update_source(enum PRI_CONNECTED_LINE_UPDATE_SOURCE pri_source) -+{ -+ enum AST_CONNECTED_LINE_UPDATE_SOURCE ast_source; -+ -+ switch (pri_source) { -+ case PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER: -+ ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ break; -+ case PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER: -+ ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ break; -+ case PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING: -+ ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING; -+ break; -+ case PRI_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN: -+ default: -+ ast_source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN; -+ break; -+ } /* end switch */ -+ -+ return ast_source; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static enum PRI_CONNECTED_LINE_UPDATE_SOURCE ast_to_pri_connected_line_update_source(enum AST_CONNECTED_LINE_UPDATE_SOURCE ast_source) -+{ -+ enum PRI_CONNECTED_LINE_UPDATE_SOURCE pri_source; -+ -+ switch (ast_source) { -+ case AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER: -+ pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ break; -+ case AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER: -+ pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ break; -+ case AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING: -+ pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING; -+ break; -+ case AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN: -+ default: -+ pri_source = PRI_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN; -+ break; -+ } /* end switch */ -+ -+ return pri_source; -+} -+#endif /* defined(HAVE_PRI) */ -+ - static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) - { - struct dahdi_pvt *p = ast->tech_pvt; -@@ -2125,11 +3356,12 @@ - ast_mutex_unlock(&p->lock); - return -1; - } -+ p->waitingfordt.tv_sec = 0; - p->dialednone = 0; - if ((p->radio || (p->oprmode < 0))) /* if a radio channel, up immediately */ - { - /* Special pseudo -- automatically up */ -- ast_setstate(ast, AST_STATE_UP); -+ ast_setstate(ast, AST_STATE_UP); - ast_mutex_unlock(&p->lock); - return 0; - } -@@ -2151,7 +3383,7 @@ - case SIG_FXOKS: - if (p->owner == ast) { - /* Normal ring, on hook */ -- -+ - /* Don't send audio while on hook, until the call is answered */ - p->dialing = 1; - if (p->use_callerid) { -@@ -2162,7 +3394,7 @@ - } - p->callwaitcas = 0; - if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) { -- p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p)); -+ p->cidlen = ast_callerid_generate(p->cidspill, ast->connected.id.name, ast->connected.id.number, AST_LAW(p)); - p->cidpos = 0; - send_callerid(p); - } -@@ -2203,12 +3435,12 @@ - } else { - /* Call waiting call */ - p->callwaitrings = 0; -- if (ast->cid.cid_num) -- ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num)); -+ if (ast->connected.id.number) -+ ast_copy_string(p->callwait_num, ast->connected.id.number, sizeof(p->callwait_num)); - else - p->callwait_num[0] = '\0'; -- if (ast->cid.cid_name) -- ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name)); -+ if (ast->connected.id.name) -+ ast_copy_string(p->callwait_name, ast->connected.id.name, sizeof(p->callwait_name)); - else - p->callwait_name[0] = '\0'; - /* Call waiting tone instead */ -@@ -2219,10 +3451,9 @@ - /* Make ring-back */ - if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE)) - ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name); -- - } -- n = ast->cid.cid_name; -- l = ast->cid.cid_num; -+ n = ast->connected.id.name; -+ l = ast->connected.id.number; - if (l) - ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num)); - else -@@ -2288,15 +3519,15 @@ - - switch (mysig) { - case SIG_FEATD: -- l = ast->cid.cid_num; -- if (l) -+ l = ast->connected.id.number; -+ if (l) - snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c); - else - snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c); - break; - case SIG_FEATDMF: -- l = ast->cid.cid_num; -- if (l) -+ l = ast->connected.id.number; -+ if (l) - snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c); - else - snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c); -@@ -2348,6 +3579,20 @@ - p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0'; - } else - p->echobreak = 0; -+ -+ /* waitfordialtone ? */ -+#ifdef HAVE_PRI -+ if (!p->pri) { -+#endif -+ if( p->waitfordialtone && CANPROGRESSDETECT(p) && p->dsp ) { -+ ast_log(LOG_DEBUG, "Defer dialling for %dms or dialtone\n", p->waitfordialtone); -+ gettimeofday(&p->waitingfordt,NULL); -+ ast_setstate(ast, AST_STATE_OFFHOOK); -+ break; -+ } -+#ifdef HAVE_PRI -+ } -+#endif - if (!res) { - if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) { - int saveerr = errno; -@@ -2369,7 +3614,7 @@ - case 0: - /* Special pseudo -- automatically up*/ - ast_setstate(ast, AST_STATE_UP); -- break; -+ break; - case SIG_PRI: - case SIG_BRI: - case SIG_BRI_PTMP: -@@ -2382,7 +3627,8 @@ - ast_mutex_unlock(&p->lock); - return -1; - } --#ifdef HAVE_SS7 -+ -+#if defined(HAVE_SS7) - if (p->ss7) { - char ss7_called_nai; - int called_nai_strip; -@@ -2402,13 +3648,19 @@ - const char *send_far = NULL; - - c = strchr(dest, '/'); -- if (c) -+ if (c) { - c++; -- else -- c = dest; -+ } else { -+ c = ""; -+ } -+ if (strlen(c) < p->stripmsd) { -+ ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd); -+ ast_mutex_unlock(&p->lock); -+ return -1; -+ } - - if (!p->hidecallerid) { -- l = ast->cid.cid_num; -+ l = ast->connected.id.number; - } else { - l = NULL; - } -@@ -2457,10 +3709,10 @@ - } - } - isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai, -- p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED), -- p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED ); -+ p->use_callingpres ? cid_pres2ss7pres(ast->connected.id.number_presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED), -+ p->use_callingpres ? cid_pres2ss7screen(ast->connected.id.number_presentation) : SS7_SCREENING_USER_PROVIDED ); - -- isup_set_oli(p->ss7call, ast->cid.cid_ani2); -+ isup_set_oli(p->ss7call, ast->connected.ani2); - isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc); - - ast_channel_lock(ast); -@@ -2468,17 +3720,17 @@ - charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER"); - if (charge_str) - isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10); -- -+ - gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS"); - if (gen_address) - isup_set_gen_address(p->ss7call, gen_address, p->gen_add_nai,p->gen_add_pres_ind, p->gen_add_num_plan,p->gen_add_type); /* need to add some types here for NAI,PRES,TYPE */ -- -+ - gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS"); - gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE"); - gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME"); - if (gen_digits) -- isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme)); -- -+ isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme)); -+ - gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME"); - if (gen_name) - isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED); -@@ -2486,37 +3738,43 @@ - jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP"); - if (jip_digits) - isup_set_jip_digits(p->ss7call, jip_digits); -- -+ - lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT"); - if (lspi_ident) -- isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00); -- -+ isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00); -+ - rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON"); - if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) { - isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00); /* Setting for Nortel DMS-250/500 */ - } -- -+ - call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT"); - call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC"); - if (call_ref_id && call_ref_pc) { - isup_set_callref(p->ss7call, atoi(call_ref_id), - call_ref_pc ? atoi(call_ref_pc) : 0); - } -- -+ - send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR"); - if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 )) - (isup_far(p->ss7->ss7, p->ss7call)); -- -+ - ast_channel_unlock(ast); - - isup_iam(p->ss7->ss7, p->ss7call); - ast_setstate(ast, AST_STATE_DIALING); - ss7_rel(p->ss7); - } --#endif /* HAVE_SS7 */ --#ifdef HAVE_PRI -+#endif /* defined(HAVE_SS7) */ -+ -+#if defined(HAVE_PRI) - if (p->pri) { - struct pri_sr *sr; -+ struct ast_channel *peer; -+ struct ccbsnr_link *cclink; -+ unsigned int state = 0; -+ char *callingnum; -+ char *callernum; - #ifdef SUPPORT_USERUSER - const char *useruser; - #endif -@@ -2525,22 +3783,20 @@ - int prilocaldialplan; - int ldp_strip; - int exclusive; -- const char *rr_str; -- int redirect_reason; - - c = strchr(dest, '/'); -- if (c) -+ if (c) { - c++; -- else -- c = dest; -+ } else { -+ c = ""; -+ } - - l = NULL; - n = NULL; -- - if (!p->hidecallerid) { -- l = ast->cid.cid_num; -+ l = ast->connected.id.number; - if (!p->hidecalleridname) { -- n = ast->cid.cid_name; -+ n = ast->connected.id.name; - } - } - -@@ -2598,15 +3854,16 @@ - else - exclusive = 1; - } -- -+ - 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 == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW))); -+ pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability, -+ (p->digital ? -1 : -+ ((p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW))); - if (p->pri->facilityenable) - pri_facility_enable(p->pri->pri); - - ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability)); -+ - dp_strip = 0; - pridialplan = p->pri->dialplan - 1; - if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */ -@@ -2669,8 +3926,11 @@ - pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0); - break; - default: -- if (isalpha(*c)) -- ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c); -+ if (isalpha(c[p->stripmsd])) { -+ ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n", -+ c[p->stripmsd] > 'Z' ? "NPI" : "TON", c[p->stripmsd]); -+ } -+ break; - } - c++; - } -@@ -2739,39 +3999,87 @@ - prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0); - break; - default: -- if (isalpha(*l)) -- ast_log(LOG_WARNING, "Unrecognized prilocaldialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c); -+ if (isalpha(*l)) { -+ ast_log(LOG_WARNING, -+ "Unrecognized prilocaldialplan %s modifier: %c\n", -+ *l > 'Z' ? "NPI" : "TON", *l); -+ } -+ break; - } - l++; - } - } - pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan, -- p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE)); -- if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) { -- if (!strcasecmp(rr_str, "UNKNOWN")) -- redirect_reason = 0; -- else if (!strcasecmp(rr_str, "BUSY")) -- redirect_reason = 1; -- else if (!strcasecmp(rr_str, "NO_REPLY")) -- redirect_reason = 2; -- else if (!strcasecmp(rr_str, "UNCONDITIONAL")) -- redirect_reason = 15; -- else -- redirect_reason = PRI_REDIR_UNCONDITIONAL; -- } else -- redirect_reason = PRI_REDIR_UNCONDITIONAL; -- pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason); -+ p->use_callingpres ? ast->connected.id.number_presentation : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE)); -+ pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, ast->redirecting.from.number_type, -+ ast->redirecting.from.number_presentation, -+ ast_to_pri_reason(ast->redirecting.reason)); -+ pri_sr_set_redirecting_name(sr, ast->redirecting.from.name); - - #ifdef SUPPORT_USERUSER - /* User-user info */ - useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO"); -- - if (useruser) - pri_sr_set_useruser(sr, useruser); - #endif -+ callingnum = c + p->stripmsd + dp_strip; -+ callernum = l ? (l + ldp_strip) : NULL; - -+ /* search ccbs-list */ -+ cclink = ccbsnr_get_link_by_number(callingnum, callernum, &state); -+ -+ if (p->ccringout) { -+ if (cclink) { -+ pri_sr_set_ccringout(sr, p->ccringout); -+ } else { -+ ast_verb(3, -+ "DAHDI-Call: ccbsnr-link found. state(%d). Change to Dial without CC-Ringout\n", -+ state); -+ p->ccringout = 0; -+ } -+ } else { -+ /* Normal Call */ -+ if (cclink) { -+ int span = CCBS_SPAN(cclink->handle); -+ struct dahdi_pri *ccbs_pri; -+ -+ switch (state) { -+ case CC_WAIT_ACK: -+ case CC_WAIT_USER_A_ANSWER_N: -+ case CC_INVOKED_A_RET: -+ ast_verb(4, -+ "DAHDI-Call: CCBS-List-Obj 0x%p: handle %x span(%d) peer=%p\n", -+ cclink, cclink->handle, span, cclink->peer); -+ -+ if (cclink->call) { -+ pri_call_set_cc_operation(cclink->call, PRI_CC_CANCEL); -+ -+ ccbs_pri = &pris[span - 1]; -+ if (ccbs_pri != p->pri) { -+ if (pri_nochannel_grab(ccbs_pri)) { -+ ast_log(LOG_WARNING, "Failed to grab PRI!\n"); -+ return -1; -+ } -+ -+ pri_hangup(ccbs_pri->pri, cclink->call, -1); -+ -+ pri_rel(ccbs_pri); -+ } else { -+ pri_hangup(p->pri->pri, cclink->call, -1); -+ } -+ } -+ cclink->call = NULL; -+ ccbsnr_del_link(cclink->handle); -+ break; -+ default: -+ ast_verb(3, "DAHDI-Call:wrong ccbsnr-link-state '%d'\n", state); -+ break; -+ } -+ } -+ } -+ - if (pri_setup(p->pri->pri, p->call, sr)) { -- ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", -+ ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", - c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan)); - pri_rel(p->pri); - ast_mutex_unlock(&p->lock); -@@ -2781,8 +4089,20 @@ - pri_sr_free(sr); - ast_setstate(ast, AST_STATE_DIALING); - pri_rel(p->pri); -+ peer = cc_get_peer_link_id(pbx_builtin_getvar_helper(ast, "CCPEERLINKID")); -+ if (peer) { -+ char tmp[32]; -+ -+ pbx_builtin_setvar_helper(peer, "CCPEERLINKID", "0"); -+ -+ ast_verb(3, "DAHDI peer link is %p %s.\n", peer, peer->name); -+ -+ snprintf(tmp, sizeof(tmp) - 1, "%d", p->pri->span); -+ pbx_builtin_setvar_helper(peer, "CCBSNRONPRISPAN", tmp); -+ } - } --#endif -+#endif /* defined(HAVE_PRI) */ -+ - ast_mutex_unlock(&p->lock); - return 0; - } -@@ -2881,7 +4201,7 @@ - /* Free associated memory */ - if (pl) - destroy_dahdi_pvt(&pl); -- if (option_verbose > 2) -+ if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x); - } - iflist = NULL; -@@ -2889,15 +4209,522 @@ - ast_mutex_unlock(&iflock); - } - --#ifdef HAVE_PRI --static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility"; -+#if defined(HAVE_PRI) -+static char *dahdi_qsig_ccbsnr_initialize_app = "DAHDIQsigCcbsnrInitialize"; - --static char *dahdi_send_keypad_facility_synopsis = "Send digits out of band over a PRI"; -+/* -+ * store the peer for future actions -+ */ -+static int dahdi_qsig_ccbsnr_initialize_exec(struct ast_channel *ast, void *param) -+{ -+ char buffer[32]; -+ int id; - --static char *dahdi_send_keypad_facility_descrip = --" DAHDISendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n" --" IE over the current channel.\n"; -+ id = cc_add_peer_link_id(ast); - -+ if (id >= 0) { -+ snprintf(buffer, sizeof(buffer) - 1, "%d", id); -+ pbx_builtin_setvar_helper(ast, "_CCPEERLINKID", buffer); -+ pbx_builtin_setvar_helper(ast, "_CCBSNRREQSTATE", "AVAILABLE"); -+ pbx_builtin_setvar_helper(ast, "_CCBSNRONPRISPAN", "0"); -+ } -+ -+ ast_verb(3, "Added %s as DAHDI peer link.\n", ast->name); -+ -+ return 0; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static char *dahdi_qsic_check_ccbsnr_app = "DAHDIQsigCheckCcbsnr"; -+ -+static int dahdi_qsig_check_ccbsnr_exec(struct ast_channel *ast, void *param) -+{ -+#define CC_MAX_NOCHANNELS 256 -+#define MAX_DISSALOWED 4 -+ -+ char *data = (char *) param; -+ char *parse, *tok, *tokb; -+ int maxcount = 0; -+ char *dissalowed_callernum[MAX_DISSALOWED] = {NULL, NULL, NULL, NULL}; -+ char *maxcounter = NULL; -+ char *callingnum = NULL; -+ char *callernum = NULL; -+ int count = 0; -+ int flag = 0; -+ char *c; -+ int cnt; -+ -+ if (ast_strlen_zero(param)) { -+ ast_debug(1, "Check command requires arguments!\n"); -+ return -1; -+ } -+ -+ parse = ast_strdupa(data); -+ tok = strtok_r(parse, "|", &tokb); -+ if (!tok) { -+ ast_log(LOG_WARNING, "DAHDIQsigCheckCcbsnr requires at least maxcounter argument\n"); -+ return -1; -+ } -+ maxcounter = tok; -+ if (*tokb != '|') { -+ tok = strtok_r(NULL, "|", &tokb); -+ if (!tok) { -+ ast_log(LOG_WARNING, "DAHDIQsigCheckCcbsnr without callingnum argument\n"); -+ return -1; -+ } -+ callingnum = tok; -+ } else { -+ callingnum = ""; -+ tokb++; -+ } -+ -+ if (*tokb != '|') { -+ tok = strtok_r(NULL, "|", &tokb); -+ if (!tok) { -+ ast_log(LOG_NOTICE, "DAHDIQsigCheckCcbsnr without callernum argument\n"); -+ return -1; -+ } -+ callernum = tok; -+ } else { -+ callernum = ""; -+ tokb++; -+ } -+ -+ -+ /* Optional args 'dissalowed_callernum'*/ -+ for (cnt = 0; cnt < MAX_DISSALOWED; cnt++) { -+ tok = strtok_r(NULL, "|", &tokb); -+ if (!tok) { -+ ast_verb(3, "DAHDIQsigCheckCcbsnr without dissalowed-callernum argument\n"); -+ } else { -+ dissalowed_callernum[cnt] = tok; -+ } -+ } -+ -+ ast_verb(3, "DAHDI ccbsnr: '%s' '%s' '%s'\n", maxcounter, callingnum, callernum); -+ for (cnt = 0; cnt < MAX_DISSALOWED; cnt++) { -+ if (dissalowed_callernum[cnt]) { -+ ast_verb(3, "DAHDI ccbsnr: '%s'\n", dissalowed_callernum[cnt]); -+ } -+ } -+ -+ maxcount = (int)strtol(maxcounter, NULL, 0); -+ if (maxcount > CC_MAX_NOCHANNELS) { -+ ast_debug(1, "DAHDIQsigCheckCcbsnr range:(%d - %d)\n", 0, CC_MAX_NOCHANNELS); -+ return -1; -+ } else if (!maxcount) { -+ maxcount = CC_MAX_NOCHANNELS; -+ } -+ -+ if (ast_strlen_zero(callernum)) { -+ flag = 1; -+ ast_verb(3, "DAHDIQsigCheckCcbsnr: no caller number - |\n"); -+ } else if (ast_strlen_zero(callingnum)) { -+ flag = 1; -+ ast_verb(3, "DAHDIQsigCheckCcbsnr: no caller number - |\n"); -+ } else if (!strcmp(callernum, callingnum)) { -+ flag = 1; -+ ast_verb(3, -+ "DAHDIQsigCheckCcbsnr: caller number(%s) and calling number are equal\n", -+ callernum); -+ } else { -+ for (c = callernum; *c; c++) -+ *c = tolower(*c); -+ for (cnt = 0; cnt < MAX_DISSALOWED; cnt++) { -+ if (dissalowed_callernum[cnt]) { -+ if (!strcmp(callernum, dissalowed_callernum[cnt])) { -+ flag = 1; -+ ast_verb(4, "DAHDIQsigCheckCcbsnr: dissalowed_callernum - %s\n", -+ dissalowed_callernum[cnt]); -+ break; -+ } -+ } -+ } -+ count = ccbsnr_count_callingnum(callingnum); -+ ast_verb(4, "DAHDIQsigCheckCcbsnr: maxcount(%d) count(%d)\n", maxcount, count); -+ if (count >= maxcount) { -+ flag = 1; -+ ast_verb(3, "DAHDIQsigCheckCcbsnr: count(%d) |\n", -+ count); -+ } -+ } -+ -+ if (flag) { -+ ast_verb(3, "Set CCBSNRREQSTATE to NOTAVAILABLE\n"); -+ pbx_builtin_setvar_helper(ast, "CCBSNRREQSTATE", "NOTAVAILABLE"); -+ } -+ -+ return 0; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static char *dahdi_qsic_clear_nochannel_app = "DAHDIQsigClearNoChannel"; -+ -+static int dahdi_qsig_clear_nochannel_exec(struct ast_channel *ast, void *param) -+{ -+ char *callingnum, *callernum; -+ char *data = (char *) param; -+ -+ struct ccbsnr_link *cclink; -+ unsigned int state = 0; -+ struct dahdi_pri *pri; -+ unsigned int span; -+ int cr; -+ q931_call *call; -+ -+ if (ast_strlen_zero(data)) { -+ ast_debug(1, "Clear command requires arguments!\n"); -+ return -1; -+ } -+ -+ callingnum = strsep(&data, "|"); -+ callernum = data; -+ -+ if ((!callingnum) || (!callernum)) { -+ ast_debug(1, "DAHDIQsigClearNoChannel requires |\n"); -+ return -1; -+ } -+ -+ ast_verb(3, "DAHDI ccbsnr: '%s' '%s'\n", callingnum, callernum); -+ -+ cclink = ccbsnr_get_link_by_number(callingnum, callernum, &state); -+ if (cclink) { -+ ast_verb(3, "DAHDI ccbsnr: state(%d)\n", state); -+ -+ switch (state) { -+ case CC_WAIT_ACK: -+ case CC_WAIT_USER_A_ANSWER_N: -+ case CC_INVOKED_A_RET: -+ if (cclink->call) { -+ span = CCBS_SPAN(cclink->handle); -+ pri = &pris[span - 1]; -+ -+ if (pri_nochannel_grab(pri)) { -+ ast_log(LOG_WARNING, "Failed to grab PRI!\n"); -+ return -1; -+ } -+ cr = CCBS_CR(cclink->handle); -+ call = pri_find_call(pri->pri, cr); -+ -+ ast_log(LOG_NOTICE, "destroy cclink: call found(%p)\n", call); -+ -+ if (call == cclink->call) { -+ ast_log(LOG_NOTICE, "destroy call(%p) cr(%x):Q931_call found, hang it up it.\n", -+ call, cr); -+ -+ pri_call_set_cc_operation(call, PRI_CC_CANCEL); -+ pri_hangup(pri->pri, call, -1); -+ } -+ pri_rel(pri); -+ } -+ ast_mutex_lock(&ccbsnr_lock); -+ cclink->call = NULL; -+ ast_mutex_unlock(&ccbsnr_lock); -+ ccbsnr_del_link(cclink->handle); -+ break; -+ default: -+ ast_verb(2, "PRI_EVENT_HANGUP:wrong state '%d'\n", state); -+ break; -+ } -+ } else { -+ ast_verb(2, -+ "dahdi_qsig_clear_nochannel: CCBS-List-Obj for callingnum(%s) callernum(%s) not found\n", -+ callingnum, callernum); -+ return 0; -+ } -+ return 0; -+ -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static char *dahdi_qsic_ccbsnr_request_app = "DAHDIQsigCcbsnrRequest"; -+ -+static int dahdi_qsig_ccbsnr_request_exec(struct ast_channel *ast, void *param) -+{ -+ int type; -+ char *ccbsnrtype, *callingnum, *callernum, *callername, *context, *priority; -+ char *data = (char *) param; -+ -+ const char *ccbsnronprispan; -+ unsigned int prispan; -+ char *c, *l, *n; -+ char *s = NULL; -+ int dp_strip; -+ int ldp_strip; -+ struct pri_sr *sr; -+ int pridialplan; -+ int prilocaldialplan; -+ struct dahdi_pri *pri; -+ struct ccbsnr_link *cclink; -+ q931_call *call; -+ -+ /* sets for no channel call */ -+ int channel = 0; -+ int exclusive = 1; -+ int nonisdn = 0; -+ int transmode = -1; -+ int userl1 = ast->transfercapability; -+ int cref = 0; -+ -+ if (ast_strlen_zero(data)) { -+ ast_debug(1, "CCBScommand requires arguments!\n"); -+ return -1; -+ } -+ -+ ccbsnrtype = strsep(&data, "|"); -+ callingnum = strsep(&data, "|"); -+ callernum = strsep(&data, "|"); -+ callername = strsep(&data, "|"); -+ context = strsep(&data, "|"); -+ priority = data; -+ -+ if ((!ccbsnrtype) || (!callingnum) || (!callernum) || (!callername) || (!context) || (!priority)) { -+ ast_debug(1, "DAHDIQsigCcbsnrRequest requires |||||\n"); -+ return -1; -+ } -+ -+ ast_verb(3, "DAHDI ccbsnr: '%s' '%s' '%s' '%s' '%s' '%s'\n", -+ ccbsnrtype, callingnum, callernum, callername, context, priority); -+ -+ if (!strcmp(callernum, callingnum)) { -+ ast_debug(1, "DAHDIQsigCcbsnrRequest: caller number(%s) and calling number are equal\n", callernum); -+ return -1; -+ } -+ -+ if (!strcmp(ccbsnrtype, "CCBS")) -+ type = PRI_CC_CCBSREQUEST; -+ else if (!strcmp(ccbsnrtype, "CCNR")) -+ type = PRI_CC_CCNRREQUEST; -+ else { -+ ast_verb(2, "DAHDIQsigCcbsnrRequest requires |||||\n"); -+ return -1; -+ } -+ -+ ccbsnronprispan = pbx_builtin_getvar_helper(ast, "CCBSNRONPRISPAN"); -+ ast_verb(3, "DAHDI ccbsnronprispan: '%s'\n", ccbsnronprispan); -+ -+ if (ast_strlen_zero(ccbsnronprispan)) { -+ ast_debug(1, "DAHDIQsigCcbsnrRequest: Use initialize befor use this funktion\n"); -+ return -1; -+ } -+ -+ prispan = (int)strtol(ccbsnronprispan, NULL, 0); -+ -+ if ((prispan < 1) || (prispan > NUM_SPANS)) { -+ ast_verb(2, "DAHDI:Invalid span %d. Should be a number %d to %d\n", prispan, -+ 1, NUM_SPANS); -+ return -1; -+ } -+ -+ pri = &pris[prispan-1]; -+ if (pri_nochannel_grab(pri)) { -+ ast_log(LOG_WARNING, "Failed to grab PRI!\n"); -+ return -1; -+ } -+ -+ if (!(call = pri_new_nochannel_call(pri->pri, &cref))) { -+ ast_log(LOG_WARNING, "Unable to create no channel call on span %d\n", prispan); -+ pri_rel(pri); -+ return -1; -+ } -+ -+ if (!(sr = pri_sr_new())) { -+ ast_log(LOG_WARNING, "Failed to allocate setup request for no channel on span %d\n", prispan); -+ pri_rel(pri); -+ } -+ pri_sr_set_no_channel_call(sr); -+ pri_sr_set_ccbsnr(sr, type); -+ -+ channel |= prispan << 8 | exclusive << 16; -+ pri_sr_set_channel(sr, channel, exclusive, nonisdn); -+ pri_sr_set_bearer(sr, transmode, userl1); -+ if (pri->facilityenable) -+ pri_facility_enable(pri->pri); -+ -+ ast_verb(4, "DAHDI:Requested transfer capability: 0x%.2x - %s\n", -+ ast->transfercapability, ast_transfercapability2str(ast->transfercapability)); -+ dp_strip = 0; -+ pridialplan = pri->dialplan - 1; -+ c = callingnum; -+ if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */ -+ if (strncmp(c, pri->internationalprefix, strlen(pri->internationalprefix)) == 0) { -+ if (pridialplan == -2) { -+ dp_strip = strlen(pri->internationalprefix); -+ } -+ pridialplan = PRI_INTERNATIONAL_ISDN; -+ } else if (strncmp(c, pri->nationalprefix, strlen(pri->nationalprefix)) == 0) { -+ if (pridialplan == -2) { -+ dp_strip = strlen(pri->nationalprefix); -+ } -+ pridialplan = PRI_NATIONAL_ISDN; -+ } else { -+ pridialplan = PRI_LOCAL_ISDN; -+ } -+ } -+ while (c[0] > '9' && c[0] != '*' && c[0] != '#') { -+ switch (c[0]) { -+ case 'U': -+ pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf); -+ break; -+ case 'I': -+ pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf); -+ break; -+ case 'N': -+ pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf); -+ break; -+ case 'L': -+ pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf); -+ break; -+ case 'S': -+ pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf); -+ break; -+ case 'V': -+ pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf); -+ break; -+ case 'R': -+ pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf); -+ break; -+ case 'u': -+ pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0); -+ break; -+ case 'e': -+ pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0); -+ break; -+ case 'x': -+ pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0); -+ break; -+ case 'f': -+ pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0); -+ break; -+ case 'n': -+ pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0); -+ break; -+ case 'p': -+ pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0); -+ break; -+ case 'r': -+ pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0); -+ break; -+ default: -+ if (isalpha(*c)) -+ ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c); -+ } -+ c++; -+ } -+ pri_sr_set_called(sr, c + dp_strip, pridialplan, s ? 1 : 0); -+ -+ l = callernum; -+ n = callername; -+ ldp_strip = 0; -+ prilocaldialplan = pri->localdialplan - 1; -+ if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */ -+ if (strncmp(l, pri->internationalprefix, strlen(pri->internationalprefix)) == 0) { -+ if (prilocaldialplan == -2) { -+ ldp_strip = strlen(pri->internationalprefix); -+ } -+ prilocaldialplan = PRI_INTERNATIONAL_ISDN; -+ } else if (strncmp(l, pri->nationalprefix, strlen(pri->nationalprefix)) == 0) { -+ if (prilocaldialplan == -2) { -+ ldp_strip = strlen(pri->nationalprefix); -+ } -+ prilocaldialplan = PRI_NATIONAL_ISDN; -+ } else { -+ prilocaldialplan = PRI_LOCAL_ISDN; -+ } -+ } -+ if (l != NULL) { -+ while (*l > '9' && *l != '*' && *l != '#') { -+ switch (*l) { -+ case 'U': -+ prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'I': -+ prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'N': -+ prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'L': -+ prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'S': -+ prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'V': -+ prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'R': -+ prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf); -+ break; -+ case 'u': -+ prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0); -+ break; -+ case 'e': -+ prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0); -+ break; -+ case 'x': -+ prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0); -+ break; -+ case 'f': -+ prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0); -+ break; -+ case 'n': -+ prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0); -+ break; -+ case 'p': -+ prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0); -+ break; -+ case 'r': -+ prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0); -+ break; -+ default: -+ if (isalpha(*l)) -+ ast_log(LOG_WARNING, "Unrecognized prilocaldialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c); -+ } -+ l++; -+ } -+ } -+ -+ pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan, -+ pri->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE)); -+ -+ cclink = ccbsnr_new_id(cref, prispan, call, type, callingnum, callernum, -+ callername, context, (int)strtol(priority, NULL, 0), ast); -+ if (!cclink) { -+ ast_log(LOG_WARNING, "Unable to allocate ccbsnr list object. Aborting!\n"); -+ pri_rel(pri); -+ pri_sr_free(sr); -+ return -1; -+ } -+ -+ if (pri_setup(pri->pri, cclink->call, sr)) { -+ unsigned int handle = CCBS_HANDLE(prispan, cref); -+ ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", -+ c + dp_strip, dialplan2str(pri->dialplan)); -+ -+ pri_hangup(pri->pri, cclink->call, -1); -+ cclink->call = NULL; -+ ccbsnr_del_link(handle); -+ pri_rel(pri); -+ pri_sr_free(sr); -+ -+ return -1; -+ } -+ -+ pri_sr_free(sr); -+ ast_setstate(ast, AST_STATE_DIALING); -+ pri_rel(pri); -+ -+ return 0; -+} -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) -+static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility"; -+ - static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data) - { - /* Data will be our digit string */ -@@ -2937,7 +4764,85 @@ - - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) -+#if defined(HAVE_PRI_PROG_W_CAUSE) -+static char *dahdi_send_callrerouting_facility_app = "DAHDISendCallreroutingFacility"; -+ -+static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, void *data) -+{ -+ /* Data will be our digit string */ -+ struct dahdi_pvt *p; -+ char *parse; -+ int res = -1; -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(destination); -+ AST_APP_ARG(original); -+ AST_APP_ARG(reason); -+ ); -+ -+ if (ast_strlen_zero(data)) { -+ ast_log(LOG_DEBUG, "No data sent to application!\n"); -+ return -1; -+ } -+ -+ p = (struct dahdi_pvt *)chan->tech_pvt; -+ -+ if (!p) { -+ ast_log(LOG_DEBUG, "Unable to find technology private\n"); -+ return -1; -+ } -+ -+ parse = ast_strdupa(data); -+ AST_STANDARD_APP_ARGS(args, parse); -+ -+ if (ast_strlen_zero(args.destination)) { -+ ast_log(LOG_WARNING, "callrerouting facility requires at least destination number argument\n"); -+ return -1; -+ } -+ -+ if (ast_strlen_zero(args.original)) { -+ ast_log(LOG_WARNING, "Callrerouting Facility without original called number argument\n"); -+ args.original = NULL; -+ } -+ -+ if (ast_strlen_zero(args.reason)) { -+ ast_log(LOG_NOTICE, "Callrerouting Facility without diversion reason argument, defaulting to unknown\n"); -+ args.reason = NULL; -+ } -+ -+ ast_mutex_lock(&p->lock); -+ -+ if (!p->pri || !p->call) { -+ ast_log(LOG_DEBUG, "Unable to find pri or call on channel!\n"); -+ ast_mutex_unlock(&p->lock); -+ return -1; -+ } -+ -+ switch (p->sig) { -+ case SIG_PRI: -+ if (!pri_grab(p, p->pri)) { -+ if (chan->_state == AST_STATE_RING) { -+ res = pri_callrerouting_facility(p->pri->pri, p->call, args.destination, args.original, args.reason); -+ } -+ pri_rel(p->pri); -+ } else { -+ ast_log(LOG_DEBUG, "Unable to grab pri to send callrerouting facility on span %d!\n", p->span); -+ ast_mutex_unlock(&p->lock); -+ return -1; -+ } -+ break; -+ } -+ -+ ast_mutex_unlock(&p->lock); -+ -+ return res; -+} -+#endif /* defined(HAVE_PRI_PROG_W_CAUSE) */ -+#endif /* defined(HAVE_PRI) */ -+ -+#if defined(HAVE_PRI) - static int pri_is_up(struct dahdi_pri *pri) - { - int x; -@@ -2947,7 +4852,9 @@ - } - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_assign_bearer(struct dahdi_pvt *crv, struct dahdi_pri *pri, struct dahdi_pvt *bearer) - { - bearer->owner = &inuse; -@@ -2960,7 +4867,9 @@ - crv->pri = pri; - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *pri_order(int level) - { - switch (level) { -@@ -2974,9 +4883,11 @@ - return "Quaternary"; - default: - return ""; -- } -+ } - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - /* Returns fd of the active dchan */ - static int pri_active_dchan_fd(struct dahdi_pri *pri) - { -@@ -2989,7 +4900,9 @@ - - return pri->fds[x]; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_find_dchan(struct dahdi_pri *pri) - { - int oldslot = -1; -@@ -3006,8 +4919,11 @@ - } - if (newslot < 0) { - newslot = 0; -- ast_log(LOG_WARNING, "No D-channels available! Using Primary channel %d as D-channel anyway!\n", -- pri->dchannels[newslot]); -+ /* This is annoying to see on non persistent layer 2 connections. Let's not complain in that case */ -+ if (pri->sig != SIG_BRI_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", -@@ -3015,7 +4931,7 @@ - pri->pri = pri->dchans[newslot]; - return 0; - } --#endif -+#endif /* defined(HAVE_PRI) */ - - static int dahdi_hangup(struct ast_channel *ast) - { -@@ -3032,9 +4948,24 @@ - ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); - return 0; - } -- -+ - ast_mutex_lock(&p->lock); -- -+ -+#ifdef HAVE_PRI -+ if (p->dummychannel == 1) { -+ ast_verb(3, "Hangup: dummy-channel(%s)\n", ast->name); -+ ast_verb(3, "Hangup:tech_pvt=%p q931_call=%p\n", p, p->call); -+ -+ ast->tech_pvt = NULL; -+ ast_mutex_unlock(&p->lock); -+ ast_module_unref(ast_module_info->self); -+ ast_mutex_destroy(&p->lock); -+ ast_free(p); -+ return 0; -+ } -+ p->ccringout = 0; -+#endif -+ - idx = dahdi_get_index(ast, p, 1); - - if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) { -@@ -3050,21 +4981,20 @@ - ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num)); - ast_free(p->origcid_num); - p->origcid_num = NULL; -- } -+ } - if (p->origcid_name) { - ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name)); - ast_free(p->origcid_name); - p->origcid_name = NULL; -- } -+ } - if (p->dsp) - ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); -- if (p->exten) -- p->exten[0] = '\0'; -+ p->exten[0] = '\0'; - - ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n", - p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd); - p->ignoredtmf = 0; -- -+ - if (idx > -1) { - /* Real channel, do some fixup */ - p->subs[idx].owner = NULL; -@@ -3134,7 +5064,7 @@ - /* This is actually part of a three way, placed on hold. Place the third part - on music on hold now */ - if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) { -- ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD, -+ ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD, - S_OR(p->mohsuggest, NULL), - !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0); - } -@@ -3149,7 +5079,7 @@ - /* The other party of the three way call is currently in a call-wait state. - Start music on hold for them, and take the main guy out of the third call */ - if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) { -- ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD, -+ ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD, - S_OR(p->mohsuggest, NULL), - !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0); - } -@@ -3182,15 +5112,31 @@ - p->alerting = 0; - p->setup_ack = 0; - p->rlt = 0; --#endif -+#endif - if (p->dsp) { - ast_dsp_free(p->dsp); - p->dsp = NULL; - } - -+ if (p->faxbuffersinuse) { -+ /* faxbuffers are in use, revert them */ -+ struct dahdi_bufferinfo bi = { -+ .txbufpolicy = p->buf_policy, -+ .rxbufpolicy = p->buf_policy, -+ .bufsize = p->bufsize, -+ .numbufs = p->buf_no -+ }; -+ int bpres; -+ -+ if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) { -+ ast_log(LOG_WARNING, "Channel '%s' unable to revert faxbuffer policy: %s\n", ast->name, strerror(errno)); -+ } -+ p->faxbuffersinuse = 0; -+ } -+ - law = DAHDI_LAW_DEFAULT; - res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law); -- if (res < 0) -+ if (res < 0) - ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno)); - /* Perform low level hangup if no owner left */ - #ifdef HAVE_SS7 -@@ -3235,7 +5181,7 @@ - - pri_hangup(p->pri->pri, p->call, -1); - p->call = NULL; -- if (p->bearer) -+ if (p->bearer) - p->bearer->call = NULL; - } else { - const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE"); -@@ -3255,9 +5201,9 @@ - } - pri_hangup(p->pri->pri, p->call, icause); - } -- if (res < 0) -+ if (res < 0) - ast_log(LOG_WARNING, "pri_disconnect failed\n"); -- pri_rel(p->pri); -+ pri_rel(p->pri); - } else { - ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); - res = -1; -@@ -3289,6 +5235,7 @@ - tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION); - else - tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1); -+ p->fxsoffhookstate = par.rxisoffhook; - } - break; - case SIG_FXSGS: -@@ -3316,6 +5263,7 @@ - p->callwaitcas = 0; - p->callwaiting = p->permcallwaiting; - p->hidecallerid = p->permhidecallerid; -+ p->waitingfordt.tv_sec = 0; - p->dialing = 0; - p->rdnis[0] = '\0'; - update_conf(p); -@@ -3481,8 +5429,8 @@ - int idx; - struct dahdi_pvt *p = chan->tech_pvt, *pp; - struct oprmode *oprmode; -- - -+ - /* all supported options require data */ - if (!data || (datalen < 1)) { - errno = EINVAL; -@@ -3543,7 +5491,8 @@ - dahdi_disable_ec(p); - /* otherwise, turn it on */ - if (!p->didtdd) { /* if havent done it yet */ -- unsigned char mybuf[41000], *buf; -+ unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */ -+ unsigned char *buf; - int size, res, fd, len; - struct pollfd fds[1]; - -@@ -3587,7 +5536,7 @@ - len -= size; - buf += size; - } -- p->didtdd = 1; /* set to have done it now */ -+ p->didtdd = 1; /* set to have done it now */ - } - if (*cp == 2) { /* Mate mode */ - if (p->tdd) -@@ -3595,10 +5544,10 @@ - p->tdd = 0; - p->mate = 1; - break; -- } -+ } - if (!p->tdd) { /* if we dont have one yet */ - p->tdd = tdd_new(); /* allocate one */ -- } -+ } - break; - case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */ - if (!p->dsp) -@@ -3610,11 +5559,11 @@ - break; - case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */ - cp = (char *) data; -- if (!*cp) { -+ if (!*cp) { - ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name); - x = 0; - dahdi_disable_ec(p); -- } else { -+ } else { - ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name); - x = 1; - } -@@ -3623,13 +5572,20 @@ - break; - case AST_OPTION_OPRMODE: /* Operator services mode */ - oprmode = (struct oprmode *) data; -+ /* We don't support operator mode across technologies */ -+ if (strcasecmp(chan->tech->type, oprmode->peer->tech->type)) { -+ ast_log(LOG_NOTICE, "Operator mode not supported on %s to %s calls.\n", -+ chan->tech->type, oprmode->peer->tech->type); -+ errno = EINVAL; -+ return -1; -+ } - pp = oprmode->peer->tech_pvt; - p->oprmode = pp->oprmode = 0; - /* setup peers */ - p->oprpeer = pp; - pp->oprpeer = p; - /* setup modes, if any */ -- if (oprmode->mode) -+ if (oprmode->mode) - { - pp->oprmode = oprmode->mode; - p->oprmode = -oprmode->mode; -@@ -3656,15 +5612,15 @@ - static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) - { - struct dahdi_pvt *p = chan->tech_pvt; -- -+ - if (!strcasecmp(data, "rxgain")) { - ast_mutex_lock(&p->lock); - snprintf(buf, len, "%f", p->rxgain); -- ast_mutex_unlock(&p->lock); -+ ast_mutex_unlock(&p->lock); - } else if (!strcasecmp(data, "txgain")) { - ast_mutex_lock(&p->lock); - snprintf(buf, len, "%f", p->txgain); -- ast_mutex_unlock(&p->lock); -+ ast_mutex_unlock(&p->lock); - } else { - ast_copy_string(buf, "", len); - } -@@ -3744,10 +5700,10 @@ - ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel); - master->slaves[MAX_SLAVES - 1] = slave; - } -- if (slave->master) -+ if (slave->master) - ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel); - slave->master = master; -- -+ - ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x); - } - -@@ -3892,7 +5848,7 @@ - nothingok = 0; - } - } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) { -- /* We have a real and a call wait. If we're in a three way call, put us in it, otherwise, -+ /* We have a real and a call wait. If we're in a three way call, put us in it, otherwise, - don't put us in anything */ - if (p1->subs[SUB_CALLWAIT].inthreeway) { - master = p1; -@@ -3913,11 +5869,11 @@ - /* Stop any tones, or play ringtone as appropriate. If they're bridged - in an active threeway call with a channel that is ringing, we should - indicate ringing. */ -- if ((oi1 == SUB_THREEWAY) && -- p1->subs[SUB_THREEWAY].inthreeway && -- p1->subs[SUB_REAL].owner && -- p1->subs[SUB_REAL].inthreeway && -- (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { -+ if ((oi1 == SUB_THREEWAY) && -+ p1->subs[SUB_THREEWAY].inthreeway && -+ p1->subs[SUB_REAL].owner && -+ p1->subs[SUB_REAL].inthreeway && -+ (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { - ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name); - tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE); - os1 = p1->subs[SUB_REAL].owner->_state; -@@ -3925,11 +5881,11 @@ - ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1); - tone_zone_play_tone(p0->subs[oi0].dfd, -1); - } -- if ((oi0 == SUB_THREEWAY) && -- p0->subs[SUB_THREEWAY].inthreeway && -- p0->subs[SUB_REAL].owner && -- p0->subs[SUB_REAL].inthreeway && -- (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { -+ if ((oi0 == SUB_THREEWAY) && -+ p0->subs[SUB_THREEWAY].inthreeway && -+ p0->subs[SUB_REAL].owner && -+ p0->subs[SUB_REAL].inthreeway && -+ (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { - ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name); - tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE); - os0 = p0->subs[SUB_REAL].owner->_state; -@@ -3966,7 +5922,7 @@ - dahdi_enable_ec(p1); - return AST_BRIDGE_FAILED; - } -- -+ - ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name); - - if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL)) -@@ -3979,9 +5935,9 @@ - struct ast_channel *c0_priority[2] = {c0, c1}; - struct ast_channel *c1_priority[2] = {c1, c0}; - -- /* Here's our main loop... Start by locking things, looking for private parts, -+ /* Here's our main loop... Start by locking things, looking for private parts, - and then balking if anything is wrong */ -- -+ - ast_channel_lock(c0); - while (ast_channel_trylock(c1)) { - CHANNEL_DEADLOCK_AVOIDANCE(c0); -@@ -3998,19 +5954,19 @@ - ast_channel_unlock(c0); - ast_channel_unlock(c1); - -- if (!timeoutms || -- (op0 != p0) || -- (op1 != p1) || -- (ofd0 != c0->fds[0]) || -- (ofd1 != c1->fds[0]) || -- (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) || -- (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) || -- (oc0 != p0->owner) || -- (oc1 != p1->owner) || -- (t0 != p0->subs[SUB_REAL].inthreeway) || -- (t1 != p1->subs[SUB_REAL].inthreeway) || -- (oi0 != i0) || -- (oi1 != i1)) { -+ if (!timeoutms || -+ (op0 != p0) || -+ (op1 != p1) || -+ (ofd0 != c0->fds[0]) || -+ (ofd1 != c1->fds[0]) || -+ (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) || -+ (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) || -+ (oc0 != p0->owner) || -+ (oc1 != p1->owner) || -+ (t0 != p0->subs[SUB_REAL].inthreeway) || -+ (t1 != p1->subs[SUB_REAL].inthreeway) || -+ (oi0 != i0) || -+ (oi1 != i1)) { - ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n", - op0->channel, oi0, op1->channel, oi1); - res = AST_BRIDGE_RETRY; -@@ -4020,9 +5976,9 @@ - #ifdef PRI_2BCT - q931c0 = p0->call; - q931c1 = p1->call; -- if (p0->transfer && p1->transfer -- && q931c0 && q931c1 -- && !triedtopribridge) { -+ if (p0->transfer && p1->transfer -+ && q931c0 && q931c1 -+ && !triedtopribridge) { - pri_channel_bridge(q931c0, q931c1); - triedtopribridge = 1; - } -@@ -4053,7 +6009,7 @@ - } - } - ast_frfree(f); -- -+ - /* Swap who gets priority */ - priority = !priority; - } -@@ -4091,7 +6047,7 @@ - dahdi_unlink(NULL, p, 0); - p->subs[x].owner = newchan; - } -- if (newchan->_state == AST_STATE_RINGING) -+ if (newchan->_state == AST_STATE_RINGING) - dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0); - update_conf(p); - ast_mutex_unlock(&p->lock); -@@ -4195,7 +6151,7 @@ - ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno)); - return 0; - } -- /* If we have no master and don't have a confno, then -+ /* If we have no master and don't have a confno, then - if we're in a conference, it's probably a MeetMe room or - some such, so don't let us 3-way out! */ - if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) { -@@ -4266,7 +6222,22 @@ - } else if (f->subclass == 'f') { - /* Fax tone -- Handle and return NULL */ - if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) { -- p->faxhandled++; -+ /* If faxbuffers are configured, use them for the fax transmission */ -+ if (p->usefaxbuffers && !p->faxbuffersinuse) { -+ struct dahdi_bufferinfo bi = { -+ .txbufpolicy = p->faxbuf_policy, -+ .bufsize = p->bufsize, -+ .numbufs = p->faxbuf_no -+ }; -+ int res; -+ -+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) { -+ ast_log(LOG_WARNING, "Channel '%s' unable to set faxbuffer policy, reason: %s\n", ast->name, strerror(errno)); -+ } else { -+ p->faxbuffersinuse = 1; -+ } -+ } -+ p->faxhandled = 1; - if (strcmp(ast->exten, "fax")) { - const char *target_context = S_OR(ast->macrocontext, ast->context); - -@@ -4301,16 +6272,16 @@ - *dest = &p->subs[idx].f; - } - } -- -+ - static void handle_alarms(struct dahdi_pvt *p, int alms) - { - const char *alarm_str = alarm2str(alms); - - ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str); - manager_event(EVENT_FLAG_SYSTEM, "Alarm", -- "Alarm: %s\r\n" -- "Channel: %d\r\n", -- alarm_str, p->channel); -+ "Alarm: %s\r\n" -+ "Channel: %d\r\n", -+ alarm_str, p->channel); - } - - static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) -@@ -4348,7 +6319,7 @@ - ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx); - - if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) { -- p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0; -+ p->pulsedial = (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0; - ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff); - #ifdef HAVE_PRI - if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) { -@@ -4384,7 +6355,7 @@ - /* Stop tone if there's a pulse start and the PBX isn't started */ - if (!ast->pbx) - tone_zone_play_tone(p->subs[idx].dfd, -1); -- break; -+ break; - case DAHDI_EVENT_DIALCOMPLETE: - if (p->inalarm) break; - if ((p->radio || (p->oprmode < 0))) break; -@@ -4417,7 +6388,15 @@ - if (ast->_state == AST_STATE_DIALING) { - if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) { - ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n"); -- } else if (p->confirmanswer || (!p->dialednone && ((mysig == SIG_EM) || (mysig == SIG_EM_E1) || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD) || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF) || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB) || (mysig == SIG_SF) || (mysig == SIG_SFWINK) || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF) || (mysig == SIG_SF_FEATB)))) { -+ } else if (p->confirmanswer || (!p->dialednone -+ && ((mysig == SIG_EM) || (mysig == SIG_EM_E1) -+ || (mysig == SIG_EMWINK) || (mysig == SIG_FEATD) -+ || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF) -+ || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) -+ || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB) -+ || (mysig == SIG_SF) || (mysig == SIG_SFWINK) -+ || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF) -+ || (mysig == SIG_SF_FEATB)))) { - ast_setstate(ast, AST_STATE_RINGING); - } else if (!p->answeronpolarityswitch) { - ast_setstate(ast, AST_STATE_UP); -@@ -4496,6 +6475,7 @@ - case SIG_FXOGS: - case SIG_FXOKS: - p->onhooktime = time(NULL); -+ p->fxsoffhookstate = 0; - p->msgstate = -1; - /* Check for some special conditions regarding call waiting */ - if (idx == SUB_REAL) { -@@ -4504,11 +6484,11 @@ - /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */ - swap_subs(p, SUB_CALLWAIT, SUB_REAL); - ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel); -- unalloc_sub(p, SUB_CALLWAIT); -+ unalloc_sub(p, SUB_CALLWAIT); - #if 0 - p->subs[idx].needanswer = 0; - p->subs[idx].needringing = 0; --#endif -+#endif - p->callwaitingrepeat = 0; - p->cidcwexpire = 0; - p->owner = NULL; -@@ -4540,7 +6520,7 @@ - mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime); - ast_debug(1, "Last flash was %d ms ago\n", mssinceflash); - if (mssinceflash < MIN_MS_SINCE_FLASH) { -- /* It hasn't been long enough since the last flashook. This is probably a bounce on -+ /* It hasn't been long enough since the last flashook. This is probably a bounce on - hanging up. Hangup both channels now */ - if (p->subs[SUB_THREEWAY].owner) - ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER); -@@ -4647,6 +6627,7 @@ - case SIG_FXOLS: - case SIG_FXOGS: - case SIG_FXOKS: -+ p->fxsoffhookstate = 1; - switch (ast->_state) { - case AST_STATE_RINGING: - dahdi_enable_ec(p); -@@ -4718,10 +6699,10 @@ - p->ringt = p->ringt_base; - } - -- /* If we get a ring then we cannot be in -+ /* If we get a ring then we cannot be in - * reversed polarity. So we reset to idle */ - ast_debug(1, "Setting IDLE polarity due " -- "to ring. Old polarity was %d\n", -+ "to ring. Old polarity was %d\n", - p->polarity); - p->polarity = POLARITY_IDLE; - -@@ -4796,7 +6777,7 @@ - /* Extremely unlikely but just in case */ - if (p->bearer) - p->bearer->inalarm = 0; --#endif -+#endif - ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel); - manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", - "Channel: %d\r\n", p->channel); -@@ -4836,7 +6817,7 @@ - ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel); - goto winkflashdone; - } -- -+ - if (p->subs[SUB_CALLWAIT].owner) { - /* Swap to call-wait */ - swap_subs(p, SUB_REAL, SUB_CALLWAIT); -@@ -4863,14 +6844,16 @@ - } - p->subs[SUB_REAL].needunhold = 1; - } else if (!p->subs[SUB_THREEWAY].owner) { -- char cid_num[256]; -- char cid_name[256]; -- - if (!p->threewaycalling) { - /* Just send a flash if no 3-way calling */ - p->subs[SUB_REAL].needflash = 1; - goto winkflashdone; - } else if (!check_for_conference(p)) { -+ char cid_num[256]; -+ char cid_name[256]; -+ -+ cid_num[0] = 0; -+ cid_name[0] = 0; - if (p->dahditrcallerid && p->owner) { - if (p->owner->cid.cid_num) - ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num)); -@@ -4880,8 +6863,8 @@ - /* XXX This section needs much more error checking!!! XXX */ - /* Start a 3-way call if feasible */ - if (!((ast->pbx) || -- (ast->_state == AST_STATE_UP) || -- (ast->_state == AST_STATE_RING))) { -+ (ast->_state == AST_STATE_UP) || -+ (ast->_state == AST_STATE_RING))) { - ast_debug(1, "Flash when call not up or ringing\n"); - goto winkflashdone; - } -@@ -4917,15 +6900,15 @@ - } else { - struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner); - int way3bridge = 0, cdr3way = 0; -- -+ - if (!other) { - other = ast_bridged_channel(p->subs[SUB_REAL].owner); - } else - way3bridge = 1; -- -+ - if (p->subs[SUB_THREEWAY].owner->cdr) - cdr3way = 1; -- -+ - ast_verb(3, "Started three way call on channel %d\n", p->channel); - - /* Start music on hold if appropriate */ -@@ -4955,17 +6938,17 @@ - p->subs[SUB_THREEWAY].inthreeway = 0; - } else { - /* Lets see what we're up to */ -- if (((ast->pbx) || (ast->_state == AST_STATE_UP)) && -- (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) { -+ if (((ast->pbx) || (ast->_state == AST_STATE_UP)) && -+ (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) { - int otherindex = SUB_THREEWAY; - struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner); - int way3bridge = 0, cdr3way = 0; -- -+ - if (!other) { - other = ast_bridged_channel(p->subs[SUB_REAL].owner); - } else - way3bridge = 1; -- -+ - if (p->subs[SUB_THREEWAY].owner->cdr) - cdr3way = 1; - -@@ -4996,10 +6979,9 @@ - p->subs[SUB_REAL].needunhold = 1; - dahdi_enable_ec(p); - } -- - } - } -- winkflashdone: -+winkflashdone: - update_conf(p); - break; - case SIG_EM: -@@ -5047,7 +7029,7 @@ - ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno)); - p->dop.dialstr[0] = '\0'; - return NULL; -- } else -+ } else - ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr); - } - p->dop.dialstr[0] = '\0'; -@@ -5059,6 +7041,7 @@ - case DAHDI_EVENT_HOOKCOMPLETE: - if (p->inalarm) break; - if ((p->radio || (p->oprmode < 0))) break; -+ if (p->waitingfordt.tv_sec) break; - switch (mysig) { - case SIG_FXSLS: /* only interesting for FXS */ - case SIG_FXSGS: -@@ -5076,7 +7059,7 @@ - ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno)); - p->dop.dialstr[0] = '\0'; - return NULL; -- } else -+ } else - ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr); - } - p->dop.dialstr[0] = '\0'; -@@ -5106,8 +7089,8 @@ - if (p->polarity == POLARITY_IDLE) { - p->polarity = POLARITY_REV; - if (p->answeronpolarityswitch && -- ((ast->_state == AST_STATE_DIALING) || -- (ast->_state == AST_STATE_RINGING))) { -+ ((ast->_state == AST_STATE_DIALING) || -+ (ast->_state == AST_STATE_RINGING))) { - ast_debug(1, "Answering on polarity switch!\n"); - ast_setstate(p->owner, AST_STATE_UP); - if (p->hanguponpolarityswitch) { -@@ -5115,17 +7098,16 @@ - } - } else - ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state); -- -- } -+ } - /* Removed else statement from here as it was preventing hangups from ever happening*/ - /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */ - if (p->hanguponpolarityswitch && - (p->polarityonanswerdelay > 0) && -- (p->polarity == POLARITY_REV) && -+ (p->polarity == POLARITY_REV) && - ((ast->_state == AST_STATE_UP) || (ast->_state == AST_STATE_RING)) ) { -- /* Added log_debug information below to provide a better indication of what is going on */ -+ /* Added log_debug information below to provide a better indication of what is going on */ - ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) ); -- -+ - if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) { - ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel); - ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); -@@ -5137,7 +7119,7 @@ - p->polarity = POLARITY_IDLE; - ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state); - } -- /* Added more log_debug information below to provide a better indication of what is going on */ -+ /* Added more log_debug information below to provide a better indication of what is going on */ - ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) ); - break; - default: -@@ -5156,7 +7138,7 @@ - - - idx = dahdi_get_index(ast, p, 1); -- -+ - p->subs[idx].f.frametype = AST_FRAME_NULL; - p->subs[idx].f.datalen = 0; - p->subs[idx].f.samples = 0; -@@ -5166,8 +7148,8 @@ - p->subs[idx].f.delivery = ast_tv(0,0); - p->subs[idx].f.src = "dahdi_exception"; - p->subs[idx].f.data.ptr = NULL; -- -- -+ -+ - if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) { - /* If nobody owns us, absorb the event appropriately, otherwise - we loop indefinitely. This occurs when, during call waiting, the -@@ -5240,7 +7222,7 @@ - f = &p->subs[idx].f; - return f; - } -- if (!(p->radio || (p->oprmode < 0))) -+ if (!(p->radio || (p->oprmode < 0))) - ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel); - /* If it's not us, return NULL immediately */ - if (ast != p->owner) { -@@ -5262,7 +7244,7 @@ - return f; - } - --static struct ast_frame *dahdi_read(struct ast_channel *ast) -+static struct ast_frame *dahdi_read(struct ast_channel *ast) - { - struct dahdi_pvt *p = ast->tech_pvt; - int res; -@@ -5275,14 +7257,14 @@ - } - - idx = dahdi_get_index(ast, p, 0); -- -+ - /* Hang up if we don't really exist */ - if (idx < 0) { - ast_log(LOG_WARNING, "We dont exist?\n"); - ast_mutex_unlock(&p->lock); - return NULL; - } -- -+ - if ((p->radio || (p->oprmode < 0)) && p->inalarm) return NULL; - - p->subs[idx].f.frametype = AST_FRAME_NULL; -@@ -5294,7 +7276,7 @@ - p->subs[idx].f.delivery = ast_tv(0,0); - p->subs[idx].f.src = "dahdi_read"; - p->subs[idx].f.data.ptr = NULL; -- -+ - /* make sure it sends initial key state as first frame */ - if ((p->radio || (p->oprmode < 0)) && (!p->firstradio)) - { -@@ -5322,7 +7304,7 @@ - ast_mutex_unlock(&p->lock); - return NULL; - } -- else if (p->ringt > 0) -+ else if (p->ringt > 0) - p->ringt--; - - if (p->subs[idx].needringing) { -@@ -5360,7 +7342,7 @@ - ); - p->subs[idx].needcallerid = 0; - } -- -+ - if (p->subs[idx].needanswer) { - /* Send answer frame if requested */ - p->subs[idx].needanswer = 0; -@@ -5368,8 +7350,8 @@ - p->subs[idx].f.subclass = AST_CONTROL_ANSWER; - ast_mutex_unlock(&p->lock); - return &p->subs[idx].f; -- } -- -+ } -+ - if (p->subs[idx].needflash) { - /* Send answer frame if requested */ - p->subs[idx].needflash = 0; -@@ -5377,8 +7359,8 @@ - p->subs[idx].f.subclass = AST_CONTROL_FLASH; - ast_mutex_unlock(&p->lock); - return &p->subs[idx].f; -- } -- -+ } -+ - if (p->subs[idx].needhold) { - /* Send answer frame if requested */ - p->subs[idx].needhold = 0; -@@ -5387,8 +7369,8 @@ - ast_mutex_unlock(&p->lock); - ast_debug(1, "Sending hold on '%s'\n", ast->name); - return &p->subs[idx].f; -- } -- -+ } -+ - if (p->subs[idx].needunhold) { - /* Send answer frame if requested */ - p->subs[idx].needunhold = 0; -@@ -5397,21 +7379,21 @@ - ast_mutex_unlock(&p->lock); - ast_debug(1, "Sending unhold on '%s'\n", ast->name); - return &p->subs[idx].f; -- } -- -+ } -+ - if (ast->rawreadformat == AST_FORMAT_SLINEAR) { - if (!p->subs[idx].linear) { - p->subs[idx].linear = 1; - res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); -- if (res) -+ if (res) - ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx); - } - } else if ((ast->rawreadformat == AST_FORMAT_ULAW) || -- (ast->rawreadformat == AST_FORMAT_ALAW)) { -+ (ast->rawreadformat == AST_FORMAT_ALAW)) { - if (p->subs[idx].linear) { - p->subs[idx].linear = 0; - res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); -- if (res) -+ if (res) - ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx); - } - } else { -@@ -5426,7 +7408,7 @@ - /* Check for hangup */ - if (res < 0) { - f = NULL; -- if (res == -1) { -+ if (res == -1) { - if (errno == EAGAIN) { - /* Return "NULL" frame if there is nobody there */ - ast_mutex_unlock(&p->lock); -@@ -5484,7 +7466,7 @@ - } - if (p->subs[idx].linear) { - p->subs[idx].f.datalen = READ_SIZE * 2; -- } else -+ } else - p->subs[idx].f.datalen = READ_SIZE; - - /* Handle CallerID Transmission */ -@@ -5500,11 +7482,11 @@ - p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]); - #if 0 - ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name); --#endif -+#endif - if (p->dialing || /* Transmitting something */ -- (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */ -- ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */ -- ) { -+ (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */ -+ ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */ -+ ) { - /* Whoops, we're still dialing, or in a state where we shouldn't transmit.... - don't send anything */ - p->subs[idx].f.frametype = AST_FRAME_NULL; -@@ -5515,8 +7497,8 @@ - p->subs[idx].f.data.ptr = NULL; - p->subs[idx].f.datalen= 0; - } -- if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress) && !idx) { -- /* Perform busy detection. etc on the dahdi line */ -+ if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect || p->callprogress || p->waitingfordt.tv_sec) && !idx) { -+ /* Perform busy detection etc on the dahdi line */ - int mute; - - f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f); -@@ -5532,25 +7514,54 @@ - if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) { - if ((ast->_state == AST_STATE_UP) && !p->outgoing) { - /* Treat this as a "hangup" instead of a "busy" on the assumption that -- a busy */ -+ a busy */ - f = NULL; - } - } else if (f->frametype == AST_FRAME_DTMF) { - #ifdef HAVE_PRI -- if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && -- ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) || -- (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) { -+ if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && -+ ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) || -+ (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) { - /* Don't accept in-band DTMF when in overlap dial mode */ - f->frametype = AST_FRAME_NULL; - f->subclass = 0; - } --#endif -+#endif - /* DSP clears us of being pulse */ - p->pulsedial = 0; -+ } else if (p->waitingfordt.tv_sec) { -+ if (ast_tvdiff_ms(ast_tvnow(), p->waitingfordt) >= p->waitfordialtone ) { -+ p->waitingfordt.tv_sec = 0; -+ ast_log(LOG_WARNING, "Never saw dialtone on channel %d\n", p->channel); -+ f=NULL; -+ } else if (f->frametype == AST_FRAME_VOICE) { -+ f->frametype = AST_FRAME_NULL; -+ f->subclass = 0; -+ if ((ast_dsp_get_tstate(p->dsp) == DSP_TONE_STATE_DIALTONE || ast_dsp_get_tstate(p->dsp) == DSP_TONE_STATE_RINGING) && ast_dsp_get_tcount(p->dsp) > 9) { -+ p->waitingfordt.tv_sec = 0; -+ p->dsp_features &= ~DSP_FEATURE_WAITDIALTONE; -+ ast_dsp_set_features(p->dsp, p->dsp_features); -+ ast_log(LOG_DEBUG, "Got 10 samples of dialtone!\n"); -+ if (!ast_strlen_zero(p->dop.dialstr)) { /* Dial deferred digits */ -+ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop); -+ if (res < 0) { -+ ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", p->channel); -+ p->dop.dialstr[0] = '\0'; -+ return NULL; -+ } else { -+ ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr); -+ p->dialing = 1; -+ p->dop.dialstr[0] = '\0'; -+ p->dop.op = DAHDI_DIAL_OP_REPLACE; -+ ast_setstate(ast, AST_STATE_DIALING); -+ } -+ } -+ } -+ } - } - } -- } else -- f = &p->subs[idx].f; -+ } else -+ f = &p->subs[idx].f; - - if (f && (f->frametype == AST_FRAME_DTMF)) - dahdi_handle_dtmfup(ast, idx, &f); -@@ -5600,7 +7611,7 @@ - #ifdef HAVE_PRI - ast_mutex_lock(&p->lock); - if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) { -- if (p->pri->pri) { -+ if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital); - pri_rel(p->pri); -@@ -5618,9 +7629,9 @@ - ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype); - return 0; - } -- if ((frame->subclass != AST_FORMAT_SLINEAR) && -- (frame->subclass != AST_FORMAT_ULAW) && -- (frame->subclass != AST_FORMAT_ALAW)) { -+ if ((frame->subclass != AST_FORMAT_SLINEAR) && -+ (frame->subclass != AST_FORMAT_ULAW) && -+ (frame->subclass != AST_FORMAT_ALAW)) { - ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass); - return -1; - } -@@ -5661,7 +7672,7 @@ - if (res < 0) { - ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno)); - return -1; -- } -+ } - return 0; - } - -@@ -5671,6 +7682,7 @@ - int res=-1; - int idx; - int func = DAHDI_FLASH; -+ - ast_mutex_lock(&p->lock); - idx = dahdi_get_index(chan, p, 0); - ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name); -@@ -5682,12 +7694,16 @@ - chan->hangupcause = AST_CAUSE_USER_BUSY; - chan->_softhangup |= AST_SOFTHANGUP_DEV; - res = 0; -- } else if (!p->progress && -+ } else if (!p->progress && - ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { -- if (p->pri->pri) { -+ if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, PRI_CAUSE_USER_BUSY); /* cause = 17 */ -+#else - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); -+#endif - pri_rel(p->pri); - } - else -@@ -5701,9 +7717,9 @@ - break; - case AST_CONTROL_RINGING: - #ifdef HAVE_PRI -- if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) -+ if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) { -- if (p->pri->pri) { -+ if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { - pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital); - pri_rel(p->pri); -@@ -5719,7 +7735,7 @@ - if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) { - if (p->ss7->ss7) { - ss7_grab(p, p->ss7); -- -+ - if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) - p->rlt = 1; - if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */ -@@ -5729,9 +7745,9 @@ - } - } - #endif -- -+ - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE); -- -+ - if (chan->_state != AST_STATE_UP) { - if ((chan->_state != AST_STATE_RING) || - ((p->sig != SIG_FXSKS) && -@@ -5745,7 +7761,7 @@ - #ifdef HAVE_PRI - if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { -- if (p->pri->pri) { -+ if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { - pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital); - pri_rel(p->pri); -@@ -5760,9 +7776,9 @@ - /* This IF sends the FAR for an answered ALEG call */ - if (chan->_state == AST_STATE_UP && (p->rlt != 1) && (p->sig == SIG_SS7)){ - if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) -- p->rlt = 1; -+ p->rlt = 1; - } -- -+ - if (!p->proceeding && p->sig == SIG_SS7 && p->ss7 && !p->outgoing) { - if (p->ss7->ss7) { - ss7_grab(p, p->ss7); -@@ -5782,9 +7798,13 @@ - p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */ - if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { -- if (p->pri->pri) { -+ if (p->pri->pri) { - if (!pri_grab(p, p->pri)) { -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, -1); /* no cause at all */ -+#else - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); -+#endif - pri_rel(p->pri); - } - else -@@ -5816,11 +7836,15 @@ - chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION; - chan->_softhangup |= AST_SOFTHANGUP_DEV; - res = 0; -- } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) -+ } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) - && p->pri && !p->outgoing) { -- if (p->pri) { -+ if (p->pri) { - if (!pri_grab(p, p->pri)) { -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ pri_progress_with_cause(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1, PRI_CAUSE_SWITCH_CONGESTION); /* cause = 42 */ -+#else - pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1); -+#endif - pri_rel(p->pri); - } else - ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); -@@ -5838,7 +7862,7 @@ - res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD); - pri_rel(p->pri); - } else -- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); -+ ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); - } else - #endif - ast_moh_start(chan, data, p->mohinterpret); -@@ -5850,19 +7874,19 @@ - res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL); - pri_rel(p->pri); - } else -- ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); -+ ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span); - } else - #endif - ast_moh_stop(chan); - break; - case AST_CONTROL_RADIO_KEY: -- if (p->radio) -- res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK); -+ if (p->radio) -+ res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK); - res = 0; - break; - case AST_CONTROL_RADIO_UNKEY: - if (p->radio) -- res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF); -+ res = dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF); - res = 0; - break; - case AST_CONTROL_FLASH: -@@ -5871,7 +7895,7 @@ - /* Clear out the dial buffer */ - p->dop.dialstr[0] = '\0'; - if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) { -- ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", -+ ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", - chan->name, strerror(errno)); - } else - res = 0; -@@ -5884,6 +7908,65 @@ - case -1: - res = tone_zone_play_tone(p->subs[idx].dfd, -1); - break; -+ case AST_CONTROL_CONNECTED_LINE: -+ ast_debug(1, "Received AST_CONTROL_CONNECTED_LINE on %s\n", chan->name); -+#if defined(HAVE_PRI) -+ if (p->pri) { -+ struct pri_party_connected_line connected; -+ -+ if (chan->connected.id.number) { -+ ast_copy_string(connected.id.number, chan->connected.id.number, sizeof(connected.id.number)); -+ } else { -+ connected.id.number[0] = '\0'; -+ } -+ if (chan->connected.id.name) { -+ ast_copy_string(connected.id.name, chan->connected.id.name, sizeof(connected.id.name)); -+ } else { -+ connected.id.name[0] = '\0'; -+ } -+ connected.id.number_type = chan->connected.id.number_type; -+ connected.id.number_presentation = ast_to_pri_presentation(chan->connected.id.number_presentation); -+ connected.source = ast_to_pri_connected_line_update_source(chan->connected.source); -+ pri_connected_line_update(p->pri->pri, p->call, &connected); -+ } -+#endif /* defined(HAVE_PRI) */ -+ break; -+ case AST_CONTROL_REDIRECTING: -+ ast_debug(1, "Received AST_CONTROL_REDIRECTING on %s\n", chan->name); -+#if defined(HAVE_PRI) -+ if (p->pri) { -+ struct pri_party_redirecting redirecting; -+ -+ if (chan->cid.cid_rdnis) { -+ ast_copy_string(redirecting.from.number, chan->cid.cid_rdnis, sizeof(redirecting.from.number)); -+ } else { -+ redirecting.from.number[0] = '\0'; -+ } -+ if (chan->redirecting.from.name) { -+ ast_copy_string(redirecting.from.name, chan->redirecting.from.name, sizeof(redirecting.from.name)); -+ } else { -+ redirecting.from.name[0] = '\0'; -+ } -+ redirecting.from.number_type = chan->redirecting.from.number_type; -+ redirecting.from.number_presentation = ast_to_pri_presentation(chan->redirecting.from.number_presentation); -+ if (chan->redirecting.to.number) { -+ ast_copy_string(redirecting.to.number, chan->redirecting.to.number, sizeof(redirecting.to.number)); -+ } else { -+ redirecting.to.number[0] = '\0'; -+ } -+ if (chan->redirecting.to.name) { -+ ast_copy_string(redirecting.to.name, chan->redirecting.to.name, sizeof(redirecting.to.name)); -+ } else { -+ redirecting.to.name[0] = '\0'; -+ } -+ redirecting.to.number_type = chan->redirecting.to.number_type; -+ redirecting.to.number_presentation = ast_to_pri_presentation(chan->redirecting.to.number_presentation); -+ redirecting.count = chan->redirecting.count; -+ redirecting.reason = ast_to_pri_reason(chan->redirecting.reason); -+ pri_redirecting_update(p->pri->pri, p->call, &redirecting); -+ } -+#endif /* defined(HAVE_PRI) */ -+ break; - } - } else - res = 0; -@@ -5915,15 +7998,15 @@ - #endif - if (i->channel == CHAN_PSEUDO) - ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random()); -- else -+ else - ast_str_set(&chan_name, 0, "%d-%d", i->channel, y); - for (x = 0; x < 3; x++) { -- if ((idx != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name + 6)) -+ if ((idx != x) && i->subs[x].owner && !strcasecmp(ast_str_buffer(chan_name), i->subs[x].owner->name + 6)) - break; - } - y++; - } while (x < 3); -- tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "DAHDI/%s", chan_name->str); -+ tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "DAHDI/%s", ast_str_buffer(chan_name)); - if (!tmp) - return NULL; - tmp->tech = &dahdi_tech; -@@ -5958,8 +8041,10 @@ - features |= DSP_FEATURE_BUSY_DETECT; - if ((i->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(i)) - features |= DSP_FEATURE_CALL_PROGRESS; -- if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) || -- (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) { -+ if ((i->waitfordialtone) && CANPROGRESSDETECT(i)) -+ features |= DSP_FEATURE_WAITDIALTONE; -+ if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) || -+ (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) { - features |= DSP_FEATURE_FAX_DETECT; - } - x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE; -@@ -6001,7 +8086,7 @@ - } - } - } -- -+ - if (state == AST_STATE_RING) - tmp->rings = 1; - tmp->tech_pvt = i; -@@ -6038,7 +8123,7 @@ - #ifdef PRI_ANI - if (!ast_strlen_zero(i->cid_ani)) - tmp->cid.cid_ani = ast_strdup(i->cid_ani); -- else -+ else - tmp->cid.cid_ani = ast_strdup(i->cid_num); - #else - tmp->cid.cid_ani = ast_strdup(i->cid_num); -@@ -6066,7 +8151,7 @@ - ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name); - - for (v = i->vars ; v ; v = v->next) -- pbx_builtin_setvar_helper(tmp, v->name, v->value); -+ pbx_builtin_setvar_helper(tmp, v->name, v->value); - - if (startpbx) { - if (ast_pbx_start(tmp)) { -@@ -6107,14 +8192,14 @@ - dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK); - for (;;) - { -- /* set bits of interest */ -+ /* set bits of interest */ - j = DAHDI_IOMUX_SIGEVENT; -- /* wait for some happening */ -+ /* wait for some happening */ - if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1); -- /* exit loop if we have it */ -+ /* exit loop if we have it */ - if (j & DAHDI_IOMUX_SIGEVENT) break; - } -- /* get the event info */ -+ /* get the event info */ - if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1); - return 0; - } -@@ -6123,7 +8208,7 @@ - * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5) - * \param on 1 to enable, 0 to disable - * -- * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical -+ * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical - * DAHDI channel). Use this to enable or disable it. - * - * \bug the use of the word "channel" for those dahdichans is really confusing. -@@ -6132,7 +8217,7 @@ - { - /* Do not disturb */ - dahdichan->dnd = on; -- ast_verb(3, "%s DND on channel %d\n", -+ ast_verb(3, "%s DND on channel %d\n", - on? "Enabled" : "Disabled", - dahdichan->channel); - manager_event(EVENT_FLAG_SYSTEM, "DNDState", -@@ -6256,7 +8341,7 @@ - case SIG_SF_FEATDMF: - case SIG_SF_FEATB: - case SIG_SFWINK: -- if (dahdi_wink(p, idx)) -+ if (dahdi_wink(p, idx)) - goto quit; - /* Fall through */ - case SIG_EM: -@@ -6269,8 +8354,8 @@ - /* set digit mode appropriately */ - if (p->dsp) { - if (NEED_MFDETECT(p)) -- ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); -- else -+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); -+ else - ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); - } - memset(dtmfbuf, 0, sizeof(dtmfbuf)); -@@ -6381,18 +8466,18 @@ - char anibuf[100]; - - if (ast_safe_sleep(chan,1000) == -1) { -- ast_hangup(chan); -- goto quit; -+ ast_hangup(chan); -+ goto quit; - } -- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK); -- ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); -- res = my_getsigstr(chan, anibuf, "#", 10000); -- if ((res > 0) && (strlen(anibuf) > 2)) { -+ dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK); -+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); -+ res = my_getsigstr(chan, anibuf, "#", 10000); -+ if ((res > 0) && (strlen(anibuf) > 2)) { - if (anibuf[strlen(anibuf) - 1] == '#') - anibuf[strlen(anibuf) - 1] = 0; - ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2); - } -- ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); -+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); - } - - ast_copy_string(exten, dtmfbuf, sizeof(exten)); -@@ -6468,16 +8553,16 @@ - } - if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) { - dahdi_wink(p, idx); -- /* some switches require a minimum guard time between -- the last FGD wink and something that answers -- immediately. This ensures it */ -- if (ast_safe_sleep(chan,100)) goto quit; -+ /* some switches require a minimum guard time between -+ the last FGD wink and something that answers -+ immediately. This ensures it */ -+ if (ast_safe_sleep(chan,100)) goto quit; - } - dahdi_enable_ec(p); - if (NEED_MFDETECT(p)) { - if (p->dsp) { - if (!p->hardwaredtmf) -- ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); -+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); - else { - ast_dsp_free(p->dsp); - p->dsp = NULL; -@@ -6517,12 +8602,12 @@ - timeout = firstdigittimeout; - /* If starting a threeway call, never timeout on the first digit so someone - can use flash-hook as a "hold" feature */ -- if (p->subs[SUB_THREEWAY].owner) -+ if (p->subs[SUB_THREEWAY].owner) - timeout = 999999; - while (len < AST_MAX_EXTENSION-1) { - /* Read digit unless it's supposed to be immediate, in which case the - only answer is 's' */ -- if (p->immediate) -+ if (p->immediate) - res = 's'; - else - res = ast_waitfordigit(chan, timeout); -@@ -6532,7 +8617,7 @@ - res = tone_zone_play_tone(p->subs[idx].dfd, -1); - ast_hangup(chan); - goto quit; -- } else if (res) { -+ } else if (res) { - ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout); - exten[len++]=res; - exten[len] = '\0'; -@@ -6545,7 +8630,7 @@ - if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) { - if (getforward) { - /* Record this as the forwarding extension */ -- ast_copy_string(p->call_forward, exten, sizeof(p->call_forward)); -+ ast_copy_string(p->call_forward, exten, sizeof(p->call_forward)); - ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel); - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL); - if (res) -@@ -6557,14 +8642,14 @@ - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE); - len = 0; - getforward = 0; -- } else { -+ } else { - res = tone_zone_play_tone(p->subs[idx].dfd, -1); - ast_copy_string(chan->exten, exten, sizeof(chan->exten)); - if (!ast_strlen_zero(p->cid_num)) { - if (!p->hidecallerid) -- ast_set_callerid(chan, p->cid_num, NULL, p->cid_num); -+ ast_set_callerid(chan, p->cid_num, NULL, p->cid_num); - else -- ast_set_callerid(chan, NULL, NULL, p->cid_num); -+ ast_set_callerid(chan, NULL, NULL, p->cid_num); - } - if (!ast_strlen_zero(p->cid_name)) { - if (!p->hidecallerid) -@@ -6596,26 +8681,26 @@ - p->callwaiting = 0; - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL); - if (res) { -- ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", -+ ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", - chan->name, strerror(errno)); - } - len = 0; - ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len); - memset(exten, 0, sizeof(exten)); - timeout = firstdigittimeout; -- -+ - } else if (!strcmp(exten,ast_pickup_ext())) { - /* Scan all channels and see if there are any - * ringing channels that have call groups -- * that equal this channels pickup group -+ * that equal this channels pickup group - */ -- if (idx == SUB_REAL) { -+ if (idx == SUB_REAL) { - /* Switch us from Third call to Call Wait */ -- if (p->subs[SUB_THREEWAY].owner) { -- /* If you make a threeway call and the *8# a call, it should actually -+ if (p->subs[SUB_THREEWAY].owner) { -+ /* If you make a threeway call and the *8# a call, it should actually - look like a callwait */ -- alloc_sub(p, SUB_CALLWAIT); -- swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY); -+ alloc_sub(p, SUB_CALLWAIT); -+ swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY); - unalloc_sub(p, SUB_THREEWAY); - } - dahdi_enable_ec(p); -@@ -6631,7 +8716,7 @@ - ast_hangup(chan); - goto quit; - } -- -+ - } else if (!p->hidecallerid && !strcmp(exten, "*67")) { - ast_verb(3, "Disabling Caller*ID on %s\n", chan->name); - /* Disable Caller*ID if enabled */ -@@ -6644,7 +8729,7 @@ - chan->cid.cid_name = NULL; - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL); - if (res) { -- ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", -+ ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", - chan->name, strerror(errno)); - } - len = 0; -@@ -6684,10 +8769,10 @@ - getforward = 0; - memset(exten, 0, sizeof(exten)); - len = 0; -- } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && -+ } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && - p->subs[SUB_THREEWAY].owner && - ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) { -- /* This is a three way call, the main call being a real channel, -+ /* This is a three way call, the main call being a real channel, - and we're parking the first call. */ - ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL); - ast_verb(3, "Parking call to '%s'\n", chan->name); -@@ -6713,29 +8798,29 @@ - ast_set_callerid(chan, p->cid_num, p->cid_name, NULL); - res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL); - if (res) { -- ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", -+ ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", - chan->name, strerror(errno)); - } - len = 0; - memset(exten, 0, sizeof(exten)); - timeout = firstdigittimeout; - } else if (!strcmp(exten, "*0")) { -- struct ast_channel *nbridge = -+ struct ast_channel *nbridge = - p->subs[SUB_THREEWAY].owner; - struct dahdi_pvt *pbridge = NULL; -- /* set up the private struct of the bridged one, if any */ -- if (nbridge && ast_bridged_channel(nbridge)) -+ /* set up the private struct of the bridged one, if any */ -+ if (nbridge && ast_bridged_channel(nbridge)) - pbridge = ast_bridged_channel(nbridge)->tech_pvt; -- if (nbridge && pbridge && -- (nbridge->tech == &dahdi_tech) && -- (ast_bridged_channel(nbridge)->tech == &dahdi_tech) && -- ISTRUNK(pbridge)) { -+ if (nbridge && pbridge && -+ (nbridge->tech == &dahdi_tech) && -+ (ast_bridged_channel(nbridge)->tech == &dahdi_tech) && -+ ISTRUNK(pbridge)) { - int func = DAHDI_FLASH; - /* Clear out the dial buffer */ - p->dop.dialstr[0] = '\0'; - /* flash hookswitch */ - if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) { -- ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", -+ ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", - nbridge->name, strerror(errno)); - } - swap_subs(p, SUB_REAL, SUB_THREEWAY); -@@ -6754,7 +8839,7 @@ - p->owner = p->subs[SUB_REAL].owner; - ast_hangup(chan); - goto quit; -- } -+ } - } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) && - ((exten[0] != '*') || (strlen(exten) > 2))) { - ast_debug(1, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "", chan->context); -@@ -6819,7 +8904,7 @@ - } - - if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) { -- number = smdi_msg->calling_st; -+ number = smdi_msg->calling_st; - - /* 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, -@@ -6841,7 +8926,7 @@ - "Exiting simple switch\n"); - ast_hangup(chan); - goto quit; -- } -+ } - f = ast_read(chan); - if (!f) - break; -@@ -6852,7 +8937,7 @@ - } - ast_frfree(f); - if (chan->_state == AST_STATE_RING || -- chan->_state == AST_STATE_RINGING) -+ chan->_state == AST_STATE_RINGING) - break; /* Got ring */ - } - dtmfbuf[k] = '\0'; -@@ -6860,10 +8945,10 @@ - /* Got cid and ring. */ - ast_debug(1, "CID got string '%s'\n", dtmfbuf); - callerid_get_dtmf(dtmfbuf, dtmfcid, &flags); -- ast_debug(1, "CID is '%s', flags %d\n", -+ ast_debug(1, "CID is '%s', flags %d\n", - dtmfcid, flags); - /* If first byte is NULL, we have no cid */ -- if (!ast_strlen_zero(dtmfcid)) -+ if (!ast_strlen_zero(dtmfcid)) - number = dtmfcid; - else - number = NULL; -@@ -6877,11 +8962,11 @@ - #endif - /* Take out of linear mode for Caller*ID processing */ - dahdi_setlinear(p->subs[idx].dfd, 0); -- -+ - /* First we wait and listen for the Caller*ID */ -- for (;;) { -+ for (;;) { - i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; -- if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { -+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { - ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); - callerid_free(cs); - ast_hangup(chan); -@@ -6913,7 +8998,7 @@ - } - samples += res; - -- if (p->cid_signalling == CID_SIG_V23_JP) { -+ if (p->cid_signalling == CID_SIG_V23_JP) { - res = callerid_feed_jp(cs, buf, res, AST_LAW(p)); - } else { - res = callerid_feed(cs, buf, res, AST_LAW(p)); -@@ -6939,7 +9024,7 @@ - res = 4000; - } else { - -- /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ -+ /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ - res = 2000; - } - -@@ -6951,7 +9036,7 @@ - "Exiting simple switch\n"); - ast_hangup(chan); - goto quit; -- } -+ } - if (!(f = ast_read(chan))) { - ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n"); - ast_hangup(chan); -@@ -6959,13 +9044,13 @@ - } - ast_frfree(f); - if (chan->_state == AST_STATE_RING || -- chan->_state == AST_STATE_RINGING) -+ chan->_state == AST_STATE_RINGING) - break; /* Got ring */ - } -- -+ - /* We must have a ring by now, so, if configured, lets try to listen for -- * distinctive ringing */ -- if (p->usedistinctiveringdetection == 1) { -+ * distinctive ringing */ -+ if (p->usedistinctiveringdetection) { - len = 0; - distMatches = 0; - /* Clear the current ring data array so we dont have old data in it. */ -@@ -6979,10 +9064,10 @@ - ast_copy_string(p->context, p->defcontext, sizeof(p->context)); - ast_copy_string(chan->context,p->defcontext,sizeof(chan->context)); - } -- -- for (;;) { -+ -+ for (;;) { - i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; -- if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { -+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { - ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); - callerid_free(cs); - ast_hangup(chan); -@@ -6993,9 +9078,9 @@ - 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 < p->ringt_base/2) - break; - /* Increment the ringT counter so we can match it against -@@ -7013,7 +9098,7 @@ - } - break; - } -- if (p->ringt) -+ if (p->ringt) - p->ringt--; - if (p->ringt == 1) { - res = -1; -@@ -7033,9 +9118,8 @@ - ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n", - curRingData[counter1]); - distMatches++; -- } -- else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) && -- curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) { -+ } else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) && -+ curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) { - ast_verb(3, "Ring pattern matched in range: %d to %d\n", - (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range), - (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range)); -@@ -7056,153 +9140,83 @@ - dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); - #if 1 - restore_gains(p); --#endif -+#endif - } else -- ast_log(LOG_WARNING, "Unable to get caller ID space\n"); -+ ast_log(LOG_WARNING, "Unable to get caller ID space\n"); - } else { - ast_log(LOG_WARNING, "Channel %s in prering " - "state, but I have nothing to do. " - "Terminating simple switch, should be " -- "restarted by the actual ring.\n", -+ "restarted by the actual ring.\n", - chan->name); - ast_hangup(chan); - goto quit; - } - } else if (p->use_callerid && p->cid_start == CID_START_RING) { -- if (p->cid_signalling == CID_SIG_DTMF) { -- int k = 0; -- cs = NULL; -- dahdi_setlinear(p->subs[idx].dfd, 0); -- res = 2000; -- for (;;) { -- struct ast_frame *f; -- res = ast_waitfor(chan, res); -- if (res <= 0) { -- ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. " -- "Exiting simple switch\n"); -- ast_hangup(chan); -- return NULL; -- } -- f = ast_read(chan); -- if (f->frametype == AST_FRAME_DTMF) { -- dtmfbuf[k++] = f->subclass; -- ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass); -- res = 2000; -- } -- ast_frfree(f); -- -- if (p->ringt_base == p->ringt) -- break; -- -- } -- dtmfbuf[k] = '\0'; -- dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); -- /* Got cid and ring. */ -- callerid_get_dtmf(dtmfbuf, dtmfcid, &flags); -- ast_log(LOG_DEBUG, "CID is '%s', flags %d\n", -- dtmfcid, flags); -- /* If first byte is NULL, we have no cid */ -- if (!ast_strlen_zero(dtmfcid)) -- number = dtmfcid; -- else -- number = NULL; -- /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */ -- } else { -- /* FSK Bell202 callerID */ -- cs = callerid_new(p->cid_signalling); -- if (cs) { --#if 1 -- bump_gains(p); --#endif -- samples = 0; -- len = 0; -- distMatches = 0; -- /* Clear the current ring data array so we dont have old data in it. */ -- for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); 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) { -- ast_copy_string(p->context, p->defcontext, sizeof(p->context)); -- ast_copy_string(chan->context,p->defcontext,sizeof(chan->context)); -- } -- -- /* Take out of linear mode for Caller*ID processing */ -+ if (p->cid_signalling == CID_SIG_DTMF) { -+ int k = 0; -+ cs = NULL; - dahdi_setlinear(p->subs[idx].dfd, 0); -- for (;;) { -- i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; -- if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { -- ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); -- callerid_free(cs); -+ res = 2000; -+ for (;;) { -+ struct ast_frame *f; -+ res = ast_waitfor(chan, res); -+ if (res <= 0) { -+ ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. " -+ "Exiting simple switch\n"); - ast_hangup(chan); -- goto quit; -+ return NULL; - } -- if (i & DAHDI_IOMUX_SIGEVENT) { -- res = dahdi_get_event(p->subs[idx].dfd); -- ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res)); -- /* If we get a PR event, they hung up while processing calerid */ -- if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) { -- ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel); -- p->polarity = POLARITY_IDLE; -- callerid_free(cs); -- ast_hangup(chan); -- goto quit; -- } -- res = 0; -- /* Let us detect callerid when the telco uses distinctive ring */ -+ f = ast_read(chan); -+ if (f->frametype == AST_FRAME_DTMF) { -+ dtmfbuf[k++] = f->subclass; -+ ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass); -+ res = 2000; -+ } -+ ast_frfree(f); - -- curRingData[receivedRingT] = p->ringt; -- -- if (p->ringt < p->ringt_base/2) -- break; -- /* Increment the ringT counter so we can match it against -- values in chan_dahdi.conf for distinctive ring */ -- if (++receivedRingT == ARRAY_LEN(curRingData)) -- break; -- } else if (i & DAHDI_IOMUX_READ) { -- res = read(p->subs[idx].dfd, 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); -- goto quit; -- } -- break; -- } -- if (p->ringt) -- p->ringt--; -- if (p->ringt == 1) { -- res = -1; -- break; -- } -- samples += res; -- res = callerid_feed(cs, buf, res, AST_LAW(p)); -- if (res < 0) { -- ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno)); -- break; -- } else if (res) -- break; -- else if (samples > (8000 * 10)) -- break; -- } -+ if (p->ringt_base == p->ringt) -+ break; - } -- if (res == 1) { -- callerid_get(cs, &name, &number, &flags); -- ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags); -- } -- if (distinctiveringaftercid == 1) { -+ dtmfbuf[k] = '\0'; -+ dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); -+ /* Got cid and ring. */ -+ callerid_get_dtmf(dtmfbuf, dtmfcid, &flags); -+ ast_log(LOG_DEBUG, "CID is '%s', flags %d\n", -+ dtmfcid, flags); -+ /* If first byte is NULL, we have no cid */ -+ if (!ast_strlen_zero(dtmfcid)) -+ number = dtmfcid; -+ else -+ number = NULL; -+ /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */ -+ } else { -+ /* FSK Bell202 callerID */ -+ cs = callerid_new(p->cid_signalling); -+ if (cs) { -+#if 1 -+ bump_gains(p); -+#endif -+ samples = 0; -+ len = 0; -+ distMatches = 0; - /* Clear the current ring data array so we dont have old data in it. */ -- for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) { -+ for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); 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) { -+ ast_copy_string(p->context, p->defcontext, sizeof(p->context)); -+ ast_copy_string(chan->context,p->defcontext,sizeof(chan->context)); - } -- receivedRingT = 0; -- ast_verb(3, "Detecting post-CID distinctive ring\n"); -+ -+ /* Take out of linear mode for Caller*ID processing */ -+ dahdi_setlinear(p->subs[idx].dfd, 0); - for (;;) { - i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; -- if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { -+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { - ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); - callerid_free(cs); - ast_hangup(chan); -@@ -7211,6 +9225,14 @@ - if (i & DAHDI_IOMUX_SIGEVENT) { - res = dahdi_get_event(p->subs[idx].dfd); - ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res)); -+ /* If we get a PR event, they hung up while processing calerid */ -+ if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) { -+ ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel); -+ p->polarity = POLARITY_IDLE; -+ callerid_free(cs); -+ ast_hangup(chan); -+ goto quit; -+ } - res = 0; - /* Let us detect callerid when the telco uses distinctive ring */ - -@@ -7233,65 +9255,125 @@ - } - break; - } -- if (p->ringt) -- p->ringt--; -+ if (p->ringt) -+ p->ringt--; - if (p->ringt == 1) { - res = -1; - break; - } -+ samples += res; -+ res = callerid_feed(cs, buf, res, AST_LAW(p)); -+ if (res < 0) { -+ ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno)); -+ break; -+ } else if (res) -+ break; -+ else if (samples > (8000 * 10)) -+ break; - } - } -- } -- if (p->usedistinctiveringdetection == 1) { -+ if (res == 1) { -+ callerid_get(cs, &name, &number, &flags); -+ ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags); -+ } -+ if (distinctiveringaftercid == 1) { -+ /* 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; -+ ast_verb(3, "Detecting post-CID distinctive ring\n"); -+ for (;;) { -+ i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; -+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) { -+ ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); -+ callerid_free(cs); -+ ast_hangup(chan); -+ goto quit; -+ } -+ if (i & DAHDI_IOMUX_SIGEVENT) { -+ res = dahdi_get_event(p->subs[idx].dfd); -+ ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res)); -+ res = 0; -+ /* Let us detect callerid when the telco uses distinctive ring */ -+ -+ curRingData[receivedRingT] = p->ringt; -+ -+ if (p->ringt < p->ringt_base/2) -+ break; -+ /* Increment the ringT counter so we can match it against -+ values in chan_dahdi.conf for distinctive ring */ -+ if (++receivedRingT == ARRAY_LEN(curRingData)) -+ break; -+ } else if (i & DAHDI_IOMUX_READ) { -+ res = read(p->subs[idx].dfd, 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); -+ goto quit; -+ } -+ break; -+ } -+ if (p->ringt) -+ p->ringt--; -+ if (p->ringt == 1) { -+ res = -1; -+ break; -+ } -+ } -+ } -+ } -+ if (p->usedistinctiveringdetection) { - /* this only shows up if you have n of the dring patterns filled in */ -- ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]); -+ ast_verb(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 chan_dahdi.conf for this -- channel */ -+ for (counter = 0; counter < 3; counter++) { -+ /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this -+ channel */ - /* this only shows up if you have n of the dring patterns filled in */ -- ast_verb(3, "Checking %d,%d,%d\n", -- p->drings.ringnum[counter].ring[0], -- p->drings.ringnum[counter].ring[1], -- p->drings.ringnum[counter].ring[2]); -- distMatches = 0; -- for (counter1 = 0; counter1 < 3; counter1++) { -- ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range); -- if (p->drings.ringnum[counter].ring[counter1] == -1) { -- ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n", -- curRingData[counter1]); -- distMatches++; -+ ast_verb(3, "Checking %d,%d,%d\n", -+ p->drings.ringnum[counter].ring[0], -+ p->drings.ringnum[counter].ring[1], -+ p->drings.ringnum[counter].ring[2]); -+ distMatches = 0; -+ for (counter1 = 0; counter1 < 3; counter1++) { -+ ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range); -+ if (p->drings.ringnum[counter].ring[counter1] == -1) { -+ ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n", -+ curRingData[counter1]); -+ distMatches++; -+ } -+ else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) && -+ curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) { -+ ast_verb(3, "Ring pattern matched in range: %d to %d\n", -+ (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range), -+ (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range)); -+ distMatches++; -+ } - } -- else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) && -- curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) { -- ast_verb(3, "Ring pattern matched in range: %d to %d\n", -- (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range), -- (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range)); -- distMatches++; -+ if (distMatches == 3) { -+ /* The ring matches, set the context to whatever is for distinctive ring.. */ -+ ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)); -+ ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)); -+ ast_verb(3, "Distinctive Ring matched context %s\n",p->context); -+ break; - } - } -- if (distMatches == 3) { -- /* The ring matches, set the context to whatever is for distinctive ring.. */ -- ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context)); -- ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context)); -- ast_verb(3, "Distinctive Ring matched context %s\n",p->context); -- break; -- } - } -- } -- /* Restore linear mode (if appropriate) for Caller*ID processing */ -- dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); -+ /* Restore linear mode (if appropriate) for Caller*ID processing */ -+ dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear); - #if 1 -- restore_gains(p); --#endif -- if (res < 0) { -- ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name); -- } -- } else -- ast_log(LOG_WARNING, "Unable to get caller ID space\n"); -- } -- } -- else -+ restore_gains(p); -+#endif -+ if (res < 0) { -+ ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name); -+ } -+ } else -+ ast_log(LOG_WARNING, "Unable to get caller ID space\n"); -+ } -+ } else - cs = NULL; - - if (number) -@@ -7380,18 +9462,18 @@ - int i, res; - unsigned int spill_done = 0; - int spill_result = -1; -- -+ - if (!(cs = callerid_new(mtd->pvt->cid_signalling))) { - mtd->pvt->mwimonitoractive = 0; - - return NULL; - } -- -+ - callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt)); - - bump_gains(mtd->pvt); - -- for (;;) { -+ for (;;) { - i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; - if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) { - ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); -@@ -7426,7 +9508,7 @@ - default: - ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to ss_thread\n", res, event2str(res)); - callerid_free(cs); -- -+ - restore_gains(mtd->pvt); - mtd->pvt->ringt = mtd->pvt->ringt_base; - -@@ -7500,170 +9582,198 @@ - return NULL; - } - --/* States for sending MWI message -- * First three states are required for send Ring Pulse Alert Signal -- */ --enum mwisend_states { -- MWI_SEND_SA, -- MWI_SEND_SA_WAIT, -- MWI_SEND_PAUSE, -- MWI_SEND_SPILL, -- MWI_SEND_CLEANUP, -- MWI_SEND_DONE --}; -- --static void *mwi_send_thread(void *data) -+/* -+* The following three functions (mwi_send_init, mwi_send_process_buffer, -+* mwi_send_process_event) work with the do_monitor thread to generate mwi spills -+* that are sent out via FXA port on voicemail state change. The execution of -+* the mwi send is state driven and can either generate a ring pulse prior to -+* sending the fsk spill or simply send an fsk spill. -+*/ -+static int mwi_send_init(struct dahdi_pvt * pvt) - { -- struct mwi_thread_data *mtd = data; -- struct timeval timeout_basis, suspend, now; -- int x, i, res; -- int num_read; -- enum mwisend_states mwi_send_state = MWI_SEND_SPILL; /*Assume FSK only */ -+ int x, res; - -- ast_mutex_lock(&mwi_thread_lock); -- mwi_thread_count++; -- ast_mutex_unlock(&mwi_thread_lock); -- -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI - /* Determine how this spill is to be sent */ -- if(mwisend_rpas) { -- mwi_send_state = MWI_SEND_SA; -+ if (pvt->mwisend_rpas) { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_SA; -+ pvt->mwisendactive = 1; -+ } else if (pvt->mwisend_fsk) { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_SPILL; -+ pvt->mwisendactive = 1; -+ } else { -+ pvt->mwisendactive = 0; -+ return 0; - } -+#else -+ if (mwisend_rpas) { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_SA; -+ } else { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_SPILL; -+ } -+ pvt->mwisendactive = 1; -+#endif - -- gettimeofday(&timeout_basis, NULL); -- -- mtd->pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE); -- if (!mtd->pvt->cidspill) { -- mtd->pvt->mwisendactive = 0; -- ast_free(mtd); -- return NULL; -+ if (pvt->cidspill) { -+ ast_log(LOG_WARNING, "cidspill already exists when trying to send FSK MWI\n"); -+ ast_free(pvt->cidspill); -+ pvt->cidspill = NULL; -+ pvt->cidpos = 0; -+ pvt->cidlen = 0; - } -+ pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE); -+ if (!pvt->cidspill) { -+ pvt->mwisendactive = 0; -+ return -1; -+ } - x = DAHDI_FLUSH_BOTH; -- res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x); -+ res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x); - x = 3000; -- ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x); -- mtd->pvt->cidlen = vmwi_generate(mtd->pvt->cidspill, has_voicemail(mtd->pvt), CID_MWI_TYPE_MDMF_FULL, -- AST_LAW(mtd->pvt), mtd->pvt->cid_name, mtd->pvt->cid_num, 0); -- mtd->pvt->cidpos = 0; -+ ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x); -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ if (pvt->mwisend_fsk) { -+#endif -+ pvt->cidlen = vmwi_generate(pvt->cidspill, has_voicemail(pvt), CID_MWI_TYPE_MDMF_FULL, -+ AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0); -+ pvt->cidpos = 0; -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ } -+#endif -+ return 0; -+} - -- while (MWI_SEND_DONE != mwi_send_state) { -- num_read = 0; -- gettimeofday(&now, NULL); -- if ( 10 < (now.tv_sec - timeout_basis.tv_sec)) { -- ast_log(LOG_WARNING, "MWI Send TIMEOUT in state %d\n", mwi_send_state); -- goto quit; -- } -+static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read) -+{ -+ struct timeval now; -+ int res; - -- i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT; -- if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) { -- ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); -- goto quit; -- } -- -- if (i & DAHDI_IOMUX_SIGEVENT) { -- /* If we get an event, screen out events that we do not act on. -- * Otherwise, let handle_init_event determine what is needed -- */ -- res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd); -- switch (res) { -- case DAHDI_EVENT_RINGEROFF: -- if(mwi_send_state == MWI_SEND_SA_WAIT) { -- if (dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) { -- ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s\n", strerror(errno)); -- goto quit; -- } -- mwi_send_state = MWI_SEND_PAUSE; -- gettimeofday(&suspend, NULL); -- } -- break; -- case DAHDI_EVENT_RINGERON: -- case DAHDI_EVENT_HOOKCOMPLETE: -- break; -- default: -- /* Got to the default init event handler */ -- if (0 < handle_init_event(mtd->pvt, res)) { -- /* I've spawned a thread, get out */ -- goto quit; -- } -- break; -+ /* sanity check to catch if this had been interrupted previously -+ * i.e. state says there is more to do but there is no spill allocated -+ */ -+ if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_DONE; -+ } else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) { -+ /* Normal processing -- Perform mwi send action */ -+ switch ( pvt->mwisend_data.mwisend_current) { -+ case MWI_SEND_SA: -+ /* Send the Ring Pulse Signal Alert */ -+ res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence); -+ if (res) { -+ ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno)); -+ goto quit; - } -- } else if (i & DAHDI_IOMUX_READ) { -- if ((num_read = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) { -- if (errno != ELAST) { -- ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno)); -- goto quit; -+ res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING); -+ pvt->mwisend_data.mwisend_current = MWI_SEND_SA_WAIT; -+ break; -+ case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */ -+ break; -+ case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/ -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ if (pvt->mwisend_fsk) { -+#endif -+ gettimeofday(&now, NULL); -+ if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_SPILL; - } -- break; -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ } else { /* support for mwisendtype=nofsk */ -+ pvt->mwisend_data.mwisend_current = MWI_SEND_CLEANUP; - } -- } -- /* Perform mwi send action */ -- switch ( mwi_send_state) { -- case MWI_SEND_SA: -- /* Send the Ring Pulse Signal Alert */ -- res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence); -- if (res) { -- ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno)); -+#endif -+ break; -+ case MWI_SEND_SPILL: -+ /* We read some number of bytes. Write an equal amount of data */ -+ if(0 < num_read) { -+ if (num_read > pvt->cidlen - pvt->cidpos) -+ num_read = pvt->cidlen - pvt->cidpos; -+ res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read); -+ if (res > 0) { -+ pvt->cidpos += res; -+ if (pvt->cidpos >= pvt->cidlen) { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_CLEANUP; -+ } -+ } else { -+ ast_log(LOG_WARNING, "MWI FSK Send Write failed: %s\n", strerror(errno)); - goto quit; - } -- dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RING); -- mwi_send_state = MWI_SEND_SA_WAIT; -- break; -- case MWI_SEND_SA_WAIT: /* do nothing until I get RINGEROFF event */ -- break; -- case MWI_SEND_PAUSE: /* Wait between alert and spill - min of 500 mS*/ -- gettimeofday(&now, NULL); -- if ((int)(now.tv_sec - suspend.tv_sec) * 1000000 + (int)now.tv_usec - (int)suspend.tv_usec > 500000) { -- mwi_send_state = MWI_SEND_SPILL; -- } -- break; -- case MWI_SEND_SPILL: -- /* We read some number of bytes. Write an equal amount of data */ -- if(0 < num_read) { -- if (num_read > mtd->pvt->cidlen - mtd->pvt->cidpos) -- num_read = mtd->pvt->cidlen - mtd->pvt->cidpos; -- res = write(mtd->pvt->subs[SUB_REAL].dfd, mtd->pvt->cidspill + mtd->pvt->cidpos, num_read); -- if (res > 0) { -- mtd->pvt->cidpos += res; -- if (mtd->pvt->cidpos >= mtd->pvt->cidlen) { -- ast_free(mtd->pvt->cidspill); -- mtd->pvt->cidspill = NULL; -- mtd->pvt->cidpos = 0; -- mtd->pvt->cidlen = 0; -- mwi_send_state = MWI_SEND_CLEANUP; -- } -- } else { -- ast_log(LOG_WARNING, "MWI Send Write failed: %s\n", strerror(errno)); -- goto quit; -- } -- } -- break; -- case MWI_SEND_CLEANUP: -- /* For now, do nothing */ -- mwi_send_state = MWI_SEND_DONE; -- break; -- default: -- /* Should not get here, punt*/ -- goto quit; -- break; -+ } -+ break; -+ case MWI_SEND_CLEANUP: -+ /* For now, do nothing */ -+ pvt->mwisend_data.mwisend_current = MWI_SEND_DONE; -+ break; -+ default: -+ /* Should not get here, punt*/ -+ goto quit; - } - } - -+ if (MWI_SEND_DONE == pvt->mwisend_data.mwisend_current) { -+ if (pvt->cidspill) { -+ ast_free(pvt->cidspill); -+ pvt->cidspill = NULL; -+ pvt->cidpos = 0; -+ pvt->cidlen = 0; -+ } -+ pvt->mwisendactive = 0; -+ } -+ return 0; - quit: -- if(mtd->pvt->cidspill) { -- ast_free(mtd->pvt->cidspill); -- mtd->pvt->cidspill = NULL; -+ if (pvt->cidspill) { -+ ast_free(pvt->cidspill); -+ pvt->cidspill = NULL; -+ pvt->cidpos = 0; -+ pvt->cidlen = 0; - } -- mtd->pvt->mwisendactive = 0; -- ast_free(mtd); -+ pvt->mwisendactive = 0; -+ return -1; -+} - -- ast_mutex_lock(&mwi_thread_lock); -- mwi_thread_count--; -- ast_cond_signal(&mwi_thread_complete); -- ast_mutex_unlock(&mwi_thread_lock); -+static int mwi_send_process_event(struct dahdi_pvt * pvt, int event) -+{ -+ int handled = 0; - -- return NULL; -+ if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) { -+ switch (event) { -+ case DAHDI_EVENT_RINGEROFF: -+ if(pvt->mwisend_data.mwisend_current == MWI_SEND_SA_WAIT) { -+ handled = 1; -+ -+ if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) { -+ ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s mwi send aborted\n", strerror(errno)); -+ if(pvt->cidspill) { -+ ast_free(pvt->cidspill); -+ pvt->cidspill = NULL; -+ } -+ pvt->mwisend_data.mwisend_current = MWI_SEND_DONE; -+ pvt->mwisendactive = 0; -+ } else { -+ pvt->mwisend_data.mwisend_current = MWI_SEND_PAUSE; -+ gettimeofday(&pvt->mwisend_data.pause, NULL); -+ } -+ } -+ break; -+ /* Going off hook, I need to punt this spill */ -+ case DAHDI_EVENT_RINGOFFHOOK: -+ if (pvt->cidspill) { -+ ast_free(pvt->cidspill); -+ pvt->cidspill = NULL; -+ pvt->cidpos = 0; -+ pvt->cidlen = 0; -+ } -+ pvt->mwisend_data.mwisend_current = MWI_SEND_DONE; -+ pvt->mwisendactive = 0; -+ break; -+ case DAHDI_EVENT_RINGERON: -+ case DAHDI_EVENT_HOOKCOMPLETE: -+ break; -+ default: -+ break; -+ } -+ } -+ return handled; - } - -- - /* destroy a DAHDI channel, identified by its number */ - static int dahdi_destroy_channel_bynum(int channel) - { -@@ -7709,6 +9819,7 @@ - case SIG_FXOGS: - case SIG_FXOKS: - res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK); -+ i->fxsoffhookstate = 1; - if (res && (errno == EBUSY)) - break; - if (i->cidspill) { -@@ -7735,7 +9846,7 @@ - res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER); - else - res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE); -- if (res < 0) -+ if (res < 0) - ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel); - if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) { - ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel); -@@ -7786,7 +9897,7 @@ - ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel); - } - ast_hangup(chan); -- } else { -+ } else { - thread_spawned = 1; - } - break; -@@ -7794,7 +9905,7 @@ - ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel); - res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION); - if (res < 0) -- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel); -+ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel); - return -1; - } - break; -@@ -7846,7 +9957,7 @@ - #ifdef ZHONE_HACK - dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK); - usleep(1); --#endif -+#endif - res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1); - dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK); - break; -@@ -7862,23 +9973,26 @@ - res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1); - return -1; - } -+ if (i->sig & __DAHDI_SIG_FXO) { -+ i->fxsoffhookstate = 0; -+ } - break; - case DAHDI_EVENT_POLARITY: - switch (i->sig) { - case SIG_FXSLS: - case SIG_FXSKS: - case SIG_FXSGS: -- /* We have already got a PR before the channel was -- created, but it wasn't handled. We need polarity -- to be REV for remote hangup detection to work. -+ /* We have already got a PR before the channel was -+ created, but it wasn't handled. We need polarity -+ to be REV for remote hangup detection to work. - At least in Spain */ - if (i->hanguponpolarityswitch) - i->polarity = POLARITY_REV; - if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) { - i->polarity = POLARITY_REV; - ast_verb(2, "Starting post polarity " -- "CID detection on channel %d\n", -- i->channel); -+ "CID detection on channel %d\n", -+ i->channel); - chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0); - if (!chan) { - ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel); -@@ -7896,8 +10010,8 @@ - } - break; - case DAHDI_EVENT_REMOVED: /* destroy channel */ -- ast_log(LOG_NOTICE, -- "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n", -+ ast_log(LOG_NOTICE, -+ "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n", - i->channel); - dahdi_destroy_channel_bynum(i->channel); - break; -@@ -7961,14 +10075,14 @@ - i = iflist; - while (i) { - if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) { -- if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive && !i->mwisendactive) { -+ if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) { - /* This needs to be watched, as it lacks an owner */ - pfds[count].fd = i->subs[SUB_REAL].dfd; - pfds[count].events = POLLPRI; - pfds[count].revents = 0; - /* If we are monitoring for VMWI or sending CID, we need to - read from the channel as well */ -- if (i->cidspill || i->mwimonitor_fsk) -+ if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk) - pfds[count].events |= POLLIN; - count++; - } -@@ -7977,7 +10091,7 @@ - } - /* Okay, now that we know what to do, release the interface lock */ - ast_mutex_unlock(&iflock); -- -+ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_testcancel(); - /* Wait at least a second for something to happen */ -@@ -8004,33 +10118,23 @@ - if (!found && ((i == last) || ((i == iflist) && !last))) { - last = i; - if (last) { -- if (!last->mwisendactive && last->sig & __DAHDI_SIG_FXO) { -+ /* Only allow MWI to be initiated on a quiescent fxs port */ -+ if (!last->mwisendactive && last->sig & __DAHDI_SIG_FXO && -+ !last->fxsoffhookstate && !last->owner && -+ !ast_strlen_zero(last->mailbox) && (thispass - last->onhooktime > 3)) { - res = has_voicemail(last); - if (last->msgstate != res) { -- -- /* This channel has a new voicemail state, -- * initiate a thread to send an MWI message -- */ -- pthread_attr_t attr; -- pthread_t threadid; -- struct mwi_thread_data *mtd; -+ /* Set driver resources for signalling VMWI */ - res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res); - if (res2) { - /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */ - ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno)); - } -- pthread_attr_init(&attr); -- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -- if ((mtd = ast_calloc(1, sizeof(*mtd)))) { -- last->msgstate = res; -- mtd->pvt = last; -- last->mwisendactive = 1; -- if (ast_pthread_create_background(&threadid, &attr, mwi_send_thread, mtd)) { -- ast_log(LOG_WARNING, "Unable to start mwi send thread on channel %d\n", last->channel); -- ast_free(mtd); -- last->mwisendactive = 0; -- } -+ /* If enabled for FSK spill then initiate it */ -+ if (mwi_send_init(last)) { -+ ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel); - } -+ last->msgstate = res; - found ++; - } - } -@@ -8048,23 +10152,23 @@ - /* Don't hold iflock while handling init events */ - ast_mutex_unlock(&iflock); - handle_init_event(i, res); -- ast_mutex_lock(&iflock); -+ ast_mutex_lock(&iflock); - } - i = i->next; - continue; -- } -+ } - pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint); - if (pollres & POLLIN) { - if (i->owner || i->subs[SUB_REAL].owner) { - #ifdef HAVE_PRI - if (!i->pri) --#endif -+#endif - ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd); - i = i->next; - continue; - } -- if (!i->cidspill && !i->mwimonitor_fsk) { -- ast_log(LOG_WARNING, "Whoa.... I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd); -+ if (!i->mwimonitor_fsk && !i->mwisendactive) { -+ ast_log(LOG_WARNING, "Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd); - i = i->next; - continue; - } -@@ -8092,6 +10196,9 @@ - } - } - } -+ if (i->mwisendactive) { -+ mwi_send_process_buffer(i, res); -+ } - } else { - ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno)); - } -@@ -8100,7 +10207,7 @@ - if (i->owner || i->subs[SUB_REAL].owner) { - #ifdef HAVE_PRI - if (!i->pri) --#endif -+#endif - ast_log(LOG_WARNING, "Whoa.... I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd); - i = i->next; - continue; -@@ -8109,8 +10216,10 @@ - ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel); - /* Don't hold iflock while handling init events */ - ast_mutex_unlock(&iflock); -- handle_init_event(i, res); -- ast_mutex_lock(&iflock); -+ if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) { -+ handle_init_event(i, res); -+ } -+ ast_mutex_lock(&iflock); - } - } - i=i->next; -@@ -8119,7 +10228,7 @@ - } - /* Never reached */ - return NULL; -- -+ - } - - static int restart_monitor(void) -@@ -8148,7 +10257,7 @@ - return 0; - } - --#ifdef HAVE_PRI -+#if defined(HAVE_PRI) - static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si) - { - int x; -@@ -8194,7 +10303,9 @@ - } - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_create_trunkgroup(int trunkgroup, int *channels) - { - struct dahdi_spaninfo si; -@@ -8210,7 +10321,7 @@ - } - } - for (y = 0; y < NUM_DCHANS; y++) { -- if (!channels[y]) -+ if (!channels[y]) - break; - memset(&si, 0, sizeof(si)); - memset(&p, 0, sizeof(p)); -@@ -8255,9 +10366,11 @@ - pris[span].span = span + 1; - close(fd); - } -- return 0; -+ return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_create_spanmap(int span, int trunkgroup, int logicalspan) - { - if (pris[span].mastertrunkgroup) { -@@ -8268,11 +10381,9 @@ - pris[span].prilogicalspan = logicalspan; - return 0; - } -+#endif /* defined(HAVE_PRI) */ - --#endif -- --#ifdef HAVE_SS7 -- -+#if defined(HAVE_SS7) - static unsigned int parse_pointcode(const char *pcstring) - { - unsigned int code1, code2, code3; -@@ -8286,7 +10397,9 @@ - - return 0; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static struct dahdi_ss7 * ss7_resolve_linkset(int linkset) - { - if ((linkset < 0) || (linkset >= NUM_SPANS)) -@@ -8294,7 +10407,7 @@ - else - return &linksets[linkset - 1]; - } --#endif /* HAVE_SS7 */ -+#endif /* defined(HAVE_SS7) */ - - /* converts a DAHDI sigtype to signalling as can be configured from - * chan_dahdi.conf. -@@ -8303,13 +10416,13 @@ - */ - static int sigtype_to_signalling(int sigtype) - { -- return sigtype; -+ return sigtype; - } - - static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, struct dahdi_pri *pri, int reloading) - { - /* Make a dahdi_pvt structure for this interface (or CRV if "pri" is specified) */ -- struct dahdi_pvt *tmp = NULL, *tmp2, *prev = NULL; -+ struct dahdi_pvt *tmp = NULL, *tmp2, *prev = NULL; - char fn[80]; - struct dahdi_bufferinfo bi; - -@@ -8453,7 +10566,7 @@ - int matchesdchan; - int x,y; - offset = 0; -- if (((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP)) -+ if (((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP)) - && ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) { - ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno)); - destroy_dahdi_pvt(&tmp); -@@ -8549,6 +10662,8 @@ - pris[span].minunused = conf->pri.minunused; - pris[span].minidle = conf->pri.minidle; - pris[span].overlapdial = conf->pri.overlapdial; -+ pris[span].qsigchannelmapping = conf->pri.qsigchannelmapping; -+ pris[span].discardremoteholdretrieval = conf->pri.discardremoteholdretrieval; - #ifdef HAVE_PRI_INBANDDISCONNECT - pris[span].inbanddisconnect = conf->pri.inbanddisconnect; - #endif -@@ -8561,7 +10676,10 @@ - ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix)); - ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix)); - pris[span].resetinterval = conf->pri.resetinterval; -- -+ if (chan_sig == SIG_PRI) { -+ pris[span].use_callingpres = conf->chan.use_callingpres; -+ } -+ - tmp->pri = &pris[span]; - tmp->prioffset = offset; - tmp->call = NULL; -@@ -8655,8 +10773,19 @@ - if (res < 0) { - ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno)); - } -- } else -+ } else { - ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno)); -+ } -+ tmp->buf_policy = conf->chan.buf_policy; -+ tmp->buf_no = conf->chan.buf_no; -+ tmp->usefaxbuffers = conf->chan.usefaxbuffers; -+ tmp->faxbuf_policy = conf->chan.faxbuf_policy; -+ tmp->faxbuf_no = conf->chan.faxbuf_no; -+ /* This is not as gnarly as it may first appear. If the ioctl above failed, we'd be setting -+ * tmp->bufsize to zero which would cause subsequent faxbuffer-related ioctl calls to fail. -+ * The reason the ioctl call above failed should to be determined before worrying about the -+ * faxbuffer-related ioctl calls */ -+ tmp->bufsize = bi.bufsize; - } - #endif - tmp->immediate = conf->chan.immediate; -@@ -8708,6 +10837,7 @@ - tmp->busy_tonelength = conf->chan.busy_tonelength; - tmp->busy_quietlength = conf->chan.busy_quietlength; - tmp->callprogress = conf->chan.callprogress; -+ tmp->waitfordialtone = conf->chan.waitfordialtone; - tmp->cancallforward = conf->chan.cancallforward; - tmp->dtmfrelax = conf->chan.dtmfrelax; - tmp->callwaiting = tmp->permcallwaiting; -@@ -8761,7 +10891,7 @@ - tmp->cid_ton = 0; - ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name)); - ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox)); -- if (!ast_strlen_zero(tmp->mailbox)) { -+ if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) { - char *mailbox, *context; - mailbox = context = ast_strdupa(tmp->mailbox); - strsep(&context, "@"); -@@ -8774,6 +10904,22 @@ - AST_EVENT_IE_END); - } - tmp->msgstate = -1; -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ tmp->mwisend_setting = conf->chan.mwisend_setting; -+ tmp->mwisend_fsk = conf->chan.mwisend_fsk; -+ tmp->mwisend_rpas = conf->chan.mwisend_rpas; -+#endif -+ if (chan_sig & __DAHDI_SIG_FXO) { -+ memset(&p, 0, sizeof(p)); -+ res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p); -+ if (!res) { -+ tmp->fxsoffhookstate = p.rxisoffhook; -+ } -+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI -+ res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting); -+#endif -+ } -+ tmp->onhooktime = time(NULL); - tmp->group = conf->chan.group; - tmp->callgroup = conf->chan.callgroup; - tmp->pickupgroup= conf->chan.pickupgroup; -@@ -8784,7 +10930,6 @@ - tmp->rxgain = conf->chan.rxgain; - tmp->txgain = conf->chan.txgain; - tmp->tonezone = conf->chan.tonezone; -- tmp->onhooktime = time(NULL); - if (tmp->subs[SUB_REAL].dfd > -1) { - set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law); - if (tmp->dsp) -@@ -8800,7 +10945,7 @@ - /* the dchannel is down so put the channel in alarm */ - if (tmp->pri && !pri_is_up(tmp->pri)) - tmp->inalarm = 1; --#endif -+#endif - if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) { - tmp->inalarm = 1; - handle_alarms(tmp, res); -@@ -8892,12 +11037,12 @@ - if (p->dnd) - return 0; - /* If guard time, definitely not */ -- if (p->guardtime && (time(NULL) < p->guardtime)) -+ if (p->guardtime && (time(NULL) < p->guardtime)) - return 0; - - if (p->locallyblocked || p->remotelyblocked) - return 0; -- -+ - /* If no owner definitely available */ - if (!p->owner) { - #ifdef HAVE_PRI -@@ -8956,7 +11101,7 @@ - } - - /* If it's not an FXO, forget about call wait */ -- if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS)) -+ if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS)) - return 0; - - if (!p->callwaiting) { -@@ -8968,9 +11113,9 @@ - /* If there is already a call waiting call, then we can't take a second one */ - return 0; - } -- -+ - if ((p->owner->_state != AST_STATE_UP) && -- ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) { -+ ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) { - /* If the current call is not up, then don't allow the call */ - return 0; - } -@@ -8982,19 +11127,23 @@ - return 1; - } - --static struct dahdi_pvt *chandup(struct dahdi_pvt *src) -+/* This function can *ONLY* be used for copying pseudo (CHAN_PSEUDO) private -+ structures; it makes no attempt to safely copy regular channel private -+ structures that might contain reference-counted object pointers and other -+ scary bits -+*/ -+static struct dahdi_pvt *duplicate_pseudo(struct dahdi_pvt *src) - { - struct dahdi_pvt *p; - struct dahdi_bufferinfo bi; - int res; -- -+ - if ((p = ast_malloc(sizeof(*p)))) { - memcpy(p, src, sizeof(struct dahdi_pvt)); - ast_mutex_init(&p->lock); - p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo"); -- /* Allocate a dahdi structure */ - if (p->subs[SUB_REAL].dfd < 0) { -- ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno)); -+ ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno)); - destroy_dahdi_pvt(&p); - return NULL; - } -@@ -9018,9 +11167,8 @@ - iflist->next->prev = p; - return p; - } -- - --#ifdef HAVE_PRI -+#if defined(HAVE_PRI) - static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards) - { - int x; -@@ -9034,7 +11182,7 @@ - if (!backwards && (x >= pri->numchans)) - break; - if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) { -- ast_debug(1, "Found empty available channel %d/%d\n", -+ ast_debug(1, "Found empty available channel %d/%d\n", - pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset); - return x; - } -@@ -9045,7 +11193,7 @@ - } - return -1; - } --#endif -+#endif /* defined(HAVE_PRI) */ - - static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause) - { -@@ -9067,12 +11215,29 @@ - int bearer = -1; - int trunkgroup; - struct dahdi_pri *pri=NULL; --#endif -+#endif - struct dahdi_pvt *exitpvt, *start, *end; - ast_mutex_t *lock; - int channelmatched = 0; - int groupmatched = 0; -- -+ -+ /* -+ * data is ---v -+ * Dial(DAHDI/pseudo[/extension]) -+ * Dial(DAHDI/[c|r|d][/extension]) -+ * Dial(DAHDI/:[c|r|d][/extension]) -+ * Dial(DAHDI/(g|G|r|R)[c|r|d][/extension]) -+ * -+ * g - channel group allocation search forward -+ * G - channel group allocation search backward -+ * r - channel group allocation round robin search forward -+ * R - channel group allocation round robin search backward -+ * -+ * c - Wait for DTMF digit to confirm answer -+ * r - Set distintive ring cadance number -+ * d - Force bearer capability for ISDN/SS7 call to digital. -+ */ -+ - /* Assume we're locking the iflock */ - lock = &iflock; - start = iflist; -@@ -9085,8 +11250,9 @@ - } - if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') { - /* Retrieve the group number */ -- char *stringp=NULL; -- stringp=dest + 1; -+ char *stringp; -+ -+ 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); -@@ -9113,15 +11279,16 @@ - roundrobin = 1; - } - } else { -- char *stringp=NULL; -- stringp=dest; -+ char *stringp; -+ -+ stringp = dest; - s = strsep(&stringp, "/"); - p = iflist; - if (!strcasecmp(s, "pseudo")) { - /* Special case for pseudo */ - x = CHAN_PSEUDO; - channelmatch = x; -- } -+ } - #ifdef HAVE_PRI - else if ((res = sscanf(s, "%d:%d%c%d", &trunkgroup, &crv, &opt, &y)) > 1) { - if ((trunkgroup < 1) || (crv < 1)) { -@@ -9145,7 +11312,7 @@ - channelmatch = crv; - p = pris[x].crvs; - } --#endif -+#endif - 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 NULL; -@@ -9165,7 +11332,7 @@ - - if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) { - ast_debug(1, "Using channel %d\n", p->channel); -- if (p->inalarm) -+ if (p->inalarm) - goto next; - - callwait = (p->owner != NULL); -@@ -9192,9 +11359,9 @@ - p->pri = pri; - } - } --#endif -+#endif - if (p->channel == CHAN_PSEUDO) { -- p = chandup(p); -+ p = duplicate_pseudo(p); - if (!p) { - break; - } -@@ -9212,7 +11379,7 @@ - /* Log owner to bearer channel, too */ - p->bearer->owner = tmp; - } --#endif -+#endif - /* Make special notes */ - if (res > 1) { - if (opt == 'c') { -@@ -9229,6 +11396,11 @@ - p->digital = 1; - if (tmp) - tmp->transfercapability = AST_TRANS_CAP_DIGITAL; -+#if defined(HAVE_PRI) -+ } else if (opt == 'q') { -+ /* Append CC-Ringout facility */ -+ p->ccringout = 1; -+#endif /* defined(HAVE_PRI) */ - } else { - ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data); - } -@@ -9264,7 +11436,7 @@ - *cause = AST_CAUSE_CONGESTION; - } - } -- -+ - return tmp; - } - -@@ -9273,10 +11445,9 @@ - { - return ioctl(dfd, DAHDI_SETLAW, &law); - } --#endif -+#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ - --#ifdef HAVE_SS7 -- -+#if defined(HAVE_SS7) - static int ss7_find_cic(struct dahdi_ss7 *linkset, int cic, unsigned int dpc) - { - int i; -@@ -9289,7 +11460,9 @@ - } - return winner; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void ss7_handle_cqm(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc) - { - unsigned char status[32]; -@@ -9319,9 +11492,27 @@ - isup_cqr(linkset->ss7, startcic, endcic, dpc, status); - else - ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n"); -- -+ - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) -+static inline void ss7_hangup_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc) -+{ -+ int i; -+ -+ for (i = 0; i < linkset->numchans; i++) { -+ if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) { -+ ast_mutex_lock(&linkset->pvts[i]->lock); -+ if (linkset->pvts[i]->owner) -+ linkset->pvts[i]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -+ ast_mutex_unlock(&linkset->pvts[i]->lock); -+ } -+ } -+} -+#endif /* defined(HAVE_SS7) */ -+ -+#if defined(HAVE_SS7) - static inline void ss7_block_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block) - { - int i; -@@ -9336,7 +11527,9 @@ - } - } - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void ss7_inservice(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc) - { - int i; -@@ -9346,7 +11539,9 @@ - linkset->pvts[i]->inservice = 1; - } - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void ss7_reset_linkset(struct dahdi_ss7 *linkset) - { - int i, startcic = -1, endcic, dpc; -@@ -9374,7 +11569,9 @@ - } - } - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void dahdi_loopback(struct dahdi_pvt *p, int enable) - { - if (p->loopedback != enable) { -@@ -9385,7 +11582,9 @@ - p->loopedback = enable; - } - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - /* XXX: This function is assumed to be called with the private channel lock and linkset lock held */ - static void ss7_start_call(struct dahdi_pvt *p, struct dahdi_ss7 *linkset) - { -@@ -9397,16 +11596,16 @@ - - if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1) - ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, law, strerror(errno)); -- -+ - if (linkset->type == SS7_ITU) - law = DAHDI_LAW_ALAW; - else - law = DAHDI_LAW_MULAW; - - res = dahdi_setlaw(p->subs[SUB_REAL].dfd, law); -- if (res < 0) -+ if (res < 0) - ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel); -- -+ - if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) { - p->proceeding = 1; - isup_acm(ss7, p->ss7call); -@@ -9502,7 +11701,9 @@ - ast_mutex_lock(&p->lock); - ast_mutex_lock(&linkset->lock); - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void ss7_apply_plan_to_number(char *buf, size_t size, const struct dahdi_ss7 *ss7, const char *number, const unsigned nai) - { - switch (nai) { -@@ -9523,11 +11724,16 @@ - break; - } - } -+#endif /* defined(HAVE_SS7) */ -+ -+#if defined(HAVE_SS7) - static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind) - { -- return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3); -+ return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3); - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void *ss7_linkset(void *data) - { - int res, i; -@@ -9615,15 +11821,11 @@ - } - - if (pollers[i].revents & POLLIN) { -- ast_mutex_lock(&linkset->lock); - res = ss7_read(ss7, pollers[i].fd); -- ast_mutex_unlock(&linkset->lock); - } - - if (pollers[i].revents & POLLOUT) { -- ast_mutex_lock(&linkset->lock); - res = ss7_write(ss7, pollers[i].fd); -- ast_mutex_unlock(&linkset->lock); - if (res < 0) { - ast_debug(1, "Error in write %s\n", strerror(errno)); - } -@@ -9675,8 +11877,8 @@ - dahdi_queue_frame(p, &f, linkset); - p->progress = 1; - if (p->dsp && p->dsp_features) { -- ast_dsp_set_features(p->dsp, p->dsp_features); -- p->dsp_features = 0; -+ ast_dsp_set_features(p->dsp, p->dsp_features); -+ p->dsp_features = 0; - } - } - break; -@@ -9716,6 +11918,7 @@ - p = linkset->pvts[chanpos]; - isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc); - ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0); -+ ss7_hangup_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc); - break; - case ISUP_EVENT_CQM: - ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic); -@@ -9775,7 +11978,7 @@ - ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name)); - else - p->cid_name[0] = '\0'; -- -+ - p->cid_ani2 = e->iam.oli_ani2; - p->cid_ton = 0; - ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number)); -@@ -9792,11 +11995,11 @@ - ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num)); - ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name)); - p->calling_party_cat = e->iam.calling_party_cat; -- -+ - /* Set DNID */ - if (!ast_strlen_zero(e->iam.called_party_num)) - ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai); -- -+ - if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) { - - if (e->iam.cot_check_required) { -@@ -9852,13 +12055,13 @@ - ast_log(LOG_WARNING, "CVT on unconfigured CIC %d\n", e->cvt.cic); - break; - } -- -+ - p = linkset->pvts[chanpos]; -- -+ - ast_mutex_lock(&p->lock); - dahdi_loopback(p, 1); - ast_mutex_unlock(&p->lock); -- -+ - isup_cvr(linkset->ss7, e->cvt.cic, p->dpc); - break; - case ISUP_EVENT_REL: -@@ -9895,7 +12098,7 @@ - p = linkset->pvts[chanpos]; - - ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic); -- -+ - if (e->acm.call_ref_ident > 0) { - p->rlt = 1; /* Setting it but not using it here*/ - } -@@ -10011,8 +12214,8 @@ - ast_mutex_lock(&p->lock); - p->subs[SUB_REAL].needanswer = 1; - if (p->dsp && p->dsp_features) { -- ast_dsp_set_features(p->dsp, p->dsp_features); -- p->dsp_features = 0; -+ ast_dsp_set_features(p->dsp, p->dsp_features); -+ p->dsp_features = 0; - } - dahdi_enable_ec(p); - ast_mutex_unlock(&p->lock); -@@ -10059,7 +12262,9 @@ - - return 0; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void dahdi_ss7_message(struct ss7 *ss7, char *s) - { - #if 0 -@@ -10074,7 +12279,9 @@ - ast_verbose("%s", s); - #endif - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static void dahdi_ss7_error(struct ss7 *ss7, char *s) - { - #if 0 -@@ -10088,10 +12295,9 @@ - ast_log(LOG_ERROR, "%s", s); - #endif - } -+#endif /* defined(HAVE_SS7) */ - --#endif /* HAVE_SS7 */ -- --#ifdef HAVE_PRI -+#if defined(HAVE_PRI) - static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv) - { - struct dahdi_pvt *p; -@@ -10103,8 +12309,9 @@ - } - return NULL; - } -+#endif /* defined(HAVE_PRI) */ - -- -+#if defined(HAVE_PRI) - static int pri_find_principle(struct dahdi_pri *pri, int channel) - { - int x; -@@ -10128,10 +12335,12 @@ - break; - } - } -- -+ - return principle; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c) - { - int x; -@@ -10141,9 +12350,9 @@ - return -1; - return principle; - } -- if ((principle > -1) && -- (principle < pri->numchans) && -- (pri->pvts[principle]) && -+ if ((principle > -1) && -+ (principle < pri->numchans) && -+ (pri->pvts[principle]) && - (pri->pvts[principle]->call == c)) - return principle; - /* First, check for other bearers */ -@@ -10166,9 +12375,9 @@ - new->owner = old->owner; - old->owner = NULL; - if (new->owner) { -- ast_string_field_build(new->owner, name, -- "DAHDI/%d:%d-%d", pri->trunkgroup, -- new->channel, 1); -+ ast_string_field_build(new->owner, name, -+ "DAHDI/%d:%d-%d", pri->trunkgroup, -+ new->channel, 1); - new->owner->tech_pvt = new; - ast_channel_set_fd(new->owner, 0, new->subs[SUB_REAL].dfd); - new->subs[SUB_REAL].owner = old->subs[SUB_REAL].owner; -@@ -10194,7 +12403,7 @@ - /* This is our match... Perform some basic checks */ - if (crv->bearer) - ast_log(LOG_WARNING, "Trying to fix up call which already has a bearer which isn't the one we think it is\n"); -- else if (pri->pvts[principle]->owner) -+ else if (pri->pvts[principle]->owner) - ast_log(LOG_WARNING, "Tring to fix up a call to a bearer which already has an owner!\n"); - else { - /* Looks good. Drop the pseudo channel now, clear up the assignment, and -@@ -10214,7 +12423,9 @@ - ast_log(LOG_WARNING, "Call specified, but not found?\n"); - return -1; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static void *do_idle_thread(void *vchan) - { - struct ast_channel *chan = vchan; -@@ -10262,7 +12473,9 @@ - ast_hangup(chan); - return NULL; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - #ifndef PRI_RESTART - #error "Upgrade your libpri" - #endif -@@ -10304,7 +12517,9 @@ - - ast_mutex_unlock(&pridebugfdlock); - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static void dahdi_pri_error(struct pri *pri, char *s) - { - int x, y; -@@ -10343,15 +12558,17 @@ - - ast_mutex_unlock(&pridebugfdlock); - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_check_restart(struct dahdi_pri *pri) - { - do { - pri->resetpos++; - } while ((pri->resetpos < pri->numchans) && -- (!pri->pvts[pri->resetpos] || -- pri->pvts[pri->resetpos]->call || -- pri->pvts[pri->resetpos]->resetting)); -+ (!pri->pvts[pri->resetpos] || -+ pri->pvts[pri->resetpos]->call || -+ pri->pvts[pri->resetpos]->resetting)); - if (pri->resetpos < pri->numchans) { - /* Mark the channel as resetting and restart it */ - pri->pvts[pri->resetpos]->resetting = 1; -@@ -10362,7 +12579,9 @@ - } - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri) - { - int x; -@@ -10386,7 +12605,9 @@ - ast_mutex_lock(&pri->lock); - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char * redirectingreason2str(int redirectingreason) - { - switch (redirectingreason) { -@@ -10402,7 +12623,9 @@ - return "NOREDIRECT"; - } - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static void apply_plan_to_number(char *buf, size_t size, const struct dahdi_pri *pri, const char *number, const int plan) - { - if (pri->dialplan == -2) { /* autodetect the TON but leave the number untouched */ -@@ -10430,8 +12653,9 @@ - break; - } - } -+#endif /* defined(HAVE_PRI) */ - -- -+#if defined(HAVE_PRI) - static void *pri_dchannel(void *vpri) - { - struct dahdi_pri *pri = vpri; -@@ -10461,7 +12685,7 @@ - char plancallingnum[256]; - char plancallingani[256]; - char calledtonstr[10]; -- -+ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - - gettimeofday(&lastidle, NULL); -@@ -10493,7 +12717,7 @@ - numdchans = i; - time(&t); - ast_mutex_lock(&pri->lock); -- if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) { -+ if ((pri->switchtype != PRI_SWITCH_GR303_TMC) && (pri->sig != SIG_BRI_PTMP) && (pri->resetinterval > 0)) { - if (pri->resetting && pri_is_up(pri)) { - if (pri->resetpos < 0) - pri_check_restart(pri); -@@ -10510,8 +12734,8 @@ - haveidles = 0; - activeidles = 0; - for (x = pri->numchans; x >= 0; x--) { -- if (pri->pvts[x] && !pri->pvts[x]->owner && -- !pri->pvts[x]->call) { -+ if (pri->pvts[x] && !pri->pvts[x]->owner && -+ !pri->pvts[x]->call) { - if (haveidles < pri->minunused) { - haveidles++; - } else if (!pri->pvts[x]->resetting) { -@@ -10537,8 +12761,8 @@ - lastidle = ast_tvnow(); - } - } else if ((haveidles < pri->minunused) && -- (activeidles > pri->minidle)) { -- /* Mark something for hangup if there is something -+ (activeidles > pri->minidle)) { -+ /* Mark something for hangup if there is something - that can be hungup */ - for (x = pri->numchans; x >= 0; x--) { - /* find a candidate channel */ -@@ -10548,9 +12772,9 @@ - /* Stop if we have enough idle channels or - can't spare any more active idle ones */ - if ((haveidles >= pri->minunused) || -- (activeidles <= pri->minidle)) -+ (activeidles <= pri->minidle)) - break; -- } -+ } - } - } - } -@@ -10627,7 +12851,7 @@ - pri->span - ); - } -- /* Keep track of alarm state */ -+ /* Keep track of alarm state */ - if (x == DAHDI_EVENT_ALARM) { - pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP); - pri_find_dchan(pri); -@@ -10635,7 +12859,7 @@ - pri->dchanavail[which] |= DCHAN_NOTINALARM; - pri_restart(pri->dchans[which]); - } -- -+ - ast_debug(1, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span); - } else if (fds[which].revents & POLLIN) { - e = pri_check_event(pri->dchans[which]); -@@ -10708,16 +12932,21 @@ - } else if (p->owner) - p->owner->_softhangup |= AST_SOFTHANGUP_DEV; - } -- p->inalarm = 1; -+ /* For PTMP connections with non persistent layer 2 we want -+ * to *not* declare inalarm unless there actually is an alarm */ -+ if (p->sig != SIG_BRI_PTMP) { -+ p->inalarm = 1; -+ } - } - } -+ ccbsnr_destroy_all_of_span(pri); - } - break; - case PRI_EVENT_RESTART: - if (e->restart.channel > -1) { - chanpos = pri_find_principle(pri, e->restart.channel); - if (chanpos < 0) -- ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n", -+ ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n", - PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span); - else { - ast_verb(3, "B-channel %d/%d restarted on span %d\n", -@@ -10728,7 +12957,7 @@ - pri->pvts[chanpos]->call = NULL; - } - /* Force soft hangup if appropriate */ -- if (pri->pvts[chanpos]->realcall) -+ if (pri->pvts[chanpos]->realcall) - pri_hangup_all(pri->pvts[chanpos]->realcall, pri); - else if (pri->pvts[chanpos]->owner) - pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -@@ -10743,7 +12972,7 @@ - pri_destroycall(pri->pri, pri->pvts[x]->call); - pri->pvts[x]->call = NULL; - } -- if (pri->pvts[chanpos]->realcall) -+ if (pri->pvts[chanpos]->realcall) - pri_hangup_all(pri->pvts[chanpos]->realcall, pri); - else if (pri->pvts[x]->owner) - pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -@@ -10754,52 +12983,75 @@ - case PRI_EVENT_KEYPAD_DIGIT: - chanpos = pri_find_principle(pri, e->digit.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n", -+ ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n", - PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->digit.call); - if (chanpos > -1) { - ast_mutex_lock(&pri->pvts[chanpos]->lock); - /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */ -- if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) { -+ if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) -+ && pri->pvts[chanpos]->call == e->digit.call -+ && pri->pvts[chanpos]->owner) { - /* how to do that */ - int digitlen = strlen(e->digit.digits); -- char digit; -- int i; -- for (i = 0; i < digitlen; i++) { -- digit = e->digit.digits[i]; -- { -- struct ast_frame f = { AST_FRAME_DTMF, digit, }; -- dahdi_queue_frame(pri->pvts[chanpos], &f, pri); -- } -+ int i; -+ -+ for (i = 0; i < digitlen; i++) { -+ struct ast_frame f = { AST_FRAME_DTMF, e->digit.digits[i], }; -+ -+ dahdi_queue_frame(pri->pvts[chanpos], &f, pri); - } - } - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - } - } - break; -- -+ - case PRI_EVENT_INFO_RECEIVED: - chanpos = pri_find_principle(pri, e->ring.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n", -+ ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n", - PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->ring.call); - if (chanpos > -1) { - 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 & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) { -+ if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) -+ && pri->pvts[chanpos]->call == e->ring.call -+ && pri->pvts[chanpos]->owner) { - /* how to do that */ - int digitlen = strlen(e->ring.callednum); -- char digit; -- int i; -- for (i = 0; i < digitlen; i++) { -- digit = e->ring.callednum[i]; -- { -- struct ast_frame f = { AST_FRAME_DTMF, digit, }; -- dahdi_queue_frame(pri->pvts[chanpos], &f, pri); -+ int i; -+ -+ for (i = 0; i < digitlen; i++) { -+ struct ast_frame f = { AST_FRAME_DTMF, e->ring.callednum[i], }; -+ -+ dahdi_queue_frame(pri->pvts[chanpos], &f, pri); -+ } -+ if (pri->pvts[chanpos]->owner) { -+ char dnid[AST_MAX_EXTENSION]; -+ -+ /* -+ * Append the received info digits to the end of -+ * the exten and dnid strings -+ */ -+ strncat(pri->pvts[chanpos]->owner->exten, -+ e->ring.callednum, -+ sizeof(pri->pvts[chanpos]->owner->exten) - 1 -+ - strlen(pri->pvts[chanpos]->owner->exten)); -+ if (pri->pvts[chanpos]->owner->cid.cid_dnid) { -+ ast_copy_string(dnid, -+ pri->pvts[chanpos]->owner->cid.cid_dnid, -+ sizeof(dnid)); -+ ast_free(pri->pvts[chanpos]->owner->cid.cid_dnid); -+ } else { -+ dnid[0] = 0; - } -+ strncat(dnid, e->ring.callednum, -+ sizeof(dnid) - 1 - strlen(dnid)); -+ pri->pvts[chanpos]->owner->cid.cid_dnid = ast_strdup(dnid); - } - } - ast_mutex_unlock(&pri->pvts[chanpos]->lock); -@@ -10814,18 +13066,18 @@ - 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", -+ 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); - } else { - 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", -+ 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 { - /* This is where we handle initial glare */ -- ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiate channel.\n", -+ ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d. Attempting to renegotiate channel.\n", - PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span); - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - chanpos = -1; -@@ -10837,6 +13089,7 @@ - if ((chanpos < 0) && (e->ring.flexible)) - chanpos = pri_find_empty_chan(pri, 1); - if (chanpos > -1) { -+ struct ast_party_redirecting redirecting = {{0,},}; - ast_mutex_lock(&pri->pvts[chanpos]->lock); - if (pri->switchtype == PRI_SWITCH_GR303_TMC) { - /* Should be safe to lock CRV AFAIK while bearer is still locked */ -@@ -10858,6 +13111,17 @@ - break; - } - } -+ if (e->ring.redirectingnum[0] || e->ring.redirectingname[0]) { -+ redirecting.to.number = e->ring.callednum; -+ redirecting.to.number_type = e->ring.calledplan; -+ redirecting.to.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; -+ redirecting.from.name = e->ring.redirectingname; -+ redirecting.from.number = e->ring.redirectingnum; -+ redirecting.from.number_presentation = e->ring.redirectingpres; -+ redirecting.from.number_type = e->ring.callingplanrdnis; -+ redirecting.reason = pri_to_ast_reason(e->ring.redirectingreason); -+ redirecting.count = e->ring.redirectingcount; -+ } - 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) { -@@ -10881,7 +13145,7 @@ - pri->pvts[chanpos]->cid_ton = 0; - } - apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri, -- e->ring.redirectingnum, e->ring.callingplanrdnis); -+ e->ring.redirectingnum, e->ring.callingplanrdnis); - /* If immediate=yes go to s|1 */ - if (pri->pvts[chanpos]->immediate) { - ast_verb(3, "Going to extension s|1 because of immediate=yes\n"); -@@ -10924,7 +13188,7 @@ - else - law = DAHDI_LAW_MULAW; - res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law); -- if (res < 0) -+ 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].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law); - if (res < 0) -@@ -10934,16 +13198,18 @@ - pri->pvts[chanpos]->proceeding = 1; - pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0); - } else { -- if (pri->switchtype != PRI_SWITCH_GR303_TMC) -+ 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); - } - /* Get the use_callingpres state */ - pri->pvts[chanpos]->callingpres = e->ring.callingpres; -- -+ - /* Start PBX */ -- if (!e->ring.complete && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) { -+ if (!e->ring.complete -+ && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) -+ && 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); - if (crv) { -@@ -10958,6 +13224,9 @@ - - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - -+ if (c && (redirecting.from.number || redirecting.from.name)) { -+ ast_set_redirecting(c, &redirecting); -+ } - if (!ast_strlen_zero(e->ring.callingsubaddr)) { - pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr); - } -@@ -10975,9 +13244,11 @@ - - snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan); - pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr); -- if (e->ring.redirectingreason >= 0) -+ if (e->ring.redirectingreason >= 0) { -+ /* This is now just a status variable. Use REDIRECTING() dialplan function. */ - pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason)); -- -+ } -+ - ast_mutex_lock(&pri->pvts[chanpos]->lock); - ast_mutex_lock(&pri->lock); - if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) { -@@ -10985,7 +13256,7 @@ - plancallingnum, S_OR(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", -+ 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); - if (c) - ast_hangup(c); -@@ -10994,7 +13265,7 @@ - pri->pvts[chanpos]->call = NULL; - } - } -- } else { -+ } else { - ast_mutex_unlock(&pri->lock); - /* Release PRI lock while we create the channel */ - c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 1, SUB_REAL, law, e->ring.ctype); -@@ -11003,6 +13274,9 @@ - - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - -+ if (redirecting.from.number || redirecting.from.name) { -+ ast_set_redirecting(c, &redirecting); -+ } - if (e->ring.ani2 >= 0) { - snprintf(ani2str, 5, "%d", e->ring.ani2); - pbx_builtin_setvar_helper(c, "ANI2", ani2str); -@@ -11015,9 +13289,11 @@ - } - #endif - -- if (e->ring.redirectingreason >= 0) -+ if (e->ring.redirectingreason >= 0) { -+ /* This is now just a status variable. Use REDIRECTING() dialplan function. */ - pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason)); -- -+ } -+ - snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan); - pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr); - -@@ -11025,7 +13301,7 @@ - ast_mutex_lock(&pri->lock); - - ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n", -- plancallingnum, pri->pvts[chanpos]->exten, -+ plancallingnum, pri->pvts[chanpos]->exten, - pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span); - - dahdi_enable_ec(pri->pvts[chanpos]); -@@ -11033,7 +13309,7 @@ - - ast_mutex_lock(&pri->lock); - -- ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", -+ 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->pvts[chanpos]->call = NULL; -@@ -11041,7 +13317,7 @@ - } - } else { - ast_verb(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]->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->pvts[chanpos]->call = NULL; -@@ -11060,12 +13336,12 @@ - case PRI_EVENT_RINGING: - chanpos = pri_find_principle(pri, e->ringing.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n", -+ ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n", - PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n", -+ ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n", - PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span); - } else { - ast_mutex_lock(&pri->pvts[chanpos]->lock); -@@ -11076,11 +13352,13 @@ - } else - ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n"); - -+ if ( - #ifdef PRI_PROGRESS_MASK -- if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) { -+ e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE - #else -- if (e->ringing.progress == 8) { -+ e->ringing.progress == 8 - #endif -+ ) { - /* Now we can do call progress detection */ - if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) { - /* RINGING detection isn't required because we got ALERTING signal */ -@@ -11098,6 +13376,19 @@ - } - #endif - -+ if ((e->ringing.calledname[0] || e->ringing.callednum[0]) && pri->pvts[chanpos]->owner) { -+ struct ast_party_connected_line connected; -+ -+ /* Update the connected line information on the other channel */ -+ ast_party_connected_line_init(&connected); -+ connected.id.name = e->ringing.calledname; -+ connected.id.number = e->ringing.callednum; -+ connected.id.number_type = e->ringing.calledplan; -+ connected.id.number_presentation = pri_to_ast_presentation(e->ringing.calledpres); -+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_queue_connected_line_update(pri->pvts[chanpos]->owner, &connected); -+ } -+ - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - } - } -@@ -11106,11 +13397,13 @@ - /* Get chan value if e->e is not PRI_EVNT_RINGING */ - chanpos = pri_find_principle(pri, e->proceeding.channel); - if (chanpos > -1) { -+ if ((!pri->pvts[chanpos]->progress) - #ifdef PRI_PROGRESS_MASK -- if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) { -+ || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) - #else -- if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progress == 8)) { -+ || (e->proceeding.progress == 8) - #endif -+ ) { - struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, }; - - if (e->proceeding.cause > -1) { -@@ -11126,16 +13419,18 @@ - } - } - } -- -+ - ast_mutex_lock(&pri->pvts[chanpos]->lock); - ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n", - pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span); - dahdi_queue_frame(pri->pvts[chanpos], &f, pri); -+ if ( - #ifdef PRI_PROGRESS_MASK -- if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) { -+ e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE - #else -- if (e->proceeding.progress == 8) { -+ e->proceeding.progress == 8 - #endif -+ ) { - /* Now we can do call progress detection */ - if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) { - ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features); -@@ -11152,16 +13447,18 @@ - if (chanpos > -1) { - if (!pri->pvts[chanpos]->proceeding) { - struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, }; -- -+ - ast_mutex_lock(&pri->pvts[chanpos]->lock); - ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n", - pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span); - dahdi_queue_frame(pri->pvts[chanpos], &f, pri); -+ if ( - #ifdef PRI_PROGRESS_MASK -- if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) { -+ e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE - #else -- if (e->proceeding.progress == 8) { -+ e->proceeding.progress == 8 - #endif -+ ) { - /* Now we can do call progress detection */ - if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) { - ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features); -@@ -11179,168 +13476,499 @@ - case PRI_EVENT_FACNAME: - chanpos = pri_find_principle(pri, e->facname.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n", -+ ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n", - PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->facname.call); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n", -+ ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n", - PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span); - } else { - /* Re-use *69 field for PRI */ - ast_mutex_lock(&pri->pvts[chanpos]->lock); - ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num)); - ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name)); -- pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1; -+ pri->pvts[chanpos]->subs[SUB_REAL].needcallerid = 1; - dahdi_enable_ec(pri->pvts[chanpos]); - ast_mutex_unlock(&pri->pvts[chanpos]->lock); - } - } -- break; -- case PRI_EVENT_ANSWER: -- chanpos = pri_find_principle(pri, e->answer.channel); -- if (chanpos < 0) { -- ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n", -- PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ break; -+ case PRI_EVENT_FACILITY: -+ { -+ unsigned int handle; -+ int channel = e->facility.channel; -+ int ccbsnronprispan = PRI_SPAN(channel); -+ int explicit = PRI_EXPLICIT(channel); -+ int i; -+ -+ channel = PRI_CHANNEL(channel); -+ -+ ast_verb(4, -+ "PRI_EVENT_CC_FACILITY e->facility.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", -+ e->facility.channel, ccbsnronprispan, explicit, channel); -+ if (channel == 0) { -+ for (i = 0; i < e->facility.subcmds.counter_subcmd; i++) { -+ struct subcommand *subcmd = &e->facility.subcmds.subcmd[i]; -+ -+ switch (subcmd->cmd) { -+ case CMD_CC_EXECPOSIBLE_INV: -+ { -+ int cr = e->facility.cref; -+ unsigned int state; -+ -+ ast_verb(4, -+ "Facility cc-execposible INV cr %d channel %d/%d, span %d\n", -+ cr, ccbsnronprispan, channel, pri->span); -+ -+ handle = CCBS_HANDLE(ccbsnronprispan, cr); -+ state = 0; -+ ast_verb(4, -+ "Facility cc-execposible: handle=%x\n", handle); -+ if (ccbsnr_get_link(handle, &state) != NULL) { -+ if (state == CC_INVOKED_A_RET) { -+ ast_verb(4, -+ "DAHDI ccbsnr_remote_user_free: state '%d'\n", -+ state); -+ ccbsnr_remote_user_free(handle); -+ } -+ } else { -+ ast_verb(3, -+ "Facility cc-execposible: List-obj not found - handle=%x state=%d\n", -+ handle, state); -+ } -+ break; -+ } -+ default: -+ ast_log(LOG_WARNING, -+ "Illegal subcommand %d in facility request on channel %d/%d span %d\n", -+ subcmd->cmd, ccbsnronprispan, channel, pri->span); -+ break; -+ } -+ } - } else { -- chanpos = pri_fixup_principle(pri, chanpos, e->answer.call); -+ chanpos = pri_find_principle(pri, e->facility.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n", -- PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ ast_log(LOG_WARNING, "Facility requested on unconfigured channel %d/%d span %d\n", -+ PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span); - } else { -- ast_mutex_lock(&pri->pvts[chanpos]->lock); -- /* Now we can do call progress detection */ -+ chanpos = pri_fixup_principle(pri, chanpos, e->facility.call); -+ if (chanpos < 0) { -+ ast_log(LOG_WARNING, "Facility requested on channel %d/%d not in use on span %d\n", -+ PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span); -+ } else { -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ for (i = 0; i < e->facility.subcmds.counter_subcmd; i++) { -+ struct subcommand *subcmd = &e->facility.subcmds.subcmd[i]; -+ struct ast_channel *owner; - -- /* We changed this so it turns on the DSP no matter what... progress or no progress. -- * By this time, we need DTMF detection and other features that were previously disabled -- * -- Matt F */ -- if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) { -- ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features); -- pri->pvts[chanpos]->dsp_features = 0; -+ switch (subcmd->cmd) { -+ case CMD_CONNECTEDLINE: -+ owner = pri->pvts[chanpos]->owner; -+ if (owner) { -+ struct ast_party_connected_line connected; -+ struct cmd_connectedline *cmdcl; -+ -+ /* Update the connected line information on the other channel */ -+ ast_party_connected_line_init(&connected); -+ cmdcl = &subcmd->connectedline; -+ connected.id.number = cmdcl->connected.id.number; -+ connected.id.name = cmdcl->connected.id.name; -+ connected.id.number_type = cmdcl->connected.id.number_type; -+ connected.id.number_presentation = pri_to_ast_presentation(cmdcl->connected.id.number_presentation); -+ connected.source = pri_to_ast_connected_line_update_source(cmdcl->connected.source); -+ ast_queue_connected_line_update(owner, &connected); -+ -+ ast_copy_string(pri->pvts[chanpos]->lastcid_num, cmdcl->connected.id.number, sizeof(pri->pvts[chanpos]->lastcid_num)); -+ ast_copy_string(pri->pvts[chanpos]->lastcid_name, cmdcl->connected.id.name, sizeof(pri->pvts[chanpos]->lastcid_name)); -+ -+ pri->pvts[chanpos]->subs[SUB_REAL].needcallerid = 1; -+ //dahdi_enable_ec(pri->pvts[chanpos]); -+ } -+ break; -+ case CMD_REDIRECTING: -+ owner = pri->pvts[chanpos]->owner; -+ if (owner) { -+ struct ast_party_redirecting redirecting = {{0,},}; -+ struct cmd_redirecting *cmdr; -+ -+ cmdr = &subcmd->redirecting; -+ redirecting.from.number = cmdr->redirecting.from.number; -+ redirecting.from.name = cmdr->redirecting.from.name; -+ redirecting.from.number_type = cmdr->redirecting.from.number_type; -+ redirecting.from.number_presentation = pri_to_ast_presentation(cmdr->redirecting.from.number_presentation); -+ redirecting.to.number = cmdr->redirecting.to.number; -+ redirecting.to.name = cmdr->redirecting.to.name; -+ redirecting.to.number_type = cmdr->redirecting.to.number_type; -+ redirecting.to.number_presentation = pri_to_ast_presentation(cmdr->redirecting.to.number_presentation); -+ redirecting.count = 0; -+ redirecting.reason = pri_to_ast_reason(cmdr->redirecting.reason); -+ ast_queue_redirecting_update(owner, &redirecting); -+ } -+ break; -+ default: -+ ast_log(LOG_WARNING, -+ "Illegal subcommand %d in facility request on channel %d/%d not in use on span %d\n", -+ subcmd->cmd, PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span); -+ break; -+ } -+ } -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); - } -- if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) { -- ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n"); -- x = DAHDI_START; -- res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); -- if (res < 0) { -- if (errno != EINPROGRESS) { -- ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno)); -+ } -+ } -+ break; -+ } -+ case PRI_EVENT_ANSWER: -+ { -+ int channel = e->answer.channel; -+ int ccbsnronprispan = PRI_SPAN(channel); -+ int explicit = PRI_EXPLICIT(channel); -+ int i; -+ -+ channel = PRI_CHANNEL(channel); -+ -+ ast_verb(4, -+ "PRI_EVENT_ANSWER e->answer.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", -+ e->answer.channel, ccbsnronprispan, explicit, channel); -+ -+ if (channel == 0) { /* No channel Connection */ -+ for (i = 0; i < e->answer.subcmds.counter_subcmd; i++) { -+ struct subcommand *subcmd = &e->answer.subcmds.subcmd[i]; -+ -+ switch (subcmd->cmd) { -+ case CMD_CC_CCBSREQUEST_RR: -+ { -+ struct ccbsnr_link *cclink; -+ unsigned int handle; -+ int cr = e->answer.cref; -+ int no_path_reservation = subcmd->cc_ccbs_rr.cc_request_res.no_path_reservation; -+ int retain_service = subcmd->cc_ccbs_rr.cc_request_res.retain_service; -+ -+ ast_verb(4, -+ "Answer ccbs-request RR no-path-reservation '%d' retain-service '%d' on channel %d/%d on span %d\n", -+ no_path_reservation, retain_service, -+ PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ handle = CCBS_HANDLE(ccbsnronprispan,cr); -+ cclink = ccbsnr_select_link(handle); -+ if (cclink) { -+ struct ast_channel *peer; -+ -+ peer = cclink->peer; -+ cclink->peer = NULL; -+ ast_verb(4, -+ "PRI_EVENT_ANSWER: peer on CCBS-List-Obj (%p))\n", -+ peer); -+ -+ if (peer) { -+ ast_verb(4, -+ "fac-ev:PRI_CC_CCBSREQUEST:set per peer %p state ACTIVATED\n", -+ peer); -+ pbx_builtin_setvar_helper(peer, "CCBSNRREQSTATE", "ACTIVATED"); -+ } else { -+ ast_verb(4, -+ "PRI_EVENT_ANSWER: No peer on CCBS-List-Obj found\n"); - } -+ } else { -+ ast_verb(3, -+ "PRI_EVENT_ANSWER: CCBS-List-Obj not found: e->answer.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", -+ e->answer.channel, ccbsnronprispan, explicit, channel); - } -- } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) { -- pri->pvts[chanpos]->dialing = 1; -- /* Send any "w" waited stuff */ -- res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop); -- if (res < 0) { -- ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno)); -- pri->pvts[chanpos]->dop.dialstr[0] = '\0'; -- } else -- ast_debug(1, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr); -+ break; -+ } - -- pri->pvts[chanpos]->dop.dialstr[0] = '\0'; -- } else if (pri->pvts[chanpos]->confirmanswer) { -- ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel); -- } else { -- pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1; -- /* Enable echo cancellation if it's not on already */ -- dahdi_enable_ec(pri->pvts[chanpos]); -+ case CMD_CC_CCNRREQUEST_RR: -+ { -+ struct ccbsnr_link *cclink; -+ unsigned int handle; -+ int cr = e->answer.cref; -+ int no_path_reservation = subcmd->cc_ccnr_rr.cc_request_res.no_path_reservation; -+ int retain_service = subcmd->cc_ccnr_rr.cc_request_res.retain_service; -+ -+ ast_verb(3, -+ "Answer ccnr-request RR no-path-reservation '%d' retain-service '%d' on channel %d/%d on span %d\n", -+ no_path_reservation, retain_service, -+ PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ handle = CCBS_HANDLE(ccbsnronprispan,cr); -+ cclink = ccbsnr_select_link(handle); -+ if (cclink) { -+ struct ast_channel *peer; -+ peer = cclink->peer; -+ cclink->peer = NULL; -+ ast_verb(4, -+ "PRI_EVENT_ANSWER: peer on CCBS-List-Obj (%p))\n", peer); -+ -+ if (peer) { -+ ast_verb(4, -+ "fac-ev:PRI_CC_CCBSREQUEST:set per peer %p state ACTIVATED\n", -+ peer); -+ pbx_builtin_setvar_helper(peer, "CCBSNRREQSTATE", "ACTIVATED"); -+ } else { -+ ast_verb(3, "PRI_EVENT_ANSWER: No peer on CCBS-List-Obj found\n"); -+ } -+ } else { -+ ast_verb(3, -+ "PRI_EVENT_ANSWER: CCBS-List-Obj not found: e->answer.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", -+ e->answer.channel, ccbsnronprispan, explicit, channel); -+ } -+ break; - } - -+ default: -+ ast_log(LOG_WARNING, "Illegal subcommand %d in answer on channel %d/%d span %d\n", -+ subcmd->cmd, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ break; -+ } -+ } -+ } else { -+ chanpos = pri_find_principle(pri, e->answer.channel); -+ if (chanpos < 0) { -+ ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n", -+ PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ } else { -+ chanpos = pri_fixup_principle(pri, chanpos, e->answer.call); -+ if (chanpos < 0) { -+ ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n", -+ PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span); -+ } else { -+ struct ast_party_connected_line connected; -+ struct ast_channel *owner; -+ -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ /* Now we can do call progress detection */ -+ -+ /* We changed this so it turns on the DSP no matter what... progress or no progress. -+ * By this time, we need DTMF detection and other features that were previously disabled -+ * -- Matt F */ -+ if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) { -+ ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features); -+ pri->pvts[chanpos]->dsp_features = 0; -+ } -+ if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) { -+ ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n"); -+ x = DAHDI_START; -+ res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); -+ if (res < 0) { -+ if (errno != EINPROGRESS) { -+ ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno)); -+ } -+ } -+ } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) { -+ pri->pvts[chanpos]->dialing = 1; -+ /* Send any "w" waited stuff */ -+ res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop); -+ if (res < 0) { -+ ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno)); -+ pri->pvts[chanpos]->dop.dialstr[0] = '\0'; -+ } else -+ ast_debug(1, "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_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel); -+ } else { -+ pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1; -+ /* Enable echo cancellation if it's not on already */ -+ dahdi_enable_ec(pri->pvts[chanpos]); -+ } -+ -+ owner = pri->pvts[chanpos]->owner; - #ifdef SUPPORT_USERUSER -- if (!ast_strlen_zero(e->answer.useruserinfo)) { -- struct ast_channel *owner = pri->pvts[chanpos]->owner; -+ if (!ast_strlen_zero(e->answer.useruserinfo)) { -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo); -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ } -+#endif -+ -+ if (owner) { -+ /* Update the connected line information on the other channel */ -+ ast_party_connected_line_init(&connected); -+ connected.id.name = e->answer.connectedname; -+ connected.id.number = e->answer.connectednum; -+ connected.id.number_type = e->answer.connectedplan; -+ connected.id.number_presentation = pri_to_ast_presentation(e->answer.connectedpres); -+ connected.source = pri_to_ast_connected_line_update_source(e->answer.source); -+ ast_queue_connected_line_update(owner, &connected); -+ } -+ - ast_mutex_unlock(&pri->pvts[chanpos]->lock); -- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo); -- ast_mutex_lock(&pri->pvts[chanpos]->lock); - } --#endif -- -- ast_mutex_unlock(&pri->pvts[chanpos]->lock); - } - } -- break; -+ break; -+ } - case PRI_EVENT_HANGUP: -- chanpos = pri_find_principle(pri, e->hangup.channel); -- if (chanpos < 0) { -- ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n", -- PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ { -+ int errorvalue = 0; -+ int channel = e->hangup.channel; -+ int ccbsnronprispan = PRI_SPAN(channel); -+ int explicit = PRI_EXPLICIT(channel); -+ int i; -+ -+ channel = PRI_CHANNEL(channel); -+ -+ ast_verb(4, "Channel %d/%d, span %d got hangup, cause %d\n", -+ ccbsnronprispan, channel, pri->span, e->hangup.cause); -+ -+ if (channel == 0) { /* No channel Connection */ -+ struct ccbsnr_link *cclink; -+ unsigned int handle; -+ int cr; -+ unsigned int state; -+ -+ for (i = 0; i < e->hangup.subcmds.counter_subcmd; i++) { -+ struct subcommand *subcmd = &e->hangup.subcmds.subcmd[i]; -+ -+ switch (subcmd->cmd) { -+ case CMD_CC_ERROR: -+ errorvalue = subcmd->cc_error.error_value; -+ ast_verb(4, -+ "Hangup cc-error RR value '%d' on channel %d/%d on span %d\n", -+ errorvalue, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ break; -+ case CMD_CC_CANCEL_INV: -+ ast_verb(4, -+ "Hangup cc-cancel INV numberA '%s' numberB '%s' on channel %d/%d on span %d\n", -+ subcmd->cc_cancel_inv.cc_optional_arg.number_A, -+ subcmd->cc_cancel_inv.cc_optional_arg.number_B, -+ PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ break; -+ default: -+ ast_log(LOG_WARNING, "Illegal subcommand %d in hangup on channel %d/%d span %d\n", -+ subcmd->cmd, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ break; -+ } -+ } -+ -+ cr = e->hangup.cref; -+ state = 0; -+ -+ handle = CCBS_HANDLE(ccbsnronprispan,cr); -+ cclink = ccbsnr_get_link(handle, &state); -+ if (cclink) { -+ switch (state) { -+ case CC_WAIT_ACK: -+ case CC_WAIT_USER_A_ANSWER_N: -+ case CC_INVOKED_A_RET: -+ ast_verb(4, -+ "PRI_EVENT_HANGUP: CCBS-List-Obj 0x%p: handle %x e->hangup.channel(0x%x) span(%d) explicit(%d) channel(%d) error(%d) peer=%p\n", -+ cclink, handle, e->hangup.channel, ccbsnronprispan, explicit, channel, errorvalue, cclink->peer); -+ -+ pri_hangup(pri->pri, cclink->call, e->hangup.cause); -+ cclink->call = NULL; -+ ccbsnr_del_link(handle); -+ break; -+ default: -+ ast_verb(3, "PRI_EVENT_HANGUP:wrong state '%d'\n", state); -+ break; -+ } -+ } else { -+ ast_verb(4, "PRI_EVENT_HANGUP: CCBS-List-Obj not found: e->hangup.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", -+ e->hangup.channel, ccbsnronprispan, explicit, channel); -+ ast_verb(3, "Hangup on bad channel %d/%d on span %d\n", -+ PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ } - } else { -- chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call); -- if (chanpos > -1) { -- ast_mutex_lock(&pri->pvts[chanpos]->lock); -- if (!pri->pvts[chanpos]->alreadyhungup) { -- /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */ -- pri->pvts[chanpos]->alreadyhungup = 1; -- if (pri->pvts[chanpos]->realcall) -- pri_hangup_all(pri->pvts[chanpos]->realcall, pri); -- else if (pri->pvts[chanpos]->owner) { -- /* Queue a BUSY instead of a hangup if our cause is appropriate */ -- pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause; -- if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP) -- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -- else { -- switch (e->hangup.cause) { -- case PRI_CAUSE_USER_BUSY: -- pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1; -- break; -- case PRI_CAUSE_CALL_REJECTED: -- case PRI_CAUSE_NETWORK_OUT_OF_ORDER: -- case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: -- case PRI_CAUSE_SWITCH_CONGESTION: -- case PRI_CAUSE_DESTINATION_OUT_OF_ORDER: -- case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE: -- pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1; -- break; -- default: -+ chanpos = pri_find_principle(pri, e->hangup.channel); -+ if (chanpos < 0) { -+ ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n", -+ PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ } else { -+ chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call); -+ if (chanpos > -1) { -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ if (!pri->pvts[chanpos]->alreadyhungup) { -+ /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */ -+ pri->pvts[chanpos]->alreadyhungup = 1; -+ if (pri->pvts[chanpos]->realcall) -+ pri_hangup_all(pri->pvts[chanpos]->realcall, pri); -+ else if (pri->pvts[chanpos]->owner) { -+ /* Queue a BUSY instead of a hangup if our cause is appropriate */ -+ pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause; -+ if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP) - pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -+ else { -+ switch (e->hangup.cause) { -+ case PRI_CAUSE_USER_BUSY: -+ pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1; -+ break; -+ case PRI_CAUSE_CALL_REJECTED: -+ case PRI_CAUSE_NETWORK_OUT_OF_ORDER: -+ case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: -+ case PRI_CAUSE_SWITCH_CONGESTION: -+ case PRI_CAUSE_DESTINATION_OUT_OF_ORDER: -+ case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE: -+ pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1; -+ break; -+ default: -+ pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -+ break; -+ } - } - } -+ ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n", -+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause); -+ } else { -+ pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause); -+ pri->pvts[chanpos]->call = NULL; - } -- ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n", -- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause); -- } else { -- pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause); -- pri->pvts[chanpos]->call = NULL; -- } -- if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) { -- ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n", -+ if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) { -+ ast_verb(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; -- } -- if (e->hangup.aoc_units > -1) -- ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n", -+ pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos])); -+ pri->pvts[chanpos]->resetting = 1; -+ } -+ if (e->hangup.aoc_units > -1) -+ ast_verb(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 (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) { -- struct ast_channel *owner = pri->pvts[chanpos]->owner; -+ if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) { -+ struct ast_channel *owner = pri->pvts[chanpos]->owner; -+ ast_mutex_unlock(&pri->pvts[chanpos]->lock); -+ pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo); -+ ast_mutex_lock(&pri->pvts[chanpos]->lock); -+ } -+#endif -+ for (i = 0; i < e->hangup.subcmds.counter_subcmd; i++) { -+ struct subcommand *subcmd = &e->hangup.subcmds.subcmd[i]; -+ -+ switch (subcmd->cmd) { -+ case CMD_CC_RINGOUT_INV: -+ ast_verb(3, "Facility cc-suspend INV on channel %d/%d, span %d\n", -+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span); -+ break; -+ -+ default: -+ ast_log(LOG_WARNING, "Illegal subcommand %d in hangup on channel %d/%d not in use on span %d\n", -+ subcmd->cmd, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); -+ break; -+ } -+ } -+ - ast_mutex_unlock(&pri->pvts[chanpos]->lock); -- pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo); -- ast_mutex_lock(&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); - } --#endif -- -- 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); - } -- } -+ } - break; -+ } - #ifndef PRI_EVENT_HANGUP_REQ - #error please update libpri - #endif - 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", -+ 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); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call); - if (chanpos > -1) { - ast_mutex_lock(&pri->pvts[chanpos]->lock); -- if (pri->pvts[chanpos]->realcall) -+ if (pri->pvts[chanpos]->realcall) - pri_hangup_all(pri->pvts[chanpos]->realcall, pri); - else if (pri->pvts[chanpos]->owner) { - pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause; -@@ -11348,25 +13976,26 @@ - pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; - else { - switch (e->hangup.cause) { -- case PRI_CAUSE_USER_BUSY: -- pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1; -- break; -- case PRI_CAUSE_CALL_REJECTED: -- case PRI_CAUSE_NETWORK_OUT_OF_ORDER: -- case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: -- case PRI_CAUSE_SWITCH_CONGESTION: -- case PRI_CAUSE_DESTINATION_OUT_OF_ORDER: -- case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE: -- pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1; -- break; -- default: -- pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -+ case PRI_CAUSE_USER_BUSY: -+ pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1; -+ break; -+ case PRI_CAUSE_CALL_REJECTED: -+ case PRI_CAUSE_NETWORK_OUT_OF_ORDER: -+ case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: -+ case PRI_CAUSE_SWITCH_CONGESTION: -+ case PRI_CAUSE_DESTINATION_OUT_OF_ORDER: -+ case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE: -+ pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1; -+ break; -+ default: -+ pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; -+ break; - } - } - ast_verb(3, "Channel %d/%d, span %d got hangup request, cause %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause); - if (e->hangup.aoc_units > -1) - ast_verb(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]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s"); - } else { - pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause); - pri->pvts[chanpos]->call = NULL; -@@ -11391,12 +14020,44 @@ - } 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); - } -- } -+ } - break; - case PRI_EVENT_HANGUP_ACK: -+ { -+ int channel = e->hangup.channel; -+ int ccbsnronprispan = PRI_SPAN(channel); -+ int explicit = PRI_EXPLICIT(channel); -+ channel = PRI_CHANNEL(channel); -+ -+ ast_verb(4, "PRI_EVENT_HANGUP_ACK e->hangup.cause(%d) e->hangup.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", -+ e->hangup.cause, e->hangup.channel, ccbsnronprispan, explicit, channel); -+ ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n", -+ ccbsnronprispan, channel, pri->span, e->hangup.cause); -+ if (channel == 0) { /* No channel Connection */ -+ struct ccbsnr_link *cclink; -+ unsigned int handle; -+ int cr = e->hangup.cref; -+ unsigned int state = 0; -+ -+ handle = CCBS_HANDLE(ccbsnronprispan,cr); -+ cclink = ccbsnr_get_link(handle, &state); -+ if (cclink) { -+ ast_verb(4, -+ "PRI_EVENT_HANGUP_ACK: CCBS-List-Obj 0x%p: handle %x e->hangup.channel(0x%x) span(%d) explicit(%d) channel(%d) peer=%p\n", -+ cclink, handle, e->hangup.channel, ccbsnronprispan, explicit, channel, cclink->peer); -+ cclink->call = NULL; -+ ccbsnr_del_link(handle); -+ } else { -+ ast_verb(4, -+ "PRI_EVENT_HANGUP_ACK: CCBS-List-Obj 0x%p: handle %x e->hangup.channel(0x%x) span(%d) explicit(%d) channel(%d)", -+ cclink, handle, e->hangup.channel, ccbsnronprispan, explicit, channel); -+ } -+ break; -+ } -+ - chanpos = pri_find_principle(pri, e->hangup.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n", -+ ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n", - PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call); -@@ -11421,6 +14082,7 @@ - } - } - break; -+ } - case PRI_EVENT_CONFIG_ERR: - ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err); - break; -@@ -11434,12 +14096,12 @@ - if (pri->pvts[x] && pri->pvts[x]->resetting) { - chanpos = x; - ast_mutex_lock(&pri->pvts[chanpos]->lock); -- ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, -+ ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, - pri->pvts[chanpos]->prioffset, pri->span); -- if (pri->pvts[chanpos]->realcall) -+ if (pri->pvts[chanpos]->realcall) - pri_hangup_all(pri->pvts[chanpos]->realcall, pri); - else if (pri->pvts[chanpos]->owner) { -- ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan, -+ ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan, - pri->pvts[chanpos]->prioffset, pri->span); - pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV; - } -@@ -11453,13 +14115,13 @@ - } - } - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n", -+ ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n", - PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span); - } - } else { - if (pri->pvts[chanpos]) { - ast_mutex_lock(&pri->pvts[chanpos]->lock); -- if (pri->pvts[chanpos]->realcall) -+ if (pri->pvts[chanpos]->realcall) - pri_hangup_all(pri->pvts[chanpos]->realcall, pri); - else if (pri->pvts[chanpos]->owner) { - ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n", -@@ -11479,7 +14141,7 @@ - case PRI_EVENT_SETUP_ACK: - chanpos = pri_find_principle(pri, e->setup_ack.channel); - if (chanpos < 0) { -- ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", -+ ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", - PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span); - } else { - chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call); -@@ -11489,7 +14151,7 @@ - /* Send any queued digits */ - for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) { - ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]); -- pri_information(pri->pri, pri->pvts[chanpos]->call, -+ pri_information(pri->pri, pri->pvts[chanpos]->call, - pri->pvts[chanpos]->dialdest[x]); - } - ast_mutex_unlock(&pri->pvts[chanpos]->lock); -@@ -11502,7 +14164,7 @@ - if (chanpos < 0) { - ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n", - PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span); -- } else { -+ } else if (!pri->discardremoteholdretrieval) { - struct ast_frame f = { AST_FRAME_CONTROL, }; - ast_mutex_lock(&pri->pvts[chanpos]->lock); - switch (e->notify.info) { -@@ -11521,13 +14183,15 @@ - default: - ast_debug(1, "Event: %d\n", e->e); - } -- } -+ } - ast_mutex_unlock(&pri->lock); - } - /* Never reached */ - return NULL; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static int start_pri(struct dahdi_pri *pri) - { - int res, x; -@@ -11535,7 +14199,7 @@ - struct dahdi_bufferinfo bi; - struct dahdi_spaninfo si; - int i; -- -+ - for (i = 0; i < NUM_DCHANS; i++) { - if (!pri->dchannels[i]) - break; -@@ -11576,19 +14240,23 @@ - return -1; - } - switch (pri->sig) { -- case SIG_BRI: -- pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype); -- break; -- case SIG_BRI_PTMP: -- pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype); -- break; -- default: -- pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype); -+ case SIG_BRI: -+ pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype); -+ break; -+ case SIG_BRI_PTMP: -+ pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype); -+ break; -+ default: -+ pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype); -+ break; - } - /* Force overlap dial if we're doing GR-303! */ - if (pri->switchtype == PRI_SWITCH_GR303_TMC) - pri->overlapdial |= DAHDI_OVERLAPDIAL_BOTH; - pri_set_overlapdial(pri->dchans[i],(pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)?1:0); -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ pri_set_chan_mapping_logical(pri->dchans[i], pri->qsigchannelmapping == DAHDI_CHAN_MAPPING_LOGICAL); -+#endif - #ifdef HAVE_PRI_INBANDDISCONNECT - pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect); - #endif -@@ -11623,7 +14291,9 @@ - } - return 0; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos) - { - int which, span; -@@ -11642,38 +14312,16 @@ - } - return ret; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *complete_span_4(const char *line, const char *word, int pos, int state) - { - return complete_span_helper(line,word,pos,state,3); - } -+#endif /* defined(HAVE_PRI) */ - --static char *complete_span_5(const char *line, const char *word, int pos, int state) --{ -- return complete_span_helper(line,word,pos,state,4); --} -- --static char *handle_pri_unset_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "pri unset debug file"; -- e->usage = "Usage: pri unset debug file\n" -- " Stop sending debug output to the previously \n" -- " specified file\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- /* Assume it is unset */ -- ast_mutex_lock(&pridebugfdlock); -- close(pridebugfd); -- pridebugfd = -1; -- ast_cli(a->fd, "PRI debug output to file disabled\n"); -- ast_mutex_unlock(&pridebugfdlock); -- return CLI_SUCCESS; --} -- -+#if defined(HAVE_PRI) - static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int myfd; -@@ -11681,10 +14329,10 @@ - case CLI_INIT: - e->command = "pri set debug file"; - e->usage = "Usage: pri set debug file [output-file]\n" -- " Sends PRI debug output to the specified output file\n"; -+ " Sends PRI debug output to the specified output file\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - if (a->argc < 5) - return CLI_SHOWUSAGE; -@@ -11709,65 +14357,38 @@ - ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]); - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int span; - int x; -+ int level = 0; - switch (cmd) { -- case CLI_INIT: -- e->command = "pri debug span"; -- e->usage = -- "Usage: pri debug span \n" -+ case CLI_INIT: -+ e->command = "pri set debug {on|off|0|1|2} span"; -+ e->usage = -+ "Usage: pri set debug {|on|off} span \n" - " Enables debugging on a given PRI span\n"; - return NULL; -- case CLI_GENERATE: -+ case CLI_GENERATE: - return complete_span_4(a->line, a->word, a->pos, a->n); - } -- if (a->argc < 4) { -+ if (a->argc < 6) { - return CLI_SHOWUSAGE; - } -- span = atoi(a->argv[3]); -- if ((span < 1) || (span > NUM_SPANS)) { -- ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS); -- return CLI_SUCCESS; -- } -- if (!pris[span-1].pri) { -- ast_cli(a->fd, "No PRI running on span %d\n", span); -- return CLI_SUCCESS; -- } -- for (x = 0; x < NUM_DCHANS; x++) { -- if (pris[span-1].dchans[x]) -- pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU | -- PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | -- PRI_DEBUG_Q921_STATE); -- } -- ast_cli(a->fd, "Enabled debugging on span %d\n", span); -- return CLI_SUCCESS; --} - -- -- --static char *handle_pri_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- int span; -- int x; -- switch (cmd) { -- case CLI_INIT: -- e->command = "pri no debug span"; -- e->usage = -- "Usage: pri no debug span \n" -- " Disables debugging on a given PRI span\n"; -- return NULL; -- case CLI_GENERATE: -- return complete_span_5(a->line, a->word, a->pos, a->n); -+ if (!strcasecmp(a->argv[3], "on")) { -+ level = 1; -+ } else if (!strcasecmp(a->argv[3], "off")) { -+ level = 0; -+ } else { -+ level = atoi(a->argv[3]); - } -- if (a->argc < 5) -- return CLI_SHOWUSAGE; -- -- span = atoi(a->argv[4]); -+ span = atoi(a->argv[5]); - if ((span < 1) || (span > NUM_SPANS)) { -- ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS); -+ ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[5], 1, NUM_SPANS); - return CLI_SUCCESS; - } - if (!pris[span-1].pri) { -@@ -11775,49 +14396,33 @@ - return CLI_SUCCESS; - } - for (x = 0; x < NUM_DCHANS; x++) { -- if (pris[span-1].dchans[x]) -- pri_set_debug(pris[span-1].dchans[x], 0); -+ if (pris[span-1].dchans[x]) { -+ if (level == 1) { -+ pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU | -+ PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | -+ PRI_DEBUG_Q921_STATE); -+ ast_cli(a->fd, "Enabled debugging on span %d\n", span); -+ } else if (level == 0) { -+ pri_set_debug(pris[span-1].dchans[x], 0); -+ //close the file if it's set -+ ast_mutex_lock(&pridebugfdlock); -+ close(pridebugfd); -+ pridebugfd = -1; -+ ast_cli(a->fd, "PRI debug output to file disabled\n"); -+ ast_mutex_unlock(&pridebugfdlock); -+ } else { -+ pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU | -+ PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | -+ PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE); -+ ast_cli(a->fd, "Enabled debugging on span %d\n", span); -+ } -+ } - } -- ast_cli(a->fd, "Disabled debugging on span %d\n", span); - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_PRI) */ - --static char *handle_pri_really_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- int span; -- int x; -- switch (cmd) { -- case CLI_INIT: -- e->command = "pri intensive debug span"; -- e->usage = -- "Usage: pri intensive debug span \n" -- " Enables debugging down to the Q.921 level\n"; -- return NULL; -- case CLI_GENERATE: -- return complete_span_5(a->line, a->word, a->pos, a->n); -- } -- -- if (a->argc < 5) -- return CLI_SHOWUSAGE; -- span = atoi(a->argv[4]); -- if ((span < 1) || (span > NUM_SPANS)) { -- ast_cli(a->fd, "Invalid span %s. Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS); -- return CLI_SUCCESS; -- } -- if (!pris[span-1].pri) { -- ast_cli(a->fd, "No PRI running on span %d\n", span); -- return CLI_SUCCESS; -- } -- for (x = 0; x < NUM_DCHANS; x++) { -- if (pris[span-1].dchans[x]) -- pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU | -- PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | -- PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE); -- } -- ast_cli(a->fd, "Enabled EXTENSIVE debugging on span %d\n", span); -- return CLI_SUCCESS; --} -- -+#if defined(HAVE_PRI) - static void build_status(char *s, size_t len, int status, int active) - { - if (!s || len < 1) { -@@ -11838,7 +14443,9 @@ - strncat(s, ", Standby", len - strlen(s) - 1); - s[len - 1] = '\0'; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int span; -@@ -11848,12 +14455,12 @@ - switch (cmd) { - case CLI_INIT: - e->command = "pri show spans"; -- e->usage = -+ e->usage = - "Usage: pri show spans\n" - " Displays PRI Information\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - if (a->argc != 3) -@@ -11871,16 +14478,23 @@ - } - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int span; - int x; - char status[256]; -+ struct ccbsnr_link *ccbsnr; -+ int ccbsnronprispan; -+ int cr; -+ int counter = 0; -+ - switch (cmd) { -- case CLI_INIT: -+ case CLI_INIT: - e->command = "pri show span"; -- e->usage = -+ e->usage = - "Usage: pri show span \n" - " Displays PRI Information on a given PRI span\n"; - return NULL; -@@ -11919,9 +14533,31 @@ - ast_cli(a->fd, "Overlap Recv: %s\n\n", (pris[span-1].overlapdial & DAHDI_OVERLAPDIAL_INCOMING)?"Yes":"No"); - } - } -+ -+ ast_mutex_lock(&ccbsnr_lock); -+ ccbsnr = ccbsnr_list; -+ if (ccbsnr) { -+ ast_cli(a->fd, "ccbsnr-list: %p\n", ccbsnr); -+ } -+ -+ while (ccbsnr) { -+ ccbsnronprispan = CCBS_SPAN(ccbsnr->handle); -+ cr = CCBS_CR(ccbsnr->handle); -+ ast_cli(a->fd, -+ "%d. Active No Channel Call: Q.931 Call %p cr=%d span=%d type=%d handle=%x state=%d (%s, %s, %s, %s, %d) peer=%p\n", -+ ++counter, ccbsnr->call, cr, ccbsnronprispan, ccbsnr->type, ccbsnr->handle, ccbsnr->state, -+ ccbsnr->callingnum, ccbsnr->callernum, ccbsnr->callername, -+ ccbsnr->context, ccbsnr->priority, ccbsnr->peer); -+ -+ ccbsnr = ccbsnr->next; -+ } -+ ast_mutex_unlock(&ccbsnr_lock); -+ - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int x; -@@ -11930,22 +14566,22 @@ - int debug=0; - - switch (cmd) { -- case CLI_INIT: -+ case CLI_INIT: - e->command = "pri show debug"; -- e->usage = -+ e->usage = - "Usage: pri show debug\n" - " Show the debug state of pri spans\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - for (span = 0; span < NUM_SPANS; span++) { -- if (pris[span].pri) { -+ if (pris[span].pri) { - for (x = 0; x < NUM_DCHANS; x++) { - debug = 0; -- if (pris[span].dchans[x]) { -- debug = pri_get_debug(pris[span].dchans[x]); -+ if (pris[span].dchans[x]) { -+ debug = pri_get_debug(pris[span].dchans[x]); - ast_cli(a->fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" ); - count++; - } -@@ -11954,21 +14590,23 @@ - - } - ast_mutex_lock(&pridebugfdlock); -- if (pridebugfd >= 0) -+ if (pridebugfd >= 0) - ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename); - ast_mutex_unlock(&pridebugfdlock); -- -- if (!count) -+ -+ if (!count) - ast_cli(a->fd, "No debug set or no PRI running\n"); - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { - case CLI_INIT: - e->command = "pri show version"; -- e->usage = -+ e->usage = - "Usage: pri show version\n" - "Show libpri version information\n"; - return NULL; -@@ -11980,21 +14618,19 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_PRI) */ - -+#if defined(HAVE_PRI) - static struct ast_cli_entry dahdi_pri_cli[] = { - AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"), -- AST_CLI_DEFINE(handle_pri_no_debug, "Disables PRI debugging on a span"), -- AST_CLI_DEFINE(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"), - AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI Information"), - AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI Information"), - AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"), - AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"), -- AST_CLI_DEFINE(handle_pri_unset_debug_file, "Ends PRI debug output to file"), - AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"), - }; -+#endif /* defined(HAVE_PRI) */ - --#endif /* HAVE_PRI */ -- - static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int channel; -@@ -12002,16 +14638,16 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi destroy channel"; -- e->usage = -+ e->usage = - "Usage: dahdi 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"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - if (a->argc != 4) - return CLI_SHOWUSAGE; -- -+ - channel = atoi(a->argv[3]); - ret = dahdi_destroy_channel_bynum(channel); - return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE; -@@ -12022,9 +14658,9 @@ - struct dahdi_pvt *p; - retry: - ast_mutex_lock(&iflock); -- for (p = iflist; p; p = p->next) { -+ for (p = iflist; p; p = p->next) { - ast_mutex_lock(&p->lock); -- if (p->owner && !p->restartpending) { -+ if (p->owner && !p->restartpending) { - if (ast_channel_trylock(p->owner)) { - if (option_debug > 2) - ast_verbose("Avoiding deadlock\n"); -@@ -12041,7 +14677,7 @@ - ast_channel_unlock(p->owner); - } - ast_mutex_unlock(&p->lock); -- } -+ } - ast_mutex_unlock(&iflock); - } - -@@ -12061,6 +14697,8 @@ - ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n"); - - #if defined(HAVE_PRI) -+ cc_destroy_all_peer_link_id(); -+ ccbsnr_clear_all(); - for (i = 0; i < NUM_SPANS; i++) { - if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) { - cancel_code = pthread_cancel(pris[i].master); -@@ -12081,7 +14719,7 @@ - pthread_join(linksets[i].master, NULL); - ast_debug(4, "Joined thread of span %d\n", i); - } -- } -+ } - #endif - - ast_mutex_lock(&monlock); -@@ -12094,12 +14732,6 @@ - } - monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */ - -- ast_mutex_lock(&mwi_thread_lock); -- while (mwi_thread_count > 0) { -- ast_debug(3, "Waiting on %d mwi_send_thread(s) to finish\n", mwi_thread_count); -- ast_cond_wait(&mwi_thread_complete, &mwi_thread_lock); -- } -- ast_mutex_unlock(&mwi_thread_lock); - ast_mutex_lock(&ss_thread_lock); - while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */ - int x = DAHDI_FLASH; -@@ -12107,7 +14739,7 @@ - - for (p = iflist; p; p = p->next) { - if (p->owner) -- ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */ -+ ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */ - } - ast_cond_wait(&ss_thread_complete, &ss_thread_lock); - } -@@ -12169,7 +14801,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi restart"; -- e->usage = -+ e->usage = - "Usage: dahdi restart\n" - " Restarts the DAHDI channels: destroys them all and then\n" - " re-reads them from chan_dahdi.conf.\n" -@@ -12217,13 +14849,13 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi show channels [trunkgroup|group|context]"; -- e->usage = -+ e->usage = - "Usage: dahdi show channels [ trunkgroup | group | context ]\n" - " Shows a list of available channels with optional filtering\n" - " must be a number between 0 and 63\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - lock = &iflock; -@@ -12254,7 +14886,7 @@ - return CLI_FAILURE; - } - } else --#endif -+#endif - if (!strcasecmp(a->argv[3], "group")) { - targetnum = atoi(a->argv[4]); - if ((targetnum < 0) || (targetnum > 63)) -@@ -12271,8 +14903,8 @@ - ast_cli(a->fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State"); - #else - ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State"); --#endif -- -+#endif -+ - tmp = start; - while (tmp) { - if (filtertype) { -@@ -12338,12 +14970,12 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi show channel"; -- e->usage = -+ e->usage = - "Usage: dahdi show channel \n" - " Detailed information about a given channel\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - lock = &iflock; -@@ -12379,10 +15011,10 @@ - while (tmp) { - if (tmp->channel == channel) { - #ifdef HAVE_PRI -- if (pri) -+ if (pri) - ast_cli(a->fd, "Trunk/CRV: %d/%d\n", trunkgroup, tmp->channel); - else --#endif -+#endif - ast_cli(a->fd, "Channel: %d\n", tmp->channel); - ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd); - ast_cli(a->fd, "Span: %d\n", tmp->span); -@@ -12442,6 +15074,7 @@ - } else { - ast_cli(a->fd, "\tnone\n"); - } -+ ast_cli(a->fd, "Wait for dialtone: %dms\n", tmp->waitfordialtone); - if (tmp->master) - ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel); - for (x = 0; x < MAX_SLAVES; x++) { -@@ -12463,12 +15096,11 @@ - if (tmp->bearer) - ast_cli(a->fd, "Bearer "); - ast_cli(a->fd, "\n"); -- if (tmp->logicalspan) -+ if (tmp->logicalspan) - ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan); - else - ast_cli(a->fd, "PRI Logical Span: Implicit\n"); - } -- - #endif - memset(&ci, 0, sizeof(ci)); - ps.channo = tmp->channel; -@@ -12490,7 +15122,7 @@ - } - tmp = tmp->next; - } -- -+ - ast_cli(a->fd, "Unable to find given channel %d\n", channel); - ast_mutex_unlock(lock); - return CLI_FAILURE; -@@ -12502,12 +15134,12 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi show cadences"; -- e->usage = -+ e->usage = - "Usage: dahdi show cadences\n" - " Shows all cadences currently defined\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - for (i = 0; i < num_cadence; i++) { - char output[1024]; -@@ -12533,7 +15165,7 @@ - } - - /* Based on irqmiss.c */ --static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n" - #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n" -@@ -12547,12 +15179,12 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi show status"; -- e->usage = -+ e->usage = - "Usage: dahdi show status\n" - " Shows a list of DAHDI cards with status\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - ctl = open("/dev/dahdi/ctl", O_RDWR); - if (ctl < 0) { -@@ -12594,18 +15226,18 @@ - strcpy(alarmstr, "UNCONFIGURED"); - } - -- ast_cli(a->fd, FORMAT, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count -- , s.lineconfig & DAHDI_CONFIG_D4 ? "D4" : -- s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" : -- s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" : -- "CAS" -- , s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" : -- s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" : -- s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" : -- "Unk" -- , s.lineconfig & DAHDI_CONFIG_CRC4 ? -- s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : "YEL" -- , lbostr[s.lbo] -+ ast_cli(a->fd, FORMAT, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count, -+ s.lineconfig & DAHDI_CONFIG_D4 ? "D4" : -+ s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" : -+ s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" : -+ "CAS", -+ s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" : -+ s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" : -+ s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" : -+ "Unk", -+ s.lineconfig & DAHDI_CONFIG_CRC4 ? -+ s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : "YEL", -+ lbostr[s.lbo] - ); - } - close(ctl); -@@ -12623,7 +15255,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi show version"; -- e->usage = -+ e->usage = - "Usage: dahdi show version\n" - " Shows the DAHDI version in use\n"; - return NULL; -@@ -12659,7 +15291,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi set hwgain"; -- e->usage = -+ e->usage = - "Usage: dahdi set hwgain \n" - " Sets the hardware gain on a a given channel, overriding the\n" - " value provided at module loadtime, whether the channel is in\n" -@@ -12669,12 +15301,12 @@ - " is the gain in dB (e.g. -3.5 for -3.5dB)\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - if (a->argc != 6) - return CLI_SHOWUSAGE; -- -+ - if (!strcasecmp("rx", a->argv[3])) - tx = 0; /* rx */ - else if (!strcasecmp("tx", a->argv[3])) -@@ -12729,7 +15361,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi set swgain"; -- e->usage = -+ e->usage = - "Usage: dahdi set swgain \n" - " Sets the software gain on a a given channel, overriding the\n" - " value provided at module loadtime, whether the channel is in\n" -@@ -12739,14 +15371,14 @@ - " is the gain in dB (e.g. -3.5 for -3.5dB)\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - lock = &iflock; - - if (a->argc != 6) - return CLI_SHOWUSAGE; -- -+ - if (!strcasecmp("rx", a->argv[3])) - tx = 0; /* rx */ - else if (!strcasecmp("tx", a->argv[3])) -@@ -12800,7 +15432,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "dahdi set dnd"; -- e->usage = -+ e->usage = - "Usage: dahdi set dnd \n" - " Sets/resets DND (Do Not Disturb) mode on a channel.\n" - " Changes take effect immediately.\n" -@@ -12809,7 +15441,7 @@ - ; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return NULL; - } - - if (a->argc != 5) -@@ -12819,7 +15451,7 @@ - ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]); - return CLI_SHOWUSAGE; - } -- -+ - if (ast_true(a->argv[4])) - on = 1; - else if (ast_false(a->argv[4])) -@@ -12875,7 +15507,7 @@ - p->fake_event = DAHDI_EVENT_ONHOOK; - break; - default: -- ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name); -+ ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name); - } - } - return 0; -@@ -12994,7 +15626,7 @@ - } - for (i = 0; i < strlen(number); i++) { - struct ast_frame f = { AST_FRAME_DTMF, number[i] }; -- dahdi_queue_frame(p, &f, NULL); -+ dahdi_queue_frame(p, &f, NULL); - } - astman_send_ack(s, m, "DAHDIDialOffhook"); - return 0; -@@ -13017,7 +15649,7 @@ - snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); - - ast_mutex_lock(&iflock); -- -+ - tmp = iflist; - while (tmp) { - if (tmp->channel > 0) { -@@ -13043,13 +15675,13 @@ - "Alarm: %s\r\n" - "%s" - "\r\n", -- tmp->channel, -+ tmp->channel, - tmp->owner->name, - tmp->owner->uniqueid, - tmp->owner->accountcode, -- sig2str(tmp->sig), -+ sig2str(tmp->sig), - tmp->sig, -- tmp->context, -+ tmp->context, - tmp->dnd ? "Enabled" : "Disabled", - alarm2str(alm), idText); - } else { -@@ -13063,29 +15695,29 @@ - "Alarm: %s\r\n" - "%s" - "\r\n", -- tmp->channel, sig2str(tmp->sig), tmp->sig, -- tmp->context, -+ tmp->channel, sig2str(tmp->sig), tmp->sig, -+ tmp->context, - tmp->dnd ? "Enabled" : "Disabled", - alarm2str(alm), idText); - } -- } -+ } - - tmp = tmp->next; - } - - ast_mutex_unlock(&iflock); -- -- astman_append(s, -+ -+ astman_append(s, - "Event: DAHDIShowChannelsComplete\r\n" - "%s" - "Items: %d\r\n" -- "\r\n", -+ "\r\n", - idText, - channels); - return 0; - } - --#ifdef HAVE_SS7 -+#if defined(HAVE_SS7) - static int linkset_addsigchan(int sigchan) - { - struct dahdi_ss7 *link; -@@ -13204,69 +15836,48 @@ - - return 0; - } -+#endif /* defined(HAVE_SS7) */ - --static char *handle_ss7_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- int span; -- switch (cmd) { -- case CLI_INIT: -- e->command = "ss7 no debug linkset"; -- e->usage = -- "Usage: ss7 no debug linkset \n" -- " Disables debugging on a given SS7 linkset\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- if (a->argc < 5) -- return CLI_SHOWUSAGE; -- span = atoi(a->argv[4]); -- if ((span < 1) || (span > NUM_SPANS)) { -- ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[4], 1, NUM_SPANS); -- return CLI_SUCCESS; -- } -- if (!linksets[span-1].ss7) { -- ast_cli(a->fd, "No SS7 running on linkset %d\n", span); -- return CLI_SUCCESS; -- } -- if (linksets[span-1].ss7) -- ss7_set_debug(linksets[span-1].ss7, 0); -- -- ast_cli(a->fd, "Disabled debugging on linkset %d\n", span); -- return CLI_SUCCESS; --} -- -+#if defined(HAVE_SS7) - static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int span; - switch (cmd) { - case CLI_INIT: -- e->command = "ss7 debug linkset"; -- e->usage = -- "Usage: ss7 debug linkset \n" -+ e->command = "ss7 set debug {on|off} linkset"; -+ e->usage = -+ "Usage: ss7 set debug {on|off} linkset \n" - " Enables debugging on a given SS7 linkset\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } -- if (a->argc < 4) -+ if (a->argc < 6) - return CLI_SHOWUSAGE; -- span = atoi(a->argv[3]); -+ span = atoi(a->argv[5]); - if ((span < 1) || (span > NUM_SPANS)) { -- ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS); -+ ast_cli(a->fd, "Invalid linkset %s. Should be a number from %d to %d\n", a->argv[5], 1, NUM_SPANS); - return CLI_SUCCESS; - } - if (!linksets[span-1].ss7) { - ast_cli(a->fd, "No SS7 running on linkset %d\n", span); - return CLI_SUCCESS; - } -- if (linksets[span-1].ss7) -- ss7_set_debug(linksets[span-1].ss7, SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP); -+ if (linksets[span-1].ss7) { -+ if (strcasecmp(a->argv[3], "on")) { -+ ss7_set_debug(linksets[span-1].ss7, SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP); -+ ast_cli(a->fd, "Enabled debugging on linkset %d\n", span); -+ } else { -+ ss7_set_debug(linksets[span-1].ss7, 0); -+ ast_cli(a->fd, "Disabled debugging on linkset %d\n", span); -+ } -+ } - -- ast_cli(a->fd, "Enabled debugging on linkset %d\n", span); - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int linkset, cic; -@@ -13274,7 +15885,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "ss7 block cic"; -- e->usage = -+ e->usage = - "Usage: ss7 block cic \n" - " Sends a remote blocking request for the given CIC on the specified linkset\n"; - return NULL; -@@ -13329,7 +15940,9 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int linkset; -@@ -13337,7 +15950,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "ss7 block linkset"; -- e->usage = -+ e->usage = - "Usage: ss7 block linkset \n" - " Sends a remote blocking request for all CICs on the given linkset\n"; - return NULL; -@@ -13371,7 +15984,9 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int linkset, cic; -@@ -13379,7 +15994,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "ss7 unblock cic"; -- e->usage = -+ e->usage = - "Usage: ss7 unblock cic \n" - " Sends a remote unblocking request for the given CIC on the specified linkset\n"; - return NULL; -@@ -13428,7 +16043,9 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int linkset; -@@ -13436,7 +16053,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "ss7 unblock linkset"; -- e->usage = -+ e->usage = - "Usage: ss7 unblock linkset \n" - " Sends a remote unblocking request for all CICs on the specified linkset\n"; - return NULL; -@@ -13471,7 +16088,9 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - int linkset; -@@ -13479,7 +16098,7 @@ - switch (cmd) { - case CLI_INIT: - e->command = "ss7 show linkset"; -- e->usage = -+ e->usage = - "Usage: ss7 show linkset \n" - " Shows the status of an SS7 linkset.\n"; - return NULL; -@@ -13505,13 +16124,15 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { - case CLI_INIT: - e->command = "ss7 show version"; -- e->usage = -+ e->usage = - "Usage: ss7 show version\n" - " Show the libss7 version\n"; - return NULL; -@@ -13523,10 +16144,11 @@ - - return CLI_SUCCESS; - } -+#endif /* defined(HAVE_SS7) */ - -+#if defined(HAVE_SS7) - static struct ast_cli_entry dahdi_ss7_cli[] = { -- AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), -- AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), -+ AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), - AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"), - AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"), - AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"), -@@ -13534,7 +16156,7 @@ - AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"), - AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"), - }; --#endif /* HAVE_SS7 */ -+#endif /* defined(HAVE_SS7) */ - - static int __unload_module(void) - { -@@ -13545,21 +16167,28 @@ - - #ifdef HAVE_PRI - for (i = 0; i < NUM_SPANS; i++) { -- if (pris[i].master != AST_PTHREADT_NULL) -+ if (pris[i].master != AST_PTHREADT_NULL) - pthread_cancel(pris[i].master); - } - ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli)); - ast_unregister_application(dahdi_send_keypad_facility_app); -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ ast_unregister_application(dahdi_send_callrerouting_facility_app); - #endif -+ ast_unregister_application(dahdi_qsig_ccbsnr_initialize_app); -+ ast_unregister_application(dahdi_qsic_ccbsnr_request_app); -+ ast_unregister_application(dahdi_qsic_clear_nochannel_app); -+ ast_unregister_application(dahdi_qsic_check_ccbsnr_app); -+#endif - #if defined(HAVE_SS7) - for (i = 0; i < NUM_SPANS; i++) { - if (linksets[i].master != AST_PTHREADT_NULL) - pthread_cancel(linksets[i].master); - } -- ast_cli_unregister_multiple(dahdi_ss7_cli, sizeof(dahdi_ss7_cli) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli)); - #endif - -- ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli)); - ast_manager_unregister( "DAHDIDialOffhook" ); - ast_manager_unregister( "DAHDIHangup" ); - ast_manager_unregister( "DAHDITransfer" ); -@@ -13608,7 +16237,6 @@ - } - #endif - -- ast_cond_destroy(&mwi_thread_complete); - ast_cond_destroy(&ss_thread_complete); - return 0; - } -@@ -13619,6 +16247,8 @@ - int y; - #endif - #ifdef HAVE_PRI -+ cc_destroy_all_peer_link_id(); -+ ccbsnr_destroy_all(); - for (y = 0; y < NUM_SPANS; y++) - ast_mutex_destroy(&pris[y].lock); - #endif -@@ -13638,7 +16268,7 @@ - struct dahdi_pri *pri; - int trunkgroup, y; - #endif -- -+ - if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) { - ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n"); - return -1; -@@ -13669,7 +16299,7 @@ - return -1; - } - } --#endif -+#endif - - while ((chan = strsep(&c, ","))) { - if (sscanf(chan, "%d-%d", &start, &finish) == 2) { -@@ -13695,15 +16325,15 @@ - for (x = start; x <= finish; x++) { - #ifdef HAVE_PRI - tmp = mkintf(x, conf, pri, reload); --#else -+#else - tmp = mkintf(x, conf, NULL, reload); --#endif -+#endif - - if (tmp) { - #ifdef HAVE_PRI -- if (pri) -+ if (pri) - ast_verb(3, "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig)); -- else -+ else - #endif - ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig)); - } else { -@@ -13717,7 +16347,7 @@ - return 0; - } - --/** The length of the parameters list of 'dahdichan'. -+/** The length of the parameters list of 'dahdichan'. - * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */ - #define MAX_CHANLIST_LEN 80 - -@@ -13736,7 +16366,7 @@ - /* first parameter is tap length, process it here */ - - x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]); -- -+ - if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024)) - confp->chan.echocancel.head.tap_length = x; - else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0]))) -@@ -13773,9 +16403,9 @@ - } - - /*! process_dahdi() - ignore keyword 'channel' and similar */ --#define PROC_DAHDI_OPT_NOCHAN (1 << 0) -+#define PROC_DAHDI_OPT_NOCHAN (1 << 0) - /*! process_dahdi() - No warnings on non-existing cofiguration keywords */ --#define PROC_DAHDI_OPT_NOWARN (1 << 1) -+#define PROC_DAHDI_OPT_NOWARN (1 << 1) - - static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options) - { -@@ -13796,8 +16426,8 @@ - /* Create the interface list */ - if (!strcasecmp(v->name, "channel") - #ifdef HAVE_PRI -- || !strcasecmp(v->name, "crv") --#endif -+ || !strcasecmp(v->name, "crv") -+#endif - ) { - int iscrv; - if (options & PROC_DAHDI_OPT_NOCHAN) { -@@ -13824,9 +16454,34 @@ - confp->chan.buf_policy = DAHDI_POLICY_WHEN_FULL; - } else if (!strcasecmp(policy, "immediate")) { - confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE; -+#ifdef HAVE_DAHDI_HALF_FULL -+ } else if (!strcasecmp(policy, "half_full")) { -+ confp->chan.buf_policy = DAHDI_POLICY_HALF_FULL; -+#endif - } else { - ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy); - } -+ } else if (!strcasecmp(v->name, "faxbuffers")) { -+ int res; -+ char policy[21] = ""; -+ -+ res = sscanf(v->value, "%d,%20s", &confp->chan.faxbuf_no, policy); -+ if (res != 2) { -+ ast_log(LOG_WARNING, "Parsing faxbuffers option data failed, using defaults.\n"); -+ confp->chan.faxbuf_no = numbufs; -+ continue; -+ } -+ confp->chan.usefaxbuffers = 1; -+ if (confp->chan.faxbuf_no < 0) -+ confp->chan.faxbuf_no = numbufs; -+ if (!strcasecmp(policy, "full")) { -+ confp->chan.faxbuf_policy = DAHDI_POLICY_WHEN_FULL; -+ } else if (!strcasecmp(policy, "immediate")) { -+ confp->chan.faxbuf_policy = DAHDI_POLICY_IMMEDIATE; -+ } else { -+ ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy); -+ confp->chan.usefaxbuffers = 0; -+ } - } else if (!strcasecmp(v->name, "dahdichan")) { - ast_copy_string(dahdichan, v->value, sizeof(dahdichan)); - } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) { -@@ -13880,7 +16535,7 @@ - } else if (!strcasecmp(v->name, "cancallforward")) { - confp->chan.cancallforward = ast_true(v->value); - } else if (!strcasecmp(v->name, "relaxdtmf")) { -- if (ast_true(v->value)) -+ if (ast_true(v->value)) - confp->chan.dtmfrelax = DSP_DIGITMODE_RELAXDTMF; - else - confp->chan.dtmfrelax = 0; -@@ -13914,6 +16569,8 @@ - confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS; - if (ast_true(v->value)) - confp->chan.callprogress |= CALLPROGRESS_PROGRESS; -+ } else if (!strcasecmp(v->name, "waitfordialtone")) { -+ confp->chan.waitfordialtone = atoi(v->value); - } else if (!strcasecmp(v->name, "faxdetect")) { - confp->chan.callprogress &= ~CALLPROGRESS_FAX; - if (!strcasecmp(v->value, "incoming")) { -@@ -13927,7 +16584,7 @@ - } 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 4000 ms at line %d.\n", v->lineno); -+ ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno); - } else { - confp->chan.echotraining = y; - } -@@ -13953,7 +16610,7 @@ - ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language)); - } else if (!strcasecmp(v->name, "progzone")) { - ast_copy_string(progzone, v->value, sizeof(progzone)); -- } else if (!strcasecmp(v->name, "mohinterpret") -+ } else if (!strcasecmp(v->name, "mohinterpret") - ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) { - ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret)); - } else if (!strcasecmp(v->name, "mohsuggest")) { -@@ -13993,7 +16650,7 @@ - confp->chan.transfertobusy = ast_true(v->value); - } else if (!strcasecmp(v->name, "mwimonitor")) { - confp->chan.mwimonitor_neon = 0; -- confp->chan.mwimonitor_fsk = 0; -+ confp->chan.mwimonitor_fsk = 0; - confp->chan.mwimonitor_rpas = 0; - if (strcasestr(v->value, "fsk")) { - confp->chan.mwimonitor_fsk = 1; -@@ -14007,7 +16664,7 @@ - /* If set to true or yes, assume that simple fsk is desired */ - if (ast_true(v->value)) { - confp->chan.mwimonitor_fsk = 1; -- } -+ } - } else if (!strcasecmp(v->name, "cid_rxgain")) { - if (sscanf(v->value, "%f", &confp->chan.cid_rxgain) != 1) { - ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno); -@@ -14030,7 +16687,7 @@ - confp->chan.cid_name[0] = '\0'; - } else { - ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num)); -- } -+ } - } else if (!strcasecmp(v->name, "fullname")) { - ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name)); - } else if (!strcasecmp(v->name, "cid_number")) { -@@ -14045,7 +16702,7 @@ - ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode)); - } else if (!strcasecmp(v->name, "amaflags")) { - y = ast_cdr_amaflags2int(v->value); -- if (y < 0) -+ if (y < 0) - ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno); - else - confp->chan.amaflags = y; -@@ -14060,11 +16717,35 @@ - } else if (!strcasecmp(v->name, "mwimonitornotify")) { - ast_copy_string(mwimonitornotify, v->value, sizeof(mwimonitornotify)); - } else if (!strcasecmp(v->name, "mwisendtype")) { -+#ifndef HAVE_DAHDI_LINEREVERSE_VMWI /* backward compatibility for older dahdi VMWI implementation */ - if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */ - mwisend_rpas = 1; - } else { - mwisend_rpas = 0; - } -+#else -+ /* Default is fsk, to turn it off you must specify nofsk */ -+ memset(&confp->chan.mwisend_setting, 0, sizeof(confp->chan.mwisend_setting)); -+ if (strcasestr(v->value, "nofsk")) { /* NoFSK */ -+ confp->chan.mwisend_fsk = 0; -+ } else { /* Default FSK */ -+ confp->chan.mwisend_fsk = 1; -+ } -+ if (strcasestr(v->value, "rpas")) { /* Ring Pulse Alert Signal, normally followed by FSK */ -+ confp->chan.mwisend_rpas = 1; -+ } else { -+ confp->chan.mwisend_rpas = 0; -+ } -+ if (strcasestr(v->value, "lrev")) { /* Line Reversal */ -+ confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_LREV; -+ } -+ if (strcasestr(v->value, "hvdc")) { /* HV 90VDC */ -+ confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVDC; -+ } -+ if ( (strcasestr(v->value, "neon")) || (strcasestr(v->value, "hvac")) ){ /* 90V DC pulses */ -+ confp->chan.mwisend_setting.vmwi_type |= DAHDI_VMWI_HVAC; -+ } -+#endif - } else if (reload != 1) { - if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) { - int orig_radio = confp->chan.radio; -@@ -14265,7 +16946,7 @@ - ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno); - } - } else if (!strcasecmp(v->name, "switchtype")) { -- if (!strcasecmp(v->value, "national")) -+ if (!strcasecmp(v->value, "national")) - confp->pri.switchtype = PRI_SWITCH_NI2; - else if (!strcasecmp(v->value, "ni1")) - confp->pri.switchtype = PRI_SWITCH_NI1; -@@ -14289,7 +16970,7 @@ - else if (!strcasecmp(v->value, "megacom")) - confp->pri.nsf = PRI_NSF_MEGACOM; - else if (!strcasecmp(v->value, "tollfreemegacom")) -- confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM; -+ confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM; - else if (!strcasecmp(v->value, "accunet")) - confp->pri.nsf = PRI_NSF_ACCUNET; - else if (!strcasecmp(v->value, "none")) -@@ -14329,7 +17010,7 @@ - } else if (!strcasecmp(v->name, "minunused")) { - confp->pri.minunused = atoi(v->value); - } else if (!strcasecmp(v->name, "minidle")) { -- confp->pri.minidle = atoi(v->value); -+ confp->pri.minidle = atoi(v->value); - } else if (!strcasecmp(v->name, "idleext")) { - ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext)); - } else if (!strcasecmp(v->name, "idledial")) { -@@ -14346,6 +17027,18 @@ - } else { - confp->pri.overlapdial = DAHDI_OVERLAPDIAL_NONE; - } -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ } else if (!strcasecmp(v->name, "qsigchannelmapping")) { -+ if (!strcasecmp(v->value, "logical")) { -+ confp->pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_LOGICAL; -+ } else if (!strcasecmp(v->value, "physical")) { -+ confp->pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL; -+ } else { -+ confp->pri.qsigchannelmapping = DAHDI_CHAN_MAPPING_PHYSICAL; -+ } -+#endif -+ } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) { -+ confp->pri.discardremoteholdretrieval = ast_true(v->value); - #ifdef HAVE_PRI_INBANDDISCONNECT - } else if (!strcasecmp(v->name, "inbanddisconnect")) { - confp->pri.inbanddisconnect = ast_true(v->value); -@@ -14450,7 +17143,6 @@ - } - if (ast_true(v->value)) - link->flags |= LINKSET_FLAG_EXPLICITACM; -- - #endif /* HAVE_SS7 */ - } else if (!strcasecmp(v->name, "cadence")) { - /* setup to scan our argument */ -@@ -14465,13 +17157,13 @@ - ast_copy_string(original_args, v->value, sizeof(original_args)); - /* 16 cadences allowed (8 pairs) */ - element_count = sscanf(v->value, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12], &c[13], &c[14], &c[15]); -- -+ - /* Cadence must be even (on/off) */ - if (element_count % 2 == 1) { - ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno); - cadence_is_ok = 0; - } -- -+ - /* Ring cadences cannot be negative */ - for (i = 0; i < element_count; i++) { - if (c[i] == 0) { -@@ -14501,12 +17193,12 @@ - } - } - } -- -+ - /* Substitute our scanned cadence */ - for (i = 0; i < 16; i++) { - new_cadence.ringcadence[i] = c[i]; - } -- -+ - if (cadence_is_ok) { - /* ---we scanned it without getting annoyed; now some sanity checks--- */ - if (element_count < 2) { -@@ -14584,7 +17276,7 @@ - } else if (!(options & PROC_DAHDI_OPT_NOWARN) ) - ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno); - } -- if (dahdichan[0]) { -+ if (dahdichan[0]) { - /* The user has set 'dahdichan' */ - /*< \todo pass proper line number instead of 0 */ - if (build_channels(confp, 0, dahdichan, reload, 0, &found_pseudo)) { -@@ -14610,7 +17302,7 @@ - } - return 0; - } -- -+ - static int setup_dahdi(int reload) - { - struct ast_config *cfg, *ucfg; -@@ -14638,13 +17330,28 @@ - return 0; - } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - ucfg = ast_config_load("users.conf", config_flags); -- if (ucfg == CONFIG_STATUS_FILEUNCHANGED) -+ if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { - return 0; -+ } else if (ucfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n"); -+ return 0; -+ } - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- cfg = ast_config_load(config, config_flags); -+ if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config); -+ ast_config_destroy(ucfg); -+ return 0; -+ } -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "File %s cannot be parsed. Aborting.\n", config); -+ return 0; - } else { - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- ucfg = ast_config_load("users.conf", config_flags); -+ if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "File users.conf cannot be parsed. Aborting.\n"); -+ ast_config_destroy(cfg); -+ return 0; -+ } - } - - /* It's a little silly to lock it, but we mind as well just to be sure */ -@@ -14685,7 +17392,7 @@ - if ((c = strchr(v->value, ','))) { - trunkgroup = atoi(c + 1); - if (trunkgroup > 0) { -- if ((c = strchr(c + 1, ','))) -+ if ((c = strchr(c + 1, ','))) - logicalspan = atoi(c + 1); - else - logicalspan = 0; -@@ -14709,7 +17416,7 @@ - } - } - #endif -- -+ - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf)); - -@@ -14730,10 +17437,10 @@ - /* [channels] and [trunkgroups] are used. Let's also reserve - * [globals] and [general] for future use - */ -- if (!strcasecmp(cat, "general") || -- !strcasecmp(cat, "trunkgroups") || -- !strcasecmp(cat, "globals") || -- !strcasecmp(cat, "channels")) { -+ if (!strcasecmp(cat, "general") || -+ !strcasecmp(cat, "trunkgroups") || -+ !strcasecmp(cat, "globals") || -+ !strcasecmp(cat, "channels")) { - continue; - } - -@@ -14830,9 +17537,15 @@ - } - pri_set_error(dahdi_pri_error); - pri_set_message(dahdi_pri_message); -- ast_register_application(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec, -- dahdi_send_keypad_facility_synopsis, dahdi_send_keypad_facility_descrip); -+ ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec); -+#ifdef HAVE_PRI_PROG_W_CAUSE -+ ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec); - #endif -+ ast_register_application_xml(dahdi_qsig_ccbsnr_initialize_app, dahdi_qsig_ccbsnr_initialize_exec); -+ ast_register_application_xml(dahdi_qsic_ccbsnr_request_app, dahdi_qsig_ccbsnr_request_exec); -+ ast_register_application_xml(dahdi_qsic_clear_nochannel_app, dahdi_qsig_clear_nochannel_exec); -+ ast_register_application_xml(dahdi_qsic_check_ccbsnr_app, dahdi_qsig_check_ccbsnr_exec); -+#endif - #ifdef HAVE_SS7 - memset(linksets, 0, sizeof(linksets)); - for (y = 0; y < NUM_SPANS; y++) { -@@ -14857,13 +17570,13 @@ - ast_string_field_init(&inuse, 16); - ast_string_field_set(&inuse, name, "GR-303InUse"); - ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli)); --#endif -+#endif - #ifdef HAVE_SS7 - ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli)); - #endif - - ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli)); -- -+ - memset(round_robin, 0, sizeof(round_robin)); - ast_manager_register( "DAHDITransfer", 0, action_transfer, "Transfer DAHDI Channel" ); - ast_manager_register( "DAHDIHangup", 0, action_transferhangup, "Hangup DAHDI Channel" ); -@@ -14873,7 +17586,6 @@ - ast_manager_register("DAHDIShowChannels", 0, action_dahdishowchannels, "Show status DAHDI channels"); - ast_manager_register("DAHDIRestart", 0, action_dahdirestart, "Fully Restart DAHDI channels (terminates calls)"); - -- ast_cond_init(&mwi_thread_complete, NULL); - ast_cond_init(&ss_thread_complete, NULL); - - return res; -@@ -14905,7 +17617,7 @@ - } - if (!text[0]) return(0); /* if nothing to send, dont */ - if ((!p->tdd) && (!p->mate)) return(0); /* if not in TDD mode, just return */ -- if (p->mate) -+ if (p->mate) - buf = ast_malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN); - else - buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN); -@@ -14953,7 +17665,7 @@ - ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel); - continue; - } -- /* if got exception */ -+ /* if got exception */ - if (fds[0].revents & POLLPRI) { - ast_free(mybuf); - return -1; -@@ -14983,6 +17695,11 @@ - { - int res = 0; - -+#if defined(HAVE_PRI) -+ cc_destroy_all_peer_link_id(); -+ ccbsnr_destroy_all(); -+#endif /* defined(HAVE_PRI) */ -+ - res = setup_dahdi(1); - if (res) { - ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n"); -@@ -15010,9 +17727,7 @@ - #endif - - AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc, -- .load = load_module, -- .unload = unload_module, -- .reload = reload, -- ); -- -- -+ .load = load_module, -+ .unload = unload_module, -+ .reload = reload, -+ ); -Index: channels/chan_phone.c -=================================================================== ---- a/channels/chan_phone.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_phone.c (.../team/group/issue14292) (revision 178988) -@@ -303,13 +303,13 @@ - snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min); - } - /* the standard format of ast->callerid is: "name" , but not always complete */ -- if (ast_strlen_zero(ast->cid.cid_name)) -+ if (ast_strlen_zero(ast->connected.id.name)) - strcpy(cid.name, DEFAULT_CALLER_ID); - else -- ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name)); -+ ast_copy_string(cid.name, ast->connected.id.name, sizeof(cid.name)); - -- if (ast->cid.cid_num) -- ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number)); -+ if (ast->connected.id.number) -+ ast_copy_string(cid.number, ast->connected.id.number, sizeof(cid.number)); - - p = ast->tech_pvt; - -@@ -1346,7 +1346,10 @@ - int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */ - struct ast_flags config_flags = { 0 }; - -- cfg = ast_config_load(config, config_flags); -+ if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); -+ return AST_MODULE_LOAD_DECLINE; -+ } - - /* We *must* have a config file otherwise stop immediately */ - if (!cfg) { -Index: channels/chan_h323.c -=================================================================== ---- a/channels/chan_h323.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_h323.c (.../team/group/issue14292) (revision 178988) -@@ -606,18 +606,18 @@ - /* make sure null terminated */ - called_addr[sizeof(called_addr) - 1] = '\0'; - -- if (c->cid.cid_num) -- ast_copy_string(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num)); -+ if (c->connected.id.number) -+ ast_copy_string(pvt->options.cid_num, c->connected.id.number, sizeof(pvt->options.cid_num)); - -- if (c->cid.cid_name) -- ast_copy_string(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name)); -+ if (c->connected.id.name) -+ ast_copy_string(pvt->options.cid_name, c->connected.id.name, sizeof(pvt->options.cid_name)); - - if (c->cid.cid_rdnis) { - ast_copy_string(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis)); - } - -- pvt->options.presentation = c->cid.cid_pres; -- pvt->options.type_of_number = c->cid.cid_ton; -+ pvt->options.presentation = c->connected.id.number_presentation; -+ pvt->options.type_of_number = c->connected.id.number_type; - - if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) { - if (!strcasecmp(addr, "UNKNOWN")) -@@ -1922,15 +1922,6 @@ - return info; - } - --/* -- * Definition taken from rtp.c for rtpPayloadType because we need it here. -- */ -- --struct rtpPayloadType { -- int isAstFormat; /* whether the following code is an AST_FORMAT */ -- int code; --}; -- - /*! \brief - * Call-back function passing remote ip/port information from H.323 to asterisk - * -@@ -2619,20 +2610,23 @@ - { - switch (cmd) { - case CLI_INIT: -- e->command = "h323 set trace [off]"; -+ e->command = "h323 set trace [on|off]"; - e->usage = -- "Usage: h323 set trace (off|)\n" -+ "Usage: h323 set trace (on|off|)\n" - " Enable/Disable H.323 stack tracing for debugging purposes\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != e->args) - return CLI_SHOWUSAGE; - if (!strcasecmp(a->argv[3], "off")) { - h323_debug(0, 0); - ast_cli(a->fd, "H.323 Trace Disabled\n"); -+ } else if (!strcasecmp(a->argv[3], "on")) { -+ h323_debug(1, 1); -+ ast_cli(a->fd, "H.323 Trace Enabled\n"); - } else { - int tracelevel = atoi(a->argv[3]); - h323_debug(1, tracelevel); -@@ -2645,21 +2639,21 @@ - { - switch (cmd) { - case CLI_INIT: -- e->command = "h323 set debug [off]"; -+ e->command = "h323 set debug [on|off]"; - e->usage = -- "Usage: h323 set debug [off]\n" -+ "Usage: h323 set debug [on|off]\n" - " Enable/Disable H.323 debugging output\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - -- if (a->argc < 3 || a->argc > 4) -+ if (a->argc != e->args) - return CLI_SHOWUSAGE; -- if (a->argc == 4 && strcasecmp(a->argv[3], "off")) -+ if (strcasecmp(a->argv[3], "on") && strcasecmp(a->argv[3], "off")) - return CLI_SHOWUSAGE; - -- h323debug = (a->argc == 3) ? 1 : 0; -+ h323debug = (strcasecmp(a->argv[3], "on")) ? 0 : 1; - ast_cli(a->fd, "H.323 Debugging %s\n", h323debug ? "Enabled" : "Disabled"); - return CLI_SUCCESS; - } -@@ -2816,13 +2810,28 @@ - return 1; - } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - ucfg = ast_config_load("users.conf", config_flags); -- if (ucfg == CONFIG_STATUS_FILEUNCHANGED) -+ if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { - return 0; -+ } else if (ucfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n"); -+ return 0; -+ } - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- cfg = ast_config_load(config, config_flags); -+ if ((cfg = ast_config_load(config, config_flags))) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); -+ ast_config_destroy(ucfg); -+ return 0; -+ } -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); -+ return 0; - } else { - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- ucfg = ast_config_load("users.conf", config_flags); -+ if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n"); -+ ast_config_destroy(cfg); -+ return 0; -+ } - } - - if (is_reload) { -Index: channels/chan_vpb.cc -=================================================================== ---- a/channels/chan_vpb.cc (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_vpb.cc (.../team/group/issue14292) (revision 178988) -@@ -30,7 +30,7 @@ - */ - - /*** MODULEINFO -- vpbapi -+ vpb - ***/ - - #include -@@ -2714,7 +2714,7 @@ - cfg = ast_config_load(config, config_flags); - - /* We *must* have a config file otherwise stop immediately */ -- if (!cfg) { -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_ERROR, "Unable to load config %s\n", config); - return AST_MODULE_LOAD_DECLINE; - } -Index: channels/chan_sip.c -=================================================================== ---- a/channels/chan_sip.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_sip.c (.../team/group/issue14292) (revision 178988) -@@ -31,17 +31,20 @@ - * ********** IMPORTANT * - * \note TCP/TLS support is EXPERIMENTAL and WILL CHANGE. This applies to configuration - * settings, dialplan commands and dialplans apps/functions -+ * See \ref sip_tcp_tls - * - * -- * TODO:s -+ * ******** General TODO:s - * \todo Better support of forking - * \todo VIA branch tag transaction checking - * \todo Transaction support -- * \todo We need to test TCP sessions with SIP proxies and in regards -- * to the SIP outbound specs. -- * \todo Fix TCP/TLS handling in dialplan, SRV records, transfers and much more -- * \todo Save TCP/TLS sessions in registry -- * \todo Add TCP/TLS information to function SIPPEER and SIPCHANINFO -+ * \todo Asterisk should send a non-100 provisional response every minute to keep proxies -+ * from cancelling the transaction (RFC 3261 13.3.1.1). See bug #11157. -+ * -+ * ******** Wishlist: Improvements -+ * - Support of SIP domains for devices, so that we match on username@domain in the From: header -+ * - Connect registrations with a specific device on the incoming call. It's not done -+ * automatically in Asterisk - * - * \ingroup channel_drivers - * -@@ -62,7 +65,8 @@ - * - * \par incoming packets - * Incoming packets are received in the monitoring thread, then handled by -- * sipsock_read(). This function parses the packet and matches an existing -+ * sipsock_read() for udp only. In tcp, packets are read by the tcp_helper thread. -+ * sipsock_read() function parses the packet and matches an existing - * dialog or starts a new SIP dialog. - * - * sipsock_read sends the packet to handle_incoming(), that parses a bit more. -@@ -90,6 +94,75 @@ - * the sip_hangup() function - */ - -+/*! -+ * \page sip_tcp_tls SIP TCP and TLS support -+ * -+ * \par tcpfixes TCP implementation changes needed -+ * \todo Fix TCP/TLS handling in dialplan, SRV records, transfers and much more -+ * \todo Save TCP/TLS sessions in registry -+ * If someone registers a SIPS uri, this forces us to set up a TLS connection back. -+ * \todo Add TCP/TLS information to function SIPPEER and SIPCHANINFO -+ * \todo If tcpenable=yes, we must open a TCP socket on the same address as the IP for UDP. -+ * The tcpbindaddr config option should only be used to open ADDITIONAL ports -+ * So we should propably go back to -+ * bindaddr= the default address to bind to. If tcpenable=yes, then bind this to both udp and TCP -+ * if tlsenable=yes, open TLS port (provided we also have cert) -+ * tcpbindaddr = extra address for additional TCP connections -+ * tlsbindaddr = extra address for additional TCP/TLS connections -+ * udpbindaddr = extra address for additional UDP connections -+ * These three options should take multiple IP/port pairs -+ * Note: Since opening additional listen sockets is a *new* feature we do not have today -+ * the XXXbindaddr options needs to be disabled until we have support for it -+ * -+ * \todo re-evaluate the transport= setting in sip.conf. This is right now not well -+ * thought of. If a device in sip.conf contacts us via TCP, we should not switch transport, -+ * even if udp is the configured first transport. -+ * -+ * \todo Be prepared for one outbound and another incoming socket per pvt. This applies -+ * specially to communication with other peers (proxies). -+ * \todo We need to test TCP sessions with SIP proxies and in regards -+ * to the SIP outbound specs. -+ * \todo ;transport=tls was deprecated in RFC3261 and should not be used at all. See section 26.2.2. -+ * -+ * \todo If the message is smaller than the given Content-length, the request should get a 400 Bad request -+ * message. If it's a response, it should be dropped. (RFC 3261, Section 18.3) -+ * \todo Since we have had multidomain support in Asterisk for quite a while, we need to support -+ * multiple domains in our TLS implementation, meaning one socket and one cert per domain -+ * \todo Selection of transport for a request needs to be done after we've parsed all route headers, -+ * also considering outbound proxy options. -+ * First request: Outboundproxy, routes, (reg contact or URI. If URI doesn't have port: DNS naptr, srv, AAA) -+ * Intermediate requests: Outboundproxy(only when forced), routes, contact/uri -+ * DNS naptr support is crucial. A SIP uri might lead to a TLS connection. -+ * Also note that due to outbound proxy settings, a SIPS uri might have to be sent on UDP (not to recommend though) -+ * \todo Default transports are set to UDP, which cause the wrong behaviour when contacting remote -+ * devices directly from the dialplan. UDP is only a fallback if no other method works, -+ * in order to be compatible with RFC2543 (SIP/1.0) devices. For transactions that exceed the -+ * MTU (like INIVTE with video, audio and RTT) TCP should be preferred. -+ * -+ * When dialling unconfigured peers (with no port number) or devices in external domains -+ * NAPTR records MUST be consulted to find configured transport. If they are not found, -+ * SRV records for both TCP and UDP should be checked. If there's a record for TCP, use that. -+ * If there's no record for TCP, then use UDP as a last resort. If there's no SRV records, -+ * \note this only applies if there's no outbound proxy configured for the session. If an outbound -+ * proxy is configured, these procedures might apply for locating the proxy and determining -+ * the transport to use for communication with the proxy. -+ * \par Other bugs to fix ---- -+ * __set_address_from_contact(const char *fullcontact, struct sockaddr_in *sin, int tcp) -+ * - sets TLS port as default for all TCP connections, unless other port is given in contact. -+ * parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req) -+ * - assumes that the contact the UA registers is using the same transport as the REGISTER request, which is -+ * a bad guess. -+ * - Does not save any information about TCP/TLS connected devices, which is a severe BUG, as discussed on the mailing list. -+ * get_destination(struct sip_pvt *p, struct sip_request *oreq) -+ * - Doesn't store the information that we got an incoming SIPS request in the channel, so that -+ * we can require a secure signalling path OUT of Asterisk (on SIP or IAX2). Possibly, the call should -+ * fail on in-secure signalling paths if there's no override in our configuration. At least, provide a -+ * channel variable in the dialplan. -+ * get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req) -+ * - As above, if we have a SIPS: uri in the refer-to header -+ * - Does not check transport in refer_to uri. -+ */ -+ - /*** MODULEINFO - chan_local - ***/ -@@ -199,6 +272,208 @@ - #include "asterisk/event.h" - #include "asterisk/tcptls.h" - -+/*** DOCUMENTATION -+ -+ -+ Change the dtmfmode for a SIP call. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Changes the dtmfmode for a SIP call. -+ -+ -+ -+ -+ Add a SIP header to the outbound call. -+ -+ -+ -+ -+ -+ -+ Adds a header to a SIP call placed with DIAL. -+ Remember to use the X-header if you are adding non-standard SIP -+ headers, like X-Asterisk-Accountcode:. Use this with care. -+ Adding the wrong headers may jeopardize the SIP dialog. -+ Always returns 0. -+ -+ -+ -+ -+ Remove SIP headers previously added with SIPAddHeader -+ -+ -+ -+ -+ -+ SIPRemoveHeader() allows you to remove headers which were previously -+ added with SIPAddHeader(). If no parameter is supplied, all previously added -+ headers will be removed. If a parameter is supplied, only the matching headers -+ will be removed. -+ For example you have added these 2 headers: -+ SIPAddHeader(P-Asserted-Identity: sip:foo@bar); -+ SIPAddHeader(P-Preferred-Identity: sip:bar@foo); -+ -+ // remove all headers -+ SIPRemoveHeader(); -+ // remove all P- headers -+ SIPRemoveHeader(P-); -+ // remove only the PAI header (note the : at the end) -+ SIPRemoveHeader(P-Asserted-Identity:); -+ -+ Always returns 0. -+ -+ -+ -+ -+ Gets the specified SIP header. -+ -+ -+ -+ -+ If not specified, defaults to 1. -+ -+ -+ -+ Since there are several headers (such as Via) which can occur multiple -+ times, SIP_HEADER takes an optional second argument to specify which header with -+ that name to retrieve. Headers start at offset 1. -+ -+ -+ -+ -+ Gets SIP peer information. -+ -+ -+ -+ -+ -+ -+ (default) The ip address. -+ -+ -+ The port number. -+ -+ -+ The configured mailbox. -+ -+ -+ The configured context. -+ -+ -+ The epoch time of the next expire. -+ -+ -+ Is it dynamic? (yes/no). -+ -+ -+ The configured Caller ID name. -+ -+ -+ The configured Caller ID number. -+ -+ -+ The configured Callgroup. -+ -+ -+ The configured Pickupgroup. -+ -+ -+ The configured codecs. -+ -+ -+ Status (if qualify=yes). -+ -+ -+ Registration extension. -+ -+ -+ Call limit (call-limit). -+ -+ -+ Configured call level for signalling busy. -+ -+ -+ Current amount of calls. Only available if call-limit is set. -+ -+ -+ Default language for peer. -+ -+ -+ Account code for this peer. -+ -+ -+ Current user agent id for peer. -+ -+ -+ A channel variable configured with setvar for this peer. -+ -+ -+ Preferred codec index number x (beginning with zero). -+ -+ -+ -+ -+ -+ -+ -+ -+ Gets the specified SIP parameter from the current channel. -+ -+ -+ -+ -+ -+ The IP address of the peer. -+ -+ -+ The source IP address of the peer. -+ -+ -+ The URI from the From: header. -+ -+ -+ The URI from the Contact: header. -+ -+ -+ The useragent. -+ -+ -+ The name of the peer. -+ -+ -+ 1 if T38 is offered or enabled in this channel, -+ otherwise 0. -+ -+ -+ -+ -+ -+ -+ -+ -+ Checks if domain is a local domain. -+ -+ -+ -+ -+ -+ This function checks if the domain in the argument is configured -+ as a local SIP domain that this Asterisk server is configured to handle. -+ Returns the domain name if it is locally handled, otherwise an empty string. -+ Check the domain= configuration in sip.conf. -+ -+ -+ ***/ -+ - #ifndef FALSE - #define FALSE 0 - #endif -@@ -207,21 +482,26 @@ - #define TRUE 1 - #endif - --#define SIPBUFSIZE 512 -+#ifndef MAX -+#define MAX(a,b) ((a) > (b) ? (a) : (b)) -+#endif - - /* Arguments for find_peer */ - #define FINDALLDEVICES FALSE - #define FINDONLYUSERS TRUE - -+#define SIPBUFSIZE 512 /*!< Buffer size for many operations */ -+ - #define XMIT_ERROR -2 - --#define SIP_RESERVED ";/?:@&=+$,# " -+#define SIP_RESERVED ";/?:@&=+$,# " /*!< Reserved characters in the username part of the URI */ - - /* #define VOCAL_DATA_HACK */ - - #define DEFAULT_DEFAULT_EXPIRY 120 - #define DEFAULT_MIN_EXPIRY 60 - #define DEFAULT_MAX_EXPIRY 3600 -+#define DEFAULT_MWI_EXPIRY 3600 - #define DEFAULT_REGISTRATION_TIMEOUT 20 - #define DEFAULT_MAX_FORWARDS "70" - -@@ -241,11 +521,12 @@ - static int min_expiry = DEFAULT_MIN_EXPIRY; /*!< Minimum accepted registration time */ - static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registration time */ - static int default_expiry = DEFAULT_DEFAULT_EXPIRY; -+static int mwi_expiry = DEFAULT_MWI_EXPIRY; - --#ifndef MAX --#define MAX(a,b) ((a) > (b) ? (a) : (b)) --#endif -+#define DEFAULT_QUALIFY_GAP 100 -+#define DEFAULT_QUALIFY_PEERS 1 - -+ - #define CALLERID_UNKNOWN "Unknown" - - #define DEFAULT_MAXMS 2000 /*!< Qualification: Must be faster than 2 seconds by default */ -@@ -254,19 +535,19 @@ - - #define DEFAULT_RETRANS 1000 /*!< How frequently to retransmit Default: 2 * 500 ms in RFC 3261 */ - #define MAX_RETRANS 6 /*!< Try only 6 times for retransmissions, a total of 7 transmissions */ --#define SIP_TIMER_T1 500 /* SIP timer T1 (according to RFC 3261) */ -+#define SIP_TIMER_T1 500 /*!< SIP timer T1 (according to RFC 3261) */ - #define SIP_TRANS_TIMEOUT 64 * SIP_TIMER_T1/*!< SIP request timeout (rfc 3261) 64*T1 - \todo Use known T1 for timeout (peerpoke) - */ --#define DEFAULT_TRANS_TIMEOUT -1 /* Use default SIP transaction timeout */ -+#define DEFAULT_TRANS_TIMEOUT -1 /*!< Use default SIP transaction timeout */ - #define MAX_AUTHTRIES 3 /*!< Try authentication three times, then fail */ - - #define SIP_MAX_HEADERS 64 /*!< Max amount of SIP headers to read */ - #define SIP_MAX_LINES 64 /*!< Max amount of lines in SIP attachment (like SDP) */ --#define SIP_MAX_PACKET 4096 /*!< Also from RFC 3261 (2543), should sub headers tho */ --#define SIP_MIN_PACKET 1024 /*!< Initialize size of memory to allocate for packets */ -+#define SIP_MIN_PACKET 4096 /*!< Initialize size of memory to allocate for packets */ -+#define MAX_HISTORY_ENTRIES 50 /*!< Max entires in the history list for a sip_pvt */ - --#define INITIAL_CSEQ 101 /*!< our initial sip sequence number */ -+#define INITIAL_CSEQ 101 /*!< Our initial sip sequence number */ - - #define DEFAULT_MAX_SE 1800 /*!< Session-Timer Default Session-Expires period (RFC 4028) */ - #define DEFAULT_MIN_SE 90 /*!< Session-Timer Default Min-SE period (RFC 4028) */ -@@ -281,15 +562,16 @@ - .resync_threshold = -1, - .impl = "" - }; --static struct ast_jb_conf global_jbconf; /*!< Global jitterbuffer configuration */ -+static struct ast_jb_conf global_jbconf; /*!< Global jitterbuffer configuration */ - --static const char config[] = "sip.conf"; /*!< Main configuration file */ -+static const char config[] = "sip.conf"; /*!< Main configuration file */ - static const char notify_config[] = "sip_notify.conf"; /*!< Configuration file for sending Notify with CLI commands to reconfigure or reboot phones */ - - #define RTP 1 - #define NO_RTP 0 - - /*! \brief Authorization scheme for call transfers -+ - \note Not a bitfield flag, since there are plans for other modes, - like "only allow transfers for authenticated devices" */ - enum transfermodes { -@@ -300,8 +582,8 @@ - - /*! \brief The result of a lot of functions */ - enum sip_result { -- AST_SUCCESS = 0, /*! FALSE means success, funny enough */ -- AST_FAILURE = -1, -+ AST_SUCCESS = 0, /*!< FALSE means success, funny enough */ -+ AST_FAILURE = -1, /*!< Failure code */ - }; - - /*! \brief States for the INVITE transaction, not the dialog -@@ -345,13 +627,14 @@ - XMIT_UNRELIABLE = 0, /*!< Transmit SIP message without bothering with re-transmits */ - }; - -+/*! \brief Results from the parse_register() function */ - enum parse_register_result { - PARSE_REGISTER_FAILED, - PARSE_REGISTER_UPDATE, - PARSE_REGISTER_QUERY, - }; - --/*! \brief Type of subscription, based on the packages we do support */ -+/*! \brief Type of subscription, based on the packages we do support, see \ref subscription_types */ - enum subscriptiontype { - NONE = 0, - XPIDF_XML, -@@ -411,7 +694,7 @@ - - /*! \brief States for outbound registrations (with register= lines in sip.conf */ - enum sipregistrystate { -- REG_STATE_UNREGISTERED = 0, /*!< We are not registred -+ REG_STATE_UNREGISTERED = 0, /*!< We are not registered - * \note Initial state. We should have a timeout scheduled for the initial - * (or next) registration transmission, calling sip_reregister - */ -@@ -470,15 +753,16 @@ - - /*! \brief definition of a sip proxy server - * -- * For outbound proxies, this is allocated in the SIP peer dynamically or -- * statically as the global_outboundproxy. The pointer in a SIP message is just -- * a pointer and should *not* be de-allocated. -+ * For outbound proxies, a sip_peer will contain a reference to a -+ * dynamically allocated instance of a sip_proxy. A sip_pvt may also -+ * contain a reference to a peer's outboundproxy, or it may contain -+ * a reference to the sip_cfg.outboundproxy. - */ - struct sip_proxy { - char name[MAXHOSTNAMELEN]; /*!< DNS name of domain/host or IP */ - struct sockaddr_in ip; /*!< Currently used IP address and port */ - time_t last_dnsupdate; /*!< When this was resolved */ -- enum sip_transport transport; -+ enum sip_transport transport; - int force; /*!< If it's an outbound proxy, Force use of this outbound proxy for all outbound requests */ - /* Room for a SRV record chain based on the name */ - }; -@@ -528,6 +812,13 @@ - SIP_PING, /*!< Not supported at all, no standard but still implemented out there */ - }; - -+/*! \brief Settings for the 'notifycid' option, see sip.conf.sample for details. */ -+enum notifycid_setting { -+ DISABLED = 0, -+ ENABLED = 1, -+ IGNORE_CONTEXT = 2, -+}; -+ - /*! \brief The core structure to setup dialogs. We parse incoming messages by using - structure and then route the messages according to the type. - -@@ -591,7 +882,8 @@ - #define SIP_OPT_FROMCHANGE (1 << 17) - #define SIP_OPT_RECLISTINV (1 << 18) - #define SIP_OPT_RECLISTSUB (1 << 19) --#define SIP_OPT_UNKNOWN (1 << 20) -+#define SIP_OPT_OUTBOUND (1 << 20) -+#define SIP_OPT_UNKNOWN (1 << 21) - - - /*! \brief List of well-known SIP options. If we get this in a require, -@@ -617,6 +909,8 @@ - { SIP_OPT_JOIN, NOT_SUPPORTED, "join" }, - /* Disable the REFER subscription, RFC 4488 */ - { SIP_OPT_NOREFERSUB, NOT_SUPPORTED, "norefersub" }, -+ /* SIP outbound - the final NAT battle - draft-sip-outbound */ -+ { SIP_OPT_OUTBOUND, NOT_SUPPORTED, "outbound" }, - /* RFC3327: Path support */ - { SIP_OPT_PATH, NOT_SUPPORTED, "path" }, - /* RFC3840: Callee preferences */ -@@ -645,9 +939,57 @@ - { SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED, "tdialog" }, - }; - -+/*! \brief Diversion header reasons -+ * -+ * The core defines a bunch of constants used to define -+ * redirecting reasons. This provides a translation table -+ * between those and the strings which may be present in -+ * a SIP Diversion header -+ */ -+static const struct sip_reasons { -+ enum AST_REDIRECTING_REASON code; -+ char * const text; -+} sip_reason_table[] = { -+ { AST_REDIRECTING_REASON_UNKNOWN, "unknown" }, -+ { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" }, -+ { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" }, -+ { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" }, -+ { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" }, -+ { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" }, -+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" }, -+ { AST_REDIRECTING_REASON_DEFLECTION, "deflection" }, -+ { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" }, -+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" }, -+ { AST_REDIRECTING_REASON_AWAY, "away" }, -+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"} -+}; - -+static enum AST_REDIRECTING_REASON sip_reason_str_to_code(const char *text) -+{ -+ enum AST_REDIRECTING_REASON ast = AST_REDIRECTING_REASON_UNKNOWN; -+ int i; -+ -+ for (i = 0; i < ARRAY_LEN(sip_reason_table); ++i) { -+ if (!strcasecmp(text, sip_reason_table[i].text)) { -+ ast = sip_reason_table[i].code; -+ break; -+ } -+ } -+ -+ return ast; -+} -+ -+static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code) -+{ -+ if (code >= 0 && code < ARRAY_LEN(sip_reason_table)) { -+ return sip_reason_table[code].text; -+ } -+ -+ return "unknown"; -+} -+ - /*! \brief SIP Methods we support -- \todo This string should be set dynamically. We only support REFER and SUBSCRIBE is we have -+ \todo This string should be set dynamically. We only support REFER and SUBSCRIBE if we have - allowsubscribe and allowrefer on in sip.conf. - */ - #define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY" -@@ -661,7 +1003,7 @@ - - /*! \brief Standard SIP unsecure port for UDP and TCP from RFC 3261. DO NOT CHANGE THIS */ - #define STANDARD_SIP_PORT 5060 --/*! \brief Standard SIP TLS port for sips: from RFC 3261. DO NOT CHANGE THIS */ -+/*! \brief Standard SIP TLS port from RFC 3261. DO NOT CHANGE THIS */ - #define STANDARD_TLS_PORT 5061 - - /*! \note in many SIP headers, absence of a port number implies port 5060, -@@ -680,16 +1022,17 @@ - yet encouraging new behaviour on new installations - */ - /*@{*/ --#define DEFAULT_CONTEXT "default" --#define DEFAULT_MOHINTERPRET "default" -+#define DEFAULT_CONTEXT "default" /*!< The default context for [general] section as well as devices */ -+#define DEFAULT_MOHINTERPRET "default" /*!< The default music class */ - #define DEFAULT_MOHSUGGEST "" --#define DEFAULT_VMEXTEN "asterisk" --#define DEFAULT_CALLERID "asterisk" -+#define DEFAULT_VMEXTEN "asterisk" /*!< Default voicemail extension */ -+#define DEFAULT_CALLERID "asterisk" /*!< Default caller ID */ - #define DEFAULT_NOTIFYMIME "application/simple-message-summary" - #define DEFAULT_ALLOWGUEST TRUE -+#define DEFAULT_RTPKEEPALIVE 0 /*!< Default RTPkeepalive setting */ - #define DEFAULT_CALLCOUNTER FALSE - #define DEFAULT_SRVLOOKUP TRUE /*!< Recommended setting is ON */ --#define DEFAULT_COMPACTHEADERS FALSE -+#define DEFAULT_COMPACTHEADERS FALSE /*!< Send compact (one-character) SIP headers. Default off */ - #define DEFAULT_TOS_SIP 0 /*!< Call signalling packets should be marked as DSCP CS3, but the default is 0 to be compatible with previous versions. */ - #define DEFAULT_TOS_AUDIO 0 /*!< Audio packets should be marked as DSCP EF (Expedited Forwarding), but the default is 0 to be compatible with previous versions. */ - #define DEFAULT_TOS_VIDEO 0 /*!< Video packets should be marked as DSCP AF41, but the default is 0 to be compatible with previous versions. */ -@@ -700,10 +1043,14 @@ - #define DEFAULT_COS_TEXT 5 /*!< Level 2 class of service for text media (T.140) */ - #define DEFAULT_ALLOW_EXT_DOM TRUE /*!< Allow external domains */ - #define DEFAULT_REALM "asterisk" /*!< Realm for HTTP digest authentication */ --#define DEFAULT_NOTIFYRINGING TRUE --#define DEFAULT_PEDANTIC FALSE --#define DEFAULT_AUTOCREATEPEER FALSE --#define DEFAULT_QUALIFY FALSE -+#define DEFAULT_NOTIFYRINGING TRUE /*!< Notify devicestate system on ringing state */ -+#define DEFAULT_NOTIFYCID DISABLED /*!< Include CID with ringing notifications */ -+#define DEFAULT_PEDANTIC FALSE /*!< Avoid following SIP standards for dialog matching */ -+#define DEFAULT_AUTOCREATEPEER FALSE /*!< Don't create peers automagically */ -+#define DEFAULT_MATCHEXTERNIPLOCALLY FALSE /*!< Match extern IP locally default setting */ -+#define DEFAULT_QUALIFY FALSE /*!< Don't monitor devices */ -+#define DEFAULT_CALLEVENTS FALSE /*!< Extra manager SIP call events */ -+#define DEFAULT_ALWAYSAUTHREJECT FALSE /*!< Don't reject authentication requests always */ - #define DEFAULT_REGEXTENONQUALIFY FALSE - #define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */ - #define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */ -@@ -719,8 +1066,6 @@ - configuring devices - */ - /*@{*/ --static char default_context[AST_MAX_CONTEXT]; --static char default_subscribecontext[AST_MAX_CONTEXT]; - static char default_language[MAX_LANGUAGE]; - static char default_callerid[AST_MAX_EXTENSION]; - static char default_fromdomain[AST_MAX_EXTENSION]; -@@ -733,15 +1078,9 @@ - static char default_parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */ - static int default_maxcallbitrate; /*!< Maximum bitrate for call */ - static struct ast_codec_pref default_prefs; /*!< Default codec prefs */ -+static unsigned int default_transports; /*!< Default Transports (enum sip_transport) that are acceptable */ -+static unsigned int default_primary_transport; /*!< Default primary Transport (enum sip_transport) for outbound connections to devices */ - --/*! \brief a place to store all global settings for the sip channel driver */ --struct sip_settings { -- int peer_rtupdate; /*!< G: Update database with registration data for peer? */ -- int rtsave_sysname; /*!< G: Save system name at registration? */ -- int ignore_regexpire; /*!< G: Ignore expiration of peer */ --}; -- --static struct sip_settings sip_cfg; - /*@}*/ - - /*! \name GlobalSettings -@@ -749,27 +1088,52 @@ - of sip.conf - */ - /*@{*/ --static int global_directrtpsetup; /*!< Enable support for Direct RTP setup (no re-invites) */ --static int global_rtautoclear; /*!< Realtime ?? */ --static int global_notifyringing; /*!< Send notifications on ringing */ --static int global_notifyhold; /*!< Send notifications on hold */ --static int global_alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */ --static int global_srvlookup; /*!< SRV Lookup on or off. Default is on */ --static int pedanticsipchecking; /*!< Extra checking ? Default off */ --static int autocreatepeer; /*!< Auto creation of peers at registration? Default off. */ -+/*! \brief a place to store all global settings for the sip channel driver -+ These are settings that will be possibly to apply on a group level later on. -+ \note Do not add settings that only apply to the channel itself and can't -+ be applied to devices (trunks, services, phones) -+*/ -+struct sip_settings { -+ int peer_rtupdate; /*!< G: Update database with registration data for peer? */ -+ int rtsave_sysname; /*!< G: Save system name at registration? */ -+ int ignore_regexpire; /*!< G: Ignore expiration of peer */ -+ int rtautoclear; /*!< Realtime ?? */ -+ int directrtpsetup; /*!< Enable support for Direct RTP setup (no re-invites) */ -+ int pedanticsipchecking; /*!< Extra checking ? Default off */ -+ int autocreatepeer; /*!< Auto creation of peers at registration? Default off. */ -+ int srvlookup; /*!< SRV Lookup on or off. Default is on */ -+ int allowguest; /*!< allow unauthenticated peers to connect? */ -+ int alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */ -+ int compactheaders; /*!< send compact sip headers */ -+ int allow_external_domains; /*!< Accept calls to external SIP domains? */ -+ int callevents; /*!< Whether we send manager events or not */ -+ int regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */ -+ int matchexterniplocally; /*!< Match externip/externhost setting against localnet setting */ -+ int notifyringing; /*!< Send notifications on ringing */ -+ int notifyhold; /*!< Send notifications on hold */ -+ enum notifycid_setting notifycid; /*!< Send CID with ringing notifications */ -+ enum transfermodes allowtransfer; /*!< SIP Refer restriction scheme */ -+ int allowsubscribe; /*!< Flag for disabling ALL subscriptions, this is FALSE only if all peers are FALSE -+ the global setting is in globals_flags[1] */ -+ char realm[MAXHOSTNAMELEN]; /*!< Default realm */ -+ struct sip_proxy outboundproxy; /*!< Outbound proxy */ -+ char default_context[AST_MAX_CONTEXT]; -+ char default_subscribecontext[AST_MAX_CONTEXT]; -+}; -+ -+static struct sip_settings sip_cfg; -+ - static int global_match_auth_username; /*!< Match auth username if available instead of From: Default off. */ -+ - static int global_relaxdtmf; /*!< Relax DTMF */ - static int global_rtptimeout; /*!< Time out call if no RTP */ - static int global_rtpholdtimeout; /*!< Time out call if no RTP during hold */ - static int global_rtpkeepalive; /*!< Send RTP keepalives */ - static int global_reg_timeout; - static int global_regattempts_max; /*!< Registration attempts before giving up */ --static int global_allowguest; /*!< allow unauthenticated peers to connect? */ - static int global_callcounter; /*!< Enable call counters for all devices. This is currently enabled by setting the peer - call-limit to 999. When we remove the call-limit from the code, we can make it - with just a boolean flag in the device structure */ --static int global_allowsubscribe; /*!< Flag for disabling ALL subscriptions, this is FALSE only if all peers are FALSE -- the global setting is in globals_flags[1] */ - static unsigned int global_tos_sip; /*!< IP type of service for SIP packets */ - static unsigned int global_tos_audio; /*!< IP type of service for audio RTP packets */ - static unsigned int global_tos_video; /*!< IP type of service for video RTP packets */ -@@ -778,26 +1142,20 @@ - static unsigned int global_cos_audio; /*!< 802.1p class of service for audio RTP packets */ - static unsigned int global_cos_video; /*!< 802.1p class of service for video RTP packets */ - static unsigned int global_cos_text; /*!< 802.1p class of service for text RTP packets */ --static int compactheaders; /*!< send compact sip headers */ - static int recordhistory; /*!< Record SIP history. Off by default */ - static int dumphistory; /*!< Dump history to verbose before destroying SIP dialog */ --static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */ - static char global_regcontext[AST_MAX_CONTEXT]; /*!< Context for auto-extensions */ - static char global_useragent[AST_MAX_EXTENSION]; /*!< Useragent for the SIP channel */ - static char global_sdpsession[AST_MAX_EXTENSION]; /*!< SDP session name for the SIP channel */ - static char global_sdpowner[AST_MAX_EXTENSION]; /*!< SDP owner name for the SIP channel */ --static int allow_external_domains; /*!< Accept calls to external SIP domains? */ --static int global_callevents; /*!< Whether we send manager events or not */ - static int global_authfailureevents; /*!< Whether we send authentication failure manager events or not. Default no. */ - static int global_t1; /*!< T1 time */ - static int global_t1min; /*!< T1 roundtrip time minimum */ - static int global_timer_b; /*!< Timer B - RFC 3261 Section 17.1.1.2 */ --static int global_regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */ - static int global_autoframing; /*!< Turn autoframing on or off. */ --static enum transfermodes global_allowtransfer; /*!< SIP Refer restriction scheme */ --static struct sip_proxy global_outboundproxy; /*!< Outbound proxy */ --static int global_matchexterniplocally; /*!< Match externip/externhost setting against localnet setting */ - static int global_qualifyfreq; /*!< Qualify frequency */ -+static int global_qualify_gap; /*!< Time between our group of peer pokes */ -+static int global_qualify_peers; /*!< Number of peers to poke at a given time */ - - - /*! \brief Codecs that we support by default: */ -@@ -912,7 +1270,7 @@ - * To avoid adding a bunch of redundant pointer arithmetic to the code, this macro is - * provided to retrieve the string at a particular offset within the request's buffer - */ --#define REQ_OFFSET_TO_STR(req,offset) ((req)->data->str + ((req)->offset)) -+#define REQ_OFFSET_TO_STR(req,offset) (ast_str_buffer((req)->data) + ((req)->offset)) - - /*! \brief structure used in transfers */ - struct sip_dual { -@@ -1039,7 +1397,10 @@ - #define SIP_PROG_INBAND_NO (1 << 25) - #define SIP_PROG_INBAND_YES (2 << 25) - --#define SIP_SENDRPID (1 << 29) /*!< DP: Remote Party-ID Support */ -+#define SIP_SENDRPID (3 << 29) /*!< DP: Remote Party-ID Support */ -+#define SIP_SENDRPID_NO (0 << 29) -+#define SIP_SENDRPID_PAI (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */ -+#define SIP_SENDRPID_RPID (2 << 29) /*!< Use "Remote-Party-ID" for rpid */ - #define SIP_G726_NONSTANDARD (1 << 31) /*!< DP: Use non-standard packing for G726-32 data */ - - /*! \brief Flags to copy from peer/user to dialog */ -@@ -1058,11 +1419,15 @@ - /* Space for addition of other realtime flags in the future */ - #define SIP_PAGE2_STATECHANGEQUEUE (1 << 9) /*!< D: Unsent state pending change exists */ - -+#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 10) -+#define SIP_PAGE2_RPID_IMMEDIATE (1 << 11) -+ - #define SIP_PAGE2_VIDEOSUPPORT (1 << 14) /*!< DP: Video supported if offered? */ - #define SIP_PAGE2_TEXTSUPPORT (1 << 15) /*!< GDP: Global text enable */ - #define SIP_PAGE2_ALLOWSUBSCRIBE (1 << 16) /*!< GP: Allow subscriptions from this peer? */ - #define SIP_PAGE2_ALLOWOVERLAP (1 << 17) /*!< DP: Allow overlap dialing ? */ - #define SIP_PAGE2_SUBSCRIBEMWIONLY (1 << 18) /*!< GP: Only issue MWI notification if subscribed to */ -+#define SIP_PAGE2_IGNORESDPVERSION (1 << 19) /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */ - - #define SIP_PAGE2_T38SUPPORT (7 << 20) /*!< GDP: T38 Fax Passthrough Support */ - #define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 20) /*!< GDP: T38 Fax Passthrough Support */ -@@ -1077,15 +1442,16 @@ - #define SIP_PAGE2_RFC2833_COMPENSATE (1 << 25) /*!< DP: Compensate for buggy RFC2833 implementations */ - #define SIP_PAGE2_BUGGY_MWI (1 << 26) /*!< DP: Buggy CISCO MWI fix */ - #define SIP_PAGE2_DIALOG_ESTABLISHED (1 << 27) /*!< 29: Has a dialog been established? */ -+#define SIP_PAGE2_FAX_DETECT (1 << 28) /*!< DP: Fax Detection support */ - #define SIP_PAGE2_REGISTERTRYING (1 << 29) /*!< DP: Send 100 Trying on REGISTER attempts */ - #define SIP_PAGE2_UDPTL_DESTINATION (1 << 30) /*!< DP: Use source IP of RTP as destination if NAT is enabled */ - #define SIP_PAGE2_VIDEOSUPPORT_ALWAYS (1 << 31) /*!< DP: Always set up video, even if endpoints don't support it */ - - #define SIP_PAGE2_FLAGS_TO_COPY \ -- (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | \ -- SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI | \ -- SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_UDPTL_DESTINATION | \ -- SIP_PAGE2_VIDEOSUPPORT_ALWAYS) -+ (SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_IGNORESDPVERSION | \ -+ SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | \ -+ SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \ -+ SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_RPID_IMMEDIATE) - - /*@}*/ - -@@ -1290,15 +1656,13 @@ - AST_STRING_FIELD(peermd5secret); - AST_STRING_FIELD(cid_num); /*!< Caller*ID number */ - AST_STRING_FIELD(cid_name); /*!< Caller*ID name */ -- AST_STRING_FIELD(via); /*!< Via: header */ - AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */ - /* we only store the part in in this field. */ - AST_STRING_FIELD(our_contact); /*!< Our contact header */ -- AST_STRING_FIELD(rpid); /*!< Our RPID header */ -- AST_STRING_FIELD(rpid_from); /*!< Our RPID From header */ - AST_STRING_FIELD(url); /*!< URL to be sent with next message to peer */ - AST_STRING_FIELD(parkinglot); /*!< Parkinglot */ - ); -+ char via[128]; /*!< Via: header */ - struct sip_socket socket; /*!< The socket used for this dialog */ - unsigned int ocseq; /*!< Current outgoing seqno */ - unsigned int icseq; /*!< Current incoming seqno */ -@@ -1330,7 +1694,7 @@ - int jointnoncodeccapability; /*!< Joint Non codec capability */ - int redircodecs; /*!< Redirect codecs */ - int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */ -- struct sip_proxy *outboundproxy; /*!< Outbound proxy for this dialog. Use ref_proxy to set this instead of setting it directly */ -+ struct sip_proxy *outboundproxy; /*!< Outbound proxy for this dialog. Use ref_proxy to set this instead of setting it directly*/ - struct t38properties t38; /*!< T38 settings */ - struct sockaddr_in udptlredirip; /*!< Where our T.38 UDPTL should be going if not to us */ - struct ast_udptl *udptl; /*!< T.38 UDPTL session */ -@@ -1398,12 +1762,13 @@ - you know more) */ - struct sip_st_dlg *stimer; /*!< SIP Session-Timers */ - -- int red; --}; -+ int red; /*!< T.140 RTP Redundancy */ -+ int hangupcause; /*!< Storage of hangupcause copied from our owner before we disconnect from the AST channel (only used at hangup) */ - --/*! Max entires in the history list for a sip_pvt */ --#define MAX_HISTORY_ENTRIES 50 -+ struct sip_subscription_mwi *mwi; /*!< If this is a subscription MWI dialog, to which subscription */ -+}; - -+ - /*! \brief - * Here we implement the container for dialogs (sip_pvt), defining - * generic wrapper functions to ease the transition from the current -@@ -1504,24 +1869,33 @@ - */ - /* XXX field 'name' must be first otherwise sip_addrcmp() will fail, as will astobj2 hashing of the structure */ - struct sip_peer { -- char name[80]; /*!< peer->name is the unique name of this object */ -+ char name[80]; /*!< the unique name of this object */ -+ AST_DECLARE_STRING_FIELDS( -+ AST_STRING_FIELD(secret); /*!< Password for inbound auth */ -+ AST_STRING_FIELD(md5secret); /*!< Password in MD5 */ -+ AST_STRING_FIELD(remotesecret); /*!< Remote secret (trunks, remote devices) */ -+ AST_STRING_FIELD(context); /*!< Default context for incoming calls */ -+ AST_STRING_FIELD(subscribecontext); /*!< Default context for subscriptions */ -+ AST_STRING_FIELD(username); /*!< Temporary username until registration */ -+ AST_STRING_FIELD(accountcode); /*!< Account code */ -+ AST_STRING_FIELD(tohost); /*!< If not dynamic, IP address */ -+ AST_STRING_FIELD(regexten); /*!< Extension to register (if regcontext is used) */ -+ AST_STRING_FIELD(fromuser); /*!< From: user when calling this peer */ -+ AST_STRING_FIELD(fromdomain); /*!< From: domain when calling this peer */ -+ AST_STRING_FIELD(fullcontact); /*!< Contact registered with us (not in sip.conf) */ -+ AST_STRING_FIELD(cid_num); /*!< Caller ID num */ -+ AST_STRING_FIELD(cid_name); /*!< Caller ID name */ -+ AST_STRING_FIELD(vmexten); /*!< Dialplan extension for MWI notify message*/ -+ AST_STRING_FIELD(language); /*!< Default language for prompts */ -+ AST_STRING_FIELD(mohinterpret); /*!< Music on Hold class */ -+ AST_STRING_FIELD(mohsuggest); /*!< Music on Hold class */ -+ AST_STRING_FIELD(parkinglot); /*!< Parkinglot */ -+ AST_STRING_FIELD(useragent); /*!< User agent in SIP request (saved from registration) */ -+ ); - struct sip_socket socket; /*!< Socket used for this peer */ -- unsigned int transports:3; /*!< Transports (enum sip_transport) that are acceptable for this peer */ -- char secret[80]; /*!< Password */ -- char md5secret[80]; /*!< Password in MD5 */ -+ unsigned int transports:3; /*!< Transports (enum sip_transport) that are acceptable for this peer */ - struct sip_auth *auth; /*!< Realm authentication list */ -- char context[AST_MAX_CONTEXT]; /*!< Default context for incoming calls */ -- char subscribecontext[AST_MAX_CONTEXT]; /*!< Default context for subscriptions */ -- char username[80]; /*!< Temporary username until registration */ -- char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */ - int amaflags; /*!< AMA Flags (for billing) */ -- char tohost[MAXHOSTNAMELEN]; /*!< If not dynamic, IP address */ -- char regexten[AST_MAX_EXTENSION]; /*!< Extension to register (if regcontext is used) */ -- char fromuser[80]; /*!< From: user when calling this peer */ -- char fromdomain[MAXHOSTNAMELEN]; /*!< From: domain when calling this peer */ -- char fullcontact[256]; /*!< Contact registered with us (not in sip.conf) */ -- char cid_num[80]; /*!< Caller ID num */ -- char cid_name[80]; /*!< Caller ID name */ - int callingpres; /*!< Calling id presentation */ - int inUse; /*!< Number of calls in use */ - int inRinging; /*!< Number of calls ringing */ -@@ -1529,12 +1903,6 @@ - int call_limit; /*!< Limit of concurrent calls */ - int busy_level; /*!< Level of active channels where we signal busy */ - enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */ -- char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/ -- char language[MAX_LANGUAGE]; /*!< Default language for prompts */ -- char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */ -- char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */ -- char parkinglot[AST_MAX_CONTEXT];/*!< Parkinglot */ -- char useragent[256]; /*!< User agent in SIP request (saved from registration) */ - struct ast_codec_pref prefs; /*!< codec prefs */ - int lastmsgssent; - unsigned int sipoptions; /*!< Supported SIP options */ -@@ -1545,10 +1913,9 @@ - - /* things that don't belong in flags */ - char is_realtime; /*!< this is a 'realtime' peer */ -- char rt_fromcontact; /*!< P: copy fromcontact from realtime */ -- char host_dynamic; /*!< P: Dynamic Peers register with Asterisk */ -- char selfdestruct; /*!< P: Automatic peers need to destruct themselves */ -- char onlymatchonip; /*!< P: Only match on IP for incoming calls (old type=peer) */ -+ char rt_fromcontact; /*!< copy fromcontact from realtime */ -+ char host_dynamic; /*!< Dynamic Peers register with Asterisk */ -+ char selfdestruct; /*!< Automatic peers need to destruct themselves */ - char the_mark; /*!< moved out of ASTOBJ into struct proper; That which bears the_mark should be deleted! */ - - int expire; /*!< When to expire this peer registration */ -@@ -1580,7 +1947,10 @@ - int timer_t1; /*!< The maximum T1 value for the peer */ - int timer_b; /*!< The maximum timer B (transaction timeouts) */ - int deprecated_username; /*!< If it's a realtime peer, are they using the deprecated "username" instead of "defaultuser" */ -+ -+ /*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */ - enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */ -+ char onlymatchonip; /*!< Only match on IP for incoming calls (old type=peer) */ - }; - - -@@ -1646,6 +2016,25 @@ - AST_LIST_ENTRY(sip_threadinfo) list; - }; - -+/*! \brief Definition of an MWI subscription to another server */ -+struct sip_subscription_mwi { -+ ASTOBJ_COMPONENTS_FULL(struct sip_subscription_mwi,1,1); -+ AST_DECLARE_STRING_FIELDS( -+ AST_STRING_FIELD(username); /*!< Who we are sending the subscription as */ -+ AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */ -+ AST_STRING_FIELD(hostname); /*!< Domain or host we subscribe to */ -+ AST_STRING_FIELD(secret); /*!< Password in clear text */ -+ AST_STRING_FIELD(mailbox); /*!< Mailbox store to put MWI into */ -+ ); -+ enum sip_transport transport; /*!< Transport to use */ -+ int portno; /*!< Optional port override */ -+ int resub; /*!< Sched ID of resubscription */ -+ unsigned int subscribed:1; /*!< Whether we are currently subscribed or not */ -+ struct sip_pvt *call; /*!< Outbound subscription dialog */ -+ struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for subscription */ -+ struct sockaddr_in us; /*!< Who the server thinks we are */ -+}; -+ - /* --- Hash tables of various objects --------*/ - - #ifdef LOW_MEMORY -@@ -1671,6 +2060,11 @@ - int recheck; - } regl; - -+/*! \brief The MWI subscription list */ -+static struct ast_subscription_mwi_list { -+ ASTOBJ_CONTAINER_COMPONENTS(struct sip_subscription_mwi); -+} submwil; -+ - /*! \brief - * \note The only member of the peer used here is the name field - */ -@@ -1715,18 +2109,15 @@ - { - struct sip_peer *peer = obj, *peer2 = arg; - -- if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr) { -+ if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr) - return 0; -- } - - if (!ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) && !ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) { -- if (peer->addr.sin_port == peer2->addr.sin_port) { -+ if (peer->addr.sin_port == peer2->addr.sin_port) - return CMP_MATCH | CMP_STOP; -- } else { -+ else - return 0; -- } - } -- - return CMP_MATCH | CMP_STOP; - } - -@@ -1771,11 +2162,11 @@ - - /* --- Sockets and networking --------------*/ - --/*! \brief Main socket for SIP communication. -+/*! \brief Main socket for UDP SIP communication. - * - * sipsock is shared between the SIP manager thread (which handles reload -- * requests), the io handler (sipsock_read()) and the user routines that -- * issue writes (using __sip_xmit()). -+ * requests), the udp io handler (sipsock_read()) and the user routines that -+ * issue udp writes (using __sip_xmit()). - * The socket is -1 only when opening fails (this is a permanent condition), - * or when we are handling a reload() that changes its address (this is - * a transient situation during which we might have a harmless race, see -@@ -1888,7 +2279,7 @@ - static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req); - static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req); - static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req); --static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp); -+static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid); - static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported); - static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale); - static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); -@@ -1901,7 +2292,7 @@ - static int transmit_info_with_vidupdate(struct sip_pvt *p); - static int transmit_message_with_text(struct sip_pvt *p, const char *text); - static int transmit_refer(struct sip_pvt *p, const char *dest); --static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten); -+static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten); - static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate); - static int transmit_notify_custom(struct sip_pvt *p, struct ast_variable *vars); - static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader); -@@ -1909,7 +2300,7 @@ - static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno); - static void copy_request(struct sip_request *dst, const struct sip_request *src); - static void receive_message(struct sip_pvt *p, struct sip_request *req); --static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req); -+static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward); - static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only); - - /*--- Dialog management */ -@@ -1947,10 +2338,10 @@ - static const char *get_sdp(struct sip_request *req, const char *name); - static int find_sdp(struct sip_request *req); - static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action); --static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate, -+static void add_codec_to_sdp(const struct sip_pvt *p, int codec, - struct ast_str **m_buf, struct ast_str **a_buf, - int debug, int *min_packet_size); --static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate, -+static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, - struct ast_str **m_buf, struct ast_str **a_buf, - int debug); - static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp); -@@ -1986,10 +2377,13 @@ - static void *do_monitor(void *data); - static int restart_monitor(void); - static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer); -+static struct ast_variable *copy_vars(struct ast_variable *src); - /* static int sip_addrcmp(char *name, struct sockaddr_in *sin); Support for peer matching */ - static int sip_refer_allocate(struct sip_pvt *p); - static void ast_quiet_chan(struct ast_channel *chan); - static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target); -+static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context); -+ - /*! - * \brief generic function for determining if a correct transport is being - * used to contact a peer -@@ -2004,7 +2398,7 @@ - else if (!(peer->transports & tmpl->socket.type)) {\ - ast_log(LOG_ERROR, \ - "'%s' is not a valid transport for '%s'. we only use '%s'! ending call.\n", \ -- get_transport(tmpl->socket.type), peer->name, get_transport_list(peer) \ -+ get_transport(tmpl->socket.type), peer->name, get_transport_list(peer->transports) \ - ); \ - ret = 1; \ - } else if (peer->socket.type & SIP_TRANSPORT_TLS) { \ -@@ -2056,6 +2450,7 @@ - static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); - static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); - static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); -+static char *sip_show_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); - static const char *subscription_type2str(enum subscriptiontype subtype) attribute_pure; - static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype); - static char *complete_sip_peer(const char *word, int state, int flags2); -@@ -2071,7 +2466,6 @@ - static char *sip_do_debug_peer(int fd, char *arg); - static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); - static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); --static char *sip_do_history_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); - static char *sip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); - static int sip_dtmfmode(struct ast_channel *chan, void *data); - static int sip_addheader(struct ast_channel *chan, void *data); -@@ -2112,7 +2506,7 @@ - static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v); - - /* Realtime device support */ --static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, const char *useragent, int expirey, int deprecated_username); -+static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, const char *useragent, int expirey, int deprecated_username, int lastms); - static void update_peer(struct sip_peer *p, int expire); - static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config); - static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername); -@@ -2154,11 +2548,14 @@ - static int set_address_from_contact(struct sip_pvt *pvt); - static void check_via(struct sip_pvt *p, struct sip_request *req); - static char *get_calleridname(const char *input, char *output, size_t outputsize); --static int get_rpid_num(const char *input, char *output, int maxlen); --static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq); -+static int get_rpid(struct sip_pvt *p, struct sip_request *oreq); -+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason); - static int get_destination(struct sip_pvt *p, struct sip_request *oreq); - static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline); - static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout); -+static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen); -+static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen); -+static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward); - - /*-- TCP connection handling ---*/ - static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session); -@@ -2170,6 +2567,7 @@ - static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch); - static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod); - static int init_resp(struct sip_request *resp, const char *msg); -+static inline int resp_needs_contact(const char *msg, enum sipmethod method); - static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req); - static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p); - static void build_via(struct sip_pvt *p); -@@ -2184,6 +2582,7 @@ - static int add_line(struct sip_request *req, const char *line); - static int add_text(struct sip_request *req, const char *text); - static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode); -+static int add_rpid(struct sip_request *req, struct sip_pvt *p); - static int add_vidupdate(struct sip_request *req); - static void add_route(struct sip_request *req, struct sip_route *route); - static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field); -@@ -2192,7 +2591,6 @@ - static void set_destination(struct sip_pvt *p, char *uri); - static void append_date(struct sip_request *req); - static void build_contact(struct sip_pvt *p); --static void build_rpid(struct sip_pvt *p); - - /*------Request handling functions */ - static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock); -@@ -2213,6 +2611,7 @@ - static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); - static void handle_response_notify(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); - static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); -+static void handle_response_subscribe(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); - static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); - static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); - -@@ -2245,6 +2644,12 @@ - static enum st_mode st_get_mode(struct sip_pvt *); - static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p); - -+/*!--- SIP MWI Subscription support */ -+static int sip_subscribe_mwi(const char *value, int lineno); -+static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi); -+static void sip_send_all_mwi_subscriptions(void); -+static int sip_subscribe_mwi_do(const void *data); -+static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi); - - /*! \brief Definition of this channel for PBX channel registration */ - static const struct ast_channel_tech sip_tech = { -@@ -2296,7 +2701,7 @@ - .master = AST_PTHREADT_NULL, - .tls_cfg = NULL, - .poll_timeout = -1, -- .name = "sip tcp server", -+ .name = "SIP TCP server", - .accept_fn = ast_tcptls_server_root, - .worker_fn = sip_tcp_worker_fn, - }; -@@ -2307,7 +2712,7 @@ - .master = AST_PTHREADT_NULL, - .tls_cfg = &sip_tls_cfg, - .poll_timeout = -1, -- .name = "sip tls server", -+ .name = "SIP TLS server", - .accept_fn = ast_tcptls_server_root, - .worker_fn = sip_tcp_worker_fn, - }; -@@ -2352,7 +2757,22 @@ - .get_codec = sip_get_codec, - }; - -+/*! -+ * duplicate a list of channel variables, \return the copy. -+ */ -+static struct ast_variable *copy_vars(struct ast_variable *src) -+{ -+ struct ast_variable *res = NULL, *tmp, *v = NULL; - -+ for (v = src ; v ; v = v->next) { -+ if ((tmp = ast_variable_new(v->name, v->value, v->file))) { -+ tmp->next = res; -+ res = tmp; -+ } -+ } -+ return res; -+} -+ - /*! \brief SIP TCP connection handler */ - static void *sip_tcp_worker_fn(void *data) - { -@@ -2361,7 +2781,9 @@ - return _sip_tcp_helper_thread(NULL, tcptls_session); - } - --/*! \brief SIP TCP thread management function */ -+/*! \brief SIP TCP thread management function -+ This function reads from the socket, parses the packet into a request -+*/ - static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session) - { - int res, cl; -@@ -2434,6 +2856,7 @@ - } - copy_request(&reqcpy, &req); - parse_request(&reqcpy); -+ /* In order to know how much to read, we need the content-length header */ - if (sscanf(get_header(&reqcpy, "Content-Length"), "%d", &cl)) { - while (cl > 0) { - ast_mutex_lock(&tcptls_session->lock); -@@ -2449,6 +2872,9 @@ - req.len = req.data->used; - } - } -+ /*! \todo XXX If there's no Content-Length or if the content-length and what -+ we receive is not the same - we should generate an error */ -+ - req.socket.tcptls_session = tcptls_session; - handle_request_do(&req, &tcptls_session->remote_address); - } -@@ -2472,6 +2898,7 @@ - } - - ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP"); -+ - - ao2_ref(tcptls_session, -1); - tcptls_session = NULL; -@@ -2508,18 +2935,19 @@ - * \param proxy The sip_proxy which we will point pvt towards. - * \return Returns void - */ --static struct sip_proxy *ref_proxy(struct sip_pvt *pvt, struct sip_proxy *proxy) -+static void ref_proxy(struct sip_pvt *pvt, struct sip_proxy *proxy) - { - struct sip_proxy *old_obproxy = pvt->outboundproxy; -- /* Cool, now get the refs correct */ -- if (proxy && proxy != &global_outboundproxy) { -+ /* The sip_cfg.outboundproxy is statically allocated, and so -+ * we don't ever need to adjust refcounts for it -+ */ -+ if (proxy && proxy != &sip_cfg.outboundproxy) { - ao2_ref(proxy, +1); - } - pvt->outboundproxy = proxy; -- if (old_obproxy && old_obproxy != &global_outboundproxy) { -+ if (old_obproxy && old_obproxy != &sip_cfg.outboundproxy) { - ao2_ref(old_obproxy, -1); - } -- return proxy; - } - - /*! -@@ -2616,6 +3044,12 @@ - return map_x_s(referstatusstrings, rstatus, ""); - } - -+static inline void pvt_set_needdestroy(struct sip_pvt *pvt, const char *reason) -+{ -+ append_history(pvt, "NeedDestroy", "Setting needdestroy because %s", reason); -+ pvt->needdestroy = 1; -+} -+ - /*! \brief Initialize the initital request packet in the pvt structure. - This packet is used for creating replies and future requests in - a dialog */ -@@ -2647,7 +3081,7 @@ - if (!inet_aton(proxy->name, &proxy->ip.sin_addr)) { - /* Ok, not an IP address, then let's check if it's a domain or host */ - /* XXX Todo - if we have proxy port, don't do SRV */ -- if (ast_get_ip_or_srv(&proxy->ip, proxy->name, global_srvlookup ? "_sip._udp" : NULL) < 0) { -+ if (ast_get_ip_or_srv(&proxy->ip, proxy->name, sip_cfg.srvlookup ? "_sip._udp" : NULL) < 0) { - ast_log(LOG_WARNING, "Unable to locate host '%s'\n", proxy->name); - return FALSE; - } -@@ -2679,11 +3113,11 @@ - append_history(dialog, "OBproxy", "Using peer obproxy %s", peer->outboundproxy->name); - return peer->outboundproxy; - } -- if (global_outboundproxy.name[0]) { -+ if (sip_cfg.outboundproxy.name[0]) { - if (sipdebug) - ast_debug(1, "OBPROXY: Applying global OBproxy to this call\n"); -- append_history(dialog, "OBproxy", "Using global obproxy %s", global_outboundproxy.name); -- return &global_outboundproxy; -+ append_history(dialog, "OBproxy", "Using global obproxy %s", sip_cfg.outboundproxy.name); -+ return &sip_cfg.outboundproxy; - } - if (sipdebug) - ast_debug(1, "OBPROXY: Not applying OBproxy to this call\n"); -@@ -2808,8 +3242,9 @@ - return sip_debug_test_addr(sip_real_dst(p)); - } - --static inline const char *get_transport_list(struct sip_peer *peer) { -- switch (peer->transports) { -+/*! \brief Return configuration of transports for a device */ -+static inline const char *get_transport_list(unsigned int transports) { -+ switch (transports) { - case SIP_TRANSPORT_UDP: - return "UDP"; - case SIP_TRANSPORT_TCP: -@@ -2823,11 +3258,12 @@ - case SIP_TRANSPORT_TCP | SIP_TRANSPORT_TLS: - return "TLS,TCP"; - default: -- return peer->transports ? -+ return transports ? - "TLS,TCP,UDP" : "UNKNOWN"; - } - } - -+/*! \brief Return transport as string */ - static inline const char *get_transport(enum sip_transport t) - { - switch (t) { -@@ -2842,6 +3278,12 @@ - return "UNKNOWN"; - } - -+/*! \brief Return transport of dialog. -+ \note this is based on a false assumption. We don't always use the -+ outbound proxy for all requests in a dialog. It depends on the -+ "force" parameter. The FIRST request is always sent to the ob proxy. -+ \todo Fix this function to work correctly -+*/ - static inline const char *get_transport_pvt(struct sip_pvt *p) - { - if (p->outboundproxy && p->outboundproxy->transport) -@@ -2860,7 +3302,7 @@ - int res = 0; - const struct sockaddr_in *dst = sip_real_dst(p); - -- ast_debug(1, "Trying to put '%.10s' onto %s socket destined for %s:%d\n", data->str, get_transport_pvt(p), ast_inet_ntoa(dst->sin_addr), htons(dst->sin_port)); -+ ast_debug(2, "Trying to put '%.10s' onto %s socket destined for %s:%d\n", data->str, get_transport_pvt(p), ast_inet_ntoa(dst->sin_addr), htons(dst->sin_port)); - - if (sip_prepare_socket(p) < 0) - return XMIT_ERROR; -@@ -2903,10 +3345,10 @@ - const char *rport = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : ""; - - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ -- ast_string_field_build(p, via, "SIP/2.0/%s %s:%d;branch=z9hG4bK%08x%s", -- get_transport_pvt(p), -- ast_inet_ntoa(p->ourip.sin_addr), -- ntohs(p->ourip.sin_port), (int) p->branch, rport); -+ snprintf(p->via, sizeof(p->via), "SIP/2.0/%s %s:%d;branch=z9hG4bK%08x%s", -+ get_transport_pvt(p), -+ ast_inet_ntoa(p->ourip.sin_addr), -+ ntohs(p->ourip.sin_port), (int) p->branch, rport); - } - - /*! \brief NAT fix - decide which IP address to use for Asterisk server? -@@ -2943,7 +3385,7 @@ - ast_apply_ha(localaddr, &theirs) == AST_SENSE_ALLOW ; - - if (want_remap && -- (!global_matchexterniplocally || !ast_apply_ha(localaddr, us)) ) { -+ (!sip_cfg.matchexterniplocally || !ast_apply_ha(localaddr, us)) ) { - /* if we used externhost or stun, see if it is time to refresh the info */ - if (externexpire && time(NULL) >= externexpire) { - if (stunaddr.sin_addr.s_addr) { -@@ -3100,7 +3542,7 @@ - - /* Let the peerpoke system expire packets when the timer expires for poke_noanswer */ - if (pkt->method != SIP_OPTIONS && pkt->method != SIP_REGISTER) { -- pkt->owner->needdestroy = 1; -+ pvt_set_needdestroy(pkt->owner, "no response to critical packet"); - sip_alreadygone(pkt->owner); - append_history(pkt->owner, "DialogKill", "Killing this failed dialog immediately"); - } -@@ -3112,7 +3554,7 @@ - if (pkt->owner->owner) - ast_channel_unlock(pkt->owner->owner); - append_history(pkt->owner, "ByeFailure", "Remote peer doesn't respond to bye. Destroying call anyway."); -- pkt->owner->needdestroy = 1; -+ pvt_set_needdestroy(pkt->owner, "no response to BYE"); - } - - /* Remove the packet */ -@@ -3151,14 +3593,15 @@ - - /* If the transport is something reliable (TCP or TLS) then don't really send this reliably */ - /* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */ -- /* According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */ -+ /*! \todo According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */ - if (!(p->socket.type & SIP_TRANSPORT_UDP)) { -- xmitres = __sip_xmit(dialog_ref(p, "pasing dialog ptr into callback..."), data, len); /* Send packet */ -+ xmitres = __sip_xmit(dialog_ref(p, "passing dialog ptr into callback..."), data, len); /* Send packet */ - if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */ - append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)"); - return AST_FAILURE; -- } else -+ } else { - return AST_SUCCESS; -+ } - } - - if (!(pkt = ast_calloc(1, sizeof(*pkt) + len + 1))) -@@ -3412,7 +3855,7 @@ - if (!req->lines) { - /* Add extra empty return. add_header() reserves 4 bytes so cannot be truncated */ - ast_str_append(&req->data, 0, "\r\n"); -- req->len = req->data->used; -+ req->len = ast_str_strlen(req->data); - } - } - -@@ -3608,6 +4051,8 @@ - * \verbatim - * general form we are expecting is sip[s]:username[:password][;parameter]@host[:port][;...] - * \endverbatim -+ * -+ * \todo This function needs to look for ;transport= too - */ - static int parse_uri(char *uri, char *scheme, - char **ret_name, char **pass, char **domain, char **port, char **options) -@@ -3735,12 +4180,13 @@ - that name and store that in the "regserver" field in the sippeers - table to facilitate multi-server setups. - */ --static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, int deprecated_username) -+static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, int deprecated_username, int lastms) - { - char port[10]; - char ipaddr[INET_ADDRSTRLEN]; - char regseconds[20]; - char *tablename = NULL; -+ char str_lastms[20]; - - const char *sysname = ast_config_AST_SYSTEM_NAME; - char *syslabel = NULL; -@@ -3752,6 +4198,8 @@ - - tablename = realtimeregs ? "sipregs" : "sippeers"; - -+ -+ snprintf(str_lastms, sizeof(str_lastms), "%d", lastms); - snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime); /* Expiration time */ - ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr)); - snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port)); -@@ -3765,12 +4213,12 @@ - ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, - "port", port, "regseconds", regseconds, - deprecated_username ? "username" : "defaultuser", defaultuser, -- "useragent", useragent, -+ "useragent", useragent, "lastms", str_lastms, - fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */ - } else { - ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, - "port", port, "regseconds", regseconds, -- "useragent", useragent, -+ "useragent", useragent, "lastms", str_lastms, - deprecated_username ? "username" : "defaultuser", defaultuser, - syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */ - } -@@ -3883,6 +4331,8 @@ - ao2_ref(peer->socket.tcptls_session, -1); - peer->socket.tcptls_session = NULL; - } -+ -+ ast_string_field_free_memory(peer); - } - - /*! \brief Update peer data in database (if used) */ -@@ -3891,7 +4341,7 @@ - int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS); - if (sip_cfg.peer_rtupdate && - (p->is_realtime || rtcachefriends)) { -- realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, p->useragent, expire, p->deprecated_username); -+ realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, p->useragent, expire, p->deprecated_username, p->lastms); - } - } - -@@ -4091,7 +4541,7 @@ - /* Cache peer */ - ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_RTAUTOCLEAR|SIP_PAGE2_RTCACHEFRIENDS); - if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR)) { -- AST_SCHED_REPLACE_UNREF(peer->expire, sched, global_rtautoclear * 1000, expire_register, peer, -+ AST_SCHED_REPLACE_UNREF(peer->expire, sched, sip_cfg.rtautoclear * 1000, expire_register, peer, - unref_peer(_data, "remove registration ref"), - unref_peer(peer, "remove registration ref"), - ref_peer(peer, "add registration ref")); -@@ -4112,30 +4562,20 @@ - return peer; - } - --/* The first element here must *always* be tmp_peer. This is because the user of this function -- * passes it in using OBJ_POINTER which causes astobj2 to perform hashing on the name to find -- * where the peer is. Since tmp_peer is at the beginning this just magically works. Move it and it -- * will break. People will be angry. Just don't do it. -- */ --struct peer_finding_info { -- struct sip_peer tmp_peer; -- int forcenamematch; --}; -- - /* Function to assist finding peers by name only */ --static int find_by_name(void *obj, void *arg, int flags) -+static int find_by_name(void *obj, void *arg, void *data, int flags) - { -- struct sip_peer *search = obj; -- struct peer_finding_info *pfi = arg; -+ struct sip_peer *search = obj, *match = arg; -+ int *forcenamematch = data; - - /* Usernames in SIP uri's are case sensitive. Domains are not */ -- if (strcmp(search->name, pfi->tmp_peer.name)) { -+ if (strcmp(search->name, match->name)) { - return 0; - } - - /* If we're only looking for name matches, we should avoid type=peer devices, - since these should not match on any name-based search */ -- if (pfi->forcenamematch && search->onlymatchonip) { -+ if (*forcenamematch && search->onlymatchonip) { - return 0; - } - -@@ -4146,19 +4586,19 @@ - * This is used on find matching device on name or ip/port. - If the device was declared as type=peer, we don't match on peer name on incoming INVITEs. - -- \note Avoid using this function in new functions if there is a way to avoid it, i -+ \note Avoid using this function in new functions if there is a way to avoid it, - since it might cause a database lookup. -+ - */ - static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int forcenamematch, int devstate_only) - { - struct sip_peer *p = NULL; -+ struct sip_peer tmp_peer; - - if (peer) { -- struct peer_finding_info pfi = { .forcenamematch = forcenamematch, }; -- ast_copy_string(pfi.tmp_peer.name, peer, sizeof(pfi.tmp_peer.name)); -- p = ao2_t_callback(peers, OBJ_POINTER, find_by_name, &pfi, "ao2_callback in peers table"); -+ ast_copy_string(tmp_peer.name, peer, sizeof(tmp_peer.name)); -+ p = ao2_t_callback_data(peers, OBJ_POINTER, find_by_name, &tmp_peer, &forcenamematch, "ao2_find in peers table"); - } else if (sin) { /* search by addr? */ -- struct sip_peer tmp_peer; - tmp_peer.addr.sin_addr.s_addr = sin->sin_addr.s_addr; - tmp_peer.addr.sin_port = sin->sin_port; - tmp_peer.flags[0].flags = 0; -@@ -4172,8 +4612,9 @@ - } - } - -- if (!p && (realtime || devstate_only)) -+ if (!p && (realtime || devstate_only)) { - p = realtime_peer(peer, sin, devstate_only); -+ } - - return p; - } -@@ -4230,6 +4671,28 @@ - /* Woot we got a message, create a control frame and send it on! */ - if (message) - ast_queue_control_data(chan, AST_CONTROL_T38, &message, sizeof(message)); -+ -+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT) && !p->outgoing_call) { -+ /* fax detection is enabled and this is an incoming call */ -+ ast_channel_lock(chan); -+ if (strcmp(chan->exten, "fax") && state == T38_ENABLED) { -+ const char *target_context = S_OR(chan->macrocontext, chan->context); -+ ast_channel_unlock(chan); -+ if (ast_exists_extension(chan, target_context, "fax", 1, chan->cid.cid_num)) { -+ /* save the DID/DNIS when we transfer the fax call to a 'fax' extension */ -+ ast_verb(3, "Redirecting '%s' to fax extension\n", chan->name); -+ pbx_builtin_setvar_helper(chan, "FAXEXTEN", chan->exten); -+ if (ast_async_goto(chan, target_context, "fax", 1)) { -+ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", chan->name, target_context); -+ } -+ } else { -+ ast_log(LOG_NOTICE, "Fax detected but no fax extension.\n"); -+ } -+ } else { -+ ast_channel_unlock(chan); -+ ast_debug(1, "Already in a fax extension (or T38 was not enabled, state: '%d'), not redirecting.\n", state); -+ } -+ } - } - - /*! \brief Set the global T38 capabilities on a SIP dialog structure */ -@@ -4270,6 +4733,7 @@ - */ - static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) - { -+ - /* this checks that the dialog is contacting the peer on a valid - * transport type based on the peers transport configuration, - * otherwise, this function bails out */ -@@ -4300,6 +4764,10 @@ - } - dialog->prefs = peer->prefs; - if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) { -+ if (!dialog->udptl) { -+ /* t38pt_udptl was enabled in the peer and not in [general] */ -+ dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr); -+ } - ast_copy_flags(&dialog->t38.t38support, &peer->flags[1], SIP_PAGE2_T38SUPPORT); - set_t38_capabilities(dialog); - dialog->t38.jointcapability = dialog->t38.capability; -@@ -4344,6 +4812,8 @@ - ast_string_field_set(dialog, tohost, peer->tohost); - ast_string_field_set(dialog, fullcontact, peer->fullcontact); - ast_string_field_set(dialog, context, peer->context); -+ ast_string_field_set(dialog, cid_num, peer->cid_num); -+ ast_string_field_set(dialog, cid_name, peer->cid_name); - ast_string_field_set(dialog, parkinglot, peer->parkinglot); - ref_proxy(dialog, obproxy_get(dialog, peer)); - dialog->callgroup = peer->callgroup; -@@ -4398,6 +4868,8 @@ - if (peer->call_limit) - ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT); - -+ dialog->chanvars = copy_vars(peer->chanvars); -+ - return 0; - } - -@@ -4410,7 +4882,7 @@ - struct ast_hostent ahp; - struct sip_peer *peer; - char *port; -- int portno; -+ int portno = 0; - char host[MAXHOSTNAMELEN], *hostn; - char peername[256]; - int srv_ret = 0; -@@ -4461,12 +4933,14 @@ - - /* Let's see if we can find the host in DNS. First try DNS SRV records, - then hostname lookup */ -- /*! \todo Fix this function. When we ask SRC, we should check all transports -+ /*! \todo Fix this function. When we ask for SRV, we should check all transports - In the future, we should first check NAPTR to find out transport preference - */ - hostn = peername; -- portno = port ? atoi(port) : (dialog->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT; -- if (global_srvlookup) { -+ /* Section 4.2 of RFC 3263 specifies that if a port number is specified, then -+ * an A record lookup should be used instead of SRV. -+ */ -+ if (!port && sip_cfg.srvlookup) { - char service[MAXHOSTNAMELEN]; - int tportno; - -@@ -4477,7 +4951,8 @@ - portno = tportno; - } - } -- -+ if (!portno) -+ portno = port ? atoi(port) : (dialog->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT; - hp = ast_gethostbyname(hostn, &ahp); - if (!hp) { - ast_log(LOG_WARNING, "No such host: %s\n", peername); -@@ -4544,6 +5019,8 @@ - } else if (!p->options->addsipheaders && !strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) { - /* Check whether there is a variable with a name starting with SIPADDHEADER */ - p->options->addsipheaders = 1; -+ } else if (!strcasecmp(ast_var_name(current), "SIPFROMDOMAIN")) { -+ ast_string_field_set(p, fromdomain, ast_var_value(current)); - } else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER")) { - /* This is a transfered call */ - p->options->transfer = 1; -@@ -4636,6 +5113,20 @@ - ast_free(reg); - } - -+/*! \brief Destroy MWI subscription object */ -+static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi) -+{ -+ if (mwi->call) { -+ mwi->call->mwi = NULL; -+ sip_destroy(mwi->call); -+ } -+ -+ AST_SCHED_DEL(sched, mwi->resub); -+ ast_string_field_free_memory(mwi); -+ ast_dnsmgr_release(mwi->dnsmgr); -+ ast_free(mwi); -+} -+ - /*! \brief Execute destruction of SIP dialog structure, release memory */ - static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist) - { -@@ -4679,6 +5170,10 @@ - p->registry = registry_unref(p->registry, "delete p->registry"); - } - -+ if (p->mwi) { -+ p->mwi->call = NULL; -+ } -+ - if (dumphistory) - sip_dump_history(p); - -@@ -4781,7 +5276,7 @@ - ast_copy_string(name, fup->username, sizeof(name)); - - /* Check the list of devices */ -- if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, TRUE, FINDALLDEVICES, FALSE) ) ) { /* Try to find peer */ -+ if ((p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, TRUE, FINDALLDEVICES, FALSE))) { - inuse = &p->inUse; - call_limit = &p->call_limit; - inringing = &p->inRinging; -@@ -4799,9 +5294,11 @@ - if (inuse) { - sip_pvt_lock(fup); - ao2_lock(p); -- if ((*inuse > 0) && ast_test_flag(&fup->flags[0], SIP_INC_COUNT)) { -- (*inuse)--; -- ast_clear_flag(&fup->flags[0], SIP_INC_COUNT); -+ if (*inuse > 0) { -+ if (ast_test_flag(&fup->flags[0], SIP_INC_COUNT)) { -+ (*inuse)--; -+ ast_clear_flag(&fup->flags[0], SIP_INC_COUNT); -+ } - } else { - *inuse = 0; - } -@@ -4813,9 +5310,11 @@ - if (inringing) { - sip_pvt_lock(fup); - ao2_lock(p); -- if ((*inringing > 0)&& ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { -- (*inringing)--; -- ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); -+ if (*inringing > 0) { -+ if (ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { -+ (*inringing)--; -+ ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); -+ } - } else { - *inringing = 0; - } -@@ -4826,7 +5325,7 @@ - /* Decrement onhold count if applicable */ - sip_pvt_lock(fup); - ao2_lock(p); -- if (ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD) && global_notifyhold) { -+ if (ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD) && sip_cfg.notifyhold) { - ast_clear_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD); - ao2_unlock(p); - sip_pvt_unlock(fup); -@@ -4844,7 +5343,7 @@ - /* If call limit is active and we have reached the limit, reject the call */ - if (*call_limit > 0 ) { - if (*inuse >= *call_limit) { -- ast_log(LOG_ERROR, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", "peer", name, *call_limit); -+ ast_log(LOG_NOTICE, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", "peer", name, *call_limit); - unref_peer(p, "update_call_counter: unref peer p, call limit exceeded"); - return -1; - } -@@ -4879,7 +5378,9 @@ - sip_pvt_lock(fup); - ao2_lock(p); - if (ast_test_flag(&fup->flags[0], SIP_INC_RINGING)) { -- (*inringing)--; -+ if (*inringing > 0) { -+ (*inringing)--; -+ } - ast_clear_flag(&fup->flags[0], SIP_INC_RINGING); - } - ao2_unlock(p); -@@ -5090,12 +5591,19 @@ - ast_debug(1, "Asked to hangup channel that was not connected\n"); - return 0; - } -- if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { -+ if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE) || ast->hangupcause == AST_CAUSE_ANSWERED_ELSEWHERE) { - ast_debug(1, "This call was answered elsewhere"); -+ if (ast->hangupcause == AST_CAUSE_ANSWERED_ELSEWHERE) { -+ ast_debug(1, "####### It's the cause code, buddy. The cause code!!!\n"); -+ } - append_history(p, "Cancel", "Call answered elsewhere"); - p->answered_elsewhere = TRUE; - } - -+ /* Store hangupcause locally in PVT so we still have it before disconnect */ -+ if (p->owner) -+ p->hangupcause = p->owner->hangupcause; -+ - if (ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) { - if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { - if (sipdebug) -@@ -5145,7 +5653,7 @@ - - stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */ - -- append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->owner->hangupcause) : "Unknown"); -+ append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->hangupcause) : "Unknown"); - - /* Disconnect */ - if (p->vad) -@@ -5196,7 +5704,7 @@ - } - } else { /* Incoming call, not up */ - const char *res; -- if (ast->hangupcause && (res = hangup_cause2sip(ast->hangupcause))) -+ if (p->hangupcause && (res = hangup_cause2sip(p->hangupcause))) - transmit_response_reliable(p, res, &p->initreq); - else - transmit_response_reliable(p, "603 Declined", &p->initreq); -@@ -5256,8 +5764,9 @@ - } - } - } -- if (needdestroy) -- p->needdestroy = 1; -+ if (needdestroy) { -+ pvt_set_needdestroy(p, "hangup"); -+ } - sip_pvt_unlock(p); - return 0; - } -@@ -5304,7 +5813,7 @@ - ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); - } else { - ast_rtp_new_source(p->rtp); -- res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE); -+ res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE, TRUE); - ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); - } - } -@@ -5341,7 +5850,7 @@ - !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { - ast_rtp_new_source(p->rtp); - p->invitestate = INV_EARLY_MEDIA; -- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); -+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); - } - p->lastrtptx = time(NULL); -@@ -5359,7 +5868,7 @@ - !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && - !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { - p->invitestate = INV_EARLY_MEDIA; -- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); -+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); - } - p->lastrtptx = time(NULL); -@@ -5380,7 +5889,7 @@ - !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && - !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { - p->invitestate = INV_EARLY_MEDIA; -- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); -+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); - } - p->lastrtptx = time(NULL); -@@ -5584,7 +6093,7 @@ - !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && - !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { - p->invitestate = INV_EARLY_MEDIA; -- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE); -+ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE); - ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); - break; - } -@@ -5630,6 +6139,12 @@ - case AST_CONTROL_SRCUPDATE: - ast_rtp_new_source(p->rtp); - break; -+ case AST_CONTROL_CONNECTED_LINE: -+ update_connectedline(p, data, datalen); -+ break; -+ case AST_CONTROL_REDIRECTING: -+ update_redirecting(p, data, datalen); -+ break; - case -1: - res = -1; - break; -@@ -5664,12 +6179,15 @@ - { - const char *my_name; /* pick a good name */ - -- if (title) -+ if (title) { - my_name = title; -- else if ( (my_name = strchr(i->fromdomain, ':')) ) -- my_name++; /* skip ':' */ -- else -- my_name = i->fromdomain; -+ } else { -+ char *port = NULL; -+ my_name = ast_strdupa(i->fromdomain); -+ if ((port = strchr(i->fromdomain, ':'))) { -+ *port = '\0'; -+ } -+ } - - sip_pvt_unlock(i); - /* Don't hold a sip pvt lock while we allocate a channel */ -@@ -5814,8 +6332,10 @@ - pbx_builtin_setvar_helper(tmp, "_T38CALL", "1"); - - /* Set channel variables for this call from configuration */ -- for (v = i->chanvars ; v ; v = v->next) -- pbx_builtin_setvar_helper(tmp, v->name, v->value); -+ for (v = i->chanvars ; v ; v = v->next) { -+ char valuebuf[1024]; -+ pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf))); -+ } - - if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { - ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); -@@ -5828,7 +6348,7 @@ - append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid); - - /* Inform manager user about new channel and their SIP call ID */ -- if (global_callevents) -+ if (sip_cfg.callevents) - manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", - "Channel: %s\r\nUniqueid: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\n", - tmp->name, tmp->uniqueid, "SIP", i->callid, i->fullcontact); -@@ -5837,9 +6357,9 @@ - } - - /*! \brief Reads one line of SIP message body */ --static char *get_body_by_line(const char *line, const char *name, int nameLen) -+static char *get_body_by_line(const char *line, const char *name, int nameLen, char delimiter) - { -- if (!strncasecmp(line, name, nameLen) && line[nameLen] == '=') -+ if (!strncasecmp(line, name, nameLen) && line[nameLen] == delimiter) - return ast_skip_blanks(line + nameLen + 1); - - return ""; -@@ -5854,7 +6374,7 @@ - int len = strlen(name); - - while (*start < req->sdp_end) { -- const char *r = get_body_by_line(REQ_OFFSET_TO_STR(req, line[(*start)++]), name, len); -+ const char *r = get_body_by_line(REQ_OFFSET_TO_STR(req, line[(*start)++]), name, len, '='); - if (r[0] != '\0') - return r; - } -@@ -5871,14 +6391,14 @@ - } - - /*! \brief Get a specific line from the message body */ --static char *get_body(struct sip_request *req, char *name) -+static char *get_body(struct sip_request *req, char *name, char delimiter) - { - int x; - int len = strlen(name); - char *r; - - for (x = 0; x < req->lines; x++) { -- r = get_body_by_line(REQ_OFFSET_TO_STR(req, line[x]), name, len); -+ r = get_body_by_line(REQ_OFFSET_TO_STR(req, line[x]), name, len, delimiter); - if (r[0] != '\0') - return r; - } -@@ -5944,7 +6464,7 @@ - char *header = REQ_OFFSET_TO_STR(req, header[x]); - if (!strncasecmp(header, name, len)) { - char *r = header + len; /* skip name */ -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - r = ast_skip_blanks(r); - - if (*r == ':') { -@@ -6265,7 +6785,7 @@ - ast_string_field_set(p, mohinterpret, default_mohinterpret); - ast_string_field_set(p, mohsuggest, default_mohsuggest); - p->capability = global_capability; -- p->allowtransfer = global_allowtransfer; -+ p->allowtransfer = sip_cfg.allowtransfer; - if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) || - (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) - p->noncodeccapability |= AST_RTP_DTMF; -@@ -6274,7 +6794,7 @@ - set_t38_capabilities(p); - p->t38.jointcapability = p->t38.capability; - } -- ast_string_field_set(p, context, default_context); -+ ast_string_field_set(p, context, sip_cfg.default_context); - ast_string_field_set(p, parkinglot, default_parkinglot); - - AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue); -@@ -6312,7 +6832,7 @@ - found = (!strcmp(p->callid, arg->callid)); - else { - found = !strcmp(p->callid, arg->callid); -- if (pedanticsipchecking && found) { -+ if (sip_cfg.pedanticsipchecking && found) { - found = ast_strlen_zero(arg->tag) || ast_strlen_zero(p->theirtag) || !ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED) || !strcmp(p->theirtag, arg->tag); - } - } -@@ -6320,7 +6840,7 @@ - ast_debug(5, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag); - - /* If we get a new request within an existing to-tag - check the to tag as well */ -- if (pedanticsipchecking && found && arg->method != SIP_RESPONSE) { /* SIP Request */ -+ if (sip_cfg.pedanticsipchecking && found && arg->method != SIP_RESPONSE) { /* SIP Request */ - if (p->tag[0] == '\0' && arg->totag[0]) { - /* We have no to tag, but they have. Wrong dialog */ - found = FALSE; -@@ -6366,7 +6886,7 @@ - arg.totag = totag; - arg.tag = ""; /* make sure tag is never NULL */ - -- if (pedanticsipchecking) { -+ if (sip_cfg.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 - and to tags to identify a call leg. -@@ -6394,7 +6914,7 @@ - } - - restartsearch: -- if (!pedanticsipchecking) { -+ if (!sip_cfg.pedanticsipchecking) { - struct sip_pvt tmp_dialog = { - .callid = callid, - }; -@@ -6472,7 +6992,6 @@ - enum sip_transport transport = SIP_TRANSPORT_UDP; - char buf[256] = ""; - char *username = NULL; -- char *port = NULL; - char *hostname=NULL, *secret=NULL, *authuser=NULL, *expire=NULL; - char *callback=NULL; - -@@ -6481,6 +7000,16 @@ - - ast_copy_string(buf, value, sizeof(buf)); - -+ /* split [/contact][~expiry] */ -+ expire = strchr(buf, '~'); -+ if (expire) -+ *expire++ = '\0'; -+ callback = strchr(buf, '/'); -+ if (callback) -+ *callback++ = '\0'; -+ if (ast_strlen_zero(callback)) -+ callback = "s"; -+ - sip_parse_host(buf, lineno, &username, &portnum, &transport); - - /* First split around the last '@' then parse the two components. */ -@@ -6491,34 +7020,24 @@ - ast_log(LOG_WARNING, "Format for registration is [transport://]user[:secret[:authuser]]@domain[:port][/extension][~expiry] at line %d\n", lineno); - return -1; - } -- /* split user[:secret[:authuser]] */ -- secret = strchr(username, ':'); -- if (secret) { -- *secret++ = '\0'; -- authuser = strchr(secret, ':'); -- if (authuser) -- *authuser++ = '\0'; -+ -+ /* split user[:secret[:authuser]] from the end to allow : character in user portion*/ -+ authuser = strrchr(username, ':'); -+ if (authuser) { -+ *authuser++ = '\0'; -+ secret = strrchr(username, ':'); -+ if (secret) -+ *secret++ = '\0'; -+ else { -+ secret = authuser; -+ authuser = NULL; -+ } - } -+ if ((authuser) && (ast_strlen_zero(authuser))) -+ authuser = NULL; -+ if ((secret) && (ast_strlen_zero(secret))) -+ secret = NULL; - -- /* split host[:port][/contact] */ -- expire = strchr(hostname, '~'); -- if (expire) -- *expire++ = '\0'; -- callback = strchr(hostname, '/'); -- if (callback) -- *callback++ = '\0'; -- if (ast_strlen_zero(callback)) -- callback = "s"; -- /* Separate host from port when checking for reserved characters -- */ -- if ((port = strchr(hostname, ':'))) { -- *port = '\0'; -- } -- /* And then re-merge the host and port so they are stored correctly -- */ -- if (port) { -- *port = ':'; -- } - if (!(reg = ast_calloc(1, sizeof(*reg)))) { - ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n"); - return -1; -@@ -6554,6 +7073,80 @@ - return 0; - } - -+/*! \brief Parse mwi=> line in sip.conf and add to list */ -+static int sip_subscribe_mwi(const char *value, int lineno) -+{ -+ struct sip_subscription_mwi *mwi; -+ int portnum = 0; -+ enum sip_transport transport = SIP_TRANSPORT_UDP; -+ char buf[256] = ""; -+ char *username = NULL, *hostname = NULL, *secret = NULL, *authuser = NULL, *porta = NULL, *mailbox = NULL; -+ -+ if (!value) { -+ return -1; -+ } -+ -+ ast_copy_string(buf, value, sizeof(buf)); -+ -+ sip_parse_host(buf, lineno, &username, &portnum, &transport); -+ -+ if ((hostname = strrchr(username, '@'))) { -+ *hostname++ = '\0'; -+ } -+ -+ if ((secret = strchr(username, ':'))) { -+ *secret++ = '\0'; -+ if ((authuser = strchr(secret, ':'))) { -+ *authuser++ = '\0'; -+ } -+ } -+ -+ if ((mailbox = strchr(hostname, '/'))) { -+ *mailbox++ = '\0'; -+ } -+ -+ if (ast_strlen_zero(username) || ast_strlen_zero(hostname) || ast_strlen_zero(mailbox)) { -+ ast_log(LOG_WARNING, "Format for MWI subscription is user[:secret[:authuser]]@host[:port][/mailbox] at line %d\n", lineno); -+ return -1; -+ } -+ -+ if ((porta = strchr(hostname, ':'))) { -+ *porta++ = '\0'; -+ if (!(portnum = atoi(porta))) { -+ ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno); -+ return -1; -+ } -+ } -+ -+ if (!(mwi = ast_calloc(1, sizeof(*mwi)))) { -+ return -1; -+ } -+ -+ if (ast_string_field_init(mwi, 256)) { -+ ast_free(mwi); -+ return -1; -+ } -+ -+ ASTOBJ_INIT(mwi); -+ ast_string_field_set(mwi, username, username); -+ if (secret) { -+ ast_string_field_set(mwi, secret, secret); -+ } -+ if (authuser) { -+ ast_string_field_set(mwi, authuser, authuser); -+ } -+ ast_string_field_set(mwi, hostname, hostname); -+ ast_string_field_set(mwi, mailbox, mailbox); -+ mwi->resub = -1; -+ mwi->portno = portnum; -+ mwi->transport = transport; -+ -+ ASTOBJ_CONTAINER_LINK(&submwil, mwi); -+ ASTOBJ_UNREF(mwi, sip_subscribe_mwi_destroy); -+ -+ return 0; -+} -+ - /*! \brief Parse multiline SIP headers into one header - This is enabled if pedanticsipchecking is enabled */ - static int lws2sws(char *msgbuf, int len) -@@ -6683,7 +7276,7 @@ - req->headers = i; - req->lines = 0; - /* req->data->used will be a NULL byte */ -- req->line[0] = req->data->used; -+ req->line[0] = ast_str_strlen(req->data); - } - - if (*c) { -@@ -6904,37 +7497,40 @@ - - o = get_sdp(req, "o"); - if (ast_strlen_zero(o)) { -- ast_log(LOG_WARNING, "SDP sytax error. SDP without an o= line\n"); -+ ast_log(LOG_WARNING, "SDP syntax error. SDP without an o= line\n"); - return -1; - } - - o_copy = ast_strdupa(o); - token = strsep(&o_copy, " "); /* Skip username */ - if (!o_copy) { -- ast_log(LOG_WARNING, "SDP sytax error in o= line username\n"); -+ ast_log(LOG_WARNING, "SDP syntax error in o= line username\n"); - return -1; - } - token = strsep(&o_copy, " "); /* Skip session-id */ - if (!o_copy) { -- ast_log(LOG_WARNING, "SDP sytax error in o= line session-id\n"); -+ ast_log(LOG_WARNING, "SDP syntax error in o= line session-id\n"); - return -1; - } - token = strsep(&o_copy, " "); /* Version */ - if (!o_copy) { -- ast_log(LOG_WARNING, "SDP sytax error in o= line\n"); -+ ast_log(LOG_WARNING, "SDP syntax error in o= line\n"); - return -1; - } - if (!sscanf(token, "%" SCNu64, &rua_version)) { -- ast_log(LOG_WARNING, "SDP sytax error in o= line version\n"); -+ ast_log(LOG_WARNING, "SDP syntax error in o= line version\n"); - return -1; - } - -- if (p->sessionversion_remote < 0 || p->sessionversion_remote != rua_version) { -- p->sessionversion_remote = rua_version; -+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_IGNORESDPVERSION) -+ || p->sessionversion_remote < 0 -+ || p->sessionversion_remote != rua_version) { -+ -+ p->sessionversion_remote = rua_version; - p->session_modify = TRUE; - } else if (p->sessionversion_remote == rua_version) { - p->session_modify = FALSE; -- ast_debug(2, "SDP version number same as previous SDP\n"); -+ ast_debug(2, "SDP version number same as previous SDP. Not parsing this SDP.\n"); - return 0; - } - -@@ -7144,23 +7740,18 @@ - /* XXX This needs to be done per media stream, since it's media stream specific */ - iterator = req->sdp_start; - while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') { -- char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */ -+ char mimeSubtype[128]; -+ char fmtp_string[64]; -+ unsigned int sample_rate; -+ - if (option_debug > 1) { - int breakout = FALSE; -- -+ - /* If we're debugging, check for unsupported sdp options */ - if (!strncasecmp(a, "rtcp:", (size_t) 5)) { - if (debug) - ast_verbose("Got unsupported a:rtcp in SDP offer \n"); - breakout = TRUE; -- } else if (!strncasecmp(a, "fmtp:", (size_t) 5)) { -- /* Format parameters: Not supported */ -- /* Note: This is used for codec parameters, like bitrate for -- G722 and video formats for H263 and H264 -- See RFC2327 for an example */ -- if (debug) -- ast_verbose("Got unsupported a:fmtp in SDP offer \n"); -- breakout = TRUE; - } else if (!strncasecmp(a, "framerate:", (size_t) 10)) { - /* Video stuff: Not supported */ - if (debug) -@@ -7180,21 +7771,29 @@ - if (breakout) /* We have a match, skip to next header */ - continue; - } -+ - if (!strcasecmp(a, "sendonly")) { - if (sendonly == -1) - sendonly = 1; - continue; -- } else if (!strcasecmp(a, "inactive")) { -+ } -+ -+ if (!strcasecmp(a, "inactive")) { - if (sendonly == -1) - sendonly = 2; - continue; -- } else if (!strcasecmp(a, "sendrecv")) { -+ } -+ -+ if (!strcasecmp(a, "sendrecv")) { - if (sendonly == -1) - sendonly = 0; - continue; -- } else if (strlen(a) > 5 && !strncasecmp(a, "ptime", 5)) { -+ } -+ -+ if (!strncasecmp(a, "ptime", 5)) { - char *tmp = strrchr(a, ':'); - long int framing = 0; -+ - if (tmp) { - tmp++; - framing = strtol(tmp, NULL, 10); -@@ -7218,8 +7817,9 @@ - ast_rtp_codec_setpref(p->rtp, pref); - } - continue; -- -- } else if (!strncmp(a, red_fmtp, strlen(red_fmtp))) { -+ } -+ -+ if (!strncmp(a, red_fmtp, strlen(red_fmtp))) { - /* count numbers of generations in fmtp */ - red_cp = &red_fmtp[strlen(red_fmtp)]; - strncpy(red_fmtp, a, 100); -@@ -7231,15 +7831,59 @@ - red_cp = strtok(NULL, "/"); - } - red_cp = red_fmtp; -+ continue; -+ } - -- } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) == 2) { -+ if (sscanf(a, "fmtp: %u %63s", &codec, fmtp_string) == 2) { -+ struct rtpPayloadType payload; -+ unsigned int handled = 0; -+ -+ payload = ast_rtp_lookup_pt(newaudiortp, codec); -+ if (!payload.code) { -+ /* it wasn't found, try the video rtp */ -+ payload = ast_rtp_lookup_pt(newvideortp, codec); -+ } -+ if (payload.code && payload.isAstFormat) { -+ unsigned int bit_rate; -+ -+ switch (payload.code) { -+ case AST_FORMAT_SIREN7: -+ if (sscanf(fmtp_string, "bitrate=%u", &bit_rate) == 1) { -+ if (bit_rate != 32000) { -+ ast_log(LOG_WARNING, "Got Siren7 offer at %d bps, but only 32000 bps supported; ignoring.\n", bit_rate); -+ ast_rtp_unset_m_type(newaudiortp, codec); -+ } else { -+ handled = 1; -+ } -+ } -+ break; -+ case AST_FORMAT_SIREN14: -+ if (sscanf(fmtp_string, "bitrate=%u", &bit_rate) == 1) { -+ if (bit_rate != 48000) { -+ ast_log(LOG_WARNING, "Got Siren14 offer at %d bps, but only 48000 bps supported; ignoring.\n", bit_rate); -+ ast_rtp_unset_m_type(newaudiortp, codec); -+ } else { -+ handled = 1; -+ } -+ } -+ break; -+ } -+ } -+ -+ if (!handled) { -+ ast_debug(1, "Got unsupported a:%s in SDP offer\n", a); -+ } -+ continue; -+ } -+ -+ if (sscanf(a, "rtpmap: %u %127[^/]/%u", &codec, mimeSubtype, &sample_rate) == 3) { - /* We have a rtpmap to handle */ - - if (last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) { -- /* Note: should really look at the 'freq' and '#chans' params too */ -+ /* Note: should really look at the '#chans' params too */ - /* Note: This should all be done in the context of the m= above */ - if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) { /* Video */ -- if(ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0) != -1) { -+ if (ast_rtp_set_rtpmap_type_rate(newvideortp, codec, "video", mimeSubtype, 0, sample_rate) != -1) { - if (debug) - ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec); - found_rtpmap_codecs[last_rtpmap_codec] = codec; -@@ -7261,11 +7905,12 @@ - sprintf(red_fmtp, "fmtp:%d ", red_pt); - - if (debug) -- ast_verbose("Red submimetype has payload type: %d\n", red_pt); -+ ast_verbose("RED submimetype has payload type: %d\n", red_pt); - } - } else { /* Must be audio?? */ -- if(ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype, -- ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0) != -1) { -+ if (ast_rtp_set_rtpmap_type_rate(newaudiortp, codec, "audio", mimeSubtype, -+ ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0, -+ sample_rate) != -1) { - if (debug) - ast_verbose("Found audio description format %s for ID %d\n", mimeSubtype, codec); - found_rtpmap_codecs[last_rtpmap_codec] = codec; -@@ -7526,14 +8171,14 @@ - ast_queue_frame(p->owner, &ast_null_frame); - /* Queue Manager Unhold event */ - append_history(p, "Unhold", "%s", req->data->str); -- if (global_callevents) -+ if (sip_cfg.callevents) - manager_event(EVENT_FLAG_CALL, "Hold", - "Status: Off\r\n" - "Channel: %s\r\n" - "Uniqueid: %s\r\n", - p->owner->name, - p->owner->uniqueid); -- if (global_notifyhold) -+ if (sip_cfg.notifyhold) - sip_peer_hold(p, FALSE); - ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */ - } else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1)) { -@@ -7548,7 +8193,7 @@ - ast_queue_frame(p->owner, &ast_null_frame); - /* Queue Manager Hold event */ - append_history(p, "Hold", "%s", req->data->str); -- if (global_callevents && !ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { -+ if (sip_cfg.callevents && !ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { - manager_event(EVENT_FLAG_CALL, "Hold", - "Status: On\r\n" - "Channel: %s\r\n" -@@ -7562,7 +8207,7 @@ - ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_INACTIVE); - else - ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_ACTIVE); -- if (global_notifyhold && !already_on_hold) -+ if (sip_cfg.notifyhold && !already_on_hold) - sip_peer_hold(p, TRUE); - } - -@@ -7590,13 +8235,14 @@ - return -1; - } - -- if (compactheaders) -+ if (sip_cfg.compactheaders) { - var = find_alias(var, var); -+ } - - ast_str_append(&req->data, 0, "%s: %s\r\n", var, value); - req->header[req->headers] = req->len; - -- req->len = req->data->used; -+ req->len = ast_str_strlen(req->data); - req->headers++; - - return 0; -@@ -7623,7 +8269,7 @@ - req->len += ast_str_append(&req->data, 0, "\r\n"); - req->line[req->lines] = req->len; - ast_str_append(&req->data, 0, "%s", line); -- req->len = req->data->used; -+ req->len = ast_str_strlen(req->data); - req->lines++; - return 0; - } -@@ -7756,7 +8402,15 @@ - add_header(req, "Route", r); - } - --/*! \brief Set destination from SIP URI */ -+/*! \brief Set destination from SIP URI -+ * -+ * Parse uri to h (host) and port - uri is already just the part inside the <> -+ * general form we are expecting is sip[s]:username[:password][;parameter]@host[:port][;...] -+ * If there's a port given, turn NAPTR/SRV off. NAPTR might indicate SIPS preference even -+ * for SIP: uri's -+ * -+ * If there's a sips: uri scheme, TLS will be required. -+ */ - static void set_destination(struct sip_pvt *p, char *uri) - { - char *h, *maddr, hostname[256]; -@@ -7764,10 +8418,9 @@ - struct hostent *hp; - struct ast_hostent ahp; - int debug=sip_debug_test_pvt(p); -+ int tls_on = FALSE; -+ int use_dns = sip_cfg.srvlookup; - -- /* Parse uri to h (host) and port - uri is already just the part inside the <> */ -- /* general form we are expecting is sip[s]:username[:password][;parameter]@host[:port][;...] */ -- - if (debug) - ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri); - -@@ -7777,10 +8430,12 @@ - ++h; - else { - h = uri; -- if (!strncasecmp(h, "sip:", 4)) -+ if (!strncasecmp(h, "sip:", 4)) { - h += 4; -- else if (!strncasecmp(h, "sips:", 5)) -+ } else if (!strncasecmp(h, "sips:", 5)) { - h += 5; -+ tls_on = TRUE; -+ } - } - hn = strcspn(h, ":;>") + 1; - if (hn > sizeof(hostname)) -@@ -7794,9 +8449,9 @@ - /* Parse port */ - ++h; - port = strtol(h, &h, 10); -- } -- else -- port = STANDARD_SIP_PORT; -+ use_dns = FALSE; -+ } else -+ port = tls_on ? STANDARD_TLS_PORT : STANDARD_SIP_PORT; - - /* Got the hostname:port - but maybe there's a "maddr=" to override address? */ - maddr = strstr(h, "maddr="); -@@ -7807,6 +8462,8 @@ - hn = sizeof(hostname); - ast_copy_string(hostname, maddr, hn); - } -+ -+ /*! \todo XXX If we have use_dns on, then look for NAPTR/SRV, otherwise, just look for A records */ - - hp = ast_gethostbyname(hostname, &ahp); - if (hp == NULL) { -@@ -7845,12 +8502,72 @@ - req->method = sipmethod; - req->header[0] = 0; - ast_str_set(&req->data, 0, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip); -- req->len = req->data->used; -+ req->len = ast_str_strlen(req->data); - req->headers++; - return 0; - } - -+/*! \brief Test if this response needs a contact header */ -+static inline int resp_needs_contact(const char *msg, enum sipmethod method) { -+ /* Requirements for Contact header inclusion in responses generated -+ * from the header tables found in the following RFCs. Where the -+ * Contact header was marked mandatory (m) or optional (o) this -+ * function returns 1. -+ * -+ * - RFC 3261 (ACK, BYE, CANCEL, INVITE, OPTIONS, REGISTER) -+ * - RFC 2976 (INFO) -+ * - RFC 3262 (PRACK) -+ * - RFC 3265 (SUBSCRIBE, NOTIFY) -+ * - RFC 3311 (UPDATE) -+ * - RFC 3428 (MESSAGE) -+ * - RFC 3515 (REFER) -+ * - RFC 3903 (PUBLISH) -+ */ - -+ switch (method) { -+ /* 1xx, 2xx, 3xx, 485 */ -+ case SIP_INVITE: -+ case SIP_UPDATE: -+ case SIP_SUBSCRIBE: -+ case SIP_NOTIFY: -+ if ((msg[0] >= '1' && msg[0] <= '3') || !strncmp(msg, "485", 3)) -+ return 1; -+ break; -+ -+ /* 2xx, 3xx, 485 */ -+ case SIP_REGISTER: -+ case SIP_OPTIONS: -+ if (msg[0] == '2' || msg[0] == '3' || !strncmp(msg, "485", 3)) -+ return 1; -+ break; -+ -+ /* 3xx, 485 */ -+ case SIP_BYE: -+ case SIP_PRACK: -+ case SIP_MESSAGE: -+ case SIP_PUBLISH: -+ if (msg[0] == '3' || !strncmp(msg, "485", 3)) -+ return 1; -+ break; -+ -+ /* 2xx, 3xx, 4xx, 5xx, 6xx */ -+ case SIP_REFER: -+ if (msg[0] >= '2' && msg[0] <= '6') -+ return 1; -+ break; -+ -+ /* contact will not be included for everything else */ -+ case SIP_ACK: -+ case SIP_CANCEL: -+ case SIP_INFO: -+ case SIP_PING: -+ default: -+ return 0; -+ } -+ return 0; -+} -+ -+ - /*! \brief Prepare SIP response packet */ - static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req) - { -@@ -7903,7 +8620,7 @@ - snprintf(contact, sizeof(contact), "%s;expires=%d", p->our_contact, p->expiry); - add_header(resp, "Contact", contact); /* Not when we unregister */ - } -- } else if (msg[0] != '4' && !ast_strlen_zero(p->our_contact)) { -+ } else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) { - add_header(resp, "Contact", p->our_contact); - } - -@@ -8017,9 +8734,6 @@ - if (!ast_strlen_zero(global_useragent)) - add_header(req, "User-Agent", global_useragent); - -- if (!ast_strlen_zero(p->rpid)) -- add_header(req, "Remote-Party-ID", p->rpid); -- - if (!ast_strlen_zero(p->url)) { - add_header(req, "Access-URL", p->url); - ast_string_field_set(p, url, NULL); -@@ -8057,6 +8771,14 @@ - return -1; - } - respprep(&resp, p, msg, req); -+ -+ if (ast_test_flag(&p->flags[0], SIP_SENDRPID) -+ && ast_test_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND) -+ && (!strcasecmp(msg, "180 Ringing") || !strcasecmp(msg, "183 Session Progress"))) { -+ ast_clear_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND); -+ add_rpid(&resp, p); -+ } -+ - add_header_contentLength(&resp, 0); - /* If we are cancelling an incoming invite for some reason, add information - about the reason why we are doing this in clear text */ -@@ -8226,7 +8948,7 @@ - } - /* Stale means that they sent us correct authentication, but - based it on an old challenge (nonce) */ -- snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", global_realm, randdata, stale ? ", stale=true" : ""); -+ snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", sip_cfg.realm, randdata, stale ? ", stale=true" : ""); - respprep(&resp, p, msg, req); - add_header(&resp, header, tmp); - add_header_contentLength(&resp, 0); -@@ -8276,6 +8998,84 @@ - return 0; - } - -+/*! \brief Add Remote-Party-ID header to SIP message */ -+static int add_rpid(struct sip_request *req, struct sip_pvt *p) { -+ char tmp[256]; -+ char *lid_num = NULL; -+ char *lid_name = NULL; -+ int lid_pres; -+ const char *fromdomain; -+ const char *privacy = NULL; -+ const char *screen = NULL; -+ const char *anonymous_string = "\"Anonymous\" "; -+ -+ if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) { -+ return 0; -+ } -+ -+ if (p->owner && p->owner->connected.id.number) -+ lid_num = p->owner->connected.id.number; -+ if (p->owner && p->owner->connected.id.name) -+ lid_name = p->owner->connected.id.name; -+ lid_pres = (p->owner) ? p->owner->connected.id.number_presentation : AST_PRES_NUMBER_NOT_AVAILABLE; -+ -+ if (ast_strlen_zero(lid_num)) -+ return 0; -+ if (ast_strlen_zero(lid_name)) -+ lid_name = lid_num; -+ fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); -+ -+ if (ast_test_flag(&p->flags[0], SIP_SENDRPID_PAI)) { -+ if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) { -+ snprintf(tmp, sizeof(tmp), "%s", anonymous_string); -+ } else { -+ snprintf(tmp, sizeof(tmp), "\"%s\" ", lid_name, lid_num, fromdomain); -+ } -+ add_header(req, "P-Asserted-Identity", tmp); -+ } else { -+ snprintf(tmp, sizeof(tmp), "\"%s\" ;party=%s", lid_name, lid_num, fromdomain, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "calling" : "called"); -+ -+ switch (lid_pres) { -+ case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: -+ case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: -+ privacy = "off"; -+ screen = "no"; -+ break; -+ case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: -+ case AST_PRES_ALLOWED_NETWORK_NUMBER: -+ privacy = "off"; -+ screen = "yes"; -+ break; -+ case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: -+ case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: -+ privacy = "full"; -+ screen = "no"; -+ break; -+ case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: -+ case AST_PRES_PROHIB_NETWORK_NUMBER: -+ privacy = "full"; -+ screen = "yes"; -+ break; -+ case AST_PRES_NUMBER_NOT_AVAILABLE: -+ break; -+ default: -+ if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) { -+ privacy = "full"; -+ } -+ else -+ privacy = "off"; -+ screen = "no"; -+ break; -+ } -+ -+ if (!ast_strlen_zero(privacy) && !ast_strlen_zero(screen)) -+ snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), ";privacy=%s;screen=%s", privacy, screen); -+ -+ add_header(req, "Remote-Party-ID", tmp); -+ } -+ return 0; -+} -+ - /*! \brief add XML encoded media control with update - \note XML: The only way to turn 0 bits of information into a few hundred. (markster) */ - static int add_vidupdate(struct sip_request *req) -@@ -8297,7 +9097,7 @@ - } - - /*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */ --static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate, -+static void add_codec_to_sdp(const struct sip_pvt *p, int codec, - struct ast_str **m_buf, struct ast_str **a_buf, - int debug, int *min_packet_size) - { -@@ -8317,18 +9117,31 @@ - return; - ast_str_append(m_buf, 0, " %d", rtp_code); - ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, -- ast_rtp_lookup_mime_subtype(1, codec, -- ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0), -- sample_rate); -- if (codec == AST_FORMAT_G729A) { -+ ast_rtp_lookup_mime_subtype(1, codec, -+ ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0), -+ ast_rtp_lookup_sample_rate(1, codec)); -+ -+ switch (codec) { -+ case AST_FORMAT_G729A: - /* Indicate that we don't support VAD (G.729 annex B) */ - ast_str_append(a_buf, 0, "a=fmtp:%d annexb=no\r\n", rtp_code); -- } else if (codec == AST_FORMAT_G723_1) { -+ break; -+ case AST_FORMAT_G723_1: - /* Indicate that we don't support VAD (G.723.1 annex A) */ - ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code); -- } else if (codec == AST_FORMAT_ILBC) { -+ break; -+ case AST_FORMAT_ILBC: - /* Add information about us using only 20/30 ms packetization */ - ast_str_append(a_buf, 0, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms); -+ break; -+ case AST_FORMAT_SIREN7: -+ /* Indicate that we only expect 32Kbps */ -+ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code); -+ break; -+ case AST_FORMAT_SIREN14: -+ /* Indicate that we only expect 48Kbps */ -+ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=48000\r\n", rtp_code); -+ break; - } - - if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size)) -@@ -8341,7 +9154,7 @@ - - /*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */ - /* This is different to the audio one now so we can add more caps later */ --static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate, -+static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec, - struct ast_str **m_buf, struct ast_str **a_buf, - int debug, int *min_packet_size) - { -@@ -8358,12 +9171,13 @@ - - ast_str_append(m_buf, 0, " %d", rtp_code); - ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, -- ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate); -+ ast_rtp_lookup_mime_subtype(1, codec, 0), -+ ast_rtp_lookup_sample_rate(1, codec)); - /* Add fmtp code here */ - } - - /*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */ --static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate, -+static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec, - struct ast_str **m_buf, struct ast_str **a_buf, - int debug, int *min_packet_size) - { -@@ -8380,11 +9194,12 @@ - - ast_str_append(m_buf, 0, " %d", rtp_code); - ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, -- ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate); -+ ast_rtp_lookup_mime_subtype(1, codec, 0), -+ ast_rtp_lookup_sample_rate(1, codec)); - /* Add fmtp code here */ - - if (codec == AST_FORMAT_T140RED) { -- ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code, -+ ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code, - ast_rtp_lookup_code(p->trtp, 1, AST_FORMAT_T140), - ast_rtp_lookup_code(p->trtp, 1, AST_FORMAT_T140), - ast_rtp_lookup_code(p->trtp, 1, AST_FORMAT_T140)); -@@ -8509,7 +9324,7 @@ - - - /*! \brief Add RFC 2833 DTMF offer to SDP */ --static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate, -+static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, - struct ast_str **m_buf, struct ast_str **a_buf, - int debug) - { -@@ -8522,8 +9337,8 @@ - - ast_str_append(m_buf, 0, " %d", rtp_code); - ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, -- ast_rtp_lookup_mime_subtype(0, format, 0), -- sample_rate); -+ ast_rtp_lookup_mime_subtype(0, format, 0), -+ ast_rtp_lookup_sample_rate(0, format)); - if (format == AST_RTP_DTMF) /* Indicate we support DTMF and FLASH... */ - ast_str_append(a_buf, 0, "a=fmtp:%d 0-16\r\n", rtp_code); - } -@@ -8564,13 +9379,6 @@ - - } - --/*! -- * \note G.722 actually is supposed to specified as 8 kHz, even though it is -- * really 16 kHz. Update this macro for other formats as they are added in -- * the future. -- */ --#define SDP_SAMPLE_RATE(x) 8000 -- - /*! \brief Add Session Description Protocol message - - If oldsdp is TRUE, then the SDP version number is not incremented. This mechanism -@@ -8742,9 +9550,7 @@ - if (capability & p->prefcodec) { - int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK; - -- add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec), -- &m_audio, &a_audio, -- debug, &min_audio_packet_size); -+ add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size); - alreadysent |= codec; - } - -@@ -8761,9 +9567,7 @@ - if (alreadysent & codec) - continue; - -- add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec), -- &m_audio, &a_audio, -- debug, &min_audio_packet_size); -+ add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size); - alreadysent |= codec; - } - -@@ -8776,14 +9580,11 @@ - continue; - - if (x & AST_FORMAT_AUDIO_MASK) -- add_codec_to_sdp(p, x, SDP_SAMPLE_RATE(x), -- &m_audio, &a_audio, debug, &min_audio_packet_size); -- else if (x & AST_FORMAT_VIDEO_MASK) -- add_vcodec_to_sdp(p, x, 90000, -- &m_video, &a_video, debug, &min_video_packet_size); -+ add_codec_to_sdp(p, x, &m_audio, &a_audio, debug, &min_audio_packet_size); -+ else if (x & AST_FORMAT_VIDEO_MASK) -+ add_vcodec_to_sdp(p, x, &m_video, &a_video, debug, &min_video_packet_size); - else if (x & AST_FORMAT_TEXT_MASK) -- add_tcodec_to_sdp(p, x, 1000, -- &m_text, &a_text, debug, &min_text_packet_size); -+ add_tcodec_to_sdp(p, x, &m_text, &a_text, debug, &min_text_packet_size); - } - - /* Now add DTMF RFC2833 telephony-event as a codec */ -@@ -8791,7 +9592,7 @@ - if (!(p->jointnoncodeccapability & x)) - continue; - -- add_noncodec_to_sdp(p, x, 8000, &m_audio, &a_audio, debug); -+ add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug); - } - - ast_debug(3, "-- Done with adding codecs to SDP\n"); -@@ -8912,7 +9713,7 @@ - /*! \brief Used for 200 OK and 183 early media - \return Will return XMIT_ERROR for network errors. - */ --static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp) -+static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid) - { - struct sip_request resp; - int seqno; -@@ -8921,6 +9722,9 @@ - return -1; - } - respprep(&resp, p, msg, req); -+ if (rpid == TRUE) { -+ add_rpid(&resp, p); -+ } - if (p->rtp) { - if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { - ast_debug(1, "Setting framing from config on incoming call\n"); -@@ -9060,87 +9864,10 @@ - ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport); - else - ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr)); -- } else -+ } else { -+ /*! \todo We should not always add port here. Port is only added if it's non-standard (see code above) */ - ast_string_field_build(p, our_contact, "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type)); --} -- --/*! \brief Build the Remote Party-ID & From using callingpres options */ --static void build_rpid(struct sip_pvt *p) --{ -- int send_pres_tags = TRUE; -- const char *privacy=NULL; -- const char *screen=NULL; -- char buf[256]; -- const char *clid = default_callerid; -- const char *clin = NULL; -- const char *fromdomain; -- -- if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from)) -- return; -- -- if (p->owner && p->owner->cid.cid_num) -- clid = p->owner->cid.cid_num; -- if (p->owner && p->owner->cid.cid_name) -- clin = p->owner->cid.cid_name; -- if (ast_strlen_zero(clin)) -- clin = clid; -- -- switch (p->callingpres) { -- case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: -- privacy = "off"; -- screen = "no"; -- break; -- case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: -- privacy = "off"; -- screen = "yes"; -- break; -- case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: -- privacy = "off"; -- screen = "no"; -- break; -- case AST_PRES_ALLOWED_NETWORK_NUMBER: -- privacy = "off"; -- screen = "yes"; -- break; -- case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED: -- privacy = "full"; -- screen = "no"; -- break; -- case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: -- privacy = "full"; -- screen = "yes"; -- break; -- case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: -- privacy = "full"; -- screen = "no"; -- break; -- case AST_PRES_PROHIB_NETWORK_NUMBER: -- privacy = "full"; -- screen = "yes"; -- break; -- case AST_PRES_NUMBER_NOT_AVAILABLE: -- send_pres_tags = FALSE; -- break; -- default: -- ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres); -- if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) -- privacy = "full"; -- else -- privacy = "off"; -- screen = "no"; -- break; - } -- -- fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)); -- -- snprintf(buf, sizeof(buf), "\"%s\" ", clin, clid, fromdomain); -- if (send_pres_tags) -- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen); -- ast_string_field_set(p, rpid, buf); -- -- ast_string_field_build(p, rpid_from, "\"%s\" ;tag=%s", clin, -- S_OR(p->fromuser, clid), -- fromdomain, p->tag); - } - - /*! \brief Initiate new SIP request to peer/user */ -@@ -9178,16 +9905,10 @@ - - snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text); - -- if (p->owner) { -- l = p->owner->cid.cid_num; -- n = p->owner->cid.cid_name; -+ if (p->owner && (p->owner->connected.id.number_presentation & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) { -+ l = p->owner->connected.id.number; -+ n = p->owner->connected.id.name; - } -- /* if we are not sending RPID and user wants his callerid restricted */ -- if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) && -- ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) { -- l = CALLERID_UNKNOWN; -- n = l; -- } - if (ast_strlen_zero(l)) - l = default_callerid; - if (ast_strlen_zero(n)) -@@ -9204,7 +9925,7 @@ - else /* Save for any further attempts */ - ast_string_field_set(p, fromname, n); - -- if (pedanticsipchecking) { -+ if (sip_cfg.pedanticsipchecking) { - ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0); - n = tmp_n; - ast_uri_encode(l, tmp_l, sizeof(tmp_l), 0); -@@ -9226,7 +9947,7 @@ - ast_str_append(&invite, 0, "sip:"); - if (!ast_strlen_zero(p->username)) { - n = p->username; -- if (pedanticsipchecking) { -+ if (sip_cfg.pedanticsipchecking) { - ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0); - n = tmp_n; - } -@@ -9275,12 +9996,7 @@ - /* SLD: FIXME?: do Route: here too? I think not cos this is the first request. - * OTOH, then we won't have anything in p->route anyway */ - -- /* Build Remote Party-ID and From */ -- if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) { -- build_rpid(p); -- add_header(req, "From", p->rpid_from); -- } else -- add_header(req, "From", from); -+ add_header(req, "From", from); - add_header(req, "To", to); - ast_string_field_set(p, exten, l); - build_contact(p); -@@ -9289,11 +10005,47 @@ - add_header(req, "CSeq", tmp_n); - if (!ast_strlen_zero(global_useragent)) - add_header(req, "User-Agent", global_useragent); -- if (!ast_strlen_zero(p->rpid)) -- add_header(req, "Remote-Party-ID", p->rpid); - } - --/*! \brief Build REFER/INVITE/OPTIONS message and transmit it -+/*! \brief Add "Diversion" header to outgoing message -+ * -+ * We need to add a Diversion header if the owner channel of -+ * this dialog has redirecting information associated with it. -+ * -+ * \param req The request/response to which we will add the header -+ * \param pvt The sip_pvt which represents the call-leg -+ * \param apr Redirecting data used to make the diversion header -+ */ -+static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt) -+{ -+ const char *diverting_number; -+ const char *diverting_name; -+ const char *reason; -+ char header_text[256]; -+ -+ if (!pvt->owner) { -+ return; -+ } -+ -+ diverting_number = pvt->owner->cid.cid_rdnis; -+ diverting_name = pvt->owner->redirecting.from.name; -+ reason = sip_reason_code_to_str(pvt->owner->redirecting.reason); -+ -+ if (ast_strlen_zero(diverting_number)) { -+ return; -+ } -+ -+ /* We at least have a number to place in the Diversion header, which is enough */ -+ if (ast_strlen_zero(diverting_name)) { -+ snprintf(header_text, sizeof(header_text), ";reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason); -+ } else { -+ snprintf(header_text, sizeof(header_text), "\"%s\" ;reason=%s", diverting_name, diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason); -+ } -+ -+ add_header(req, "Diversion", header_text); -+} -+ -+/*! \brief Build REFER/INVITE/OPTIONS/SUBSCRIBE message and transmit it - \param init 0 = Prepare request within dialog, 1= prepare request, new branch, 2= prepare new request and new dialog. do_proxy_auth calls this with init!=2 - \param p sip_pvt structure - \param sdp unknown -@@ -9330,7 +10082,15 @@ - add_header(&req, "Referred-By", buf); - } - } -+ } else if (sipmethod == SIP_SUBSCRIBE) { /* We only support sending MWI subscriptions right now */ -+ char buf[SIPBUFSIZE]; -+ -+ add_header(&req, "Event", "message-summary"); -+ add_header(&req, "Accept", "application/simple-message-summary"); -+ snprintf(buf, sizeof(buf), "%d", mwi_expiry); -+ add_header(&req, "Expires", buf); - } -+ - /* This new INVITE is part of an attended transfer. Make sure that the - other end knows and replace the current call with this new call */ - if (p->options && !ast_strlen_zero(p->options->replaces)) { -@@ -9403,6 +10163,11 @@ - - ast_channel_unlock(chan); - } -+ if ((sipmethod == SIP_INVITE || sipmethod == SIP_UPDATE) && ast_test_flag(&p->flags[0], SIP_SENDRPID)) -+ add_rpid(&req, p); -+ if (sipmethod == SIP_INVITE) { -+ add_diversion_header(&req, p); -+ } - if (sdp) { - if (p->udptl && (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)) { - ast_udptl_offered_from_local(p->udptl, 1); -@@ -9422,6 +10187,102 @@ - return send_request(p, &req, init ? XMIT_CRITICAL : XMIT_RELIABLE, p->ocseq); - } - -+/*! \brief Send a subscription or resubscription for MWI */ -+static int sip_subscribe_mwi_do(const void *data) -+{ -+ struct sip_subscription_mwi *mwi = (struct sip_subscription_mwi*)data; -+ -+ if (!mwi) { -+ return -1; -+ } -+ -+ mwi->resub = -1; -+ __sip_subscribe_mwi_do(mwi); -+ ASTOBJ_UNREF(mwi, sip_subscribe_mwi_destroy); -+ -+ return 0; -+} -+ -+/*! \brief Actually setup an MWI subscription or resubscribe */ -+static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi) -+{ -+ /* If we have no DNS manager let's do a lookup */ -+ if (!mwi->dnsmgr) { -+ char transport[MAXHOSTNAMELEN]; -+ snprintf(transport, sizeof(transport), "_sip._%s", get_transport(mwi->transport)); -+ ast_dnsmgr_lookup(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL); -+ } -+ -+ /* If we already have a subscription up simply send a resubscription */ -+ if (mwi->call) { -+ transmit_invite(mwi->call, SIP_SUBSCRIBE, 0, 0); -+ return 0; -+ } -+ -+ /* Create a dialog that we will use for the subscription */ -+ if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE))) { -+ return -1; -+ } -+ -+ ref_proxy(mwi->call, obproxy_get(mwi->call, NULL)); -+ -+ if (!mwi->us.sin_port && mwi->portno) { -+ mwi->us.sin_port = htons(mwi->portno); -+ } -+ -+ /* Setup the destination of our subscription */ -+ if (create_addr(mwi->call, mwi->hostname, &mwi->us, 0)) { -+ dialog_unlink_all(mwi->call, TRUE, TRUE); -+ mwi->call = dialog_unref(mwi->call, "unref dialog after unlink_all"); -+ return 0; -+ } -+ -+ if (!mwi->dnsmgr && mwi->portno) { -+ mwi->call->sa.sin_port = htons(mwi->portno); -+ mwi->call->recv.sin_port = htons(mwi->portno); -+ } else { -+ mwi->portno = ntohs(mwi->call->sa.sin_port); -+ } -+ -+ /* Set various other information */ -+ if (!ast_strlen_zero(mwi->authuser)) { -+ ast_string_field_set(mwi->call, peername, mwi->authuser); -+ ast_string_field_set(mwi->call, authname, mwi->authuser); -+ ast_string_field_set(mwi->call, fromuser, mwi->authuser); -+ } else { -+ ast_string_field_set(mwi->call, peername, mwi->username); -+ ast_string_field_set(mwi->call, authname, mwi->username); -+ ast_string_field_set(mwi->call, fromuser, mwi->username); -+ } -+ ast_string_field_set(mwi->call, username, mwi->username); -+ if (!ast_strlen_zero(mwi->secret)) { -+ ast_string_field_set(mwi->call, peersecret, mwi->secret); -+ } -+ mwi->call->socket.type = mwi->transport; -+ mwi->call->socket.port = htons(mwi->portno); -+ ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip); -+ build_contact(mwi->call); -+ build_via(mwi->call); -+ build_callid_pvt(mwi->call); -+ ast_set_flag(&mwi->call->flags[0], SIP_OUTGOING); -+ -+ /* Associate the call with us */ -+ mwi->call->mwi = ASTOBJ_REF(mwi); -+ -+ /* Actually send the packet */ -+ transmit_invite(mwi->call, SIP_SUBSCRIBE, 0, 2); -+ -+ return 0; -+} -+ -+static int find_calling_channel(struct ast_channel *c, void *data) { -+ struct sip_pvt *p = data; -+ -+ return (c->pbx && -+ (!strcasecmp(c->macroexten, p->exten) || !strcasecmp(c->exten, p->exten)) && -+ (sip_cfg.notifycid == IGNORE_CONTEXT || !strcasecmp(c->context, p->context))); -+} -+ - /*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */ - static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout) - { -@@ -9441,7 +10302,7 @@ - - switch (state) { - case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE): -- statestring = (global_notifyringing) ? "early" : "confirmed"; -+ statestring = (sip_cfg.notifyringing) ? "early" : "confirmed"; - local_state = NOTIFY_INUSE; - pidfstate = "busy"; - pidfnote = "Ringing"; -@@ -9579,11 +10440,45 @@ - break; - case DIALOG_INFO_XML: /* SNOM subscribes in this format */ - ast_str_append(&tmp, 0, "\n"); -- ast_str_append(&tmp, 0, "\n", p->dialogver++, full ? "full":"partial", mto); -- if ((state & AST_EXTENSION_RINGING) && global_notifyringing) -- ast_str_append(&tmp, 0, "\n", p->exten); -- else -+ ast_str_append(&tmp, 0, "\n", p->dialogver++, full ? "full" : "partial", mto); -+ if ((state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) { -+ const char *local_display = p->exten; -+ char *local_target = mto; -+ -+ /* There are some limitations to how this works. The primary one is that the -+ callee must be dialing the same extension that is being monitored. Simply dialing -+ the hint'd device is not sufficient. */ -+ if (sip_cfg.notifycid) { -+ struct ast_channel *caller = ast_channel_search_locked(find_calling_channel, p); -+ -+ if (caller) { -+ int need = strlen(caller->cid.cid_num) + strlen(p->fromdomain) + sizeof("sip:@"); -+ local_target = alloca(need); -+ snprintf(local_target, need, "sip:%s@%s", caller->cid.cid_num, p->fromdomain); -+ local_display = ast_strdupa(caller->cid.cid_name); -+ ast_channel_unlock(caller); -+ caller = NULL; -+ } -+ } -+ -+ /* We create a fake call-id which the phone will send back in an INVITE -+ Replaces header which we can grab and do some magic with. */ -+ ast_str_append(&tmp, 0, -+ "\n" -+ "\n" -+ /* See the limitations of this above. Luckily the phone seems to still be -+ happy when these values are not correct. */ -+ "%s\n" -+ "\n" -+ "\n" -+ "\n" -+ "%s\n" -+ "\n" -+ "\n", -+ p->exten, p->callid, local_display, local_target, local_target, mto, mto); -+ } else { - ast_str_append(&tmp, 0, "\n", p->exten); -+ } - ast_str_append(&tmp, 0, "%s\n", statestring); - if (state == AST_EXTENSION_ONHOLD) { - ast_str_append(&tmp, 0, "\n\n" -@@ -9611,7 +10506,7 @@ - - We use the SIP Event package message-summary - MIME type defaults to "application/simple-message-summary"; - */ --static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten) -+static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten) - { - struct sip_request req; - struct ast_str *out = ast_str_alloca(500); -@@ -9755,6 +10650,80 @@ - " *Variable: = At least one variable pair must be specified.\n" - " ActionID: Action ID for this transaction. Will be returned.\n"; - -+/*! \brief Send a provisional response indicating that a call was redirected -+ */ -+static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen) -+{ -+ struct sip_request resp; -+ -+ if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) { -+ return; -+ } -+ -+ if (!ast_strlen_zero(p->owner->redirecting.to.number)) { -+ ast_string_field_set(p, exten, p->owner->redirecting.to.number); -+ build_contact(p); -+ } -+ respprep(&resp, p, "181 Call is being forwarded", &p->initreq); -+ add_diversion_header(&resp, p); -+ send_response(p, &resp, XMIT_UNRELIABLE, 0); -+} -+ -+/*! \brief Notify peer that the connected line has changed */ -+static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen) -+{ -+ -+ if (!ast_test_flag(&p->flags[0], SIP_SENDRPID)) -+ return; -+ if (ast_strlen_zero(p->owner->connected.id.number)) -+ return; -+ -+ append_history(p, "ConnectedLine", "%s party is now %s <%s>", ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "Calling" : "Called", p->owner->connected.id.name, p->owner->connected.id.number); -+ -+ if (p->owner->_state == AST_STATE_UP || ast_test_flag(&p->flags[0], SIP_OUTGOING)) { -+ struct sip_request req; -+ -+ if (p->invitestate == INV_CONFIRMED || p->invitestate == INV_TERMINATED) { -+ reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ? SIP_UPDATE : SIP_INVITE, 0, 1); -+ -+ add_header(&req, "Allow", ALLOWED_METHODS); -+ add_header(&req, "Supported", SUPPORTED_EXTENSIONS); -+ add_rpid(&req, p); -+ add_sdp(&req, p, FALSE); -+ -+ initialize_initreq(p, &req); -+ p->lastinvite = p->ocseq; -+ ast_set_flag(&p->flags[0], SIP_OUTGOING); -+ send_request(p, &req, XMIT_CRITICAL, p->ocseq); -+ } else { -+ reqprep(&req, p, SIP_UPDATE, 0, 1); -+ add_rpid(&req, p); -+ add_header_contentLength(&req, 0); -+ send_request(p, &req, XMIT_CRITICAL, p->ocseq); -+ } -+ } else { -+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPID_IMMEDIATE)) { -+ struct sip_request resp; -+ -+ if ((p->owner->_state == AST_STATE_RING) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT)) { -+ respprep(&resp, p, "180 Ringing", &p->initreq); -+ add_rpid(&resp, p); -+ send_response(p, &resp, XMIT_UNRELIABLE, 0); -+ ast_set_flag(&p->flags[0], SIP_RINGING); -+ } else if (p->owner->_state == AST_STATE_RINGING) { -+ respprep(&resp, p, "183 Session Progress", &p->initreq); -+ add_rpid(&resp, p); -+ send_response(p, &resp, XMIT_UNRELIABLE, 0); -+ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); -+ } else { -+ ast_log(LOG_DEBUG, "Unable able to send update to '%s' in state '%s'\n", p->owner->name, ast_state2str(p->owner->_state)); -+ } -+ } else { -+ ast_set_flag(&p->flags[1], SIP_PAGE2_CONNECTLINEUPDATE_PEND); -+ } -+ } -+} -+ - static const struct _map_x_s regstatestrings[] = { - { REG_STATE_FAILED, "Failed" }, - { REG_STATE_UNREGISTERED, "Unregistered"}, -@@ -9843,7 +10812,7 @@ - in the single SIP manager thread. */ - p = r->call; - sip_pvt_lock(p); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "registration timeout"); - /* Pretend to ACK anything just in case */ - __sip_pretend_ack(p); - sip_pvt_unlock(p); -@@ -9884,6 +10853,7 @@ - struct sip_pvt *p; - int res; - char *fromdomain; -+ char *domainport = NULL; - - /* exit if we are already in process with this registrar ?*/ - if (r == NULL || ((auth == NULL) && (r->regstate == REG_STATE_REGSENT || r->regstate == REG_STATE_AUTHSENT))) { -@@ -9896,7 +10866,7 @@ - if (r->dnsmgr == NULL) { - char transport[MAXHOSTNAMELEN]; - snprintf(transport, sizeof(transport), "_sip._%s", get_transport(r->transport)); /* have to use static get_transport function */ -- ast_dnsmgr_lookup(r->hostname, &r->us, &r->dnsmgr, global_srvlookup ? transport : NULL); -+ ast_dnsmgr_lookup(r->hostname, &r->us, &r->dnsmgr, sip_cfg.srvlookup ? transport : NULL); - } - - if (r->call) { /* We have a registration */ -@@ -9960,8 +10930,9 @@ - ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Registration is outgoing call */ - r->call = dialog_ref(p, "copying dialog into registry r->call"); /* Save pointer to SIP dialog */ - p->registry = registry_addref(r, "transmit_register: addref to p->registry in transmit_register"); /* Add pointer to registry in packet */ -- if (!ast_strlen_zero(r->secret)) /* Secret (password) */ -+ if (!ast_strlen_zero(r->secret)) { /* Secret (password) */ - ast_string_field_set(p, peersecret, r->secret); -+ } - if (!ast_strlen_zero(r->md5secret)) - ast_string_field_set(p, peermd5secret, r->md5secret); - /* User name in this realm -@@ -10032,10 +11003,23 @@ - /* Fromdomain is what we are registering to, regardless of actual - host name from SRV */ - if (!ast_strlen_zero(p->fromdomain)) { -- if (r->portno && r->portno != STANDARD_SIP_PORT) -- snprintf(addr, sizeof(addr), "sip:%s:%d", p->fromdomain, r->portno); -- else -- snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain); -+ domainport = strrchr(p->fromdomain, ':'); -+ if (domainport) { -+ *domainport++ = '\0'; /* trim off domainport from p->fromdomain */ -+ if (ast_strlen_zero(domainport)) -+ domainport = NULL; -+ } -+ if (domainport) { -+ if (atoi(domainport) != STANDARD_SIP_PORT) -+ snprintf(addr, sizeof(addr), "sip:%s:%s", p->fromdomain, domainport); -+ else -+ snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain); -+ } else { -+ if (r->portno && r->portno != STANDARD_SIP_PORT) -+ snprintf(addr, sizeof(addr), "sip:%s:%d", p->fromdomain, r->portno); -+ else -+ snprintf(addr, sizeof(addr), "sip:%s", p->fromdomain); -+ } - } else { - if (r->portno && r->portno != STANDARD_SIP_PORT) - snprintf(addr, sizeof(addr), "sip:%s:%d", r->hostname, r->portno); -@@ -10140,6 +11124,7 @@ - char referto[256]; - char *ttag, *ftag; - char *theirtag = ast_strdupa(p->theirtag); -+ int use_tls=FALSE; - - if (sipdebug) - ast_debug(1, "SIP transfer of %s to %s\n", p->callid, dest); -@@ -10158,21 +11143,23 @@ - ast_copy_string(from, of, sizeof(from)); - of = get_in_brackets(from); - ast_string_field_set(p, from, of); -- if (!strncasecmp(of, "sip:", 4)) -+ if (!strncasecmp(of, "sip:", 4)) { - of += 4; -- else if (!strncasecmp(of, "sips:", 5)) -+ }else if (!strncasecmp(of, "sips:", 5)) { - of += 5; -- else -- ast_log(LOG_NOTICE, "From address missing 'sip(s):', using it anyway\n"); -+ use_tls = TRUE; -+ } else { -+ ast_log(LOG_NOTICE, "From address missing 'sip(s):', assuming sip:\n"); -+ } - /* Get just the username part */ - if ((c = strchr(dest, '@'))) - c = NULL; - else if ((c = strchr(of, '@'))) - *c++ = '\0'; - if (c) -- snprintf(referto, sizeof(referto), "", dest, c); -+ snprintf(referto, sizeof(referto), "", use_tls ? "s" : "", dest, c); - else -- snprintf(referto, sizeof(referto), "", dest); -+ snprintf(referto, sizeof(referto), "", use_tls ? "s" : "", dest); - - /* save in case we get 407 challenge */ - sip_refer_allocate(p); -@@ -10274,11 +11261,11 @@ - } - /* If we are hanging up and know a cause for that, send it in clear text to make - debugging easier. */ -- if (sipmethod == SIP_BYE && p->owner && p->owner->hangupcause) { -+ if (sipmethod == SIP_BYE) { - char buf[10]; - -- add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause)); -- snprintf(buf, sizeof(buf), "%d", p->owner->hangupcause); -+ add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->hangupcause)); -+ snprintf(buf, sizeof(buf), "%d", p->hangupcause); - add_header(&resp, "X-Asterisk-HangupCauseCode", buf); - } - -@@ -10293,10 +11280,12 @@ - char *tablename = (realtimeregs) ? "sipregs" : "sippeers"; - - if (!sip_cfg.ignore_regexpire) { -- if (peer->rt_fromcontact) -+ if (peer->rt_fromcontact) { - ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", peer->deprecated_username ? "username" : "defaultuser", "", "regserver", "", "useragent", "", SENTINEL); -- else -+ ast_update_realtime(tablename, "name", peer->name, "lastms", "", SENTINEL); -+ } else { - ast_db_del("SIP/Registry", peer->name); -+ } - } - } - -@@ -10385,9 +11374,9 @@ - return; - - if (username) -- ast_copy_string(peer->username, username, sizeof(peer->username)); -+ ast_string_field_set(peer, username, username); - if (contact) -- ast_copy_string(peer->fullcontact, contact, sizeof(peer->fullcontact)); -+ ast_string_field_set(peer, fullcontact, contact); - - ast_debug(2, "SIP Seeding peer from astdb: '%s' at %s@%s:%d for %d\n", - peer->name, peer->username, ast_inet_ntoa(in), port, expire); -@@ -10442,6 +11431,7 @@ - char contact_buf[256]; - char contact2_buf[256]; - char *contact, *contact2; -+ int use_tls = FALSE; - - /* Work on a copy */ - ast_copy_string(contact_buf, fullcontact, sizeof(contact_buf)); -@@ -10450,12 +11440,24 @@ - contact2 = contact2_buf; - - /* We have only the part in here so we just need to parse a SIP URI.*/ -+ -+ /*! \brief This code is wrong, it assumes that the contact we receive will use the -+ same transport as the request. It's not a valid assumption. The contact for -+ a udp connection can be a SIPS uri, or request ;transport=tcp -+ \todo Fix this buggy code. It doesn't even parse transport!!!! -+ -+ Note: The outbound proxy could be using UDP between the proxy and Asterisk. -+ We still need to be able to send to the remote agent through the proxy. -+ */ - if (tcp) { -- if (parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL)) { -+ if (!parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL)) { -+ use_tls = TRUE; -+ } else { - if (parse_uri(contact2, "sip:", &contact, NULL, &host, &pt, NULL)) - ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact); - } - port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_TLS_PORT; -+ /*! \todo XXX why are we setting TLS port if there's no port given? parse_uri needs to return the transport. */ - } else { - if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, NULL)) - ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact); -@@ -10464,6 +11466,10 @@ - - /* XXX This could block for a long time XXX */ - /* We should only do this if it's a name, not an IP */ -+ /* \todo - if there's no PORT number in contact - we are required to check NAPTR/SRV records -+ to find transport, port address and hostname. If there's a port number, we have to -+ assume that the domain part is a host name and only look for an A/AAAA record in DNS. -+ */ - hp = ast_gethostbyname(host, &ahp); - if (!hp) { - ast_log(LOG_WARNING, "Invalid host name in Contact: (can't resolve in DNS) : '%s'\n", host); -@@ -10482,6 +11488,7 @@ - if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) { - /* NAT: Don't trust the contact field. Just use what they came to us - with. */ -+ /*! \todo We need to save the TRANSPORT here too */ - pvt->sa = pvt->recv; - return 0; - } -@@ -10548,8 +11555,8 @@ - destroy_association(peer); - - register_peer_exten(peer, FALSE); /* Remove extension from regexten= setting in sip.conf */ -- peer->fullcontact[0] = '\0'; -- peer->useragent[0] = '\0'; -+ ast_string_field_set(peer, fullcontact, ""); -+ ast_string_field_set(peer, useragent, ""); - peer->sipoptions = 0; - peer->lastms = 0; - pvt->expiry = 0; -@@ -10561,12 +11568,18 @@ - } - - /* Store whatever we got as a contact from the client */ -- ast_copy_string(peer->fullcontact, curi, sizeof(peer->fullcontact)); -+ ast_string_field_set(peer, fullcontact, curi); - - /* For the 200 OK, we should use the received contact */ - ast_string_field_build(pvt, our_contact, "<%s>", curi); - - /* Make sure it's a SIP URL */ -+ /*! \todo This code assumes that the Contact is using the same transport as the -+ REGISTER request. That might not be true at all. You can receive -+ sips: requests over any transport. Needs to be fixed. -+ Does not parse the ;transport uri parameter at this point, which might be handy -+ in some situations. -+ */ - if (pvt->socket.type == SIP_TRANSPORT_TLS) { - if (parse_uri(curi, "sips:", &curi, NULL, &host, &pt, NULL)) { - if (parse_uri(curi2, "sip:", &curi, NULL, &host, &pt, NULL)) -@@ -10588,22 +11601,25 @@ - - /* Check that they're allowed to register at this IP */ - /* XXX This could block for a long time XXX */ -+ /*! \todo Check NAPTR/SRV if we have not got a port in the URI */ - hp = ast_gethostbyname(host, &ahp); - if (!hp) { - ast_log(LOG_WARNING, "Invalid host '%s'\n", host); -- *peer->fullcontact = '\0'; -+ ast_string_field_set(peer, fullcontact, ""); - ast_string_field_set(pvt, our_contact, ""); - return PARSE_REGISTER_FAILED; - } - memcpy(&testsin.sin_addr, hp->h_addr, sizeof(testsin.sin_addr)); -- if ( ast_apply_ha(global_contact_ha, &testsin) != AST_SENSE_ALLOW || -+ if (ast_apply_ha(global_contact_ha, &testsin) != AST_SENSE_ALLOW || - ast_apply_ha(peer->contactha, &testsin) != AST_SENSE_ALLOW) { - ast_log(LOG_WARNING, "Host '%s' disallowed by rule\n", host); -- *peer->fullcontact = '\0'; -+ ast_string_field_set(peer, fullcontact, ""); - ast_string_field_set(pvt, our_contact, ""); - return PARSE_REGISTER_FAILED; - } - -+ /*! \todo This could come before the checking of DNS earlier on, to avoid -+ DNS lookups where we don't need it... */ - if (!ast_test_flag(&peer->flags[0], SIP_NAT_ROUTE)) { - peer->addr.sin_family = AF_INET; - memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr)); -@@ -10621,7 +11637,7 @@ - peer->sipoptions = pvt->sipoptions; - - if (!ast_strlen_zero(curi) && ast_strlen_zero(peer->username)) -- ast_copy_string(peer->username, curi, sizeof(peer->username)); -+ ast_string_field_set(peer, username, curi); - - AST_SCHED_DEL_UNREF(sched, peer->expire, - unref_peer(peer, "remove register expire ref")); -@@ -10643,7 +11659,7 @@ - snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port), expire, peer->username, peer->fullcontact); - /* Saving TCP connections is useless, we won't be able to reconnect - XXX WHY???? XXX -- \todo check this -+ \todo Fix this immediately. - */ - if (!peer->rt_fromcontact && (peer->socket.type & SIP_TRANSPORT_UDP)) - ast_db_put("SIP/Registry", peer->name, data); -@@ -10658,8 +11674,8 @@ - - /* Save User agent */ - useragent = get_header(req, "User-Agent"); -- if (strcasecmp(useragent, peer->useragent)) { /* XXX copy if they are different ? */ -- ast_copy_string(peer->useragent, useragent, sizeof(peer->useragent)); -+ if (strcasecmp(useragent, peer->useragent)) { -+ ast_string_field_set(peer, useragent, useragent); - ast_verb(4, "Saved useragent \"%s\" for peer %s\n", peer->useragent, peer->name); - } - return PARSE_REGISTER_UPDATE; -@@ -10917,7 +11933,7 @@ - ast_copy_string(a1_hash, md5secret, sizeof(a1_hash)); - else { - char a1[256]; -- snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret); -+ snprintf(a1, sizeof(a1), "%s:%s:%s", username, sip_cfg.realm, secret); - ast_md5_hash(a1_hash, a1); - } - -@@ -11055,12 +12071,15 @@ - * Terminate the uri at the first ';' or space. - * Technically we should ignore escaped space per RFC3261 (19.1.1 etc) - * but don't do it for the time being. Remember the uri format is: -+ * (User-parameters was added after RFC 3261) - *\verbatim - * -- * sip:user:password@host:port;uri-parameters?headers -- * sips:user:password@host:port;uri-parameters?headers -+ * sip:user:password;user-parameters@host:port;uri-parameters?headers -+ * sips:user:password;user-parameters@host:port;uri-parameters?headers - * - *\endverbatim -+ * \todo As this function does not support user-parameters, it's considered broken -+ * and needs fixing. - */ - static char *terminate_uri(char *uri) - { -@@ -11088,7 +12107,7 @@ - terminate_uri(uri); /* warning, overwrite the string */ - - ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp)); -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(tmp); - - c = get_in_brackets(tmp); -@@ -11103,7 +12122,7 @@ - ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(sin->sin_addr)); - } - -- /* XXX here too we interpret a missing @domain as a name-only -+ /*! \todo XXX here too we interpret a missing @domain as a name-only - * URI, whereas the RFC says this is a domain-only uri. - */ - /* Strip off the domain name */ -@@ -11137,6 +12156,7 @@ - } - - if (peer) { -+ /*! \todo OEJ Remove this - there's never RTP in a REGISTER dialog... */ - /* Set Frame packetization */ - if (p->rtp) { - ast_rtp_codec_setpref(p->rtp, &peer->prefs); -@@ -11187,7 +12207,7 @@ - } - } - } -- if (!peer && autocreatepeer) { -+ if (!peer && sip_cfg.autocreatepeer) { - /* Create peer if we have autocreate mode enabled */ - peer = temp_peer(name); - if (peer) { -@@ -11245,7 +12265,7 @@ - case AUTH_NOT_FOUND: - case AUTH_PEER_NOT_DYNAMIC: - case AUTH_ACL_FAILED: -- if (global_alwaysauthreject) { -+ if (sip_cfg.alwaysauthreject) { - transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE); - } else { - /* URI not found */ -@@ -11303,20 +12323,199 @@ - } - } - -+/*! \brief Parse the parts of the P-Asserted-Identity header -+ * on an incoming packet. Returns 1 if a valid header is found -+ * and it is different from the current caller id. -+ */ -+static int get_pai(struct sip_pvt *p, struct sip_request *req) -+{ -+ char pai[256]; -+ char privacy[64]; -+ char *cid_num = ""; -+ char *cid_name = ""; -+ int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; -+ char *start = NULL, *end = NULL; -+ -+ ast_copy_string(pai, get_header(req, "P-Asserted-Identity"), sizeof(pai)); -+ -+ if (ast_strlen_zero(pai)) { -+ return 0; -+ } -+ -+ start = pai; -+ if (*start == '"') { -+ *start++ = '\0'; -+ end = strchr(start, '"'); -+ if (!end) -+ return 0; -+ *end++ = '\0'; -+ cid_name = start; -+ start = ast_skip_blanks(end); -+ } -+ -+ if (*start != '<') -+ return 0; -+ *start++ = '\0'; -+ end = strchr(start, '@'); -+ if (!end) -+ return 0; -+ *end++ = '\0'; -+ if (!strncasecmp(start, "anonymous@anonymous.invalid", 27)) { -+ callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; -+ /*XXX Assume no change in cid_num. Perhaps it should be -+ * blanked? -+ */ -+ cid_num = (char *)p->cid_num; -+ } else if (!strncasecmp(start, "sip:", 4)) { -+ cid_num = start + 4; -+ if (ast_is_shrinkable_phonenumber(cid_num)) -+ ast_shrink_phone_number(cid_num); -+ start = end; -+ -+ end = strchr(start, '>'); -+ if (!end) -+ return 0; -+ *end = '\0'; -+ } else { -+ return 0; -+ } -+ -+ ast_copy_string(privacy, get_header(req, "Privacy"), sizeof(privacy)); -+ if (!ast_strlen_zero(privacy) && strncmp(privacy, "id", 2)) { -+ callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; -+ } -+ -+ /* Only return true if the supplied caller id is different */ -+ if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres) -+ return 0; -+ -+ ast_string_field_set(p, cid_num, cid_num); -+ ast_string_field_set(p, cid_name, cid_name); -+ p->callingpres = callingpres; -+ -+ if (p->owner) { -+ ast_set_callerid(p->owner, cid_num, cid_name, NULL); -+ p->owner->cid.cid_pres = callingpres; -+ } -+ -+ return 1; -+} -+ -+/*! \brief Get name, number and presentation from remote party id header, -+ * returns true if a valid header was found and it was different from the -+ * current caller id. -+ */ -+static int get_rpid(struct sip_pvt *p, struct sip_request *oreq) -+{ -+ char tmp[256]; -+ struct sip_request *req; -+ char *cid_num = ""; -+ char *cid_name = ""; -+ int callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; -+ char *privacy = ""; -+ char *screen = ""; -+ char *start, *end; -+ -+ if (!ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) -+ return 0; -+ req = oreq; -+ if (!req) -+ req = &p->initreq; -+ ast_copy_string(tmp, get_header(req, "Remote-Party-ID"), sizeof(tmp)); -+ if (ast_strlen_zero(tmp)) { -+ return get_pai(p, req); -+ } -+ -+ start = tmp; -+ if (*start == '"') { -+ *start++ = '\0'; -+ end = strchr(start, '"'); -+ if (!end) -+ return 0; -+ *end++ = '\0'; -+ cid_name = start; -+ start = ast_skip_blanks(end); -+ } -+ -+ if (*start != '<') -+ return 0; -+ *start++ = '\0'; -+ end = strchr(start, '@'); -+ if (!end) -+ return 0; -+ *end++ = '\0'; -+ if (strncasecmp(start, "sip:", 4)) -+ return 0; -+ cid_num = start + 4; -+ if (ast_is_shrinkable_phonenumber(cid_num)) -+ ast_shrink_phone_number(cid_num); -+ start = end; -+ -+ end = strchr(start, '>'); -+ if (!end) -+ return 0; -+ *end++ = '\0'; -+ if (*end) { -+ start = end; -+ if (*start != ';') -+ return 0; -+ *start++ = '\0'; -+ while (!ast_strlen_zero(start)) { -+ end = strchr(start, ';'); -+ if (end) -+ *end++ = '\0'; -+ if (!strncasecmp(start, "privacy=", 8)) -+ privacy = start + 8; -+ else if (!strncasecmp(start, "screen=", 7)) -+ screen = start + 7; -+ start = end; -+ } -+ -+ if (!strcasecmp(privacy, "full")) { -+ if (!strcasecmp(screen, "yes")) -+ callingpres = AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; -+ else if (!strcasecmp(screen, "no")) -+ callingpres = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; -+ } else { -+ if (!strcasecmp(screen, "yes")) -+ callingpres = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; -+ else if (!strcasecmp(screen, "no")) -+ callingpres = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; -+ } -+ } -+ -+ /* Only return true if the supplied caller id is different */ -+ if (!strcasecmp(p->cid_num, cid_num) && !strcasecmp(p->cid_name, cid_name) && p->callingpres == callingpres) -+ return 0; -+ -+ ast_string_field_set(p, cid_num, cid_num); -+ ast_string_field_set(p, cid_name, cid_name); -+ p->callingpres = callingpres; -+ -+ if (p->owner) { -+ ast_set_callerid(p->owner, cid_num, cid_name, NULL); -+ p->owner->cid.cid_pres = callingpres; -+ } -+ -+ return 1; -+} -+ - /*! \brief Get referring dnis */ --static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq) -+static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason) - { -- char tmp[256], *exten, *rexten, *rdomain; -- char *params, *reason = NULL; -+ char tmp[256], *exten, *rexten, *rdomain, *rname = NULL; -+ char *params, *reason_param = NULL; - struct sip_request *req; - - req = oreq ? oreq : &p->initreq; - - ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp)); - if (ast_strlen_zero(tmp)) -- return 0; -+ return -1; - -- params = strchr(tmp, ';'); -+ if ((params = strchr(tmp, '>'))) { -+ params = strchr(params, ';'); -+ } - - exten = get_in_brackets(tmp); - if (!strncasecmp(exten, "sip:", 4)) { -@@ -11335,16 +12534,16 @@ - while (*params == ';' || *params == ' ') - params++; - /* Check if we have a reason parameter */ -- if ((reason = strcasestr(params, "reason="))) { -- reason+=7; -+ if ((reason_param = strcasestr(params, "reason="))) { -+ reason_param+=7; - /* Remove enclosing double-quotes */ -- if (*reason == '"') -- ast_strip_quoted(reason, "\"", "\""); -- if (!ast_strlen_zero(reason)) { -- sip_set_redirstr(p, reason); -+ if (*reason_param == '"') -+ ast_strip_quoted(reason_param, "\"", "\""); -+ if (!ast_strlen_zero(reason_param)) { -+ sip_set_redirstr(p, reason_param); - if (p->owner) { - pbx_builtin_setvar_helper(p->owner, "__PRIREDIRECTREASON", p->redircause); -- pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason); -+ pbx_builtin_setvar_helper(p->owner, "__SIPREDIRECTREASON", reason_param); - } - } - } -@@ -11356,10 +12555,29 @@ - pbx_builtin_setvar_helper(p->owner, "__SIPRDNISDOMAIN", rdomain); - - if (sip_debug_test_pvt(p)) -- ast_verbose("RDNIS for this call is is %s (reason %s)\n", exten, reason ? reason : ""); -+ ast_verbose("RDNIS for this call is %s (reason %s)\n", exten, reason ? reason_param : ""); - -- ast_string_field_set(p, rdnis, rexten); -+ /*ast_string_field_set(p, rdnis, rexten);*/ - -+ if (*tmp == '\"') { -+ char *end_quote; -+ rname = tmp + 1; -+ end_quote = strchr(rname, '\"'); -+ *end_quote = '\0'; -+ } -+ -+ if (number) { -+ *number = ast_strdup(rexten); -+ } -+ -+ if (name && rname) { -+ *name = ast_strdup(rname); -+ } -+ -+ if (reason && !ast_strlen_zero(reason_param)) { -+ *reason = sip_reason_str_to_code(reason_param); -+ } -+ - return 0; - } - -@@ -11370,6 +12588,10 @@ - \return 0 on success (found a matching extension), - 1 for pickup extension or overlap dialling support (if we support it), - -1 on error. -+ -+ \note If the incoming uri is a SIPS: uri, we are required to carry this across -+ the dialplan, so that the outbound call also is a sips: call or encrypted -+ IAX2 call. If that's not available, the call should FAIL. - */ - static int get_destination(struct sip_pvt *p, struct sip_request *oreq) - { -@@ -11387,7 +12609,7 @@ - if (req->rlPart2) - ast_copy_string(tmp, REQ_OFFSET_TO_STR(req, rlPart2), sizeof(tmp)); - -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(tmp); - - uri = get_in_brackets(tmp); -@@ -11407,7 +12629,7 @@ - */ - ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf)); - if (!ast_strlen_zero(tmpf)) { -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(tmpf); - from = get_in_brackets(tmpf); - } -@@ -11453,7 +12675,7 @@ - - domain_context[0] = '\0'; - if (!check_sip_domain(p->domain, domain_context, sizeof(domain_context))) { -- if (!allow_external_domains && (req->method == SIP_INVITE || req->method == SIP_REFER)) { -+ if (!sip_cfg.allow_external_domains && (req->method == SIP_INVITE || req->method == SIP_REFER)) { - ast_debug(1, "Got SIP %s to non-local domain '%s'; refusing request.\n", sip_methods[req->method].text, p->domain); - return -2; - } -@@ -11519,9 +12741,24 @@ - if (sip_pvt_ptr) { - /* Go ahead and lock it (and its owner) before returning */ - sip_pvt_lock(sip_pvt_ptr); -- if (pedanticsipchecking) { -+ if (sip_cfg.pedanticsipchecking) { - const char *pvt_fromtag, *pvt_totag; -+ unsigned char frommismatch = 0, tomismatch = 0; - -+ if (ast_strlen_zero(fromtag)) { -+ sip_pvt_unlock(sip_pvt_ptr); -+ ast_debug(4, "Matched %s call for callid=%s - no from tag specified, pedantic check fails\n", -+ sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid); -+ return NULL; -+ } -+ -+ if (ast_strlen_zero(totag)) { -+ sip_pvt_unlock(sip_pvt_ptr); -+ ast_debug(4, "Matched %s call for callid=%s - no to tag specified, pedantic check fails\n", -+ sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid); -+ return NULL; -+ } -+ - if (sip_pvt_ptr->outgoing_call == TRUE) { - /* Outgoing call tags : from is "our", to is "their" */ - pvt_fromtag = sip_pvt_ptr->tag ; -@@ -11531,11 +12768,22 @@ - pvt_fromtag = sip_pvt_ptr->theirtag ; - pvt_totag = sip_pvt_ptr->tag ; - } -- if (ast_strlen_zero(fromtag) || strcmp(fromtag, pvt_fromtag) || (!ast_strlen_zero(totag) && strcmp(totag, pvt_totag))) { -+ -+ frommismatch = !!strcmp(fromtag, pvt_fromtag); -+ tomismatch = !!strcmp(totag, pvt_totag); -+ -+ if (frommismatch || tomismatch) { - sip_pvt_unlock(sip_pvt_ptr); -- ast_debug(4, "Matched %s call for callid=%s - But the pedantic check rejected the match; their tag is %s Our tag is %s\n", -+ if (frommismatch) { -+ ast_debug(4, "Matched %s call for callid=%s - pedantic from tag check fails; their tag is %s our tag is %s\n", - sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid, -- sip_pvt_ptr->theirtag, sip_pvt_ptr->tag); -+ fromtag, pvt_fromtag); -+ } -+ if (tomismatch) { -+ ast_debug(4, "Matched %s call for callid=%s - pedantic to tag check fails; their tag is %s our tag is %s\n", -+ sip_pvt_ptr->outgoing_call == TRUE ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid, -+ totag, pvt_totag); -+ } - return NULL; - } - } -@@ -11557,7 +12805,12 @@ - } - - /*! \brief Call transfer support (the REFER method) -- * Extracts Refer headers into pvt dialog structure */ -+ * Extracts Refer headers into pvt dialog structure -+ * -+ * \note If we get a SIPS uri in the refer-to header, we're required to set up a secure signalling path -+ * to that extension. As a minimum, this needs to be added to a channel variable, if not a channel -+ * flag. -+ */ - static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req) - { - -@@ -11586,7 +12839,7 @@ - } - h_refer_to = ast_strdupa(p_refer_to); - refer_to = get_in_brackets(h_refer_to); -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(refer_to); - - if (!strncasecmp(refer_to, "sip:", 4)) { -@@ -11613,7 +12866,7 @@ - if (!ast_strlen_zero(p_referred_by)) { - char *lessthan; - h_referred_by = ast_strdupa(p_referred_by); -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(h_referred_by); - - /* Store referrer's caller ID name */ -@@ -11634,49 +12887,46 @@ - } - - /* Check for arguments in the refer_to header */ -- if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */ -- *ptr++ = '\0'; -- if (!strncasecmp(ptr, "REPLACES=", 9)) { -- char *to = NULL, *from = NULL; -- -- /* This is an attended transfer */ -- referdata->attendedtransfer = 1; -- ast_copy_string(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid)); -- ast_uri_decode(referdata->replaces_callid); -- if ((ptr = strchr(referdata->replaces_callid, ';'))) /* Find options */ { -- *ptr++ = '\0'; -- } -- -- if (ptr) { -- /* Find the different tags before we destroy the string */ -- to = strcasestr(ptr, "to-tag="); -- from = strcasestr(ptr, "from-tag="); -- } -- -- /* Grab the to header */ -- if (to) { -- ptr = to + 7; -- if ((to = strchr(ptr, '&'))) -- *to = '\0'; -- if ((to = strchr(ptr, ';'))) -- *to = '\0'; -- ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag)); -- } -- -- if (from) { -- ptr = from + 9; -- if ((to = strchr(ptr, '&'))) -- *to = '\0'; -- if ((to = strchr(ptr, ';'))) -- *to = '\0'; -- ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag)); -- } -- -- if (!pedanticsipchecking) -- ast_debug(2, "Attended transfer: Will use Replace-Call-ID : %s (No check of from/to tags)\n", referdata->replaces_callid ); -- else -- ast_debug(2, "Attended transfer: Will use Replace-Call-ID : %s F-tag: %s T-tag: %s\n", referdata->replaces_callid, referdata->replaces_callid_fromtag ? referdata->replaces_callid_fromtag : "", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "" ); -+ if ((ptr = strcasestr(refer_to, "replaces="))) { -+ char *to = NULL, *from = NULL; -+ -+ /* This is an attended transfer */ -+ referdata->attendedtransfer = 1; -+ ast_copy_string(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid)); -+ ast_uri_decode(referdata->replaces_callid); -+ if ((ptr = strchr(referdata->replaces_callid, ';'))) /* Find options */ { -+ *ptr++ = '\0'; - } -+ -+ if (ptr) { -+ /* Find the different tags before we destroy the string */ -+ to = strcasestr(ptr, "to-tag="); -+ from = strcasestr(ptr, "from-tag="); -+ } -+ -+ /* Grab the to header */ -+ if (to) { -+ ptr = to + 7; -+ if ((to = strchr(ptr, '&'))) -+ *to = '\0'; -+ if ((to = strchr(ptr, ';'))) -+ *to = '\0'; -+ ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag)); -+ } -+ -+ if (from) { -+ ptr = from + 9; -+ if ((to = strchr(ptr, '&'))) -+ *to = '\0'; -+ if ((to = strchr(ptr, ';'))) -+ *to = '\0'; -+ ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag)); -+ } -+ -+ if (!sip_cfg.pedanticsipchecking) -+ ast_debug(2, "Attended transfer: Will use Replace-Call-ID : %s (No check of from/to tags)\n", referdata->replaces_callid ); -+ else -+ ast_debug(2, "Attended transfer: Will use Replace-Call-ID : %s F-tag: %s T-tag: %s\n", referdata->replaces_callid, referdata->replaces_callid_fromtag ? referdata->replaces_callid_fromtag : "", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "" ); - } - - if ((ptr = strchr(refer_to, '@'))) { /* Separate domain */ -@@ -11715,7 +12965,7 @@ - /* By default, use the context in the channel sending the REFER */ - if (ast_strlen_zero(transfer_context)) { - transfer_context = S_OR(transferer->owner->macrocontext, -- S_OR(transferer->context, default_context)); -+ S_OR(transferer->context, sip_cfg.default_context)); - } - - ast_copy_string(referdata->refer_to_context, transfer_context, sizeof(referdata->refer_to_context)); -@@ -11736,7 +12986,9 @@ - } - - --/*! \brief Call transfer support (old way, deprecated by the IETF)--*/ -+/*! \brief Call transfer support (old way, deprecated by the IETF) -+ * \note does not account for SIPS: uri requirements, nor check transport -+ */ - static int get_also_info(struct sip_pvt *p, struct sip_request *oreq) - { - char tmp[256] = "", *c, *a; -@@ -11752,7 +13004,7 @@ - ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp)); - c = get_in_brackets(tmp); - -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(c); - - if (!strncasecmp(c, "sip:", 4)) { -@@ -11781,7 +13033,7 @@ - /* By default, use the context in the channel sending the REFER */ - if (ast_strlen_zero(transfer_context)) { - transfer_context = S_OR(p->owner->macrocontext, -- S_OR(p->context, default_context)); -+ S_OR(p->context, sip_cfg.default_context)); - } - if (ast_exists_extension(NULL, transfer_context, c, 1, NULL)) { - /* This is a blind transfer */ -@@ -11935,73 +13187,12 @@ - return output; - } - --/*! \brief Get caller id number from Remote-Party-ID header field -- * Returns true if number should be restricted (privacy setting found) -- * output is set to NULL if no number found -- */ --static int get_rpid_num(const char *input, char *output, int maxlen) --{ -- char *start; -- char *end; - -- start = strchr(input, ':'); -- if (!start) { -- output[0] = '\0'; -- return 0; -- } -- start++; -- -- /* we found "number" */ -- ast_copy_string(output, start, maxlen); -- output[maxlen-1] = '\0'; -- -- end = strchr(output, '@'); -- if (end) -- *end = '\0'; -- else -- output[0] = '\0'; -- if (strstr(input, "privacy=full") || strstr(input, "privacy=uri")) -- return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED; -- -- return 0; --} -- --/*! -- * duplicate a list of channel variables, \return the copy. -- */ --static struct ast_variable *copy_vars(struct ast_variable *src) --{ -- struct ast_variable *res = NULL, *tmp, *v = NULL; -- -- for (v = src ; v ; v = v->next) { -- if ((tmp = ast_variable_new(v->name, v->value, v->file))) { -- tmp->next = res; -- res = tmp; -- } -- } -- return res; --} -- --/*! \brief helper function for check_{user|peer}_ok() */ --static void replace_cid(struct sip_pvt *p, const char *rpid_num, const char *calleridname) --{ -- /* replace callerid if rpid found, and not restricted */ -- if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) { -- char *tmp = ast_strdupa(rpid_num); /* XXX the copy can be done later */ -- if (!ast_strlen_zero(calleridname)) -- ast_string_field_set(p, cid_name, calleridname); -- if (ast_is_shrinkable_phonenumber(tmp)) -- ast_shrink_phone_number(tmp); -- ast_string_field_set(p, cid_num, tmp); -- } --} -- - /*! \brief Validate device authentication */ - static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, - struct sip_request *req, int sipmethod, struct sockaddr_in *sin, - struct sip_peer **authpeer, -- enum xmittype reliable, -- char *rpid_num, char *calleridname, char *uri2) -+ enum xmittype reliable, char *calleridname, char *uri2) - { - enum check_auth_result res; - int debug=sip_debug_test_addr(sin); -@@ -12049,7 +13240,6 @@ - if (p->sipoptions) - peer->sipoptions = p->sipoptions; - -- replace_cid(p, rpid_num, calleridname); - do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT_ROUTE)); - - ast_string_field_set(p, peersecret, peer->secret); -@@ -12101,14 +13291,18 @@ - /* XXX this takes the name from the caller... can we override ? */ - ast_string_field_set(p, authname, peer->username); - } -- if (!ast_strlen_zero(peer->cid_num)) { -- char *tmp = ast_strdupa(peer->cid_num); -- if (ast_is_shrinkable_phonenumber(tmp)) -- ast_shrink_phone_number(tmp); -- ast_string_field_set(p, cid_num, tmp); -+ if (!get_rpid(p, req)) { -+ if (!ast_strlen_zero(peer->cid_num)) { -+ char *tmp = ast_strdupa(peer->cid_num); -+ if (ast_is_shrinkable_phonenumber(tmp)) -+ ast_shrink_phone_number(tmp); -+ ast_string_field_set(p, cid_num, tmp); -+ } -+ if (!ast_strlen_zero(peer->cid_name)) -+ ast_string_field_set(p, cid_name, peer->cid_name); -+ if (peer->callingpres) -+ p->callingpres = peer->callingpres; - } -- if (!ast_strlen_zero(peer->cid_name)) -- ast_string_field_set(p, cid_name, peer->cid_name); - ast_string_field_set(p, fullcontact, peer->fullcontact); - if (!ast_strlen_zero(peer->context)) - ast_string_field_set(p, context, peer->context); -@@ -12163,8 +13357,6 @@ - char *dummy; /* dummy return value for parse_uri */ - char *domain; /* dummy return value for parse_uri */ - char *of, *of2; -- char rpid_num[50]; -- const char *rpid; - enum check_auth_result res; - char calleridname[50]; - char *uri2 = ast_strdupa(uri); -@@ -12172,7 +13364,7 @@ - terminate_uri(uri2); /* trim extra stuff */ - - ast_copy_string(from, get_header(req, "From"), sizeof(from)); -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - ast_uri_decode(from); - /* XXX here tries to map the username for invite things */ - memset(calleridname, 0, sizeof(calleridname)); -@@ -12180,11 +13372,6 @@ - if (calleridname[0]) - ast_string_field_set(p, cid_name, calleridname); - -- rpid = get_header(req, "Remote-Party-ID"); -- memset(rpid_num, 0, sizeof(rpid_num)); -- if (!ast_strlen_zero(rpid)) -- p->callingpres = get_rpid_num(rpid, rpid_num, sizeof(rpid_num)); -- - of = get_in_brackets(from); - if (ast_strlen_zero(p->exten)) { - char *t = uri2; -@@ -12205,6 +13392,8 @@ - of2 = ast_strdupa(of); - - /* ignore all fields but name */ -+ /*! \todo Samme logical error as in many places above. Need a generic function for this. -+ */ - if (p->socket.type == SIP_TRANSPORT_TLS) { - if (parse_uri(of, "sips:", &of, &dummy, &domain, &dummy, &dummy)) { - if (parse_uri(of2, "sip:", &of, &dummy, &domain, &dummy, &dummy)) -@@ -12256,15 +13445,15 @@ - } - - res = check_peer_ok(p, of, req, sipmethod, sin, -- authpeer, reliable, rpid_num, calleridname, uri2); -+ authpeer, reliable, calleridname, uri2); - if (res != AUTH_DONT_KNOW) - return res; - - /* Finally, apply the guest policy */ -- if (global_allowguest) { -- replace_cid(p, rpid_num, calleridname); -+ if (sip_cfg.allowguest) { -+ get_rpid(p, req); - res = AUTH_SUCCESSFUL; -- } else if (global_alwaysauthreject) -+ } else if (sip_cfg.alwaysauthreject) - res = AUTH_FAKE_AUTH; /* reject with fake authorization request */ - else - res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */ -@@ -13023,11 +14212,11 @@ - } - } - --/* this func is used with ao2_callback to unlink/delete all dialogs that -+/*! \brief this func is used with ao2_callback to unlink/delete all dialogs that - are marked needdestroy. It will return CMP_MATCH for candidates, and they -- will be unlinked */ -+ will be unlinked - --/* TODO: Implement a queue and instead of marking a dialog -+ TODO: Implement a queue and instead of marking a dialog - to be destroyed, toss it into the queue. Have a separate - thread do the locking and destruction */ - -@@ -13095,7 +14284,7 @@ - - /* this func is used with ao2_callback to unlink/delete all marked - peers */ --static int peer_is_marked(void *peerobj, void *arg, int flags) -+static int peer_is_marked(void *peerobj, void *arg, int flags) - { - struct sip_peer *peer = peerobj; - return peer->the_mark ? CMP_MATCH : 0; -@@ -13111,19 +14300,25 @@ - char *name = NULL; - regex_t regexbuf; - struct ao2_iterator i; -+ static char *choices[] = { "all", "like", NULL }; -+ char *cmplt; - - if (cmd == CLI_INIT) { -- e->command = "sip prune realtime [peer|all] [all|like]"; -+ e->command = "sip prune realtime [peer|all]"; - e->usage = - "Usage: sip prune realtime [peer [|all|like ]|all]\n" - " Prunes object(s) from the cache.\n" - " Optional regular expression pattern is used to filter the objects.\n"; - return NULL; - } else if (cmd == CLI_GENERATE) { -- if (a->pos == 4) { -- if (strcasestr(a->line, "realtime peer")) -- return complete_sip_peer(a->word, a->n, SIP_PAGE2_RTCACHEFRIENDS); -+ if (a->pos == 4 && !strcasecmp(a->argv[3], "peer")) { -+ cmplt = ast_cli_complete(a->word, choices, a->n); -+ if (!cmplt) -+ cmplt = complete_sip_peer(a->word, a->n - sizeof(choices), SIP_PAGE2_RTCACHEFRIENDS); -+ return cmplt; - } -+ if (a->pos == 5 && !strcasecmp(a->argv[4], "like")) -+ return complete_sip_peer(a->word, a->n, SIP_PAGE2_RTCACHEFRIENDS); - return NULL; - } - switch (a->argc) { -@@ -13149,9 +14344,9 @@ - multi = TRUE; - } else - return CLI_SHOWUSAGE; -- if (!strcasecmp(a->argv[4], "like")) -+ if (!strcasecmp(name, "like")) - return CLI_SHOWUSAGE; -- if (!multi && !strcasecmp(a->argv[4], "all")) { -+ if (!multi && !strcasecmp(name, "all")) { - multi = TRUE; - name = NULL; - } -@@ -13196,7 +14391,7 @@ - unref_peer(pi, "toss iterator peer ptr"); - } - if (pruned) { -- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, 0, -+ ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL, - "initiating callback to remove marked peers"); - ast_cli(a->fd, "%d peers pruned.\n", pruned); - } else -@@ -13453,6 +14648,7 @@ - } - ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"":""); - ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"":""); -+ ast_cli(fd, " Remote Secret: %s\n", ast_strlen_zero(peer->remotesecret)?"":""); - for (auth = peer->auth; auth; auth = auth->next) { - ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s ", auth->realm, auth->username); - ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"":(!ast_strlen_zero(auth->md5secret)?"" : "")); -@@ -13497,6 +14693,7 @@ - ast_cli(fd, " User=Phone : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_USEREQPHONE))); - ast_cli(fd, " Video Support: %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT))); - ast_cli(fd, " Text Support : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT))); -+ ast_cli(fd, " Ign SDP ver : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION))); - ast_cli(fd, " Trust RPID : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID))); - ast_cli(fd, " Send RPID : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_SENDRPID))); - ast_cli(fd, " Subscriptions: %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))); -@@ -13512,7 +14709,8 @@ - ast_cli(fd, " ToHost : %s\n", peer->tohost); - ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port)); - ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port)); -- ast_cli(fd, " Transport : %s\n", get_transport(peer->socket.type)); -+ ast_cli(fd, " Prim.Transp. : %s\n", get_transport(peer->socket.type)); -+ ast_cli(fd, " Allowed.Trsp : %s\n", get_transport_list(peer->transports)); - if (!ast_strlen_zero(global_regcontext)) - ast_cli(fd, " Reg. exten : %s\n", peer->regexten); - ast_cli(fd, " Def. Username: %s\n", peer->username); -@@ -13564,6 +14762,7 @@ - astman_append(s, "ObjectName: %s\r\n", peer->name); - astman_append(s, "ChanObjectType: peer\r\n"); - astman_append(s, "SecretExist: %s\r\n", ast_strlen_zero(peer->secret)?"N":"Y"); -+ astman_append(s, "RemoteSecretExist: %s\r\n", ast_strlen_zero(peer->remotesecret)?"N":"Y"); - astman_append(s, "MD5SecretExist: %s\r\n", ast_strlen_zero(peer->md5secret)?"N":"Y"); - astman_append(s, "Context: %s\r\n", peer->context); - astman_append(s, "Language: %s\r\n", peer->language); -@@ -13760,7 +14959,7 @@ - - static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -- char cbuf[2256]; -+ struct ast_str *cbuf; - struct ast_cb_names cbnames = {9, { "retrans_pkt", - "__sip_autodestruct", - "expire_register", -@@ -13790,9 +14989,13 @@ - case CLI_GENERATE: - return NULL; - } -+ -+ cbuf = ast_str_alloca(2048); -+ - ast_cli(a->fd, "\n"); -- ast_sched_report(sched, cbuf, sizeof(cbuf), &cbnames); -- ast_cli(a->fd, "%s", cbuf); -+ ast_sched_report(sched, &cbuf, &cbnames); -+ ast_cli(a->fd, "%s", cbuf->str); -+ - return CLI_SUCCESS; - } - -@@ -14009,29 +15212,30 @@ - } - ast_cli(a->fd, " Videosupport: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT))); - ast_cli(a->fd, " Textsupport: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT))); -- ast_cli(a->fd, " AutoCreate Peer: %s\n", cli_yesno(autocreatepeer)); -+ ast_cli(a->fd, " Ignore SDP sess. ver.: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_IGNORESDPVERSION))); -+ ast_cli(a->fd, " AutoCreate Peer: %s\n", cli_yesno(sip_cfg.autocreatepeer)); - ast_cli(a->fd, " Match Auth Username: %s\n", cli_yesno(global_match_auth_username)); -- ast_cli(a->fd, " Allow unknown access: %s\n", cli_yesno(global_allowguest)); -+ ast_cli(a->fd, " Allow unknown access: %s\n", cli_yesno(sip_cfg.allowguest)); - ast_cli(a->fd, " Allow subscriptions: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))); - ast_cli(a->fd, " Allow overlap dialing: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP))); - ast_cli(a->fd, " Allow promsic. redir: %s\n", cli_yesno(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR))); - ast_cli(a->fd, " Enable call counters: %s\n", cli_yesno(global_callcounter)); - ast_cli(a->fd, " SIP domain support: %s\n", cli_yesno(!AST_LIST_EMPTY(&domain_list))); - ast_cli(a->fd, " Realm. auth: %s\n", cli_yesno(authl != NULL)); -- ast_cli(a->fd, " Our auth realm %s\n", global_realm); -- ast_cli(a->fd, " Call to non-local dom.: %s\n", cli_yesno(allow_external_domains)); -+ ast_cli(a->fd, " Our auth realm %s\n", sip_cfg.realm); -+ ast_cli(a->fd, " Call to non-local dom.: %s\n", cli_yesno(sip_cfg.allow_external_domains)); - ast_cli(a->fd, " URI user is phone no: %s\n", cli_yesno(ast_test_flag(&global_flags[0], SIP_USEREQPHONE))); -- ast_cli(a->fd, " Always auth rejects: %s\n", cli_yesno(global_alwaysauthreject)); -- ast_cli(a->fd, " Direct RTP setup: %s\n", cli_yesno(global_directrtpsetup)); -+ ast_cli(a->fd, " Always auth rejects: %s\n", cli_yesno(sip_cfg.alwaysauthreject)); -+ ast_cli(a->fd, " Direct RTP setup: %s\n", cli_yesno(sip_cfg.directrtpsetup)); - ast_cli(a->fd, " User Agent: %s\n", global_useragent); - ast_cli(a->fd, " SDP Session Name: %s\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession); - ast_cli(a->fd, " SDP Owner Name: %s\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner); - ast_cli(a->fd, " Reg. context: %s\n", S_OR(global_regcontext, "(not set)")); -- ast_cli(a->fd, " Regexten on Qualify: %s\n", cli_yesno(global_regextenonqualify)); -+ ast_cli(a->fd, " Regexten on Qualify: %s\n", cli_yesno(sip_cfg.regextenonqualify)); - ast_cli(a->fd, " Caller ID: %s\n", default_callerid); - ast_cli(a->fd, " From: Domain: %s\n", default_fromdomain); - ast_cli(a->fd, " Record SIP history: %s\n", recordhistory ? "On" : "Off"); -- ast_cli(a->fd, " Call Events: %s\n", global_callevents ? "On" : "Off"); -+ ast_cli(a->fd, " Call Events: %s\n", sip_cfg.callevents ? "On" : "Off"); - ast_cli(a->fd, " Auth. Failure Events: %s\n", global_authfailureevents ? "On" : "Off"); - - ast_cli(a->fd, " T38 fax pt UDPTL: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_UDPTL))); -@@ -14102,25 +15306,30 @@ - ast_cli(a->fd, "\n"); - ast_cli(a->fd, " Relax DTMF: %s\n", cli_yesno(global_relaxdtmf)); - ast_cli(a->fd, " RFC2833 Compensation: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_RFC2833_COMPENSATE))); -- ast_cli(a->fd, " Compact SIP headers: %s\n", cli_yesno(compactheaders)); -+ ast_cli(a->fd, " Compact SIP headers: %s\n", cli_yesno(sip_cfg.compactheaders)); - ast_cli(a->fd, " RTP Keepalive: %d %s\n", global_rtpkeepalive, global_rtpkeepalive ? "" : "(Disabled)" ); - ast_cli(a->fd, " RTP Timeout: %d %s\n", global_rtptimeout, global_rtptimeout ? "" : "(Disabled)" ); - ast_cli(a->fd, " RTP Hold Timeout: %d %s\n", global_rtpholdtimeout, global_rtpholdtimeout ? "" : "(Disabled)"); - ast_cli(a->fd, " MWI NOTIFY mime type: %s\n", default_notifymime); -- ast_cli(a->fd, " DNS SRV lookup: %s\n", cli_yesno(global_srvlookup)); -- ast_cli(a->fd, " Pedantic SIP support: %s\n", cli_yesno(pedanticsipchecking)); -+ ast_cli(a->fd, " DNS SRV lookup: %s\n", cli_yesno(sip_cfg.srvlookup)); -+ ast_cli(a->fd, " Pedantic SIP support: %s\n", cli_yesno(sip_cfg.pedanticsipchecking)); - ast_cli(a->fd, " Reg. min duration %d secs\n", min_expiry); - ast_cli(a->fd, " Reg. max duration: %d secs\n", max_expiry); - ast_cli(a->fd, " Reg. default duration: %d secs\n", default_expiry); - ast_cli(a->fd, " Outbound reg. timeout: %d secs\n", global_reg_timeout); - ast_cli(a->fd, " Outbound reg. attempts: %d\n", global_regattempts_max); -- ast_cli(a->fd, " Notify ringing state: %s\n", cli_yesno(global_notifyringing)); -- ast_cli(a->fd, " Notify hold state: %s\n", cli_yesno(global_notifyhold)); -- ast_cli(a->fd, " SIP Transfer mode: %s\n", transfermode2str(global_allowtransfer)); -+ ast_cli(a->fd, " Notify ringing state: %s\n", cli_yesno(sip_cfg.notifyringing)); -+ if (sip_cfg.notifyringing) { -+ ast_cli(a->fd, " Include CID: %s%s\n", -+ cli_yesno(sip_cfg.notifycid), -+ sip_cfg.notifycid == IGNORE_CONTEXT ? " (Ignoring context)" : ""); -+ } -+ ast_cli(a->fd, " Notify hold state: %s\n", cli_yesno(sip_cfg.notifyhold)); -+ ast_cli(a->fd, " SIP Transfer mode: %s\n", transfermode2str(sip_cfg.allowtransfer)); - ast_cli(a->fd, " Max Call Bitrate: %d kbps\n", default_maxcallbitrate); - ast_cli(a->fd, " Auto-Framing: %s\n", cli_yesno(global_autoframing)); -- ast_cli(a->fd, " Outb. proxy: %s %s\n", ast_strlen_zero(global_outboundproxy.name) ? "" : global_outboundproxy.name, -- global_outboundproxy.force ? "(forced)" : ""); -+ ast_cli(a->fd, " Outb. proxy: %s %s\n", ast_strlen_zero(sip_cfg.outboundproxy.name) ? "" : sip_cfg.outboundproxy.name, -+ sip_cfg.outboundproxy.force ? "(forced)" : ""); - ast_cli(a->fd, " Session Timers: %s\n", stmode2str(global_st_mode)); - ast_cli(a->fd, " Session Refresher: %s\n", strefresher2str (global_st_refresher)); - ast_cli(a->fd, " Session Expires: %d secs\n", global_max_se); -@@ -14131,7 +15340,9 @@ - - ast_cli(a->fd, "\nDefault Settings:\n"); - ast_cli(a->fd, "-----------------\n"); -- ast_cli(a->fd, " Context: %s\n", default_context); -+ ast_cli(a->fd, " Allowed transports: %s\n", get_transport_list(default_transports)); -+ ast_cli(a->fd, " Outbound transport: %s\n", get_transport(default_primary_transport)); -+ ast_cli(a->fd, " Context: %s\n", sip_cfg.default_context); - ast_cli(a->fd, " Nat: %s\n", nat2str(ast_test_flag(&global_flags[0], SIP_NAT))); - ast_cli(a->fd, " DTMF: %s\n", dtmfmode2str(ast_test_flag(&global_flags[0], SIP_DTMF))); - ast_cli(a->fd, " Qualify: %d\n", default_qualify); -@@ -14152,12 +15363,42 @@ - ast_cli(a->fd, " Update: %s\n", cli_yesno(sip_cfg.peer_rtupdate)); - ast_cli(a->fd, " Ignore Reg. Expire: %s\n", cli_yesno(sip_cfg.ignore_regexpire)); - ast_cli(a->fd, " Save sys. name: %s\n", cli_yesno(sip_cfg.rtsave_sysname)); -- ast_cli(a->fd, " Auto Clear: %d\n", global_rtautoclear); -+ ast_cli(a->fd, " Auto Clear: %d\n", sip_cfg.rtautoclear); - } - ast_cli(a->fd, "\n----\n"); - return CLI_SUCCESS; - } - -+static char *sip_show_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+#define FORMAT "%-30.30s %-12.12s %-10.10s %-10.10s\n" -+ char host[80]; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "sip show mwi"; -+ e->usage = -+ "Usage: sip show mwi\n" -+ " Provides a list of MWI subscriptions and status.\n"; -+ return NULL; -+ case CLI_GENERATE: -+ return NULL; -+ } -+ -+ ast_cli(a->fd, FORMAT, "Host", "Username", "Mailbox", "Subscribed"); -+ -+ ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do { -+ ASTOBJ_RDLOCK(iterator); -+ snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : STANDARD_SIP_PORT); -+ ast_cli(a->fd, FORMAT, host, iterator->username, iterator->mailbox, iterator->subscribed ? "Yes" : "No"); -+ ASTOBJ_UNLOCK(iterator); -+ } while(0)); -+ -+ return CLI_SUCCESS; -+#undef FORMAT -+} -+ -+ - /*! \brief Show subscription type in string format */ - static const char *subscription_type2str(enum subscriptiontype subtype) - { -@@ -14638,7 +15879,7 @@ - } - - /* Try getting the "signal=" part */ -- if (ast_strlen_zero(c = get_body(req, "Signal")) && ast_strlen_zero(c = get_body(req, "d"))) { -+ if (ast_strlen_zero(c = get_body(req, "Signal", '=')) && ast_strlen_zero(c = get_body(req, "d", '='))) { - ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid); - transmit_response(p, "200 OK", req); /* Should return error */ - return; -@@ -14646,7 +15887,7 @@ - ast_copy_string(buf, c, sizeof(buf)); - } - -- if (!ast_strlen_zero((c = get_body(req, "Duration")))) -+ if (!ast_strlen_zero((c = get_body(req, "Duration", '=')))) - duration = atoi(c); - if (!duration) - duration = 100; /* 100 ms */ -@@ -14867,7 +16108,7 @@ - " IP address or registered peer.\n"; - return NULL; - } else if (cmd == CLI_GENERATE) { -- if (a->pos == 4 && strcasestr(a->line, " peer")) /* XXX should check on argv too */ -+ if (a->pos == 4 && !strcasecmp(a->argv[3], "peer")) - return complete_sip_peer(a->word, a->n, 0); - return NULL; - } -@@ -14963,36 +16204,6 @@ - return CLI_SUCCESS; - } - --/*! \brief Enable/Disable SIP History logging (CLI) - deprecated. use sip_set_history instead */ --static char *sip_do_history_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "sip history [off]"; -- e->usage = -- "Usage: sip history [off]\n" -- " Enables/Disables recording of SIP dialog history for debugging purposes.\n" -- " Use 'sip show history' to view the history of a call number.\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- -- if (a->argc < 2 || a->argc > 3) { -- return CLI_SHOWUSAGE; -- } -- if (a->argc == 2) { -- recordhistory = TRUE; -- ast_cli(a->fd, "SIP History Recording Enabled (use 'sip show history')\n"); -- } else { -- if (strncasecmp(a->argv[2], "off", 3)) -- return CLI_SHOWUSAGE; -- recordhistory = FALSE; -- ast_cli(a->fd, "SIP History Recording Disabled\n"); -- } -- return CLI_SUCCESS; --} -- - /*! \brief Enable/Disable SIP History logging (CLI) */ - static char *sip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -@@ -15178,7 +16389,7 @@ - auth = find_realm_authentication(authl, p->realm); /* If not, global list */ - - if (auth) { -- ast_log(LOG_DEBUG, "use realm [%s] from peer [%s][%s]\n", auth->username, p->peername, p->username); -+ ast_debug(3, "use realm [%s] from peer [%s][%s]\n", auth->username, p->peername, p->username); - username = auth->username; - secret = auth->secret; - md5secret = auth->md5secret; -@@ -15281,11 +16492,6 @@ - - static struct ast_custom_function sip_header_function = { - .name = "SIP_HEADER", -- .synopsis = "Gets the specified SIP header", -- .syntax = "SIP_HEADER([,])", -- .desc = "Since there are several headers (such as Via) which can occur multiple\n" -- "times, SIP_HEADER takes an optional second argument to specify which header with\n" -- "that name to retrieve. Headers start at offset 1.\n", - .read = func_header_read, - }; - -@@ -15305,13 +16511,7 @@ - - static struct ast_custom_function checksipdomain_function = { - .name = "CHECKSIPDOMAIN", -- .synopsis = "Checks if domain is a local domain", -- .syntax = "CHECKSIPDOMAIN()", - .read = func_check_sipdomain, -- .desc = "This function checks if the domain in the argument is configured\n" -- "as a local SIP domain that this Asterisk server is configured to handle.\n" -- "Returns the domain name if it is locally handled, otherwise an empty string.\n" -- "Check the domain= configuration in sip.conf\n", - }; - - /*! \brief ${SIPPEER()} Dialplan function - reads peer data */ -@@ -15378,9 +16578,11 @@ - struct ast_variable *v; - - chanvar = strsep(&chanvar, "]"); -- for (v = peer->chanvars ; v ; v = v->next) -- if (!strcasecmp(v->name, chanvar)) -+ for (v = peer->chanvars ; v ; v = v->next) { -+ if (!strcasecmp(v->name, chanvar)) { - ast_copy_string(buf, v->value, len); -+ } -+ } - } else if (!strncasecmp(colname, "codec[", 6)) { - char *codecnum; - int codec = 0; -@@ -15402,35 +16604,9 @@ - } - - /*! \brief Structure to declare a dialplan function: SIPPEER */ --struct ast_custom_function sippeer_function = { -+static struct ast_custom_function sippeer_function = { - .name = "SIPPEER", -- .synopsis = "Gets SIP peer information", -- .syntax = "SIPPEER([,item])", - .read = function_sippeer, -- .desc = "Valid items are:\n" -- "- ip (default) The IP address.\n" -- "- port The port number\n" -- "- mailbox The configured mailbox.\n" -- "- context The configured context.\n" -- "- expire The epoch time of the next expire.\n" -- "- dynamic Is it dynamic? (yes/no).\n" -- "- callerid_name The configured Caller ID name.\n" -- "- callerid_num The configured Caller ID number.\n" -- "- callgroup The configured Callgroup.\n" -- "- pickupgroup The configured Pickupgroup.\n" -- "- codecs The configured codecs.\n" -- "- status Status (if qualify=yes).\n" -- "- regexten Registration extension\n" -- "- limit Call limit (call-limit)\n" -- "- busylevel Configured call level for signalling busy\n" -- "- curcalls Current amount of calls \n" -- " Only available if call-limit is set\n" -- "- language Default language for peer\n" -- "- accountcode Account code for this peer\n" -- "- useragent Current user agent id for peer\n" -- "- chanvar[name] A channel variable configured with setvar for this peer.\n" -- "- codec[x] Preferred codec index number 'x' (beginning with zero).\n" -- "\n" - }; - - /*! \brief ${SIPCHANINFO()} Dialplan function - reads sip channel data */ -@@ -15495,37 +16671,153 @@ - /*! \brief Structure to declare a dialplan function: SIPCHANINFO */ - static struct ast_custom_function sipchaninfo_function = { - .name = "SIPCHANINFO", -- .synopsis = "Gets the specified SIP parameter from the current channel", -- .syntax = "SIPCHANINFO(item)", - .read = function_sipchaninfo_read, -- .desc = "Valid items are:\n" -- "- peerip The IP address of the peer.\n" -- "- recvip The source IP address of the peer.\n" -- "- from The URI from the From: header.\n" -- "- uri The URI from the Contact: header.\n" -- "- useragent The useragent.\n" -- "- peername The name of the peer.\n" -- "- t38passthrough 1 if T38 is offered or enabled in this channel, otherwise 0\n" - }; - --/*! \brief Parse 302 Moved temporalily response */ --static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req) -+static int read_to_parts(struct sip_pvt *p, struct sip_request *req, char **name, char **number) - { -- char tmp[SIPBUFSIZE]; -- char *s, *e, *t, *trans; -+ -+ char to_header[256]; -+ char *to_name = NULL; -+ char *to_number = NULL; -+ char *separator; -+ -+ ast_copy_string(to_header, get_header(req, "To"), sizeof(to_header)); -+ -+ /* Let's get that number first! */ -+ to_number = get_in_brackets(to_header); -+ -+ if (!strncasecmp(to_number, "sip:", 4)) { -+ to_number += 4; -+ } else if (!strncasecmp(to_number, "sips:", 5)) { -+ to_number += 5; -+ } else { -+ ast_log(LOG_WARNING, "Not a SIP URI? (%s)!\n", to_number); -+ return -1; -+ } -+ -+ /* Remove the host and such since we just want the number */ -+ if ((separator = strchr(to_number, '@'))) { -+ *separator = '\0'; -+ } -+ -+ /* We have the number. Let's get the name now. */ -+ -+ if (*to_header == '\"') { -+ to_name = to_header + 1; -+ if (!(separator = (char *)find_closing_quote(to_name, NULL))) { -+ ast_log(LOG_NOTICE, "No closing quote in name section of To: header (%s)\n", to_header); -+ return -1; -+ } -+ *separator = '\0'; -+ } -+ -+ if (number) { -+ *number = ast_strdup(to_number); -+ } -+ if (name && !ast_strlen_zero(to_name)) { -+ *name = ast_strdup(to_name); -+ } -+ -+ return 0; -+} -+ -+/*! \brief update redirecting information for a channel based on headers -+ * -+ */ -+static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward) -+{ -+ char *redirecting_from_name = NULL; -+ char *redirecting_from_number = NULL; -+ char *redirecting_to_name = NULL; -+ char *redirecting_to_number = NULL; -+ int reason = AST_REDIRECTING_REASON_UNCONDITIONAL; -+ int is_response = req->method == SIP_RESPONSE; -+ int res = 0; -+ -+ res = get_rdnis(p, req, &redirecting_from_name, &redirecting_from_number, &reason); -+ if (res == -1) { -+ if (is_response) { -+ read_to_parts(p, req, &redirecting_from_name, &redirecting_from_number); -+ } else { -+ return; -+ } -+ } -+ -+ /* At this point, all redirecting "from" info should be filled in appropriately -+ * on to the "to" info -+ */ -+ -+ if (is_response) { -+ parse_moved_contact(p, req, &redirecting_to_name, &redirecting_to_number, set_call_forward); -+ } else { -+ read_to_parts(p, req, &redirecting_to_name, &redirecting_to_number); -+ } -+ -+ if (!ast_strlen_zero(redirecting_from_number)) { -+ if (redirecting->from.number) { -+ ast_free(redirecting->from.number); -+ } -+ ast_debug(3, "Got redirecting from number %s\n", redirecting_from_number); -+ redirecting->from.number = redirecting_from_number; -+ } -+ if (!ast_strlen_zero(redirecting_from_name)) { -+ if (redirecting->from.name) { -+ ast_free(redirecting->from.name); -+ } -+ ast_debug(3, "Got redirecting from name %s\n", redirecting_from_name); -+ redirecting->from.name = redirecting_from_name; -+ } -+ if (!ast_strlen_zero(redirecting_to_number)) { -+ if (redirecting->to.number) { -+ ast_free(redirecting->to.number); -+ } -+ ast_debug(3, "Got redirecting to number %s\n", redirecting_to_number); -+ redirecting->to.number = redirecting_to_number; -+ } -+ if (!ast_strlen_zero(redirecting_to_name)) { -+ if (redirecting->to.name) { -+ ast_free(redirecting->to.name); -+ } -+ ast_debug(3, "Got redirecting to name %s\n", redirecting_from_number); -+ redirecting->to.name = redirecting_to_name; -+ } -+ redirecting->reason = reason; -+} -+ -+/*! \brief Parse 302 Moved temporalily response -+ \todo XXX Doesn't redirect over TLS on sips: uri's. -+ If we get a redirect to a SIPS: uri, this needs to be going back to the -+ dialplan (this is a request for a secure signalling path). -+ Note that transport=tls is deprecated, but we need to support it on incoming requests. -+*/ -+static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward) -+{ -+ char contact[SIPBUFSIZE]; -+ char *contact_name = NULL; -+ char *contact_number = NULL; -+ char *separator, *trans; - char *domain; - enum sip_transport transport = SIP_TRANSPORT_UDP; - -- ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp)); -- if ((t = strchr(tmp, ','))) -- *t = '\0'; -+ ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); -+ if ((separator = strchr(contact, ','))) -+ *separator = '\0'; - -- s = get_in_brackets(tmp); -- if ((trans = strcasestr(s, ";transport="))) do { -+ /* ooh, a name */ -+ if (*contact == '"') { -+ contact_name = contact + 1; -+ if ((separator = strchr(contact_name, '"'))) { -+ *separator++ = '\0'; -+ } -+ } -+ -+ contact_number = get_in_brackets(contact); -+ if ((trans = strcasestr(contact_number, ";transport="))) { - trans += 11; - -- if ((e = strchr(trans, ';'))) -- *e = '\0'; -+ if ((separator = strchr(trans, ';'))) -+ *separator = '\0'; - - if (!strncasecmp(trans, "tcp", 3)) - transport = SIP_TRANSPORT_TCP; -@@ -15533,11 +16825,12 @@ - transport = SIP_TRANSPORT_TLS; - else { - if (strncasecmp(trans, "udp", 3)) -- ast_debug(1, "received contact with an invalid transport, '%s'\n", s); -+ ast_debug(1, "received contact with an invalid transport, '%s'\n", contact_number); -+ /* This will assume UDP for all unknown transports */ - transport = SIP_TRANSPORT_UDP; - } -- } while(0); -- s = remove_uri_parameters(s); -+ } -+ contact_number = remove_uri_parameters(contact_number); - - if (p->socket.tcptls_session) { - ao2_ref(p->socket.tcptls_session, -1); -@@ -15547,51 +16840,70 @@ - p->socket.fd = -1; - p->socket.type = transport; - -- if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) { -+ if (set_call_forward && ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) { - char *host = NULL; -- if (!strncasecmp(s, "sip:", 4)) -- s += 4; -- else if (!strncasecmp(s, "sips:", 5)) -- s += 5; -- e = strchr(s, '/'); -- if (e) -- *e = '\0'; -- if ((host = strchr(s, '@'))) { -+ if (!strncasecmp(contact_number, "sip:", 4)) -+ contact_number += 4; -+ else if (!strncasecmp(contact_number, "sips:", 5)) -+ contact_number += 5; -+ separator = strchr(contact_number, '/'); -+ if (separator) -+ *separator = '\0'; -+ if ((host = strchr(contact_number, '@'))) { - *host++ = '\0'; -- ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", s, get_transport(transport), host); -+ ast_debug(2, "Found promiscuous redirection to 'SIP/%s::::%s@%s'\n", contact_number, get_transport(transport), host); - if (p->owner) -- ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", s, get_transport(transport), host); -+ ast_string_field_build(p->owner, call_forward, "SIP/%s::::%s@%s", contact_number, get_transport(transport), host); - } else { -- ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), s); -+ ast_debug(2, "Found promiscuous redirection to 'SIP/::::%s@%s'\n", get_transport(transport), contact_number); - if (p->owner) -- ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), s); -+ ast_string_field_build(p->owner, call_forward, "SIP/::::%s@%s", get_transport(transport), contact_number); - } - } else { -- e = strchr(tmp, '@'); -- if (e) { -- *e++ = '\0'; -- domain = e; -+ separator = strchr(contact, '@'); -+ if (separator) { -+ *separator++ = '\0'; -+ domain = separator; - } else { - /* No username part */ -- domain = tmp; -+ domain = contact; - } -- e = strchr(tmp, '/'); /* WHEN do we hae a forward slash in the URI? */ -- if (e) -- *e = '\0'; -+ separator = strchr(contact, '/'); /* WHEN do we hae a forward slash in the URI? */ -+ if (separator) -+ *separator = '\0'; - -- if (!strncasecmp(s, "sip:", 4)) -- s += 4; -- else if (!strncasecmp(s, "sips:", 5)) -- s += 5; -- e = strchr(s, ';'); /* And username ; parameters? */ -- if (e) -- *e = '\0'; -- ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", s, domain); -- if (p->owner) { -- pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain); -- ast_string_field_set(p->owner, call_forward, s); -+ if (!strncasecmp(contact_number, "sip:", 4)) -+ contact_number += 4; -+ else if (!strncasecmp(contact_number, "sips:", 5)) -+ contact_number += 5; -+ separator = strchr(contact_number, ';'); /* And username ; parameters? */ -+ if (separator) -+ *separator = '\0'; -+ if (set_call_forward) { -+ ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", contact_number, domain); -+ if (p->owner) { -+ pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain); -+ ast_string_field_set(p->owner, call_forward, contact_number); -+ } - } - } -+ -+ /* We've gotten the number for the contact, now get the name */ -+ -+ if (*contact == '\"') { -+ contact_name = contact + 1; -+ if (!(separator = (char *)find_closing_quote(contact_name, NULL))) { -+ ast_log(LOG_NOTICE, "No closing quote on name in Contact header? %s\n", contact); -+ } -+ *separator = '\0'; -+ } -+ -+ if (name && !ast_strlen_zero(contact_name)) { -+ *name = ast_strdup(contact_name); -+ } -+ if (number) { -+ *number = ast_strdup(contact_number); -+ } - } - - /*! \brief Check pending actions on SIP call */ -@@ -15604,7 +16916,7 @@ - /* Actually don't destroy us yet, wait for the 487 on our original - INVITE, but do set an autodestruct just in case we never get it. */ - else { -- /* We have a pending outbound invite, don't send someting -+ /* We have a pending outbound invite, don't send something - new in-transaction */ - if (p->pendinginvite) - return; -@@ -15652,7 +16964,8 @@ - struct ast_channel *bridgepeer = NULL; - char *p_hdrval; - int rtn; -- -+ struct ast_party_connected_line connected; -+ - if (reinvite) - ast_debug(4, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid); - else -@@ -15670,7 +16983,7 @@ - /* RFC3261 says we must treat every 1xx response (but not 100) - that we don't recognize as if it was 183. - */ -- if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 182 && resp != 183) -+ if (resp > 100 && resp < 200 && resp!=101 && resp != 180 && resp != 181 && resp != 182 && resp != 183) - resp = 183; - - /* Any response between 100 and 199 is PROCEEDING */ -@@ -15698,6 +17011,14 @@ - if (!req->ignore && p->invitestate != INV_CANCELLED && sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); - if (!req->ignore && p->owner) { -+ if (get_rpid(p, req)) { -+ ast_party_connected_line_init(&connected); -+ connected.id.number = (char *) p->cid_num; -+ connected.id.name = (char *) p->cid_name; -+ connected.id.number_presentation = p->callingpres; -+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_queue_connected_line_update(p->owner, &connected); -+ } - ast_queue_control(p->owner, AST_CONTROL_RINGING); - if (p->owner->_state != AST_STATE_UP) { - ast_setstate(p->owner, AST_STATE_RINGING); -@@ -15714,11 +17035,33 @@ - } - check_pendings(p); - break; -+ -+ case 181: /* Call Is Being Forwarded */ -+ if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) -+ ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); -+ if (!req->ignore && p->owner) { -+ struct ast_party_redirecting redirecting = {{0,},}; -+ change_redirecting_information(p, req, &redirecting, FALSE); -+ ast_queue_redirecting_update(p->owner, &redirecting); -+ } -+ check_pendings(p); -+ break; - - case 183: /* Session progress */ - if (!req->ignore && (p->invitestate != INV_CANCELLED) && sip_cancel_destroy(p)) - ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); - /* Ignore 183 Session progress without SDP */ -+ if (!req->ignore && p->owner) { -+ if (get_rpid(p, req)) { -+ /* Queue a connected line update */ -+ ast_party_connected_line_init(&connected); -+ connected.id.number = (char *) p->cid_num; -+ connected.id.name = (char *) p->cid_name; -+ connected.id.number_presentation = p->callingpres; -+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_queue_connected_line_update(p->owner, &connected); -+ } -+ } - if (find_sdp(req)) { - if (p->invitestate != INV_CANCELLED) - p->invitestate = INV_EARLY_MEDIA; -@@ -15742,6 +17085,16 @@ - /* For re-invites, we try to recover */ - ast_set_flag(&p->flags[0], SIP_PENDINGBYE); - } -+ -+ if (!req->ignore && p->owner && get_rpid(p, req)) { -+ /* Queue a connected line update */ -+ ast_party_connected_line_init(&connected); -+ connected.id.number = (char *) p->cid_num; -+ connected.id.name = (char *) p->cid_name; -+ connected.id.number_presentation = p->callingpres; -+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_queue_connected_line_update(p->owner, &connected); -+ } - - /* Parse contact header for continued conversation */ - /* When we get 200 OK, we know which device (and IP) to contact for this call */ -@@ -15799,11 +17152,14 @@ - - if (!req->ignore && p->owner) { - if (!reinvite) { -+ struct ast_party_connected_line connected; -+ ast_party_connected_line_collect_caller(&connected, &p->owner->cid); -+ ast_queue_connected_line_update(p->owner, &connected); - ast_queue_control(p->owner, AST_CONTROL_ANSWER); -- if (global_callevents) -+ if (sip_cfg.callevents) - manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", - "Channel: %s\r\nChanneltype: %s\r\nUniqueid: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n", -- p->owner->name, p->owner->uniqueid, "SIP", p->callid, p->fullcontact, p->peername); -+ p->owner->name, "SIP", p->owner->uniqueid, p->callid, p->fullcontact, p->peername); - } else { /* RE-invite */ - ast_queue_frame(p->owner, &ast_null_frame); - } -@@ -15868,7 +17224,7 @@ - p->invitestate = INV_CALLING; - if (p->authtries == MAX_AUTHTRIES || do_proxy_auth(p, req, resp, SIP_INVITE, 1)) { - ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From")); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "failed to authenticate on INVITE"); - sip_alreadygone(p); - if (p->owner) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -@@ -15882,7 +17238,7 @@ - ast_log(LOG_WARNING, "Received response: \"Forbidden\" from '%s'\n", get_header(&p->initreq, "From")); - if (!req->ignore && p->owner) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 403 response"); - sip_alreadygone(p); - break; - -@@ -15909,6 +17265,16 @@ - proc_422_rsp(p, req); - break; - -+ case 428: /* Use identity header - rfc 4474 - not supported by Asterisk yet */ -+ xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); -+ append_history(p, "Identity", "SIP identity is required. Not supported by Asterisk."); -+ ast_log(LOG_WARNING, "SIP identity required by proxy. SIP dialog '%s'. Giving up.\n", p->callid); -+ if (p->owner) -+ ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -+ break; -+ -+ -+ - case 487: /* Cancelled transaction */ - /* We have sent CANCEL on an outbound INVITE - This transaction is already scheduled to be killed by sip_hangup(). -@@ -15920,7 +17286,7 @@ - } else if (!req->ignore) { - update_call_counter(p, DEC_CALL_LIMIT); - append_history(p, "Hangup", "Got 487 on CANCEL request from us on call without owner. Killing this dialog."); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 487 response"); - sip_alreadygone(p); - } - break; -@@ -15945,13 +17311,13 @@ - /* The dialog is now terminated */ - if (p->owner && !req->ignore) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "got error on T.38 initial invite"); - sip_alreadygone(p); - } else { - /* We can't set up this call, so give up */ - if (p->owner && !req->ignore) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 488 response"); - /* If there's no dialog to end, then mark p as already gone */ - if (!reinvite) - sip_alreadygone(p); -@@ -15962,7 +17328,7 @@ - if (p->owner && !req->ignore) { - if (p->owner->_state != AST_STATE_UP) { - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 491 response"); - } else { - /* This is a re-invite that failed. */ - /* Reset the flag after a while -@@ -16003,7 +17369,7 @@ - } else { - if (p->subscribed == NONE) { - ast_debug(4, "Got 200 accepted on NOTIFY\n"); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 200 response"); - } - if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) { - /* Ready to send the next state we have on queue */ -@@ -16020,16 +17386,75 @@ - ast_string_field_set(p, theirtag, NULL); - if (ast_strlen_zero(p->authname)) { - ast_log(LOG_WARNING, "Asked to authenticate NOTIFY to %s:%d but we have no matching peer or realm auth!\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unable to authenticate NOTIFY"); - } - if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_NOTIFY, 0)) { -- ast_log(LOG_NOTICE, "Failed to authenticate on NOTYFY to '%s'\n", get_header(&p->initreq, "From")); -- p->needdestroy = 1; -+ ast_log(LOG_NOTICE, "Failed to authenticate on NOTIFY to '%s'\n", get_header(&p->initreq, "From")); -+ pvt_set_needdestroy(p, "failed to authenticate NOTIFY"); - } - break; - } - } - -+/* \brief Handle SIP response in SUBSCRIBE transaction */ -+static void handle_response_subscribe(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno) -+{ -+ if (!p->mwi) { -+ return; -+ } -+ -+ switch (resp) { -+ case 200: /* Subscription accepted */ -+ ast_debug(3, "Got 200 OK on subscription for MWI\n"); -+ if (p->options) { -+ ast_free(p->options); -+ p->options = NULL; -+ } -+ p->mwi->subscribed = 1; -+ if ((p->mwi->resub = ast_sched_add(sched, mwi_expiry * 1000, sip_subscribe_mwi_do, ASTOBJ_REF(p->mwi))) < 0) { -+ ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy); -+ } -+ break; -+ case 401: -+ case 407: -+ ast_string_field_set(p, theirtag, NULL); -+ if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_SUBSCRIBE, 0)) { -+ ast_log(LOG_NOTICE, "Failed to authenticate on SUBSCRIBE to '%s'\n", get_header(&p->initreq, "From")); -+ p->mwi->call = NULL; -+ ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy); -+ pvt_set_needdestroy(p, "failed to authenticate SUBSCRIBE"); -+ } -+ break; -+ case 403: -+ transmit_response_with_date(p, "200 OK", req); -+ ast_log(LOG_WARNING, "Authentication failed while trying to subscribe for MWI.\n"); -+ p->mwi->call = NULL; -+ ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy); -+ pvt_set_needdestroy(p, "received 403 response"); -+ sip_alreadygone(p); -+ break; -+ case 404: -+ ast_log(LOG_WARNING, "Subscription failed for MWI. The remote side said that a mailbox may not have been configured.\n"); -+ p->mwi->call = NULL; -+ ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy); -+ pvt_set_needdestroy(p, "received 404 response"); -+ break; -+ case 481: -+ ast_log(LOG_WARNING, "Subscription failed for MWI. The remote side said that our dialog did not exist.\n"); -+ p->mwi->call = NULL; -+ ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy); -+ pvt_set_needdestroy(p, "received 481 response"); -+ break; -+ case 500: -+ case 501: -+ ast_log(LOG_WARNING, "Subscription failed for MWI. The remote side may have suffered a heart attack.\n"); -+ p->mwi->call = NULL; -+ ASTOBJ_UNREF(p->mwi, sip_subscribe_mwi_destroy); -+ pvt_set_needdestroy(p, "received 500/501 response"); -+ break; -+ } -+} -+ - /* \brief Handle SIP response in REFER transaction - We've sent a REFER, now handle responses to it - */ -@@ -16054,12 +17479,12 @@ - if (ast_strlen_zero(p->authname)) { - ast_log(LOG_WARNING, "Asked to authenticate REFER to %s:%d but we have no matching peer or realm auth!\n", - ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unable to authenticate REFER"); - } - if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_REFER, 0)) { - ast_log(LOG_NOTICE, "Failed to authenticate on REFER to '%s'\n", get_header(&p->initreq, "From")); - p->refer->status = REFER_NOAUTH; -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "failed to authenticat REFER"); - } - break; - case 481: /* Call leg does not exist */ -@@ -16070,7 +17495,7 @@ - ast_log(LOG_WARNING, "Remote host can't match REFER request to call '%s'. Giving up.\n", p->callid); - if (p->owner) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 481 response"); - break; - - case 500: /* Server error */ -@@ -16078,13 +17503,13 @@ - /* Return to the current call onhold */ - /* Status flag needed to be reset */ - ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 500/501 response"); - p->refer->status = REFER_FAILED; - break; - case 603: /* Transfer declined */ - ast_log(LOG_NOTICE, "SIP transfer to %s declined, call miserably fails. \n", p->refer->refer_to); - p->refer->status = REFER_FAILED; -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 603 response"); - break; - } - } -@@ -16100,18 +17525,18 @@ - case 401: /* Unauthorized */ - if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) { - ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s@%s' (Tries %d)\n", p->registry->username, p->registry->hostname, p->authtries); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "failed to authenticate REGISTER"); - } - break; - case 403: /* Forbidden */ - ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname); - AST_SCHED_DEL(sched, r->timeout); - r->regstate = REG_STATE_NOAUTH; -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 403 response"); - break; - case 404: /* Not found */ - ast_log(LOG_WARNING, "Got 404 Not found on SIP register to service %s@%s, giving up\n", p->registry->username, p->registry->hostname); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 404 response"); - if (r->call) - r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 404"); - r->regstate = REG_STATE_REJECTED; -@@ -16120,7 +17545,7 @@ - case 407: /* Proxy auth */ - if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) { - ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(&p->initreq, "From"), p->authtries); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "failed to authenticate REGISTER"); - } - break; - case 408: /* Request timeout */ -@@ -16138,7 +17563,7 @@ - r->timeout = -1; - if (r->call) { - r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 423"); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 423 response"); - } - if (r->expiry > max_expiry) { - ast_log(LOG_WARNING, "Required expiration time from %s@%s is too high, giving up\n", p->registry->username, p->registry->hostname); -@@ -16152,7 +17577,7 @@ - break; - case 479: /* SER: Not able to process the URI - address is wrong in register*/ - ast_log(LOG_WARNING, "Got error 479 on register to %s@%s, giving up (check config)\n", p->registry->username, p->registry->hostname); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 479 response"); - if (r->call) - r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 479"); - r->regstate = REG_STATE_REJECTED; -@@ -16161,7 +17586,7 @@ - case 200: /* 200 OK */ - if (!r) { - ast_log(LOG_WARNING, "Got 200 OK on REGISTER, but there isn't a registry entry for '%s' (we probably already got the OK)\n", S_OR(p->peername, p->username)); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received erroneous 200 response"); - return 0; - } - -@@ -16267,18 +17692,21 @@ - peer->call = dialog_unref(peer->call, "unref dialog peer->call"); - if (statechanged) { - const char *s = is_reachable ? "Reachable" : "Lagged"; -+ char str_lastms[20]; -+ snprintf(str_lastms, sizeof(str_lastms), "%d", pingtime); - - ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n", - peer->name, s, pingtime, peer->maxms); - ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); -+ ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL); - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", - "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: %s\r\nTime: %d\r\n", - peer->name, s, pingtime); -- if (is_reachable && global_regextenonqualify) -+ if (is_reachable && sip_cfg.regextenonqualify) - register_peer_exten(peer, TRUE); - } - -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "got OPTIONS response"); - - /* Try again eventually */ - AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, -@@ -16358,7 +17786,7 @@ - * receive any of those responses to a BYE. - */ - if ((resp == 404 || resp == 408 || resp == 481) && sipmethod == SIP_BYE) { -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 4XX response to a BYE"); - return; - } - -@@ -16372,18 +17800,10 @@ - switch(resp) { - case 100: /* 100 Trying */ - case 101: /* 101 Dialog establishment */ -- if (sipmethod == SIP_INVITE) -- handle_response_invite(p, resp, rest, req, seqno); -- break; - case 183: /* 183 Session Progress */ -- if (sipmethod == SIP_INVITE) -- handle_response_invite(p, resp, rest, req, seqno); -- break; - case 180: /* 180 Ringing */ -- if (sipmethod == SIP_INVITE) -- handle_response_invite(p, resp, rest, req, seqno); -- break; -- case 182: /* 182 Queued */ -+ case 182: /* 182 Queued */ -+ case 181: /* 181 Call Is Being Forwarded */ - if (sipmethod == SIP_INVITE) - handle_response_invite(p, resp, rest, req, seqno); - break; -@@ -16397,13 +17817,14 @@ - handle_response_invite(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_NOTIFY) { - handle_response_notify(p, resp, rest, req, seqno); -- } else if (sipmethod == SIP_REGISTER) -+ } else if (sipmethod == SIP_REGISTER) { - res = handle_response_register(p, resp, rest, req, seqno); -- else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */ -- p->needdestroy = 1; -- ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); - } else if (sipmethod == SIP_SUBSCRIBE) { - ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); -+ handle_response_subscribe(p, resp, rest, req, seqno); -+ } else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */ -+ pvt_set_needdestroy(p, "received 200 response"); -+ ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); - } - break; - case 202: /* Transfer accepted */ -@@ -16418,6 +17839,8 @@ - handle_response_notify(p, resp, rest, req, seqno); - else if (sipmethod == SIP_REFER) - handle_response_refer(p, resp, rest, req, seqno); -+ else if (sipmethod == SIP_SUBSCRIBE) -+ handle_response_subscribe(p, resp, rest, req, seqno); - else if (p->registry && sipmethod == SIP_REGISTER) - res = handle_response_register(p, resp, rest, req, seqno); - else if (sipmethod == SIP_BYE) { -@@ -16426,24 +17849,26 @@ - if (ast_strlen_zero(p->authname)) { - ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n", - msg, ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unable to authenticate BYE"); - } else if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp, sipmethod, 0)) { - ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From")); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "failed to authenticate BYE"); - } - } else { - ast_log(LOG_WARNING, "Got authentication request (%d) on %s to '%s'\n", resp, sip_methods[sipmethod].text, get_header(req, "To")); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 407 response"); - } - break; - case 403: /* Forbidden - we failed authentication */ - if (sipmethod == SIP_INVITE) - handle_response_invite(p, resp, rest, req, seqno); -+ else if (sipmethod == SIP_SUBSCRIBE) -+ handle_response_subscribe(p, resp, rest, req, seqno); - else if (p->registry && sipmethod == SIP_REGISTER) - res = handle_response_register(p, resp, rest, req, seqno); - else { - ast_log(LOG_WARNING, "Forbidden - maybe wrong password on authentication for %s\n", msg); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 403 response"); - } - break; - case 404: /* Not found */ -@@ -16451,6 +17876,8 @@ - res = handle_response_register(p, resp, rest, req, seqno); - else if (sipmethod == SIP_INVITE) - handle_response_invite(p, resp, rest, req, seqno); -+ else if (sipmethod == SIP_SUBSCRIBE) -+ handle_response_subscribe(p, resp, rest, req, seqno); - else if (owner) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); - break; -@@ -16464,12 +17891,12 @@ - else if (sipmethod == SIP_REGISTER) - res = handle_response_register(p, resp, rest, req, seqno); - else if (sipmethod == SIP_BYE) { -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 408 response"); - ast_debug(4, "Got timeout on bye. Thanks for the answer. Now, kill this call\n"); - } else { - if (owner) - ast_queue_control(p->owner, AST_CONTROL_CONGESTION); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 408 response"); - } - break; - -@@ -16484,6 +17911,8 @@ - handle_response_invite(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_REFER) { - handle_response_refer(p, resp, rest, req, seqno); -+ } else if (sipmethod == SIP_SUBSCRIBE) { -+ handle_response_subscribe(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_BYE) { - /* The other side has no transaction to bye, - just assume it's all right then */ -@@ -16509,8 +17938,8 @@ - if (sipmethod == SIP_INVITE) - handle_response_invite(p, resp, rest, req, seqno); - else { -- ast_debug(1, "Got 491 on %s, unspported. Call ID %s\n", sip_methods[sipmethod].text, p->callid); -- p->needdestroy = 1; -+ ast_debug(1, "Got 491 on %s, unsupported. Call ID %s\n", sip_methods[sipmethod].text, p->callid); -+ pvt_set_needdestroy(p, "received 491 response"); - } - break; - case 501: /* Not Implemented */ -@@ -16542,7 +17971,11 @@ - case 301: /* Moved permanently */ - case 302: /* Moved temporarily */ - case 305: /* Use Proxy */ -- parse_moved_contact(p, req); -+ { -+ struct ast_party_redirecting redirecting = {{0,},}; -+ change_redirecting_information(p, req, &redirecting, TRUE); -+ ast_set_redirecting(p->owner, &redirecting); -+ } - /* Fall through */ - case 486: /* Busy here */ - case 600: /* Busy everywhere */ -@@ -16568,6 +18001,9 @@ - if (sipmethod == SIP_REFER) { - handle_response_refer(p, resp, rest, req, seqno); - break; -+ } else if (sipmethod == SIP_SUBSCRIBE) { -+ handle_response_subscribe(p, resp, rest, req, seqno); -+ break; - } - /* Fall through */ - case 502: /* Bad gateway */ -@@ -16587,8 +18023,9 @@ - transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); - if (sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO) - sip_alreadygone(p); -- if (!p->owner) -- p->needdestroy = 1; -+ if (!p->owner) { -+ pvt_set_needdestroy(p, "transaction completed"); -+ } - } else if ((resp >= 100) && (resp < 200)) { - if (sipmethod == SIP_INVITE) { - if (!req->ignore && sip_cancel_destroy(p)) -@@ -16635,23 +18072,22 @@ - ast_log(LOG_WARNING, "Notify answer on an owned channel?\n"); - /* ast_queue_hangup(p->owner); Disabled */ - } else { -- if (!p->subscribed && !p->refer) -- p->needdestroy = 1; -+ if (!p->subscribed && !p->refer) { -+ pvt_set_needdestroy(p, "transaction completed"); -+ } - if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) { - /* Ready to send the next state we have on queue */ - ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE); - cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p); - } - } -- } else if (sipmethod == SIP_BYE) -- p->needdestroy = 1; -- else if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) -+ } else if (sipmethod == SIP_BYE) { -+ pvt_set_needdestroy(p, "transaction completed"); -+ } else if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) { - /* We successfully transmitted a message or - a video update request in INFO */ - ; -- else if (sipmethod == SIP_BYE) -- /* Ok, we're ready to go */ -- p->needdestroy = 1; -+ } - break; - case 202: /* Transfer accepted */ - if (sipmethod == SIP_REFER) -@@ -16666,7 +18102,7 @@ - else if (sipmethod == SIP_BYE) { - if (p->authtries == MAX_AUTHTRIES || do_proxy_auth(p, req, resp, sipmethod, 0)) { - ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From")); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "failed to authenticate BYE"); - } - } - break; -@@ -16675,7 +18111,7 @@ - /* Re-invite failed */ - handle_response_invite(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_BYE) { -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 481 response"); - } else if (sipdebug) { - ast_debug(1, "Remote host can't match request %s to call '%s'. Giving up\n", sip_methods[sipmethod].text, p->callid); - } -@@ -17016,12 +18452,7 @@ - if (sipdebug) - ast_debug(2, "Got NOTIFY Event: %s\n", event); - -- if (strcmp(event, "refer")) { -- /* We don't understand this event. */ -- /* Here's room to implement incoming voicemail notifications :-) */ -- transmit_response(p, "489 Bad event", req); -- res = -1; -- } else { -+ if (!strcmp(event, "refer")) { - /* Save nesting depth for now, since there might be other events we will - support in the future */ - -@@ -17121,8 +18552,34 @@ - - /* Confirm that we received this packet */ - transmit_response(p, "200 OK", req); -- }; -+ } else if (p->mwi && !strcmp(event, "message-summary")) { -+ char *c = ast_strdupa(get_body(req, "Voice-Message", ':')); - -+ if (!ast_strlen_zero(c)) { -+ char *old = strsep(&c, " "); -+ char *new = strsep(&old, "/"); -+ struct ast_event *event; -+ -+ if ((event = ast_event_new(AST_EVENT_MWI, -+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, p->mwi->mailbox, -+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "SIP_Remote", -+ AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(new), -+ AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, atoi(old), -+ AST_EVENT_IE_END))) { -+ ast_event_queue_and_cache(event, -+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, -+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, -+ AST_EVENT_IE_END); -+ } -+ } -+ -+ transmit_response(p, "200 OK", req); -+ } else { -+ /* We don't understand this event. */ -+ transmit_response(p, "489 Bad event", req); -+ res = -1; -+ } -+ - if (!p->lastinvite) - sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); - -@@ -17156,7 +18613,7 @@ - build_contact(p); - - if (ast_strlen_zero(p->context)) -- ast_string_field_set(p, context, default_context); -+ ast_string_field_set(p, context, sip_cfg.default_context); - - if (ast_shutting_down()) - transmit_response_with_allow(p, "503 Unavailable", req, 0); -@@ -17213,7 +18670,7 @@ - /* We should answer something here. If we are here, the - call we are replacing exists, so an accepted - can't harm */ -- transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE); -+ transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE); - /* Do something more clever here */ - ast_channel_unlock(c); - sip_pvt_unlock(p->refer->refer_call); -@@ -17247,7 +18704,7 @@ - Targetcall is not touched by the masq */ - - /* Answer the incoming call and set channel to UP state */ -- transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE); -+ transmit_response_with_sdp(p, "200 OK", req, XMIT_RELIABLE, FALSE, FALSE); - - ast_setstate(c, AST_STATE_UP); - -@@ -17347,19 +18804,32 @@ - */ - static int sip_uri_params_cmp(const char *input1, const char *input2) - { -- char *params1 = ast_strdupa(input1); -- char *params2 = ast_strdupa(input2); -+ char *params1 = NULL; -+ char *params2 = NULL; - char *pos1; - char *pos2; -+ int zerolength1 = 0; -+ int zerolength2 = 0; - int maddrmatch = 0; - int ttlmatch = 0; - int usermatch = 0; - int methodmatch = 0; - -+ if (ast_strlen_zero(input1)) { -+ zerolength1 = 1; -+ } else { -+ params1 = ast_strdupa(input1); -+ } -+ if (ast_strlen_zero(input2)) { -+ zerolength2 = 1; -+ } else { -+ params2 = ast_strdupa(input2); -+ } -+ - /*Quick optimization. If both params are zero-length, then - * they match - */ -- if (ast_strlen_zero(params1) && ast_strlen_zero(params2)) { -+ if (zerolength1 && zerolength2) { - return 0; - } - -@@ -17474,13 +18944,25 @@ - */ - static int sip_uri_headers_cmp(const char *input1, const char *input2) - { -- char *headers1 = ast_strdupa(input1); -- char *headers2 = ast_strdupa(input2); -- int zerolength1 = ast_strlen_zero(headers1); -- int zerolength2 = ast_strlen_zero(headers2); -+ char *headers1 = NULL; -+ char *headers2 = NULL; -+ int zerolength1 = 0; -+ int zerolength2 = 0; - int different = 0; - char *header1; - -+ if (ast_strlen_zero(input1)) { -+ zerolength1 = 1; -+ } else { -+ headers1 = ast_strdupa(input1); -+ } -+ -+ if (ast_strlen_zero(input2)) { -+ zerolength2 = 1; -+ } else { -+ headers2 = ast_strdupa(input2); -+ } -+ - if ((zerolength1 && !zerolength2) || - (zerolength2 && !zerolength1)) - return 1; -@@ -17588,11 +19070,33 @@ - return sip_uri_params_cmp(params1, params2); - } - -+static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context) -+{ -+ struct ast_str *str = ast_str_alloca(AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2); -+ struct ast_app *pickup = pbx_findapp("Pickup"); - --/*! \brief Handle incoming INVITE request --\note If the INVITE has a Replaces header, it is part of an -+ if (!pickup) { -+ ast_log(LOG_ERROR, "Unable to perform pickup: Application 'Pickup' not loaded (app_directed_pickup.so).\n"); -+ return -1; -+ } -+ -+ ast_str_set(&str, 0, "%s@%s", extension, context); -+ -+ ast_debug(2, "About to call Pickup(%s)\n", str->str); -+ -+ /* There is no point in capturing the return value since pickup_exec -+ doesn't return anything meaningful unless the passed data is an empty -+ string (which in our case it will not be) */ -+ pbx_exec(channel, pickup, str->str); -+ -+ return 0; -+} -+ -+/*! -+ * \brief Handle incoming INVITE request -+ * \note If the INVITE has a Replaces header, it is part of an - * attended transfer. If so, we do not go through the dial -- * plan but tries to find the active call and masquerade -+ * plan but try to find the active call and masquerade - * into it - */ - static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock) -@@ -17615,6 +19119,12 @@ - int st_interval = 0; /* Session-Timer negotiated refresh interval */ - enum st_refresher st_ref; /* Session-Timer session refresher */ - int dlg_min_se = -1; -+ struct { -+ char exten[AST_MAX_EXTENSION]; -+ char context[AST_MAX_CONTEXT]; -+ } pickup = { -+ .exten = "", -+ }; - st_ref = SESSION_TIMER_REFRESHER_AUTO; - - /* Find out what they support */ -@@ -17654,7 +19164,7 @@ - int different; - char *initial_rlPart2 = REQ_OFFSET_TO_STR(&p->initreq, rlPart2); - char *this_rlPart2 = REQ_OFFSET_TO_STR(req, rlPart2); -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - different = sip_uri_cmp(initial_rlPart2, this_rlPart2); - else - different = strcmp(initial_rlPart2, this_rlPart2); -@@ -17756,14 +19266,36 @@ - } - } - -- if (sipdebug) -- ast_debug(4, "Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n", replace_id, fromtag ? fromtag : "", totag ? totag : ""); -+ if (sipdebug) -+ ast_debug(4, "Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n", -+ replace_id, -+ fromtag ? fromtag : "", -+ totag ? totag : ""); - -+ /* Try to find call that we are replacing. -+ If we have a Replaces header, we need to cancel that call if we succeed with this call. -+ First we cheat a little and look for a magic call-id from phones that support -+ dialog-info+xml so we can do technology independent pickup... */ -+ if (strncmp(replace_id, "pickup-", 7) == 0) { -+ struct sip_pvt *subscription = NULL; -+ replace_id += 7; /* Worst case we are looking at \0 */ - -- /* Try to find call that we are replacing -- If we have a Replaces header, we need to cancel that call if we succeed with this call -- */ -- if ((p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) { -+ if ((subscription = get_sip_pvt_byid_locked(replace_id, NULL, NULL)) == NULL) { -+ ast_log(LOG_NOTICE, "Unable to find subscription with call-id: %s\n", replace_id); -+ transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req); -+ error = 1; -+ } else { -+ ast_log(LOG_NOTICE, "Trying to pick up %s@%s\n", subscription->exten, subscription->context); -+ ast_copy_string(pickup.exten, subscription->exten, sizeof(pickup.exten)); -+ ast_copy_string(pickup.context, subscription->context, sizeof(pickup.context)); -+ sip_pvt_unlock(subscription); -+ if (subscription->owner) { -+ ast_channel_unlock(subscription->owner); -+ } -+ } -+ } -+ -+ if (!error && ast_strlen_zero(pickup.exten) && (p->refer->refer_call = get_sip_pvt_byid_locked(replace_id, totag, fromtag)) == NULL) { - ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existent call id (%s)!\n", replace_id); - transmit_response_reliable(p, "481 Call Leg Does Not Exist (Replaces)", req); - error = 1; -@@ -17782,7 +19314,7 @@ - error = 1; - } - -- if (!error && !p->refer->refer_call->owner) { -+ if (!error && ast_strlen_zero(pickup.exten) && !p->refer->refer_call->owner) { - /* Oops, someting wrong anyway, no owner, no call */ - ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-existing call id (%s)!\n", replace_id); - /* Check for better return code */ -@@ -17790,7 +19322,7 @@ - error = 1; - } - -- if (!error && p->refer->refer_call->owner->_state != AST_STATE_RINGING && p->refer->refer_call->owner->_state != AST_STATE_RING && p->refer->refer_call->owner->_state != AST_STATE_UP ) { -+ if (!error && ast_strlen_zero(pickup.exten) && p->refer->refer_call->owner->_state != AST_STATE_RINGING && p->refer->refer_call->owner->_state != AST_STATE_RING && p->refer->refer_call->owner->_state != AST_STATE_UP) { - ast_log(LOG_NOTICE, "Supervised transfer attempted to replace non-ringing or active call id (%s)!\n", replace_id); - transmit_response_reliable(p, "603 Declined (Replaces)", req); - error = 1; -@@ -17834,6 +19366,16 @@ - parse_ok_contact(p, req); - } else { /* Re-invite on existing call */ - ast_clear_flag(&p->flags[0], SIP_OUTGOING); /* This is now an inbound dialog */ -+ if (get_rpid(p, req)) { -+ struct ast_party_connected_line connected; -+ -+ ast_party_connected_line_init(&connected); -+ connected.id.number = (char *) p->cid_num; -+ connected.id.name = (char *) p->cid_name; -+ connected.id.number_presentation = p->callingpres; -+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ ast_queue_connected_line_update(p->owner, &connected); -+ } - /* Handle SDP here if we already have an owner */ - if (find_sdp(req)) { - if (process_sdp(p, req, SDP_T38_INITIATE)) { -@@ -17856,6 +19398,7 @@ - if (!p->lastinvite && !req->ignore && !p->owner) { - /* This is a new invite */ - /* Handle authentication if this is our first invite */ -+ struct ast_party_redirecting redirecting = {{0,},}; - res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin); - if (res == AUTH_CHALLENGE_SENT) { - p->invitestate = INV_COMPLETED; /* Needs to restart in another INVITE transaction */ -@@ -17898,7 +19441,7 @@ - - /* Initialize the context if it hasn't been already */ - if (ast_strlen_zero(p->context)) -- ast_string_field_set(p, context, default_context); -+ ast_string_field_set(p, context, sip_cfg.default_context); - - - /* Check number of concurrent calls -vs- incoming limit HERE */ -@@ -17913,7 +19456,7 @@ - return 0; - } - gotdest = get_destination(p, NULL); /* Get destination right away */ -- get_rdnis(p, NULL); /* Get redirect information */ -+ change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */ - extract_uri(p, req); /* Get the Contact URI */ - build_contact(p); /* Build our contact header */ - -@@ -17957,9 +19500,11 @@ - if (c) { - /* Pre-lock the call */ - ast_channel_lock(c); -+ ast_set_redirecting(c, &redirecting); - } - } - } else { -+ struct ast_party_redirecting redirecting = {{0,},}; - if (sipdebug) { - if (!req->ignore) - ast_debug(2, "Got a SIP re-invite for call %s\n", p->callid); -@@ -17969,6 +19514,10 @@ - if (!req->ignore) - reinvite = 1; - c = p->owner; -+ change_redirecting_information(p, req, &redirecting, FALSE); /*Will return immediately if no Diversion header is present */ -+ if (c) { -+ ast_set_redirecting(c, &redirecting); -+ } - } - - /* Session-Timers */ -@@ -18105,10 +19654,28 @@ - p->lastinvite = seqno; - - if (replace_id) { /* Attended transfer or call pickup - we're the target */ -- /* Go and take over the target call */ -- if (sipdebug) -- ast_debug(4, "Sending this call to the invite/replcaes handler %s\n", p->callid); -- return handle_invite_replaces(p, req, debug, seqno, sin); -+ if (!ast_strlen_zero(pickup.exten)) { -+ append_history(p, "Xfer", "INVITE/Replace received"); -+ -+ /* Let the caller know we're giving it a shot */ -+ transmit_response(p, "100 Trying", req); -+ ast_setstate(c, AST_STATE_RING); -+ -+ /* Do the pickup itself */ -+ ast_channel_unlock(c); -+ *nounlock = 1; -+ do_magic_pickup(c, pickup.exten, pickup.context); -+ -+ /* Now we're either masqueraded or we failed to pickup, in either case we... */ -+ ast_hangup(c); -+ -+ return 0; -+ } else { -+ /* Go and take over the target call */ -+ if (sipdebug) -+ ast_debug(4, "Sending this call to the invite/replcaes handler %s\n", p->callid); -+ return handle_invite_replaces(p, req, debug, seqno, sin); -+ } - } - - -@@ -18161,7 +19728,6 @@ - c->hangupcause = AST_CAUSE_CALL_REJECTED; - } else { - sip_pvt_unlock(p); -- ast_setstate(c, AST_STATE_DOWN); - c->hangupcause = AST_CAUSE_NORMAL_CLEARING; - } - p->invitestate = INV_COMPLETED; -@@ -18248,7 +19814,7 @@ - if (sendok) { - /* If this is not a re-invite or something to ignore - it's critical */ - ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); -- transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE); -+ transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE, FALSE); - } - } - p->invitestate = INV_TERMINATED; -@@ -18366,16 +19932,50 @@ - else - ast_clear_flag(&transferer->flags[0], SIP_DEFER_BYE_ON_TRANSFER); - } else { -+ struct ast_party_connected_line connected_caller; -+ - /* Transfer succeeded! */ -+ const char *xfersound = pbx_builtin_getvar_helper(target.chan1, "ATTENDED_TRANSFER_COMPLETE_SOUND"); - - /* Tell transferer that we're done. */ - transmit_notify_with_sipfrag(transferer, seqno, "200 OK", TRUE); - append_history(transferer, "Xfer", "Refer succeeded"); - transferer->refer->status = REFER_200OK; -+ if (target.chan2 && !ast_strlen_zero(xfersound) && ast_streamfile(target.chan2, xfersound, target.chan2->language) >= 0) { -+ ast_waitstream(target.chan2, ""); -+ } - if (targetcall_pvt->owner) { - ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name); - ast_channel_unlock(targetcall_pvt->owner); - } -+ -+ if (target.chan2) { -+ /* Tell each of the other channels to whom they are now connected */ -+ ast_party_connected_line_collect_caller(&connected_caller, ¤t->chan2->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ ast_connected_line_update(target.chan2, &connected_caller); -+ ast_party_connected_line_collect_caller(&connected_caller, &target.chan2->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ ast_connected_line_update(current->chan2, &connected_caller); -+ } else { -+ /* Notify the first other party that they are connected to someone else assuming that target.chan1 -+ has progressed far enough through the dialplan to have it's called party information set. */ -+ if (current->chan2) { -+ connected_caller = target.chan1->connected; -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ ast_connected_line_update(current->chan2, &connected_caller); -+ } -+ -+ /* We can't indicate to the called channel directly so we force the masquerade to complete -+ and queue and update to be read and passed-through */ -+ ast_channel_lock(target.chan1); -+ ast_do_masquerade(target.chan1); -+ ast_channel_unlock(target.chan1); -+ -+ ast_party_connected_line_collect_caller(&connected_caller, &target.chan1->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; -+ ast_queue_connected_line_update(target.chan1, &connected_caller); -+ } - } - if (targetcall_pvt) - ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt"); -@@ -18452,6 +20052,7 @@ - /* Chan2: Call between asterisk and transferee */ - - int res = 0; -+ current.req.data = NULL; - - if (req->debug) - ast_verbose("Call %s got a SIP call transfer from %s: (REFER)!\n", p->callid, ast_test_flag(&p->flags[0], SIP_OUTGOING) ? "callee" : "caller"); -@@ -18464,7 +20065,7 @@ - if (!req->ignore) { - append_history(p, "Xfer", "Refer failed. Outside of dialog."); - sip_alreadygone(p); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "outside of dialog"); - } - return 0; - } -@@ -18524,10 +20125,10 @@ - return 0; - } - if (ast_strlen_zero(p->context)) -- ast_string_field_set(p, context, default_context); -+ ast_string_field_set(p, context, sip_cfg.default_context); - - /* If we do not support SIP domains, all transfers are local */ -- if (allow_external_domains && check_sip_domain(p->refer->refer_to_domain, NULL, 0)) { -+ if (sip_cfg.allow_external_domains && check_sip_domain(p->refer->refer_to_domain, NULL, 0)) { - p->refer->localtransfer = 1; - if (sipdebug) - ast_debug(3, "This SIP transfer is local : %s\n", p->refer->refer_to_domain); -@@ -18957,7 +20558,7 @@ - ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method. Ask vendor to support REFER instead\n", - ast_inet_ntoa(p->recv.sin_addr)); - if (ast_strlen_zero(p->context)) -- ast_string_field_set(p, context, default_context); -+ ast_string_field_set(p, context, sip_cfg.default_context); - res = get_also_info(p, req); - if (!res) { - c = p->owner; -@@ -19015,7 +20616,7 @@ - /*! \brief Handle incoming SUBSCRIBE request */ - static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e) - { -- int gotdest; -+ int gotdest = 0; - int res = 0; - int firststate = AST_EXTENSION_REMOVED; - struct sip_peer *authpeer = NULL; -@@ -19045,9 +20646,9 @@ - /* Check if we have a global disallow setting on subscriptions. - if so, we don't have to check peer settings after auth, which saves a lot of processing - */ -- if (!global_allowsubscribe) { -+ if (!sip_cfg.allowsubscribe) { - transmit_response(p, "403 Forbidden (policy)", req); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "forbidden"); - return 0; - } - -@@ -19060,7 +20661,7 @@ - if (req->debug) - ast_verbose("Received resubscription for a dialog we no longer know about. Telling remote side to subscribe again.\n"); - transmit_response(p, "481 Subscription does not exist", req); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "subscription does not exist"); - return 0; - } - -@@ -19079,7 +20680,7 @@ - if (ast_strlen_zero(eventheader)) { - transmit_response(p, "489 Bad Event", req); - ast_debug(2, "Received SIP subscribe for unknown event package: \n"); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unknown event package in subscribe"); - return 0; - } - -@@ -19104,7 +20705,7 @@ - ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", get_header(req, "From")); - transmit_response_reliable(p, "403 Forbidden", req); - } -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "authentication failed"); - return 0; - } - -@@ -19116,14 +20717,16 @@ - /* Check if this device is allowed to subscribe at all */ - if (!ast_test_flag(&p->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) { - transmit_response(p, "403 Forbidden (policy)", req); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "subscription not allowed"); - if (authpeer) - unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 1)"); - return 0; - } - -- /* Get destination right away */ -- gotdest = get_destination(p, NULL); -+ if (strcmp(event, "message-summary")) { -+ /* Get destination right away */ -+ gotdest = get_destination(p, NULL); -+ } - - /* Get full contact header - this needs to be used as a request URI in NOTIFY's */ - parse_ok_contact(p, req); -@@ -19131,7 +20734,7 @@ - build_contact(p); - if (gotdest) { - transmit_response(p, "404 Not Found", req); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "subscription target not found"); - if (authpeer) - unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 2)"); - return 0; -@@ -19166,7 +20769,7 @@ - - ast_log(LOG_WARNING, "SUBSCRIBE failure: no Accept header: pvt: stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n", - p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "no Accept header"); - return 0; - } - /* if p->subscribed is non-zero, then accept is not obligatory; according to rfc 3265 section 3.1.3, at least. -@@ -19179,7 +20782,7 @@ - - ast_log(LOG_WARNING, "SUBSCRIBE failure: unrecognized format: '%s' pvt: subscribed: %d, stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n", - acceptheader, (int)p->subscribed, p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unrecognized format"); - return 0; - } - } else if (!strcmp(event, "message-summary")) { -@@ -19187,7 +20790,7 @@ - /* Format requested that we do not support */ - transmit_response(p, "406 Not Acceptable", req); - ast_debug(2, "Received SIP mailbox subscription for unknown format: %s\n", acceptheader); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unknown format"); - if (authpeer) - unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 3)"); - return 0; -@@ -19199,7 +20802,7 @@ - */ - if (!authpeer || AST_LIST_EMPTY(&authpeer->mailboxes)) { - transmit_response(p, "404 Not found (no mailbox)", req); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "received 404 response"); - ast_log(LOG_NOTICE, "Received SIP subscribe for peer without mailbox: %s\n", authpeer->name); - if (authpeer) - unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 4)"); -@@ -19226,7 +20829,7 @@ - } else { /* At this point, Asterisk does not understand the specified event */ - transmit_response(p, "489 Bad Event", req); - ast_debug(2, "Received SIP subscribe for unknown event package: %s\n", event); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "unknown event package"); - if (authpeer) - unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 5)"); - return 0; -@@ -19279,7 +20882,7 @@ - - ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_inet_ntoa(p->sa.sin_addr)); - transmit_response(p, "404 Not found", req); -- p->needdestroy = 1; -+ pvt_set_needdestroy(p, "no extension for SUBSCRIBE"); - return 0; - } - ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); -@@ -19313,7 +20916,7 @@ - if (!strcmp(p_old->username, p->username)) { - if (!strcmp(p_old->exten, p->exten) && - !strcmp(p_old->context, p->context)) { -- p_old->needdestroy = 1; -+ pvt_set_needdestroy(p_old, "replacing subscription"); - sip_pvt_unlock(p_old); - ao2_t_ref(p_old, -1, "toss dialog ptr from iterator_next before break"); - break; -@@ -19323,8 +20926,9 @@ - ao2_t_ref(p_old, -1, "toss dialog ptr from iterator_next"); - } - } -- if (!p->expiry) -- p->needdestroy = 1; -+ if (!p->expiry) { -+ pvt_set_needdestroy(p, "forcing expiration"); -+ } - } - return 1; - } -@@ -19415,8 +21019,9 @@ - error = 1; - } - if (error) { -- if (!p->initreq.headers) /* New call */ -- p->needdestroy = 1; /* Make sure we destroy this dialog */ -+ if (!p->initreq.headers) { /* New call */ -+ pvt_set_needdestroy(p, "no headers"); -+ } - return -1; - } - /* Get the command XXX */ -@@ -19439,10 +21044,10 @@ - */ - int ret = 0; - -- if (p->ocseq < seqno && seqno != p->lastnoninvite) { -+ if (p->ocseq < seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) { - ast_debug(1, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq); - ret = -1; -- } else if (p->ocseq != seqno && seqno != p->lastnoninvite) { -+ } else if (p->ocseq != seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) { - /* ignore means "don't do anything with it" but still have to - * respond appropriately. - * But in this case this is a response already, so we really -@@ -19511,7 +21116,7 @@ - } - snprintf(p->lastmsg, sizeof(p->lastmsg), "Rx: %s", cmd); - -- if (pedanticsipchecking) { -+ if (sip_cfg.pedanticsipchecking) { - /* If this is a request packet without a from tag, it's not - correct according to RFC 3261 */ - /* Check if this a new request in a new dialog with a totag already attached to it, -@@ -19587,16 +21192,18 @@ - check_pendings(p); - } - /* Got an ACK that we did not match. Ignore silently */ -- if (!p->lastinvite && ast_strlen_zero(p->randdata)) -- p->needdestroy = 1; -+ if (!p->lastinvite && ast_strlen_zero(p->randdata)) { -+ pvt_set_needdestroy(p, "unmatched ACK"); -+ } - break; - default: - transmit_response_with_allow(p, "501 Method Not Implemented", req, 0); - ast_log(LOG_NOTICE, "Unknown SIP command '%s' from '%s'\n", - cmd, ast_inet_ntoa(p->sa.sin_addr)); - /* If this is some new method, and we don't have a call, destroy it now */ -- if (!p->initreq.headers) -- p->needdestroy = 1; -+ if (!p->initreq.headers) { -+ pvt_set_needdestroy(p, "unimplemented method"); -+ } - break; - } - return res; -@@ -19691,7 +21298,7 @@ - return 0; - } - --/*! \brief Read data from SIP socket -+/*! \brief Read data from SIP UDP socket - \note sipsock_read locks the owner channel while we are processing the SIP message - \return 1 on error, 0 on success - \note Successful messages is connected to SIP call and forwarded to handle_incoming() -@@ -19742,6 +21349,10 @@ - return 1; - } - -+/*! \brief Handle incoming SIP message - request or response -+ -+ This is used for all transports (udp, tcp and tcp/tls) -+*/ - static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin) - { - struct sip_pvt *p; -@@ -19751,10 +21362,10 @@ - - if (sip_debug_test_addr(sin)) /* Set the debug flag early on packet level */ - req->debug = 1; -- if (pedanticsipchecking) -+ if (sip_cfg.pedanticsipchecking) - req->len = lws2sws(req->data->str, req->len); /* Fix multiline headers */ - if (req->debug) { -- ast_verbose("\n<--- SIP read from %s://%s:%d --->\n%s\n<------------->\n", -+ ast_verbose("\n<--- SIP read from %s:%s:%d --->\n%s\n<------------->\n", - get_transport(req->socket.type), ast_inet_ntoa(sin->sin_addr), - ntohs(sin->sin_port), req->data->str); - } -@@ -19889,7 +21500,7 @@ - return tcptls_instance; - } - --/*! \todo document this function. */ -+/*! \todo Get socket for dialog, prepare if needed, and return file handle */ - static int sip_prepare_socket(struct sip_pvt *p) - { - struct sip_socket *s = &p->socket; -@@ -19901,8 +21512,11 @@ - }; - - if (s->fd != -1) -- return s->fd; -+ return s->fd; /* This socket is already active */ - -+ /*! \todo Check this... This might be wrong, depending on the proxy configuration -+ If proxy is in "force" mode its correct. -+ */ - if (p->outboundproxy && p->outboundproxy->transport) { - s->type = p->outboundproxy->transport; - } -@@ -20216,7 +21830,7 @@ - of time since the last time we did it (when MWI is being sent, we can - get back to this point every millisecond or less) - */ -- ao2_t_callback(dialogs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, dialog_needdestroy, &t, -+ ao2_t_callback(dialogs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, dialog_needdestroy, &t, - "callback to remove dialogs w/needdestroy"); - - /* the old methodology would be to restart the search for dialogs to delete with every -@@ -20592,9 +22206,11 @@ - - if (peer->lastms > -1) { - ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Last qualify: %d\n", peer->name, peer->lastms); -+ ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", "-1", SENTINEL); - manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, -1); -- if (global_regextenonqualify) -+ if (sip_cfg.regextenonqualify) { - register_peer_exten(peer, FALSE); -+ } - } - - if (peer->call) { -@@ -20923,7 +22539,7 @@ - */ - if (create_addr(p, host, NULL, 1)) { - *cause = AST_CAUSE_UNREGISTERED; -- ast_debug(3, "Cant create SIP call - target device not registred\n"); -+ ast_debug(3, "Cant create SIP call - target device not registered\n"); - dialog_unlink_all(p, TRUE, TRUE); - dialog_unref(p, "unref dialog p UNREGISTERED"); - /* sip_destroy(p); */ -@@ -20962,7 +22578,7 @@ - p->jointcapability = oldformat; - sip_pvt_lock(p); - tmpc = sip_new(p, AST_STATE_DOWN, host); /* Place the call */ -- if (global_callevents) -+ if (sip_cfg.callevents) - manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", - "Channel: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n", - p->owner? p->owner->name : "", "SIP", p->callid, p->fullcontact, p->peername); -@@ -21016,7 +22632,16 @@ - ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID); - } else if (!strcasecmp(v->name, "sendrpid")) { - ast_set_flag(&mask[0], SIP_SENDRPID); -- ast_set2_flag(&flags[0], ast_true(v->value), SIP_SENDRPID); -+ if (!strcasecmp(v->value, "pai")) { -+ ast_set_flag(&flags[0], SIP_SENDRPID_PAI); -+ } else if (!strcasecmp(v->value, "rpid")) { -+ ast_set_flag(&flags[0], SIP_SENDRPID_RPID); -+ } else if (ast_true(v->value)) { -+ ast_set_flag(&flags[0], SIP_SENDRPID_RPID); -+ } -+ } else if (!strcasecmp(v->name, "rpid_immediate")) { -+ ast_set_flag(&mask[1], SIP_PAGE2_RPID_IMMEDIATE); -+ ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RPID_IMMEDIATE); - } else if (!strcasecmp(v->name, "g726nonstandard")) { - ast_set_flag(&mask[0], SIP_G726_NONSTANDARD); - ast_set2_flag(&flags[0], ast_true(v->value), SIP_G726_NONSTANDARD); -@@ -21104,6 +22729,12 @@ - } else if (!strcasecmp(v->name, "allowsubscribe")) { - ast_set_flag(&mask[1], SIP_PAGE2_ALLOWSUBSCRIBE); - ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_ALLOWSUBSCRIBE); -+ } else if (!strcasecmp(v->name, "ignoresdpversion")) { -+ ast_set_flag(&mask[1], SIP_PAGE2_IGNORESDPVERSION); -+ ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_IGNORESDPVERSION); -+ } else if (!strcasecmp(v->name, "faxdetect")) { -+ ast_set_flag(&mask[1], SIP_PAGE2_FAX_DETECT); -+ ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_FAX_DETECT); - } else if (!strcasecmp(v->name, "t38pt_udptl")) { - ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_UDPTL); - ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_UDPTL); -@@ -21310,13 +22941,14 @@ - peer->socket.type = SIP_TRANSPORT_UDP; - peer->socket.fd = -1; - } -+ peer->type = SIP_TYPE_PEER; - ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY); - ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY); -- strcpy(peer->context, default_context); -- strcpy(peer->subscribecontext, default_subscribecontext); -- strcpy(peer->language, default_language); -- strcpy(peer->mohinterpret, default_mohinterpret); -- strcpy(peer->mohsuggest, default_mohsuggest); -+ ast_string_field_set(peer, context, sip_cfg.default_context); -+ ast_string_field_set(peer, subscribecontext, sip_cfg.default_subscribecontext); -+ ast_string_field_set(peer, language, default_language); -+ ast_string_field_set(peer, mohinterpret, default_mohinterpret); -+ ast_string_field_set(peer, mohsuggest, default_mohsuggest); - peer->addr.sin_family = AF_INET; - peer->defaddr.sin_family = AF_INET; - peer->capability = global_capability; -@@ -21324,19 +22956,20 @@ - peer->rtptimeout = global_rtptimeout; - peer->rtpholdtimeout = global_rtpholdtimeout; - peer->rtpkeepalive = global_rtpkeepalive; -- peer->allowtransfer = global_allowtransfer; -+ peer->allowtransfer = sip_cfg.allowtransfer; - peer->autoframing = global_autoframing; - peer->qualifyfreq = global_qualifyfreq; - if (global_callcounter) - peer->call_limit=999; -- strcpy(peer->vmexten, default_vmexten); -- peer->secret[0] = '\0'; -- peer->md5secret[0] = '\0'; -- peer->cid_num[0] = '\0'; -- peer->cid_name[0] = '\0'; -- peer->fromdomain[0] = '\0'; -- peer->fromuser[0] = '\0'; -- peer->regexten[0] = '\0'; -+ ast_string_field_set(peer, vmexten, default_vmexten); -+ ast_string_field_set(peer, secret, ""); -+ ast_string_field_set(peer, remotesecret, ""); -+ ast_string_field_set(peer, md5secret, ""); -+ ast_string_field_set(peer, cid_num, ""); -+ ast_string_field_set(peer, cid_name, ""); -+ ast_string_field_set(peer, fromdomain, ""); -+ ast_string_field_set(peer, fromuser, ""); -+ ast_string_field_set(peer, regexten, ""); - peer->callgroup = 0; - peer->pickupgroup = 0; - peer->maxms = default_qualify; -@@ -21358,6 +22991,11 @@ - if (!(peer = ao2_t_alloc(sizeof(*peer), sip_destroy_peer_fn, "allocate a peer struct"))) - return NULL; - -+ if (ast_string_field_init(peer, 512)) { -+ ao2_t_ref(peer, -1, "failed to string_field_init, drop peer"); -+ return NULL; -+ } -+ - ast_atomic_fetchadd_int(&apeerobjs, 1); - set_peer_defaults(peer); - -@@ -21432,6 +23070,11 @@ - if (!(peer = ao2_t_alloc(sizeof(*peer), sip_destroy_peer_fn, "allocate a peer struct"))) - return NULL; - -+ if (ast_string_field_init(peer, 512)) { -+ ao2_t_ref(peer, -1, "failed to string_field_init, drop peer"); -+ return NULL; -+ } -+ - if (realtime && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) { - ast_atomic_fetchadd_int(&rpeerobjs, 1); - ast_debug(3, "-REALTIME- peer built. Name: %s. Peer objects: %d\n", name, rpeerobjs); -@@ -21488,6 +23131,8 @@ - } - } else if (realtime && !strcasecmp(v->name, "regseconds")) { - ast_get_time_t(v->value, ®seconds, 0, NULL); -+ } else if (realtime && !strcasecmp(v->name, "lastms")) { -+ sscanf(v->value, "%d", &peer->lastms); - } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) { - inet_aton(v->value, &(peer->addr.sin_addr)); - } else if (realtime && !strcasecmp(v->name, "name")) -@@ -21510,28 +23155,34 @@ - peer->onlymatchonip = FALSE; - peer->type = SIP_TYPE_USER | SIP_TYPE_PEER; - } -- } else if (!strcasecmp(v->name, "secret")) -- ast_copy_string(peer->secret, v->value, sizeof(peer->secret)); -- else if (!strcasecmp(v->name, "md5secret")) -- ast_copy_string(peer->md5secret, v->value, sizeof(peer->md5secret)); -+ } else if (!strcasecmp(v->name, "remotesecret")) { -+ ast_string_field_set(peer, remotesecret, v->value); -+ } else if (!strcasecmp(v->name, "secret")) { -+ ast_string_field_set(peer, secret, v->value); -+ } else if (!strcasecmp(v->name, "md5secret")) -+ ast_string_field_set(peer, md5secret, v->value); - else if (!strcasecmp(v->name, "auth")) - peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno); - else if (!strcasecmp(v->name, "callerid")) { -- ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num)); -+ char cid_name[80] = { '\0' }, cid_num[80] = { '\0' }; -+ -+ ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); -+ ast_string_field_set(peer, cid_name, cid_name); -+ ast_string_field_set(peer, cid_num, cid_num); - } else if (!strcasecmp(v->name, "fullname")) { -- ast_copy_string(peer->cid_name, v->value, sizeof(peer->cid_name)); -+ ast_string_field_set(peer, cid_name, v->value); - } else if (!strcasecmp(v->name, "cid_number")) { -- ast_copy_string(peer->cid_num, v->value, sizeof(peer->cid_num)); -+ ast_string_field_set(peer, cid_num, v->value); - } else if (!strcasecmp(v->name, "context")) { -- ast_copy_string(peer->context, v->value, sizeof(peer->context)); -+ ast_string_field_set(peer, context, v->value); - } else if (!strcasecmp(v->name, "subscribecontext")) { -- ast_copy_string(peer->subscribecontext, v->value, sizeof(peer->subscribecontext)); -+ ast_string_field_set(peer, subscribecontext, v->value); - } else if (!strcasecmp(v->name, "fromdomain")) { -- ast_copy_string(peer->fromdomain, v->value, sizeof(peer->fromdomain)); -+ ast_string_field_set(peer, fromdomain, v->value); - } else if (!strcasecmp(v->name, "usereqphone")) { - ast_set2_flag(&peer->flags[0], ast_true(v->value), SIP_USEREQPHONE); - } else if (!strcasecmp(v->name, "fromuser")) { -- ast_copy_string(peer->fromuser, v->value, sizeof(peer->fromuser)); -+ ast_string_field_set(peer, fromuser, v->value); - } else if (!strcasecmp(v->name, "outboundproxy")) { - char *port, *next, *force, *proxyname; - int forceopt = FALSE; -@@ -21602,7 +23253,7 @@ - if (peer->callingpres == -1) - peer->callingpres = atoi(v->value); - } else if (!strcasecmp(v->name, "username") || !strcmp(v->name, "defaultuser")) { /* "username" is deprecated */ -- ast_copy_string(peer->username, v->value, sizeof(peer->username)); -+ ast_string_field_set(peer, username, v->value); - if (!strcasecmp(v->name, "username")) { - if (deprecation_warning) { - ast_log(LOG_NOTICE, "The 'username' field for sip peers has been deprecated in favor of the term 'defaultuser'\n"); -@@ -21611,9 +23262,9 @@ - peer->deprecated_username = 1; - } - } else if (!strcasecmp(v->name, "language")) { -- ast_copy_string(peer->language, v->value, sizeof(peer->language)); -+ ast_string_field_set(peer, language, v->value); - } else if (!strcasecmp(v->name, "regexten")) { -- ast_copy_string(peer->regexten, v->value, sizeof(peer->regexten)); -+ ast_string_field_set(peer, regexten, v->value); - } else if (!strcasecmp(v->name, "callbackextension")) { - ast_copy_string(callback, v->value, sizeof(callback)); - } else if (!strcasecmp(v->name, "callcounter")) { -@@ -21634,13 +23285,13 @@ - peer->amaflags = format; - } - } else if (!strcasecmp(v->name, "accountcode")) { -- ast_copy_string(peer->accountcode, v->value, sizeof(peer->accountcode)); -+ ast_string_field_set(peer, accountcode, v->value); - } else if (!strcasecmp(v->name, "mohinterpret")) { -- ast_copy_string(peer->mohinterpret, v->value, sizeof(peer->mohinterpret)); -+ ast_string_field_set(peer, mohinterpret, v->value); - } else if (!strcasecmp(v->name, "mohsuggest")) { -- ast_copy_string(peer->mohsuggest, v->value, sizeof(peer->mohsuggest)); -+ ast_string_field_set(peer, mohsuggest, v->value); - } else if (!strcasecmp(v->name, "parkinglot")) { -- ast_copy_string(peer->parkinglot, v->value, sizeof(peer->parkinglot)); -+ ast_string_field_set(peer, parkinglot, v->value); - } else if (!strcasecmp(v->name, "mailbox")) { - add_peer_mailboxes(peer, v->value); - } else if (!strcasecmp(v->name, "hasvoicemail")) { -@@ -21652,7 +23303,7 @@ - } else if (!strcasecmp(v->name, "subscribemwi")) { - ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_SUBSCRIBEMWIONLY); - } else if (!strcasecmp(v->name, "vmexten")) { -- ast_copy_string(peer->vmexten, v->value, sizeof(peer->vmexten)); -+ ast_string_field_set(peer, vmexten, v->value); - } else if (!strcasecmp(v->name, "callgroup")) { - peer->callgroup = ast_get_group(v->value); - } else if (!strcasecmp(v->name, "allowtransfer")) { -@@ -21772,12 +23423,14 @@ - } - - if (!peer->socket.type) { -- peer->transports = SIP_TRANSPORT_UDP; -- peer->socket.type = SIP_TRANSPORT_UDP; -+ /* Set default set of transports */ -+ peer->transports = default_transports; -+ /* Set default primary transport */ -+ peer->socket.type = default_primary_transport; - } - - if (fullcontact->used > 0) { -- ast_copy_string(peer->fullcontact, fullcontact->str, sizeof(peer->fullcontact)); -+ ast_string_field_set(peer, fullcontact, fullcontact->str); - peer->rt_fromcontact = TRUE; - /* We have a hostname in the fullcontact, but if we don't have an - * address listed on the entry (or if it's 'dynamic'), then we need to -@@ -21801,12 +23454,12 @@ - - snprintf(transport, sizeof(transport), "_sip._%s", get_transport(peer->socket.type)); - -- if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, global_srvlookup ? transport : NULL)) { -+ if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup ? transport : NULL)) { - unref_peer(peer, "getting rid of a peer pointer"); - return NULL; - } - -- ast_copy_string(peer->tohost, srvlookup, sizeof(peer->tohost)); -+ ast_string_field_set(peer, tohost, srvlookup); - } - - if (!peer->addr.sin_port) -@@ -21821,13 +23474,21 @@ - if ((nowtime - regseconds) > 0) { - destroy_association(peer); - memset(&peer->addr, 0, sizeof(peer->addr)); -+ peer->lastms = -1; - ast_debug(1, "Bah, we're expired (%d/%d/%d)!\n", (int)(nowtime - regseconds), (int)regseconds, (int)nowtime); - } - } -+ -+ /* Startup regular pokes */ -+ if (realtime && peer->lastms > 0) { -+ ref_peer(peer, "schedule qualify"); -+ sip_poke_peer(peer, 0); -+ } -+ - ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags); - ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags); - if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) -- global_allowsubscribe = TRUE; /* No global ban any more */ -+ sip_cfg.allowsubscribe = TRUE; /* No global ban any more */ - if (!found && peer->host_dynamic && !peer->is_realtime) - reg_source_db(peer); - -@@ -21847,7 +23508,7 @@ - if (!ast_strlen_zero(callback)) { /* build string from peer info */ - char *reg_string; - -- if (asprintf(®_string, "%s:%s@%s/%s", peer->username, peer->secret, peer->tohost, callback) < 0) { -+ if (asprintf(®_string, "%s:%s@%s/%s", peer->username, peer->remotesecret ? peer->remotesecret : peer->secret, peer->tohost, callback) < 0) { - ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); - } else if (reg_string) { - sip_register(reg_string, 0); /* XXX TODO: count in registry_count */ -@@ -21895,14 +23556,29 @@ - return -1; - } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - ucfg = ast_config_load("users.conf", config_flags); -- if (ucfg == CONFIG_STATUS_FILEUNCHANGED) -+ if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { - return 1; -+ } else if (ucfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Contents of users.conf are invalid and cannot be parsed\n"); -+ return 1; -+ } - /* Must reread both files, because one changed */ - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- cfg = ast_config_load(config, config_flags); -+ if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", config); -+ ast_config_destroy(ucfg); -+ return 1; -+ } -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", config); -+ return 1; - } else { - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- ucfg = ast_config_load("users.conf", config_flags); -+ if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Contents of users.conf are invalid and cannot be parsed\n"); -+ ast_config_destroy(cfg); -+ return 1; -+ } - } - - /* Initialize tcp sockets */ -@@ -21947,7 +23623,7 @@ - /* Then, actually destroy users and registry */ - ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy); - ast_debug(4, "--------------- Done destroying registry list\n"); -- ao2_t_callback(peers, OBJ_NODATA, peer_markall_func, 0, "callback to mark all peers"); -+ ao2_t_callback(peers, OBJ_NODATA, peer_markall_func, NULL, "callback to mark all peers"); - } - - /* Reset certificate handling for TLS sessions */ -@@ -21961,6 +23637,7 @@ - default_tls_cfg.cipher = ast_strdup(""); - default_tls_cfg.cafile = ast_strdup(""); - default_tls_cfg.capath = ast_strdup(""); -+ - - /* Initialize copy of current global_regcontext for later use in removing stale contexts */ - ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts)); -@@ -21982,14 +23659,16 @@ - memset(&localaddr, 0, sizeof(localaddr)); - memset(&externip, 0, sizeof(externip)); - memset(&default_prefs, 0 , sizeof(default_prefs)); -- memset(&global_outboundproxy, 0, sizeof(struct sip_proxy)); -- global_outboundproxy.ip.sin_port = htons(STANDARD_SIP_PORT); -- global_outboundproxy.ip.sin_family = AF_INET; /*!< Type of address: IPv4 */ -- global_outboundproxy.force = FALSE; /*!< Don't force proxy usage, use route: headers */ -+ memset(&sip_cfg.outboundproxy, 0, sizeof(struct sip_proxy)); -+ sip_cfg.outboundproxy.ip.sin_port = htons(STANDARD_SIP_PORT); -+ sip_cfg.outboundproxy.ip.sin_family = AF_INET; /*!< Type of address: IPv4 */ -+ sip_cfg.outboundproxy.force = FALSE; /*!< Don't force proxy usage, use route: headers */ -+ default_transports = 0; /*!< Reset default transport to zero here, default value later on */ -+ default_primary_transport = 0; /*!< Reset default primary transport to zero here, default value later on */ - ourport_tcp = STANDARD_SIP_PORT; - ourport_tls = STANDARD_TLS_PORT; - bindaddr.sin_port = htons(STANDARD_SIP_PORT); -- global_srvlookup = DEFAULT_SRVLOOKUP; -+ sip_cfg.srvlookup = DEFAULT_SRVLOOKUP; - global_tos_sip = DEFAULT_TOS_SIP; - global_tos_audio = DEFAULT_TOS_AUDIO; - global_tos_video = DEFAULT_TOS_VIDEO; -@@ -22004,34 +23683,35 @@ - externrefresh = 10; - - /* Reset channel settings to default before re-configuring */ -- allow_external_domains = DEFAULT_ALLOW_EXT_DOM; /* Allow external invites */ -+ sip_cfg.allow_external_domains = DEFAULT_ALLOW_EXT_DOM; /* Allow external invites */ - global_regcontext[0] = '\0'; -- global_regextenonqualify = DEFAULT_REGEXTENONQUALIFY; -- global_notifyringing = DEFAULT_NOTIFYRINGING; -- global_notifyhold = FALSE; /*!< Keep track of hold status for a peer */ -- global_directrtpsetup = FALSE; /* Experimental feature, disabled by default */ -- global_alwaysauthreject = 0; -- global_allowsubscribe = FALSE; -+ sip_cfg.regextenonqualify = DEFAULT_REGEXTENONQUALIFY; -+ sip_cfg.notifyringing = DEFAULT_NOTIFYRINGING; -+ sip_cfg.notifycid = DEFAULT_NOTIFYCID; -+ sip_cfg.notifyhold = FALSE; /*!< Keep track of hold status for a peer */ -+ sip_cfg.directrtpsetup = FALSE; /* Experimental feature, disabled by default */ -+ sip_cfg.alwaysauthreject = DEFAULT_ALWAYSAUTHREJECT; -+ sip_cfg.allowsubscribe = FALSE; - snprintf(global_useragent, sizeof(global_useragent), "%s %s", DEFAULT_USERAGENT, ast_get_version()); - snprintf(global_sdpsession, sizeof(global_sdpsession), "%s %s", DEFAULT_SDPSESSION, ast_get_version()); - snprintf(global_sdpowner, sizeof(global_sdpowner), "%s", DEFAULT_SDPOWNER); - ast_copy_string(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime)); -- ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); -+ ast_copy_string(sip_cfg.realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(sip_cfg.realm)); - ast_copy_string(default_callerid, DEFAULT_CALLERID, sizeof(default_callerid)); -- compactheaders = DEFAULT_COMPACTHEADERS; -+ sip_cfg.compactheaders = DEFAULT_COMPACTHEADERS; - global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; - global_regattempts_max = 0; -- pedanticsipchecking = DEFAULT_PEDANTIC; -- autocreatepeer = DEFAULT_AUTOCREATEPEER; -+ sip_cfg.pedanticsipchecking = DEFAULT_PEDANTIC; -+ sip_cfg.autocreatepeer = DEFAULT_AUTOCREATEPEER; - global_autoframing = 0; -- global_allowguest = DEFAULT_ALLOWGUEST; -+ sip_cfg.allowguest = DEFAULT_ALLOWGUEST; - global_callcounter = DEFAULT_CALLCOUNTER; - global_match_auth_username = FALSE; /*!< Match auth username if available instead of From: Default off. */ - global_rtptimeout = 0; - global_rtpholdtimeout = 0; -- global_rtpkeepalive = 0; -- global_allowtransfer = TRANSFER_OPENFORALL; /* Merrily accept all transfers by default */ -- global_rtautoclear = 120; -+ global_rtpkeepalive = DEFAULT_RTPKEEPALIVE; -+ sip_cfg.allowtransfer = TRANSFER_OPENFORALL; /* Merrily accept all transfers by default */ -+ sip_cfg.rtautoclear = 120; - ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE); /* Default for all devices: TRUE */ - ast_set_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP); /* Default for all devices: TRUE */ - sip_cfg.peer_rtupdate = TRUE; -@@ -22042,9 +23722,13 @@ - global_min_se = DEFAULT_MIN_SE; - global_max_se = DEFAULT_MAX_SE; - -+ /* Peer poking settings */ -+ global_qualify_gap = DEFAULT_QUALIFY_GAP; -+ global_qualify_peers = DEFAULT_QUALIFY_PEERS; -+ - /* Initialize some reasonable defaults at SIP reload (used both for channel and as default for devices */ -- ast_copy_string(default_context, DEFAULT_CONTEXT, sizeof(default_context)); -- default_subscribecontext[0] = '\0'; -+ ast_copy_string(sip_cfg.default_context, DEFAULT_CONTEXT, sizeof(sip_cfg.default_context)); -+ sip_cfg.default_subscribecontext[0] = '\0'; - default_language[0] = '\0'; - default_fromdomain[0] = '\0'; - default_qualify = DEFAULT_QUALIFY; -@@ -22063,20 +23747,22 @@ - - /* Misc settings for the channel */ - global_relaxdtmf = FALSE; -- global_callevents = FALSE; -+ sip_cfg.callevents = DEFAULT_CALLEVENTS; - global_authfailureevents = FALSE; - global_t1 = SIP_TIMER_T1; - global_timer_b = 64 * SIP_TIMER_T1; - global_t1min = DEFAULT_T1MIN; - global_qualifyfreq = DEFAULT_QUALIFYFREQ; - -- global_matchexterniplocally = FALSE; -+ sip_cfg.matchexterniplocally = DEFAULT_MATCHEXTERNIPLOCALLY; - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); - -+ ast_clear_flag(&global_flags[1], SIP_PAGE2_FAX_DETECT); - ast_clear_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_VIDEOSUPPORT_ALWAYS); - ast_clear_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT); -+ ast_clear_flag(&global_flags[1], SIP_PAGE2_IGNORESDPVERSION); - - - /* Read the [general] config section of sip.conf (or from realtime config) */ -@@ -22088,15 +23774,15 @@ - continue; - - if (!strcasecmp(v->name, "context")) { -- ast_copy_string(default_context, v->value, sizeof(default_context)); -+ ast_copy_string(sip_cfg.default_context, v->value, sizeof(sip_cfg.default_context)); - } else if (!strcasecmp(v->name, "subscribecontext")) { -- ast_copy_string(default_subscribecontext, v->value, sizeof(default_subscribecontext)); -+ ast_copy_string(sip_cfg.default_subscribecontext, v->value, sizeof(sip_cfg.default_subscribecontext)); - } else if (!strcasecmp(v->name, "callcounter")) { - global_callcounter = ast_true(v->value) ? 1 : 0; - } else if (!strcasecmp(v->name, "allowguest")) { -- global_allowguest = ast_true(v->value) ? 1 : 0; -+ sip_cfg.allowguest = ast_true(v->value) ? 1 : 0; - } else if (!strcasecmp(v->name, "realm")) { -- ast_copy_string(global_realm, v->value, sizeof(global_realm)); -+ ast_copy_string(sip_cfg.realm, v->value, sizeof(sip_cfg.realm)); - } else if (!strcasecmp(v->name, "useragent")) { - ast_copy_string(global_useragent, v->value, sizeof(global_useragent)); - ast_debug(1, "Setting SIP channel User-Agent Name to %s\n", global_useragent); -@@ -22109,7 +23795,7 @@ - else - ast_log(LOG_WARNING, "'%s' must not contain spaces at line %d. Using default.\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "allowtransfer")) { -- global_allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED; -+ sip_cfg.allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED; - } else if (!strcasecmp(v->name, "rtcachefriends")) { - ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS); - } else if (!strcasecmp(v->name, "rtsavesysname")) { -@@ -22127,6 +23813,25 @@ - global_timer_b = global_t1 * 64; - } else if (!strcasecmp(v->name, "t1min")) { - global_t1min = atoi(v->value); -+ } else if (!strcasecmp(v->name, "transport") && !ast_strlen_zero(v->value)) { -+ char *val = ast_strdupa(v->value); -+ char *trans; -+ -+ while ((trans = strsep(&val, ","))) { -+ trans = ast_skip_blanks(trans); -+ -+ if (!strncasecmp(trans, "udp", 3)) -+ default_transports |= SIP_TRANSPORT_UDP; -+ else if (!strncasecmp(trans, "tcp", 3)) -+ default_transports |= SIP_TRANSPORT_TCP; -+ else if (!strncasecmp(trans, "tls", 3)) -+ default_transports |= SIP_TRANSPORT_TLS; -+ else -+ ast_log(LOG_NOTICE, "'%s' is not a valid transport type. if no other is specified, udp will be used.\n", trans); -+ if (default_primary_transport == 0) { -+ default_primary_transport = default_transports; -+ } -+ } - } else if (!strcasecmp(v->name, "tcpenable")) { - sip_tcp_desc.local_address.sin_family = ast_false(v->value) ? 0 : AF_INET; - ast_debug(2, "Enabling TCP socket for listening\n"); -@@ -22169,7 +23874,7 @@ - } else if (!strcasecmp(v->name, "rtautoclear")) { - int i = atoi(v->value); - if (i > 0) -- global_rtautoclear = i; -+ sip_cfg.rtautoclear = i; - else - i = 0; - ast_set2_flag(&global_flags[1], i || ast_true(v->value), SIP_PAGE2_RTAUTOCLEAR); -@@ -22192,20 +23897,26 @@ - } else if (!strcasecmp(v->name, "rtpkeepalive")) { - if ((sscanf(v->value, "%d", &global_rtpkeepalive) != 1) || (global_rtpkeepalive < 0)) { - ast_log(LOG_WARNING, "'%s' is not a valid RTP keepalive time at line %d. Using default.\n", v->value, v->lineno); -- global_rtpkeepalive = 0; -+ global_rtpkeepalive = DEFAULT_RTPKEEPALIVE; - } - } else if (!strcasecmp(v->name, "compactheaders")) { -- compactheaders = ast_true(v->value); -+ sip_cfg.compactheaders = ast_true(v->value); - } else if (!strcasecmp(v->name, "notifymimetype")) { - ast_copy_string(default_notifymime, v->value, sizeof(default_notifymime)); - } else if (!strcasecmp(v->name, "directrtpsetup")) { -- global_directrtpsetup = ast_true(v->value); -+ sip_cfg.directrtpsetup = ast_true(v->value); - } else if (!strcasecmp(v->name, "notifyringing")) { -- global_notifyringing = ast_true(v->value); -+ sip_cfg.notifyringing = ast_true(v->value); - } else if (!strcasecmp(v->name, "notifyhold")) { -- global_notifyhold = ast_true(v->value); -+ sip_cfg.notifyhold = ast_true(v->value); -+ } else if (!strcasecmp(v->name, "notifycid")) { -+ if (!strcasecmp(v->value, "ignore-context")) { -+ sip_cfg.notifycid = IGNORE_CONTEXT; -+ } else { -+ sip_cfg.notifycid = ast_true(v->value); -+ } - } else if (!strcasecmp(v->name, "alwaysauthreject")) { -- global_alwaysauthreject = ast_true(v->value); -+ sip_cfg.alwaysauthreject = ast_true(v->value); - } else if (!strcasecmp(v->name, "mohinterpret")) { - ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret)); - } else if (!strcasecmp(v->name, "mohsuggest")) { -@@ -22224,7 +23935,7 @@ - } - ast_copy_string(global_regcontext, v->value, sizeof(global_regcontext)); - } else if (!strcasecmp(v->name, "regextenonqualify")) { -- global_regextenonqualify = ast_true(v->value); -+ sip_cfg.regextenonqualify = ast_true(v->value); - } else if (!strcasecmp(v->name, "callerid")) { - ast_copy_string(default_callerid, v->value, sizeof(default_callerid)); - } else if (!strcasecmp(v->name, "fromdomain")) { -@@ -22240,33 +23951,33 @@ - - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - -- sip_parse_host(tok, v->lineno, &proxyname, &portnum, &global_outboundproxy.transport); -+ sip_parse_host(tok, v->lineno, &proxyname, &portnum, &sip_cfg.outboundproxy.transport); - -- global_outboundproxy.ip.sin_port = htons(portnum); -+ sip_cfg.outboundproxy.ip.sin_port = htons(portnum); - - if ((tok = strtok(NULL, ","))) { -- global_outboundproxy.force = !strncasecmp(ast_skip_blanks(tok), "force", 5); -+ sip_cfg.outboundproxy.force = !strncasecmp(ast_skip_blanks(tok), "force", 5); - } else { -- global_outboundproxy.force = FALSE; -+ sip_cfg.outboundproxy.force = FALSE; - } - - if (ast_strlen_zero(proxyname)) { - ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf.", v->lineno); -- global_outboundproxy.name[0] = '\0'; -+ sip_cfg.outboundproxy.name[0] = '\0'; - continue; - } - -- ast_copy_string(global_outboundproxy.name, proxyname, sizeof(global_outboundproxy.name)); -+ ast_copy_string(sip_cfg.outboundproxy.name, proxyname, sizeof(sip_cfg.outboundproxy.name)); - -- proxy_update(&global_outboundproxy); -+ proxy_update(&sip_cfg.outboundproxy); - } else if (!strcasecmp(v->name, "autocreatepeer")) { -- autocreatepeer = ast_true(v->value); -+ sip_cfg.autocreatepeer = ast_true(v->value); - } else if (!strcasecmp(v->name, "match_auth_username")) { - global_match_auth_username = ast_true(v->value); - } else if (!strcasecmp(v->name, "srvlookup")) { -- global_srvlookup = ast_true(v->value); -+ sip_cfg.srvlookup = ast_true(v->value); - } else if (!strcasecmp(v->name, "pedantic")) { -- pedanticsipchecking = ast_true(v->value); -+ sip_cfg.pedanticsipchecking = ast_true(v->value); - } else if (!strcasecmp(v->name, "maxexpirey") || !strcasecmp(v->name, "maxexpiry")) { - max_expiry = atoi(v->value); - if (max_expiry < 1) -@@ -22279,6 +23990,10 @@ - default_expiry = atoi(v->value); - if (default_expiry < 1) - default_expiry = DEFAULT_DEFAULT_EXPIRY; -+ } else if (!strcasecmp(v->name, "mwiexpiry") || !strcasecmp(v->name, "mwiexpirey")) { -+ mwi_expiry = atoi(v->value); -+ if (mwi_expiry < 1) -+ mwi_expiry = DEFAULT_MWI_EXPIRY; - } else if (!strcasecmp(v->name, "sipdebug")) { - if (ast_true(v->value)) - sipdebug |= sip_debug_config; -@@ -22341,7 +24056,7 @@ - } else if (!strcasecmp(v->name, "autoframing")) { - global_autoframing = ast_true(v->value); - } else if (!strcasecmp(v->name, "allowexternaldomains")) { -- allow_external_domains = ast_true(v->value); -+ sip_cfg.allow_external_domains = ast_true(v->value); - } else if (!strcasecmp(v->name, "autodomain")) { - auto_sip_domains = ast_true(v->value); - } else if (!strcasecmp(v->name, "domain")) { -@@ -22360,6 +24075,8 @@ - } else if (!strcasecmp(v->name, "register")) { - if (sip_register(v->value, v->lineno) == 0) - registry_count++; -+ } else if (!strcasecmp(v->name, "mwi")) { -+ sip_subscribe_mwi(v->value, v->lineno); - } else if (!strcasecmp(v->name, "tos_sip")) { - if (ast_str2tos(v->value, &global_tos_sip)) - ast_log(LOG_WARNING, "Invalid tos_sip value at line %d, refer to QoS documentation\n", v->lineno); -@@ -22430,7 +24147,7 @@ - global_qualifyfreq = DEFAULT_QUALIFYFREQ; - } - } else if (!strcasecmp(v->name, "callevents")) { -- global_callevents = ast_true(v->value); -+ sip_cfg.callevents = ast_true(v->value); - } else if (!strcasecmp(v->name, "authfailureevents")) { - global_authfailureevents = ast_true(v->value); - } else if (!strcasecmp(v->name, "maxcallbitrate")) { -@@ -22438,7 +24155,7 @@ - if (default_maxcallbitrate < 0) - default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE; - } else if (!strcasecmp(v->name, "matchexterniplocally")) { -- global_matchexterniplocally = ast_true(v->value); -+ sip_cfg.matchexterniplocally = ast_true(v->value); - } else if (!strcasecmp(v->name, "session-timers")) { - int i = (int) str2stmode(v->value); - if (i < 0) { -@@ -22469,13 +24186,27 @@ - } else { - global_st_refresher = i; - } -+ } else if (!strcasecmp(v->name, "qualifygap")) { -+ if (sscanf(v->value, "%d", &global_qualify_gap) != 1) { -+ ast_log(LOG_WARNING, "Invalid qualifygap '%s' at line %d of %s\n", v->value, v->lineno, config); -+ global_qualify_gap = DEFAULT_QUALIFY_GAP; -+ } -+ } else if (!strcasecmp(v->name, "qualifypeers")) { -+ if (sscanf(v->value, "%d", &global_qualify_peers) != 1) { -+ ast_log(LOG_WARNING, "Invalid pokepeers '%s' at line %d of %s\n", v->value, v->lineno, config); -+ global_qualify_peers = DEFAULT_QUALIFY_PEERS; -+ } - } - } - -- if (!allow_external_domains && AST_LIST_EMPTY(&domain_list)) { -+ if (!sip_cfg.allow_external_domains && AST_LIST_EMPTY(&domain_list)) { - ast_log(LOG_WARNING, "To disallow external domains, you need to configure local SIP domains.\n"); -- allow_external_domains = 1; -+ sip_cfg.allow_external_domains = 1; - } -+ /* If not configured, set default transports */ -+ if (default_transports == 0) { -+ default_transports = default_primary_transport = SIP_TRANSPORT_UDP; -+ } - - /* Build list of authentication to various SIP realms, i.e. service providers */ - for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) { -@@ -22629,13 +24360,24 @@ - - /* Start TCP server */ - ast_tcptls_server_start(&sip_tcp_desc); -+ if (sip_tcp_desc.accept_fd == -1 && sip_tcp_desc.local_address.sin_family == AF_INET) { -+ /* TCP server start failed. Tell the admin */ -+ ast_log(LOG_ERROR, "SIP TCP Server start failed. Not listening on TCP socket.\n"); -+ sip_tcp_desc.local_address.sin_family = 0; -+ } else { -+ ast_debug(2, "SIP TCP server started\n"); -+ } - - /* Start TLS server if needed */ - memcpy(sip_tls_desc.tls_cfg, &default_tls_cfg, sizeof(default_tls_cfg)); - -- if (ast_ssl_setup(sip_tls_desc.tls_cfg)) -+ if (ast_ssl_setup(sip_tls_desc.tls_cfg)) { - ast_tcptls_server_start(&sip_tls_desc); -- else if (sip_tls_desc.tls_cfg->enabled) { -+ if (default_tls_cfg.enabled && sip_tls_desc.accept_fd == -1) { -+ ast_log(LOG_ERROR, "TLS Server start failed. Not listening on TLS socket.\n"); -+ sip_tls_desc.tls_cfg = NULL; -+ } -+ } else if (sip_tls_desc.tls_cfg->enabled) { - sip_tls_desc.tls_cfg = NULL; - ast_log(LOG_WARNING, "SIP TLS server did not load because of errors.\n"); - } -@@ -22682,7 +24424,10 @@ - /* Load the list of manual NOTIFY types to support */ - if (notify_types) - ast_config_destroy(notify_types); -- notify_types = ast_config_load(notify_config, config_flags); -+ if ((notify_types = ast_config_load(notify_config, config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed.\n", notify_config); -+ notify_types = NULL; -+ } - - /* Done, tell the manager */ - manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count); -@@ -22903,7 +24648,7 @@ - return -1; - - /* Disable early RTP bridge */ -- if (chan->_state != AST_STATE_UP && !global_directrtpsetup) /* We are in early state */ -+ if (chan->_state != AST_STATE_UP && !sip_cfg.directrtpsetup) /* We are in early state */ - return 0; - - sip_pvt_lock(p); -@@ -22963,22 +24708,10 @@ - return 0; - } - --static char *synopsis_dtmfmode = "Change the dtmfmode for a SIP call"; --static char *descrip_dtmfmode = " SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call\n"; - static char *app_dtmfmode = "SIPDtmfMode"; -- - static char *app_sipaddheader = "SIPAddHeader"; --static char *synopsis_sipaddheader = "Add a SIP header to the outbound call"; -+static char *app_sipremoveheader = "SIPRemoveHeader"; - --static char *descrip_sipaddheader = "" --" SIPAddHeader(Header: Content):\n" --"Adds a header to a SIP call placed with DIAL.\n" --"Remember to user the X-header if you are adding non-standard SIP\n" --"headers, like \"X-Asterisk-Accountcode:\". Use this with care.\n" --"Adding the wrong headers may jeopardize the SIP dialog.\n" --"Always returns 0\n"; -- -- - /*! \brief Set the DTMFmode for an outbound SIP call (application) */ - static int sip_dtmfmode(struct ast_channel *chan, void *data) - { -@@ -23076,6 +24809,38 @@ - return 0; - } - -+/*! \brief Remove SIP headers added previously with SipAddHeader application */ -+static int sip_removeheader(struct ast_channel *chan, void *data) -+{ -+ struct ast_var_t *newvariable; -+ struct varshead *headp; -+ int removeall = 0; -+ char *inbuf = (char *) data; -+ -+ if (ast_strlen_zero(inbuf)) { -+ removeall = 1; -+ } -+ ast_channel_lock(chan); -+ -+ headp=&chan->varshead; -+ AST_LIST_TRAVERSE_SAFE_BEGIN (headp, newvariable, entries) { -+ if (strncasecmp(ast_var_name(newvariable), "SIPADDHEADER", strlen("SIPADDHEADER")) == 0) { -+ if (removeall || (!strncasecmp(ast_var_value(newvariable),inbuf,strlen(inbuf)))) { -+ if (sipdebug) -+ ast_log(LOG_DEBUG,"removing SIP Header \"%s\" as %s\n", -+ ast_var_value(newvariable), -+ ast_var_name(newvariable)); -+ AST_LIST_REMOVE_CURRENT(entries); -+ ast_var_delete(newvariable); -+ } -+ } -+ } -+ AST_LIST_TRAVERSE_SAFE_END; -+ -+ ast_channel_unlock(chan); -+ return 0; -+} -+ - /*! \brief Transfer call before connect with a 302 redirect - \note Called by the transfer() dialplan application through the sip_transfer() - pbx interface function if the call is in ringing state -@@ -23143,13 +24908,10 @@ - return p->jointcapability ? p->jointcapability : p->capability; - } - --/*! \brief Send a poke to all known peers -- Space them out 100 ms apart -- XXX We might have a cool algorithm for this or use random - any suggestions? --*/ -+/*! \brief Send a poke to all known peers */ - static void sip_poke_all_peers(void) - { -- int ms = 0; -+ int ms = 0, num = 0; - struct ao2_iterator i; - struct sip_peer *peer; - -@@ -23160,7 +24922,12 @@ - - while ((peer = ao2_t_iterator_next(&i, "iterate thru peers table"))) { - ao2_lock(peer); -- ms += 100; -+ if (num == global_qualify_peers) { -+ ms += global_qualify_gap; -+ num = 0; -+ } else { -+ num++; -+ } - AST_SCHED_REPLACE_UNREF(peer->pokeexpire, sched, ms, sip_poke_peer_s, peer, - unref_peer(_data, "removing poke peer ref"), - unref_peer(peer, "removing poke peer ref"), -@@ -23193,6 +24960,19 @@ - ); - } - -+/*! \brief Send all MWI subscriptions */ -+static void sip_send_all_mwi_subscriptions(void) -+{ -+ ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do { -+ ASTOBJ_WRLOCK(iterator); -+ AST_SCHED_DEL(sched, iterator->resub); -+ if ((iterator->resub = ast_sched_add(sched, 1, sip_subscribe_mwi_do, ASTOBJ_REF(iterator))) < 0) { -+ ASTOBJ_UNREF(iterator, sip_subscribe_mwi_destroy); -+ } -+ ASTOBJ_UNLOCK(iterator); -+ } while (0)); -+} -+ - /*! \brief Reload module */ - static int sip_do_reload(enum channelreloadreason reason) - { -@@ -23203,7 +24983,7 @@ - - start_poke = time(0); - /* Prune peers who still are supposed to be deleted */ -- ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, 0, -+ ao2_t_callback(peers, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, peer_is_marked, NULL, - "callback to remove marked peers"); - - ast_debug(4, "--------------- Done destroying pruned peers\n"); -@@ -23213,6 +24993,9 @@ - - /* Register with all services */ - sip_send_all_registers(); -+ -+ sip_send_all_mwi_subscriptions(); -+ - end_poke = time(0); - - ast_debug(4, "do_reload finished. peer poke/prune reg contact time = %d sec.\n", (int)(end_poke-start_poke)); -@@ -23258,7 +25041,6 @@ - return 1; - } - --static struct ast_cli_entry cli_sip_do_history_deprecated = AST_CLI_DEFINE(sip_do_history_deprecated, "Enable/Disable SIP history"); - /*! \brief SIP Cli commands definition */ - static struct ast_cli_entry cli_sip[] = { - AST_CLI_DEFINE(sip_show_channels, "List active SIP channels or subscriptions"), -@@ -23270,6 +25052,7 @@ - AST_CLI_DEFINE(sip_show_registry, "List SIP registration status"), - AST_CLI_DEFINE(sip_unregister, "Unregister (force expiration) a SIP peer from the registry"), - AST_CLI_DEFINE(sip_show_settings, "Show SIP global settings"), -+ AST_CLI_DEFINE(sip_show_mwi, "Show MWI subscriptions"), - AST_CLI_DEFINE(sip_cli_notify, "Send a notify packet to a SIP peer"), - AST_CLI_DEFINE(sip_show_channel, "Show detailed SIP channel info"), - AST_CLI_DEFINE(sip_show_history, "Show SIP dialog history"), -@@ -23280,7 +25063,7 @@ - AST_CLI_DEFINE(sip_show_sched, "Present a report on the status of the sched queue"), - AST_CLI_DEFINE(sip_prune_realtime, "Prune cached Realtime users/peers"), - AST_CLI_DEFINE(sip_do_debug, "Enable/Disable SIP debugging"), -- AST_CLI_DEFINE(sip_set_history, "Enable/Disable SIP history", .deprecate_cmd = &cli_sip_do_history_deprecated), -+ AST_CLI_DEFINE(sip_set_history, "Enable/Disable SIP history"), - AST_CLI_DEFINE(sip_reload, "Reload SIP configuration"), - AST_CLI_DEFINE(sip_show_tcp, "List TCP Connections") - }; -@@ -23296,6 +25079,7 @@ - dialogs = ao2_t_container_alloc(hash_dialog_size, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs"); - - ASTOBJ_CONTAINER_INIT(®l); /* Registry object list -- not searched for anything */ -+ ASTOBJ_CONTAINER_INIT(&submwil); /* MWI subscription object list */ - - if (!(sched = sched_context_create())) { - ast_log(LOG_ERROR, "Unable to create scheduler context\n"); -@@ -23329,7 +25113,7 @@ - } - - /* Register all CLI functions for SIP */ -- ast_cli_register_multiple(cli_sip, sizeof(cli_sip)/ sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_sip, ARRAY_LEN(cli_sip)); - - /* Tell the RTP subdriver that we're here */ - ast_rtp_proto_register(&sip_rtp); -@@ -23338,8 +25122,9 @@ - ast_udptl_proto_register(&sip_udptl); - - /* Register dialplan applications */ -- ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode); -- ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader); -+ ast_register_application_xml(app_dtmfmode, sip_dtmfmode); -+ ast_register_application_xml(app_sipaddheader, sip_addheader); -+ ast_register_application_xml(app_sipremoveheader, sip_removeheader); - - /* Register dialplan functions */ - ast_custom_function_register(&sip_header_function); -@@ -23360,7 +25145,8 @@ - "Send a SIP notify", mandescr_sipnotify); - sip_poke_all_peers(); - sip_send_all_registers(); -- -+ sip_send_all_mwi_subscriptions(); -+ - /* And start the monitor for the first time */ - restart_monitor(); - -@@ -23400,9 +25186,10 @@ - /* Unregister dial plan applications */ - ast_unregister_application(app_dtmfmode); - ast_unregister_application(app_sipaddheader); -+ ast_unregister_application(app_sipremoveheader); - - /* Unregister CLI commands */ -- ast_cli_unregister_multiple(cli_sip, sizeof(cli_sip) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_sip, ARRAY_LEN(cli_sip)); - - /* Disconnect from the RTP subsystem */ - ast_rtp_proto_unregister(&sip_rtp); -@@ -23477,6 +25264,8 @@ - - ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy); - ASTOBJ_CONTAINER_DESTROY(®l); -+ ASTOBJ_CONTAINER_DESTROYALL(&submwil, sip_subscribe_mwi_destroy); -+ ASTOBJ_CONTAINER_DESTROY(&submwil); - - ao2_t_ref(peers, -1, "unref the peers table"); - ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table"); -Index: channels/chan_agent.c -=================================================================== ---- a/channels/chan_agent.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_agent.c (.../team/group/issue14292) (revision 178988) -@@ -69,40 +69,113 @@ - #include "asterisk/stringfields.h" - #include "asterisk/event.h" - -+/*** DOCUMENTATION -+ -+ -+ Call agent login. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Asks the agent to login to the system. Always returns -1. -+ While logged in, the agent can receive calls and will hear a beep -+ when a new call comes in. The agent can dump the call by pressing the star key. -+ -+ -+ Queue -+ AddQueueMember -+ RemoveQueueMember -+ PauseQueueMember -+ UnpauseQueueMember -+ AGENT -+ agents.conf -+ queues.conf -+ -+ -+ -+ -+ Record agent's outgoing call. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Tries to figure out the id of the agent who is placing outgoing call based on -+ comparison of the callerid of the current interface and the global variable -+ placed by the AgentCallbackLogin application. That's why it should be used only -+ with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent -+ instead of Monitor application. That has to be configured in the -+ agents.conf file. -+ Normally the app returns 0 unless the options are passed. -+ -+ -+ agents.conf -+ -+ -+ -+ -+ Gets information about an Agent -+ -+ -+ -+ -+ The valid items to retrieve are: -+ -+ -+ (default) The status of the agent (LOGGEDIN | LOGGEDOUT) -+ -+ -+ The password of the agent -+ -+ -+ The name of the agent -+ -+ -+ MusicOnHold class -+ -+ -+ The callback extension for the Agent (AgentCallbackLogin) -+ -+ -+ The name of the active channel for the Agent (AgentLogin) -+ -+ -+ -+ -+ -+ -+ ***/ -+ - static const char tdesc[] = "Call Agent Proxy Channel"; - static const char config[] = "agents.conf"; - - static const char app[] = "AgentLogin"; - static const char app3[] = "AgentMonitorOutgoing"; - --static const char synopsis[] = "Call agent login"; --static const char synopsis3[] = "Record agent's outgoing call"; -- --static const char descrip[] = --" AgentLogin([AgentNo][,options]):\n" --"Asks the agent to login to the system. Always returns -1. While\n" --"logged in, the agent can receive calls and will hear a 'beep'\n" --"when a new call comes in. The agent can dump the call by pressing\n" --"the star key.\n" --"The option string may contain zero or more of the following characters:\n" --" 's' -- silent login - do not announce the login ok segment after agent logged on/off\n"; -- --static const char descrip3[] = --" AgentMonitorOutgoing([options]):\n" --"Tries to figure out the id of the agent who is placing outgoing call based on\n" --"comparison of the callerid of the current interface and the global variable \n" --"placed by the AgentCallbackLogin application. That's why it should be used only\n" --"with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n" --"instead of Monitor application. That has to be configured in the agents.conf file.\n" --"\nReturn value:\n" --"Normally the app returns 0 unless the options are passed.\n" --"\nOptions:\n" --" 'd' - make the app return -1 if there is an error condition\n" --" 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n" --" 'n' - don't generate the warnings when there is no callerid or the\n" --" agentid is not known.\n" --" It's handy if you want to have one context for agent and non-agent calls.\n"; -- - static const char mandescr_agents[] = - "Description: Will list info about all possible agents.\n" - "Variables: NONE\n"; -@@ -685,8 +758,7 @@ - time(&p->start); - /* Call on this agent */ - ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); -- ast_set_callerid(p->chan, -- ast->cid.cid_num, ast->cid.cid_name, NULL); -+ ast_set_connected_line(p->chan, &ast->connected); - ast_channel_inherit_variables(ast, p->chan); - res = ast_call(p->chan, p->loginchan, 0); - CLEANUP(ast,p); -@@ -1092,8 +1164,21 @@ - if (!cfg) { - ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); - return 0; -- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) -+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - return -1; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config); -+ return 0; -+ } -+ if ((ucfg = ast_config_load("users.conf", config_flags))) { -+ if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { -+ ucfg = NULL; -+ } else if (ucfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n"); -+ return 0; -+ } -+ } -+ - AST_LIST_LOCK(&agents); - AST_LIST_TRAVERSE(&agents, p, list) { - p->dead = 1; -@@ -1183,7 +1268,7 @@ - } - v = v->next; - } -- if ((ucfg = ast_config_load("users.conf", config_flags)) && ucfg != CONFIG_STATUS_FILEUNCHANGED) { -+ if (ucfg) { - genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); - catname = ast_category_browse(ucfg, NULL); - while(catname) { -@@ -2434,17 +2519,7 @@ - - struct ast_custom_function agent_function = { - .name = "AGENT", -- .synopsis = "Gets information about an Agent", -- .syntax = "AGENT([:item])", - .read = function_agent, -- .desc = "The valid items to retrieve are:\n" -- "- status (default) The status of the agent\n" -- " LOGGEDIN | LOGGEDOUT\n" -- "- password The password of the agent\n" -- "- name The name of the agent\n" -- "- mohclass MusicOnHold class\n" -- "- exten The callback extension for the Agent (AgentCallbackLogin)\n" -- "- channel The name of the active channel for the Agent (AgentLogin)\n" - }; - - -@@ -2468,15 +2543,15 @@ - if (persistent_agents) - reload_agents(); - /* Dialplan applications */ -- ast_register_application(app, login_exec, synopsis, descrip); -- ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); -+ ast_register_application_xml(app, login_exec); -+ ast_register_application_xml(app3, agentmonitoroutgoing_exec); - - /* Manager commands */ - ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); - ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); - - /* CLI Commands */ -- ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents)); - - /* Dialplan Functions */ - ast_custom_function_register(&agent_function); -@@ -2501,7 +2576,7 @@ - /* Unregister dialplan functions */ - ast_custom_function_unregister(&agent_function); - /* Unregister CLI commands */ -- ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents)); - /* Unregister dialplan applications */ - ast_unregister_application(app); - ast_unregister_application(app3); -Index: channels/iax2-provision.c -=================================================================== ---- a/channels/iax2-provision.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/iax2-provision.c (.../team/group/issue14292) (revision 178988) -@@ -530,7 +530,7 @@ - iax_provision_init(); - - cfg = ast_config_load2("iaxprov.conf", "chan_iax2", config_flags); -- if (cfg != NULL && cfg != CONFIG_STATUS_FILEUNCHANGED) { -+ if (cfg != NULL && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) { - /* Mark all as dead. No need for locking */ - AST_LIST_TRAVERSE(&templates, cur, list) { - cur->dead = 1; -Index: channels/chan_console.c -=================================================================== ---- a/channels/chan_console.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_console.c (.../team/group/issue14292) (revision 178988) -@@ -694,9 +694,9 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "console set autoanswer [on|off]"; -+ e->command = "console {set|show} autoanswer [on|off]"; - e->usage = -- "Usage: console set autoanswer [on|off]\n" -+ "Usage: console {set|show} autoanswer [on|off]\n" - " Enables or disables autoanswer feature. If used without\n" - " argument, displays the current on/off status of autoanswer.\n" - " The default value of autoanswer is in 'oss.conf'.\n"; -@@ -1154,12 +1154,10 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "console active"; -+ e->command = "console {set|show} active []"; - e->usage = -- "Usage: console active [device]\n" -- " If no device is specified. The active console device will be shown.\n" -- "Otherwise, the specified device will become the console device active for\n" -- "the Asterisk CLI.\n"; -+ "Usage: console {set|show} active []\n" -+ " Set or show the active console device for the Asterisk CLI.\n"; - return NULL; - case CLI_GENERATE: - if (a->pos == e->args) { -@@ -1181,7 +1179,7 @@ - if (a->argc < e->args) - return CLI_SHOWUSAGE; - -- if (a->argc == e->args) { -+ if (a->argc == 3) { - pvt = get_active_pvt(); - - if (!pvt) -@@ -1400,6 +1398,9 @@ - if (!(cfg = ast_config_load(config_file, config_flags))) { - ast_log(LOG_NOTICE, "Unable to open configuration file %s!\n", config_file); - return -1; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_NOTICE, "Config file %s has an invalid format\n", config_file); -+ return -1; - } - - ao2_callback(pvts, OBJ_NODATA, pvt_mark_destroy_cb, NULL); -Index: channels/Makefile -=================================================================== ---- a/channels/Makefile (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/Makefile (.../team/group/issue14292) (revision 178988) -@@ -16,8 +16,8 @@ - MENUSELECT_DESCRIPTION=Channel Drivers - - ifeq ($(OSARCH),OpenBSD) -- PTLIB=-lpt_OpenBSD_x86_r -- H323LIB=-lh323_OpenBSD_x86_r -+ PTLIB=-lpt -+ H323LIB=-lh323 - endif - - ifeq ($(OSARCH),linux-gnu) -@@ -105,5 +105,6 @@ - chan_usbradio.o: ./xpmr/xpmr.c ./xpmr/xpmr.h ./xpmr/xpmr_coef.h - - chan_usbradio.so: LIBS+=-lusb -lasound -+chan_usbradio.so: ASTCFLAGS+=-DNDEBUG - - -Index: channels/chan_iax2.c -=================================================================== ---- a/channels/chan_iax2.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_iax2.c (.../team/group/issue14292) (revision 178988) -@@ -94,6 +94,88 @@ - #include "iax2-provision.h" - #include "jitterbuf.h" - -+/*** DOCUMENTATION -+ -+ -+ Provision a calling IAXy with a given template. -+ -+ -+ -+ If not specified, defaults to default. -+ -+ -+ -+ Provisions the calling IAXy (assuming the calling entity is in fact an IAXy) with the -+ given template. Returns -1 on error -+ or 0 on success. -+ -+ -+ -+ -+ Gets IAX peer information. -+ -+ -+ -+ -+ -+ If peername is specified to this value, return the IP address of the -+ endpoint of the current channel -+ -+ -+ -+ -+ If peername is specified, valid items are: -+ -+ -+ (default) The IP address. -+ -+ -+ The peer's status (if qualify=yes) -+ -+ -+ The configured mailbox. -+ -+ -+ The configured context. -+ -+ -+ The epoch time of the next expire. -+ -+ -+ Is it dynamic? (yes/no). -+ -+ -+ The configured Caller ID name. -+ -+ -+ The configured Caller ID number. -+ -+ -+ The configured codecs. -+ -+ -+ Preferred codec index number x (beginning -+ with 0) -+ -+ -+ -+ -+ -+ -+ SIPPEER -+ -+ -+ -+ -+ Sets or retrieves a remote variable. -+ -+ -+ -+ -+ -+ -+ ***/ -+ - /* Define SCHED_MULTITHREADED to run the scheduler in a special - multithreaded mode. */ - #define SCHED_MULTITHREADED -@@ -223,7 +305,7 @@ - } while(0) - - static struct io_context *io; --static struct sched_context *sched; -+static struct ast_sched_thread *sched; - - static int iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH; - -@@ -250,9 +332,6 @@ - static struct ast_flags globalflags = { 0 }; - - static pthread_t netthreadid = AST_PTHREADT_NULL; --static pthread_t schedthreadid = AST_PTHREADT_NULL; --AST_MUTEX_DEFINE_STATIC(sched_lock); --static ast_cond_t sched_cond; - - enum iax2_state { - IAX_STATE_STARTED = (1 << 0), -@@ -290,13 +369,16 @@ - IAX_FORCEJITTERBUF = (1 << 20), /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */ - IAX_RTIGNOREREGEXPIRE = (1 << 21), /*!< When using realtime, ignore registration expiration */ - IAX_TRUNKTIMESTAMPS = (1 << 22), /*!< Send trunk timestamps */ -- IAX_TRANSFERMEDIA = (1 << 23), /*!< When doing IAX2 transfers, transfer media only */ -+ IAX_TRANSFERMEDIA = (1 << 23), /*!< When doing IAX2 transfers, transfer media only */ - IAX_MAXAUTHREQ = (1 << 24), /*!< Maximum outstanding AUTHREQ restriction is in place */ - IAX_DELAYPBXSTART = (1 << 25), /*!< Don't start a PBX on the channel until the peer sends us a - response, so that we've achieved a three-way handshake with - them before sending voice or anything else*/ -- IAX_ALLOWFWDOWNLOAD = (1 << 26), /*!< Allow the FWDOWNL command? */ -- IAX_NOKEYROTATE = (1 << 27), /*!< Disable key rotation with encryption */ -+ IAX_ALLOWFWDOWNLOAD = (1 << 26), /*!< Allow the FWDOWNL command? */ -+ IAX_IMMEDIATE = (1 << 27), /*!< Allow immediate off-hook to extension s */ -+ IAX_SENDCONNECTEDLINE = (1 << 28), /*!< Allow sending of connected line updates */ -+ IAX_RECVCONNECTEDLINE = (1 << 29), /*!< Allow receiving of connected line updates */ -+ IAX_FORCE_ENCRYPT = (1 << 30), /*!< Forces call encryption, if encryption not possible hangup */ - }; - - static int global_rtautoclear = 120; -@@ -434,9 +516,13 @@ - TRANSFER_BEGIN, - TRANSFER_READY, - TRANSFER_RELEASED, -+ TRANSFER_PASSTHROUGH, - TRANSFER_MBEGIN, - TRANSFER_MREADY, -- TRANSFER_MRELEASED -+ TRANSFER_MRELEASED, -+ TRANSFER_MPASSTHROUGH, -+ TRANSFER_MEDIA, -+ TRANSFER_MEDIAPASS - }; - - struct iax2_registry { -@@ -631,13 +717,6 @@ - unsigned short transfercallno; - /*! Transfer encrypt AES-128 Key */ - ast_aes_encrypt_key tdcx; -- -- /*! If transfer has been attempted */ -- unsigned int triedtransfer:1; -- /*! Whether media is released */ -- unsigned int mediareleased:1; -- /*! If media released, the peer to send media to */ -- struct sockaddr_in media; - - /*! Status of knowledge of peer ADSI capability */ - int peeradsicpe; -@@ -735,7 +814,7 @@ - static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin); - - static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt); --static char *complete_iax2_peers(const char *line, const char *word, int pos, int state); -+static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, int flags); - static char *complete_iax2_unregister(const char *line, const char *word, int pos, int state); - - enum iax2_thread_iostate { -@@ -863,6 +942,13 @@ - */ - static struct timeval lastused[ARRAY_LEN(iaxs)]; - -+/*! -+ * * \brief Another container of iax2_pvt structures -+ * -+ * Active IAX2 pvt stucts used during transfering a call are stored here. -+ */ -+static struct ao2_container *iax_transfercallno_pvts; -+ - /* Flag to use with trunk calls, keeping these calls high up. It halves our effective use - but keeps the division between trunked and non-trunked better. */ - #define TRUNK_CALL_START ARRAY_LEN(iaxs) / 2 -@@ -950,7 +1036,7 @@ - static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen); - static int iax2_poke_peer(struct iax2_peer *peer, int heldcall); - static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force); --static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final, int media); -+static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final); - static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen); - static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img); - static int iax2_sendtext(struct ast_channel *c, const char *text); -@@ -963,14 +1049,14 @@ - static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int); - static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int); - static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int); --static int send_command_media(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int); - static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause); - static struct ast_frame *iax2_read(struct ast_channel *c); - static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly); - static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly); - static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime); -+static void *iax2_dup_variable_datastore(void *); - static void prune_peers(void); --static void *iax2_dup_variable_datastore(void *); -+static void prune_users(void); - static void iax2_free_variable_datastore(void *); - - static int acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen); -@@ -1176,22 +1262,18 @@ - #define schedule_action(func, data) __schedule_action(func, data, __PRETTY_FUNCTION__) - #endif - --static int iax2_sched_replace(int id, struct sched_context *con, int when, ast_sched_cb callback, const void *data) -+static int iax2_sched_replace(int id, struct ast_sched_thread *st, int when, -+ ast_sched_cb callback, const void *data) - { -- AST_SCHED_REPLACE(id, con, when, callback, data); -- signal_condition(&sched_lock, &sched_cond); -+ ast_sched_thread_del(st, id); - -- return id; -+ return ast_sched_thread_add(st, when, callback, data); - } - --static int iax2_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data) -+static int iax2_sched_add(struct ast_sched_thread *st, int when, -+ ast_sched_cb callback, const void *data) - { -- int res; -- -- res = ast_sched_add(con, when, callback, data); -- signal_condition(&sched_lock, &sched_cond); -- -- return res; -+ return ast_sched_thread_add(st, when, callback, data); - } - - static int send_ping(const void *data); -@@ -1227,13 +1309,29 @@ - return 0; - } - -+static void encmethods_to_str(int e, struct ast_str *buf) -+{ -+ ast_str_set(&buf, 0, "("); -+ if (e & IAX_ENCRYPT_AES128) { -+ ast_str_append(&buf, 0, "aes128"); -+ } -+ if (e & IAX_ENCRYPT_KEYROTATE) { -+ ast_str_append(&buf, 0, ",keyrotate"); -+ } -+ if (ast_str_strlen(buf) > 1) { -+ ast_str_append(&buf, 0, ")"); -+ } else { -+ ast_str_set(&buf, 0, "No"); -+ } -+} -+ - static int get_encrypt_methods(const char *s) - { - int e; - if (!strcasecmp(s, "aes128")) -- e = IAX_ENCRYPT_AES128; -+ e = IAX_ENCRYPT_AES128 | IAX_ENCRYPT_KEYROTATE; - else if (ast_true(s)) -- e = IAX_ENCRYPT_AES128; -+ e = IAX_ENCRYPT_AES128 | IAX_ENCRYPT_KEYROTATE; - else - e = 0; - return e; -@@ -1378,6 +1476,14 @@ - return NULL; - } - -+static struct iax2_user *find_user(const char *name) -+{ -+ struct iax2_user tmp_user = { -+ .name = name, -+ }; -+ -+ return ao2_find(users, &tmp_user, OBJ_POINTER); -+} - static inline struct iax2_user *user_ref(struct iax2_user *user) - { - ao2_ref(user, +1); -@@ -1440,18 +1546,18 @@ - ast_clear_flag(pvt, IAX_MAXAUTHREQ); - } - /* No more pings or lagrq's */ -- AST_SCHED_DEL_SPINLOCK(sched, pvt->pingid, &iaxsl[pvt->callno]); -- AST_SCHED_DEL_SPINLOCK(sched, pvt->lagid, &iaxsl[pvt->callno]); -- AST_SCHED_DEL(sched, pvt->autoid); -- AST_SCHED_DEL(sched, pvt->authid); -- AST_SCHED_DEL(sched, pvt->initid); -- AST_SCHED_DEL(sched, pvt->jbid); -- AST_SCHED_DEL(sched, pvt->keyrotateid); -+ AST_SCHED_DEL_SPINLOCK(ast_sched_thread_get_context(sched), pvt->pingid, &iaxsl[pvt->callno]); -+ AST_SCHED_DEL_SPINLOCK(ast_sched_thread_get_context(sched), pvt->lagid, &iaxsl[pvt->callno]); -+ ast_sched_thread_del(sched, pvt->autoid); -+ ast_sched_thread_del(sched, pvt->authid); -+ ast_sched_thread_del(sched, pvt->initid); -+ ast_sched_thread_del(sched, pvt->jbid); -+ ast_sched_thread_del(sched, pvt->keyrotateid); - } - - static void iax2_frame_free(struct iax_frame *fr) - { -- AST_SCHED_DEL(sched, fr->retrans); -+ ast_sched_thread_del(sched, fr->retrans); - iax_frame_free(fr); - } - -@@ -1583,7 +1689,7 @@ - if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) && - (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) { - /* We're transferring */ -- if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_NONE && cur->transfercallno == callno)) -+ if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno)) - return 1; - } - return 0; -@@ -1640,8 +1746,8 @@ - * \note We delete these before switching the slot, because if - * they fire in the meantime, they will generate a warning. - */ -- AST_SCHED_DEL(sched, iaxs[callno]->pingid); -- AST_SCHED_DEL(sched, iaxs[callno]->lagid); -+ ast_sched_thread_del(sched, iaxs[callno]->pingid); -+ ast_sched_thread_del(sched, iaxs[callno]->lagid); - iaxs[x] = iaxs[callno]; - iaxs[x]->callno = x; - iaxs[callno] = NULL; -@@ -1670,6 +1776,25 @@ - return res; - } - -+static void store_by_transfercallno(struct chan_iax2_pvt *pvt) -+{ -+ if (!pvt->transfercallno) { -+ ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n"); -+ return; -+ } -+ -+ ao2_link(iax_transfercallno_pvts, pvt); -+} -+ -+static void remove_by_transfercallno(struct chan_iax2_pvt *pvt) -+{ -+ if (!pvt->transfercallno) { -+ ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n"); -+ return; -+ } -+ -+ ao2_unlink(iax_transfercallno_pvts, pvt); -+} - static void store_by_peercallno(struct chan_iax2_pvt *pvt) - { - if (!pvt->peercallno) { -@@ -1706,12 +1831,13 @@ - struct chan_iax2_pvt tmp_pvt = { - .callno = dcallno, - .peercallno = callno, -+ .transfercallno = callno, - /* hack!! */ - .frames_received = check_dcallno, - }; - - memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr)); -- -+ /* this works for finding normal call numbers not involving transfering */ - if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) { - if (return_locked) { - ast_mutex_lock(&iaxsl[pvt->callno]); -@@ -1721,9 +1847,20 @@ - pvt = NULL; - return res; - } -+ /* this searches for transfer call numbers that might not get caught otherwise */ -+ memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr)); -+ memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.addr)); -+ if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) { -+ if (return_locked) { -+ ast_mutex_lock(&iaxsl[pvt->callno]); -+ } -+ res = pvt->callno; -+ ao2_ref(pvt, -1); -+ pvt = NULL; -+ return res; -+ } - } -- -- /* This will occur on the first response to a message that we initiated, -+ /* This will occur on the first response to a message that we initiated, - * such as a PING. */ - if (dcallno) { - ast_mutex_lock(&iaxsl[dcallno]); -@@ -1740,7 +1877,6 @@ - if (dcallno) { - ast_mutex_unlock(&iaxsl[dcallno]); - } -- - #ifdef IAX_OLD_FIND - /* If we get here, we SHOULD NOT find a call structure for this - callno; if we do, it means that there is a call structure that -@@ -1830,8 +1966,7 @@ - iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x); - iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x); - iaxs[x]->amaflags = amaflags; -- ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_NOKEYROTATE); -- -+ ast_copy_flags(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); - ast_string_field_set(iaxs[x], accountcode, accountcode); - ast_string_field_set(iaxs[x], mohinterpret, mohinterpret); - ast_string_field_set(iaxs[x], mohsuggest, mohsuggest); -@@ -2277,7 +2412,6 @@ - { - int res; - int callno = f->callno; -- struct sockaddr_in *addr; - - /* Don't send if there was an error, but return error instead */ - if (!callno || !iaxs[callno] || iaxs[callno]->error) -@@ -2286,20 +2420,16 @@ - /* Called with iaxsl held */ - if (iaxdebug) - ast_debug(3, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port)); -- -- if (f->media) { -- addr = &iaxs[callno]->media; -- } else if (f->transfer) { -- addr = &iaxs[callno]->transfer; -+ -+ if (f->transfer) { -+ if (iaxdebug) -+ iax_showframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr)); -+ res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer, sizeof(iaxs[callno]->transfer)); - } else { -- addr = &iaxs[callno]->addr; -+ if (iaxdebug) -+ iax_showframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr)); -+ res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr, sizeof(iaxs[callno]->addr)); - } -- -- iax_outputframe(f, NULL, 0, addr, f->datalen - sizeof(struct ast_iax2_full_hdr)); -- -- res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)addr, -- sizeof(iaxs[callno]->media)); -- - if (res < 0) { - if (iaxdebug) - ast_debug(1, "Received error: %s\n", strerror(errno)); -@@ -2377,6 +2507,10 @@ - remove_by_peercallno(pvt); - } - -+ if (pvt->transfercallno) { -+ remove_by_transfercallno(pvt); -+ } -+ - if (!owner) { - ao2_ref(pvt, -1); - pvt = NULL; -@@ -2422,17 +2556,9 @@ - if (f->retries >= max_retries) { - if (f->transfer) { - /* Transfer timeout */ -- struct iax_ie_data ied; -- memset(&ied, 0, sizeof(ied)); -- iax_ie_append_int(&ied, IAX_IE_TRANSFERID, iaxs[callno]->transferid); -- if (iaxs[callno]->mediareleased) { -- send_command_media(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos); -- } else { -- send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos, -1); -- } -+ send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1); - } else if (f->final) { -- if (f->final) -- iax2_destroy(callno); -+ iax2_destroy(callno); - } else { - if (iaxs[callno]->owner) - ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass, f->ts, f->oseqno); -@@ -2501,7 +2627,10 @@ - - static char *handle_cli_iax2_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -- struct iax2_peer *peer; -+ struct iax2_peer *peer = NULL; -+ struct iax2_user *user = NULL; -+ static char *choices[] = { "all", NULL }; -+ char *cmplt; - - switch (cmd) { - case CLI_INIT: -@@ -2511,29 +2640,49 @@ - " Prunes object(s) from the cache\n"; - return NULL; - case CLI_GENERATE: -- if (a->pos == 3) -- return complete_iax2_peers(a->line, a->word, a->pos, a->n); -+ if (a->pos == 3) { -+ cmplt = ast_cli_complete(a->word, choices, a->n); -+ if (!cmplt) -+ cmplt = complete_iax2_peers(a->line, a->word, a->pos, a->n - sizeof(choices), IAX_RTCACHEFRIENDS); -+ return cmplt; -+ } - return NULL; - } -- - if (a->argc != 4) -- return CLI_SHOWUSAGE; -+ return CLI_SHOWUSAGE; - if (!strcmp(a->argv[3], "all")) { -- reload_config(); -+ prune_users(); -+ prune_peers(); - ast_cli(a->fd, "Cache flushed successfully.\n"); -- } else if ((peer = find_peer(a->argv[3], 0))) { -- if(ast_test_flag(peer, IAX_RTCACHEFRIENDS)) { -- ast_set_flag(peer, IAX_RTAUTOCLEAR); -- expire_registry(peer_ref(peer)); -- ast_cli(a->fd, "Peer %s was removed from the cache.\n", a->argv[3]); -- } else { -- ast_cli(a->fd, "Peer %s is not eligible for this operation.\n", a->argv[3]); -+ return CLI_SUCCESS; -+ } -+ peer = find_peer(a->argv[3], 0); -+ user = find_user(a->argv[3]); -+ if (peer || user) { -+ if (peer) { -+ if (ast_test_flag(peer, IAX_RTCACHEFRIENDS)) { -+ ast_set_flag(peer, IAX_RTAUTOCLEAR); -+ expire_registry(peer_ref(peer)); -+ ast_cli(a->fd, "Peer %s was removed from the cache.\n", a->argv[3]); -+ } else { -+ ast_cli(a->fd, "Peer %s is not eligible for this operation.\n", a->argv[3]); -+ } -+ peer_unref(peer); - } -- peer_unref(peer); -+ if (user) { -+ if (ast_test_flag(user, IAX_RTCACHEFRIENDS)) { -+ ast_set_flag(user, IAX_RTAUTOCLEAR); -+ ast_cli(a->fd, "User %s was removed from the cache.\n", a->argv[3]); -+ } else { -+ ast_cli(a->fd, "User %s is not eligible for this operation.\n", a->argv[3]); -+ } -+ ao2_unlink(users,user); -+ user_unref(user); -+ } - } else { -- ast_cli(a->fd, "Peer %s was not found in the cache.\n", a->argv[3]); -+ ast_cli(a->fd, "%s was not found in the cache.\n", a->argv[3]); - } -- -+ - return CLI_SUCCESS; - } - -@@ -2657,6 +2806,7 @@ - char cbuf[256]; - struct iax2_peer *peer; - char codec_buf[512]; -+ struct ast_str *encmethods = ast_str_alloca(256); - int x = 0, codec = 0, load_realtime = 0; - - switch (cmd) { -@@ -2668,7 +2818,7 @@ - return NULL; - case CLI_GENERATE: - if (a->pos == 3) -- return complete_iax2_peers(a->line, a->word, a->pos, a->n); -+ return complete_iax2_peers(a->line, a->word, a->pos, a->n, 0); - return NULL; - } - -@@ -2679,6 +2829,7 @@ - - peer = find_peer(a->argv[3], load_realtime); - if (peer) { -+ encmethods_to_str(peer->encmethods, encmethods); - ast_cli(a->fd, "\n\n"); - ast_cli(a->fd, " * Name : %s\n", peer->name); - ast_cli(a->fd, " Secret : %s\n", ast_strlen_zero(peer->secret) ? "" : ""); -@@ -2686,6 +2837,8 @@ - ast_cli(a->fd, " Parking lot : %s\n", peer->parkinglot); - ast_cli(a->fd, " Mailbox : %s\n", peer->mailbox); - ast_cli(a->fd, " Dynamic : %s\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes" : "No"); -+ ast_cli(a->fd, " Trunk : %s\n", ast_test_flag(peer, IAX_TRUNK) ? "Yes" : "No"); -+ ast_cli(a->fd, " Encryption : %s\n", peer->encmethods ? ast_str_buffer(encmethods) : "No"); - ast_cli(a->fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "")); - ast_cli(a->fd, " Expire : %d\n", peer->expire); - ast_cli(a->fd, " ACL : %s\n", (peer->ha ? "Yes" : "No")); -@@ -2724,7 +2877,7 @@ - return CLI_SUCCESS; - } - --static char *complete_iax2_peers(const char *line, const char *word, int pos, int state) -+static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, int flags) - { - int which = 0; - struct iax2_peer *peer; -@@ -2734,7 +2887,8 @@ - - i = ao2_iterator_init(peers, 0); - while ((peer = ao2_iterator_next(&i))) { -- if (!strncasecmp(peer->name, word, wordlen) && ++which > state) { -+ if (!strncasecmp(peer->name, word, wordlen) && ++which > state -+ && (!flags || ast_test_flag(peer, flags))) { - res = ast_strdup(peer->name); - peer_unref(peer); - break; -@@ -3101,7 +3255,7 @@ - - jb_reset(iaxs[fr->callno]->jb); - -- AST_SCHED_DEL(sched, iaxs[fr->callno]->jbid); -+ ast_sched_thread_del(sched, iaxs[fr->callno]->jbid); - - /* deliver this frame now */ - if (tsout) -@@ -3141,7 +3295,7 @@ - /* Wake up the network and scheduler thread */ - if (netthreadid != AST_PTHREADT_NULL) - pthread_kill(netthreadid, SIGURG); -- signal_condition(&sched_lock, &sched_cond); -+ ast_sched_thread_poke(sched); - return 0; - } - -@@ -3277,7 +3431,7 @@ - ast_copy_flags(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS); - if (ast_test_flag(peer, IAX_RTAUTOCLEAR)) { - if (peer->expire > -1) { -- if (!ast_sched_del(sched, peer->expire)) { -+ if (!ast_sched_thread_del(sched, peer->expire)) { - peer->expire = -1; - peer_unref(peer); - } -@@ -3406,6 +3560,8 @@ - char outkey[80]; - char timezone[80]; - char prefs[32]; -+ char cid_num[80]; -+ char cid_name[80]; - char context[AST_MAX_CONTEXT]; - char peercontext[AST_MAX_CONTEXT]; - char mohinterpret[MAX_MUSICCLASS]; -@@ -3449,7 +3605,7 @@ - if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0))) - goto return_unref; - -- ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_NOKEYROTATE); -+ ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); - cai->maxtime = peer->maxms; - cai->capability = peer->capability; - cai->encmethods = peer->encmethods; -@@ -3467,6 +3623,8 @@ - ast_copy_string(cai->username, peer->username, sizeof(cai->username)); - ast_copy_string(cai->timezone, peer->zonetag, sizeof(cai->timezone)); - ast_copy_string(cai->outkey, peer->outkey, sizeof(cai->outkey)); -+ ast_copy_string(cai->cid_num, peer->cid_num, sizeof(cai->cid_num)); -+ ast_copy_string(cai->cid_name, peer->cid_name, sizeof(cai->cid_name)); - ast_copy_string(cai->mohinterpret, peer->mohinterpret, sizeof(cai->mohinterpret)); - ast_copy_string(cai->mohsuggest, peer->mohsuggest, sizeof(cai->mohsuggest)); - if (ast_strlen_zero(peer->dbsecret)) { -@@ -3649,16 +3807,17 @@ - ast_log(LOG_WARNING, "No peer provided in the IAX2 dial string '%s'\n", dest); - return -1; - } -- - if (!pds.exten) { - pds.exten = defaultrdest; - } -- - if (create_addr(pds.peer, c, &sin, &cai)) { - ast_log(LOG_WARNING, "No address associated with '%s'\n", pds.peer); - return -1; - } -- -+ if (ast_strlen_zero(cai.secret) && ast_test_flag(iaxs[callno], IAX_FORCE_ENCRYPT)) { -+ ast_log(LOG_WARNING, "Call terminated. No secret given and force encrypt enabled\n"); -+ return -1; -+ } - if (!pds.username && !ast_strlen_zero(cai.username)) - pds.username = cai.username; - if (!pds.password && !ast_strlen_zero(cai.secret)) -@@ -3674,8 +3833,8 @@ - if (pds.port) - sin.sin_port = htons(atoi(pds.port)); - -- l = c->cid.cid_num; -- n = c->cid.cid_name; -+ l = c->connected.id.number; -+ n = c->connected.id.name; - - /* Now build request */ - memset(&ied, 0, sizeof(ied)); -@@ -3692,21 +3851,21 @@ - - if (l) { - iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l); -- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); -+ iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->connected.id.number_presentation); - } else { - if (n) -- iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); -+ iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->connected.id.number_presentation); - else - iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, AST_PRES_NUMBER_NOT_AVAILABLE); - } - -- iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->cid.cid_ton); -+ iax_ie_append_byte(&ied, IAX_IE_CALLINGTON, c->connected.id.number_type); - iax_ie_append_short(&ied, IAX_IE_CALLINGTNS, c->cid.cid_tns); - - if (n) - iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, n); -- if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->cid.cid_ani) -- iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->cid.cid_ani); -+ if (ast_test_flag(iaxs[callno], IAX_SENDANI) && c->connected.ani) -+ iax_ie_append_str(&ied, IAX_IE_CALLING_ANI, c->connected.ani); - - if (!ast_strlen_zero(c->language)) - iax_ie_append_str(&ied, IAX_IE_LANGUAGE, c->language); -@@ -3835,7 +3994,7 @@ - ast_debug(1, "Really destroying %s now...\n", c->name); - iax2_destroy(callno); - } else if (iaxs[callno]) { -- if (ast_sched_add(sched, 10000, scheduled_destroy, CALLNO_TO_PTR(callno)) < 0) { -+ if (ast_sched_thread_add(sched, 10000, scheduled_destroy, CALLNO_TO_PTR(callno)) < 0) { - ast_log(LOG_ERROR, "Unable to schedule iax2 callno %d destruction?!! Destroying immediately.\n", callno); - iax2_destroy(callno); - } -@@ -3885,6 +4044,9 @@ - /* these two cannot be sent, because they require a result */ - errno = ENOSYS; - return -1; -+ case AST_OPTION_OPRMODE: -+ errno = EINVAL; -+ return -1; - default: - { - unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); -@@ -3931,11 +4093,10 @@ - struct iax_ie_data ied = { - .pos = 0, - }; -- -+ - ast_mutex_lock(&iaxsl[pvt->callno]); -- - pvt->keyrotateid = -- ast_sched_add(sched, 120000 + (ast_random() % 180001), iax2_key_rotate, vpvt); -+ ast_sched_thread_add(sched, 120000 + (ast_random() % 180001), iax2_key_rotate, vpvt); - - snprintf(key, sizeof(key), "%lX", ast_random()); - -@@ -3971,38 +4132,23 @@ - } - - memset(&ied0, 0, sizeof(ied0)); -- iaxs[callno0]->transferid = transferid; - iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &iaxs[callno1]->addr); - iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[callno1]->peercallno); - iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transferid); - - memset(&ied1, 0, sizeof(ied1)); -- iaxs[callno1]->transferid = transferid; - iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &iaxs[callno0]->addr); - iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[callno0]->peercallno); - iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transferid); - -- if (iaxs[callno0]->mediareleased) { -- res = send_command_media(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos); -- } else { -- res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1); -- } -- -+ res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1); - if (res) - return -1; -- -- if (iaxs[callno1]->mediareleased) -- res = send_command_media(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos); -- else -- res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1); -- -+ res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1); - if (res) - return -1; - iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN; - iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN; -- iaxs[callno0]->triedtransfer = 1; -- iaxs[callno1]->triedtransfer = 1; -- - return 0; - } - -@@ -4026,6 +4172,7 @@ - struct ast_channel *who, *other; - int to = -1; - int res = -1; -+ int transferstarted=0; - struct ast_frame *f; - unsigned short callno0 = PTR_TO_CALLNO(c0->tech_pvt); - unsigned short callno1 = PTR_TO_CALLNO(c1->tech_pvt); -@@ -4085,17 +4232,13 @@ - unlock_both(callno0, callno1); - return AST_BRIDGE_FAILED_NOWARN; - } -- /* check if if we really want native bridging */ -- if (!ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) { -- if (!iaxs[callno0]->triedtransfer && !iaxs[callno1]->triedtransfer && -- (iaxs[callno0]->transferring == TRANSFER_NONE) && -- (iaxs[callno1]->transferring == TRANSFER_NONE)) { -- /* Try the transfer */ -- if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) || -- ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA))) { -- ast_log(LOG_WARNING, "Unable to start the transfer\n"); -- } -- } -+ /* check if transfered and if we really want native bridging */ -+ if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) { -+ /* Try the transfer */ -+ if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) || -+ ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA))) -+ ast_log(LOG_WARNING, "Unable to start the transfer\n"); -+ transferstarted = 1; - } - if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) { - /* Call has been transferred. We're no longer involved */ -@@ -4136,7 +4279,7 @@ - res = AST_BRIDGE_COMPLETE; - break; - } -- if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) { -+ if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS) && (f->subclass != AST_CONTROL_SRCUPDATE)) { - *fo = f; - *rc = who; - res = AST_BRIDGE_COMPLETE; -@@ -4144,10 +4287,11 @@ - } - other = (who == c0) ? c1 : c0; /* the 'other' channel */ - if ((f->frametype == AST_FRAME_VOICE) || -- (f->frametype == AST_FRAME_TEXT) || -- (f->frametype == AST_FRAME_VIDEO) || -- (f->frametype == AST_FRAME_IMAGE) || -- (f->frametype == AST_FRAME_DTMF)) { -+ (f->frametype == AST_FRAME_TEXT) || -+ (f->frametype == AST_FRAME_VIDEO) || -+ (f->frametype == AST_FRAME_IMAGE) || -+ (f->frametype == AST_FRAME_DTMF) || -+ (f->frametype == AST_FRAME_CONTROL)) { - /* monitored dtmf take out of the bridge. - * check if we monitor the specific source. - */ -@@ -4217,6 +4361,11 @@ - ast_moh_stop(c); - goto done; - } -+ break; -+ case AST_CONTROL_CONNECTED_LINE: -+ if (!ast_test_flag(pvt, IAX_SENDCONNECTEDLINE)) -+ goto done; -+ break; - } - - res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1); -@@ -4870,7 +5019,7 @@ - return res; - } - --static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final, int media) -+static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final) - { - /* Queue a packet for delivery on a given private structure. Use "ts" for - timestamp, or calculate if ts is 0. Send immediately without retransmission -@@ -4913,13 +5062,8 @@ - pvt->keyrotateid != -1 ? "" : "no " - ); - #endif -- - if (pvt->keyrotateid == -1 && f->frametype == AST_FRAME_VOICE && IAX_CALLENCRYPTED(pvt)) { -- if (ast_test_flag(pvt, IAX_NOKEYROTATE)) { -- pvt->keyrotateid = -2; -- } else { -- iax2_key_rotate(pvt); -- } -+ iax2_key_rotate(pvt); - } - - if ((ast_test_flag(pvt, IAX_TRUNK) || -@@ -4967,7 +5111,6 @@ - fr->ts = fts; - fr->callno = pvt->callno; - fr->transfer = transfer; -- fr->media = media; - fr->final = final; - if (!sendmini) { - /* We need a full frame */ -@@ -4980,12 +5123,12 @@ - fh->scallno = htons(fr->callno | IAX_FLAG_FULL); - fh->ts = htonl(fr->ts); - fh->oseqno = fr->oseqno; -- if (transfer || media) { -+ if (transfer) { - fh->iseqno = 0; - } else - fh->iseqno = fr->iseqno; - /* Keep track of the last thing we've acknowledged */ -- if (!transfer || media) -+ if (!transfer) - pvt->aseqno = fr->iseqno; - fh->type = fr->af.frametype & 0xFF; - if (fr->af.frametype == AST_FRAME_VIDEO) -@@ -5017,8 +5160,6 @@ - if (ast_test_flag(pvt, IAX_KEYPOPULATED)) { - if (fr->transfer) - iax_outputframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr)); -- else if (fr->media) -- iax_outputframe(fr, NULL, 2, &pvt->media, fr->datalen - sizeof(struct ast_iax2_full_hdr)); - else - iax_outputframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr)); - encrypt_frame(&pvt->ecx, fh, pvt->semirand, &fr->datalen); -@@ -5045,9 +5186,6 @@ - fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr); - fr->data = vh; - fr->retries = -1; -- if (pvt->mediareleased) { -- fr->media = 1; -- } - res = send_packet(fr); - } else { - /* Mini-frames have no sequence number */ -@@ -5060,9 +5198,8 @@ - fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr); - fr->data = mh; - fr->retries = -1; -- if (pvt->mediareleased) { -- fr->media = 1; -- } -+ if (pvt->transferring == TRANSFER_MEDIAPASS) -+ fr->transfer = 1; - if (ast_test_flag(pvt, IAX_ENCRYPTED)) { - if (ast_test_flag(pvt, IAX_KEYPOPULATED)) { - encrypt_frame(&pvt->ecx, (struct ast_iax2_full_hdr *)mh, pvt->semirand, &fr->datalen); -@@ -5163,6 +5300,7 @@ - - struct iax2_peer *peer = NULL; - char name[256]; -+ struct ast_str *encmethods = ast_str_alloca(256); - int registeredonly=0; - char *term = manager ? "\r\n" : "\n"; - char idtext[256] = ""; -@@ -5208,7 +5346,6 @@ - peer_unref(peer), peer = ao2_iterator_next(&i)) { - char nm[20]; - char status[20]; -- char srch[2000]; - int retstatus; - - if (registeredonly && !peer->addr.sin_addr.s_addr) -@@ -5220,7 +5357,8 @@ - snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username); - else - ast_copy_string(name, peer->name, sizeof(name)); -- -+ -+ encmethods_to_str(peer->encmethods, encmethods); - retstatus = peer_status(peer, status, sizeof(status)); - if (retstatus > 0) - online_peers++; -@@ -5228,18 +5366,11 @@ - offline_peers++; - else - unmonitored_peers++; -- -+ - ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm)); -- -- snprintf(srch, sizeof(srch), FORMAT, name, -- peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", -- ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)", -- nm, -- ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ", -- peer->encmethods ? "(E)" : " ", status, term); -- -- if (s) -- astman_append(s, -+ -+ if (s) { -+ astman_append(s, - "Event: PeerEntry\r\n%s" - "Channeltype: IAX2\r\n" - "ChanObjectType: peer\r\n" -@@ -5247,21 +5378,28 @@ - "IPaddress: %s\r\n" - "IPport: %d\r\n" - "Dynamic: %s\r\n" -+ "Trunk: %s\r\n" -+ "Encryption: %s\r\n" - "Status: %s\r\n\r\n", - idtext, - name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "-none-", - ntohs(peer->addr.sin_port), - ast_test_flag(peer, IAX_DYNAMIC) ? "yes" : "no", -+ ast_test_flag(peer, IAX_TRUNK) ? "yes" : "no", -+ peer->encmethods ? ast_str_buffer(encmethods) : "no", - status); -- -- else -- ast_cli(fd, FORMAT, name, -+ } else { -+ ast_cli(fd, FORMAT, name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", - ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)", - nm, -- ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ", -- peer->encmethods ? "(E)" : " ", status, term); -+ ntohs(peer->addr.sin_port), -+ ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ", -+ peer->encmethods ? "(E)" : " ", -+ status, -+ term); -+ } - total_peers++; - } - -@@ -5497,6 +5635,7 @@ - char status[20]; - const char *id = astman_get_header(m,"ActionID"); - char idtext[256] = ""; -+ struct ast_str *encmethods = ast_str_alloca(256); - struct ao2_iterator i; - - if (!ast_strlen_zero(id)) -@@ -5507,7 +5646,7 @@ - - i = ao2_iterator_init(peers, 0); - for (peer = ao2_iterator_next(&i); peer; peer_unref(peer), peer = ao2_iterator_next(&i)) { -- -+ encmethods_to_str(peer->encmethods, encmethods); - astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext); - if (!ast_strlen_zero(peer->username)) { - astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username); -@@ -5520,6 +5659,8 @@ - astman_append(s, "Mask: %s\r\n", nm); - astman_append(s, "Port: %d\r\n", ntohs(peer->addr.sin_port)); - astman_append(s, "Dynamic: %s\r\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes" : "No"); -+ astman_append(s, "Trunk: %s\r\n", ast_test_flag(peer, IAX_TRUNK) ? "Yes" : "No"); -+ astman_append(s, "Encryption: %s\r\n", peer->encmethods ? ast_str_buffer(encmethods) : "No"); - peer_status(peer, status, sizeof(status)); - astman_append(s, "Status: %s\r\n\r\n", status); - peer_count++; -@@ -5593,6 +5734,55 @@ - #undef FORMAT2 - } - -+static int manager_iax2_show_registry(struct mansession *s, const struct message *m) -+{ -+ const char *id = astman_get_header(m, "ActionID"); -+ struct iax2_registry *reg = NULL; -+ char idtext[256] = ""; -+ char host[80] = ""; -+ char perceived[80] = ""; -+ int total = 0; -+ -+ if (!ast_strlen_zero(id)) -+ snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id); -+ -+ astman_send_listack(s, m, "Registrations will follow", "start"); -+ -+ AST_LIST_LOCK(®istrations); -+ AST_LIST_TRAVERSE(®istrations, reg, entry) { -+ snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(reg->addr.sin_addr), ntohs(reg->addr.sin_port)); -+ -+ if (reg->us.sin_addr.s_addr) { -+ snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port)); -+ } else { -+ ast_copy_string(perceived, "", sizeof(perceived)); -+ } -+ -+ astman_append(s, -+ "Event: RegistryEntry\r\n" -+ "Host: %s\r\n" -+ "DNSmanager: %s\r\n" -+ "Username: %s\r\n" -+ "Perceived: %s\r\n" -+ "Refresh: %d\r\n" -+ "State: %s\r\n" -+ "\r\n", host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived, -+ reg->refresh, regstate2str(reg->regstate)); -+ -+ total++; -+ } -+ AST_LIST_UNLOCK(®istrations); -+ -+ astman_append(s, -+ "Event: RegistrationsComplete\r\n" -+ "EventList: Complete\r\n" -+ "ListItems: %d\r\n" -+ "%s" -+ "\r\n", total, idtext); -+ -+ return 0; -+} -+ - static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - #define FORMAT2 "%-20.20s %-15.15s %-10.10s %-11.11s %-11.11s %-7.7s %-6.6s %-6.6s %s\n" -@@ -5760,8 +5950,8 @@ - " Enables/Disables dumping of IAX packets for debugging purposes.\n"; - return NULL; - case CLI_GENERATE: -- if (a->pos == 4) -- return complete_iax2_peers(a->line, a->word, a->pos, a->n); -+ if (a->pos == 4 && !strcasecmp(a->argv[3], "peer")) -+ return complete_iax2_peers(a->line, a->word, a->pos, a->n, 0); - return NULL; - } - -@@ -5870,7 +6060,7 @@ - res = 0; - else - /* Simple, just queue for transmission */ -- res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0, 0); -+ res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0); - } else { - ast_debug(1, "Write error: %s\n", strerror(errno)); - } -@@ -5881,7 +6071,7 @@ - } - - static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno, -- int now, int transfer, int final, int media) -+ int now, int transfer, int final) - { - struct ast_frame f = { 0, }; - -@@ -5891,12 +6081,12 @@ - f.src = __FUNCTION__; - f.data.ptr = (void *) data; - -- return iax2_send(i, &f, ts, seqno, now, transfer, final, media); -+ return iax2_send(i, &f, ts, seqno, now, transfer, final); - } - - static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno) - { -- return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0); -+ return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0); - } - - static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno) -@@ -5920,24 +6110,19 @@ - iax2_predestroy(i->callno); - if (!iaxs[call_num]) - return -1; -- return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0); -+ return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1); - } - - static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno) - { -- return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0); -+ return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0); - } - - static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen) - { -- return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0); -+ return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0); - } - --static int send_command_media(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen) --{ -- return __send_command(i, type, command, ts, data, datalen, 0, 0, 0, 0, 1); --} -- - static int apply_context(struct iax2_context *con, const char *context) - { - while(con) { -@@ -6092,10 +6277,7 @@ - if (user->maxauthreq > 0) - ast_set_flag(iaxs[callno], IAX_MAXAUTHREQ); - iaxs[callno]->prefs = user->prefs; -- ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST); -- ast_copy_flags(iaxs[callno], user, IAX_CODEC_NOPREFS); -- ast_copy_flags(iaxs[callno], user, IAX_CODEC_NOCAP); -- ast_copy_flags(iaxs[callno], user, IAX_NOKEYROTATE); -+ ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST | IAX_IMMEDIATE | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_FORCE_ENCRYPT); - iaxs[callno]->encmethods = user->encmethods; - /* Store the requested username if not specified */ - if (ast_strlen_zero(iaxs[callno]->username)) -@@ -6138,7 +6320,7 @@ - iaxs[callno]->amaflags = user->amaflags; - if (!ast_strlen_zero(user->language)) - ast_string_field_set(iaxs[callno], language, user->language); -- ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); -+ ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); - /* Keep this check last */ - if (!ast_strlen_zero(user->dbsecret)) { - char *family, *key=NULL; -@@ -6186,6 +6368,9 @@ - /* Select exactly one common encryption if there are any */ - p->encmethods &= enc; - if (p->encmethods) { -+ if (!(p->encmethods & IAX_ENCRYPT_KEYROTATE)){ /* if key rotation is not supported, turn off keyrotation. */ -+ p->keyrotateid = -2; -+ } - if (p->encmethods & IAX_ENCRYPT_AES128) - p->encmethods = IAX_ENCRYPT_AES128; - else -@@ -6273,7 +6458,10 @@ - ast_string_field_set(p, host, user->name); - user = user_unref(user); - } -- -+ if (ast_test_flag(p, IAX_FORCE_ENCRYPT) && !p->encmethods) { -+ ast_log(LOG_NOTICE, "Call Terminated, Incomming call is unencrypted while force encrypt is enabled."); -+ return res; -+ } - if (!ast_test_flag(&p->state, IAX_STATE_AUTHENTICATED)) - return res; - if (ies->password) -@@ -6593,8 +6781,13 @@ - } - } - } -- if (ies->encmethods) -+ -+ if (ies->encmethods) { - ast_set_flag(p, IAX_ENCRYPTED | IAX_KEYPOPULATED); -+ } else if (ast_test_flag(iaxs[callno], IAX_FORCE_ENCRYPT)) { -+ ast_log(LOG_NOTICE, "Call initiated without encryption while forceencryption=yes option is set"); -+ return -1; /* if force encryption is yes, and no encryption methods, then return -1 to hangup */ -+ } - if (!res) { - struct ast_datastore *variablestore; - struct ast_variable *var, *prev = NULL; -@@ -6677,10 +6870,11 @@ - pvt->transfer.sin_family = AF_INET; - pvt->transferring = TRANSFER_BEGIN; - pvt->transferid = ies->transferid; -+ store_by_transfercallno(pvt); - if (ies->transferid) - iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid); - send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos); -- return 0; -+ return 0; - } - - static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies) -@@ -6744,10 +6938,9 @@ - ast_log(LOG_WARNING, "Invalid transfer request\n"); - return -1; - } -+ remove_by_transfercallno(pvt); - memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr)); - memset(&pvt->transfer, 0, sizeof(pvt->transfer)); -- pvt->mediareleased = 0; -- memset(&pvt->media, 0, sizeof(pvt->media)); - /* Reset sequence numbers */ - pvt->oseqno = 0; - pvt->rseqno = 0; -@@ -6758,8 +6951,8 @@ - remove_by_peercallno(pvt); - } - pvt->peercallno = peercallno; -+ /*this is where the transfering call swiches hash tables */ - store_by_peercallno(pvt); -- - pvt->transferring = TRANSFER_NONE; - pvt->svoiceformat = -1; - pvt->voiceformat = 0; -@@ -6937,14 +7130,14 @@ - static void unlink_peer(struct iax2_peer *peer) - { - if (peer->expire > -1) { -- if (!ast_sched_del(sched, peer->expire)) { -+ if (!ast_sched_thread_del(sched, peer->expire)) { - peer->expire = -1; - peer_unref(peer); - } - } - - if (peer->pokeexpire > -1) { -- if (!ast_sched_del(sched, peer->pokeexpire)) { -+ if (!ast_sched_thread_del(sched, peer->pokeexpire)) { - peer->pokeexpire = -1; - peer_unref(peer); - } -@@ -7018,7 +7211,7 @@ - p->addr.sin_addr = in; - p->addr.sin_port = htons(atoi(c)); - if (p->expire > -1) { -- if (!ast_sched_del(sched, p->expire)) { -+ if (!ast_sched_thread_del(sched, p->expire)) { - p->expire = -1; - peer_unref(p); - } -@@ -7114,7 +7307,7 @@ - p->sockfd = fd; - /* Setup the expiry */ - if (p->expire > -1) { -- if (!ast_sched_del(sched, p->expire)) { -+ if (!ast_sched_thread_del(sched, p->expire)) { - p->expire = -1; - peer_unref(p); - } -@@ -8139,8 +8332,6 @@ - - static struct ast_custom_function iaxvar_function = { - .name = "IAXVAR", -- .synopsis = "Sets or retrieves a remote variable", -- .syntax = "IAXVAR()", - .read = acf_iaxvar_read, - .write = acf_iaxvar_write, - }; -@@ -8340,7 +8531,6 @@ - ((f.subclass != IAX_COMMAND_TXCNT) && - (f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */ - (f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */ -- (f.subclass != IAX_COMMAND_TXMEDIA) && /* for attended transfer */ - (f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */ - (f.subclass != IAX_COMMAND_TXACC)) || - (f.frametype != AST_FRAME_IAX))) { -@@ -8350,7 +8540,6 @@ - (f.subclass != IAX_COMMAND_TXCNT) && - (f.subclass != IAX_COMMAND_TXREADY) && /* for attended transfer */ - (f.subclass != IAX_COMMAND_TXREL) && /* for attended transfer */ -- (f.subclass != IAX_COMMAND_TXMEDIA) && /* for attended transfer */ - (f.subclass != IAX_COMMAND_UNQUELCH ) && /* for attended transfer */ - (f.subclass != IAX_COMMAND_TXACC) && - (f.subclass != IAX_COMMAND_VNAK)) || -@@ -8452,7 +8641,7 @@ - ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno); - } - } -- if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) && inaddrcmp(&sin, &iaxs[fr->callno]->media) && -+ if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) && - ((f.frametype != AST_FRAME_IAX) || - ((f.subclass != IAX_COMMAND_TXACC) && - (f.subclass != IAX_COMMAND_TXCNT)))) { -@@ -8602,7 +8791,7 @@ - } - } - if (f.frametype == AST_FRAME_IAX) { -- AST_SCHED_DEL(sched, iaxs[fr->callno]->initid); -+ ast_sched_thread_del(sched, iaxs[fr->callno]->initid); - /* Handle the IAX pseudo frame itself */ - if (iaxdebug) - ast_debug(1, "IAX subclass %d received\n", f.subclass); -@@ -8671,23 +8860,18 @@ - } - break; - case IAX_COMMAND_TXACC: -- if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) && -- (iaxs[fr->callno]->transferid == ies.transferid)) { -- /* Cancel any outstanding txcnt's */ -+ if (iaxs[fr->callno]->transferring == TRANSFER_BEGIN) { -+ /* Ack the packet with the given timestamp */ - AST_LIST_LOCK(&frame_queue); - AST_LIST_TRAVERSE(&frame_queue, cur, list) { -+ /* Cancel any outstanding txcnt's */ - if ((fr->callno == cur->callno) && (cur->transfer)) - cur->retries = -1; - } - AST_LIST_UNLOCK(&frame_queue); - memset(&ied1, 0, sizeof(ied1)); - iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->callno); -- iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid); -- if (iaxs[fr->callno]->mediareleased) { -- send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos); -- } else { -- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1); -- } -+ send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1); - iaxs[fr->callno]->transferring = TRANSFER_READY; - } - break; -@@ -8720,6 +8904,11 @@ - ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context); - break; - } -+ if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_test_flag(iaxs[fr->callno], IAX_FORCE_ENCRYPT)) { -+ auth_fail(fr->callno, IAX_COMMAND_REJECT); -+ ast_log(LOG_WARNING, "Rejected connect attempt. No secret present while force encrypt enabled.\n"); -+ break; -+ } - if (strcasecmp(iaxs[fr->callno]->exten, "TBD")) { - const char *context, *exten, *cid_num; - -@@ -9089,7 +9278,7 @@ - - /* Remove scheduled iax2_poke_noanswer */ - if (peer->pokeexpire > -1) { -- if (!ast_sched_del(sched, peer->pokeexpire)) { -+ if (!ast_sched_thread_del(sched, peer->pokeexpire)) { - peer_unref(peer); - peer->pokeexpire = -1; - } -@@ -9119,7 +9308,7 @@ - if(f.subclass == IAX_COMMAND_LAGRQ) { - /* Received a LAGRQ - echo back a LAGRP */ - fr->af.subclass = IAX_COMMAND_LAGRP; -- iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0, 0); -+ iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0); - } else { - /* Received LAGRP in response to our LAGRQ */ - unsigned int ts; -@@ -9346,11 +9535,15 @@ - ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD); - /* If this is a TBD call, we're ready but now what... */ - ast_verb(3, "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(sin.sin_addr)); -+ if (ast_test_flag(iaxs[fr->callno], IAX_IMMEDIATE)) { -+ goto immediatedial; -+ } - } - } - } - break; - case IAX_COMMAND_DIAL: -+immediatedial: - if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD)) { - ast_clear_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD); - ast_string_field_set(iaxs[fr->callno], exten, ies.called_number ? ies.called_number : "s"); -@@ -9499,28 +9692,19 @@ - } - break; - case IAX_COMMAND_TXREJ: -- if ((iaxs[fr->callno]->transferring != TRANSFER_NONE) && -- (iaxs[fr->callno]->transferid == ies.transferid)) { -- iaxs[fr->callno]->transferring = TRANSFER_NONE; -- ast_verb(3, "Channel '%s' transfer rejected\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : ""); -- memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer)); -- if (iaxs[fr->callno]->bridgecallno && -- (iaxs[fr->callno]->transferid == iaxs[iaxs[fr->callno]->bridgecallno]->transferid)) { -- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE; -- memset(&ied0, 0, sizeof(ied0)); -- iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid); -- if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) { -- send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos); -- } else { -- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos, -1); -- } -+ iaxs[fr->callno]->transferring = 0; -+ ast_verb(3, "Channel '%s' unable to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : ""); -+ memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer)); -+ if (iaxs[fr->callno]->bridgecallno) { -+ if (iaxs[iaxs[fr->callno]->bridgecallno]->transferring) { -+ iaxs[iaxs[fr->callno]->bridgecallno]->transferring = 0; -+ send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1); - } - } - break; - case IAX_COMMAND_TXREADY: -- if (((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) || -- (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) && -- (iaxs[fr->callno]->transferid == ies.transferid)) { -+ if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) || -+ (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) { - if (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN) - iaxs[fr->callno]->transferring = TRANSFER_MREADY; - else -@@ -9530,33 +9714,19 @@ - if ((iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_READY) || - (iaxs[iaxs[fr->callno]->bridgecallno]->transferring == TRANSFER_MREADY)) { - /* They're both ready, now release them. */ -- /* If a peer is media released, we must also do a media release as there may be peers in between */ -- if (iaxs[fr->callno]->mediareleased || -- iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased || -- (iaxs[fr->callno]->transferring == TRANSFER_MREADY)) { -- -+ if (iaxs[fr->callno]->transferring == TRANSFER_MREADY) { - ast_verb(3, "Attempting media bridge of %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "", - iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : ""); - -- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MRELEASED; -- iaxs[fr->callno]->transferring = TRANSFER_MRELEASED; -+ iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA; -+ iaxs[fr->callno]->transferring = TRANSFER_MEDIA; - - memset(&ied0, 0, sizeof(ied0)); - memset(&ied1, 0, sizeof(ied1)); - iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno); -- iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid); - iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno); -- iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid); -- if (iaxs[fr->callno]->mediareleased) { -- send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos); -- } else { -- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1); -- } -- if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) { -- send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos); -- } else { -- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1); -- } -+ send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1); -+ send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1); - } else { - ast_verb(3, "Releasing %s and %s\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "", - iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : ""); -@@ -9573,19 +9743,9 @@ - memset(&ied0, 0, sizeof(ied0)); - memset(&ied1, 0, sizeof(ied1)); - iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr->callno]->bridgecallno]->peercallno); -- iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid); - iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->peercallno); -- iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid); -- if (iaxs[fr->callno]->mediareleased) { -- send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos); -- } else { -- send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1); -- } -- if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) { -- send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos); -- } else { -- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1); -- } -+ send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1); -+ send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1); - } - - } -@@ -9593,50 +9753,20 @@ - } - break; - case IAX_COMMAND_TXREQ: -- /* Try transfer only if none in progress, or use the transferid to resolve contention */ -- if ((iaxs[fr->callno]->transferring == TRANSFER_NONE) || -- (iaxs[fr->callno]->transferid <= ies.transferid)) { -- /* If there is a bridged channel and it is the same transfer, reject it */ -- if (iaxs[fr->callno]->bridgecallno && -- (iaxs[fr->callno]->transferid == iaxs[iaxs[fr->callno]->bridgecallno]->transferid)) { -- iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE; -- memset(&ied0, 0, sizeof(ied0)); -- iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid); -- if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased) { -- send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos); -- } else { -- send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos, -1); -- } -- /* Start our transfer again later */ -- iaxs[fr->callno]->triedtransfer = 0; -- iaxs[iaxs[fr->callno]->bridgecallno]->triedtransfer = 0; -- } -- try_transfer(iaxs[fr->callno], &ies); -- } -- -+ try_transfer(iaxs[fr->callno], &ies); - break; - case IAX_COMMAND_TXCNT: -- if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) && -- (iaxs[fr->callno]->transferid == ies.transferid)) { -- memcpy(&iaxs[fr->callno]->transfer, &sin, sizeof(iaxs[fr->callno]->transfer)); -- memset(&ied0, 0, sizeof(ied0)); -- iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid); -- send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, ied0.buf, ied0.pos); -- } -+ if (iaxs[fr->callno]->transferring) -+ send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0); - break; - case IAX_COMMAND_TXREL: -- if ((iaxs[fr->callno]->transferring == TRANSFER_READY) && -- (iaxs[fr->callno]->transferid == ies.transferid)) { - /* Send ack immediately, rather than waiting until we've changed addresses */ - send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno); - complete_transfer(fr->callno, &ies); -- stop_stuff(fr->callno); /* for attended transfer to work with libiax */ -- } -+ stop_stuff(fr->callno); /* for attended transfer to work with libiax */ - break; - case IAX_COMMAND_TXMEDIA: -- if ((iaxs[fr->callno]->transferring == TRANSFER_READY) && -- (iaxs[fr->callno]->transferid == ies.transferid)) { -- -+ if (iaxs[fr->callno]->transferring == TRANSFER_READY) { - AST_LIST_LOCK(&frame_queue); - AST_LIST_TRAVERSE(&frame_queue, cur, list) { - /* Cancel any outstanding frames and start anew */ -@@ -9645,10 +9775,7 @@ - } - AST_LIST_UNLOCK(&frame_queue); - /* Start sending our media to the transfer address, but otherwise leave the call as-is */ -- memcpy(&iaxs[fr->callno]->media, &iaxs[fr->callno]->transfer, sizeof(iaxs[fr->callno]->addr)); -- memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer)); -- iaxs[fr->callno]->transferring = TRANSFER_NONE; -- iaxs[fr->callno]->mediareleased = 1; -+ iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS; - } - break; - case IAX_COMMAND_RTKEY: -@@ -9772,6 +9899,31 @@ - ast_mutex_unlock(&iaxsl[fr->callno]); - return 1; - } -+ /* Don't allow connected line updates unless we are configured to */ -+ if (f.frametype == AST_FRAME_CONTROL && f.subclass == AST_CONTROL_CONNECTED_LINE) { -+ struct ast_party_connected_line connected; -+ -+ if (!ast_test_flag(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) { -+ ast_mutex_unlock(&iaxsl[fr->callno]); -+ return 1; -+ } -+ -+ /* Initialize defaults */ -+ ast_party_connected_line_init(&connected); -+ connected.id.number_presentation = iaxs[fr->callno]->calling_pres; -+ -+ if (!ast_parse_connected_line_data(f.data.ptr, f.datalen, &connected)) { -+ ast_string_field_set(iaxs[fr->callno], cid_num, connected.id.number); -+ ast_string_field_set(iaxs[fr->callno], cid_name, connected.id.name); -+ iaxs[fr->callno]->calling_pres = connected.id.number_presentation; -+ -+ if (iaxs[fr->callno]->owner) { -+ ast_set_callerid(iaxs[fr->callno]->owner, S_OR(connected.id.number, ""), S_OR(connected.id.name, ""), NULL); -+ iaxs[fr->callno]->owner->cid.cid_pres = connected.id.number_presentation; -+ } -+ } -+ ast_party_connected_line_free(&connected); -+ } - /* Common things */ - f.src = "IAX2"; - f.mallocd = 0; -@@ -9807,6 +9959,7 @@ - ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts); - #endif - } -+ - /* Always run again */ - ast_mutex_unlock(&iaxsl[fr->callno]); - return 1; -@@ -10056,11 +10209,6 @@ - } - - static char *papp = "IAX2Provision"; --static char *psyn = "Provision a calling IAXy with a given template"; --static char *pdescrip = --" IAX2Provision([template]): Provisions the calling IAXy (assuming\n" --"the calling entity is in fact an IAXy) with the given template or\n" --"default if one is not specified. Returns -1 on error or 0 on success.\n"; - - /*! iax2provision - \ingroup applications -@@ -10212,7 +10360,7 @@ - iaxs[peer->callno]->peerpoke = peer; - - if (peer->pokeexpire > -1) { -- if (!ast_sched_del(sched, peer->pokeexpire)) { -+ if (!ast_sched_thread_del(sched, peer->pokeexpire)) { - peer->pokeexpire = -1; - peer_unref(peer); - } -@@ -10271,7 +10419,7 @@ - memset(&cai, 0, sizeof(cai)); - cai.capability = iax2_capability; - -- ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_NOKEYROTATE); -+ ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); - - /* Populate our address from the given */ - if (create_addr(pds.peer, NULL, &sin, &cai)) { -@@ -10290,7 +10438,7 @@ - } - - /* If this is a trunk, update it now */ -- ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_NOKEYROTATE); -+ ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE); - if (ast_test_flag(&cai, IAX_TRUNK)) { - int new_callno; - if ((new_callno = make_trunk(callno, 1)) != -1) -@@ -10327,34 +10475,6 @@ - return c; - } - --static void *sched_thread(void *ignore) --{ -- int count; -- int res; -- struct timeval wait; -- struct timespec ts; -- -- for (;;) { -- pthread_testcancel(); -- ast_mutex_lock(&sched_lock); -- res = ast_sched_wait(sched); -- if ((res > 1000) || (res < 0)) -- res = 1000; -- wait = ast_tvadd(ast_tvnow(), ast_samp2tv(res, 1000)); -- ts.tv_sec = wait.tv_sec; -- ts.tv_nsec = wait.tv_usec * 1000; -- ast_cond_timedwait(&sched_cond, &sched_lock, &ts); -- ast_mutex_unlock(&sched_lock); -- pthread_testcancel(); -- -- count = ast_sched_runq(sched); -- if (count >= 20) -- ast_debug(1, "chan_iax2: ast_sched_runq ran %d scheduled tasks all at once\n", count); -- } -- -- return NULL; --} -- - static void *network_thread(void *ignore) - { - /* Our job is simple: Send queued messages, retrying if necessary. Read frames -@@ -10442,7 +10562,6 @@ - AST_LIST_UNLOCK(&idle_list); - } - } -- ast_pthread_create_background(&schedthreadid, NULL, sched_thread, NULL); - ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL); - ast_verb(2, "%d helper threads started\n", threadcount); - return 0; -@@ -10630,10 +10749,7 @@ - - if (peer) { - if (firstpass) { -- if (ast_test_flag(&globalflags, IAX_NOKEYROTATE)) { -- ast_copy_flags(peer, &globalflags, IAX_NOKEYROTATE); -- } -- ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); -+ ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); - peer->encmethods = iax2_encryption; - peer->adsi = adsi; - ast_string_field_set(peer,secret,""); -@@ -10682,12 +10798,19 @@ - } else if (!strcasecmp(v->name, "auth")) { - peer->authmethods = get_auth_methods(v->value); - } else if (!strcasecmp(v->name, "encryption")) { -- peer->encmethods = get_encrypt_methods(v->value); -- } else if (!strcasecmp(v->name, "keyrotate")) { -- if (ast_false(v->value)) -- ast_set_flag(peer, IAX_NOKEYROTATE); -- else -- ast_clear_flag(peer, IAX_NOKEYROTATE); -+ peer->encmethods |= get_encrypt_methods(v->value); -+ if (!peer->encmethods) { -+ ast_clear_flag(peer, IAX_FORCE_ENCRYPT); -+ } -+ } else if (!strcasecmp(v->name, "forceencryption")) { -+ if (ast_false(v->value)) { -+ ast_clear_flag(peer, IAX_FORCE_ENCRYPT); -+ } else { -+ peer->encmethods |= get_encrypt_methods(v->value); -+ if (peer->encmethods) { -+ ast_set_flag(peer, IAX_FORCE_ENCRYPT); -+ } -+ } - } else if (!strcasecmp(v->name, "transfer")) { - if (!strcasecmp(v->value, "mediaonly")) { - ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); -@@ -10715,7 +10838,7 @@ - } - } else { - /* Non-dynamic. Make sure we become that way if we're not */ -- AST_SCHED_DEL(sched, peer->expire); -+ ast_sched_thread_del(sched, peer->expire); - ast_clear_flag(peer, IAX_DYNAMIC); - if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL)) - return peer_unref(peer); -@@ -10799,6 +10922,20 @@ - ast_string_field_set(peer, zonetag, v->value); - } else if (!strcasecmp(v->name, "adsi")) { - peer->adsi = ast_true(v->value); -+ } else if (!strcasecmp(v->name, "connectedline")) { -+ if (ast_true(v->value)) { -+ ast_set_flag(peer, IAX_SENDCONNECTEDLINE); -+ ast_set_flag(peer, IAX_RECVCONNECTEDLINE); -+ } else if (!strcasecmp(v->value, "send")) { -+ ast_clear_flag(peer, IAX_RECVCONNECTEDLINE); -+ ast_set_flag(peer, IAX_SENDCONNECTEDLINE); -+ } else if (!strcasecmp(v->value, "receive")) { -+ ast_clear_flag(peer, IAX_SENDCONNECTEDLINE); -+ ast_set_flag(peer, IAX_RECVCONNECTEDLINE); -+ } else { -+ ast_clear_flag(peer, IAX_SENDCONNECTEDLINE); -+ ast_clear_flag(peer, IAX_RECVCONNECTEDLINE); -+ } - }/* else if (strcasecmp(v->name,"type")) */ - /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ - v = v->next; -@@ -10897,7 +11034,7 @@ - user->adsi = adsi; - ast_string_field_set(user, name, name); - ast_string_field_set(user, language, language); -- ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_NOKEYROTATE); -+ ast_copy_flags(user, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_CODEC_USER_FIRST | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT); - ast_clear_flag(user, IAX_HASCALLERID); - ast_string_field_set(user, cid_name, ""); - ast_string_field_set(user, cid_num, ""); -@@ -10936,18 +11073,25 @@ - } else if (!strcasecmp(v->name, "trunk")) { - ast_set2_flag(user, ast_true(v->value), IAX_TRUNK); - if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) { -- ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without DAHDI timing\n", user->name); -+ ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name); - ast_clear_flag(user, IAX_TRUNK); - } - } else if (!strcasecmp(v->name, "auth")) { - user->authmethods = get_auth_methods(v->value); - } else if (!strcasecmp(v->name, "encryption")) { -- user->encmethods = get_encrypt_methods(v->value); -- } else if (!strcasecmp(v->name, "keyrotate")) { -- if (ast_false(v->value)) -- ast_set_flag(user, IAX_NOKEYROTATE); -- else -- ast_clear_flag(user, IAX_NOKEYROTATE); -+ user->encmethods |= get_encrypt_methods(v->value); -+ if (!user->encmethods) { -+ ast_clear_flag(user, IAX_FORCE_ENCRYPT); -+ } -+ } else if (!strcasecmp(v->name, "forceencryption")) { -+ if (ast_false(v->value)) { -+ ast_clear_flag(user, IAX_FORCE_ENCRYPT); -+ } else { -+ user->encmethods |= get_encrypt_methods(v->value); -+ if (user->encmethods) { -+ ast_set_flag(user, IAX_FORCE_ENCRYPT); -+ } -+ } - } else if (!strcasecmp(v->name, "transfer")) { - if (!strcasecmp(v->value, "mediaonly")) { - ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); -@@ -10964,6 +11108,8 @@ - ast_set_flag(user, IAX_CODEC_NOCAP); - ast_set_flag(user, IAX_CODEC_NOPREFS); - } -+ } else if (!strcasecmp(v->name, "immediate")) { -+ ast_set2_flag(user, ast_true(v->value), IAX_IMMEDIATE); - } else if (!strcasecmp(v->name, "jitterbuffer")) { - ast_set2_flag(user, ast_true(v->value), IAX_USEJITTERBUF); - } else if (!strcasecmp(v->name, "forcejitterbuffer")) { -@@ -11033,6 +11179,20 @@ - user->maxauthreq = 0; - } else if (!strcasecmp(v->name, "adsi")) { - user->adsi = ast_true(v->value); -+ } else if (!strcasecmp(v->name, "connectedline")) { -+ if (ast_true(v->value)) { -+ ast_set_flag(user, IAX_SENDCONNECTEDLINE); -+ ast_set_flag(user, IAX_RECVCONNECTEDLINE); -+ } else if (!strcasecmp(v->value, "send")) { -+ ast_clear_flag(user, IAX_RECVCONNECTEDLINE); -+ ast_set_flag(user, IAX_SENDCONNECTEDLINE); -+ } else if (!strcasecmp(v->value, "receive")) { -+ ast_clear_flag(user, IAX_SENDCONNECTEDLINE); -+ ast_set_flag(user, IAX_RECVCONNECTEDLINE); -+ } else { -+ ast_clear_flag(user, IAX_SENDCONNECTEDLINE); -+ ast_clear_flag(user, IAX_RECVCONNECTEDLINE); -+ } - }/* else if (strcasecmp(v->name,"type")) */ - /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ - v = v->next; -@@ -11088,7 +11248,7 @@ - - AST_LIST_LOCK(®istrations); - while ((reg = AST_LIST_REMOVE_HEAD(®istrations, entry))) { -- AST_SCHED_DEL(sched, reg->expire); -+ ast_sched_thread_del(sched, reg->expire); - if (reg->callno) { - int callno = reg->callno; - ast_mutex_lock(&iaxsl[callno]); -@@ -11114,8 +11274,9 @@ - - i = ao2_iterator_init(users, 0); - while ((user = ao2_iterator_next(&i))) { -- if (ast_test_flag(user, IAX_DELME)) -+ if (ast_test_flag(user, IAX_DELME) || ast_test_flag(user, IAX_RTCACHEFRIENDS)) { - ao2_unlink(users, user); -+ } - user_unref(user); - } - } -@@ -11128,8 +11289,9 @@ - - i = ao2_iterator_init(peers, 0); - while ((peer = ao2_iterator_next(&i))) { -- if (ast_test_flag(peer, IAX_DELME)) -+ if (ast_test_flag(peer, IAX_DELME) || ast_test_flag(peer, IAX_RTCACHEFRIENDS)) { - unlink_peer(peer); -+ } - peer_unref(peer); - } - } -@@ -11148,6 +11310,8 @@ - ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA); - ast_clear_flag((&globalflags), IAX_USEJITTERBUF); - ast_clear_flag((&globalflags), IAX_FORCEJITTERBUF); -+ ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE); -+ ast_clear_flag((&globalflags), IAX_RECVCONNECTEDLINE); - delete_users(); - } - -@@ -11183,10 +11347,21 @@ - return 0; - /* Otherwise we need to reread both files */ - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- cfg = ast_config_load(config_file, config_flags); -+ if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config_file); -+ ast_config_destroy(ucfg); -+ return 0; -+ } -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config_file); -+ return 0; - } else { /* iax.conf changed, gotta reread users.conf, too */ - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- ucfg = ast_config_load("users.conf", config_flags); -+ if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Aborting.\n"); -+ ast_config_destroy(cfg); -+ return 0; -+ } - } - - if (reload) { -@@ -11199,7 +11374,7 @@ - /* Reset Global Flags */ - memset(&globalflags, 0, sizeof(globalflags)); - ast_set_flag(&globalflags, IAX_RTUPDATE); -- -+ - #ifdef SO_NO_CHECK - nochecksums = 0; - #endif -@@ -11305,15 +11480,22 @@ - ast_netsock_unref(ns); - } - } -- } else if (!strcasecmp(v->name, "authdebug")) -+ } else if (!strcasecmp(v->name, "authdebug")) { - authdebug = ast_true(v->value); -- else if (!strcasecmp(v->name, "encryption")) -- iax2_encryption = get_encrypt_methods(v->value); -- else if (!strcasecmp(v->name, "keyrotate")) { -- if (ast_false(v->value)) -- ast_set_flag((&globalflags), IAX_NOKEYROTATE); -- else -- ast_clear_flag((&globalflags), IAX_NOKEYROTATE); -+ } else if (!strcasecmp(v->name, "encryption")) { -+ iax2_encryption |= get_encrypt_methods(v->value); -+ if (!iax2_encryption) { -+ ast_clear_flag((&globalflags), IAX_FORCE_ENCRYPT); -+ } -+ } else if (!strcasecmp(v->name, "forceencryption")) { -+ if (ast_false(v->value)) { -+ ast_clear_flag((&globalflags), IAX_FORCE_ENCRYPT); -+ } else { -+ iax2_encryption |= get_encrypt_methods(v->value); -+ if (iax2_encryption) { -+ ast_set_flag((&globalflags), IAX_FORCE_ENCRYPT); -+ } -+ } - } else if (!strcasecmp(v->name, "transfer")) { - if (!strcasecmp(v->value, "mediaonly")) { - ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); -@@ -11433,6 +11615,20 @@ - adsi = ast_true(v->value); - } else if (!strcasecmp(v->name, "srvlookup")) { - srvlookup = ast_true(v->value); -+ } else if (!strcasecmp(v->name, "connectedline")) { -+ if (ast_true(v->value)) { -+ ast_set_flag((&globalflags), IAX_SENDCONNECTEDLINE); -+ ast_set_flag((&globalflags), IAX_RECVCONNECTEDLINE); -+ } else if (!strcasecmp(v->value, "send")) { -+ ast_clear_flag((&globalflags), IAX_RECVCONNECTEDLINE); -+ ast_set_flag((&globalflags), IAX_SENDCONNECTEDLINE); -+ } else if (!strcasecmp(v->value, "receive")) { -+ ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE); -+ ast_set_flag((&globalflags), IAX_RECVCONNECTEDLINE); -+ } else { -+ ast_clear_flag((&globalflags), IAX_SENDCONNECTEDLINE); -+ ast_clear_flag((&globalflags), IAX_RECVCONNECTEDLINE); -+ } - } /*else if (strcasecmp(v->name,"type")) */ - /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ - v = v->next; -@@ -12003,23 +12199,7 @@ - - struct ast_custom_function iaxpeer_function = { - .name = "IAXPEER", -- .synopsis = "Gets IAX peer information", -- .syntax = "IAXPEER([,item])", - .read = function_iaxpeer, -- .desc = "If peername specified, valid items are:\n" -- "- ip (default) The IP address.\n" -- "- status The peer's status (if qualify=yes)\n" -- "- mailbox The configured mailbox.\n" -- "- context The configured context.\n" -- "- expire The epoch time of the next expire.\n" -- "- dynamic Is it dynamic? (yes/no).\n" -- "- callerid_name The configured Caller ID name.\n" -- "- callerid_num The configured Caller ID number.\n" -- "- codecs The configured codecs.\n" -- "- codec[x] Preferred codec index number 'x' (beginning with zero).\n" -- "\n" -- "If CURRENTCHANNEL specified, returns IP address of current channel\n" -- "\n" - }; - - static int acf_channel_write(struct ast_channel *chan, const char *function, char *args, const char *value) -@@ -12276,21 +12456,13 @@ - /* Cancel the network thread, close the net socket */ - if (netthreadid != AST_PTHREADT_NULL) { - AST_LIST_LOCK(&frame_queue); -- ast_mutex_lock(&sched_lock); - pthread_cancel(netthreadid); -- ast_cond_signal(&sched_cond); -- ast_mutex_unlock(&sched_lock); /* Release the schedule lock resource */ - AST_LIST_UNLOCK(&frame_queue); - pthread_join(netthreadid, NULL); - } -- if (schedthreadid != AST_PTHREADT_NULL) { -- ast_mutex_lock(&sched_lock); -- pthread_cancel(schedthreadid); -- ast_cond_signal(&sched_cond); -- ast_mutex_unlock(&sched_lock); -- pthread_join(schedthreadid, NULL); -- } - -+ sched = ast_sched_thread_destroy(sched); -+ - /* Call for all threads to halt */ - AST_LIST_LOCK(&idle_list); - while ((thread = AST_LIST_REMOVE_HEAD(&idle_list, list))) -@@ -12321,13 +12493,13 @@ - ast_manager_unregister( "IAXpeers" ); - ast_manager_unregister( "IAXpeerlist" ); - ast_manager_unregister( "IAXnetstats" ); -+ ast_manager_unregister( "IAXregistry" ); - ast_unregister_application(papp); -- ast_cli_unregister_multiple(cli_iax2, sizeof(cli_iax2) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_iax2, ARRAY_LEN(cli_iax2)); - ast_unregister_switch(&iax2_switch); - ast_channel_unregister(&iax2_tech); - delete_users(); - iax_provision_unload(); -- sched_context_destroy(sched); - reload_firmware(1); - - for (x = 0; x < ARRAY_LEN(iaxsl); x++) { -@@ -12337,7 +12509,7 @@ - ao2_ref(peers, -1); - ao2_ref(users, -1); - ao2_ref(iax_peercallno_pvts, -1); -- -+ ao2_ref(iax_transfercallno_pvts, -1); - if (timingfd > -1) { - ast_timer_close(timingfd); - } -@@ -12384,6 +12556,23 @@ - pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0; - } - -+static int transfercallno_pvt_hash_cb(const void *obj, const int flags) -+{ -+ const struct chan_iax2_pvt *pvt = obj; -+ -+ return pvt->transfercallno; -+} -+ -+static int transfercallno_pvt_cmp_cb(void *obj, void *arg, int flags) -+{ -+ struct chan_iax2_pvt *pvt = obj, *pvt2 = arg; -+ -+ /* The frames_received field is used to hold whether we're matching -+ * against a full frame or not ... */ -+ -+ return match(&pvt2->transfer, pvt2->transfercallno, pvt2->callno, pvt, -+ pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0; -+} - /*! \brief Load IAX2 module, load configuraiton ---*/ - static int load_module(void) - { -@@ -12405,7 +12594,13 @@ - ao2_ref(users, -1); - return AST_MODULE_LOAD_FAILURE; - } -- -+ iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb); -+ if (!iax_transfercallno_pvts) { -+ ao2_ref(peers, -1); -+ ao2_ref(users, -1); -+ ao2_ref(iax_peercallno_pvts, -1); -+ return AST_MODULE_LOAD_FAILURE; -+ } - ast_custom_function_register(&iaxpeer_function); - ast_custom_function_register(&iaxvar_function); - -@@ -12419,23 +12614,21 @@ - ast_mutex_init(&iaxsl[x]); - } - -- ast_cond_init(&sched_cond, NULL); -- -- if (!(sched = sched_context_create())) { -- ast_log(LOG_ERROR, "Failed to create scheduler context\n"); -+ if (!(sched = ast_sched_thread_create())) { -+ ast_log(LOG_ERROR, "Failed to create scheduler thread\n"); - return AST_MODULE_LOAD_FAILURE; - } - - if (!(io = io_context_create())) { - ast_log(LOG_ERROR, "Failed to create I/O context\n"); -- sched_context_destroy(sched); -+ sched = ast_sched_thread_destroy(sched); - return AST_MODULE_LOAD_FAILURE; - } - - if (!(netsock = ast_netsock_list_alloc())) { - ast_log(LOG_ERROR, "Failed to create netsock list\n"); - io_context_destroy(io); -- sched_context_destroy(sched); -+ sched = ast_sched_thread_destroy(sched); - return AST_MODULE_LOAD_FAILURE; - } - ast_netsock_init(netsock); -@@ -12444,18 +12637,19 @@ - if (!outsock) { - ast_log(LOG_ERROR, "Could not allocate outsock list.\n"); - io_context_destroy(io); -- sched_context_destroy(sched); -+ sched = ast_sched_thread_destroy(sched); - return AST_MODULE_LOAD_FAILURE; - } - ast_netsock_init(outsock); - -- ast_cli_register_multiple(cli_iax2, sizeof(cli_iax2) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_iax2, ARRAY_LEN(cli_iax2)); - -- ast_register_application(papp, iax2_prov_app, psyn, pdescrip); -+ ast_register_application_xml(papp, iax2_prov_app); - - ast_manager_register( "IAXpeers", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peers, "List IAX Peers" ); - ast_manager_register( "IAXpeerlist", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peer_list, "List IAX Peers" ); - ast_manager_register( "IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats, "Show IAX Netstats" ); -+ ast_manager_register( "IAXregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_registry, "Show IAX registrations"); - - timingfd = ast_timer_open(); - if (timingfd > -1) { -Index: channels/chan_oss.c -=================================================================== ---- a/channels/chan_oss.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_oss.c (.../team/group/issue14292) (revision 178988) -@@ -34,7 +34,7 @@ - */ - - /*** MODULEINFO -- ossaudio -+ oss - ***/ - - #include "asterisk.h" -@@ -913,9 +913,9 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "console autoanswer [on|off]"; -+ e->command = "console {set|show} autoanswer [on|off]"; - e->usage = -- "Usage: console autoanswer [on|off]\n" -+ "Usage: console {set|show} autoanswer [on|off]\n" - " Enables or disables autoanswer feature. If used without\n" - " argument, displays the current on/off status of autoanswer.\n" - " The default value of autoanswer is in 'oss.conf'.\n"; -@@ -1202,7 +1202,7 @@ - { - switch (cmd) { - case CLI_INIT: -- e->command = "console active"; -+ e->command = "console {set|show} active []"; - e->usage = - "Usage: console active [device]\n" - " If used without a parameter, displays which device is the current\n" -@@ -1213,20 +1213,20 @@ - return NULL; - } - -- if (a->argc == 2) -+ if (a->argc == 3) - ast_cli(a->fd, "active console is [%s]\n", oss_active); -- else if (a->argc != 3) -+ else if (a->argc != 4) - return CLI_SHOWUSAGE; - else { - struct chan_oss_pvt *o; -- if (strcmp(a->argv[2], "show") == 0) { -+ if (strcmp(a->argv[3], "show") == 0) { - for (o = oss_default.next; o; o = o->next) - ast_cli(a->fd, "device [%s] exists\n", o->name); - return CLI_SUCCESS; - } -- o = find_desc(a->argv[2]); -+ o = find_desc(a->argv[3]); - if (o == NULL) -- ast_cli(a->fd, "No device [%s] exists\n", a->argv[2]); -+ ast_cli(a->fd, "No device [%s] exists\n", a->argv[3]); - else - oss_active = o->name; - } -@@ -1441,6 +1441,9 @@ - if (!(cfg = ast_config_load(config, config_flags))) { - ast_log(LOG_NOTICE, "Unable to load config %s\n", config); - return AST_MODULE_LOAD_DECLINE; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); -+ return AST_MODULE_LOAD_DECLINE; - } - - do { -@@ -1463,7 +1466,7 @@ - return AST_MODULE_LOAD_FAILURE; - } - -- ast_cli_register_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_oss, ARRAY_LEN(cli_oss)); - - return AST_MODULE_LOAD_SUCCESS; - } -@@ -1474,7 +1477,7 @@ - struct chan_oss_pvt *o, *next; - - ast_channel_unregister(&oss_tech); -- ast_cli_unregister_multiple(cli_oss, sizeof(cli_oss) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_oss, ARRAY_LEN(cli_oss)); - - o = oss_default.next; - while (o) { -Index: channels/chan_misdn.c -=================================================================== ---- a/channels/chan_misdn.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_misdn.c (.../team/group/issue14292) (revision 178988) -@@ -47,6 +47,7 @@ - #include - #include - #include -+#include - - #include "asterisk/channel.h" - #include "asterisk/config.h" -@@ -114,28 +115,27 @@ - ast_mutex_t release_lock; - - enum misdn_chan_state { -- MISDN_NOTHING=0, /*!< at beginning */ -- MISDN_WAITING4DIGS, /*!< when waiting for infos */ -- MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */ -- MISDN_INCOMING_SETUP, /*!< for incoming setups*/ -- MISDN_DIALING, /*!< when pbx_start */ -- MISDN_PROGRESS, /*!< we got a progress */ -- MISDN_PROCEEDING, /*!< we got a progress */ -- MISDN_CALLING, /*!< when misdn_call is called */ -- MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */ -- MISDN_ALERTING, /*!< when Alerting */ -- MISDN_BUSY, /*!< when BUSY */ -- MISDN_CONNECTED, /*!< when connected */ -- MISDN_PRECONNECTED, /*!< when connected */ -- MISDN_DISCONNECTED, /*!< when connected */ -- MISDN_RELEASED, /*!< when connected */ -- MISDN_BRIDGED, /*!< when bridged */ -- MISDN_CLEANING, /*!< when hangup from * but we were connected before */ -- MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP came from misdn */ -- MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */ -- MISDN_HOLDED, /*!< if this chan is holded */ -- MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */ -- -+ MISDN_NOTHING = 0, /*!< at beginning */ -+ MISDN_WAITING4DIGS, /*!< when waiting for info */ -+ MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */ -+ MISDN_INCOMING_SETUP, /*!< for incoming setup */ -+ MISDN_DIALING, /*!< when pbx_start */ -+ MISDN_PROGRESS, /*!< we have progress */ -+ MISDN_PROCEEDING, /*!< we have progress */ -+ MISDN_CALLING, /*!< when misdn_call is called */ -+ MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */ -+ MISDN_ALERTING, /*!< when Alerting */ -+ MISDN_BUSY, /*!< when BUSY */ -+ MISDN_CONNECTED, /*!< when connected */ -+ MISDN_PRECONNECTED, /*!< when connected */ -+ MISDN_DISCONNECTED, /*!< when connected */ -+ MISDN_RELEASED, /*!< when connected */ -+ MISDN_BRIDGED, /*!< when bridged */ -+ MISDN_CLEANING, /*!< when hangup from * but we were connected before */ -+ MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP came from misdn */ -+ MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */ -+ MISDN_HOLDED, /*!< when on hold */ -+ MISDN_HOLD_DISCONNECT, /*!< when on hold */ - }; - - #define ORG_AST 1 -@@ -196,7 +196,7 @@ - */ - int noautorespond_on_setup; - -- int norxtone; /* Boolean assigned values but the value is not used. */ -+ int norxtone; /*!< Boolean assigned values but the value is not used. */ - - /*! - * \brief TRUE if we are not to generate tones (Playtones) -@@ -341,8 +341,6 @@ - */ - char mohinterpret[MAX_MUSICCLASS]; - -- //int zero_read_cnt; /* Not used */ -- - /*! - * \brief Number of outgoing audio frames dropped since last debug gripe message. - */ -@@ -377,7 +375,7 @@ - * \brief Tone zone sound used for dialtone generation. - * \note Used as a boolean. Non-NULL to prod generation if enabled. - */ -- const struct tone_zone_sound *ts; -+ struct ast_tone_zone_sound *ts; - - /*! - * \brief Enables overlap dialing for the set amount of seconds. (0 = Disabled) -@@ -399,21 +397,20 @@ - * \brief Overlap timer start time. Timer restarted for every digit received. - */ - struct timeval overlap_tv; -- -- //struct chan_list *peer; /* Not used */ - - /*! - * \brief Next channel call record in the list. - */ - struct chan_list *next; -- //struct chan_list *prev; /* Not used */ -- //struct chan_list *first; /* Not used */ - }; - - -+int MAXTICS = 8; - -+ - void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch); - void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch); -+static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame); - - struct robin_list { - char *group; -@@ -425,12 +422,7 @@ - static struct robin_list *robin = NULL; - - -- --static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame); -- -- -- --static inline void free_robin_list_r (struct robin_list *r) -+static inline void free_robin_list_r(struct robin_list *r) - { - if (r) { - if (r->next) -@@ -441,22 +433,23 @@ - } - } - --static void free_robin_list ( void ) -+static void free_robin_list(void) - { - free_robin_list_r(robin); - robin = NULL; - } - --static struct robin_list* get_robin_position (char *group) -+static struct robin_list* get_robin_position(char *group) - { - struct robin_list *new; - struct robin_list *iter = robin; - for (; iter; iter = iter->next) { -- if (!strcasecmp(iter->group, group)) -+ if (!strcasecmp(iter->group, group)) { - return iter; -+ } - } - new = ast_calloc(1, sizeof(*new)); -- new->group = strndup(group, strlen(group)); -+ new->group = strdup(group); - new->channel = 1; - if (robin) { - new->next = robin; -@@ -491,7 +484,7 @@ - - static const char misdn_type[] = "mISDN"; - --static int tracing = 0 ; -+static int tracing = 0; - - /*! \brief Only alaw and mulaw is allowed for now */ - static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */ -@@ -503,7 +496,6 @@ - static int *misdn_in_calls; - static int *misdn_out_calls; - -- - struct chan_list dummy_cl; - - /*! -@@ -522,8 +514,6 @@ - static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc); - static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid); - -- -- - static int dialtone_indicate(struct chan_list *cl); - static int hanguptone_indicate(struct chan_list *cl); - static int stop_indicate(struct chan_list *cl); -@@ -538,10 +528,8 @@ - - int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len); - -+void debug_numtype(int port, int numtype, char *type); - --void debug_numplan(int port, int numplan, char *type); -- -- - int add_out_calls(int port); - int add_in_calls(int port); - -@@ -560,8 +548,10 @@ - { - struct chan_list *tmp; - -- for (tmp=cl_te; tmp; tmp = tmp->next) { -- if ( tmp->ast == ast ) return tmp; -+ for (tmp = cl_te; tmp; tmp = tmp->next) { -+ if (tmp->ast == ast) { -+ return tmp; -+ } - } - - return NULL; -@@ -571,8 +561,10 @@ - { - struct chan_list *tmp; - -- for (tmp=cl_te; tmp; tmp = tmp->next) { -- if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp; -+ for (tmp = cl_te; tmp; tmp = tmp->next) { -+ if (tmp->ast && strcmp(tmp->ast->name, name) == 0) { -+ return tmp; -+ } - } - - return NULL; -@@ -580,52 +572,620 @@ - - - --struct allowed_bearers { -- int cap; -- int val; -- char *name; -- int deprecated; --}; - --static struct allowed_bearers allowed_bearers_array[]= { -- {INFO_CAPABILITY_SPEECH,1,"speech"}, -- {INFO_CAPABILITY_AUDIO_3_1K,2,"3_1khz"}, -- {INFO_CAPABILITY_DIGITAL_UNRESTRICTED,4,"digital_unrestricted"}, -- {INFO_CAPABILITY_DIGITAL_RESTRICTED,8,"digital_restricted"}, -- {INFO_CAPABILITY_DIGITAL_RESTRICTED,8,"digital_restriced", 1}, /* Allow misspelling for backwards compatibility */ -- {INFO_CAPABILITY_VIDEO,16,"video"} --}; -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN type of number code to a string -+ * -+ * \param number_type mISDN type of number code. -+ * -+ * \return The mISDN type of number code as a string -+ */ -+static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type) -+{ -+ const char *str; - --static char *bearer2str(int cap) { -- static char *bearers[]={ -- "Speech", -- "Audio 3.1k", -- "Unres Digital", -- "Res Digital", -- "Video", -- "Unknown Bearer" -- }; -+ switch (number_type) { -+ default: -+ case NUMTYPE_UNKNOWN: -+ str = "Unknown"; -+ break; -+ -+ case NUMTYPE_INTERNATIONAL: -+ str = "International"; -+ break; -+ -+ case NUMTYPE_NATIONAL: -+ str = "National"; -+ break; -+ -+ case NUMTYPE_NETWORK_SPECIFIC: -+ str = "Network Specific"; -+ break; -+ -+ case NUMTYPE_SUBSCRIBER: -+ str = "Subscriber"; -+ break; -+ -+ case NUMTYPE_ABBREVIATED: -+ str = "Abbreviated"; -+ break; -+ } /* end switch */ -+ -+ return str; -+} /* end misdn_to_str_ton() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN type of number code to Asterisk type of number code -+ * -+ * \param number_type mISDN type of number code. -+ * -+ * \return Asterisk type of number code -+ */ -+static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type) -+{ -+ int ast_number_type; -+ -+ switch (number_type) { -+ default: -+ case NUMTYPE_UNKNOWN: -+ ast_number_type = NUMTYPE_UNKNOWN << 4; -+ break; -+ -+ case NUMTYPE_INTERNATIONAL: -+ ast_number_type = NUMTYPE_INTERNATIONAL << 4; -+ break; -+ -+ case NUMTYPE_NATIONAL: -+ ast_number_type = NUMTYPE_NATIONAL << 4; -+ break; -+ -+ case NUMTYPE_NETWORK_SPECIFIC: -+ ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4; -+ break; -+ -+ case NUMTYPE_SUBSCRIBER: -+ ast_number_type = NUMTYPE_SUBSCRIBER << 4; -+ break; -+ -+ case NUMTYPE_ABBREVIATED: -+ ast_number_type = NUMTYPE_ABBREVIATED << 4; -+ break; -+ } /* end switch */ -+ -+ return ast_number_type; -+} /* end misdn_to_ast_ton() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the Asterisk type of number code to mISDN type of number code -+ * -+ * \param ast_number_type Asterisk type of number code. -+ * -+ * \return mISDN type of number code -+ */ -+static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type) -+{ -+ enum mISDN_NUMBER_TYPE number_type; -+ -+ switch ((ast_number_type >> 4) & 0x07) { -+ default: -+ case NUMTYPE_UNKNOWN: -+ number_type = NUMTYPE_UNKNOWN; -+ break; -+ -+ case NUMTYPE_INTERNATIONAL: -+ number_type = NUMTYPE_INTERNATIONAL; -+ break; -+ -+ case NUMTYPE_NATIONAL: -+ number_type = NUMTYPE_NATIONAL; -+ break; -+ -+ case NUMTYPE_NETWORK_SPECIFIC: -+ number_type = NUMTYPE_NETWORK_SPECIFIC; -+ break; -+ -+ case NUMTYPE_SUBSCRIBER: -+ number_type = NUMTYPE_SUBSCRIBER; -+ break; -+ -+ case NUMTYPE_ABBREVIATED: -+ number_type = NUMTYPE_ABBREVIATED; -+ break; -+ } /* end switch */ -+ -+ return number_type; -+} /* end ast_to_misdn_ton() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN numbering plan code to a string -+ * -+ * \param number_plan mISDN numbering plan code. -+ * -+ * \return The mISDN numbering plan code as a string -+ */ -+static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan) -+{ -+ const char *str; -+ -+ switch (number_plan) { -+ default: -+ case NUMPLAN_UNKNOWN: -+ str = "Unknown"; -+ break; -+ -+ case NUMPLAN_ISDN: -+ str = "ISDN"; -+ break; -+ -+ case NUMPLAN_DATA: -+ str = "Data"; -+ break; -+ -+ case NUMPLAN_TELEX: -+ str = "Telex"; -+ break; -+ -+ case NUMPLAN_NATIONAL: -+ str = "National"; -+ break; -+ -+ case NUMPLAN_PRIVATE: -+ str = "Private"; -+ break; -+ } /* end switch */ -+ -+ return str; -+} /* end misdn_to_str_plan() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code -+ * -+ * \param number_plan mISDN numbering plan code. -+ * -+ * \return Asterisk numbering plan code -+ */ -+static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan) -+{ -+ int ast_number_plan; -+ -+ switch (number_plan) { -+ default: -+ case NUMPLAN_UNKNOWN: -+ ast_number_plan = NUMPLAN_UNKNOWN; -+ break; -+ -+ case NUMPLAN_ISDN: -+ ast_number_plan = NUMPLAN_ISDN; -+ break; -+ -+ case NUMPLAN_DATA: -+ ast_number_plan = NUMPLAN_DATA; -+ break; -+ -+ case NUMPLAN_TELEX: -+ ast_number_plan = NUMPLAN_TELEX; -+ break; -+ -+ case NUMPLAN_NATIONAL: -+ ast_number_plan = NUMPLAN_NATIONAL; -+ break; -+ -+ case NUMPLAN_PRIVATE: -+ ast_number_plan = NUMPLAN_PRIVATE; -+ break; -+ } /* end switch */ -+ -+ return ast_number_plan; -+} /* end misdn_to_ast_plan() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code -+ * -+ * \param ast_number_plan Asterisk numbering plan code. -+ * -+ * \return mISDN numbering plan code -+ */ -+static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan) -+{ -+ enum mISDN_NUMBER_PLAN number_plan; -+ -+ switch (ast_number_plan & 0x0F) { -+ default: -+ case NUMPLAN_UNKNOWN: -+ number_plan = NUMPLAN_UNKNOWN; -+ break; -+ -+ case NUMPLAN_ISDN: -+ number_plan = NUMPLAN_ISDN; -+ break; -+ -+ case NUMPLAN_DATA: -+ number_plan = NUMPLAN_DATA; -+ break; -+ -+ case NUMPLAN_TELEX: -+ number_plan = NUMPLAN_TELEX; -+ break; -+ -+ case NUMPLAN_NATIONAL: -+ number_plan = NUMPLAN_NATIONAL; -+ break; -+ -+ case NUMPLAN_PRIVATE: -+ number_plan = NUMPLAN_PRIVATE; -+ break; -+ } /* end switch */ -+ -+ return number_plan; -+} /* end ast_to_misdn_plan() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN presentation code to a string -+ * -+ * \param presentation mISDN number presentation restriction code. -+ * -+ * \return The mISDN presentation code as a string -+ */ -+static const char *misdn_to_str_pres(int presentation) -+{ -+ const char *str; -+ -+ switch (presentation) { -+ case 0: -+ str = "Allowed"; -+ break; -+ -+ case 1: -+ str = "Restricted"; -+ break; -+ -+ case 2: -+ str = "Unavailable"; -+ break; - -- switch (cap) { -- case INFO_CAPABILITY_SPEECH: -- return bearers[0]; -+ default: -+ str = "Unknown"; - break; -- case INFO_CAPABILITY_AUDIO_3_1K: -- return bearers[1]; -+ } /* end switch */ -+ -+ return str; -+} /* end misdn_to_str_pres() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN presentation code to Asterisk presentation code -+ * -+ * \param presentation mISDN number presentation restriction code. -+ * -+ * \return Asterisk presentation code -+ */ -+static int misdn_to_ast_pres(int presentation) -+{ -+ switch (presentation) { -+ default: -+ case 0: -+ presentation = AST_PRES_ALLOWED; - break; -- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: -- return bearers[2]; -+ -+ case 1: -+ presentation = AST_PRES_RESTRICTED; - break; -- case INFO_CAPABILITY_DIGITAL_RESTRICTED: -- return bearers[3]; -+ -+ case 2: -+ presentation = AST_PRES_UNAVAILABLE; - break; -- case INFO_CAPABILITY_VIDEO: -- return bearers[4]; -+ } /* end switch */ -+ -+ return presentation; -+} /* end misdn_to_ast_pres() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the Asterisk presentation code to mISDN presentation code -+ * -+ * \param presentation Asterisk number presentation restriction code. -+ * -+ * \return mISDN presentation code -+ */ -+static int ast_to_misdn_pres(int presentation) -+{ -+ switch (presentation & AST_PRES_RESTRICTION) { -+ default: -+ case AST_PRES_ALLOWED: -+ presentation = 0; - break; -+ -+ case AST_PRES_RESTRICTED: -+ presentation = 1; -+ break; -+ -+ case AST_PRES_UNAVAILABLE: -+ presentation = 2; -+ break; -+ } /* end switch */ -+ -+ return presentation; -+} /* end ast_to_misdn_pres() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN screening code to a string -+ * -+ * \param screening mISDN number screening code. -+ * -+ * \return The mISDN screening code as a string -+ */ -+static const char *misdn_to_str_screen(int screening) -+{ -+ const char *str; -+ -+ switch (screening) { -+ case 0: -+ str = "Unscreened"; -+ break; -+ -+ case 1: -+ str = "Passed Screen"; -+ break; -+ -+ case 2: -+ str = "Failed Screen"; -+ break; -+ -+ case 3: -+ str = "Network Number"; -+ break; -+ - default: -- return bearers[5]; -+ str = "Unknown"; - break; -- } -+ } /* end switch */ -+ -+ return str; -+} /* end misdn_to_str_screen() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN screening code to Asterisk screening code -+ * -+ * \param screening mISDN number screening code. -+ * -+ * \return Asterisk screening code -+ */ -+static int misdn_to_ast_screen(int screening) -+{ -+ switch (screening) { -+ default: -+ case 0: -+ screening = AST_PRES_USER_NUMBER_UNSCREENED; -+ break; -+ -+ case 1: -+ screening = AST_PRES_USER_NUMBER_PASSED_SCREEN; -+ break; -+ -+ case 2: -+ screening = AST_PRES_USER_NUMBER_FAILED_SCREEN; -+ break; -+ -+ case 3: -+ screening = AST_PRES_NETWORK_NUMBER; -+ break; -+ } /* end switch */ -+ -+ return screening; -+} /* end misdn_to_ast_screen() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the Asterisk screening code to mISDN screening code -+ * -+ * \param screening Asterisk number screening code. -+ * -+ * \return mISDN screening code -+ */ -+static int ast_to_misdn_screen(int screening) -+{ -+ switch (screening & AST_PRES_NUMBER_TYPE) { -+ default: -+ case AST_PRES_USER_NUMBER_UNSCREENED: -+ screening = 0; -+ break; -+ -+ case AST_PRES_USER_NUMBER_PASSED_SCREEN: -+ screening = 1; -+ break; -+ -+ case AST_PRES_USER_NUMBER_FAILED_SCREEN: -+ screening = 2; -+ break; -+ -+ case AST_PRES_NETWORK_NUMBER: -+ screening = 3; -+ break; -+ } /* end switch */ -+ -+ return screening; -+} /* end ast_to_misdn_screen() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code. -+ * -+ * \param ast Asterisk redirecting reason code. -+ * -+ * \return mISDN reason code -+ */ -+static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast) -+{ -+ unsigned index; -+ -+ static const struct misdn_reasons { -+ enum AST_REDIRECTING_REASON ast; -+ enum mISDN_REDIRECTING_REASON q931; -+ } misdn_reason_table[] = { -+ /* *INDENT-OFF* */ -+ { AST_REDIRECTING_REASON_UNKNOWN, mISDN_REDIRECTING_REASON_UNKNOWN }, -+ { AST_REDIRECTING_REASON_USER_BUSY, mISDN_REDIRECTING_REASON_CALL_FWD_BUSY }, -+ { AST_REDIRECTING_REASON_NO_ANSWER, mISDN_REDIRECTING_REASON_NO_REPLY }, -+ { AST_REDIRECTING_REASON_UNAVAILABLE, mISDN_REDIRECTING_REASON_NO_REPLY }, -+ { AST_REDIRECTING_REASON_UNCONDITIONAL, mISDN_REDIRECTING_REASON_CALL_FWD }, -+ { AST_REDIRECTING_REASON_TIME_OF_DAY, mISDN_REDIRECTING_REASON_UNKNOWN }, -+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN }, -+ { AST_REDIRECTING_REASON_DEFLECTION, mISDN_REDIRECTING_REASON_DEFLECTION }, -+ { AST_REDIRECTING_REASON_FOLLOW_ME, mISDN_REDIRECTING_REASON_UNKNOWN }, -+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, mISDN_REDIRECTING_REASON_OUT_OF_ORDER }, -+ { AST_REDIRECTING_REASON_AWAY, mISDN_REDIRECTING_REASON_UNKNOWN }, -+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, mISDN_REDIRECTING_REASON_CALL_FWD_DTE } -+ /* *INDENT-ON* */ -+ }; -+ -+ for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) { -+ if (misdn_reason_table[index].ast == ast) { -+ return misdn_reason_table[index].q931; -+ } -+ } /* end for */ -+ return mISDN_REDIRECTING_REASON_UNKNOWN; -+} /* end ast_to_misdn_reason() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code -+ * -+ * \param q931 mISDN redirecting reason code. -+ * -+ * \return Asterisk redirecting reason code -+ */ -+static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931) -+{ -+ enum AST_REDIRECTING_REASON ast; -+ -+ switch (q931) { -+ default: -+ case mISDN_REDIRECTING_REASON_UNKNOWN: -+ ast = AST_REDIRECTING_REASON_UNKNOWN; -+ break; -+ -+ case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY: -+ ast = AST_REDIRECTING_REASON_USER_BUSY; -+ break; -+ -+ case mISDN_REDIRECTING_REASON_NO_REPLY: -+ ast = AST_REDIRECTING_REASON_NO_ANSWER; -+ break; -+ -+ case mISDN_REDIRECTING_REASON_DEFLECTION: -+ ast = AST_REDIRECTING_REASON_DEFLECTION; -+ break; -+ -+ case mISDN_REDIRECTING_REASON_OUT_OF_ORDER: -+ ast = AST_REDIRECTING_REASON_OUT_OF_ORDER; -+ break; -+ -+ case mISDN_REDIRECTING_REASON_CALL_FWD_DTE: -+ ast = AST_REDIRECTING_REASON_CALL_FWD_DTE; -+ break; -+ -+ case mISDN_REDIRECTING_REASON_CALL_FWD: -+ ast = AST_REDIRECTING_REASON_UNCONDITIONAL; -+ break; -+ } /* end switch */ -+ -+ return ast; -+} /* end misdn_to_ast_reason() */ -+ -+ -+ -+struct allowed_bearers { -+ char *name; /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */ -+ char *display; /*!< Bearer capability displayable name */ -+ int cap; /*!< SETUP message bearer capability field code value */ -+ int deprecated; /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */ -+}; -+ -+/* *INDENT-OFF* */ -+static const struct allowed_bearers allowed_bearers_array[] = { -+ /* Name, Displayable Name Bearer Capability, Deprecated */ -+ { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 }, -+ { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 }, -+ { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 }, -+ { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 }, -+ { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 }, /* Allow misspelling for backwards compatibility */ -+ { "video", "Video", INFO_CAPABILITY_VIDEO, 0 } -+}; -+/* *INDENT-ON* */ -+ -+static const char *bearer2str(int cap) -+{ -+ unsigned index; -+ -+ for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) { -+ if (allowed_bearers_array[index].cap == cap) { -+ return allowed_bearers_array[index].display; -+ } -+ } /* end for */ -+ -+ return "Unknown Bearer"; - } - - -@@ -634,57 +1194,58 @@ - switch (fac->Function) { - #ifdef HAVE_MISDN_FAC_RESULT - case Fac_RESULT: -- chan_misdn_log(0, bc->port," --> Received RESULT Operation\n"); -+ chan_misdn_log(0, bc->port, " --> Received RESULT Operation\n"); - break; - #endif - #ifdef HAVE_MISDN_FAC_ERROR - case Fac_ERROR: -- chan_misdn_log(0, bc->port," --> Received Error Operation\n"); -- chan_misdn_log(0, bc->port," --> Value:%d Error:%s\n",fac->u.ERROR.errorValue, fac->u.ERROR.error); -+ chan_misdn_log(0, bc->port, " --> Received Error Operation\n"); -+ chan_misdn_log(0, bc->port, " --> Value:%d Error:%s\n", fac->u.ERROR.errorValue, fac->u.ERROR.error); - break; - #endif - case Fac_CD: -- chan_misdn_log(1,bc->port," --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber, -+ chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber, - fac->u.CDeflection.PresentationAllowed ? "yes" : "no"); - break; - case Fac_AOCDCurrency: -- if (fac->u.AOCDcur.chargeNotAvailable) -- chan_misdn_log(1,bc->port," --> AOCD currency: charge not available\n"); -- else if (fac->u.AOCDcur.freeOfCharge) -- chan_misdn_log(1,bc->port," --> AOCD currency: free of charge\n"); -- else if (fac->u.AOCDchu.billingId >= 0) -- chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n", -+ if (fac->u.AOCDcur.chargeNotAvailable) { -+ chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n"); -+ } else if (fac->u.AOCDcur.freeOfCharge) { -+ chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n"); -+ } else if (fac->u.AOCDchu.billingId >= 0) { -+ chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n", - fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier, - (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId); -- else -- chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n", -+ } else { -+ chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n", - fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier, - (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total"); -+ } - break; - case Fac_AOCDChargingUnit: -- if (fac->u.AOCDchu.chargeNotAvailable) -- chan_misdn_log(1,bc->port," --> AOCD charging unit: charge not available\n"); -- else if (fac->u.AOCDchu.freeOfCharge) -- chan_misdn_log(1,bc->port," --> AOCD charging unit: free of charge\n"); -- else if (fac->u.AOCDchu.billingId >= 0) -- chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n", -+ if (fac->u.AOCDchu.chargeNotAvailable) { -+ chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n"); -+ } else if (fac->u.AOCDchu.freeOfCharge) { -+ chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n"); -+ } else if (fac->u.AOCDchu.billingId >= 0) { -+ chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n", - fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId); -- else -- chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n", -+ } else { -+ chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n", - fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total"); -+ } - break; - case Fac_None: - default: -- chan_misdn_log(1,bc->port," --> unknown facility\n"); -+ chan_misdn_log(1, bc->port, " --> unknown facility\n"); - break; - } - } - - static void print_bearer(struct misdn_bchannel *bc) - { -+ chan_misdn_log(2, bc->port, " --> Bearer: %s\n", bearer2str(bc->capability)); - -- chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability)); -- - switch(bc->law) { - case INFO_CODEC_ALAW: - chan_misdn_log(2, bc->port, " --> Codec: Alaw\n"); -@@ -695,52 +1256,153 @@ - } - } - -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Prefix a string to another string in place. -+ * -+ * \param str_prefix String to prefix to the main string. -+ * \param str_main String to get the prefix added to it. -+ * \param size Buffer size of the main string (Includes null terminator). -+ * -+ * \note The str_main buffer size must be greater than one. -+ * -+ * \return Nothing -+ */ -+static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size) -+{ -+ size_t len_over; -+ size_t len_total; -+ size_t len_main; -+ size_t len_prefix; -+ -+ len_prefix = strlen(str_prefix); -+ if (!len_prefix) { -+ /* There is no prefix to prepend. */ -+ return; -+ } -+ len_main = strlen(str_main); -+ len_total = len_prefix + len_main; -+ if (size <= len_total) { -+ /* We need to truncate since the buffer is too small. */ -+ len_over = len_total + 1 - size; -+ if (len_over <= len_main) { -+ len_main -= len_over; -+ } else { -+ len_over -= len_main; -+ len_main = 0; -+ len_prefix -= len_over; -+ } -+ } -+ if (len_main) { -+ memmove(str_main + len_prefix, str_main, len_main); -+ } -+ memcpy(str_main, str_prefix, len_prefix); -+ str_main[len_prefix + len_main] = 0; -+} /* end misdn_prefix_string() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Add a configured prefix to the given number. -+ * -+ * \param port Logical port number -+ * \param number_type Type-of-number passed in. -+ * \param number Given number string to add prefix -+ * \param size Buffer size number string occupies. -+ * -+ * \return Nothing -+ */ -+static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size) -+{ -+ enum misdn_cfg_elements type_prefix; -+ char num_prefix[MISDN_MAX_NUMBER_LEN]; -+ -+ /* Get prefix string. */ -+ switch (number_type) { -+ case NUMTYPE_UNKNOWN: -+ type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN; -+ break; -+ case NUMTYPE_INTERNATIONAL: -+ type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL; -+ break; -+ case NUMTYPE_NATIONAL: -+ type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL; -+ break; -+ case NUMTYPE_NETWORK_SPECIFIC: -+ type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC; -+ break; -+ case NUMTYPE_SUBSCRIBER: -+ type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER; -+ break; -+ case NUMTYPE_ABBREVIATED: -+ type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED; -+ break; -+ default: -+ /* Type-of-number does not have a prefix that can be added. */ -+ return; -+ } /* end switch */ -+ misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix)); -+ -+ misdn_prefix_string(num_prefix, number, size); -+} /* end misdn_add_number_prefix() */ -+ - static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc) - { - char buf[128]; - -- if (!bc->AOCD_need_export || !ast) -+ if (!bc->AOCD_need_export || !ast) { - return; -+ } - - if (originator == ORG_AST) { - ast = ast_bridged_channel(ast); -- if (!ast) -+ if (!ast) { - return; -+ } - } - - switch (bc->AOCDtype) { - case Fac_AOCDCurrency: - pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency"); -- if (bc->AOCD.currency.chargeNotAvailable) -+ if (bc->AOCD.currency.chargeNotAvailable) { - pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no"); -- else { -+ } else { - pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes"); -- if (bc->AOCD.currency.freeOfCharge) -+ if (bc->AOCD.currency.freeOfCharge) { - pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes"); -- else { -+ } else { - pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no"); - if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) { - pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf); -- if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) -+ if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) { - pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf); -+ } - } - } - } - break; - case Fac_AOCDChargingUnit: - pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit"); -- if (bc->AOCD.chargingUnit.chargeNotAvailable) -+ if (bc->AOCD.chargingUnit.chargeNotAvailable) { - pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no"); -- else { -+ } else { - pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes"); -- if (bc->AOCD.chargingUnit.freeOfCharge) -+ if (bc->AOCD.chargingUnit.freeOfCharge) { - pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes"); -- else { -+ } else { - pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no"); - if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) { - pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf); -- if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) -+ if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) { - pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf); -+ } - } - } - } -@@ -755,9 +1417,10 @@ - /*************** Helpers END *************/ - - static void sighandler(int sig) --{} -+{ -+} - --static void* misdn_tasks_thread_func (void *data) -+static void *misdn_tasks_thread_func(void *data) - { - int wait; - struct sigaction sa; -@@ -772,16 +1435,18 @@ - - while (1) { - wait = ast_sched_wait(misdn_tasks); -- if (wait < 0) -+ if (wait < 0) { - wait = 8000; -- if (poll(NULL, 0, wait) < 0) -+ } -+ if (poll(NULL, 0, wait) < 0) { - chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n"); -+ } - ast_sched_runq(misdn_tasks); - } - return NULL; - } - --static void misdn_tasks_init (void) -+static void misdn_tasks_init(void) - { - sem_t blocker; - int i = 5; -@@ -800,7 +1465,7 @@ - sem_destroy(&blocker); - } - --static void misdn_tasks_destroy (void) -+static void misdn_tasks_destroy(void) - { - if (misdn_tasks) { - chan_misdn_log(4, 0, "Killing misdn_tasks thread\n"); -@@ -812,12 +1477,12 @@ - } - } - --static inline void misdn_tasks_wakeup (void) -+static inline void misdn_tasks_wakeup(void) - { - pthread_kill(misdn_tasks_thread, SIGUSR1); - } - --static inline int _misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data, int variable) -+static inline int _misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data, int variable) - { - int task_id; - -@@ -830,33 +1495,36 @@ - return task_id; - } - --static int misdn_tasks_add (int timeout, ast_sched_cb callback, const void *data) -+static int misdn_tasks_add(int timeout, ast_sched_cb callback, const void *data) - { - return _misdn_tasks_add_variable(timeout, callback, data, 0); - } - --static int misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data) -+static int misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data) - { - return _misdn_tasks_add_variable(timeout, callback, data, 1); - } - --static void misdn_tasks_remove (int task_id) -+static void misdn_tasks_remove(int task_id) - { - AST_SCHED_DEL(misdn_tasks, task_id); - } - --static int misdn_l1_task (const void *data) -+static int misdn_l1_task(const void *vdata) - { -- misdn_lib_isdn_l1watcher(*(int *)data); -- chan_misdn_log(5, *(int *)data, "L1watcher timeout\n"); -+ const int *data = vdata; -+ -+ misdn_lib_isdn_l1watcher(*data); -+ chan_misdn_log(5, *data, "L1watcher timeout\n"); - return 1; - } - --static int misdn_overlap_dial_task (const void *data) -+static int misdn_overlap_dial_task(const void *data) - { - struct timeval tv_end, tv_now; - int diff; -- struct chan_list *ch = (struct chan_list *)data; -+ struct chan_list *ch = (struct chan_list *) data; -+ char *dad; - - chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state); - -@@ -864,48 +1532,49 @@ - ch->overlap_dial_task = -1; - return 0; - } -- -+ - ast_mutex_lock(&ch->overlap_tv_lock); - tv_end = ch->overlap_tv; - ast_mutex_unlock(&ch->overlap_tv_lock); -- -+ - tv_end.tv_sec += ch->overlap_dial; - tv_now = ast_tvnow(); - - diff = ast_tvdiff_ms(tv_end, tv_now); -+ if (100 < diff) { -+ return diff; -+ } - -- if (diff <= 100) { -- char *dad=ch->bc->dad, sexten[]="s"; -- /* if we are 100ms near the timeout, we are satisfied.. */ -- stop_indicate(ch); -- -- if (ast_strlen_zero(ch->bc->dad)) { -- dad=sexten; -- strcpy(ch->ast->exten, sexten); -+ /* if we are 100ms near the timeout, we are satisfied.. */ -+ stop_indicate(ch); -+ -+ if (ast_strlen_zero(ch->bc->dialed.number)) { -+ dad = "s"; -+ strcpy(ch->ast->exten, dad); -+ } else { -+ dad = ch->bc->dialed.number; -+ } -+ -+ if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) { -+ ch->state = MISDN_DIALING; -+ if (pbx_start_chan(ch) < 0) { -+ chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n"); -+ goto misdn_overlap_dial_task_disconnect; - } -- -- if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) { -- ch->state=MISDN_DIALING; -- if (pbx_start_chan(ch) < 0) { -- chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n"); -- goto misdn_overlap_dial_task_disconnect; -- } -- } else { -+ } else { - misdn_overlap_dial_task_disconnect: -- hanguptone_indicate(ch); -- ch->bc->out_cause=1; -- ch->state=MISDN_CLEANING; -- misdn_lib_send_event(ch->bc, EVENT_DISCONNECT); -- } -- ch->overlap_dial_task = -1; -- return 0; -- } else -- return diff; -+ hanguptone_indicate(ch); -+ ch->bc->out_cause = AST_CAUSE_UNALLOCATED; -+ ch->state = MISDN_CLEANING; -+ misdn_lib_send_event(ch->bc, EVENT_DISCONNECT); -+ } -+ ch->overlap_dial_task = -1; -+ return 0; - } - --static void send_digit_to_chan(struct chan_list *cl, char digit ) -+static void send_digit_to_chan(struct chan_list *cl, char digit) - { -- static const char* dtmf_tones[] = { -+ static const char *dtmf_tones[] = { - "!941+1336/100,!0/100", /* 0 */ - "!697+1209/100,!0/100", /* 1 */ - "!697+1336/100,!0/100", /* 2 */ -@@ -921,18 +1590,19 @@ - "!852+1633/100,!0/100", /* C */ - "!941+1633/100,!0/100", /* D */ - "!941+1209/100,!0/100", /* * */ -- "!941+1477/100,!0/100" }; /* # */ -- struct ast_channel *chan=cl->ast; -+ "!941+1477/100,!0/100", /* # */ -+ }; -+ struct ast_channel *chan = cl->ast; - -- if (digit >= '0' && digit <='9') -- ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0); -- else if (digit >= 'A' && digit <= 'D') -- ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0); -- else if (digit == '*') -- ast_playtones_start(chan,0,dtmf_tones[14], 0); -- else if (digit == '#') -- ast_playtones_start(chan,0,dtmf_tones[15], 0); -- else { -+ if (digit >= '0' && digit <='9') { -+ ast_playtones_start(chan, 0, dtmf_tones[digit - '0'], 0); -+ } else if (digit >= 'A' && digit <= 'D') { -+ ast_playtones_start(chan, 0, dtmf_tones[digit - 'A' + 10], 0); -+ } else if (digit == '*') { -+ ast_playtones_start(chan, 0, dtmf_tones[14], 0); -+ } else if (digit == '#') { -+ ast_playtones_start(chan, 0, dtmf_tones[15], 0); -+ } else { - /* not handled */ - ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name); - } -@@ -945,40 +1615,51 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "misdn set debug"; -+ e->command = "misdn set debug [on|off]"; - e->usage = -- "Usage: misdn set debug [only] | [port [only]]\n" -+ "Usage: misdn set debug {on|off|} [only] | [port [only]]\n" - " Set the debug level of the mISDN channel.\n"; - return NULL; - case CLI_GENERATE: - return complete_debug_port(a); - } - -- if (a->argc < 4 || a->argc > 7) -+ if (a->argc < 4 || a->argc > 7) { - return CLI_SHOWUSAGE; -+ } - -- level = atoi(a->argv[3]); -+ if (!strcasecmp(a->argv[3], "on")) { -+ level = 1; -+ } else if (!strcasecmp(a->argv[3], "off")) { -+ level = 0; -+ } else if (isdigit(a->argv[3][0])) { -+ level = atoi(a->argv[3]); -+ } else { -+ return CLI_SHOWUSAGE; -+ } - - switch (a->argc) { -- case 4: -+ case 4: - case 5: - { -- int only = 0, i; -+ int i; -+ int only = 0; - if (a->argc == 5) { -- if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) -+ if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) { - return CLI_SHOWUSAGE; -- else -+ } else { - only = 1; -+ } - } - - for (i = 0; i <= max_ports; i++) { - misdn_debug[i] = level; - misdn_debug_only[i] = only; - } -- ast_cli(a->fd, "changing debug level for all ports to %d%s\n",misdn_debug[0], only?" (only)":""); -+ ast_cli(a->fd, "changing debug level for all ports to %d%s\n", misdn_debug[0], only ? " (only)" : ""); - } - break; -- case 6: -+ case 6: - case 7: - { - int port; -@@ -999,14 +1680,16 @@ - return 0; - } - if (a->argc == 7) { -- if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) -+ if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) { - return CLI_SHOWUSAGE; -- else -+ } else { - misdn_debug_only[port] = 1; -- } else -+ } -+ } else { - misdn_debug_only[port] = 0; -+ } - misdn_debug[port] = level; -- ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port]?" (only)":"", port); -+ ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port] ? " (only)" : "", port); - } - } - -@@ -1027,10 +1710,11 @@ - return NULL; - } - -- if (a->argc != 5) -+ if (a->argc != 5) { - return CLI_SHOWUSAGE; -+ } - -- /* Is this supposed to not do anything? */ -+ /* XXX Is this supposed to not do anything? XXX */ - - return CLI_SUCCESS; - } -@@ -1048,8 +1732,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - misdn_lib_port_block(atoi(a->argv[3])); - -@@ -1069,8 +1754,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - misdn_lib_port_unblock(atoi(a->argv[3])); - -@@ -1090,8 +1776,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - misdn_lib_port_restart(atoi(a->argv[3])); - -@@ -1111,8 +1798,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - misdn_lib_pid_restart(atoi(a->argv[3])); - -@@ -1132,8 +1820,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - misdn_lib_get_port_up(atoi(a->argv[3])); - -@@ -1153,8 +1842,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - misdn_lib_get_port_down(atoi(a->argv[3])); - -@@ -1173,17 +1863,17 @@ - term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp)); - misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def)); - -- if (elem < MISDN_CFG_LAST) -+ if (elem < MISDN_CFG_LAST) { - term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section)); -- else -+ } else { - term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section)); -+ } - -- if (*def) -+ if (*def) { - ast_cli(fd, "[%s] %s (Default: %s)\n\t%s\n", section, name, def, desc); -- else -+ } else { - ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc); -- -- return; -+ } - } - - static char *handle_cli_misdn_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -@@ -1209,10 +1899,11 @@ - if (!strcmp(a->argv[3], "description")) { - if (a->argc == 5) { - enum misdn_cfg_elements elem = misdn_cfg_get_elem(a->argv[4]); -- if (elem == MISDN_CFG_FIRST) -+ if (elem == MISDN_CFG_FIRST) { - ast_cli(a->fd, "Unknown element: %s\n", a->argv[4]); -- else -+ } else { - show_config_description(a->fd, elem); -+ } - return CLI_SUCCESS; - } - return CLI_SHOWUSAGE; -@@ -1279,27 +1970,29 @@ - }; - - static struct state_struct state_array[] = { -- {MISDN_NOTHING,"NOTHING"}, /* at beginning */ -- {MISDN_WAITING4DIGS,"WAITING4DIGS"}, /* when waiting for infos */ -- {MISDN_EXTCANTMATCH,"EXTCANTMATCH"}, /* when asterisk couldn't match our ext */ -- {MISDN_INCOMING_SETUP,"INCOMING SETUP"}, /* when pbx_start */ -- {MISDN_DIALING,"DIALING"}, /* when pbx_start */ -- {MISDN_PROGRESS,"PROGRESS"}, /* when pbx_start */ -- {MISDN_PROCEEDING,"PROCEEDING"}, /* when pbx_start */ -- {MISDN_CALLING,"CALLING"}, /* when misdn_call is called */ -- {MISDN_CALLING_ACKNOWLEDGE,"CALLING_ACKNOWLEDGE"}, /* when misdn_call is called */ -- {MISDN_ALERTING,"ALERTING"}, /* when Alerting */ -- {MISDN_BUSY,"BUSY"}, /* when BUSY */ -- {MISDN_CONNECTED,"CONNECTED"}, /* when connected */ -- {MISDN_PRECONNECTED,"PRECONNECTED"}, /* when connected */ -- {MISDN_DISCONNECTED,"DISCONNECTED"}, /* when connected */ -- {MISDN_RELEASED,"RELEASED"}, /* when connected */ -- {MISDN_BRIDGED,"BRIDGED"}, /* when bridged */ -- {MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */ -- {MISDN_HUNGUP_FROM_MISDN,"HUNGUP_FROM_MISDN"}, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ -- {MISDN_HOLDED,"HOLDED"}, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ -- {MISDN_HOLD_DISCONNECT,"HOLD_DISCONNECT"}, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ -- {MISDN_HUNGUP_FROM_AST,"HUNGUP_FROM_AST"} /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */ -+/* *INDENT-OFF* */ -+ { MISDN_NOTHING, "NOTHING" }, /* at beginning */ -+ { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */ -+ { MISDN_EXTCANTMATCH, "EXTCANTMATCH" }, /* when asterisk couldn't match our ext */ -+ { MISDN_INCOMING_SETUP, "INCOMING SETUP" }, /* when pbx_start */ -+ { MISDN_DIALING, "DIALING" }, /* when pbx_start */ -+ { MISDN_PROGRESS, "PROGRESS" }, /* when pbx_start */ -+ { MISDN_PROCEEDING, "PROCEEDING" }, /* when pbx_start */ -+ { MISDN_CALLING, "CALLING" }, /* when misdn_call is called */ -+ { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */ -+ { MISDN_ALERTING, "ALERTING" }, /* when Alerting */ -+ { MISDN_BUSY, "BUSY" }, /* when BUSY */ -+ { MISDN_CONNECTED, "CONNECTED" }, /* when connected */ -+ { MISDN_PRECONNECTED, "PRECONNECTED" }, /* when connected */ -+ { MISDN_DISCONNECTED, "DISCONNECTED" }, /* when connected */ -+ { MISDN_RELEASED, "RELEASED" }, /* when connected */ -+ { MISDN_BRIDGED, "BRIDGED" }, /* when bridged */ -+ { MISDN_CLEANING, "CLEANING" }, /* when hangup from * but we were connected before */ -+ { MISDN_HUNGUP_FROM_MISDN, "HUNGUP_FROM_MISDN" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ -+ { MISDN_HOLDED, "HOLDED" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ -+ { MISDN_HOLD_DISCONNECT, "HOLD_DISCONNECT" }, /* when DISCONNECT/RELEASE/REL_COMP came from misdn */ -+ { MISDN_HUNGUP_FROM_AST, "HUNGUP_FROM_AST" }, /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */ -+/* *INDENT-ON* */ - }; - - static const char *misdn_get_ch_state(struct chan_list *p) -@@ -1307,11 +2000,14 @@ - int i; - static char state[8]; - -- if( !p) return NULL; -+ if (!p) { -+ return NULL; -+ } - -- for (i = 0; i < sizeof(state_array) / sizeof(struct state_struct); i++) { -- if (state_array[i].state == p->state) -- return state_array[i].txt; -+ for (i = 0; i < ARRAY_LEN(state_array); i++) { -+ if (state_array[i].state == p->state) { -+ return state_array[i].txt; -+ } - } - - snprintf(state, sizeof(state), "%d", p->state) ; -@@ -1320,7 +2016,6 @@ - } - - -- - static void reload_config(void) - { - int i, cfg_debug; -@@ -1356,8 +2051,9 @@ - return NULL; - } - -- if (a->argc != 2) -+ if (a->argc != 2) { - return CLI_SHOWUSAGE; -+ } - - ast_cli(a->fd, "Reloading mISDN configuration\n"); - reload_config(); -@@ -1367,19 +2063,25 @@ - static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc) - { - struct ast_channel *ast = help->ast; -+ - ast_cli(fd, -- "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n", -- -- bc->pid, bc->port, bc->channel, -+ "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n" -+ " --> caller:\"%s\" <%s>\n" -+ " --> redirecting:\"%s\" <%s>\n" -+ " --> context:%s state:%s\n", -+ bc->pid, -+ bc->port, -+ bc->channel, - bc->nt ? "NT" : "TE", - help->originator == ORG_AST ? "*" : "I", -- ast ? ast->exten : NULL, -- ast ? ast->cid.cid_num : NULL, -- bc->rad, -- ast ? ast->context : NULL, -- misdn_get_ch_state(help) -- ); -- if (misdn_debug[bc->port] > 0) -+ ast ? ast->exten : "", -+ (ast && ast->cid.cid_name) ? ast->cid.cid_name : "", -+ (ast && ast->cid.cid_num) ? ast->cid.cid_num : "", -+ bc->redirecting.from.name, -+ bc->redirecting.from.number, -+ ast ? ast->context : "", -+ misdn_get_ch_state(help)); -+ if (misdn_debug[bc->port] > 0) { - ast_cli(fd, - " --> astname: %s\n" - " --> ch_l3id: %x\n" -@@ -1401,27 +2103,24 @@ - help->l3id, - help->addr, - bc->addr, -- bc ? bc->l3_id : -1, -+ bc->l3_id, - bc->display, -- - bc->active, - bc_state2str(bc->bc_state), - bearer2str(bc->capability), - #ifdef MISDN_1_2 - bc->pipeline, - #else -- bc->ec_enable, -+ bc->ec_enable, - #endif -- - help->norxtone, help->notxtone, -- bc->holded -- ); -- -+ bc->holded); -+ } - } - - static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -- struct chan_list *help = NULL; -+ struct chan_list *help; - - switch (cmd) { - case CLI_INIT: -@@ -1434,12 +2133,13 @@ - return NULL; - } - -- if (a->argc != 3) -+ if (a->argc != 3) { - return CLI_SHOWUSAGE; -+ } - - help = cl_te; - -- ast_cli(a->fd, "Channel List: %p\n", cl_te); -+ ast_cli(a->fd, "Channel List: %p\n", cl_te); - - for (; help; help = help->next) { - struct misdn_bchannel *bc = help->bc; -@@ -1453,23 +2153,26 @@ - continue; - } - -- if (misdn_debug[0] > 2) -+ if (misdn_debug[0] > 2) { - ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast); -+ } - if (bc) { - print_bc_info(a->fd, help, bc); - } else { - if (help->state == MISDN_HOLDED) { - ast_cli(a->fd, "ITS A HOLDED BC:\n"); - ast_cli(a->fd, " --> l3_id: %x\n" -- " --> dad:%s oad:%s\n" -- " --> hold_port: %d\n" -- " --> hold_channel: %d\n", -- help->l3id, -- ast->exten, -- ast->cid.cid_num, -- help->hold_info.port, -- help->hold_info.channel -- ); -+ " --> dialed:%s\n" -+ " --> caller:\"%s\" <%s>\n" -+ " --> hold_port: %d\n" -+ " --> hold_channel: %d\n", -+ help->l3id, -+ ast->exten, -+ ast->cid.cid_name ? ast->cid.cid_name : "", -+ ast->cid.cid_num ? ast->cid.cid_num : "", -+ help->hold_info.port, -+ help->hold_info.channel -+ ); - } else { - ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num); - } -@@ -1483,7 +2186,7 @@ - - static char *handle_cli_misdn_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -- struct chan_list *help = NULL; -+ struct chan_list *help; - - switch (cmd) { - case CLI_INIT: -@@ -1496,8 +2199,9 @@ - return complete_ch(a); - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - help = cl_te; - -@@ -1510,15 +2214,12 @@ - print_bc_info(a->fd, help, bc); - break; - } -- } -+ } - } - - return CLI_SUCCESS; - } - --ast_mutex_t lock; --int MAXTICS = 8; -- - static char *handle_cli_misdn_set_tics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { -@@ -1531,9 +2232,11 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - -+ /* XXX Wow, this does... a whole lot of nothing... XXX */ - MAXTICS = atoi(a->argv[3]); - - return CLI_SUCCESS; -@@ -1554,15 +2257,16 @@ - return NULL; - } - -- if (a->argc != 3) -+ if (a->argc != 3) { - return CLI_SHOWUSAGE; -+ } - - ast_cli(a->fd, "BEGIN STACK_LIST:\n"); - for (port = misdn_cfg_get_next_port(0); port > 0; - port = misdn_cfg_get_next_port(port)) { - char buf[128]; - get_show_stack_details(port, buf); -- ast_cli(a->fd," %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : ""); -+ ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : ""); - } - - return CLI_SUCCESS; -@@ -1583,8 +2287,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - ast_cli(a->fd, "Port\tin_calls\tout_calls\n"); - for (port = misdn_cfg_get_next_port(0); port > 0; -@@ -1612,8 +2317,9 @@ - return NULL; - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - port = atoi(a->argv[3]); - -@@ -1647,8 +2353,9 @@ - return complete_ch(a); - } - -- if (a->argc < 5) -+ if (a->argc < 5) { - return CLI_SHOWUSAGE; -+ } - - if (strstr(a->argv[3], "calldeflect")) { - if (a->argc < 6) { -@@ -1661,18 +2368,18 @@ - ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame); - tmp = get_chan_by_ast_name(channame); - if (!tmp) { -- ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n",nr, channame); -+ ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n", nr, channame); - return 0; - } - - if (strlen(nr) >= 15) { -- ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to 15 digits are allowed).\n",nr, channame); -+ ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to 15 digits are allowed).\n", nr, channame); - return 0; - } - tmp->bc->fac_out.Function = Fac_CD; -- ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber)); -+ ast_copy_string((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber)); - misdn_lib_send_event(tmp->bc, EVENT_FACILITY); -- } else if (strstr(a->argv[3],"CFActivate")) { -+ } else if (strstr(a->argv[3], "CFActivate")) { - if (a->argc < 7) { - ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n"); - return 0; -@@ -1686,16 +2393,16 @@ - ast_verbose("Sending CFActivate Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr); - - bc->fac_out.Function = Fac_CFActivate; -- bc->fac_out.u.CFActivate.BasicService = 0; //All Services -- bc->fac_out.u.CFActivate.Procedure = 0; //Unconditional -+ bc->fac_out.u.CFActivate.BasicService = 0; /* All Services */ -+ bc->fac_out.u.CFActivate.Procedure = 0; /* Unconditional */ - ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber)); - ast_copy_string((char *)bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber)); - - misdn_lib_send_event(bc, EVENT_FACILITY); -- } else if (strstr(a->argv[3],"CFDeactivate")) { -+ } else if (strstr(a->argv[3], "CFDeactivate")) { - - if (a->argc < 6) { -- ast_verbose("CFActivate requires 1 arg: FromNumber\n\n"); -+ ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n"); - return 0; - } - port = atoi(a->argv[4]); -@@ -1705,10 +2412,10 @@ - ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr); - - bc->fac_out.Function = Fac_CFDeactivate; -- bc->fac_out.u.CFDeactivate.BasicService = 0; //All Services -- bc->fac_out.u.CFDeactivate.Procedure = 0; //Unconditional -- -- ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber)); -+ bc->fac_out.u.CFDeactivate.BasicService = 0; /* All Services */ -+ bc->fac_out.u.CFDeactivate.Procedure = 0; /* Unconditional */ -+ ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber)); -+ - misdn_lib_send_event(bc, EVENT_FACILITY); - } - -@@ -1717,6 +2424,9 @@ - - static char *handle_cli_misdn_send_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -+ int port; -+ int channel; -+ - switch (cmd) { - case CLI_INIT: - e->command = "misdn send restart"; -@@ -1728,14 +2438,19 @@ - return NULL; - } - -- if (a->argc < 4 || a->argc > 5) -+ if (a->argc < 4 || a->argc > 5) { - return CLI_SHOWUSAGE; -+ } - -- if (a->argc == 5) -- misdn_lib_send_restart(atoi(a->argv[3]), atoi(a->argv[4])); -- else -- misdn_lib_send_restart(atoi(a->argv[3]), -1); -+ port = atoi(a->argv[3]); - -+ if (a->argc == 5) { -+ channel = atoi(a->argv[4]); -+ misdn_lib_send_restart(port, channel); -+ } else { -+ misdn_lib_send_restart(port, -1); -+ } -+ - return CLI_SUCCESS; - } - -@@ -1758,8 +2473,9 @@ - return complete_ch(a); - } - -- if (a->argc != 5) -+ if (a->argc != 5) { - return CLI_SHOWUSAGE; -+ } - - channame = a->argv[3]; - msg = a->argv[4]; -@@ -1803,8 +2519,9 @@ - return complete_ch(a); - } - -- if (a->argc != 4) -+ if (a->argc != 4) { - return CLI_SHOWUSAGE; -+ } - - channame = a->argv[3]; - -@@ -1816,7 +2533,7 @@ - return CLI_SUCCESS; - } - -- tmp->toggle_ec = tmp->toggle_ec?0:1; -+ tmp->toggle_ec = tmp->toggle_ec ? 0 : 1; - - if (tmp->toggle_ec) { - #ifdef MISDN_1_2 -@@ -1850,8 +2567,9 @@ - return complete_ch(a); - } - -- if (a->argc != 5) -+ if (a->argc != 5) { - return CLI_SHOWUSAGE; -+ } - - channame = a->argv[3]; - msg = a->argv[4]; -@@ -1875,21 +2593,24 @@ - return ast_complete_channels(a->line, a->word, a->pos, a->n, 3); - } - --static char *complete_debug_port (struct ast_cli_args *a) -+static char *complete_debug_port(struct ast_cli_args *a) - { -- if (a->n) -+ if (a->n) { - return NULL; -+ } - - switch (a->pos) { - case 4: -- if (a->word[0] == 'p') -+ if (a->word[0] == 'p') { - return ast_strdup("port"); -- else if (a->word[0] == 'o') -+ } else if (a->word[0] == 'o') { - return ast_strdup("only"); -+ } - break; - case 6: -- if (a->word[0] == 'o') -+ if (a->word[0] == 'o') { - return ast_strdup("only"); -+ } - break; - } - return NULL; -@@ -1905,12 +2626,15 @@ - - switch (a->pos) { - case 3: -- if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) -+ if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) { - return ast_strdup("description"); -- if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) -+ } -+ if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) { - return ast_strdup("descriptions"); -- if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) -+ } -+ if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) { - return ast_strdup("0"); -+ } - while ((port = misdn_cfg_get_next_port(port)) != -1) { - snprintf(buffer, sizeof(buffer), "%d", port); - if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) { -@@ -1921,19 +2645,23 @@ - case 4: - if (strstr(a->line, "description ")) { - for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) { -- if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) -+ if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) { - continue; -+ } - misdn_cfg_get_name(elem, buffer, sizeof(buffer)); - if (!wordlen || !strncmp(a->word, buffer, wordlen)) { -- if (++which > a->n) -+ if (++which > a->n) { - return ast_strdup(buffer); -+ } - } - } - } else if (strstr(a->line, "descriptions ")) { -- if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) -+ if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) { - return ast_strdup("general"); -- if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) -+ } -+ if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) { - return ast_strdup("ports"); -+ } - } - break; - } -@@ -1965,23 +2693,25 @@ - }; - - /*! \brief Updates caller ID information from config */ --static int update_config(struct chan_list *ch, int orig) -+static void update_config(struct chan_list *ch) - { - struct ast_channel *ast; - struct misdn_bchannel *bc; -- int port, hdlc = 0; -- int pres, screen; -+ int port; -+ int hdlc = 0; -+ int pres; -+ int screen; - - if (!ch) { - ast_log(LOG_WARNING, "Cannot configure without chanlist\n"); -- return -1; -+ return; - } - - ast = ch->ast; - bc = ch->bc; - if (! ast || ! bc) { - ast_log(LOG_WARNING, "Cannot configure without ast || bc\n"); -- return -1; -+ return; - } - - port = bc->port; -@@ -1989,7 +2719,6 @@ - chan_misdn_log(7, port, "update_config: Getting Config\n"); - - misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); -- - if (hdlc) { - switch (bc->capability) { - case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: -@@ -2005,53 +2734,18 @@ - misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen)); - chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen); - -- if ( (pres + screen) < 0 ) { -- -- chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres); -+ if (pres < 0 || screen < 0) { -+ chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number_presentation); - -- switch (ast->cid.cid_pres & 0x60) { -- -- case AST_PRES_RESTRICTED: -- bc->pres = 1; -- chan_misdn_log(2, port, " --> PRES: Restricted (0x1)\n"); -- break; -- case AST_PRES_UNAVAILABLE: -- bc->pres = 2; -- chan_misdn_log(2, port, " --> PRES: Unavailable (0x2)\n"); -- break; -- default: -- bc->pres = 0; -- chan_misdn_log(2, port, " --> PRES: Allowed (0x0)\n"); -- } -+ bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation); -+ chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation); - -- switch (ast->cid.cid_pres & 0x3) { -- -- case AST_PRES_USER_NUMBER_UNSCREENED: -- bc->screen = 0; -- chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); -- break; -- case AST_PRES_USER_NUMBER_PASSED_SCREEN: -- bc->screen = 1; -- chan_misdn_log(2, port, " --> SCREEN: Passed Screen (0x1)\n"); -- break; -- case AST_PRES_USER_NUMBER_FAILED_SCREEN: -- bc->screen = 2; -- chan_misdn_log(2, port, " --> SCREEN: Failed Screen (0x2)\n"); -- break; -- case AST_PRES_NETWORK_NUMBER: -- bc->screen = 3; -- chan_misdn_log(2, port, " --> SCREEN: Network Nr. (0x3)\n"); -- break; -- default: -- bc->screen = 0; -- chan_misdn_log(2, port, " --> SCREEN: Unscreened (0x0)\n"); -- } -+ bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation); -+ chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening); - } else { -- bc->screen = screen; -- bc->pres = pres; -+ bc->caller.screening = screen; -+ bc->caller.presentation = pres; - } -- -- return 0; - } - - -@@ -2071,7 +2765,7 @@ - len = 1000; - } - -- if ( threshold > len ) { -+ if (threshold > len) { - chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n"); - } - -@@ -2081,28 +2775,35 @@ - ch->jb = NULL; - } - -- ch->jb=misdn_jb_init(len, threshold); -+ ch->jb = misdn_jb_init(len, threshold); - -- if (!ch->jb ) -+ if (!ch->jb) { - bc->nojitter = 1; -+ } - } - } - - --void debug_numplan(int port, int numplan, char *type) -+void debug_numtype(int port, int numtype, char *type) - { -- switch (numplan) { -- case NUMPLAN_INTERNATIONAL: -+ switch (numtype) { -+ case NUMTYPE_UNKNOWN: -+ chan_misdn_log(2, port, " --> %s: Unknown\n", type); -+ break; -+ case NUMTYPE_INTERNATIONAL: - chan_misdn_log(2, port, " --> %s: International\n", type); - break; -- case NUMPLAN_NATIONAL: -+ case NUMTYPE_NATIONAL: - chan_misdn_log(2, port, " --> %s: National\n", type); - break; -- case NUMPLAN_SUBSCRIBER: -+ case NUMTYPE_NETWORK_SPECIFIC: -+ chan_misdn_log(2, port, " --> %s: Network Specific\n", type); -+ break; -+ case NUMTYPE_SUBSCRIBER: - chan_misdn_log(2, port, " --> %s: Subscriber\n", type); - break; -- case NUMPLAN_UNKNOWN: -- chan_misdn_log(2, port, " --> %s: Unknown\n", type); -+ case NUMTYPE_ABBREVIATED: -+ chan_misdn_log(2, port, " --> %s: Abbreviated\n", type); - break; - /* Maybe we should cut off the prefix if present ? */ - default: -@@ -2119,14 +2820,16 @@ - - misdn_cfg_get(bc->port, MISDN_CFG_PIPELINE, bc->pipeline, sizeof(bc->pipeline)); - -- if (*bc->pipeline) -+ if (*bc->pipeline) { - return 0; -+ } - - misdn_cfg_get(bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec)); -- if (ec == 1) -+ if (ec == 1) { - ast_copy_string(bc->pipeline, "mg2ec", sizeof(bc->pipeline)); -- else if (ec > 1) -+ } else if (ec > 1) { - snprintf(bc->pipeline, sizeof(bc->pipeline), "mg2ec(deftaps=%d)", ec); -+ } - - return 0; - } -@@ -2150,7 +2853,7 @@ - #endif - - --static int read_config(struct chan_list *ch, int orig) -+static int read_config(struct chan_list *ch) - { - struct ast_channel *ast; - struct misdn_bchannel *bc; -@@ -2190,10 +2893,9 @@ - - misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf)); - -- misdn_cfg_get( port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int)); -- -+ misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int)); - if (ch->ast_dsp) { -- ch->ignore_dtmf=1; -+ ch->ignore_dtmf = 1; - } - - misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(bc->need_more_infos)); -@@ -2208,7 +2910,6 @@ - misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect)); - - misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc)); -- - if (hdlc) { - switch (bc->capability) { - case INFO_CAPABILITY_DIGITAL_UNRESTRICTED: -@@ -2237,14 +2938,16 @@ - - misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect)); - -+ misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected)); -+ misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup)); -+ - misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); - misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); -- - chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg)); - ast->pickupgroup = pg; - ast->callgroup = cg; - -- if (orig == ORG_AST) { -+ if (ch->originator == ORG_AST) { - char callerid[BUFFERSIZE + 1]; - - /* ORIGINATOR Asterisk (outgoing call) */ -@@ -2252,90 +2955,51 @@ - misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(bc->te_choose_channel)); - - if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) { -- if (strstr(faxdetect, "nojump")) -- ch->faxdetect = 2; -- else -- ch->faxdetect = 1; -+ ch->faxdetect = strstr(faxdetect, "nojump") ? 2 : 1; - } - - misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid)); -- if ( ! ast_strlen_zero(callerid) ) { -- chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid); -- ast_copy_string(bc->oad, callerid, sizeof(bc->oad)); -+ if (!ast_strlen_zero(callerid)) { -+ char *cid_name = NULL; -+ char *cid_num = NULL; -+ -+ ast_callerid_parse(callerid, &cid_name, &cid_num); -+ if (cid_name) { -+ ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name)); -+ } else { -+ bc->caller.name[0] = 0; -+ } -+ if (cid_num) { -+ ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number)); -+ } else { -+ bc->caller.number[0] = 0; -+ } -+ chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number); - } - -- misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(bc->dnumplan)); -- misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(bc->onumplan)); -- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan)); -- debug_numplan(port, bc->dnumplan, "TON"); -- debug_numplan(port, bc->onumplan, "LTON"); -- debug_numplan(port, bc->cpnnumplan, "CTON"); -+ misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type)); -+ bc->dialed.number_plan = NUMPLAN_ISDN; -+ debug_numtype(port, bc->dialed.number_type, "TON"); - - ch->overlap_dial = 0; - } else { - /* ORIGINATOR MISDN (incoming call) */ -- char prefix[BUFFERSIZE + 1] = ""; - - if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) { -- if (strstr(faxdetect, "nojump")) -- ch->faxdetect = 2; -- else -- ch->faxdetect = 1; -+ ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1; - } - -- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan)); -- debug_numplan(port, bc->cpnnumplan, "CTON"); -+ /* Add configured prefix to caller.number */ -+ misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number)); - -- switch (bc->onumplan) { -- case NUMPLAN_INTERNATIONAL: -- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix)); -- break; -- -- case NUMPLAN_NATIONAL: -- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix)); -- break; -- default: -- break; -+ if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) { -+ ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number)); - } - -- ast_copy_string(buf, bc->oad, sizeof(buf)); -- snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf); -+ /* Add configured prefix to dialed.number */ -+ misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number)); - -- if (!ast_strlen_zero(bc->dad)) { -- ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad)); -- } -- -- if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) { -- ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad)); -- } -- -- prefix[0] = 0; -- -- switch (bc->dnumplan) { -- case NUMPLAN_INTERNATIONAL: -- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix)); -- break; -- case NUMPLAN_NATIONAL: -- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix)); -- break; -- default: -- break; -- } -- -- ast_copy_string(buf, bc->dad, sizeof(buf)); -- snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf); -- -- if (strcmp(bc->dad, ast->exten)) { -- ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten)); -- } -- -- ast_set_callerid(ast, bc->oad, NULL, bc->oad); -- -- if ( !ast_strlen_zero(bc->rad) ) { -- if (ast->cid.cid_rdnis) -- ast_free(ast->cid.cid_rdnis); -- ast->cid.cid_rdnis = ast_strdup(bc->rad); -- } -+ ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten)); - - misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial)); - ast_mutex_init(&ch->overlap_tv_lock); -@@ -2345,16 +3009,15 @@ - - if (ch->faxdetect || ch->ast_dsp) { - misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout)); -- if (!ch->dsp) -+ if (!ch->dsp) { - ch->dsp = ast_dsp_new(); -+ } - if (ch->dsp) { -- if (ch->faxdetect) -- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT); -- else -- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT ); -+ ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | (ch->faxdetect ? DSP_FEATURE_FAX_DETECT : 0)); - } -- if (!ch->trans) -+ if (!ch->trans) { - ch->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW); -+ } - } - - /* AOCD initialization */ -@@ -2364,6 +3027,87 @@ - } - - -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Notify peer that the connected line has changed. -+ * -+ * \param ast Current Asterisk channel -+ * \param bc Associated B channel -+ * \param originator Who originally created this channel. ORG_AST or ORG_MISDN -+ * -+ * \return Nothing -+ */ -+static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator) -+{ -+ int number_type; -+ -+ if (originator == ORG_MISDN) { -+ /* ORIGINATOR MISDN (incoming call) */ -+ -+ ast_copy_string(bc->connected.name, S_OR(ast->connected.id.name, ""), sizeof(bc->connected.name)); -+ ast_copy_string(bc->connected.number, S_OR(ast->connected.id.number, ""), sizeof(bc->connected.number)); -+ bc->connected.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation); -+ bc->connected.screening = ast_to_misdn_screen(ast->connected.id.number_presentation); -+ -+ misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type)); -+ if (number_type < 0) { -+ bc->connected.number_type = ast_to_misdn_ton(ast->connected.id.number_type); -+ bc->connected.number_plan = ast_to_misdn_plan(ast->connected.id.number_type); -+ } else { -+ /* Force us to send in CONNECT message */ -+ bc->connected.number_type = number_type; -+ bc->connected.number_plan = NUMPLAN_ISDN; -+ } -+ debug_numtype(bc->port, bc->connected.number_type, "CTON"); -+ } else { -+ /* ORIGINATOR Asterisk (outgoing call) */ -+ -+ ast_copy_string(bc->caller.name, S_OR(ast->connected.id.name, ""), sizeof(bc->caller.name)); -+ ast_copy_string(bc->caller.number, S_OR(ast->connected.id.number, ""), sizeof(bc->caller.number)); -+ bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number_presentation); -+ bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number_presentation); -+ -+ misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type)); -+ if (number_type < 0) { -+ bc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type); -+ bc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type); -+ } else { -+ /* Force us to send in SETUP message */ -+ bc->caller.number_type = number_type; -+ bc->caller.number_plan = NUMPLAN_ISDN; -+ } -+ debug_numtype(bc->port, bc->caller.number_type, "LTON"); -+ } -+} /* end misdn_update_connected_line() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Copy the redirecting info out of the Asterisk channel -+ * -+ * \param bc Associated B channel -+ * \param ast Current Asterisk channel -+ * -+ * \return Nothing -+ */ -+static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast) -+{ -+ ast_copy_string(bc->redirecting.from.name, S_OR(ast->redirecting.from.name, ""), sizeof(bc->redirecting.from.name)); -+ ast_copy_string(bc->redirecting.from.number, S_OR(ast->cid.cid_rdnis, ""), sizeof(bc->redirecting.from.number)); -+ bc->redirecting.from.presentation = ast_to_misdn_pres(ast->redirecting.from.number_presentation); -+ bc->redirecting.from.screening = ast_to_misdn_screen(ast->redirecting.from.number_presentation); -+ bc->redirecting.from.number_type = ast_to_misdn_ton(ast->redirecting.from.number_type); -+ bc->redirecting.from.number_plan = ast_to_misdn_plan(ast->redirecting.from.number_type); -+ bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason); -+} /* end misdn_copy_redirecting_from_ast() */ -+ -+ - /*****************************/ - /*** AST Indications Start ***/ - /*****************************/ -@@ -2374,76 +3118,97 @@ - int r; - int exceed; - int bridging; -- struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(ast); -+ int number_type; -+ struct chan_list *ch; - struct misdn_bchannel *newbc; -- char *opts = NULL, *ext, *tokb; -- char *dest_cp = ast_strdupa(dest); -+ char *dest_cp; - -- ext = strtok_r(dest_cp, "/", &tokb); -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(intf); /* The interface token is discarded. */ -+ AST_APP_ARG(ext); /* extension token */ -+ AST_APP_ARG(opts); /* options token */ -+ ); - -- if (ext) { -- ext = strtok_r(NULL, "/", &tokb); -- if (ext) { -- opts = strtok_r(NULL, "/", &tokb); -- } else { -- chan_misdn_log(0, 0, "misdn_call: No Extension given!\n"); -- return -1; -- } -- } -- - if (!ast) { - ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n"); - return -1; - } - -- if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest ) { -+ if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest) { - ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); - ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; - ast_setstate(ast, AST_STATE_DOWN); - return -1; - } - -+ ch = MISDN_ASTERISK_TECH_PVT(ast); - if (!ch) { -- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); -+ ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast->name); - ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; - ast_setstate(ast, AST_STATE_DOWN); - return -1; - } - - newbc = ch->bc; -- - if (!newbc) { -- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); -+ ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast->name); - ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; - ast_setstate(ast, AST_STATE_DOWN); - return -1; - } -+ -+ /* -+ * dest is ---v -+ * Dial(mISDN/g:group_name[/extension[/options]]) -+ * Dial(mISDN/port[:preselected_channel][/extension[/options]]) -+ * -+ * The dial extension could be empty if you are using MISDN_KEYPAD -+ * to control ISDN provider features. -+ */ -+ dest_cp = ast_strdupa(dest); -+ AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/'); -+ if (!args.ext) { -+ args.ext = ""; -+ } - - port = newbc->port; - -- if ((exceed = add_out_calls(port))) { -+ exceed = add_out_calls(port); -+ if (exceed != 0) { - char tmp[16]; - snprintf(tmp, sizeof(tmp), "%d", exceed); - pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp); -+ ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE; -+ ast_setstate(ast, AST_STATE_DOWN); - return -1; - } - - chan_misdn_log(1, port, "* CALL: %s\n", dest); - -- chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context); -+ chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context); - -- chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten); -- if (ast->exten) { -- ast_copy_string(ast->exten, ext, sizeof(ast->exten)); -- ast_copy_string(newbc->dad, ext, sizeof(newbc->dad)); -+ ast_copy_string(ast->exten, args.ext, sizeof(ast->exten)); -+ ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number)); -+ -+ if (ast_strlen_zero(newbc->caller.name) && !ast_strlen_zero(ast->connected.id.name)) { -+ ast_copy_string(newbc->caller.name, ast->connected.id.name, sizeof(newbc->caller.name)); -+ chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number); - } -+ if (ast_strlen_zero(newbc->caller.number) && !ast_strlen_zero(ast->connected.id.number)) { -+ ast_copy_string(newbc->caller.number, ast->connected.id.number, sizeof(newbc->caller.number)); -+ chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number); -+ } - -- ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad)); -- -- chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num); -- if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) { -- ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad)); -+ misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type)); -+ if (number_type < 0) { -+ newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number_type); -+ newbc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number_type); -+ } else { -+ /* Force us to send in SETUP message */ -+ newbc->caller.number_type = number_type; -+ newbc->caller.number_plan = NUMPLAN_ISDN; - } -+ debug_numtype(port, newbc->caller.number_type, "LTON"); - - newbc->capability = ast->transfercapability; - pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability)); -@@ -2451,18 +3216,24 @@ - chan_misdn_log(2, port, " --> * Call with flag Digital\n"); - } - -- /* update screening and presentation */ -- update_config(ch, ORG_AST); -- -- /* fill in some ies from channel vary*/ -+ /* update caller screening and presentation */ -+ update_config(ch); -+ -+ /* fill in some ies from channel dialplan variables */ - import_ch(ast, newbc, ch); - - /* Finally The Options Override Everything */ -- if (opts) -- misdn_set_opt_exec(ast, opts); -- else -+ if (!ast_strlen_zero(args.opts)) { -+ misdn_set_opt_exec(ast, args.opts); -+ } else { - chan_misdn_log(2, port, "NO OPTS GIVEN\n"); -+ } -+ if (newbc->set_presentation) { -+ newbc->caller.presentation = newbc->presentation; -+ } - -+ misdn_copy_redirecting_from_ast(newbc, ast); -+ - /*check for bridging*/ - misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging)); - if (bridging && ch->other_ch) { -@@ -2477,26 +3248,27 @@ - #endif - } - -- r = misdn_lib_send_event( newbc, EVENT_SETUP ); -+ r = misdn_lib_send_event(newbc, EVENT_SETUP); - - /** we should have l3id after sending setup **/ - ch->l3id = newbc->l3_id; - -- if ( r == -ENOCHAN ) { -+ if (r == -ENOCHAN) { - chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n"); - chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1); - ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; - ast_setstate(ast, AST_STATE_DOWN); - return -1; - } -- -+ - chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1); - - ast_setstate(ast, AST_STATE_DIALING); - ast->hangupcause = AST_CAUSE_NORMAL_CLEARING; -- -- if (newbc->nt) -+ -+ if (newbc->nt) { - stop_bc_tones(ch); -+ } - - ch->state = MISDN_CALLING; - -@@ -2509,8 +3281,10 @@ - struct chan_list *p; - const char *tmp; - -- if (!ast || ! (p = MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; -- -+ if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) { -+ return -1; -+ } -+ - chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n"); - - if (!p) { -@@ -2524,8 +3298,8 @@ - ast_queue_hangup_with_cause(ast, AST_CAUSE_PROTOCOL_ERROR); - } - -- tmp = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY"); -- -+ ast_channel_lock(ast); -+ tmp = pbx_builtin_getvar_helper(ast, "CRYPT_KEY"); - if (!ast_strlen_zero(tmp)) { - chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n"); - ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key)); -@@ -2540,16 +3314,27 @@ - p->bc->hdlc = 0; - p->bc->nojitter = 1; - } -+ ast_channel_unlock(ast); - - p->state = MISDN_CONNECTED; - stop_indicate(p); - -- if ( ast_strlen_zero(p->bc->cad) ) { -- chan_misdn_log(2,p->bc->port," --> empty cad using dad\n"); -- ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad)); -+ if (ast_strlen_zero(p->bc->connected.number)) { -+ chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n"); -+ ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number)); -+ -+ /* -+ * Use the misdn_set_opt() application to set the presentation -+ * before we answer or you can use the CONECTEDLINE() function -+ * to set everything before using the Answer() application. -+ */ -+ p->bc->connected.presentation = p->bc->presentation; -+ p->bc->connected.screening = 0; /* unscreened */ -+ p->bc->connected.number_type = p->bc->dialed.number_type; -+ p->bc->connected.number_plan = p->bc->dialed.number_plan; - } - -- misdn_lib_send_event( p->bc, EVENT_CONNECT); -+ misdn_lib_send_event(p->bc, EVENT_CONNECT); - start_bc_tones(p); - - return 0; -@@ -2566,9 +3351,11 @@ - struct chan_list *p; - struct misdn_bchannel *bc; - char buf[2] = { digit, 0 }; -- -- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) return -1; - -+ if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) { -+ return -1; -+ } -+ - bc = p->bc; - chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit); - -@@ -2579,26 +3366,30 @@ - - switch (p->state ) { - case MISDN_CALLING: -- if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) -+ if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) { - strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1); -+ } - break; - case MISDN_CALLING_ACKNOWLEDGE: - ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad)); -- if (strlen(bc->dad) < sizeof(bc->dad) - 1) -- strncat(bc->dad, buf, sizeof(bc->dad) - strlen(bc->dad) - 1); -- ast_copy_string(p->ast->exten, bc->dad, sizeof(p->ast->exten)); -- misdn_lib_send_event( bc, EVENT_INFORMATION); -+ if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) { -+ strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); -+ } -+ ast_copy_string(p->ast->exten, bc->dialed.number, sizeof(p->ast->exten)); -+ misdn_lib_send_event(bc, EVENT_INFORMATION); - break; -- default: -- /* Do not send Digits in CONNECTED State, when -- * the other side is too mISDN. */ -- if (p->other_ch ) -- return 0; -+ default: -+ /* Do not send Digits in CONNECTED State, when -+ * the other side is also mISDN. */ -+ if (p->other_ch) { -+ return 0; -+ } - -- if ( bc->send_dtmf ) -- send_digit_to_chan(p,digit); -+ if (bc->send_dtmf) { -+ send_digit_to_chan(p, digit); -+ } - break; --} -+ } - - return 0; - } -@@ -2608,7 +3399,9 @@ - { - struct chan_list *p; - -- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) )) return -1; -+ if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) { -+ return -1; -+ } - - chan_misdn_log(1, p->bc ? p->bc->port : 0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id); - -@@ -2638,7 +3431,7 @@ - - switch (cond) { - case AST_CONTROL_BUSY: -- chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid); - ast_setstate(ast, AST_STATE_BUSY); - - p->bc->out_cause = AST_CAUSE_USER_BUSY; -@@ -2650,22 +3443,22 @@ - } - return -1; - case AST_CONTROL_RING: -- chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc->pid); - return -1; - case AST_CONTROL_RINGING: -- chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc->pid); - switch (p->state) { - case MISDN_ALERTING: -- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc->pid); - break; - case MISDN_CONNECTED: -- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc->pid); - return -1; - default: - p->state = MISDN_ALERTING; -- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc->pid); - misdn_lib_send_event( p->bc, EVENT_ALERTING); -- -+ - if (p->other_ch && p->other_ch->bc) { - if (misdn_inband_avail(p->other_ch->bc)) { - chan_misdn_log(2, p->bc->port, " --> other End is mISDN and has inband info available\n"); -@@ -2678,38 +3471,39 @@ - } - } - -- chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc->pid); - ast_setstate(ast, AST_STATE_RING); -- -- if ( !p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio ) -+ -+ if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) { - chan_misdn_log(2, p->bc->port, " --> incoming_early_audio off\n"); -- else -+ } else { - return -1; -+ } - } - break; - case AST_CONTROL_ANSWER: -- chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc->pid); - start_bc_tones(p); - break; - case AST_CONTROL_TAKEOFFHOOK: -- chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc->pid); - return -1; - case AST_CONTROL_OFFHOOK: -- chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc->pid); - return -1; - case AST_CONTROL_FLASH: -- chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc->pid); - break; - case AST_CONTROL_PROGRESS: -- chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc->pid); - misdn_lib_send_event( p->bc, EVENT_PROGRESS); - break; - case AST_CONTROL_PROCEEDING: -- chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc->pid); - misdn_lib_send_event( p->bc, EVENT_PROCEEDING); - break; - case AST_CONTROL_CONGESTION: -- chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid); - - p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION; - start_bc_tones(p); -@@ -2720,23 +3514,33 @@ - } - break; - case -1 : -- chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid); - - stop_indicate(p); - -- if (p->state == MISDN_CONNECTED) -+ if (p->state == MISDN_CONNECTED) { - start_bc_tones(p); -+ } - break; - case AST_CONTROL_HOLD: - ast_moh_start(ast, data, p->mohinterpret); -- chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid); - break; - case AST_CONTROL_UNHOLD: - ast_moh_stop(ast); -- chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid); - break; -+ case AST_CONTROL_CONNECTED_LINE: -+ chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid); -+ misdn_update_connected_line(ast, p->bc, p->originator); -+ break; -+ case AST_CONTROL_REDIRECTING: -+ chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid); -+ misdn_copy_redirecting_from_ast(p->bc, ast); -+ break; - default: -- chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1); -+ chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid); -+ break; - } - - return 0; -@@ -2750,7 +3554,9 @@ - - ast_debug(1, "misdn_hangup(%s)\n", ast->name); - -- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1; -+ if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) { -+ return -1; -+ } - - if (!p) { - chan_misdn_log(3, 0, "misdn_hangup called, without chan_list obj.\n"); -@@ -2760,12 +3566,16 @@ - bc = p->bc; - - if (bc) { -- const char *tmp=pbx_builtin_getvar_helper(ast,"MISDN_USERUSER"); -+ const char *tmp; -+ -+ ast_channel_lock(ast); -+ tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER"); - if (tmp) { - ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp); - strcpy(bc->uu, tmp); -- bc->uulen=strlen(bc->uu); -+ bc->uulen = strlen(bc->uu); - } -+ ast_channel_unlock(ast); - } - - MISDN_ASTERISK_TECH_PVT(ast) = NULL; -@@ -2787,10 +3597,11 @@ - close(p->pipe[1]); - ast_free(p); - ast_mutex_unlock(&release_lock); -- -- if (bc) -+ -+ if (bc) { - misdn_lib_release(bc); -- -+ } -+ - return 0; - } - -@@ -2805,22 +3616,31 @@ - p->need_busy = 0; - - -- if (!p->bc->nt) -+ if (!p->bc->nt) { - stop_bc_tones(p); -+ } - - bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING; -- -- if ( (varcause = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE")) || -- (varcause = pbx_builtin_getvar_helper(ast, "PRI_CAUSE"))) { -+ -+ ast_channel_lock(ast); -+ if ((varcause = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE")) || -+ (varcause = pbx_builtin_getvar_helper(ast, "PRI_CAUSE"))) { - int tmpcause = atoi(varcause); - bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING; - } -- -- chan_misdn_log(1, bc->port, "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n", p->bc ? p->bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(p)); -+ ast_channel_unlock(ast); -+ -+ chan_misdn_log(1, bc->port, -+ "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n", -+ p->bc ? p->bc->pid : -1, -+ ast->context, -+ ast->exten, -+ ast->cid.cid_name ? ast->cid.cid_name : "", -+ ast->cid.cid_num ? ast->cid.cid_num : "", -+ misdn_get_ch_state(p)); - chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id); - chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause); - chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause); -- chan_misdn_log(2, bc->port, " --> state:%s\n", misdn_get_ch_state(p)); - - switch (p->state) { - case MISDN_INCOMING_SETUP: -@@ -2831,34 +3651,38 @@ - * */ - ast_log(LOG_NOTICE, "release channel, in CALLING/INCOMING_SETUP state.. no other events happened\n"); - release_chan(bc); -- misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE); -+ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE); - break; - case MISDN_HOLDED: - case MISDN_DIALING: - start_bc_tones(p); - hanguptone_indicate(p); -- -- p->state=MISDN_CLEANING; -- if (bc->need_disconnect) -- misdn_lib_send_event( bc, EVENT_DISCONNECT); -+ -+ p->state = MISDN_CLEANING; -+ if (bc->need_disconnect) { -+ misdn_lib_send_event(bc, EVENT_DISCONNECT); -+ } - break; - case MISDN_CALLING_ACKNOWLEDGE: - start_bc_tones(p); - hanguptone_indicate(p); -- -- if (bc->need_disconnect) -- misdn_lib_send_event( bc, EVENT_DISCONNECT); -+ -+ if (bc->need_disconnect) { -+ misdn_lib_send_event(bc, EVENT_DISCONNECT); -+ } - break; -- -+ - case MISDN_ALERTING: - case MISDN_PROGRESS: - case MISDN_PROCEEDING: -- if (p->originator != ORG_AST) -+ if (p->originator != ORG_AST) { - hanguptone_indicate(p); -- -+ } -+ - /*p->state=MISDN_CLEANING;*/ -- if (bc->need_disconnect) -- misdn_lib_send_event( bc, EVENT_DISCONNECT); -+ if (bc->need_disconnect) { -+ misdn_lib_send_event(bc, EVENT_DISCONNECT); -+ } - break; - case MISDN_CONNECTED: - case MISDN_PRECONNECTED: -@@ -2866,16 +3690,18 @@ - if (p->bc->nt) { - start_bc_tones(p); - hanguptone_indicate(p); -- p->bc->progress_indicator = 8; -+ p->bc->progress_indicator = INFO_PI_INBAND_AVAILABLE; - } -- if (bc->need_disconnect) -- misdn_lib_send_event( bc, EVENT_DISCONNECT); -+ if (bc->need_disconnect) { -+ misdn_lib_send_event(bc, EVENT_DISCONNECT); -+ } - - /*p->state=MISDN_CLEANING;*/ - break; - case MISDN_DISCONNECTED: -- if (bc->need_release) -- misdn_lib_send_event( bc, EVENT_RELEASE); -+ if (bc->need_release) { -+ misdn_lib_send_event(bc, EVENT_RELEASE); -+ } - p->state = MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */ - break; - -@@ -2886,31 +3712,34 @@ - - case MISDN_BUSY: - break; -- -+ - case MISDN_HOLD_DISCONNECT: - /* need to send release here */ - chan_misdn_log(1, bc->port, " --> cause %d\n", bc->cause); - chan_misdn_log(1, bc->port, " --> out_cause %d\n", bc->out_cause); - - bc->out_cause = -1; -- if (bc->need_release) -+ if (bc->need_release) { - misdn_lib_send_event(bc, EVENT_RELEASE); -+ } - p->state = MISDN_CLEANING; - break; - default: - if (bc->nt) { - bc->out_cause = -1; -- if (bc->need_release) -+ if (bc->need_release) { - misdn_lib_send_event(bc, EVENT_RELEASE); -+ } - p->state = MISDN_CLEANING; - } else { -- if (bc->need_disconnect) -+ if (bc->need_disconnect) { - misdn_lib_send_event(bc, EVENT_DISCONNECT); -+ } - } - } - - p->state = MISDN_CLEANING; -- -+ - chan_misdn_log(3, bc->port, " --> Channel: %s hanguped new state:%s\n", ast->name, misdn_get_ch_state(p)); - - return 0; -@@ -2962,10 +3791,12 @@ - ast_verb(3, "Redirecting %s to fax extension (context:%s)\n", ast->name, context); - /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ - pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten); -- if (ast_async_goto(ast, context, "fax", 1)) -+ if (ast_async_goto(ast, context, "fax", 1)) { - ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context); -- } else -- ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten); -+ } -+ } else { -+ ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten); -+ } - } else { - ast_debug(1, "Already in a fax extension, not redirecting\n"); - } -@@ -2991,7 +3822,7 @@ - { - struct chan_list *tmp; - fd_set rrfs; -- struct timeval tv; -+ struct timeval tv = { 0, 20000 }; - int len, t; - - if (!ast) { -@@ -3008,30 +3839,26 @@ - return NULL; - } - -- tv.tv_sec=0; -- tv.tv_usec=20000; -- - FD_ZERO(&rrfs); -- FD_SET(tmp->pipe[0],&rrfs); -+ FD_SET(tmp->pipe[0], &rrfs); - -- t=select(FD_SETSIZE,&rrfs,NULL, NULL,&tv); -- -+ t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv); - if (!t) { - chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n"); -- len=160; -+ len = 160; - } - -- if (t<0) { -- chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n",strerror(errno)); -+ if (t < 0) { -+ chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n", strerror(errno)); - return NULL; - } - -- if (FD_ISSET(tmp->pipe[0],&rrfs)) { -- len=read(tmp->pipe[0],tmp->ast_rd_buf,sizeof(tmp->ast_rd_buf)); -+ if (FD_ISSET(tmp->pipe[0], &rrfs)) { -+ len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf)); - -- if (len<=0) { -+ if (len <= 0) { - /* we hangup here, since our pipe is closed */ -- chan_misdn_log(2,tmp->bc->port,"misdn_read: Pipe closed, hanging up\n"); -+ chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n"); - return NULL; - } - -@@ -3045,7 +3872,7 @@ - tmp->frame.samples = len; - tmp->frame.mallocd = 0; - tmp->frame.offset = 0; -- tmp->frame.delivery = ast_tv(0,0); -+ tmp->frame.delivery = ast_tv(0, 0); - tmp->frame.src = NULL; - tmp->frame.data.ptr = tmp->ast_rd_buf; - -@@ -3072,10 +3899,11 @@ - return process_ast_dsp(tmp, &tmp->frame); - } - } else { -- if (tmp->ast_dsp) -+ if (tmp->ast_dsp) { - return process_ast_dsp(tmp, &tmp->frame); -- else -+ } else { - return &tmp->frame; -+ } - } - } - -@@ -3085,7 +3913,9 @@ - struct chan_list *ch; - int i = 0; - -- if (!ast || ! (ch = MISDN_ASTERISK_TECH_PVT(ast)) ) return -1; -+ if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) { -+ return -1; -+ } - - if (ch->state == MISDN_HOLDED) { - chan_misdn_log(7, 0, "misdn_write: Returning because holded\n"); -@@ -3109,7 +3939,6 @@ - } - - if (!(frame->subclass & prefformat)) { -- - chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass); - return 0; - } -@@ -3131,7 +3960,7 @@ - return -1; - } - -- if ( ! ch->bc->addr ) { -+ if (!ch->bc->addr) { - chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples); - return 0; - } -@@ -3142,8 +3971,9 @@ - - ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples); - -- for (i = 0; i < max ; i++) -- ast_debug(1, "%2.2x ", ((char*) frame->data.ptr)[i]); -+ for (i = 0; i < max; i++) { -+ ast_debug(1, "%2.2x ", ((char *) frame->data.ptr)[i]); -+ } - } - #endif - -@@ -3152,11 +3982,11 @@ - case BCHAN_BRIDGED: - break; - default: -- if (!ch->dropped_frame_cnt) -+ if (!ch->dropped_frame_cnt) { - chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n", frame->samples, ch->bc->addr, ast->exten, ast->cid.cid_num, misdn_get_ch_state( ch), ch->bc->bc_state, ch->bc->l3_id); -+ } - -- ch->dropped_frame_cnt++; -- if (ch->dropped_frame_cnt > 100) { -+ if (++ch->dropped_frame_cnt > 100) { - ch->dropped_frame_cnt = 0; - chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x dropped > 100 frames!\n", frame->samples, ch->bc->addr); - } -@@ -3164,17 +3994,18 @@ - return 0; - } - -- chan_misdn_log(9, ch->bc->port, "Sending :%d bytes 2 MISDN\n", frame->samples); -- if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) { -+ chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples); -+ if (!ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability)) { - /* Buffered Transmit (triggered by read from isdn side)*/ - if (misdn_jb_fill(ch->jb, frame->data.ptr, frame->samples) < 0) { -- if (ch->bc->active) -+ if (ch->bc->active) { - cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n"); -+ } - } - - } else { - /*transmit without jitterbuffer*/ -- i=misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples); -+ i = misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples); - } - - return 0; -@@ -3183,12 +4014,11 @@ - - - --static enum ast_bridge_result misdn_bridge (struct ast_channel *c0, -- struct ast_channel *c1, int flags, -- struct ast_frame **fo, -- struct ast_channel **rc, -- int timeoutms) -- -+static enum ast_bridge_result misdn_bridge(struct ast_channel *c0, -+ struct ast_channel *c1, int flags, -+ struct ast_frame **fo, -+ struct ast_channel **rc, -+ int timeoutms) - { - struct chan_list *ch1, *ch2; - struct ast_channel *carr[2], *who; -@@ -3203,8 +4033,9 @@ - carr[0] = c0; - carr[1] = c1; - -- if (!(ch1 && ch2)) -+ if (!(ch1 && ch2)) { - return -1; -+ } - - misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b)); - misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b)); -@@ -3223,13 +4054,19 @@ - - ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name); - -- chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad); -+ chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n", -+ ch1->bc->caller.name, -+ ch1->bc->caller.number, -+ ch2->bc->caller.name, -+ ch2->bc->caller.number); - -- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) -+ if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) { - ch1->ignore_dtmf = 1; -+ } - -- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_1) ) -+ if (! (flags & AST_BRIDGE_DTMF_CHANNEL_1) ) { - ch2->ignore_dtmf = 1; -+ } - - for (;/*ever*/;) { - to = -1; -@@ -3270,12 +4107,7 @@ - } - #endif - -- if (who == c0) { -- ast_write(c1, f); -- } -- else { -- ast_write(c0, f); -- } -+ ast_write((who == c0) ? c1 : c0, f); - } - - chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1); -@@ -3289,7 +4121,6 @@ - - static int dialtone_indicate(struct chan_list *cl) - { -- const struct tone_zone_sound *ts = NULL; - struct ast_channel *ast = cl->ast; - int nd = 0; - -@@ -3306,14 +4137,14 @@ - } - - chan_misdn_log(3, cl->bc->port, " --> Dial\n"); -- ts = ast_get_indication_tone(ast->zone, "dial"); -- cl->ts = ts; -+ -+ cl->ts = ast_get_indication_tone(ast->zone, "dial"); - -- if (ts) { -+ if (cl->ts) { - cl->notxtone = 0; - cl->norxtone = 0; - /* This prods us in misdn_write */ -- ast_playtones_start(ast, 0, ts->data, 0); -+ ast_playtones_start(ast, 0, cl->ts->data, 0); - } - - return 0; -@@ -3338,8 +4169,9 @@ - misdn_lib_tone_generator_stop(cl->bc); - ast_playtones_stop(ast); - -- cl->ts = NULL; -- /*ast_deactivate_generator(ast);*/ -+ if (cl->ts) { -+ cl->ts = ast_tone_zone_sound_unref(cl->ts); -+ } - - return 0; - } -@@ -3355,7 +4187,9 @@ - - static int stop_bc_tones(struct chan_list *cl) - { -- if (!cl) return -1; -+ if (!cl) { -+ return -1; -+ } - - cl->notxtone = 1; - cl->norxtone = 1; -@@ -3369,7 +4203,6 @@ - struct chan_list *cl; - - cl = ast_calloc(1, sizeof(*cl)); -- - if (!cl) { - chan_misdn_log(-1, 0, "misdn_request: malloc failed!"); - return NULL; -@@ -3388,43 +4221,59 @@ - { - struct ast_channel *tmp = NULL; - char group[BUFFERSIZE + 1] = ""; -- char buf[128]; -- char *buf2 = ast_strdupa(data), *ext = NULL, *port_str; -- char *tokb = NULL, *p = NULL; -- int channel = 0, port = 0; -+ char dial_str[128]; -+ char *dest_cp; -+ char *p = NULL; -+ int channel = 0; -+ int port = 0; - struct misdn_bchannel *newbc = NULL; - int dec = 0; -+ struct chan_list *cl; - -- struct chan_list *cl = init_chan_list(ORG_AST); -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(intf); /* interface token */ -+ AST_APP_ARG(ext); /* extension token */ -+ AST_APP_ARG(opts); /* options token */ -+ ); - -- snprintf(buf, sizeof(buf), "%s/%s", misdn_type, (char*)data); -+ snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data); - -- port_str = strtok_r(buf2, "/", &tokb); -+ /* -+ * data is ---v -+ * Dial(mISDN/g:group_name[/extension[/options]]) -+ * Dial(mISDN/port[:preselected_channel][/extension[/options]]) -+ * -+ * The dial extension could be empty if you are using MISDN_KEYPAD -+ * to control ISDN provider features. -+ */ -+ dest_cp = ast_strdupa(data); -+ AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/'); -+ if (!args.ext) { -+ args.ext = ""; -+ } - -- ext = strtok_r(NULL, "/", &tokb); -- -- if (port_str) { -- if (port_str[0] == 'g' && port_str[1] == ':' ) { -+ if (!ast_strlen_zero(args.intf)) { -+ if (args.intf[0] == 'g' && args.intf[1] == ':' ) { - /* We make a group call lets checkout which ports are in my group */ -- port_str += 2; -- ast_copy_string(group, port_str, sizeof(group)); -+ args.intf += 2; -+ ast_copy_string(group, args.intf, sizeof(group)); - chan_misdn_log(2, 0, " --> Group Call group: %s\n", group); -- } else if ((p = strchr(port_str, ':'))) { -+ } else if ((p = strchr(args.intf, ':'))) { - /* we have a preselected channel */ -- *p = 0; -- channel = atoi(++p); -- port = atoi(port_str); -+ *p++ = 0; -+ channel = atoi(p); -+ port = atoi(args.intf); - chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel); - } else { -- port = atoi(port_str); -+ port = atoi(args.intf); - } - } else { -- ast_log(LOG_WARNING, " --> ! IND : CALL dad:%s WITHOUT PORT/Group, check extensions.conf\n", ext); -+ ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str); - return NULL; - } - - if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) { -- chan_misdn_log(4, port, " --> STARTING STANDARDDEC...\n"); -+ chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n"); - dec = 1; - } - -@@ -3449,11 +4298,13 @@ - for (port = misdn_cfg_get_next_port_spin(rr->port); port > 0 && port != port_start; - port = misdn_cfg_get_next_port_spin(port)) { - -- if (!port_start) -+ if (!port_start) { - port_start = port; -+ } - -- if (port >= port_start) -+ if (port >= port_start) { - next_chan = 1; -+ } - - if (port <= port_start && next_chan) { - int maxbchans=misdn_lib_get_maxchans(port); -@@ -3471,8 +4322,9 @@ - misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check)); - port_up = misdn_lib_port_up(port, check); - -- if (check && !port_up) -+ if (check && !port_up) { - chan_misdn_log(1, port, "L1 is not Up on this Port\n"); -+ } - - if (check && port_up < 0) { - ast_log(LOG_WARNING, "This port (%d) is blocked\n", port); -@@ -3482,8 +4334,9 @@ - newbc = misdn_lib_get_free_bc(port, robin_channel, 0, 0); - if (newbc) { - chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel); -- if (port_up) -+ if (port_up) { - chan_misdn_log(4, port, "portup:%d\n", port_up); -+ } - rr->port = newbc->port; - rr->channel = newbc->channel; - break; -@@ -3492,7 +4345,6 @@ - } - } - } while (!newbc && robin_channel != rr->channel); -- - } else { - for (port = misdn_cfg_get_next_port(0); port > 0; - port = misdn_cfg_get_next_port(port)) { -@@ -3510,8 +4362,9 @@ - - if (port_up > 0) { - newbc = misdn_lib_get_free_bc(port, 0, 0, dec); -- if (newbc) -+ if (newbc) { - break; -+ } - } - } - } -@@ -3528,33 +4381,38 @@ - } - } else { - /* 'Normal' Port dial * Port dial */ -- if (channel) -+ if (channel) { - chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel); -+ } - newbc = misdn_lib_get_free_bc(port, channel, 0, dec); -- - if (!newbc) { -- ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext); -+ ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str); - return NULL; - } - } - - - /* create ast_channel and link all the objects together */ -+ cl = init_chan_list(ORG_AST); -+ if (!cl) { -+ ast_log(LOG_WARNING, "Could not create Asterisk channel for Dial(%s)\n", dial_str); -+ return NULL; -+ } - cl->bc = newbc; - -- tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel); -+ tmp = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, port, channel); - if (!tmp) { -- ast_log(LOG_ERROR,"Could not create Asterisk object\n"); -+ ast_log(LOG_ERROR, "Could not create Asterisk object\n"); - return NULL; - } - -- cl->ast=tmp; -+ cl->ast = tmp; - - /* register chan in local list */ -- cl_queue_chan(&cl_te, cl) ; -+ cl_queue_chan(&cl_te, cl); - - /* fill in the config into the objects */ -- read_config(cl, ORG_AST); -+ read_config(cl); - - /* important */ - cl->need_hangup = 0; -@@ -3594,7 +4452,7 @@ - .indicate = misdn_indication, - .fixup = misdn_fixup, - .send_text = misdn_send_text, -- .properties = 0 -+ .properties = 0, - }; - - static struct ast_channel_tech misdn_tech_wo_bridge = { -@@ -3612,7 +4470,7 @@ - .indicate = misdn_indication, - .fixup = misdn_fixup, - .send_text = misdn_send_text, -- .properties = 0 -+ .properties = 0, - }; - - -@@ -3624,12 +4482,14 @@ - int tmp_port = misdn_cfg_get_next_port(0); - char newname[255]; - for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) { -- if (tmp_port == port) -+ if (tmp_port == port) { - break; -+ } - chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2; - } -- if (c < 0) -+ if (c < 0) { - c = 0; -+ } - - snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c); - if (strncmp(tmp->name, newname, strlen(newname))) { -@@ -3648,21 +4508,22 @@ - int bridging; - - for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) { -- if (tmp_port == port) -+ if (tmp_port == port) { - break; -+ } - chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2; - } -- if (c < 0) -+ if (c < 0) { - c = 0; -+ } - - if (callerid) { - ast_callerid_parse(callerid, &cid_name, &cid_num); - } - - tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++); -- - if (tmp) { -- chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid); -+ chan_misdn_log(2, 0, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid); - - tmp->nativeformats = prefformat; - -@@ -3675,35 +4536,31 @@ - - misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging)); - -- if (bridging) -- tmp->tech = &misdn_tech; -- else -- tmp->tech = &misdn_tech_wo_bridge; -+ tmp->tech = bridging ? &misdn_tech : &misdn_tech_wo_bridge; - - tmp->writeformat = format; - tmp->readformat = format; -- tmp->priority=1; -+ tmp->priority = 1; - -- if (exten) -+ if (exten) { - ast_copy_string(tmp->exten, exten, sizeof(tmp->exten)); -- else -+ } else { - chan_misdn_log(1, 0, "misdn_new: no exten given.\n"); -+ } - -- if (callerid) -+ if (callerid) { - /* Don't use ast_set_callerid() here because it will - * generate a needless NewCallerID event */ - tmp->cid.cid_ani = ast_strdup(cid_num); -+ } - -- if (pipe(chlist->pipe) < 0) -+ if (pipe(chlist->pipe) < 0) { - ast_log(LOG_ERROR, "Pipe failed\n"); -- -+ } - ast_channel_set_fd(tmp, 0, chlist->pipe[0]); - -- if (state == AST_STATE_RING) -- tmp->rings = 1; -- else -- tmp->rings = 0; -- -+ tmp->rings = (state == AST_STATE_RING) ? 1 : 0; -+ - ast_jb_configure(tmp, misdn_get_global_jbconf()); - } else { - chan_misdn_log(-1, 0, "Unable to allocate channel structure\n"); -@@ -3716,10 +4573,16 @@ - { - struct chan_list *help = list; - for (; help; help = help->next) { -- if (help->bc == bc) return help; -+ if (help->bc == bc) { -+ return help; -+ } - } - -- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad); -+ chan_misdn_log(6, bc->port, -+ "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n", -+ bc->dialed.number, -+ bc->caller.name, -+ bc->caller.number); - - return NULL; - } -@@ -3728,10 +4591,12 @@ - { - struct chan_list *help = list; - for (; help; help = help->next) { -- if ( help->bc && (help->bc->pid == pid) ) return help; -+ if (help->bc && (help->bc->pid == pid)) { -+ return help; -+ } - } - -- chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid); -+ chan_misdn_log(6, 0, "$$$ find_chan_by_pid: No channel found for pid:%d\n", pid); - - return NULL; - } -@@ -3740,16 +4605,27 @@ - { - struct chan_list *help = list; - -- if (bc->pri) return NULL; -+ if (bc->pri) { -+ return NULL; -+ } - -- chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad); -- for (;help; help = help->next) { -- chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state==MISDN_HOLDED, help->hold_info.channel); -- if ( (help->state == MISDN_HOLDED) && -- (help->hold_info.port == bc->port) ) -+ chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d dialed:%s caller:\"%s\" <%s>\n", -+ bc->channel, -+ bc->dialed.number, -+ bc->caller.name, -+ bc->caller.number); -+ for (; help; help = help->next) { -+ chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state == MISDN_HOLDED, help->hold_info.channel); -+ if ((help->state == MISDN_HOLDED) && -+ (help->hold_info.port == bc->port)) { - return help; -+ } - } -- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad); -+ chan_misdn_log(6, bc->port, -+ "$$$ find_holded: No channel found for dialed:%s caller:\"%s\" <%s>\n", -+ bc->dialed.number, -+ bc->caller.name, -+ bc->caller.number); - - return NULL; - } -@@ -3760,10 +4636,10 @@ - struct chan_list *help = list; - - for (; help; help = help->next) { -- if ( (help->state == MISDN_HOLDED) && -- (help->l3id == l3_id) -- ) -+ if ((help->state == MISDN_HOLDED) && -+ (help->l3id == l3_id)) { - return help; -+ } - } - - return NULL; -@@ -3789,10 +4665,12 @@ - { - struct chan_list *help; - -- if (chan->dsp) -+ if (chan->dsp) { - ast_dsp_free(chan->dsp); -- if (chan->trans) -+ } -+ if (chan->trans) { - ast_translator_free_path(chan->trans); -+ } - - ast_mutex_lock(&cl_te_lock); - if (!*list) { -@@ -3824,10 +4702,7 @@ - { - int ret = ast_pbx_start(ch->ast); - -- if (ret >= 0) -- ch->need_hangup = 0; -- else -- ch->need_hangup = 1; -+ ch->need_hangup = (ret >= 0) ? 0 : 1; - - return ret; - } -@@ -3847,8 +4722,9 @@ - send_cause2ast(ch->ast, ch->bc, ch); - ch->need_hangup = 0; - ch->need_queue_hangup = 0; -- if (ch->ast) -+ if (ch->ast) { - ast_hangup(ch->ast); -+ } - return; - } - -@@ -3860,8 +4736,9 @@ - if (ch->ast) { - send_cause2ast(ch->ast, ch->bc, ch); - -- if (ch->ast) -+ if (ch->ast) { - ast_queue_hangup_with_cause(ch->ast, ch->bc->cause); -+ } - cb_log(2, port, " --> queue_hangup\n"); - } else { - cb_log(1, port, "Cannot hangup chan, no ast\n"); -@@ -3869,72 +4746,79 @@ - } - - /** Isdn asks us to release channel, pendant to misdn_hangup **/ --static void release_chan(struct misdn_bchannel *bc) { -- struct ast_channel *ast=NULL; -+static void release_chan(struct misdn_bchannel *bc) -+{ -+ struct ast_channel *ast = NULL; -+ struct chan_list *ch; - - ast_mutex_lock(&release_lock); -- { -- struct chan_list *ch=find_chan_by_bc(cl_te, bc); -- if (!ch) { -- chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n"); -- ast_mutex_unlock(&release_lock); -- return; -- } -+ ch = find_chan_by_bc(cl_te, bc); -+ if (!ch) { -+ chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n"); -+ ast_mutex_unlock(&release_lock); -+ return; -+ } - -- if (ch->ast) { -- ast = ch->ast; -- } -+ if (ch->ast) { -+ ast = ch->ast; -+ } - -- chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id); -+ chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id); - -- /*releasing jitterbuffer*/ -- if (ch->jb ) { -- misdn_jb_destroy(ch->jb); -- ch->jb = NULL; -- } else { -- if (!bc->nojitter) -- chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n"); -+ /* releasing jitterbuffer */ -+ if (ch->jb) { -+ misdn_jb_destroy(ch->jb); -+ ch->jb = NULL; -+ } else { -+ if (!bc->nojitter) { -+ chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n"); - } -+ } - -- if (ch->overlap_dial) { -- if (ch->overlap_dial_task != -1) { -- misdn_tasks_remove(ch->overlap_dial_task); -- ch->overlap_dial_task = -1; -- } -- ast_mutex_destroy(&ch->overlap_tv_lock); -+ if (ch->overlap_dial) { -+ if (ch->overlap_dial_task != -1) { -+ misdn_tasks_remove(ch->overlap_dial_task); -+ ch->overlap_dial_task = -1; - } -+ ast_mutex_destroy(&ch->overlap_tv_lock); -+ } - -- if (ch->originator == ORG_AST) { -- misdn_out_calls[bc->port]--; -- } else { -- misdn_in_calls[bc->port]--; -- } -+ if (ch->originator == ORG_AST) { -+ misdn_out_calls[bc->port]--; -+ } else { -+ misdn_in_calls[bc->port]--; -+ } - -- if (ch) { -- close(ch->pipe[0]); -- close(ch->pipe[1]); -+ if (ch) { -+ close(ch->pipe[0]); -+ close(ch->pipe[1]); - -- if (ast && MISDN_ASTERISK_TECH_PVT(ast)) { -- chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n", bc ? bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(ch)); -- chan_misdn_log(3, bc->port, " --> * State Down\n"); -- MISDN_ASTERISK_TECH_PVT(ast) = NULL; -+ if (ast && MISDN_ASTERISK_TECH_PVT(ast)) { -+ chan_misdn_log(1, bc->port, -+ "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s> state: %s\n", -+ bc->pid, -+ ast->context, -+ ast->exten, -+ ast->cid.cid_name ? ast->cid.cid_name : "", -+ ast->cid.cid_num ? ast->cid.cid_num : "", -+ misdn_get_ch_state(ch)); -+ chan_misdn_log(3, bc->port, " --> * State Down\n"); -+ MISDN_ASTERISK_TECH_PVT(ast) = NULL; - -- if (ast->_state != AST_STATE_RESERVED) { -- chan_misdn_log(3, bc->port, " --> Setting AST State to down\n"); -- ast_setstate(ast, AST_STATE_DOWN); -- } -+ if (ast->_state != AST_STATE_RESERVED) { -+ chan_misdn_log(3, bc->port, " --> Setting AST State to down\n"); -+ ast_setstate(ast, AST_STATE_DOWN); - } -+ } - -- ch->state = MISDN_CLEANING; -- cl_dequeue_chan(&cl_te, ch); -+ ch->state = MISDN_CLEANING; -+ cl_dequeue_chan(&cl_te, ch); - -- ast_free(ch); -- } else { -- /* chan is already cleaned, so exiting */ -- } -- -- ast_mutex_unlock(&release_lock); -+ ast_free(ch); -+ } else { -+ /* chan is already cleaned, so exiting */ - } -+ ast_mutex_unlock(&release_lock); - /*** release end **/ - } - -@@ -3946,7 +4830,7 @@ - - ast_moh_stop(ast_bridged_channel(holded_chan->ast)); - -- holded_chan->state=MISDN_CONNECTED; -+ holded_chan->state = MISDN_CONNECTED; - /* misdn_lib_transfer(holded_chan->bc); */ - ast_channel_masquerade(holded_chan->ast, ast_bridged_channel(tmp_ch->ast)); - } -@@ -3977,19 +4861,21 @@ - ch->state = MISDN_INCOMING_SETUP; - } - -- chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num); -+ chan_misdn_log(1, bc->port, -+ "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n", -+ ast->context, -+ ast->exten, -+ ast->cid.cid_name ? ast->cid.cid_name : "", -+ ast->cid.cid_num ? ast->cid.cid_num : ""); - -- strncpy(ast->exten, "s", 2); -+ strcpy(ast->exten, "s"); - - if (pbx_start_chan(ch) < 0) { - ast = NULL; - hangup_chan(ch); - hanguptone_indicate(ch); - -- if (bc->nt) -- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); -- else -- misdn_lib_send_event(bc, EVENT_DISCONNECT ); -+ misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT); - } - - -@@ -4031,12 +4917,13 @@ - - switch (bc->cause) { - -- case 1: /** Congestion Cases **/ -- case 2: -- case 3: -- case 4: -- case 22: -- case 27: -+ case AST_CAUSE_UNALLOCATED: -+ case AST_CAUSE_NO_ROUTE_TRANSIT_NET: -+ case AST_CAUSE_NO_ROUTE_DESTINATION: -+ case 4: /* Send special information tone */ -+ case AST_CAUSE_NUMBER_CHANGED: -+ case AST_CAUSE_DESTINATION_OUT_OF_ORDER: -+ /* Congestion Cases */ - /* - * Not Queueing the Congestion anymore, since we want to hear - * the inband message -@@ -4048,9 +4935,8 @@ - */ - break; - -- case 21: -- case 17: /* user busy */ -- -+ case AST_CAUSE_CALL_REJECTED: -+ case AST_CAUSE_USER_BUSY: - ch->state = MISDN_BUSY; - - if (!ch->need_busy) { -@@ -4072,14 +4958,18 @@ - /*! \brief Import parameters from the dialplan environment variables */ - void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) - { -- const char *tmp = pbx_builtin_getvar_helper(chan, "MISDN_PID"); -+ const char *tmp; -+ -+ ast_channel_lock(chan); -+ tmp = pbx_builtin_getvar_helper(chan, "MISDN_PID"); - if (tmp) { - ch->other_pid = atoi(tmp); - chan_misdn_log(3, bc->port, " --> IMPORT_PID: importing pid:%s\n", tmp); - if (ch->other_pid > 0) { - ch->other_ch = find_chan_by_pid(cl_te, ch->other_pid); -- if (ch->other_ch) -+ if (ch->other_ch) { - ch->other_ch->other_ch = ch; -+ } - } - } - -@@ -4096,14 +4986,17 @@ - } - - tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD"); -- if (tmp) -+ if (tmp) { - ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad)); -+ } -+ ast_channel_unlock(chan); - } - - /*! \brief Export parameters to the dialplan environment variables */ - void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch) - { - char tmp[32]; -+ - chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid); - snprintf(tmp, sizeof(tmp), "%d", bc->pid); - pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp); -@@ -4118,11 +5011,13 @@ - pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp); - } - -- if (bc->uulen) -+ if (bc->uulen) { - pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu); -+ } - -- if (!ast_strlen_zero(bc->keypad)) -+ if (!ast_strlen_zero(bc->keypad)) { - pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad); -+ } - } - - int add_in_calls(int port) -@@ -4156,23 +5051,27 @@ - return 0; - } - --static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) { -+static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) -+{ - if (pbx_start_chan(ch) < 0) { - hangup_chan(ch); - chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n"); - if (bc->nt) { - hanguptone_indicate(ch); - misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE); -- } else -+ } else { - misdn_lib_send_event(bc, EVENT_RELEASE); -+ } - } - } - --static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) { -- ch->state=MISDN_WAITING4DIGS; -+static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) -+{ -+ ch->state = MISDN_WAITING4DIGS; - misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); -- if (bc->nt && !bc->dad[0]) -+ if (bc->nt && !bc->dialed.number[0]) { - dialtone_indicate(ch); -+ } - } - - -@@ -4186,10 +5085,18 @@ - - if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */ - int debuglevel = 1; -- if ( event == EVENT_CLEANUP && !user_data) -+ if ( event == EVENT_CLEANUP && !user_data) { - debuglevel = 5; -+ } - -- chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none"); -+ chan_misdn_log(debuglevel, bc->port, -+ "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n", -+ manager_isdn_get_info(event), -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number, -+ bc->pid, -+ ch ? misdn_get_ch_state(ch) : "none"); - if (debuglevel == 1) { - misdn_lib_log_ies(bc); - chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state)); -@@ -4227,13 +5134,15 @@ - case EVENT_RELEASE_COMPLETE: - case EVENT_CLEANUP: - case EVENT_TIMEOUT: -- if (!ch->ast) -+ if (!ch->ast) { - chan_misdn_log(3, bc->port, "ast_hangup already called, so we have no ast ptr anymore in event(%s)\n", manager_isdn_get_info(event)); -+ } - break; - default: - if (!ch->ast || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) { -- if (event != EVENT_BCHAN_DATA) -+ if (event != EVENT_BCHAN_DATA) { - ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event)); -+ } - return -1; - } - } -@@ -4273,14 +5182,17 @@ - break; - } - -- if (bc) -+ if (bc) { - ch->bc = (struct misdn_bchannel *)user_data; -+ } - break; - - case EVENT_DTMF_TONE: - { - /* sending INFOS as DTMF-Frames :) */ -- struct ast_frame fr = { 0, }; -+ struct ast_frame fr; -+ -+ memset(&fr, 0, sizeof(fr)); - fr.frametype = AST_FRAME_DTMF; - fr.subclass = bc->dtmf ; - fr.src = NULL; -@@ -4303,12 +5215,13 @@ - break; - - case EVENT_INFORMATION: -- { -- if ( ch->state != MISDN_CONNECTED ) -+ if (ch->state != MISDN_CONNECTED) { - stop_indicate(ch); -+ } - -- if (!ch->ast) -+ if (!ch->ast) { - break; -+ } - - if (ch->state == MISDN_WAITING4DIGS ) { - /* Ok, incomplete Setup, waiting till extension exists */ -@@ -4317,25 +5230,23 @@ - ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad)); - } - -- strncat(bc->dad,bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1); -- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten)); -+ strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); -+ ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten)); - - /* Check for Pickup Request first */ - if (!strcmp(ch->ast->exten, ast_pickup_ext())) { - if (ast_pickup_call(ch->ast)) { - hangup_chan(ch); - } else { -- struct ast_channel *chan = ch->ast; - ch->state = MISDN_CALLING_ACKNOWLEDGE; -- ast_setstate(chan, AST_STATE_DOWN); - hangup_chan(ch); - ch->ast = NULL; - break; - } - } - -- if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { -- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) { -+ if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { -+ if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) { - ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port); - strcpy(ch->ast->exten, "i"); - -@@ -4344,14 +5255,15 @@ - break; - } - -- ast_log(LOG_WARNING, "Extension can never match, so disconnecting on port(%d)." -- "maybe you want to add an 'i' extension to catch this case.\n", -+ ast_log(LOG_WARNING, "Extension can never match, so disconnecting on port(%d).\n" -+ "\tMaybe you want to add an 'i' extension to catch this case.\n", - bc->port); - -- if (bc->nt) -+ if (bc->nt) { - hanguptone_indicate(ch); -+ } - ch->state = MISDN_EXTCANTMATCH; -- bc->out_cause = 1; -+ bc->out_cause = AST_CAUSE_UNALLOCATED; - - misdn_lib_send_event(bc, EVENT_DISCONNECT); - break; -@@ -4368,8 +5280,7 @@ - break; - } - -- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { -- -+ if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { - ch->state = MISDN_DIALING; - start_pbx(ch, bc, ch->ast); - } -@@ -4377,6 +5288,7 @@ - /* sending INFOS as DTMF-Frames :) */ - struct ast_frame fr; - int digits; -+ - memset(&fr, 0, sizeof(fr)); - fr.frametype = AST_FRAME_DTMF; - fr.subclass = bc->info_dad[0] ; -@@ -4391,23 +5303,21 @@ - misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits)); - if (ch->state != MISDN_CONNECTED ) { - if (digits) { -- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1); -- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten)); -+ strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); -+ ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten)); - ast_cdr_update(ch->ast); - } - - ast_queue_frame(ch->ast, &fr); - } - } -- } - break; - case EVENT_SETUP: - { - struct chan_list *ch = find_chan_by_bc(cl_te, bc); -- int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad); -+ int msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dialed.number); - struct ast_channel *chan; - int exceed; -- int pres,screen; - int ai; - int im; - -@@ -4431,27 +5341,12 @@ - int cause; - chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n"); - misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause)); -- bc->out_cause = cause ? cause : 16; -+ bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING; - return RESPONSE_RELEASE_SETUP; - } - - print_bearer(bc); -- -- if (!bc->nt && ! msn_valid) { -- chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n"); -- return RESPONSE_IGNORE_SETUP; /* Ignore MSNs which are not in our List */ -- } - -- if (bc->cw) { -- int cause; -- chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n"); -- misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause)); -- bc->out_cause = cause ? cause : 16; -- return RESPONSE_RELEASE_SETUP; -- } -- -- print_bearer(bc); -- - ch = init_chan_list(ORG_MISDN); - - if (!ch) { -@@ -4462,10 +5357,8 @@ - ch->bc = bc; - ch->l3id = bc->l3_id; - ch->addr = bc->addr; -- ch->originator = ORG_MISDN; - -- chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel); -- -+ chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, bc->port, bc->channel); - if (!chan) { - misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); - ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n"); -@@ -4480,51 +5373,45 @@ - pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp); - } - -- read_config(ch, ORG_MISDN); -+ read_config(ch); - - export_ch(chan, bc, ch); - - ch->ast->rings = 1; - ast_setstate(ch->ast, AST_STATE_RINGING); - -- switch (bc->pres) { -- case 1: -- pres = AST_PRES_RESTRICTED; -- chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n"); -- break; -- case 2: -- pres = AST_PRES_UNAVAILABLE; -- chan_misdn_log(2, bc->port, " --> PRES: Restricted (2)\n"); -- break; -- default: -- pres = AST_PRES_ALLOWED; -- chan_misdn_log(2, bc->port, " --> PRES: Restricted (%d)\n", bc->pres); -- } -+ /* Update asterisk channel caller information */ -+ chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type); -+ chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan); -+ chan->cid.cid_ton = misdn_to_ast_ton(bc->caller.number_type) -+ | misdn_to_ast_plan(bc->caller.number_plan); - -- switch (bc->screen) { -- case 0: -- screen = AST_PRES_USER_NUMBER_UNSCREENED; -- chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (0)\n"); -- break; -- case 1: -- screen = AST_PRES_USER_NUMBER_PASSED_SCREEN; -- chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n"); -- break; -- case 2: -- screen = AST_PRES_USER_NUMBER_FAILED_SCREEN; -- chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n"); -- break; -- case 3: -- screen = AST_PRES_NETWORK_NUMBER; -- chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n"); -- break; -- default: -- screen = AST_PRES_USER_NUMBER_UNSCREENED; -- chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen); -+ chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation); -+ chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening); -+ chan->cid.cid_pres = misdn_to_ast_pres(bc->caller.presentation) -+ | misdn_to_ast_screen(bc->caller.screening); -+ -+ ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number); -+ -+ if (!ast_strlen_zero(bc->redirecting.from.number)) { -+ struct ast_party_redirecting redirecting; -+ -+ /* Add configured prefix to redirecting.from.number */ -+ misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number)); -+ -+ /* Update asterisk channel redirecting information */ -+ ast_party_redirecting_set_init(&redirecting, &chan->redirecting); -+ redirecting.from.number = bc->redirecting.from.number; -+ redirecting.from.number_type = -+ misdn_to_ast_ton(bc->redirecting.from.number_type) -+ | misdn_to_ast_plan(bc->redirecting.from.number_plan); -+ redirecting.from.number_presentation = -+ misdn_to_ast_pres(bc->redirecting.from.presentation) -+ | misdn_to_ast_screen(bc->redirecting.from.screening); -+ redirecting.reason = misdn_to_ast_reason(bc->redirecting.reason); -+ ast_set_redirecting(chan, &redirecting); - } - -- chan->cid.cid_pres = pres + screen; -- - pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability)); - chan->transfercapability = bc->capability; - -@@ -4578,7 +5465,6 @@ - hangup_chan(ch); - } else { - ch->state = MISDN_CALLING_ACKNOWLEDGE; -- ast_setstate(chan, AST_STATE_DOWN); - hangup_chan(ch); - ch->ast = NULL; - break; -@@ -4595,16 +5481,16 @@ - break; - } - -- /* check if we should jump into s when we have no dad */ -+ /* check if we should jump into s when we have no dialed.number */ - misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im)); -- if (im && ast_strlen_zero(bc->dad)) { -+ if (im && ast_strlen_zero(bc->dialed.number)) { - do_immediate_setup(bc, ch, chan); - break; - } - - chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context); -- if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { -- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) { -+ if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { -+ if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) { - ast_log(LOG_WARNING, "Extension can never match, So jumping to 'i' extension. port(%d)\n", bc->port); - strcpy(ch->ast->exten, "i"); - misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE); -@@ -4613,19 +5499,17 @@ - break; - } - -- ast_log(LOG_WARNING, "Extension can never match, so disconnecting on port(%d)." -- "maybe you want to add an 'i' extension to catch this case.\n", -+ ast_log(LOG_WARNING, "Extension can never match, so disconnecting on port(%d).\n" -+ "\tMaybe you want to add an 'i' extension to catch this case.\n", - bc->port); -- if (bc->nt) -+ if (bc->nt) { - hanguptone_indicate(ch); -+ } - - ch->state = MISDN_EXTCANTMATCH; - bc->out_cause = AST_CAUSE_UNALLOCATED; - -- if (bc->nt) -- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE ); -- else -- misdn_lib_send_event(bc, EVENT_RELEASE ); -+ misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_RELEASE); - - break; - } -@@ -4650,7 +5534,7 @@ - * the number is empty, we wait for the ISDN timeout - * instead of our own timer. - */ -- if (ch->overlap_dial && bc->nt && !bc->dad[0] ) { -+ if (ch->overlap_dial && bc->nt && !bc->dialed.number[0] ) { - wait_for_digits(ch, bc, chan); - break; - } -@@ -4665,17 +5549,17 @@ - ast_mutex_unlock(&ch->overlap_tv_lock); - - wait_for_digits(ch, bc, chan); -- if (ch->overlap_dial_task == -1) -+ if (ch->overlap_dial_task == -1) { - ch->overlap_dial_task = - misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch); -- -+ } - break; - } - - /* If the extension does not exist and we're not TE_PTMP we wait for more digits - * without interdigit timeout. - * */ -- if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { -+ if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { - wait_for_digits(ch, bc, chan); - break; - } -@@ -4683,43 +5567,37 @@ - /* - * If the extension exists let's just jump into it. - * */ -- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) { -- if (bc->need_more_infos) -- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE ); -- else -- misdn_lib_send_event(bc, EVENT_PROCEEDING); -- -+ if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) { -+ misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING); - ch->state = MISDN_DIALING; - start_pbx(ch, bc, chan); - break; - } -+ break; - } -- break; - - case EVENT_SETUP_ACKNOWLEDGE: -- { - ch->state = MISDN_CALLING_ACKNOWLEDGE; - -- if (bc->channel) -+ if (bc->channel) { - update_name(ch->ast,bc->port,bc->channel); -- -+ } -+ - if (!ast_strlen_zero(bc->infos_pending)) { - /* TX Pending Infos */ -- strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1); -+ strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1); - -- if (!ch->ast) -+ if (!ch->ast) { - break; -- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten)); -+ } -+ ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten)); - ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad)); - ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending)); - - misdn_lib_send_event(bc, EVENT_INFORMATION); - } -- } -- break; -+ break; - case EVENT_PROCEEDING: -- { -- - if (misdn_cap_is_speech(bc->capability) && - misdn_inband_avail(bc) ) { - start_bc_tones(ch); -@@ -4727,39 +5605,37 @@ - - ch->state = MISDN_PROCEEDING; - -- if (!ch->ast) -+ if (!ch->ast) { - break; -+ } - - ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING); -- } -- break; -+ break; - case EVENT_PROGRESS: -- -- if (bc->channel) -+ if (bc->channel) { - update_name(ch->ast, bc->port, bc->channel); -+ } - - if (!bc->nt ) { -- if ( misdn_cap_is_speech(bc->capability) && -- misdn_inband_avail(bc) -- ) { -+ if (misdn_cap_is_speech(bc->capability) && -+ misdn_inband_avail(bc)) { - start_bc_tones(ch); - } - - ch->state = MISDN_PROGRESS; - -- if (!ch->ast) -+ if (!ch->ast) { - break; -+ } - ast_queue_control(ch->ast, AST_CONTROL_PROGRESS); - } - break; -- -- - case EVENT_ALERTING: -- { - ch->state = MISDN_ALERTING; - -- if (!ch->ast) -+ if (!ch->ast) { - break; -+ } - - ast_queue_control(ch->ast, AST_CONTROL_RINGING); - ast_setstate(ch->ast, AST_STATE_RINGING); -@@ -4777,52 +5653,53 @@ - /*tone_indicate(ch, TONE_FAR_ALERTING);*/ - } - } -- } -- break; -+ break; - case EVENT_CONNECT: - { -- struct ast_channel *bridged; -+ struct ast_party_connected_line connected; - -- /*we answer when we've got our very new L3 ID from the NT stack */ -+ /* we answer when we've got our very new L3 ID from the NT stack */ - misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE); - -- if (!ch->ast) -+ if (!ch->ast) { - break; -+ } - -- bridged = ast_bridged_channel(ch->ast); - stop_indicate(ch); - -- if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) { -- struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged); -+ /* Add configured prefix to connected.number */ -+ misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number)); - -- chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad); -- if (bridged_ch) { -- bridged_ch->bc->cpnnumplan = bc->cpnnumplan; -- ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad)); -- } -- } -+ /* Update the connected line information on the other channel */ -+ ast_party_connected_line_init(&connected); -+ connected.id.number = bc->connected.number; -+ connected.id.number_type = misdn_to_ast_ton(bc->connected.number_type) -+ | misdn_to_ast_plan(bc->connected.number_plan); -+ connected.id.number_presentation = misdn_to_ast_pres(bc->connected.presentation) -+ | misdn_to_ast_screen(bc->connected.screening); -+ connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_queue_connected_line_update(ch->ast, &connected); -+ -+ ch->l3id = bc->l3_id; -+ ch->addr = bc->addr; -+ -+ start_bc_tones(ch); -+ -+ ch->state = MISDN_CONNECTED; -+ -+ ast_queue_control(ch->ast, AST_CONTROL_ANSWER); -+ break; - } -- ch->l3id=bc->l3_id; -- ch->addr=bc->addr; -- -- start_bc_tones(ch); -- -- ch->state = MISDN_CONNECTED; -- -- ast_queue_control(ch->ast, AST_CONTROL_ANSWER); -- break; - case EVENT_CONNECT_ACKNOWLEDGE: -- { - ch->l3id = bc->l3_id; - ch->addr = bc->addr; - - start_bc_tones(ch); - - ch->state = MISDN_CONNECTED; -- } -- break; -+ break; - case EVENT_DISCONNECT: -- /*we might not have an ch->ast ptr here anymore*/ -+ /* we might not have an ch->ast ptr here anymore */ - if (ch) { - struct chan_list *holded_ch = find_holded(cl_te, bc); - -@@ -4840,14 +5717,15 @@ - - if (ch->ast) { - ch->ast->hangupcause = bc->cause; -- if (bc->cause == AST_CAUSE_USER_BUSY) -+ if (bc->cause == AST_CAUSE_USER_BUSY) { - ast_queue_control(ch->ast, AST_CONTROL_BUSY); -+ } - } - ch->need_busy = 0; - break; - } - -- /*Check for holded channel, to implement transfer*/ -+ /* Check for holded channel, to implement transfer */ - if (holded_ch && holded_ch != ch && ch->ast && ch->state == MISDN_CONNECTED) { - cb_log(1, bc->port, " --> found holded ch\n"); - misdn_transfer_bc(ch, holded_ch) ; -@@ -4866,21 +5744,18 @@ - #endif - } - bc->out_cause = -1; -- if (bc->need_release) -+ if (bc->need_release) { - misdn_lib_send_event(bc, EVENT_RELEASE); -+ } - break; -- - case EVENT_RELEASE: -- { -- bc->need_disconnect = 0; -- bc->need_release = 0; -+ bc->need_disconnect = 0; -+ bc->need_release = 0; - -- hangup_chan(ch); -- release_chan(bc); -- } -+ hangup_chan(ch); -+ release_chan(bc); - break; - case EVENT_RELEASE_COMPLETE: -- { - bc->need_disconnect = 0; - bc->need_release = 0; - bc->need_release_complete = 0; -@@ -4888,15 +5763,14 @@ - stop_bc_tones(ch); - hangup_chan(ch); - -- if (ch) -+ if (ch) { - ch->state = MISDN_CLEANING; -+ } - - release_chan(bc); -- } -- break; -+ break; - case EVENT_BCHAN_ERROR: - case EVENT_CLEANUP: -- { - stop_bc_tones(ch); - - switch (ch->state) { -@@ -4909,9 +5783,7 @@ - - hangup_chan(ch); - release_chan(bc); -- } -- break; -- -+ break; - case EVENT_TONE_GENERATE: - { - int tone_len = bc->tone_cnt; -@@ -4922,11 +5794,13 @@ - - chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len); - -- if (!ast) -+ if (!ast) { - break; -+ } - -- if (!ast->generator) -+ if (!ast->generator) { - break; -+ } - - tmp = ast->generatordata; - ast->generatordata = NULL; -@@ -4946,28 +5820,29 @@ - } else { - bc->tone_cnt = 0; - } -+ break; - } -- break; -- - case EVENT_BCHAN_DATA: -- { -- if (ch->bc->AOCD_need_export) -+ if (ch->bc->AOCD_need_export) { - export_aoc_vars(ch->originator, ch->ast, ch->bc); -- if (!misdn_cap_is_speech(ch->bc->capability) ) { -+ } -+ if (!misdn_cap_is_speech(ch->bc->capability)) { - struct ast_frame frame; -- /*In Data Modes we queue frames*/ -- frame.frametype = AST_FRAME_VOICE; /*we have no data frames yet*/ -+ -+ /* In Data Modes we queue frames */ -+ frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */ - frame.subclass = AST_FORMAT_ALAW; - frame.datalen = bc->bframe_len; - frame.samples = bc->bframe_len; - frame.mallocd = 0; - frame.offset = 0; -- frame.delivery = ast_tv(0,0); -+ frame.delivery = ast_tv(0, 0); - frame.src = NULL; - frame.data.ptr = bc->bframe; - -- if (ch->ast) -+ if (ch->ast) { - ast_queue_frame(ch->ast, &frame); -+ } - } else { - fd_set wrfs; - struct timeval tv = { 0, 0 }; -@@ -4989,7 +5864,7 @@ - } - - if (FD_ISSET(ch->pipe[1], &wrfs)) { -- chan_misdn_log(9, bc->port, "writing %d bytes 2 asterisk\n", bc->bframe_len); -+ chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len); - if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) { - chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno)); - -@@ -5001,35 +5876,34 @@ - chan_misdn_log(1, bc->port, "Write Pipe full!\n"); - } - } -- } -- break; -+ break; - case EVENT_TIMEOUT: -- { -- if (ch && bc) -+ if (ch && bc) { - chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch)); -+ } - - switch (ch->state) { - case MISDN_DIALING: - case MISDN_PROGRESS: -- if (bc->nt && !ch->nttimeout) -+ if (bc->nt && !ch->nttimeout) { - break; -- -+ } -+ /* fall-through */ - case MISDN_CALLING: - case MISDN_ALERTING: - case MISDN_PROCEEDING: - case MISDN_CALLING_ACKNOWLEDGE: - if (bc->nt) { -- bc->progress_indicator = 8; -+ bc->progress_indicator = INFO_PI_INBAND_AVAILABLE; - hanguptone_indicate(ch); - } -- -+ - bc->out_cause = AST_CAUSE_UNALLOCATED; - misdn_lib_send_event(bc, EVENT_DISCONNECT); - break; -- - case MISDN_WAITING4DIGS: - if (bc->nt) { -- bc->progress_indicator = 8; -+ bc->progress_indicator = INFO_PI_INBAND_AVAILABLE; - bc->out_cause = AST_CAUSE_UNALLOCATED; - hanguptone_indicate(ch); - misdn_lib_send_event(bc, EVENT_DISCONNECT); -@@ -5037,20 +5911,16 @@ - bc->out_cause = AST_CAUSE_NORMAL_CLEARING; - misdn_lib_send_event(bc, EVENT_RELEASE); - } -- - break; -- - case MISDN_CLEANING: -- chan_misdn_log(1,bc->port," --> in state cleaning .. so ignoring, the stack should clean it for us\n"); -+ chan_misdn_log(1, bc->port, " --> in state cleaning .. so ignoring, the stack should clean it for us\n"); - break; -- - default: -- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); -+ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE); -+ break; - } -- } -- break; -+ break; - -- - /****************************/ - /** Supplementary Services **/ - /****************************/ -@@ -5086,9 +5956,8 @@ - chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n"); - misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT); - } -+ break; - } -- break; -- - case EVENT_HOLD: - { - int hold_allowed; -@@ -5097,7 +5966,6 @@ - misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed)); - - if (!hold_allowed) { -- - chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n"); - misdn_lib_send_event(bc, EVENT_HOLD_REJECT); - break; -@@ -5118,21 +5986,19 @@ - ch->bc = NULL; - ch->hold_info.port = bc->port; - ch->hold_info.channel = bc->channel; -- - } else { - misdn_lib_send_event(bc, EVENT_HOLD_REJECT); - chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n"); - } -+ break; - } -- break; -- - case EVENT_FACILITY: - print_facility(&(bc->fac_in), bc); - - switch (bc->fac_in.Function) { - #ifdef HAVE_MISDN_FAC_RESULT - case Fac_RESULT: -- break; -+ break; - #endif - case Fac_CD: - if (ch) { -@@ -5142,7 +6008,7 @@ - ch_br = MISDN_ASTERISK_TECH_PVT(bridged); - /*ch->state = MISDN_FACILITY_DEFLECTED;*/ - if (ch_br->bc) { -- if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) { -+ if (ast_exists_extension(bridged, ch->context, (char *) bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->caller.number)) { - ch_br->state = MISDN_DIALING; - if (pbx_start_chan(ch_br) < 0) { - chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n"); -@@ -5173,21 +6039,18 @@ - #ifdef HAVE_MISDN_FAC_ERROR - case Fac_ERROR: - #endif -- break; -+ break; - default: - chan_misdn_log(0, bc->port," --> not yet handled: facility type:%d\n", bc->fac_in.Function); - } - - break; -- - case EVENT_RESTART: -- - if (!bc->dummy) { - stop_bc_tones(ch); - release_chan(bc); - } - break; -- - default: - chan_misdn_log(1, 0, "Got Unknown Event\n"); - break; -@@ -5214,26 +6077,29 @@ - - misdn_tasks_destroy(); - -- if (!g_config_initialized) -+ if (!g_config_initialized) { - return 0; -- -+ } -+ - ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry)); -- -+ - /* ast_unregister_application("misdn_crypt"); */ - ast_unregister_application("misdn_set_opt"); - ast_unregister_application("misdn_facility"); - ast_unregister_application("misdn_check_l2l1"); -- -+ - ast_channel_unregister(&misdn_tech); - - free_robin_list(); - misdn_cfg_destroy(); - misdn_lib_destroy(); - -- if (misdn_debug) -+ if (misdn_debug) { - ast_free(misdn_debug); -- if (misdn_debug_only) -+ } -+ if (misdn_debug_only) { - ast_free(misdn_debug_only); -+ } - ast_free(misdn_ports); - - return 0; -@@ -5284,8 +6150,9 @@ - misdn_debug_only = ast_calloc(max_ports + 1, sizeof(int)); - - misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, sizeof(tempbuf)); -- if (!ast_strlen_zero(tempbuf)) -+ if (!ast_strlen_zero(tempbuf)) { - tracing = 1; -+ } - - misdn_in_calls = ast_malloc(sizeof(int) * (max_ports + 1)); - misdn_out_calls = ast_malloc(sizeof(int) * (max_ports + 1)); -@@ -5301,10 +6168,12 @@ - misdn_cfg_update_ptp(); - misdn_cfg_get_ports_string(ports); - -- if (!ast_strlen_zero(ports)) -+ if (!ast_strlen_zero(ports)) { - chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports); -- if (misdn_lib_init(ports, &iface, NULL)) -+ } -+ if (misdn_lib_init(ports, &iface, NULL)) { - chan_misdn_log(0, 0, "No te ports initialized\n"); -+ } - - misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags)); - misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile)); -@@ -5410,8 +6279,13 @@ - static int misdn_facility_exec(struct ast_channel *chan, void *data) - { - struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan); -- char *parse, *tok, *tokb; -+ char *parse; - -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(facility_type); -+ AST_APP_ARG(arg)[99]; -+ ); -+ - chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type); - - if (strcasecmp(chan->tech->type, "mISDN")) { -@@ -5419,35 +6293,35 @@ - return -1; - } - -- if (ast_strlen_zero((char *)data)) { -- ast_log(LOG_WARNING, "misdn_facility Requires arguments\n"); -+ if (ast_strlen_zero((char *) data)) { -+ ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,]\n"); - return -1; - } - - parse = ast_strdupa(data); -- tok = strtok_r(parse, "|", &tokb) ; -+ AST_STANDARD_APP_ARGS(args, parse); - -- if (!tok) { -- ast_log(LOG_WARNING, "misdn_facility Requires arguments\n"); -+ if (ast_strlen_zero(args.facility_type)) { -+ ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,]\n"); - return -1; - } - -- if (!strcasecmp(tok, "calldeflect")) { -- tok = strtok_r(NULL, "|", &tokb) ; -- -- if (!tok) { -- ast_log(LOG_WARNING, "Facility: Call Defl Requires arguments\n"); -+ if (!strcasecmp(args.facility_type, "calldeflect")) { -+ if (ast_strlen_zero(args.arg[0])) { -+ ast_log(LOG_WARNING, "Facility: Call Deflection requires an argument: Number\n"); - } - -- if (strlen(tok) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) { -- ast_log(LOG_WARNING, "Facility: Number argument too long (up to 15 digits are allowed). Ignoring.\n"); -- return 0; -+ if (strlen(args.arg[0]) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) { -+ ast_log(LOG_WARNING, -+ "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n", -+ (int) sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)); -+ return 0; - } - ch->bc->fac_out.Function = Fac_CD; -- ast_copy_string((char *)ch->bc->fac_out.u.CDeflection.DeflectedToNumber, tok, sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)); -+ ast_copy_string((char *)ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0], sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)); - misdn_lib_send_event(ch->bc, EVENT_FACILITY); - } else { -- chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", tok); -+ chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", args.facility_type); - } - - return 0; -@@ -5464,11 +6338,11 @@ - int port_up; - - AST_DECLARE_APP_ARGS(args, -- AST_APP_ARG(grouppar); -- AST_APP_ARG(timeout); -+ AST_APP_ARG(grouppar); -+ AST_APP_ARG(timeout); - ); - -- if (ast_strlen_zero((char *)data)) { -+ if (ast_strlen_zero((char *) data)) { - ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n"); - return -1; - } -@@ -5491,7 +6365,7 @@ - ast_copy_string(group, port_str, sizeof(group)); - chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group); - -- for ( port = misdn_cfg_get_next_port(port); -+ for (port = misdn_cfg_get_next_port(port); - port > 0; - port = misdn_cfg_get_next_port(port)) { - char cfg_group[BUFFERSIZE + 1]; -@@ -5502,7 +6376,6 @@ - - if (!strcasecmp(cfg_group, group)) { - port_up = misdn_lib_port_up(port, 1); -- - if (!port_up) { - chan_misdn_log(2, 0, " --> port '%d'\n", port); - misdn_lib_get_port_up(port); -@@ -5602,19 +6475,23 @@ - switch (tok[0]) { - case 'r' : - rxgain = atoi(++tok); -- if (rxgain < -8) -+ if (rxgain < -8) { - rxgain = -8; -- if (rxgain > 8) -+ } -+ if (rxgain > 8) { - rxgain = 8; -+ } - ch->bc->rxgain = rxgain; - chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain); - break; - case 't': - txgain = atoi(++tok); -- if (txgain < -8) -+ if (txgain < -8) { - txgain = -8; -- if (txgain > 8) -+ } -+ if (txgain > 8) { - txgain = 8; -+ } - ch->bc->txgain = txgain; - chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain); - break; -@@ -5695,10 +6572,16 @@ - case 'p': - chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]); - /* CRICH: callingpres!!! */ -- if (strstr(tok,"allowed")) { -- ch->bc->pres = 0; -+ if (strstr(tok, "allowed")) { -+ ch->bc->presentation = 0; -+ ch->bc->set_presentation = 1; -+ } else if (strstr(tok, "restricted")) { -+ ch->bc->presentation = 1; -+ ch->bc->set_presentation = 1; - } else if (strstr(tok, "not_screened")) { -- ch->bc->pres = 1; -+ chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n"); -+ ch->bc->presentation = 1; -+ ch->bc->set_presentation = 1; - } - break; - case 'i' : -@@ -5710,16 +6593,20 @@ - } - } - -- if (change_jitter) -+ if (change_jitter) { - config_jitterbuffer(ch); -+ } - - if (ch->faxdetect || ch->ast_dsp) { -- if (!ch->dsp) -+ if (!ch->dsp) { - ch->dsp = ast_dsp_new(); -- if (ch->dsp) -+ } -+ if (ch->dsp) { - ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT); -- if (!ch->trans) -+ } -+ if (!ch->trans) { - ch->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW); -+ } - } - - if (ch->ast_dsp) { -@@ -5769,15 +6656,13 @@ - jb->state_empty = 0; - jb->bytes_wrote = 0; - jb->samples = ast_malloc(size * sizeof(char)); -- - if (!jb->samples) { - ast_free(jb); - chan_misdn_log(-1, 0, "No free Mem for jb->samples\n"); - return NULL; - } -- -+ - jb->ok = ast_malloc(size * sizeof(char)); -- - if (!jb->ok) { - ast_free(jb->samples); - ast_free(jb); -@@ -5785,8 +6670,9 @@ - return NULL; - } - -- for (i = 0; i < size; i++) -+ for (i = 0; i < size; i++) { - jb->ok[i] = 0; -+ } - - ast_mutex_init(&jb->mutexjb); - -@@ -5809,8 +6695,9 @@ - { - int i, j, rp, wp; - -- if (!jb || ! data) -+ if (!jb || ! data) { - return 0; -+ } - - ast_mutex_lock(&jb->mutexjb); - -@@ -5822,22 +6709,25 @@ - jb->ok[wp] = 1; - wp = (wp != jb->size - 1) ? wp + 1 : 0; - -- if (wp == jb->rp) -+ if (wp == jb->rp) { - jb->state_full = 1; -+ } - } - -- if (wp >= rp) -+ if (wp >= rp) { - jb->state_buffer = wp - rp; -- else -+ } else { - jb->state_buffer = jb->size - rp + wp; -+ } - chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb); - - if (jb->state_full) { - jb->wp = wp; - - rp = wp; -- for (j = 0; j < jb->upper_threshold; j++) -- rp = rp != 0 ? rp - 1 : jb->size - 1; -+ for (j = 0; j < jb->upper_threshold; j++) { -+ rp = (rp != 0) ? rp - 1 : jb->size - 1; -+ } - jb->rp = rp; - jb->state_full = 0; - jb->state_empty = 1; -@@ -5892,15 +6782,17 @@ - } - } - -- if (wp >= rp) -+ if (wp >= rp) { - jb->state_buffer = wp - rp; -- else -+ } else { - jb->state_buffer = jb->size - rp + wp; -+ } - chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb); - - jb->rp = rp; -- } else -+ } else { - chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb); -+ } - - ast_mutex_unlock(&jb->mutexjb); - -@@ -5935,13 +6827,12 @@ - vsnprintf(buf, sizeof(buf), tmpl, ap); - va_end(ap); - -- if (level == -1) -+ if (level == -1) { - ast_log(LOG_WARNING, "%s", buf); -- -- else if (misdn_debug_only[port] ? -+ } else if (misdn_debug_only[port] ? - (level == 1 && misdn_debug[port]) || (level == misdn_debug[port]) - : level <= misdn_debug[port]) { -- -+ - ast_console_puts(port_buf); - ast_console_puts(buf); - } -@@ -5954,9 +6845,10 @@ - FILE *fp = fopen(global_tracefile, "a+"); - - p = strchr(tmp, '\n'); -- if (p) -+ if (p) { - *p = ':'; -- -+ } -+ - if (!fp) { - ast_console_puts("Error opening Tracefile: [ "); - ast_console_puts(global_tracefile); -Index: channels/chan_skinny.c -=================================================================== ---- a/channels/chan_skinny.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_skinny.c (.../team/group/issue14292) (revision 178988) -@@ -54,6 +54,7 @@ - #include "asterisk/acl.h" - #include "asterisk/callerid.h" - #include "asterisk/cli.h" -+#include "asterisk/manager.h" - #include "asterisk/say.h" - #include "asterisk/cdr.h" - #include "asterisk/astdb.h" -@@ -70,6 +71,13 @@ - #include "asterisk/indications.h" - #include "asterisk/linkedlists.h" - -+#ifdef SKINNY_DEVMODE -+#define SKINNY_DEVONLY(code) \ -+ code -+#else -+#define SKINNY_DEVONLY(code) -+#endif -+ - /************************************* - * Skinny/Asterisk Protocol Settings * - *************************************/ -@@ -103,7 +111,7 @@ - } qos = { 0, 0, 0, 0, 0, 0 }; - - static int keep_alive = 120; --static char vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */ -+static char global_vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */ - static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */ - static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */ - static char date_format[6] = "D-M-Y"; -@@ -159,6 +167,11 @@ - }; - static struct ast_jb_conf global_jbconf; - -+#ifdef SKINNY_DEVMODE -+AST_THREADSTORAGE(message2str_threadbuf); -+#define MESSAGE2STR_BUFSIZE 35 -+#endif -+ - AST_THREADSTORAGE(device2str_threadbuf); - #define DEVICE2STR_BUFSIZE 15 - -@@ -967,32 +980,7 @@ - struct hostent *hp; - static int skinnysock = -1; - static pthread_t accept_t; --static char global_context[AST_MAX_CONTEXT] = "default"; --static char language[MAX_LANGUAGE] = ""; --static char mohinterpret[MAX_MUSICCLASS] = "default"; --static char mohsuggest[MAX_MUSICCLASS] = ""; --static char cid_num[AST_MAX_EXTENSION] = ""; --static char cid_name[AST_MAX_EXTENSION] = ""; --static char linelabel[AST_MAX_EXTENSION] =""; --static char parkinglot[AST_MAX_CONTEXT] =""; --static int nat = 0; --static ast_group_t cur_callergroup = 0; --static ast_group_t cur_pickupgroup = 0; --static int immediate = 0; --static int callwaiting = 0; --static int callreturn = 0; --static int threewaycalling = 0; --static int mwiblink = 0; --/* This is for flashhook transfers */ --static int transfer = 0; --static int cancallforward = 0; --/* static int busycount = 3;*/ --static char accountcode[AST_MAX_ACCOUNT_CODE] = ""; --static char mailbox[AST_MAX_EXTENSION]; --static char regexten[AST_MAX_EXTENSION]; --static int amaflags = 0; - static int callnums = 1; --static int canreinvite = 0; - - #define SKINNY_DEVICE_UNKNOWN -1 - #define SKINNY_DEVICE_NONE 0 -@@ -1077,9 +1065,6 @@ - #define SKINNY_CFWD_BUSY (1 << 1) - #define SKINNY_CFWD_NOANSWER (1 << 2) - --#define TYPE_TRUNK 1 --#define TYPE_LINE 2 -- - /* Skinny rtp stream modes. Do we really need this? */ - #define SKINNY_CX_SENDONLY 0 - #define SKINNY_CX_RECVONLY 1 -@@ -1146,65 +1131,93 @@ - struct skinny_line *parent; - }; - -+#define SKINNY_LINE_OPTIONS \ -+ char name[80]; \ -+ char label[24]; \ -+ char accountcode[AST_MAX_ACCOUNT_CODE]; \ -+ char exten[AST_MAX_EXTENSION]; \ -+ char context[AST_MAX_CONTEXT]; \ -+ char language[MAX_LANGUAGE]; \ -+ char cid_num[AST_MAX_EXTENSION]; \ -+ char cid_name[AST_MAX_EXTENSION]; \ -+ char lastcallerid[AST_MAX_EXTENSION]; \ -+ int cfwdtype; \ -+ char call_forward_all[AST_MAX_EXTENSION]; \ -+ char call_forward_busy[AST_MAX_EXTENSION]; \ -+ char call_forward_noanswer[AST_MAX_EXTENSION]; \ -+ char mailbox[AST_MAX_EXTENSION]; \ -+ char vmexten[AST_MAX_EXTENSION]; \ -+ char regexten[AST_MAX_EXTENSION]; \ -+ char regcontext[AST_MAX_CONTEXT]; \ -+ char parkinglot[AST_MAX_CONTEXT]; \ -+ char mohinterpret[MAX_MUSICCLASS]; \ -+ char mohsuggest[MAX_MUSICCLASS]; \ -+ char lastnumberdialed[AST_MAX_EXTENSION]; \ -+ int curtone; \ -+ ast_group_t callgroup; \ -+ ast_group_t pickupgroup; \ -+ int callwaiting; \ -+ int transfer; \ -+ int threewaycalling; \ -+ int mwiblink; \ -+ int cancallforward; \ -+ int getforward; \ -+ int callreturn; \ -+ int dnd; \ -+ int hascallerid; \ -+ int hidecallerid; \ -+ int amaflags; \ -+ int type; \ -+ int instance; \ -+ int group; \ -+ int needdestroy; \ -+ int confcapability; \ -+ struct ast_codec_pref confprefs; \ -+ int capability; \ -+ struct ast_codec_pref prefs; \ -+ int nonCodecCapability; \ -+ int onhooktime; \ -+ int msgstate; \ -+ int immediate; \ -+ int hookstate; \ -+ int nat; \ -+ int canreinvite; -+ - struct skinny_line { -+ SKINNY_LINE_OPTIONS - ast_mutex_t lock; -- char name[80]; -- char label[24]; /* Label that shows next to the line buttons */ -- char accountcode[AST_MAX_ACCOUNT_CODE]; -- char exten[AST_MAX_EXTENSION]; /* Extension where to start */ -- char context[AST_MAX_CONTEXT]; -- char language[MAX_LANGUAGE]; -- char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */ -- char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */ -- char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */ -- int cfwdtype; -- char call_forward_all[AST_MAX_EXTENSION]; -- char call_forward_busy[AST_MAX_EXTENSION]; -- char call_forward_noanswer[AST_MAX_EXTENSION]; -- char mailbox[AST_MAX_EXTENSION]; -- char vmexten[AST_MAX_EXTENSION]; -- char regexten[AST_MAX_EXTENSION]; /* Extension for auto-extensions */ -- char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extensions */ -- char parkinglot[AST_MAX_CONTEXT]; /* Parkinglot for parkedcalls */ -- char mohinterpret[MAX_MUSICCLASS]; -- char mohsuggest[MAX_MUSICCLASS]; -- char lastnumberdialed[AST_MAX_EXTENSION]; /* Last number that was dialed - used for redial */ -- int curtone; /* Current tone being played */ -- ast_group_t callgroup; -- ast_group_t pickupgroup; - struct ast_event_sub *mwi_event_sub; /* Event based MWI */ -- int callwaiting; -- int transfer; -- int threewaycalling; -- int mwiblink; -- int cancallforward; -- int getforward; -- int callreturn; -- int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */ -- int hascallerid; -- int hidecallerid; -- int amaflags; -- int type; -- int instance; -- int group; -- int needdestroy; -- int capability; -- int nonCodecCapability; -- int onhooktime; -- int msgstate; /* voicemail message state */ -- int immediate; -- int hookstate; -- int nat; -- int canreinvite; -- -- struct ast_codec_pref prefs; - struct skinny_subchannel *activesub; - AST_LIST_HEAD(, skinny_subchannel) sub; - AST_LIST_ENTRY(skinny_line) list; -- struct skinny_device *parent; -+ AST_LIST_ENTRY(skinny_line) all; -+ struct skinny_device *device; - struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */ -+ int newmsgs; - }; - -+struct skinny_line_options{ -+ SKINNY_LINE_OPTIONS -+} default_line_struct = { -+ .callwaiting = 1, -+ .transfer = 1, -+ .mwiblink = 0, -+ .dnd = 0, -+ .hidecallerid = 0, -+ .amaflags = 0, -+ .instance = 0, -+ .canreinvite = 0, -+ .nat = 0, -+ .confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW, -+ .capability = 0, -+ .getforward = 0, -+ .needdestroy = 0, -+ .hookstate = SKINNY_ONHOOK, -+}; -+struct skinny_line_options *default_line = &default_line_struct; -+ -+static AST_LIST_HEAD_STATIC(lines, skinny_line); -+ - struct skinny_speeddial { - ast_mutex_t lock; - char label[42]; -@@ -1226,32 +1239,65 @@ - struct skinny_device *parent; - }; - -+#define SKINNY_DEVICE_OPTIONS \ -+ char name[80]; \ -+ char id[16]; \ -+ char version_id[16]; \ -+ char exten[AST_MAX_EXTENSION]; \ -+ char vmexten[AST_MAX_EXTENSION]; \ -+ int type; \ -+ int registered; \ -+ int lastlineinstance; \ -+ int lastcallreference; \ -+ int confcapability; \ -+ struct ast_codec_pref confprefs; \ -+ int capability; \ -+ int earlyrtp; \ -+ int transfer; \ -+ int callwaiting; \ -+ int mwiblink; \ -+ int dnd; -+ - struct skinny_device { -- /* A device containing one or more lines */ -- char name[80]; -- char id[16]; -- char version_id[16]; -- char exten[AST_MAX_EXTENSION]; /* Cruddy variable name, pick a better one */ -- int type; -- int registered; -- int lastlineinstance; -- int lastcallreference; -- int capability; -- int earlyrtp; -+ SKINNY_DEVICE_OPTIONS -+ struct type *first; -+ struct type *last; -+ ast_mutex_t lock; - struct sockaddr_in addr; - struct in_addr ourip; -+ struct ast_ha *ha; -+ struct skinnysession *session; -+ struct skinny_line *activeline; - AST_LIST_HEAD(, skinny_line) lines; - AST_LIST_HEAD(, skinny_speeddial) speeddials; - AST_LIST_HEAD(, skinny_addon) addons; -- struct ast_codec_pref prefs; -- struct ast_ha *ha; -- struct skinnysession *session; -- struct skinny_line *activeline; - AST_LIST_ENTRY(skinny_device) list; - }; - -+struct skinny_device_options{ -+ SKINNY_DEVICE_OPTIONS -+} default_device_struct = { -+ .transfer = 1, -+ .earlyrtp = 1, -+ .callwaiting = 1, -+ .mwiblink = 0, -+ .dnd = 0, -+ .confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW, -+ .capability = 0, -+}; -+struct skinny_device_options *default_device = &default_device_struct; -+ - static AST_LIST_HEAD_STATIC(devices, skinny_device); - -+/*static struct ast_jb_conf default_jbconf = -+{ -+ .flags = 0, -+ .max_size = -1, -+ .resync_threshold = -1, -+ .impl = "" -+}; -+static struct ast_jb_conf global_jbconf;*/ -+ - struct skinnysession { - pthread_t t; - ast_mutex_t lock; -@@ -1277,6 +1323,7 @@ - static int skinny_senddigit_begin(struct ast_channel *ast, char digit); - static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration); - static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s); -+static void mwi_event_cb(const struct ast_event *event, void *userdata); - - static const struct ast_channel_tech skinny_tech = { - .type = "Skinny", -@@ -1763,6 +1810,7 @@ - struct skinny_speeddial *sd; - struct sockaddr_in sin; - socklen_t slen; -+ int instance; - - AST_LIST_LOCK(&devices); - AST_LIST_TRAVERSE(&devices, d, list){ -@@ -1786,10 +1834,33 @@ - AST_LIST_TRAVERSE(&d->speeddials, sd, list) { - sd->stateid = ast_extension_state_add(sd->context, sd->exten, skinny_extensionstate_cb, sd); - } -+ instance = 0; - AST_LIST_TRAVERSE(&d->lines, l, list) { -- register_exten(l); -- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); -+ instance++; - } -+ AST_LIST_TRAVERSE(&d->lines, l, list) { -+ /* FIXME: All sorts of issues will occur if this line is already connected to a device */ -+ if (l->device) { -+ ast_verb(1, "Line %s already connected to %s. Not connecting to %s.\n", l->name, l->device->name, d->name); -+ } else { -+ l->device = d; -+ l->capability = l->confcapability & d->capability; -+ l->prefs = l->confprefs; -+ if (!l->prefs.order[0]) { -+ l->prefs = d->confprefs; -+ } -+ /* l->capability = d->capability; -+ l->prefs = d->prefs; */ -+ l->instance = instance; -+ l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL); -+ set_callforwards(l, NULL, 0); -+ register_exten(l); -+ /* initialize MWI on line and device */ -+ mwi_event_cb(0, l); -+ ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); -+ } -+ --instance; -+ } - break; - } - } -@@ -1817,14 +1888,151 @@ - ast_extension_state_del(sd->stateid, NULL); - } - AST_LIST_TRAVERSE(&d->lines, l, list) { -- unregister_exten(l); -- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s@%s", l->name, d->name); -+ if (l->device == d) { -+ l->device = NULL; -+ l->capability = 0; -+ ast_parse_allow_disallow(&l->prefs, &l->capability, "all", 0); -+ l->instance = 0; -+ unregister_exten(l); -+ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s@%s", l->name, d->name); -+ } - } - } - - return -1; /* main loop will destroy the session */ - } - -+#ifdef SKINNY_DEVMODE -+static char *message2str(int type) -+{ -+ char *tmp; -+ -+ switch (type) { -+ case KEEP_ALIVE_MESSAGE: -+ return "KEEP_ALIVE_MESSAGE"; -+ case REGISTER_MESSAGE: -+ return "REGISTER_MESSAGE"; -+ case IP_PORT_MESSAGE: -+ return "IP_PORT_MESSAGE"; -+ case KEYPAD_BUTTON_MESSAGE: -+ return "KEYPAD_BUTTON_MESSAGE"; -+ case ENBLOC_CALL_MESSAGE: -+ return "ENBLOC_CALL_MESSAGE"; -+ case STIMULUS_MESSAGE: -+ return "STIMULUS_MESSAGE"; -+ case OFFHOOK_MESSAGE: -+ return "OFFHOOK_MESSAGE"; -+ case ONHOOK_MESSAGE: -+ return "ONHOOK_MESSAGE"; -+ case CAPABILITIES_RES_MESSAGE: -+ return "CAPABILITIES_RES_MESSAGE"; -+ case SPEED_DIAL_STAT_REQ_MESSAGE: -+ return "SPEED_DIAL_STAT_REQ_MESSAGE"; -+ case LINE_STATE_REQ_MESSAGE: -+ return "LINE_STATE_REQ_MESSAGE"; -+ case TIME_DATE_REQ_MESSAGE: -+ return "TIME_DATE_REQ_MESSAGE"; -+ case BUTTON_TEMPLATE_REQ_MESSAGE: -+ return "BUTTON_TEMPLATE_REQ_MESSAGE"; -+ case VERSION_REQ_MESSAGE: -+ return "VERSION_REQ_MESSAGE"; -+ case SERVER_REQUEST_MESSAGE: -+ return "SERVER_REQUEST_MESSAGE"; -+ case ALARM_MESSAGE: -+ return "ALARM_MESSAGE"; -+ case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE: -+ return "OPEN_RECEIVE_CHANNEL_ACK_MESSAGE"; -+ case SOFT_KEY_SET_REQ_MESSAGE: -+ return "SOFT_KEY_SET_REQ_MESSAGE"; -+ case SOFT_KEY_EVENT_MESSAGE: -+ return "SOFT_KEY_EVENT_MESSAGE"; -+ case UNREGISTER_MESSAGE: -+ return "UNREGISTER_MESSAGE"; -+ case SOFT_KEY_TEMPLATE_REQ_MESSAGE: -+ return "SOFT_KEY_TEMPLATE_REQ_MESSAGE"; -+ case HEADSET_STATUS_MESSAGE: -+ return "HEADSET_STATUS_MESSAGE"; -+ case REGISTER_AVAILABLE_LINES_MESSAGE: -+ return "REGISTER_AVAILABLE_LINES_MESSAGE"; -+ case REGISTER_ACK_MESSAGE: -+ return "REGISTER_ACK_MESSAGE"; -+ case START_TONE_MESSAGE: -+ return "START_TONE_MESSAGE"; -+ case STOP_TONE_MESSAGE: -+ return "STOP_TONE_MESSAGE"; -+ case SET_RINGER_MESSAGE: -+ return "SET_RINGER_MESSAGE"; -+ case SET_LAMP_MESSAGE: -+ return "SET_LAMP_MESSAGE"; -+ case SET_SPEAKER_MESSAGE: -+ return "SET_SPEAKER_MESSAGE"; -+ case SET_MICROPHONE_MESSAGE: -+ return "SET_MICROPHONE_MESSAGE"; -+ case START_MEDIA_TRANSMISSION_MESSAGE: -+ return "START_MEDIA_TRANSMISSION_MESSAGE"; -+ case STOP_MEDIA_TRANSMISSION_MESSAGE: -+ return "STOP_MEDIA_TRANSMISSION_MESSAGE"; -+ case CALL_INFO_MESSAGE: -+ return "CALL_INFO_MESSAGE"; -+ case FORWARD_STAT_MESSAGE: -+ return "FORWARD_STAT_MESSAGE"; -+ case SPEED_DIAL_STAT_RES_MESSAGE: -+ return "SPEED_DIAL_STAT_RES_MESSAGE"; -+ case LINE_STAT_RES_MESSAGE: -+ return "LINE_STAT_RES_MESSAGE"; -+ case DEFINETIMEDATE_MESSAGE: -+ return "DEFINETIMEDATE_MESSAGE"; -+ case BUTTON_TEMPLATE_RES_MESSAGE: -+ return "BUTTON_TEMPLATE_RES_MESSAGE"; -+ case VERSION_RES_MESSAGE: -+ return "VERSION_RES_MESSAGE"; -+ case DISPLAYTEXT_MESSAGE: -+ return "DISPLAYTEXT_MESSAGE"; -+ case CLEAR_NOTIFY_MESSAGE: -+ return "CLEAR_NOTIFY_MESSAGE"; -+ case CLEAR_DISPLAY_MESSAGE: -+ return "CLEAR_DISPLAY_MESSAGE"; -+ case CAPABILITIES_REQ_MESSAGE: -+ return "CAPABILITIES_REQ_MESSAGE"; -+ case REGISTER_REJ_MESSAGE: -+ return "REGISTER_REJ_MESSAGE"; -+ case SERVER_RES_MESSAGE: -+ return "SERVER_RES_MESSAGE"; -+ case RESET_MESSAGE: -+ return "RESET_MESSAGE"; -+ case KEEP_ALIVE_ACK_MESSAGE: -+ return "KEEP_ALIVE_ACK_MESSAGE"; -+ case OPEN_RECEIVE_CHANNEL_MESSAGE: -+ return "OPEN_RECEIVE_CHANNEL_MESSAGE"; -+ case CLOSE_RECEIVE_CHANNEL_MESSAGE: -+ return "CLOSE_RECEIVE_CHANNEL_MESSAGE"; -+ case SOFT_KEY_TEMPLATE_RES_MESSAGE: -+ return "SOFT_KEY_TEMPLATE_RES_MESSAGE"; -+ case SOFT_KEY_SET_RES_MESSAGE: -+ return "SOFT_KEY_SET_RES_MESSAGE"; -+ case SELECT_SOFT_KEYS_MESSAGE: -+ return "SELECT_SOFT_KEYS_MESSAGE"; -+ case CALL_STATE_MESSAGE: -+ return "CALL_STATE_MESSAGE"; -+ case DISPLAY_PROMPT_STATUS_MESSAGE: -+ return "DISPLAY_PROMPT_STATUS_MESSAGE"; -+ case CLEAR_PROMPT_MESSAGE: -+ return "CLEAR_PROMPT_MESSAGE"; -+ case DISPLAY_NOTIFY_MESSAGE: -+ return "DISPLAY_NOTIFY_MESSAGE"; -+ case ACTIVATE_CALL_PLANE_MESSAGE: -+ return "ACTIVATE_CALL_PLANE_MESSAGE"; -+ case DIALED_NUMBER_MESSAGE: -+ return "DIALED_NUMBER_MESSAGE"; -+ default: -+ if (!(tmp = ast_threadstorage_get(&message2str_threadbuf, MESSAGE2STR_BUFSIZE))) -+ return "Unknown"; -+ snprintf(tmp, MESSAGE2STR_BUFSIZE, "UNKNOWN_MESSAGE-%d", type); -+ return tmp; -+ } -+} -+#endif -+ - static int transmit_response(struct skinny_device *d, struct skinny_req *req) - { - struct skinnysession *s = d->session; -@@ -1837,8 +2045,7 @@ - - ast_mutex_lock(&s->lock); - -- if (skinnydebug) -- ast_log(LOG_VERBOSE, "writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd); -+ SKINNY_DEVONLY(if (skinnydebug>1) ast_verb(4, "Transmitting %s to %s\n", message2str(req->e), d->name);) - - if (letohl(req->len > SKINNY_MAX_PACKET) || letohl(req->len < 0)) { - ast_log(LOG_WARNING, "transmit_response: the length of the request is out of bounds\n"); -@@ -2037,6 +2244,9 @@ - //req->data.clearpromptstatus.lineInstance = instance; - //req->data.clearpromptstatus.callReference = reference; - -+ /* send datetime message. We have to do it here because it will clear the display on the phone if we do it elsewhere */ -+ handle_time_date_req_message(NULL, d->session); -+ - if (skinnydebug) - ast_verb(1, "Clearing Display\n"); - } else { -@@ -2300,67 +2510,79 @@ - return 0; - } - --static void mwi_event_cb(const struct ast_event *event, void *userdata) -+static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen) - { -- /* This module does not handle MWI in an event-based manner. However, it -- * subscribes to MWI for each mailbox that is configured so that the core -- * knows that we care about it. Then, chan_skinny will get the MWI from the -- * event cache instead of checking the mailbox directly. */ --} -+ struct ast_channel *c = sub->owner; -+ struct skinny_line *l = sub->parent; -+ struct skinny_device *d = l->device; - --static int has_voicemail(struct skinny_line *l) --{ -- int new_msgs; -- struct ast_event *event; -- char *mbox, *context; -+ if (ast_strlen_zero(c->cid.cid_num) || ast_strlen_zero(c->connected.id.number)) -+ return; - -- context = mbox = ast_strdupa(l->mailbox); -- strsep(&context, "@"); -- if (ast_strlen_zero(context)) -- context = "default"; -+ if (sub->owner->_state == AST_STATE_UP) { -+ transmit_callstate(d, l->instance, SKINNY_CONNECTED, sub->callid); -+ transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid); -+ if (sub->outgoing) -+ transmit_callinfo(d, c->connected.id.name, c->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1); -+ else -+ transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2); -+ } else { -+ if (sub->outgoing) { -+ transmit_callstate(d, l->instance, SKINNY_RINGIN, sub->callid); -+ transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid); -+ transmit_callinfo(d, c->connected.id.name, c->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1); -+ } else { -+ if (!sub->ringing) { -+ transmit_callstate(d, l->instance, SKINNY_RINGOUT, sub->callid); -+ transmit_displaypromptstatus(d, "Ring-Out", 0, l->instance, sub->callid); -+ sub->ringing = 1; -+ } else { -+ transmit_callstate(d, l->instance, SKINNY_PROGRESS, sub->callid); -+ transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid); -+ sub->progress = 1; -+ } - -- event = ast_event_get_cached(AST_EVENT_MWI, -- AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox, -- AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, -- AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, -- AST_EVENT_IE_END); -- -- if (event) { -- new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); -- ast_event_destroy(event); -- } else -- new_msgs = ast_app_has_voicemail(l->mailbox, NULL); -- -- return new_msgs; -+ transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2); -+ } -+ } - } - --static void do_housekeeping(struct skinnysession *s) -+static void mwi_event_cb(const struct ast_event *event, void *userdata) - { -- int device_lamp = 0; -- struct skinny_device *d = s->device; -- struct skinny_line *l; -+ struct skinny_line *l = userdata; -+ struct skinny_device *d = l->device; -+ if (d) { -+ struct skinnysession *s = d->session; -+ struct skinny_line *l2; -+ int new_msgs = 0; -+ int dev_msgs = 0; - -- /* Update time on device */ -- handle_time_date_req_message(NULL, s); -+ if (s) { -+ if (event) { -+ l->newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); -+ } - -- /* Set MWI on individual lines */ -- AST_LIST_TRAVERSE(&d->lines, l, list) { -- if (has_voicemail(l)) { -- if (skinnydebug) -- ast_verb(1, "Checking for voicemail Skinny %s@%s\n", l->name, d->name); -- if (skinnydebug) -- ast_verb(1, "Skinny %s@%s has voicemail!\n", l->name, d->name); -- transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON); -- device_lamp++; -- } else { -- transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF); -+ if (l->newmsgs) { -+ transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON); -+ } else { -+ transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF); -+ } -+ -+ /* find out wether the device lamp should be on or off */ -+ AST_LIST_TRAVERSE(&d->lines, l2, list) { -+ if (l2->newmsgs) { -+ dev_msgs++; -+ } -+ } -+ -+ if (dev_msgs) { -+ transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, d->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON); -+ } else { -+ transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, SKINNY_LAMP_OFF); -+ } -+ ast_verb(3, "Skinny mwi_event_cb found %d new messages\n", new_msgs); - } - } -- /* If at least one line has VM, turn the device level lamp on */ -- if (device_lamp) -- transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, SKINNY_LAMP_ON); -- else -- transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, SKINNY_LAMP_OFF); - } - - /* I do not believe skinny can deal with video. -@@ -2435,7 +2657,7 @@ - } - - l = sub->parent; -- d = l->parent; -+ d = l->device; - s = d->session; - - if (rtp){ -@@ -2491,43 +2713,21 @@ - .set_rtp_peer = skinny_set_rtp_peer, - }; - --static char *handle_skinny_set_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { - case CLI_INIT: -- e->command = "skinny set debug [off]"; -+#ifdef SKINNY_DEVMODE -+ e->command = "skinny set debug {off|on|packet}"; - e->usage = -- "Usage: skinny set debug [off]\n" -+ "Usage: skinny set debug {off|on|packet}\n" - " Enables/Disables dumping of Skinny packets for debugging purposes\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- -- if (a->argc < 3 || a->argc > 4) -- return CLI_SHOWUSAGE; -- -- if (a->argc == 3) { -- skinnydebug = 1; -- ast_cli(a->fd, "Skinny Debugging Enabled\n"); -- return CLI_SUCCESS; -- } else if (!strncasecmp(a->argv[3], "off", 3)) { -- skinnydebug = 0; -- ast_cli(a->fd, "Skinny Debugging Disabled\n"); -- return CLI_SUCCESS; -- } else { -- return CLI_SHOWUSAGE; -- } --} -- --static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "skinny set debug {on|off}"; -+#else -+ e->command = "skinny set debug {off|on}"; - e->usage = -- "Usage: skinny set debug {on|off}\n" -+ "Usage: skinny set debug {off|on}\n" - " Enables/Disables dumping of Skinny packets for debugging purposes\n"; -+#endif - return NULL; - case CLI_GENERATE: - return NULL; -@@ -2544,6 +2744,12 @@ - skinnydebug = 0; - ast_cli(a->fd, "Skinny Debugging Disabled\n"); - return CLI_SUCCESS; -+#ifdef SKINNY_DEVMODE -+ } else if (!strncasecmp(a->argv[e->args - 1], "packet", 6)) { -+ skinnydebug = 2; -+ ast_cli(a->fd, "Skinny Debugging Enabled including Packets\n"); -+ return CLI_SUCCESS; -+#endif - } else { - return CLI_SHOWUSAGE; - } -@@ -2745,102 +2951,213 @@ - ast_cli(fd, "none"); - } - --static char *handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[]) - { - struct skinny_device *d; - struct skinny_line *l; -+ const char *id; -+ char idtext[256] = ""; -+ int total_devices = 0; - -- switch (cmd) { -- case CLI_INIT: -- e->command = "skinny show devices"; -- e->usage = -- "Usage: skinny show devices\n" -- " Lists all devices known to the Skinny subsystem.\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -+ if (s) { /* Manager - get ActionID */ -+ id = astman_get_header(m, "ActionID"); -+ if (!ast_strlen_zero(id)) -+ snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id); - } - -- if (a->argc != 3) -+ switch (argc) { -+ case 3: -+ break; -+ default: - return CLI_SHOWUSAGE; -+ } - -- ast_cli(a->fd, "Name DeviceId IP Type R NL\n"); -- ast_cli(a->fd, "-------------------- ---------------- --------------- --------------- - --\n"); -+ if (!s) { -+ ast_cli(fd, "Name DeviceId IP Type R NL\n"); -+ ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n"); -+ } - -- AST_LIST_LOCK(&devices); -+ AST_LIST_LOCK(&devices); - AST_LIST_TRAVERSE(&devices, d, list) { - int numlines = 0; -+ total_devices++; - AST_LIST_TRAVERSE(&d->lines, l, list) { - numlines++; - } -- -- ast_cli(a->fd, "%-20s %-16s %-15s %-15s %c %2d\n", -- d->name, -- d->id, -- d->session?ast_inet_ntoa(d->session->sin.sin_addr):"", -- device2str(d->type), -- d->registered?'Y':'N', -- numlines); -+ if (!s) { -+ ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n", -+ d->name, -+ d->id, -+ d->session?ast_inet_ntoa(d->session->sin.sin_addr):"", -+ device2str(d->type), -+ d->registered?'Y':'N', -+ numlines); -+ } else { -+ astman_append(s, -+ "Event: DeviceEntry\r\n%s" -+ "Channeltype: SKINNY\r\n" -+ "ObjectName: %s\r\n" -+ "ChannelObjectType: device\r\n" -+ "DeviceId: %s\r\n" -+ "IPaddress: %s\r\n" -+ "Type: %s\r\n" -+ "Devicestatus: %s\r\n" -+ "NumberOfLines: %d\r\n", -+ idtext, -+ d->name, -+ d->id, -+ d->session?ast_inet_ntoa(d->session->sin.sin_addr):"-none-", -+ device2str(d->type), -+ d->registered?"registered":"unregistered", -+ numlines); -+ } - } - AST_LIST_UNLOCK(&devices); -+ -+ if (total) -+ *total = total_devices; -+ - return CLI_SUCCESS; - } - --/*! \brief Show device information */ --static char *handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char mandescr_show_devices[] = -+"Description: Lists Skinny devices in text format with details on current status.\n" -+"Devicelist will follow as separate events, followed by a final event called\n" -+"DevicelistComplete.\n" -+"Variables: \n" -+" ActionID: Action ID for this transaction. Will be returned.\n"; -+ -+/*! \brief Show SKINNY devices in the manager API */ -+/* Inspired from chan_sip */ -+static int manager_skinny_show_devices(struct mansession *s, const struct message *m) - { -- struct skinny_device *d; -- struct skinny_line *l; -- struct skinny_speeddial *sd; -- struct skinny_addon *sa; -+ const char *id = astman_get_header(m, "ActionID"); -+ const char *a[] = {"skinny", "show", "devices"}; -+ char idtext[256] = ""; -+ int total = 0; - -+ if (!ast_strlen_zero(id)) -+ snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id); -+ -+ astman_send_listack(s, m, "Device status list will follow", "start"); -+ /* List the devices in separate manager events */ -+ _skinny_show_devices(-1, &total, s, m, 3, a); -+ /* Send final confirmation */ -+ astman_append(s, -+ "Event: DevicelistComplete\r\n" -+ "EventList: Complete\r\n" -+ "ListItems: %d\r\n" -+ "%s" -+ "\r\n", total, idtext); -+ return 0; -+} -+ -+static char *handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ - switch (cmd) { - case CLI_INIT: -- e->command = "skinny show device"; -+ e->command = "skinny show devices"; - e->usage = -- "Usage: skinny show device \n" -- " Lists all deviceinformation of a specific device known to the Skinny subsystem.\n"; -+ "Usage: skinny show devices\n" -+ " Lists all devices known to the Skinny subsystem.\n"; - return NULL; - case CLI_GENERATE: -- return complete_skinny_show_device(a->line, a->word, a->pos, a->n); -+ return NULL; - } - -- if (a->argc < 4) -+ return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv); -+} -+ -+static char *_skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]) -+{ -+ struct skinny_device *d; -+ struct skinny_line *l; -+ struct skinny_speeddial *sd; -+ struct skinny_addon *sa; -+ char codec_buf[512]; -+ -+ if (argc < 4) { - return CLI_SHOWUSAGE; -+ } - - AST_LIST_LOCK(&devices); - AST_LIST_TRAVERSE(&devices, d, list) { -- if (!strcasecmp(a->argv[3], d->id) || !strcasecmp(a->argv[3], d->name)) { -+ if (!strcasecmp(argv[3], d->id) || !strcasecmp(argv[3], d->name)) { - int numlines = 0, numaddons = 0, numspeeddials = 0; - - AST_LIST_TRAVERSE(&d->lines, l, list){ - numlines++; - } - -- ast_cli(a->fd, "Name: %s\n", d->name); -- ast_cli(a->fd, "Id: %s\n", d->id); -- ast_cli(a->fd, "version: %s\n", S_OR(d->version_id, "Unknown")); -- ast_cli(a->fd, "Ip address: %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown")); -- ast_cli(a->fd, "Port: %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0)); -- ast_cli(a->fd, "Device Type: %s\n", device2str(d->type)); -- ast_cli(a->fd, "Registered: %s\n", (d->registered ? "Yes" : "No")); -- ast_cli(a->fd, "Lines: %d\n", numlines); -- AST_LIST_TRAVERSE(&d->lines, l, list) { -- ast_cli(a->fd, " %s (%s)\n", l->name, l->label); -- } - AST_LIST_TRAVERSE(&d->addons, sa, list) { - numaddons++; -- } -- ast_cli(a->fd, "Addons: %d\n", numaddons); -- AST_LIST_TRAVERSE(&d->addons, sa, list) { -- ast_cli(a->fd, " %s\n", sa->type); - } -+ - AST_LIST_TRAVERSE(&d->speeddials, sd, list) { - numspeeddials++; - } -- ast_cli(a->fd, "Speeddials: %d\n", numspeeddials); -- AST_LIST_TRAVERSE(&d->speeddials, sd, list) { -- ast_cli(a->fd, " %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint); -+ -+ if (type == 0) { /* CLI */ -+ ast_cli(fd, "Name: %s\n", d->name); -+ ast_cli(fd, "Id: %s\n", d->id); -+ ast_cli(fd, "version: %s\n", S_OR(d->version_id, "Unknown")); -+ ast_cli(fd, "Ip address: %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown")); -+ ast_cli(fd, "Port: %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0)); -+ ast_cli(fd, "Device Type: %s\n", device2str(d->type)); -+ ast_cli(fd, "Conf Codecs:"); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->confcapability); -+ ast_cli(fd, "%s\n", codec_buf); -+ ast_cli(fd, "Neg Codecs: "); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->capability); -+ ast_cli(fd, "%s\n", codec_buf); -+ ast_cli(fd, "Registered: %s\n", (d->registered ? "Yes" : "No")); -+ ast_cli(fd, "Lines: %d\n", numlines); -+ AST_LIST_TRAVERSE(&d->lines, l, list) { -+ ast_cli(fd, " %s (%s)\n", l->name, l->label); -+ } -+ AST_LIST_TRAVERSE(&d->addons, sa, list) { -+ numaddons++; -+ } -+ ast_cli(fd, "Addons: %d\n", numaddons); -+ AST_LIST_TRAVERSE(&d->addons, sa, list) { -+ ast_cli(fd, " %s\n", sa->type); -+ } -+ AST_LIST_TRAVERSE(&d->speeddials, sd, list) { -+ numspeeddials++; -+ } -+ ast_cli(fd, "Speeddials: %d\n", numspeeddials); -+ AST_LIST_TRAVERSE(&d->speeddials, sd, list) { -+ ast_cli(fd, " %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint); -+ } -+ } else { /* manager */ -+ astman_append(s, "Channeltype: SKINNY\r\n"); -+ astman_append(s, "ObjectName: %s\r\n", d->name); -+ astman_append(s, "ChannelObjectType: device\r\n"); -+ astman_append(s, "Id: %s\r\n", d->id); -+ astman_append(s, "version: %s\r\n", S_OR(d->version_id, "Unknown")); -+ astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown")); -+ astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0)); -+ astman_append(s, "DeviceType: %s\r\n", device2str(d->type)); -+ astman_append(s, "Codecs: "); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->confcapability); -+ astman_append(s, "%s\r\n", codec_buf); -+ astman_append(s, "CodecOrder: "); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->capability); -+ astman_append(s, "%s\r\n", codec_buf); -+ astman_append(s, "Devicestatus: %s\r\n", (d->registered?"registered":"unregistered")); -+ astman_append(s, "NumberOfLines: %d\r\n", numlines); -+ AST_LIST_TRAVERSE(&d->lines, l, list) { -+ astman_append(s, "Line: %s (%s)\r\n", l->name, l->label); -+ } -+ astman_append(s, "NumberOfAddons: %d\r\n", numaddons); -+ AST_LIST_TRAVERSE(&d->addons, sa, list) { -+ astman_append(s, "Addon: %s\r\n", sa->type); -+ } -+ astman_append(s, "NumberOfSpeeddials: %d\r\n", numspeeddials); -+ AST_LIST_TRAVERSE(&d->speeddials, sd, list) { -+ astman_append(s, "Speeddial: %s (%s) ishint: %d\r\n", sd->exten, sd->label, sd->isHint); -+ } - } - } - } -@@ -2848,113 +3165,307 @@ - return CLI_SUCCESS; - } - --static char *handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char mandescr_show_device[] = -+"Description: Show one SKINNY device with details on current status.\n" -+"Variables: \n" -+" Device: The device name you want to check.\n" -+" ActionID: Optional action ID for this AMI transaction.\n"; -+ -+static int manager_skinny_show_device(struct mansession *s, const struct message *m) - { -- struct skinny_device *d; -- struct skinny_line *l; -+ const char *a[4]; -+ const char *device; - -+ device = astman_get_header(m, "Device"); -+ if (ast_strlen_zero(device)) { -+ astman_send_error(s, m, "Device: missing."); -+ return 0; -+ } -+ a[0] = "skinny"; -+ a[1] = "show"; -+ a[2] = "device"; -+ a[3] = device; -+ -+ _skinny_show_device(1, -1, s, m, 4, a); -+ astman_append(s, "\r\n\r\n" ); -+ return 0; -+} -+ -+/*! \brief Show device information */ -+static char *handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ - switch (cmd) { - case CLI_INIT: -- e->command = "skinny show lines"; -+ e->command = "skinny show device"; - e->usage = -- "Usage: skinny show lines\n" -- " Lists all lines known to the Skinny subsystem.\n"; -+ "Usage: skinny show device \n" -+ " Lists all deviceinformation of a specific device known to the Skinny subsystem.\n"; - return NULL; - case CLI_GENERATE: -- return NULL; -+ return complete_skinny_show_device(a->line, a->word, a->pos, a->n); - } - -- if (a->argc != 3) -+ return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv); -+} -+ -+static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[]) -+{ -+ struct skinny_line *l; -+ struct skinny_subchannel *sub; -+ int total_lines = 0; -+ int verbose = 0; -+ const char *id; -+ char idtext[256] = ""; -+ -+ if (s) { /* Manager - get ActionID */ -+ id = astman_get_header(m, "ActionID"); -+ if (!ast_strlen_zero(id)) -+ snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id); -+ } -+ -+ switch (argc) { -+ case 4: -+ verbose = 1; -+ break; -+ case 3: -+ verbose = 0; -+ break; -+ default: - return CLI_SHOWUSAGE; -- -- -- ast_cli(a->fd, "Device Name Instance Name Label \n"); -- ast_cli(a->fd, "-------------------- -------- -------------------- --------------------\n"); -- AST_LIST_LOCK(&devices); -- AST_LIST_TRAVERSE(&devices, d, list) { -- AST_LIST_TRAVERSE(&d->lines, l, list) { -- ast_cli(a->fd, "%-20s %8d %-20s %-20s\n", -- d->name, -+ } -+ -+ if (!s) { -+ ast_cli(fd, "Name Device Name Instance Label \n"); -+ ast_cli(fd, "-------------------- -------------------- -------- --------------------\n"); -+ } -+ AST_LIST_LOCK(&lines); -+ AST_LIST_TRAVERSE(&lines, l, all) { -+ total_lines++; -+ if (!s) { -+ ast_cli(fd, "%-20s %-20s %8d %-20s\n", -+ l->name, -+ (l->device ? l->device->name : "Not connected"), - l->instance, -+ l->label); -+ if (verbose) { -+ AST_LIST_TRAVERSE(&l->sub, sub, list) { -+ ast_cli(fd, " %s> %s to %s\n", -+ (sub == l->activesub?"Active ":"Inactive"), -+ sub->owner->name, -+ (ast_bridged_channel(sub->owner)?ast_bridged_channel(sub->owner)->name:"") -+ ); -+ } -+ } -+ } else { -+ astman_append(s, -+ "Event: LineEntry\r\n%s" -+ "Channeltype: SKINNY\r\n" -+ "ObjectName: %s\r\n" -+ "ChannelObjectType: line\r\n" -+ "Device: %s\r\n" -+ "Instance: %d\r\n" -+ "Label: %s\r\n", -+ idtext, - l->name, -+ (l->device?l->device->name:"None"), -+ l->instance, - l->label); - } -+ AST_LIST_UNLOCK(&lines); - } -- AST_LIST_UNLOCK(&devices); -+ -+ if (total) { -+ *total = total_lines; -+ } -+ - return CLI_SUCCESS; - } - --/*! \brief List line information. */ --static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char mandescr_show_lines[] = -+"Description: Lists Skinny lines in text format with details on current status.\n" -+"Linelist will follow as separate events, followed by a final event called\n" -+"LinelistComplete.\n" -+"Variables: \n" -+" ActionID: Action ID for this transaction. Will be returned.\n"; -+ -+/*! \brief Show Skinny lines in the manager API */ -+/* Inspired from chan_sip */ -+static int manager_skinny_show_lines(struct mansession *s, const struct message *m) - { -- struct skinny_device *d; -- struct skinny_line *l; -- char codec_buf[512]; -- char group_buf[256]; -+ const char *id = astman_get_header(m, "ActionID"); -+ const char *a[] = {"skinny", "show", "lines"}; -+ char idtext[256] = ""; -+ int total = 0; - -+ if (!ast_strlen_zero(id)) -+ snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id); -+ -+ astman_send_listack(s, m, "Line status list will follow", "start"); -+ /* List the lines in separate manager events */ -+ _skinny_show_lines(-1, &total, s, m, 3, a); -+ /* Send final confirmation */ -+ astman_append(s, -+ "Event: LinelistComplete\r\n" -+ "EventList: Complete\r\n" -+ "ListItems: %d\r\n" -+ "%s" -+ "\r\n", total, idtext); -+ return 0; -+} -+ -+static char *handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ int verbose = 0; -+ - switch (cmd) { - case CLI_INIT: -- e->command = "skinny show line"; -+ e->command = "skinny show lines [verbose]"; - e->usage = -- "Usage: skinny show line [ on ]\n" -- " List all lineinformation of a specific line known to the Skinny subsystem.\n"; -+ "Usage: skinny show lines\n" -+ " Lists all lines known to the Skinny subsystem.\n" -+ " If 'verbose' is specified, the output includes\n" -+ " information about subs for each line.\n"; - return NULL; - case CLI_GENERATE: -- return complete_skinny_show_line(a->line, a->word, a->pos, a->n); -+ return NULL; - } - -- if (a->argc < 4) -+ if (a->argc == e->args) { -+ if (!strcasecmp(a->argv[e->args-1], "verbose")) { -+ verbose = 1; -+ } else { -+ return CLI_SHOWUSAGE; -+ } -+ } else if (a->argc != e->args - 1) { - return CLI_SHOWUSAGE; -- -+ } -+ -+ return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv); -+} -+ -+static char *_skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]) -+{ -+ struct skinny_device *d; -+ struct skinny_line *l; -+ struct ast_codec_pref *pref; -+ int x = 0, codec = 0; -+ char codec_buf[512]; -+ char group_buf[256]; -+ char cbuf[256]; -+ -+ switch (argc) { -+ case 4: -+ break; -+ case 6: -+ break; -+ default: -+ return CLI_SHOWUSAGE; -+ } -+ - AST_LIST_LOCK(&devices); - - /* Show all lines matching the one supplied */ - AST_LIST_TRAVERSE(&devices, d, list) { -- if (a->argc == 6 && (strcasecmp(a->argv[5], d->id) && strcasecmp(a->argv[5], d->name))) -+ if (argc == 6 && (strcasecmp(argv[5], d->id) && strcasecmp(argv[5], d->name))) { - continue; -+ } - AST_LIST_TRAVERSE(&d->lines, l, list) { -- if (strcasecmp(a->argv[3], l->name)) -+ if (strcasecmp(argv[3], l->name)) { - continue; -- ast_cli(a->fd, "Line: %s\n", l->name); -- ast_cli(a->fd, "On Device: %s\n", d->name); -- ast_cli(a->fd, "Line Label: %s\n", l->label); -- ast_cli(a->fd, "Extension: %s\n", S_OR(l->exten, "")); -- ast_cli(a->fd, "Context: %s\n", l->context); -- ast_cli(a->fd, "CallGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup)); -- ast_cli(a->fd, "PickupGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup)); -- ast_cli(a->fd, "Language: %s\n", S_OR(l->language, "")); -- ast_cli(a->fd, "Accountcode: %s\n", S_OR(l->accountcode, "")); -- ast_cli(a->fd, "AmaFlag: %s\n", ast_cdr_flags2str(l->amaflags)); -- ast_cli(a->fd, "CallerId Number: %s\n", S_OR(l->cid_num, "")); -- ast_cli(a->fd, "CallerId Name: %s\n", S_OR(l->cid_name, "")); -- ast_cli(a->fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No")); -- ast_cli(a->fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "")); -- ast_cli(a->fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "")); -- ast_cli(a->fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "")); -- ast_cli(a->fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "")); -- ast_cli(a->fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "")); -- ast_cli(a->fd, "MWIblink: %d\n", l->mwiblink); -- ast_cli(a->fd, "Regextension: %s\n", S_OR(l->regexten, "")); -- ast_cli(a->fd, "Regcontext: %s\n", S_OR(l->regcontext, "")); -- ast_cli(a->fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "")); -- ast_cli(a->fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "")); -- ast_cli(a->fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "")); -- ast_cli(a->fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "")); -- ast_cli(a->fd, "Transfer enabled: %s\n", (l->transfer ? "Yes" : "No")); -- ast_cli(a->fd, "Callwaiting: %s\n", (l->callwaiting ? "Yes" : "No")); -- ast_cli(a->fd, "3Way Calling: %s\n", (l->threewaycalling ? "Yes" : "No")); -- ast_cli(a->fd, "Can forward: %s\n", (l->cancallforward ? "Yes" : "No")); -- ast_cli(a->fd, "Do Not Disturb: %s\n", (l->dnd ? "Yes" : "No")); -- ast_cli(a->fd, "NAT: %s\n", (l->nat ? "Yes" : "No")); -- ast_cli(a->fd, "immediate: %s\n", (l->immediate ? "Yes" : "No")); -- ast_cli(a->fd, "Group: %d\n", l->group); -- ast_cli(a->fd, "Codecs: "); -- ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->capability); -- ast_cli(a->fd, "%s\n", codec_buf); -- ast_cli(a->fd, "Codec Order: ("); -- print_codec_to_cli(a->fd, &l->prefs); -- ast_cli(a->fd, ")\n"); -- ast_cli(a->fd, "\n"); -+ } -+ if (type == 0) { /* CLI */ -+ ast_cli(fd, "Line: %s\n", l->name); -+ ast_cli(fd, "On Device: %s\n", d->name); -+ ast_cli(fd, "Line Label: %s\n", l->label); -+ ast_cli(fd, "Extension: %s\n", S_OR(l->exten, "")); -+ ast_cli(fd, "Context: %s\n", l->context); -+ ast_cli(fd, "CallGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup)); -+ ast_cli(fd, "PickupGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup)); -+ ast_cli(fd, "Language: %s\n", S_OR(l->language, "")); -+ ast_cli(fd, "Accountcode: %s\n", S_OR(l->accountcode, "")); -+ ast_cli(fd, "AmaFlag: %s\n", ast_cdr_flags2str(l->amaflags)); -+ ast_cli(fd, "CallerId Number: %s\n", S_OR(l->cid_num, "")); -+ ast_cli(fd, "CallerId Name: %s\n", S_OR(l->cid_name, "")); -+ ast_cli(fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No")); -+ ast_cli(fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "")); -+ ast_cli(fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "")); -+ ast_cli(fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "")); -+ ast_cli(fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "")); -+ ast_cli(fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "")); -+ ast_cli(fd, "MWIblink: %d\n", l->mwiblink); -+ ast_cli(fd, "Regextension: %s\n", S_OR(l->regexten, "")); -+ ast_cli(fd, "Regcontext: %s\n", S_OR(l->regcontext, "")); -+ ast_cli(fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "")); -+ ast_cli(fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "")); -+ ast_cli(fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "")); -+ ast_cli(fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "")); -+ ast_cli(fd, "Transfer enabled: %s\n", (l->transfer ? "Yes" : "No")); -+ ast_cli(fd, "Callwaiting: %s\n", (l->callwaiting ? "Yes" : "No")); -+ ast_cli(fd, "3Way Calling: %s\n", (l->threewaycalling ? "Yes" : "No")); -+ ast_cli(fd, "Can forward: %s\n", (l->cancallforward ? "Yes" : "No")); -+ ast_cli(fd, "Do Not Disturb: %s\n", (l->dnd ? "Yes" : "No")); -+ ast_cli(fd, "NAT: %s\n", (l->nat ? "Yes" : "No")); -+ ast_cli(fd, "immediate: %s\n", (l->immediate ? "Yes" : "No")); -+ ast_cli(fd, "Group: %d\n", l->group); -+ ast_cli(fd, "Conf Codecs: "); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability); -+ ast_cli(fd, "%s\n", codec_buf); -+ ast_cli(fd, "Neg Codecs: "); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->capability); -+ ast_cli(fd, "%s\n", codec_buf); -+ ast_cli(fd, "Codec Order: ("); -+ print_codec_to_cli(fd, &l->prefs); -+ ast_cli(fd, ")\n"); -+ ast_cli(fd, "\n"); -+ } else { /* manager */ -+ astman_append(s, "Channeltype: SKINNY\r\n"); -+ astman_append(s, "ObjectName: %s\r\n", l->name); -+ astman_append(s, "ChannelObjectType: line\r\n"); -+ astman_append(s, "Device: %s\r\n", d->name); -+ astman_append(s, "LineLabel: %s\r\n", l->label); -+ astman_append(s, "Extension: %s\r\n", S_OR(l->exten, "")); -+ astman_append(s, "Context: %s\r\n", l->context); -+ astman_append(s, "CallGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup)); -+ astman_append(s, "PickupGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup)); -+ astman_append(s, "Language: %s\r\n", S_OR(l->language, "")); -+ astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "")); -+ astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(l->amaflags)); -+ astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), l->cid_name, l->cid_num, "")); -+ astman_append(s, "HideCallerId: %s\r\n", (l->hidecallerid ? "Yes" : "No")); -+ astman_append(s, "CFwdAll: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "")); -+ astman_append(s, "CFwdBusy: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "")); -+ astman_append(s, "CFwdNoAnswer: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "")); -+ astman_append(s, "VoicemailBox: %s\r\n", S_OR(l->mailbox, "")); -+ astman_append(s, "VoicemailNumber: %s\r\n", S_OR(l->vmexten, "")); -+ astman_append(s, "MWIblink: %d\r\n", l->mwiblink); -+ astman_append(s, "RegExtension: %s\r\n", S_OR(l->regexten, "")); -+ astman_append(s, "Regcontext: %s\r\n", S_OR(l->regcontext, "")); -+ astman_append(s, "MoHInterpret: %s\r\n", S_OR(l->mohinterpret, "")); -+ astman_append(s, "MoHSuggest: %s\r\n", S_OR(l->mohsuggest, "")); -+ astman_append(s, "LastDialedNr: %s\r\n", S_OR(l->lastnumberdialed, "")); -+ astman_append(s, "LastCallerID: %s\r\n", S_OR(l->lastcallerid, "")); -+ astman_append(s, "Transfer: %s\r\n", (l->transfer ? "Yes" : "No")); -+ astman_append(s, "Callwaiting: %s\r\n", (l->callwaiting ? "Yes" : "No")); -+ astman_append(s, "3WayCalling: %s\r\n", (l->threewaycalling ? "Yes" : "No")); -+ astman_append(s, "CanForward: %s\r\n", (l->cancallforward ? "Yes" : "No")); -+ astman_append(s, "DoNotDisturb: %s\r\n", (l->dnd ? "Yes" : "No")); -+ astman_append(s, "NAT: %s\r\n", (l->nat ? "Yes" : "No")); -+ astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No")); -+ astman_append(s, "Group: %d\r\n", l->group); -+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability); -+ astman_append(s, "Codecs: %s\r\n", codec_buf); -+ astman_append(s, "CodecOrder: "); -+ pref = &l->prefs; -+ for(x = 0; x < 32 ; x++) { -+ codec = ast_codec_pref_index(pref, x); -+ if (!codec) -+ break; -+ astman_append(s, "%s", ast_getformatname(codec)); -+ if (x < 31 && ast_codec_pref_index(pref, x+1)) -+ astman_append(s, ","); -+ } -+ astman_append(s, "\r\n"); -+ } - } - } - -@@ -2962,6 +3473,49 @@ - return CLI_SUCCESS; - } - -+static char mandescr_show_line[] = -+"Description: Show one SKINNY line with details on current status.\n" -+"Variables: \n" -+" Line: The line name you want to check.\n" -+" ActionID: Optional action ID for this AMI transaction.\n"; -+ -+static int manager_skinny_show_line(struct mansession *s, const struct message *m) -+{ -+ const char *a[4]; -+ const char *line; -+ -+ line = astman_get_header(m, "Line"); -+ if (ast_strlen_zero(line)) { -+ astman_send_error(s, m, "Line: missing."); -+ return 0; -+ } -+ a[0] = "skinny"; -+ a[1] = "show"; -+ a[2] = "line"; -+ a[3] = line; -+ -+ _skinny_show_line(1, -1, s, m, 4, a); -+ astman_append(s, "\r\n\r\n" ); -+ return 0; -+} -+ -+/*! \brief List line information. */ -+static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "skinny show line"; -+ e->usage = -+ "Usage: skinny show line [ on ]\n" -+ " List all lineinformation of a specific line known to the Skinny subsystem.\n"; -+ return NULL; -+ case CLI_GENERATE: -+ return complete_skinny_show_line(a->line, a->word, a->pos, a->n); -+ } -+ -+ return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv); -+} -+ - /*! \brief List global settings for the Skinny subsystem. */ - static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { -@@ -2984,7 +3538,7 @@ - ast_cli(a->fd, " Bindaddress: %s\n", ast_inet_ntoa(bindaddr.sin_addr)); - ast_cli(a->fd, " KeepAlive: %d\n", keep_alive); - ast_cli(a->fd, " Date Format: %s\n", date_format); -- ast_cli(a->fd, " Voice Mail Extension: %s\n", S_OR(vmexten, "(not set)")); -+ ast_cli(a->fd, " Voice Mail Extension: %s\n", S_OR(global_vmexten, "(not set)")); - ast_cli(a->fd, " Reg. context: %s\n", S_OR(regcontext, "(not set)")); - ast_cli(a->fd, " Jitterbuffer enabled: %s\n", (ast_test_flag(&global_jbconf, AST_JB_ENABLED) ? "Yes" : "No")); - ast_cli(a->fd, " Jitterbuffer forced: %s\n", (ast_test_flag(&global_jbconf, AST_JB_FORCED) ? "Yes" : "No")); -@@ -2996,249 +3550,20 @@ - return CLI_SUCCESS; - } - --static struct ast_cli_entry cli_skinny_set_debug_deprecated = AST_CLI_DEFINE(handle_skinny_set_debug_deprecated, "Enable/Disable Skinny debugging"); - static struct ast_cli_entry cli_skinny[] = { - AST_CLI_DEFINE(handle_skinny_show_devices, "List defined Skinny devices"), - AST_CLI_DEFINE(handle_skinny_show_device, "List Skinny device information"), - AST_CLI_DEFINE(handle_skinny_show_lines, "List defined Skinny lines per device"), - AST_CLI_DEFINE(handle_skinny_show_line, "List Skinny line information"), - AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"), -- AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging", .deprecate_cmd = &cli_skinny_set_debug_deprecated), -+ AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging"), - AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"), - }; - --static struct skinny_device *build_device(const char *cat, struct ast_variable *v) --{ -- struct skinny_device *d; -- struct skinny_line *l; -- struct skinny_speeddial *sd; -- struct skinny_addon *a; -- char device_vmexten[AST_MAX_EXTENSION]; -- struct ast_variable *chanvars = NULL; -- int lineInstance = 1; -- int speeddialInstance = 1; -- int y = 0; -- -- if (!(d = ast_calloc(1, sizeof(*d)))) { -- return NULL; -- } else { -- ast_copy_string(d->name, cat, sizeof(d->name)); -- d->lastlineinstance = 1; -- d->capability = default_capability; -- d->prefs = default_prefs; -- if (!ast_strlen_zero(vmexten)) -- ast_copy_string(device_vmexten, vmexten, sizeof(device_vmexten)); -- else -- memset(device_vmexten, 0, sizeof(device_vmexten)); -- -- d->earlyrtp = 1; -- while(v) { -- if (!strcasecmp(v->name, "host")) { -- if (ast_get_ip(&d->addr, v->value)) { -- ast_free(d); -- return NULL; -- } -- } else if (!strcasecmp(v->name, "port")) { -- d->addr.sin_port = htons(atoi(v->value)); -- } else if (!strcasecmp(v->name, "device")) { -- ast_copy_string(d->id, v->value, sizeof(d->id)); -- } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { -- d->ha = ast_append_ha(v->name, v->value, d->ha, NULL); -- } else if (!strcasecmp(v->name, "vmexten")) { -- ast_copy_string(device_vmexten, v->value, sizeof(device_vmexten)); -- } else if (!strcasecmp(v->name, "context")) { -- ast_copy_string(global_context, v->value, sizeof(global_context)); -- } else if (!strcasecmp(v->name, "regexten")) { -- ast_copy_string(regexten, v->value, sizeof(regexten)); -- } else if (!strcasecmp(v->name, "allow")) { -- ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 1); -- } else if (!strcasecmp(v->name, "disallow")) { -- ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 0); -- } else if (!strcasecmp(v->name, "version")) { -- ast_copy_string(d->version_id, v->value, sizeof(d->version_id)); -- } else if (!strcasecmp(v->name, "canreinvite")) { -- canreinvite = ast_true(v->value); -- } else if (!strcasecmp(v->name, "earlyrtp")) { -- d->earlyrtp = ast_true(v->value); -- } else if (!strcasecmp(v->name, "nat")) { -- nat = ast_true(v->value); -- } else if (!strcasecmp(v->name, "callerid")) { -- if (!strcasecmp(v->value, "asreceived")) { -- cid_num[0] = '\0'; -- cid_name[0] = '\0'; -- } else { -- ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); -- } -- } else if (!strcasecmp(v->name, "language")) { -- ast_copy_string(language, v->value, sizeof(language)); -- } else if (!strcasecmp(v->name, "accountcode")) { -- ast_copy_string(accountcode, v->value, sizeof(accountcode)); -- } else if (!strcasecmp(v->name, "amaflags")) { -- y = ast_cdr_amaflags2int(v->value); -- if (y < 0) { -- ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno); -- } else { -- amaflags = y; -- } -- } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) { -- ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret)); -- } else if (!strcasecmp(v->name, "mohsuggest")) { -- ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest)); -- } else if (!strcasecmp(v->name, "callgroup")) { -- cur_callergroup = ast_get_group(v->value); -- } else if (!strcasecmp(v->name, "pickupgroup")) { -- cur_pickupgroup = ast_get_group(v->value); -- } else if (!strcasecmp(v->name, "immediate")) { -- immediate = ast_true(v->value); -- } else if (!strcasecmp(v->name, "cancallforward")) { -- cancallforward = ast_true(v->value); -- } else if (!strcasecmp(v->name, "mailbox")) { -- ast_copy_string(mailbox, v->value, sizeof(mailbox)); -- } else if (!strcasecmp(v->name, "hasvoicemail")) { -- if (ast_true(v->value) && ast_strlen_zero(mailbox)) { -- ast_copy_string(mailbox, cat, sizeof(mailbox)); -- } -- } else if (!strcasecmp(v->name, "callreturn")) { -- callreturn = ast_true(v->value); -- } else if (!strcasecmp(v->name, "callwaiting")) { -- callwaiting = ast_true(v->value); -- } else if (!strcasecmp(v->name, "transfer")) { -- transfer = ast_true(v->value); -- } else if (!strcasecmp(v->name, "threewaycalling")) { -- threewaycalling = ast_true(v->value); -- } else if (!strcasecmp(v->name, "mwiblink")) { -- mwiblink = ast_true(v->value); -- } else if (!strcasecmp(v->name, "linelabel")) { -- ast_copy_string(linelabel, v->value, sizeof(linelabel)); -- } else if (!strcasecmp(v->name, "setvar")) { -- chanvars = add_var(v->value, chanvars); -- } else if ( !strcasecmp(v->name, "parkinglot")) { -- ast_copy_string(parkinglot, v->value, sizeof(parkinglot)); -- } else if (!strcasecmp(v->name, "speeddial")) { -- if (!(sd = ast_calloc(1, sizeof(*sd)))) { -- return NULL; -- } else { -- char buf[256]; -- char *stringp = buf, *exten, *context, *label; -- -- ast_copy_string(buf, v->value, sizeof(buf)); -- exten = strsep(&stringp, ","); -- if ((context = strchr(exten, '@'))) { -- *context++ = '\0'; -- } -- label = stringp; -- ast_mutex_init(&sd->lock); -- ast_copy_string(sd->exten, exten, sizeof(sd->exten)); -- if (!ast_strlen_zero(context)) { -- sd->isHint = 1; -- sd->instance = lineInstance++; -- ast_copy_string(sd->context, context, sizeof(sd->context)); -- } else { -- sd->isHint = 0; -- sd->instance = speeddialInstance++; -- sd->context[0] = '\0'; -- } -- ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label)); -- -- sd->parent = d; -- -- AST_LIST_INSERT_HEAD(&d->speeddials, sd, list); -- } -- } else if (!strcasecmp(v->name, "addon")) { -- if (!(a = ast_calloc(1, sizeof(*a)))) { -- return NULL; -- } else { -- ast_mutex_init(&a->lock); -- ast_copy_string(a->type, v->value, sizeof(a->type)); -- -- AST_LIST_INSERT_HEAD(&d->addons, a, list); -- } -- } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) { -- if (!(l = ast_calloc(1, sizeof(*l)))) { -- return NULL; -- } else { -- ast_mutex_init(&l->lock); -- ast_copy_string(l->name, v->value, sizeof(l->name)); -- -- /* XXX Should we check for uniqueness?? XXX */ -- ast_copy_string(l->context, global_context, sizeof(l->context)); -- ast_copy_string(l->cid_num, cid_num, sizeof(l->cid_num)); -- ast_copy_string(l->cid_name, cid_name, sizeof(l->cid_name)); -- ast_copy_string(l->label, linelabel, sizeof(l->label)); -- ast_copy_string(l->parkinglot, parkinglot, sizeof(l->parkinglot)); -- ast_copy_string(l->language, language, sizeof(l->language)); -- ast_copy_string(l->mohinterpret, mohinterpret, sizeof(l->mohinterpret)); -- ast_copy_string(l->mohsuggest, mohsuggest, sizeof(l->mohsuggest)); -- ast_copy_string(l->regexten, regexten, sizeof(l->regexten)); -- ast_copy_string(l->mailbox, mailbox, sizeof(l->mailbox)); -- if (!ast_strlen_zero(mailbox)) { -- char *cfg_mailbox, *cfg_context; -- cfg_context = cfg_mailbox = ast_strdupa(l->mailbox); -- ast_verb(3, "Setting mailbox '%s' on %s@%s\n", cfg_mailbox, d->name, l->name); -- strsep(&cfg_context, "@"); -- if (ast_strlen_zero(cfg_context)) -- cfg_context = "default"; -- l->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL, -- AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, cfg_mailbox, -- AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cfg_context, -- AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, -- AST_EVENT_IE_END); -- } -- ast_copy_string(l->vmexten, device_vmexten, sizeof(vmexten)); -- l->chanvars = chanvars; -- l->msgstate = -1; -- l->capability = d->capability; -- l->prefs = d->prefs; -- l->parent = d; -- if (!strcasecmp(v->name, "trunk")) { -- l->type = TYPE_TRUNK; -- } else { -- l->type = TYPE_LINE; -- } -- l->immediate = immediate; -- l->callgroup = cur_callergroup; -- l->pickupgroup = cur_pickupgroup; -- l->callreturn = callreturn; -- l->cancallforward = cancallforward; -- l->getforward = 0; -- set_callforwards(l, NULL, 0); -- l->callwaiting = callwaiting; -- l->transfer = transfer; -- l->threewaycalling = threewaycalling; -- l->mwiblink = mwiblink; -- l->onhooktime = time(NULL); -- l->instance = lineInstance++; -- /* ASSUME we're onhook at this point */ -- l->hookstate = SKINNY_ONHOOK; -- l->nat = nat; -- l->canreinvite = canreinvite; -- -- if (!AST_LIST_FIRST(&d->lines)) { -- d->activeline = l; -- } -- AST_LIST_INSERT_HEAD(&d->lines, l, list); -- } -- } else { -- ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno); -- } -- v = v->next; -- } -- -- if (!AST_LIST_FIRST(&d->lines)) { -- ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n"); -- return NULL; -- } -- if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) { -- d->addr.sin_port = htons(DEFAULT_SKINNY_PORT); -- } -- } -- return d; --} -- - static void start_rtp(struct skinny_subchannel *sub) - { - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - int hasvideo = 0; - - ast_mutex_lock(&sub->lock); -@@ -3277,7 +3602,7 @@ - struct ast_channel *c = data; - struct skinny_subchannel *sub = c->tech_pvt; - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - int res = 0; - - ast_copy_string(l->lastnumberdialed, c->exten, sizeof(l->lastnumberdialed)); -@@ -3285,6 +3610,8 @@ - l->hidecallerid ? "" : l->cid_num, - l->hidecallerid ? "" : l->cid_name, - c->cid.cid_ani ? NULL : l->cid_num); -+ c->connected.id.number = ast_strdup(c->exten); -+ c->connected.id.name = NULL; - ast_setstate(c, AST_STATE_RING); - if (!sub->rtp) { - start_rtp(sub); -@@ -3302,7 +3629,7 @@ - struct ast_channel *c = data; - struct skinny_subchannel *sub = c->tech_pvt; - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - int len = 0; - int timeout = firstdigittimeout; - int res = 0; -@@ -3407,7 +3734,7 @@ - int tone = 0; - struct skinny_subchannel *sub = ast->tech_pvt; - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - - if (!d->registered) { - ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest); -@@ -3427,12 +3754,18 @@ - return -1; - } - -+ if (AST_LIST_NEXT(sub,list) && !l->callwaiting) { -+ ast_queue_control(ast, AST_CONTROL_BUSY); -+ return -1; -+ } -+ - switch (l->hookstate) { - case SKINNY_OFFHOOK: - tone = SKINNY_CALLWAITTONE; - break; - case SKINNY_ONHOOK: - tone = SKINNY_ALERT; -+ l->activesub = sub; - break; - default: - ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate); -@@ -3442,7 +3775,7 @@ - transmit_callstateonly(d, sub, SKINNY_RINGIN); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN); - transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid); -- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1); -+ transmit_callinfo(d, ast->connected.id.name, ast->connected.id.number, l->cid_name, l->cid_num, l->instance, sub->callid, 1); - transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); - transmit_ringer_mode(d, SKINNY_RING_INSIDE); - -@@ -3463,10 +3796,14 @@ - ast_debug(1, "Asked to hangup channel not connected\n"); - return 0; - } -+ - l = sub->parent; -- d = l->parent; -+ d = l->device; - s = d->session; - -+ if (skinnydebug) -+ ast_verb(3,"Hanging up %s/%d\n",d->name,sub->callid); -+ - AST_LIST_REMOVE(&l->sub, sub, list); - - if (d->registered) { -@@ -3478,6 +3815,7 @@ - - } - if (sub == l->activesub) { /* we are killing the active sub, but there are other subs on the line*/ -+ ast_verb(4,"Killing active sub %d\n", sub->callid); - if (sub->related) { - l->activesub = sub->related; - } else { -@@ -3487,13 +3825,14 @@ - l->activesub = AST_LIST_FIRST(&l->sub); - } - } -- transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); -+ //transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); - transmit_activatecallplane(d, l); - transmit_closereceivechannel(d, sub); - transmit_stopmediatransmission(d, sub); - transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); - transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid); - } else { /* we are killing a background sub on the line with other subs*/ -+ ast_verb(4,"Killing inactive sub %d\n", sub->callid); - if (AST_LIST_NEXT(sub, list)) { - transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); - } else { -@@ -3501,7 +3840,7 @@ - } - } - } else { /* no more subs on line so make idle */ -- -+ ast_verb(4,"Killing only sub %d\n", sub->callid); - l->hookstate = SKINNY_ONHOOK; - transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid); - l->activesub = NULL; -@@ -3512,6 +3851,7 @@ - transmit_stopmediatransmission(d, sub); - transmit_speaker_mode(d, SKINNY_SPEAKEROFF); - transmit_ringer_mode(d, SKINNY_RING_OFF); -+ transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */ - transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid); - /* we should check to see if we can start the ringer if another line is ringing */ - } -@@ -3528,6 +3868,7 @@ - } - ast_mutex_unlock(&sub->lock); - ast_free(sub); -+ ast_module_unref(ast_module_info->self); - return 0; - } - -@@ -3536,7 +3877,7 @@ - int res = 0; - struct skinny_subchannel *sub = ast->tech_pvt; - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - - if (sub->blindxfer) { - if (skinnydebug) -@@ -3561,7 +3902,7 @@ - /* order matters here... - for some reason, transmit_callinfo must be before transmit_callstate, - or you won't get keypad messages in some situations. */ -- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); -+ transmit_callinfo(d, ast->connected.id.name, ast->connected.id.number, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); - transmit_callstateonly(d, sub, SKINNY_CONNECTED); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED); - transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid); -@@ -3678,7 +4019,7 @@ - #if 0 - struct skinny_subchannel *sub = ast->tech_pvt; - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - int tmp; - /* not right */ - sprintf(tmp, "%d", digit); -@@ -3694,7 +4035,7 @@ - - if (!l) - res = AST_DEVICE_INVALID; -- else if (!l->parent) -+ else if (!l->device) - res = AST_DEVICE_UNAVAILABLE; - else if (l->dnd) - res = AST_DEVICE_BUSY; -@@ -3754,6 +4095,12 @@ - return "Hold"; - case AST_CONTROL_UNHOLD: - return "Unhold"; -+ case AST_CONTROL_SRCUPDATE: -+ return "Media Source Update"; -+ case AST_CONTROL_CONNECTED_LINE: -+ return "Connected Line"; -+ case AST_CONTROL_REDIRECTING: -+ return "Redirecting"; - case -1: - return "Stop tone"; - default: -@@ -3768,7 +4115,7 @@ - { - struct skinny_subchannel *xferor; /* the sub doing the transferring */ - struct skinny_subchannel *xferee; /* the sub being transferred */ -- const struct tone_zone_sound *ts = NULL; -+ struct ast_tone_zone_sound *ts = NULL; - - if (ast_bridged_channel(sub->owner) || ast_bridged_channel(sub->related->owner)) { - if (sub->xferor) { -@@ -3791,8 +4138,10 @@ - } - if (xferor->owner->_state == AST_STATE_RING) { - /* play ringing inband */ -- ts = ast_get_indication_tone(xferor->owner->zone, "ring"); -- ast_playtones_start(xferor->owner, 0, ts->data, 1); -+ if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) { -+ ast_playtones_start(xferor->owner, 0, ts->data, 1); -+ ts = ast_tone_zone_sound_unref(ts); -+ } - } - if (skinnydebug) - ast_debug(1, "Transfer Masquerading %s to %s\n", -@@ -3806,8 +4155,10 @@ - ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD); - if (xferor->owner->_state == AST_STATE_RING) { - /* play ringing inband */ -- ts = ast_get_indication_tone(xferor->owner->zone, "ring"); -- ast_playtones_start(xferor->owner, 0, ts->data, 1); -+ if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) { -+ ast_playtones_start(xferor->owner, 0, ts->data, 1); -+ ts = ast_tone_zone_sound_unref(ts); -+ } - } - if (skinnydebug) - ast_debug(1, "Transfer Masquerading %s to %s\n", -@@ -3831,7 +4182,7 @@ - { - struct skinny_subchannel *sub = ast->tech_pvt; - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - struct skinnysession *s = d->session; - - if (!s) { -@@ -3857,7 +4208,7 @@ - transmit_callstateonly(d, sub, SKINNY_RINGOUT); - transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid); - transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid); -- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ -+ transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->connected.id.name, l->lastnumberdialed), S_OR(ast->connected.id.number, l->lastnumberdialed), l->instance, sub->callid, 2); /* 2 = outgoing from phone */ - sub->ringing = 1; - if (!d->earlyrtp) { - break; -@@ -3898,7 +4249,7 @@ - } - transmit_callstateonly(d, sub, SKINNY_PROGRESS); - transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid); -- transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */ -+ transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, S_OR(ast->connected.id.name, l->lastnumberdialed), S_OR(ast->connected.id.number, l->lastnumberdialed), l->instance, sub->callid, 2); /* 2 = outgoing from phone */ - sub->progress = 1; - if (!d->earlyrtp) { - break; -@@ -3919,6 +4270,9 @@ - case AST_CONTROL_SRCUPDATE: - ast_rtp_new_source(sub->rtp); - break; -+ case AST_CONTROL_CONNECTED_LINE: -+ update_connectedline(sub, data, datalen); -+ break; - default: - ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); - return -1; /* Tell asterisk to provide inband signalling */ -@@ -3930,10 +4284,15 @@ - { - struct ast_channel *tmp; - struct skinny_subchannel *sub; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - struct ast_variable *v = NULL; - int fmt; - -+ if (!l->device) { -+ ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name); -+ return NULL; -+ } -+ - tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums); - if (!tmp) { - ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); -@@ -3959,12 +4318,13 @@ - sub->related = NULL; - - AST_LIST_INSERT_HEAD(&l->sub, sub, list); -- l->activesub = sub; -+ //l->activesub = sub; - } - tmp->tech = &skinny_tech; - tmp->tech_pvt = sub; - tmp->nativeformats = l->capability; - if (!tmp->nativeformats) -+ // Should throw an error - tmp->nativeformats = default_capability; - fmt = ast_best_codec(tmp->nativeformats); - if (skinnydebug) -@@ -4030,7 +4390,7 @@ - static int skinny_hold(struct skinny_subchannel *sub) - { - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - - /* Don't try to hold a channel that doesn't exist */ - if (!sub || !sub->owner) -@@ -4057,7 +4417,7 @@ - static int skinny_unhold(struct skinny_subchannel *sub) - { - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - - /* Don't try to unhold a channel that doesn't exist */ - if (!sub || !sub->owner) -@@ -4090,10 +4450,10 @@ - } else { - if (sub->onhold) { - skinny_unhold(sub); -- transmit_selectsoftkeys(sub->parent->parent, sub->parent->instance, sub->callid, KEYDEF_CONNECTED); -+ transmit_selectsoftkeys(sub->parent->device, sub->parent->instance, sub->callid, KEYDEF_CONNECTED); - } else { - skinny_hold(sub); -- transmit_selectsoftkeys(sub->parent->parent, sub->parent->instance, sub->callid, KEYDEF_ONHOLD); -+ transmit_selectsoftkeys(sub->parent->device, sub->parent->instance, sub->callid, KEYDEF_ONHOLD); - } - } - return 1; -@@ -4102,7 +4462,7 @@ - static int handle_transfer_button(struct skinny_subchannel *sub) - { - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - struct skinny_subchannel *newsub; - struct ast_channel *c; - pthread_t t; -@@ -4166,7 +4526,6 @@ - return -1; - - transmit_response(s->device, req); -- do_housekeeping(s); - return 1; - } - -@@ -4238,7 +4597,7 @@ - static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype) - { - struct skinny_line *l = sub->parent; -- struct skinny_device *d = l->parent; -+ struct skinny_device *d = l->device; - struct ast_channel *c = sub->owner; - pthread_t t; - -@@ -4377,6 +4736,7 @@ - if (!l) { - return 0; - } -+ sub = l->activesub; - } else { - l = sub->parent; - } -@@ -4400,6 +4760,7 @@ - } else { - sub = c->tech_pvt; - l = sub->parent; -+ l->activesub = sub; - if (l->hookstate == SKINNY_ONHOOK) { - l->hookstate = SKINNY_OFFHOOK; - transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid); -@@ -4440,6 +4801,7 @@ - } else { - sub = c->tech_pvt; - l = sub->parent; -+ l->activesub = sub; - if (l->hookstate == SKINNY_ONHOOK) { - l->hookstate = SKINNY_OFFHOOK; - transmit_speaker_mode(d, SKINNY_SPEAKERON); -@@ -4499,6 +4861,7 @@ - } else { - sub = c->tech_pvt; - l = sub->parent; -+ l->activesub = sub; - - if (ast_strlen_zero(l->vmexten)) /* Exit the call if no VM pilot */ - break; -@@ -4516,7 +4879,7 @@ - transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid); - transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT); - -- if (!ast_ignore_pattern(c->context, vmexten)) { -+ if (!ast_ignore_pattern(c->context, l->vmexten)) { - transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid); - } - -@@ -4663,6 +5026,7 @@ - c = skinny_new(l, AST_STATE_DOWN); - if (c) { - sub = c->tech_pvt; -+ l->activesub = sub; - transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid); - if (skinnydebug) - ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name); -@@ -4760,6 +5124,7 @@ - c = skinny_new(l, AST_STATE_DOWN); - if (c) { - sub = c->tech_pvt; -+ l->activesub = sub; - transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid); - if (skinnydebug) - ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name); -@@ -4801,6 +5166,9 @@ - } else { - l = d->activeline; - sub = l->activesub; -+ if (!sub) { -+ return 0; -+ } - } - - if (l->hookstate == SKINNY_ONHOOK) { -@@ -4848,10 +5216,6 @@ - l->name, d->name, sub->callid); - } - } -- /* The bit commented below gives a very occasional core dump. */ -- if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) /*&& !AST_LIST_NEXT(sub, list)->rtp*/)) { -- do_housekeeping(s); -- } - return 1; - } - -@@ -4879,11 +5243,11 @@ - codecs |= acodec; - } - -- d->capability &= codecs; -+ d->capability = d->confcapability & codecs; - ast_verb(0, "Device capability set to '%d'\n", d->capability); - AST_LIST_TRAVERSE(&d->lines, l, list) { - ast_mutex_lock(&l->lock); -- l->capability = d->capability; -+ l->capability = l->confcapability & d->capability; - ast_mutex_unlock(&l->lock); - } - -@@ -5254,6 +5618,7 @@ - l->hookstate = SKINNY_OFFHOOK; - - sub = c->tech_pvt; -+ l->activesub = sub; - transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid); - if (skinnydebug) - ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name); -@@ -5368,6 +5733,7 @@ - ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name); - } else { - sub = c->tech_pvt; -+ l->activesub = sub; - if (l->hookstate == SKINNY_ONHOOK) { - l->hookstate = SKINNY_OFFHOOK; - transmit_speaker_mode(d, SKINNY_SPEAKERON); -@@ -5406,6 +5772,7 @@ - ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name); - } else { - sub = c->tech_pvt; -+ l->activesub = sub; - if (l->hookstate == SKINNY_ONHOOK) { - l->hookstate = SKINNY_OFFHOOK; - transmit_speaker_mode(d, SKINNY_SPEAKERON); -@@ -5472,6 +5839,7 @@ - ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name); - } else { - sub = c->tech_pvt; -+ l->activesub = sub; - handle_callforward_button(sub, SKINNY_CFWD_ALL); - } - break; -@@ -5489,6 +5857,7 @@ - ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name); - } else { - sub = c->tech_pvt; -+ l->activesub = sub; - handle_callforward_button(sub, SKINNY_CFWD_BUSY); - } - break; -@@ -5507,6 +5876,7 @@ - ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name); - } else { - sub = c->tech_pvt; -+ l->activesub = sub; - handle_callforward_button(sub, SKINNY_CFWD_NOANSWER); - } - #endif -@@ -5564,7 +5934,6 @@ - } - } - if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) { -- do_housekeeping(s); - ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); - } - } -@@ -5704,6 +6073,10 @@ - return 0; - } - -+ SKINNY_DEVONLY(if (skinnydebug > 1) { -+ ast_verb(4, "Received %s from %s\n", message2str(req->e), s->device->name); -+ }) -+ - switch(letohl(req->e)) { - case KEEP_ALIVE_MESSAGE: - res = handle_keep_alive_message(req, s); -@@ -5867,9 +6240,9 @@ - { - struct skinnysession *cur; - AST_LIST_LOCK(&sessions); -- AST_LIST_TRAVERSE(&sessions, cur, list) { -+ AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, cur, list) { - if (cur == s) { -- AST_LIST_REMOVE(&sessions, s, list); -+ AST_LIST_REMOVE_CURRENT(list); - if (s->fd > -1) - close(s->fd); - -@@ -5880,6 +6253,7 @@ - ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s); - } - } -+ AST_LIST_TRAVERSE_SAFE_END - AST_LIST_UNLOCK(&sessions); - } - -@@ -6024,7 +6398,6 @@ - struct skinnysession *s; - struct protoent *p; - int arg = 1; -- pthread_t tcp_thread; - - for (;;) { - sinlen = sizeof(sin); -@@ -6049,7 +6422,7 @@ - AST_LIST_INSERT_HEAD(&sessions, s, list); - AST_LIST_UNLOCK(&sessions); - -- if (ast_pthread_create_detached(&tcp_thread, NULL, skinny_session, s)) { -+ if (ast_pthread_create(&s->t, NULL, skinny_session, s)) { - destroy_session(s); - } - } -@@ -6159,104 +6532,508 @@ - return tmpc; - } - --static int reload_config(void) --{ -- int on = 1; -- struct ast_config *cfg; -- struct ast_variable *v; -- char *cat; -- struct skinny_device *d; -- int oldport = ntohs(bindaddr.sin_port); -- char *stringp, *context, *oldregcontext; -- char newcontexts[AST_MAX_CONTEXT], oldcontexts[AST_MAX_CONTEXT]; -- struct ast_flags config_flags = { 0 }; -+ #define TYPE_GENERAL 1 -+ #define TYPE_DEF_DEVICE 2 -+ #define TYPE_DEF_LINE 4 -+ #define TYPE_DEVICE 8 -+ #define TYPE_LINE 16 -+ -+ #define CLINE_OPTS ((struct skinny_line_options *)item) -+ #define CLINE ((struct skinny_line *)item) -+ #define CDEV_OPTS ((struct skinny_device_options *)item) -+ #define CDEV ((struct skinny_device *)item) -+ -+ static void config_parse_variables(int type, void *item, struct ast_variable *vptr) -+ { -+ struct ast_variable *v; -+ int lineInstance = 1; -+ int speeddialInstance = 1; -+ -+ while(vptr) { -+ v = vptr; -+ vptr = vptr->next; -+ -+ if (type & (TYPE_GENERAL)) { -+ char newcontexts[AST_MAX_CONTEXT]; -+ char oldcontexts[AST_MAX_CONTEXT]; -+ char *stringp, *context, *oldregcontext; -+ if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) { -+ v = v->next; -+ continue; -+ } -+ if (!strcasecmp(v->name, "bindaddr")) { -+ if (!(hp = ast_gethostbyname(v->value, &ahp))) { -+ ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); -+ } else { -+ memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); -+ } -+ continue; -+ } else if (!strcasecmp(v->name, "keepalive")) { -+ keep_alive = atoi(v->value); -+ continue; -+ } else if (!strcasecmp(v->name, "regcontext")) { -+ ast_copy_string(newcontexts, v->value, sizeof(newcontexts)); -+ stringp = newcontexts; -+ /* Initialize copy of current global_regcontext for later use in removing stale contexts */ -+ ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts)); -+ oldregcontext = oldcontexts; -+ /* Let's remove any contexts that are no longer defined in regcontext */ -+ cleanup_stale_contexts(stringp, oldregcontext); -+ /* Create contexts if they don't exist already */ -+ while ((context = strsep(&stringp, "&"))) { -+ ast_copy_string(used_context, context, sizeof(used_context)); -+ ast_context_find_or_create(NULL, NULL, context, "Skinny"); -+ } -+ ast_copy_string(regcontext, v->value, sizeof(regcontext)); -+ continue; -+ } else if (!strcasecmp(v->name, "dateformat")) { -+ memcpy(date_format, v->value, sizeof(date_format)); -+ continue; -+ } else if (!strcasecmp(v->name, "tos")) { -+ if (ast_str2tos(v->value, &qos.tos)) -+ ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno); -+ continue; -+ } else if (!strcasecmp(v->name, "tos_audio")) { -+ if (ast_str2tos(v->value, &qos.tos_audio)) -+ ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno); -+ continue; -+ } else if (!strcasecmp(v->name, "tos_video")) { -+ if (ast_str2tos(v->value, &qos.tos_video)) -+ ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno); -+ continue; -+ } else if (!strcasecmp(v->name, "cos")) { -+ if (ast_str2cos(v->value, &qos.cos)) -+ ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno); -+ continue; -+ } else if (!strcasecmp(v->name, "cos_audio")) { -+ if (ast_str2cos(v->value, &qos.cos_audio)) -+ ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno); -+ continue; -+ } else if (!strcasecmp(v->name, "cos_video")) { -+ if (ast_str2cos(v->value, &qos.cos_video)) -+ ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno); -+ continue; -+ } else if (!strcasecmp(v->name, "bindport")) { -+ if (sscanf(v->value, "%d", &ourport) == 1) { -+ bindaddr.sin_port = htons(ourport); -+ } else { -+ ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config); -+ } -+ continue; -+ } else if (!strcasecmp(v->name, "allow")) { -+ ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1); -+ continue; -+ } else if (!strcasecmp(v->name, "disallow")) { -+ ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0); -+ continue; -+ } -+ } -+ -+ if (!strcasecmp(v->name, "transfer")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ CDEV_OPTS->transfer = ast_true(v->value); -+ continue; -+ } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->transfer = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "callwaiting")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ CDEV_OPTS->callwaiting = ast_true(v->value); -+ continue; -+ } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->callwaiting = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "canreinvite")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->canreinvite = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "nat")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->nat = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "context")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context)); -+ continue; -+ } -+ }else if (!strcasecmp(v->name, "vmexten")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten)); -+ continue; -+ } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "mwiblink")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ CDEV_OPTS->mwiblink = ast_true(v->value); -+ continue; -+ } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->mwiblink = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "linelabel")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "callerid")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ if (!strcasecmp(v->value, "asreceived")) { -+ CLINE_OPTS->cid_num[0] = '\0'; -+ CLINE_OPTS->cid_name[0] = '\0'; -+ } else { -+ ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num)); -+ } -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "amaflags")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ int tempamaflags = ast_cdr_amaflags2int(v->value); -+ if (tempamaflags < 0) { -+ ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno); -+ } else { -+ CLINE_OPTS->amaflags = tempamaflags; -+ } -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "regexten")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "language")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "accountcode")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "mohsuggest")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "callgroup")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->callgroup = ast_get_group(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "pickupgroup")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->pickupgroup = ast_get_group(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "immediate")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->immediate = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "cancallforward")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->cancallforward = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "mailbox")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox)); -+ continue; -+ } -+ } else if ( !strcasecmp(v->name, "parkinglot")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "hasvoicemail")) { -+ if (type & (TYPE_LINE)) { -+ if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) { -+ ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox)); -+ } -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "callreturn")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->callreturn = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "threewaycalling")) { -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ CLINE_OPTS->threewaycalling = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "setvar")) { -+ if (type & (TYPE_LINE)) { -+ CLINE->chanvars = add_var(v->value, CLINE->chanvars); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "earlyrtp")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ CDEV_OPTS->earlyrtp = ast_true(v->value); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "host")) { -+ if (type & (TYPE_DEVICE)) { -+ if (ast_get_ip(&CDEV->addr, v->value)) { -+ ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno); -+ } -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "port")) { -+ if (type & (TYPE_DEF_DEVICE)) { -+ CDEV->addr.sin_port = htons(atoi(v->value)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "device")) { -+ if (type & (TYPE_DEVICE)) { -+ ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) { -+ if (type & (TYPE_DEVICE)) { -+ CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "allow")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 1); -+ continue; -+ } -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 1); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "disallow")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 0); -+ continue; -+ } -+ if (type & (TYPE_DEF_LINE | TYPE_LINE)) { -+ ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 0); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "version")) { -+ if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) { -+ ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id)); -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "line")) { -+ if (type & (TYPE_DEVICE)) { -+ struct skinny_line *l; -+ AST_LIST_TRAVERSE(&lines, l, all) { -+ if (!strcasecmp(v->value, l->name)) { - -- if (gethostname(ourhost, sizeof(ourhost))) { -- ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n"); -- return 0; -- } -- cfg = ast_config_load(config, config_flags); -+ /* FIXME: temp solution about line conflicts */ -+ struct skinny_device *d; -+ struct skinny_line *l2; -+ int lineinuse = 0; -+ AST_LIST_TRAVERSE(&devices, d, list) { -+ AST_LIST_TRAVERSE(&d->lines, l2, list) { -+ if (l2 == l) { -+ ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name); -+ lineinuse++; -+ } -+ } -+ } -+ if (!lineinuse) { -+ if (!AST_LIST_FIRST(&CDEV->lines)) { -+ CDEV->activeline = l; -+ } -+ lineInstance++; -+ AST_LIST_INSERT_HEAD(&CDEV->lines, l, list); -+ } -+ break; -+ } -+ } -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "speeddial")) { -+ if (type & (TYPE_DEVICE)) { -+ struct skinny_speeddial *sd; -+ if (!(sd = ast_calloc(1, sizeof(*sd)))) { -+ ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name); -+ continue; -+ } else { -+ char buf[256]; -+ char *stringp = buf, *exten, *context, *label; -+ ast_copy_string(buf, v->value, sizeof(buf)); -+ exten = strsep(&stringp, ","); -+ if ((context = strchr(exten, '@'))) { -+ *context++ = '\0'; -+ } -+ label = stringp; -+ ast_mutex_init(&sd->lock); -+ ast_copy_string(sd->exten, exten, sizeof(sd->exten)); -+ if (!ast_strlen_zero(context)) { -+ sd->isHint = 1; -+ sd->instance = lineInstance++; -+ ast_copy_string(sd->context, context, sizeof(sd->context)); -+ } else { -+ sd->isHint = 0; -+ sd->instance = speeddialInstance++; -+ sd->context[0] = '\0'; -+ } -+ ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label)); -+ sd->parent = CDEV; -+ AST_LIST_INSERT_HEAD(&CDEV->speeddials, sd, list); -+ } -+ continue; -+ } -+ } else if (!strcasecmp(v->name, "addon")) { -+ if (type & (TYPE_DEVICE)) { -+ struct skinny_addon *a; -+ if (!(a = ast_calloc(1, sizeof(*a)))) { -+ ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name); -+ continue; -+ } else { -+ ast_mutex_init(&a->lock); -+ ast_copy_string(a->type, v->value, sizeof(a->type)); -+ AST_LIST_INSERT_HEAD(&CDEV->addons, a, list); -+ } -+ continue; -+ } - -- /* We *must* have a config file otherwise stop immediately */ -- if (!cfg) { -- ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config); -- return -1; -- } -+ } else { -+ ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno); -+ continue; -+ } -+ ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno); -+ } -+ } -+ -+ static struct skinny_line *config_line(const char *lname, struct ast_variable *v) -+ { -+ struct skinny_line *l; -+ -+ ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname); -+ -+ AST_LIST_LOCK(&lines); -+ AST_LIST_TRAVERSE(&lines, l, all) { -+ if (!strcasecmp(lname, l->name)) { -+ ast_log(LOG_NOTICE, "Line %s already exists. Reconfiguring.\n", lname); -+ break; -+ } -+ } -+ if (!l) { -+ ast_log(LOG_NOTICE, "Creating line %s.\n", lname); -+ if (!(l=ast_calloc(1, sizeof(*l)))) { -+ ast_verb(1, "Unable to allocate memory for line %s.\n", lname); -+ AST_LIST_UNLOCK(&lines); -+ return NULL; -+ } -+ memcpy(l, default_line, sizeof(*default_line)); -+ ast_mutex_init(&l->lock); -+ ast_copy_string(l->name, lname, sizeof(l->name)); -+ AST_LIST_INSERT_TAIL(&lines, l, all); -+ } -+ ast_mutex_lock(&l->lock); -+ AST_LIST_UNLOCK(&lines); -+ -+ config_parse_variables(TYPE_LINE, l, v); -+ -+ if (!ast_strlen_zero(l->mailbox)) { -+ char *cfg_mailbox, *cfg_context; -+ cfg_context = cfg_mailbox = ast_strdupa(l->mailbox); -+ ast_verb(3, "Setting mailbox '%s' on line %s\n", cfg_mailbox, l->name); -+ strsep(&cfg_context, "@"); -+ if (ast_strlen_zero(cfg_context)) -+ cfg_context = "default"; -+ l->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, l, -+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, cfg_mailbox, -+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cfg_context, -+ AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, -+ AST_EVENT_IE_END); -+ } -+ -+ ast_mutex_unlock(&l->lock); -+ return l; -+ } -+ -+ static struct skinny_device *config_device(const char *dname, struct ast_variable *v) -+ { -+ struct skinny_device *d; -+ -+ ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname); -+ -+ AST_LIST_LOCK(&devices); -+ AST_LIST_TRAVERSE(&devices, d, list) { -+ if (!strcasecmp(dname, d->name)) { -+ break; -+ } -+ } -+ if (!d) { -+ if (!(d = ast_calloc(1, sizeof(*d)))) { -+ ast_verb(1, "Unable to allocate memory for device %s.\n", dname); -+ AST_LIST_UNLOCK(&devices); -+ return NULL; -+ } -+ memcpy(d, default_device, sizeof(*default_device)); -+ ast_mutex_init(&d->lock); -+ ast_copy_string(d->name, dname, sizeof(d->name)); -+ AST_LIST_INSERT_HEAD(&devices, d, list); -+ } -+ ast_mutex_lock(&d->lock); -+ AST_LIST_UNLOCK(&devices); -+ -+ config_parse_variables(TYPE_DEVICE, d, v); -+ -+ if (!AST_LIST_FIRST(&d->lines)) { -+ ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n"); -+ ast_mutex_unlock(&d->lock); -+ return NULL; -+ } -+ if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) { -+ d->addr.sin_port = htons(DEFAULT_SKINNY_PORT); -+ } -+ -+ ast_mutex_unlock(&d->lock); -+ return d; -+ } -+ -+ static int config_load(void) -+ { -+ int on = 1; -+ struct ast_config *cfg; -+ char *cat; -+ struct skinny_device *d; -+ struct skinny_line *l; -+ int oldport = ntohs(bindaddr.sin_port); -+ struct ast_flags config_flags = { 0 }; -+ -+ ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config); -+ -+ if (gethostname(ourhost, sizeof(ourhost))) { -+ ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n"); -+ return 0; -+ } -+ cfg = ast_config_load(config, config_flags); -+ -+ /* We *must* have a config file otherwise stop immediately */ -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config); -+ return -1; -+ } - memset(&bindaddr, 0, sizeof(bindaddr)); - memset(&default_prefs, 0, sizeof(default_prefs)); - -- /* Initialize copy of current global_regcontext for later use in removing stale contexts */ -- ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts)); -- oldregcontext = oldcontexts; -- - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); - - /* load the general section */ -- v = ast_variable_browse(cfg, "general"); -- while (v) { -- /* handle jb conf */ -- if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) { -- v = v->next; -- continue; -- } -- -- /* Create the interface list */ -- if (!strcasecmp(v->name, "bindaddr")) { -- if (!(hp = ast_gethostbyname(v->value, &ahp))) { -- ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); -- } else { -- memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); -- } -- } else if (!strcasecmp(v->name, "keepalive")) { -- keep_alive = atoi(v->value); -- } else if (!strcasecmp(v->name, "vmexten")) { -- ast_copy_string(vmexten, v->value, sizeof(vmexten)); -- } else if (!strcasecmp(v->name, "regcontext")) { -- ast_copy_string(newcontexts, v->value, sizeof(newcontexts)); -- stringp = newcontexts; -- /* Let's remove any contexts that are no longer defined in regcontext */ -- cleanup_stale_contexts(stringp, oldregcontext); -- /* Create contexts if they don't exist already */ -- while ((context = strsep(&stringp, "&"))) { -- ast_copy_string(used_context, context, sizeof(used_context)); -- ast_context_find_or_create(NULL, NULL, context, "Skinny"); -- } -- ast_copy_string(regcontext, v->value, sizeof(regcontext)); -- } else if (!strcasecmp(v->name, "dateformat")) { -- memcpy(date_format, v->value, sizeof(date_format)); -- } else if (!strcasecmp(v->name, "tos")) { -- if (ast_str2tos(v->value, &qos.tos)) -- ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno); -- } else if (!strcasecmp(v->name, "tos_audio")) { -- if (ast_str2tos(v->value, &qos.tos_audio)) -- ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno); -- } else if (!strcasecmp(v->name, "tos_video")) { -- if (ast_str2tos(v->value, &qos.tos_video)) -- ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno); -- } else if (!strcasecmp(v->name, "cos")) { -- if (ast_str2cos(v->value, &qos.cos)) -- ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno); -- } else if (!strcasecmp(v->name, "cos_audio")) { -- if (ast_str2cos(v->value, &qos.cos_audio)) -- ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno); -- } else if (!strcasecmp(v->name, "cos_video")) { -- if (ast_str2cos(v->value, &qos.cos_video)) -- ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno); -- } else if (!strcasecmp(v->name, "allow")) { -- ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1); -- } else if (!strcasecmp(v->name, "disallow")) { -- ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0); -- } else if (!strcasecmp(v->name, "bindport")) { -- if (sscanf(v->value, "%d", &ourport) == 1) { -- bindaddr.sin_port = htons(ourport); -- } else { -- ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config); -- } -- } -- v = v->next; -- } -- -+ cat = ast_category_browse(cfg, "general"); -+ config_parse_variables(TYPE_GENERAL, NULL, ast_variable_browse(cfg, "general")); -+ - if (ntohl(bindaddr.sin_addr.s_addr)) { - __ourip = bindaddr.sin_addr; - } else { -@@ -6273,22 +7050,26 @@ - } - bindaddr.sin_family = AF_INET; - -- /* load the device sections */ -- cat = ast_category_browse(cfg, NULL); -- while(cat) { -- if (!strcasecmp(cat, "general")) { -- /* Nothing to do */ -- } else { -- d = build_device(cat, ast_variable_browse(cfg, cat)); -- if (d) { -- ast_verb(3, "Added device '%s'\n", d->name); -- AST_LIST_LOCK(&devices); -- AST_LIST_INSERT_HEAD(&devices, d, list); -- AST_LIST_UNLOCK(&devices); -- } -- } -+ /* load the lines sections */ -+ default_line->confcapability = default_capability; -+ default_line->confprefs = default_prefs; -+ config_parse_variables(TYPE_DEF_LINE, default_line, ast_variable_browse(cfg, "lines")); -+ cat = ast_category_browse(cfg, "lines"); -+ while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) { -+ l = config_line(cat, ast_variable_browse(cfg, cat)); - cat = ast_category_browse(cfg, cat); - } -+ -+ /* load the devices sections */ -+ default_device->confcapability = default_capability; -+ default_device->confprefs = default_prefs; -+ config_parse_variables(TYPE_DEF_DEVICE, default_device, ast_variable_browse(cfg, "devices")); -+ cat = ast_category_browse(cfg, "devices"); -+ while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) { -+ d = config_device(cat, ast_variable_browse(cfg, cat)); -+ cat = ast_category_browse(cfg, cat); -+ } -+ - ast_mutex_lock(&netlock); - if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) { - close(skinnysock); -@@ -6344,11 +7125,13 @@ - struct skinny_addon *a; - - AST_LIST_LOCK(&devices); -+ AST_LIST_LOCK(&lines); - - /* Delete all devices */ - while ((d = AST_LIST_REMOVE_HEAD(&devices, list))) { - /* Delete all lines for this device */ - while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) { -+ AST_LIST_REMOVE(&lines, l, all); - free(l); - } - /* Delete all speeddials for this device */ -@@ -6361,6 +7144,7 @@ - } - free(d); - } -+ AST_LIST_UNLOCK(&lines); - AST_LIST_UNLOCK(&devices); - } - -@@ -6372,7 +7156,7 @@ - static int reload(void) - { - delete_devices(); -- reload_config(); -+ config_load(); - restart_monitor(); - return 0; - } -@@ -6386,7 +7170,7 @@ - soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent); - } - /* load and parse config */ -- res = reload_config(); -+ res = config_load(); - if (res == -1) { - return AST_MODULE_LOAD_DECLINE; - } -@@ -6398,7 +7182,17 @@ - } - - ast_rtp_proto_register(&skinny_rtp); -- ast_cli_register_multiple(cli_skinny, sizeof(cli_skinny) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_skinny, ARRAY_LEN(cli_skinny)); -+ -+ ast_manager_register2("SKINNYdevices", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_devices, -+ "List SKINNY devices (text format)", mandescr_show_devices); -+ ast_manager_register2("SKINNYshowdevice", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_device, -+ "Show SKINNY device (text format)", mandescr_show_device); -+ ast_manager_register2("SKINNYlines", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_lines, -+ "List SKINNY lines (text format)", mandescr_show_lines); -+ ast_manager_register2("SKINNYshowline", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_line, -+ "Show SKINNY line (text format)", mandescr_show_line); -+ - sched = sched_context_create(); - if (!sched) { - ast_log(LOG_WARNING, "Unable to create schedule context\n"); -@@ -6421,6 +7215,15 @@ - struct skinny_subchannel *sub; - struct ast_context *con; - -+ ast_rtp_proto_unregister(&skinny_rtp); -+ ast_channel_unregister(&skinny_tech); -+ ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny)); -+ -+ ast_manager_unregister("SKINNYdevices"); -+ ast_manager_unregister("SKINNYshowdevice"); -+ ast_manager_unregister("SKINNYlines"); -+ ast_manager_unregister("SKINNYshowline"); -+ - AST_LIST_LOCK(&sessions); - /* Destroy all the interfaces and free their memory */ - while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) { -@@ -6438,9 +7241,13 @@ - if (l->mwi_event_sub) - ast_event_unsubscribe(l->mwi_event_sub); - ast_mutex_unlock(&l->lock); -+ unregister_exten(l); - } - if (s->fd > -1) - close(s->fd); -+ pthread_cancel(s->t); -+ pthread_kill(s->t, SIGURG); -+ pthread_join(s->t, NULL); - free(s); - } - AST_LIST_UNLOCK(&sessions); -@@ -6465,10 +7272,6 @@ - accept_t = AST_PTHREADT_STOP; - ast_mutex_unlock(&netlock); - -- ast_rtp_proto_unregister(&skinny_rtp); -- ast_channel_unregister(&skinny_tech); -- ast_cli_unregister_multiple(cli_skinny, sizeof(cli_skinny) / sizeof(struct ast_cli_entry)); -- - close(skinnysock); - if (sched) - sched_context_destroy(sched); -Index: channels/iax2.h -=================================================================== ---- a/channels/iax2.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/iax2.h (.../team/group/issue14292) (revision 178988) -@@ -187,6 +187,7 @@ - #define IAX_AUTH_RSA (1 << 2) - - #define IAX_ENCRYPT_AES128 (1 << 0) -+#define IAX_ENCRYPT_KEYROTATE (1 << 15) /*!< Keyrotation support */ - - #define IAX_META_TRUNK 1 /*!< Trunk meta-message */ - #define IAX_META_VIDEO 2 /*!< Video frame */ -Index: channels/chan_alsa.c -=================================================================== ---- a/channels/chan_alsa.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_alsa.c (.../team/group/issue14292) (revision 178988) -@@ -28,7 +28,7 @@ - */ - - /*** MODULEINFO -- asound -+ alsa - ***/ - - #include "asterisk.h" -@@ -861,8 +861,12 @@ - - strcpy(mohinterpret, "default"); - -- if (!(cfg = ast_config_load(config, config_flags))) -+ if (!(cfg = ast_config_load(config, config_flags))) { - return AST_MODULE_LOAD_DECLINE; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "%s is in an invalid format. Aborting.\n", config); -+ return AST_MODULE_LOAD_DECLINE; -+ } - - v = ast_variable_browse(cfg, "general"); - for (; v; v = v->next) { -@@ -902,7 +906,7 @@ - return AST_MODULE_LOAD_FAILURE; - } - -- ast_cli_register_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_alsa, ARRAY_LEN(cli_alsa)); - - return AST_MODULE_LOAD_SUCCESS; - } -@@ -910,7 +914,7 @@ - static int unload_module(void) - { - ast_channel_unregister(&alsa_tech); -- ast_cli_unregister_multiple(cli_alsa, sizeof(cli_alsa) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_alsa, ARRAY_LEN(cli_alsa)); - - if (alsa.icard) - snd_pcm_close(alsa.icard); -Index: channels/chan_mgcp.c -=================================================================== ---- a/channels/chan_mgcp.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_mgcp.c (.../team/group/issue14292) (revision 178988) -@@ -916,7 +916,7 @@ - transmit_modify_request(sub->next); - } - -- transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name); -+ transmit_notify_request_with_callerid(sub, tone, ast->connected.id.number, ast->connected.id.name); - ast_setstate(ast, AST_STATE_RINGING); - - if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { -@@ -1139,31 +1139,6 @@ - return CLI_SUCCESS; - } - --static char *handle_mgcp_set_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) --{ -- switch (cmd) { -- case CLI_INIT: -- e->command = "mgcp set debug [off]"; -- e->usage = -- "Usage: mgcp set debug [off]\n" -- " Enables/Disables dumping of MGCP packets for debugging purposes\n"; -- return NULL; -- case CLI_GENERATE: -- return NULL; -- } -- -- if (a->argc < 3 || a->argc > 4) -- return CLI_SHOWUSAGE; -- if (a->argc == 3) { -- mgcpdebug = 1; -- ast_cli(a->fd, "MGCP Debugging Enabled\n"); -- } else if (!strncasecmp(a->argv[3], "off", 3)) { -- mgcpdebug = 0; -- ast_cli(a->fd, "MGCP Debugging Disabled\n"); -- } -- return CLI_SUCCESS; --} -- - static char *handle_mgcp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - switch (cmd) { -@@ -1192,11 +1167,10 @@ - return CLI_SUCCESS; - } - --static struct ast_cli_entry cli_mgcp_set_debug_deprecated = AST_CLI_DEFINE(handle_mgcp_set_debug_deprecated, "Enable/Disable MGCP debugging"); - static struct ast_cli_entry cli_mgcp[] = { - AST_CLI_DEFINE(handle_mgcp_audit_endpoint, "Audit specified MGCP endpoint"), - AST_CLI_DEFINE(handle_mgcp_show_endpoints, "List defined MGCP endpoints"), -- AST_CLI_DEFINE(handle_mgcp_set_debug, "Enable/Disable MGCP debugging", .deprecate_cmd = &cli_mgcp_set_debug_deprecated), -+ AST_CLI_DEFINE(handle_mgcp_set_debug, "Enable/Disable MGCP debugging"), - AST_CLI_DEFINE(mgcp_reload, "Reload MGCP configuration"), - }; - -@@ -4121,8 +4095,12 @@ - if (!cfg) { - ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config); - return 0; -- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) -+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - return 0; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); -+ return 0; -+ } - - memset(&bindaddr, 0, sizeof(bindaddr)); - dtmfmode = 0; -Index: channels/chan_unistim.c -=================================================================== ---- a/channels/chan_unistim.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_unistim.c (.../team/group/issue14292) (revision 178988) -@@ -439,7 +439,7 @@ - char datetimeformat; /*!< format used for displaying time/date */ - char contrast; /*!< contrast */ - char country[3]; /*!< country used for dial tone frequency */ -- struct tone_zone *tz; /*!< Tone zone for res_indications (ring, busy, congestion) */ -+ struct ast_tone_zone *tz; /*!< Tone zone for res_indications (ring, busy, congestion) */ - char ringvolume; /*!< Ring volume */ - char ringstyle; /*!< Ring melody */ - int rtp_port; /*!< RTP port used by the phone */ -@@ -1117,7 +1117,7 @@ - cur = cur->next; - } - if (cur) { /* Session found ? */ -- if (cur->device) { /* This session was registred ? */ -+ if (cur->device) { /* This session was registered ? */ - s->state = STATE_CLEANING; - if (unistimdebug) - ast_verb(0, "close_client session %p device %p lines %p sub %p\n", -@@ -3324,7 +3324,7 @@ - for (i = 1; i < 6; i++) - send_favorite(i, 0, pte, ""); - send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Sorry, this phone is not"); -- send_text(TEXT_LINE1, TEXT_NORMAL, pte, "registred in unistim.cfg"); -+ send_text(TEXT_LINE1, TEXT_NORMAL, pte, "registered in unistim.cfg"); - strcpy(tmp, "MAC = "); - strcat(tmp, pte->macaddr); - send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp); -@@ -3419,7 +3419,7 @@ - if (memcmp(buf + SIZE_HEADER, packet_recv_pick_up, sizeof(packet_recv_pick_up)) == 0) { - if (unistimdebug) - ast_verb(0, "Handset off hook\n"); -- if (!pte->device) /* We are not yet registred (asking for a TN in AUTOPROVISIONING_TN) */ -+ if (!pte->device) /* We are not yet registered (asking for a TN in AUTOPROVISIONING_TN) */ - return; - pte->device->receiver_state = STATE_OFFHOOK; - if (pte->device->output == OUTPUT_HEADPHONE) -@@ -3672,16 +3672,16 @@ - Sendicon(TEXT_LINE0, FAV_ICON_NONE, session); - - if (sub->owner) { -- if (sub->owner->cid.cid_num) { -- send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->cid.cid_num); -- change_callerid(session, 0, sub->owner->cid.cid_num); -+ if (sub->owner->connected.id.number) { -+ send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->connected.id.number); -+ change_callerid(session, 0, sub->owner->connected.id.number); - } else { - send_text(TEXT_LINE1, TEXT_NORMAL, session, DEFAULTCALLERID); - change_callerid(session, 0, DEFAULTCALLERID); - } -- if (sub->owner->cid.cid_name) { -- send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->cid.cid_name); -- change_callerid(session, 1, sub->owner->cid.cid_name); -+ if (sub->owner->connected.id.name) { -+ send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->connected.id.name); -+ change_callerid(session, 1, sub->owner->connected.id.name); - } else { - send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERNAME); - change_callerid(session, 1, DEFAULTCALLERNAME); -@@ -4057,17 +4057,17 @@ - return "UNKNOWN"; - } - --static void in_band_indication(struct ast_channel *ast, const struct tone_zone *tz, -+static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zone *tz, - const char *indication) - { -- const struct tone_zone_sound *ts = NULL; -+ struct ast_tone_zone_sound *ts = NULL; - -- ts = ast_get_indication_tone(tz, indication); -- -- if (ts && ts->data[0]) -+ if ((ts = ast_get_indication_tone(tz, indication))) { - ast_playtones_start(ast, 0, ts->data, 1); -- else -+ ts = ast_tone_zone_sound_unref(ts); -+ } else { - ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication); -+ } - } - - static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, -@@ -4682,9 +4682,9 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "unistim info"; -+ e->command = "unistim show info"; - e->usage = -- "Usage: unistim info\n" -+ "Usage: unistim show info\n" - " Dump internal structures.\n"; - return NULL; - -@@ -4751,27 +4751,27 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "unistim sp"; -+ e->command = "unistim send packet"; - e->usage = -- "Usage: unistim sp USTM/line@name hexa\n" -- " unistim sp USTM/1000@hans 19040004\n"; -+ "Usage: unistim send packet USTM/line@name hexa\n" -+ " unistim send packet USTM/1000@hans 19040004\n"; - return NULL; - - case CLI_GENERATE: - return NULL; /* no completion */ - } - -- if (a->argc < 4) -+ if (a->argc < 5) - return CLI_SHOWUSAGE; - -- if (strlen(a->argv[2]) < 9) -+ if (strlen(a->argv[3]) < 9) - return CLI_SHOWUSAGE; - -- len = strlen(a->argv[3]); -+ len = strlen(a->argv[4]); - if (len % 2) - return CLI_SHOWUSAGE; - -- ast_copy_string(tmp, a->argv[2] + 5, sizeof(tmp)); -+ ast_copy_string(tmp, a->argv[3] + 5, sizeof(tmp)); - sub = find_subchannel_by_name(tmp); - if (!sub) { - ast_cli(a->fd, "Can't find '%s'\n", tmp); -@@ -4781,15 +4781,15 @@ - ast_cli(a->fd, "'%s' is not connected\n", tmp); - return CLI_SUCCESS; - } -- ast_cli(a->fd, "Sending '%s' to %s (%p)\n", a->argv[3], tmp, sub->parent->parent->session); -+ ast_cli(a->fd, "Sending '%s' to %s (%p)\n", a->argv[4], tmp, sub->parent->parent->session); - for (i = 0; i < len; i++) { -- c = a->argv[3][i]; -+ c = a->argv[4][i]; - if (c >= 'a') - c -= 'a' - 10; - else - c -= '0'; - i++; -- cc = a->argv[3][i]; -+ cc = a->argv[4][i]; - if (cc >= 'a') - cc -= 'a' - 10; - else -@@ -5223,6 +5223,9 @@ - ast_log(LOG_ERROR, "An Unistim device must have at least one line!\n"); - ast_mutex_destroy(&l->lock); - ast_free(l); -+ if (d->tz) { -+ d->tz = ast_tone_zone_unref(d->tz); -+ } - ast_free(d); - return NULL; - } -@@ -5240,6 +5243,9 @@ - ast_log(LOG_ERROR, "You must specify the mac address with device=\n"); - ast_mutex_destroy(&l->lock); - ast_free(l); -+ if (d->tz) { -+ d->tz = ast_tone_zone_unref(d->tz); -+ } - ast_free(d); - return NULL; - } else -@@ -5304,6 +5310,9 @@ - if (!cfg) { - ast_log(LOG_ERROR, "Unable to load config %s\n", config); - return -1; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config); -+ return -1; - } - - /* Copy the default jb config over global_jbconf */ -@@ -5458,6 +5467,9 @@ - d2 = d2->next; - } - } -+ if (d->tz) { -+ d->tz = ast_tone_zone_unref(d->tz); -+ } - ast_free(d); - d = devices; - continue; -Index: channels/chan_local.c -=================================================================== ---- a/channels/chan_local.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_local.c (.../team/group/issue14292) (revision 178988) -@@ -106,8 +106,8 @@ - char exten[AST_MAX_EXTENSION]; /* Extension to call */ - int reqformat; /* Requested format */ - struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration for this local channel */ -- struct ast_channel *owner; /* Master Channel */ -- struct ast_channel *chan; /* Outbound channel */ -+ struct ast_channel *owner; /* Master Channel - Bridging happens here */ -+ struct ast_channel *chan; /* Outbound channel - PBX is run here */ - struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */ - struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */ - AST_LIST_ENTRY(local_pvt) list; /* Next entity */ -@@ -303,6 +303,7 @@ - p->chan->audiohooks = p->owner->audiohooks; - p->owner->audiohooks = audiohooks_swapper; - } -+ ast_app_group_update(p->chan, p->owner); - ast_channel_masquerade(p->owner, p->chan->_bridge); - ast_set_flag(p, LOCAL_ALREADY_MASQED); - } -@@ -401,6 +402,32 @@ - ast_moh_start(ast, data, NULL); - } else if (condition == AST_CONTROL_UNHOLD) { - ast_moh_stop(ast); -+ } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { -+ struct ast_channel *this_channel; -+ struct ast_channel *the_other_channel; -+ /* A connected line update frame may only contain a partial amount of data, such -+ * as just a source, or just a ton, and not the full amount of information. However, -+ * the collected information is all stored in the outgoing channel's connectedline -+ * structure, so when receiving a connected line update on an outgoing local channel, -+ * we need to transmit the collected connected line information instead of whatever -+ * happens to be in this control frame. The same applies for redirecting information, which -+ * is why it is handled here as well.*/ -+ isoutbound = IS_OUTBOUND(ast, p); -+ if (isoutbound) { -+ this_channel = p->chan; -+ the_other_channel = p->owner; -+ } else { -+ this_channel = p->owner; -+ the_other_channel = p->chan; -+ } -+ if (the_other_channel) { -+ /*XXX investigate later for potential deadlock issues */ -+ if (condition == AST_CONTROL_CONNECTED_LINE) { -+ ast_queue_connected_line_update(the_other_channel, &this_channel->connected); -+ } else { -+ ast_queue_redirecting_update(the_other_channel, &this_channel->redirecting); -+ } -+ } - } else { - /* Queue up a frame representing the indication as a control frame */ - ast_mutex_lock(&p->lock); -@@ -511,15 +538,15 @@ - * Note that cid_num and cid_name aren't passed in the ast_channel_alloc - * call, so it's done here instead. - */ -+ p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); -+ ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting); -+ - p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); -- p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); -- p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); -- p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); -- p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); -- p->chan->cid.cid_pres = p->owner->cid.cid_pres; -- p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; -- p->chan->cid.cid_ton = p->owner->cid.cid_ton; - p->chan->cid.cid_tns = p->owner->cid.cid_tns; -+ -+ ast_copy_connected_to_caller(&p->chan->cid, &p->owner->connected); -+ ast_copy_caller_to_connected(&p->chan->connected, &p->owner->cid); -+ - ast_string_field_set(p->chan, language, p->owner->language); - ast_string_field_set(p->chan, accountcode, p->owner->accountcode); - ast_string_field_set(p->chan, musicclass, p->owner->musicclass); -@@ -532,6 +559,11 @@ - return -1; - } - -+ /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ -+ if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { -+ ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); -+ } -+ - /* copy the channel variables from the incoming channel to the outgoing channel */ - /* Note that due to certain assumptions, they MUST be in the same order */ - AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { -@@ -567,9 +599,13 @@ - - ast_mutex_lock(&p->lock); - -- if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) -+ isoutbound = IS_OUTBOUND(ast, p); -+ -+ if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { - ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); -- isoutbound = IS_OUTBOUND(ast, p); -+ ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); -+ } -+ - if (isoutbound) { - const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); - if ((status) && (p->owner)) { -Index: channels/misdn/isdn_msg_parser.c -=================================================================== ---- a/channels/misdn/isdn_msg_parser.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/misdn/isdn_msg_parser.c (.../team/group/issue14292) (revision 178988) -@@ -26,6 +26,46 @@ - #include "ie.c" - - -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Build the name, number, name/number display message string -+ * -+ * \param display Display buffer to fill in -+ * \param display_length Length of the display buffer to fill in -+ * \param display_format Display format enumeration -+ * \param name Name string to use -+ * \param number Number string to use -+ * -+ * \return Nothing -+ */ -+static void build_display_str(char *display, size_t display_length, int display_format, const char *name, const char *number) -+{ -+ display[0] = 0; -+ switch (display_format) { -+ default: -+ case 0: /* none */ -+ break; -+ -+ case 1: /* name */ -+ snprintf(display, display_length, "%s", name); -+ break; -+ -+ case 2: /* number */ -+ snprintf(display, display_length, "%s", number); -+ break; -+ -+ case 3: /* both */ -+ if (name[0] || number[0]) { -+ snprintf(display, display_length, "\"%s\" <%s>", name, number); -+ } -+ break; -+ } /* end switch */ -+} /* end build_display_str() */ -+ -+ - static void set_channel(struct misdn_bchannel *bc, int channel) - { - -@@ -161,62 +201,74 @@ - int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; - SETUP_t *setup= (SETUP_t*)((unsigned long)msg->data+HEADER_LEN); - Q931_info_t *qi=(Q931_info_t*)((unsigned long)msg->data+HEADER_LEN); -+ int type; -+ int plan; -+ int present; -+ int screen; -+ int reason; - - #ifdef DEBUG - printf("Parsing SETUP Msg\n"); - #endif -- { -- int type,plan,present, screen; -- char id[32]; -- dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, id, sizeof(id)-1, nt,bc); - -- bc->onumplan=type; -- strcpy(bc->oad, id); -- switch (present) { -- case 0: -- bc->pres=0; /* screened */ -- break; -- case 1: -- bc->pres=1; /* not screened */ -- break; -- default: -- bc->pres=0; -- } -- switch (screen) { -- case 0: -- break; -- default: -- ; -- } -+ dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, bc->caller.number, sizeof(bc->caller.number) - 1, nt, bc); -+ bc->caller.number_type = type; -+ bc->caller.number_plan = plan; -+ switch (present) { -+ default: -+ case 0: -+ bc->caller.presentation = 0; /* presentation allowed */ -+ break; -+ case 1: -+ bc->caller.presentation = 1; /* presentation restricted */ -+ break; -+ case 2: -+ bc->caller.presentation = 2; /* Number not available */ -+ break; - } -- { -- int type, plan; -- char number[32]; -- dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)setup, &type, &plan, number, sizeof(number)-1, nt,bc); -- strcpy(bc->dad, number); -- bc->dnumplan=type; -+ if (0 <= screen) { -+ bc->caller.screening = screen; -+ } else { -+ bc->caller.screening = 0; /* Unscreened */ - } -- { -- char keypad[32]; -- dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, keypad, sizeof(keypad)-1, nt,bc); -- strcpy(bc->keypad, keypad); -- } - -- { -- dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &bc->sending_complete, nt,bc); -- -- } -+ dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *) setup, &type, &plan, bc->dialed.number, sizeof(bc->dialed.number) - 1, nt, bc); -+ bc->dialed.number_type = type; -+ bc->dialed.number_plan = plan; -+ -+ dec_ie_keypad(setup->KEYPAD, (Q931_info_t *) setup, bc->keypad, sizeof(bc->keypad) - 1, nt, bc); -+ -+ dec_ie_complete(setup->COMPLETE, (Q931_info_t *) setup, &bc->sending_complete, nt, bc); - -- { -- int type, plan, present, screen, reason; -- char id[32]; -- dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)setup, &type, &plan, &present, &screen, &reason, id, sizeof(id)-1, nt,bc); -- -- strcpy(bc->rad, id); -- bc->rnumplan=type; -+ dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *) setup, &type, &plan, &present, &screen, &reason, bc->redirecting.from.number, sizeof(bc->redirecting.from.number) - 1, nt, bc); -+ bc->redirecting.from.number_type = type; -+ bc->redirecting.from.number_plan = plan; -+ switch (present) { -+ default: -+ case 0: -+ bc->redirecting.from.presentation = 0; /* presentation allowed */ -+ break; -+ case 1: -+ bc->redirecting.from.presentation = 1; /* presentation restricted */ -+ break; -+ case 2: -+ bc->redirecting.from.presentation = 2; /* Number not available */ -+ break; - } -+ if (0 <= screen) { -+ bc->redirecting.from.screening = screen; -+ } else { -+ bc->redirecting.from.screening = 0; /* Unscreened */ -+ } -+ if (0 <= reason) { -+ bc->redirecting.reason = reason; -+ } else { -+ bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN; -+ } -+ - { - int coding, capability, mode, rate, multi, user, async, urate, stopbits, dbits, parity; -+ - dec_ie_bearer(setup->BEARER, (Q931_info_t *)setup, &coding, &capability, &mode, &rate, &multi, &user, &async, &urate, &stopbits, &dbits, &parity, nt,bc); - switch (capability) { - case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED; -@@ -271,7 +323,7 @@ - - } - --#define ANY_CHANNEL 0xff /* IE attribut for 'any channel' */ -+#define ANY_CHANNEL 0xff /* IE attribute for 'any channel' */ - static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) - { - int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; -@@ -286,35 +338,43 @@ - enc_ie_channel_id(&setup->CHANNEL_ID, msg, 1, bc->channel, nt,bc); - - -- { -- int type=bc->onumplan,plan=1,present=bc->pres,screen=bc->screen; -- enc_ie_calling_pn(&setup->CALLING_PN, msg, type, plan, present, -- screen, bc->oad, nt, bc); -- } -+ enc_ie_calling_pn(&setup->CALLING_PN, msg, bc->caller.number_type, bc->caller.number_plan, -+ bc->caller.presentation, bc->caller.screening, bc->caller.number, nt, bc); - -- { -- if (bc->dad[0]) -- enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, nt,bc); -+ if (bc->dialed.number[0]) { -+ enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dialed.number_type, bc->dialed.number_plan, bc->dialed.number, nt, bc); - } - -- { -- if (bc->rad[0]) -- enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, nt,bc); -+ if (bc->redirecting.from.number[0]) { -+ enc_ie_redir_nr(&setup->REDIR_NR, msg, bc->redirecting.from.number_type, bc->redirecting.from.number_plan, -+ bc->redirecting.from.presentation, bc->redirecting.from.screening, bc->redirecting.reason, -+ bc->redirecting.from.number, nt, bc); - } - -- { -- if (bc->keypad[0]) -- enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc); -+ if (bc->keypad[0]) { -+ enc_ie_keypad(&setup->KEYPAD, msg, bc->keypad, nt,bc); - } - - -+ - if (*bc->display) { -- enc_ie_display(&setup->DISPLAY, msg, bc->display, nt,bc); -+ enc_ie_display(&setup->DISPLAY, msg, bc->display, nt, bc); -+ } else if (nt && bc->caller.presentation == 0) { -+ char display[sizeof(bc->display)]; -+ -+ /* Presentation is allowed */ -+ build_display_str(display, sizeof(display), bc->display_setup, bc->caller.name, bc->caller.number); -+ if (display[0]) { -+ enc_ie_display(&setup->DISPLAY, msg, display, nt, bc); -+ } - } - - { -- int coding=0, capability, mode=0 /* 2 for packet ! */ -- ,user, rate=0x10; -+ int coding = 0; -+ int capability; -+ int mode = 0; /* 2 for packet! */ -+ int user; -+ int rate = 0x10; - - switch (bc->law) { - case INFO_CODEC_ULAW: user=2; -@@ -339,9 +399,7 @@ - default: - capability=bc->capability; - } -- -- -- -+ - enc_ie_bearer(&setup->BEARER, msg, coding, capability, mode, rate, -1, user, nt,bc); - } - -@@ -365,15 +423,36 @@ - { - int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; - CONNECT_t *connect=(CONNECT_t*)((unsigned long)(msg->data+HEADER_LEN)); -- -- int plan,pres,screen; -+ int type; -+ int plan; -+ int pres; -+ int screen; - - bc->ces = connect->ces; -- bc->ces = connect->ces; - - dec_ie_progress(connect->PROGRESS, (Q931_info_t *)connect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc); - -- dec_ie_connected_pn(connect->CONNECT_PN,(Q931_info_t *)connect, &bc->cpnnumplan, &plan, &pres, &screen, bc->cad, 31, nt, bc); -+ dec_ie_connected_pn(connect->CONNECT_PN, (Q931_info_t *) connect, &type, &plan, -+ &pres, &screen, bc->connected.number, sizeof(bc->connected.number) - 1, nt, bc); -+ bc->connected.number_type = type; -+ bc->connected.number_plan = plan; -+ switch (pres) { -+ default: -+ case 0: -+ bc->connected.presentation = 0; /* presentation allowed */ -+ break; -+ case 1: -+ bc->connected.presentation = 1; /* presentation restricted */ -+ break; -+ case 2: -+ bc->connected.presentation = 2; /* Number not available */ -+ break; -+ } -+ if (0 <= screen) { -+ bc->connected.screening = screen; -+ } else { -+ bc->connected.screening = 0; /* Unscreened */ -+ } - - /* - cb_log(1,bc->port,"CONNETED PN: %s cpn_dialplan:%d\n", connected_pn, type); -@@ -400,9 +479,17 @@ - enc_ie_date(&connect->DATE, msg, now, nt,bc); - } - -- { -- int type=bc->cpnnumplan, plan=1, present=2, screen=0; -- enc_ie_connected_pn(&connect->CONNECT_PN, msg, type,plan, present, screen, bc->cad, nt , bc); -+ enc_ie_connected_pn(&connect->CONNECT_PN, msg, bc->connected.number_type, bc->connected.number_plan, -+ bc->connected.presentation, bc->connected.screening, bc->connected.number, nt, bc); -+ -+ if (nt && bc->connected.presentation == 0) { -+ char display[sizeof(bc->display)]; -+ -+ /* Presentation is allowed */ -+ build_display_str(display, sizeof(display), bc->display_connected, bc->connected.name, bc->connected.number); -+ if (display[0]) { -+ enc_ie_display(&connect->DISPLAY, msg, display, nt, bc); -+ } - } - - #ifdef DEBUG -@@ -982,12 +1069,12 @@ - - static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt) - { -- int len, -- HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN; -- unsigned char *ie_fac, -- fac_tmp[256]; -- msg_t *msg =(msg_t*)create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc?bc->l3_id:-1, sizeof(FACILITY_t) ,nt); -- FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN); -+ int len; -+ int HEADER_LEN; -+ unsigned char *ie_fac; -+ unsigned char fac_tmp[256]; -+ msg_t *msg; -+ FACILITY_t *facility; - Q931_info_t *qi; - - #ifdef DEBUG -@@ -995,9 +1082,15 @@ - #endif - - len = encodeFac(fac_tmp, &(bc->fac_out)); -- if (len <= 0) -+ if (len <= 0) { -+ /* mISDN does not know how to build the requested facility structure */ - return NULL; -+ } - -+ msg = (msg_t *) create_l3msg(CC_FACILITY | REQUEST, MT_FACILITY, bc ? bc->l3_id : -1, sizeof(FACILITY_t), nt); -+ HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN; -+ facility = (FACILITY_t *) (msg->data + HEADER_LEN); -+ - ie_fac = msg_put(msg, len); - if (bc->nt) { - facility->FACILITY = ie_fac + 1; -@@ -1009,7 +1102,9 @@ - memcpy(ie_fac, fac_tmp, len); - - if (*bc->display) { -+#ifdef DEBUG - printf("Sending %s as Display\n", bc->display); -+#endif - enc_ie_display(&facility->DISPLAY, msg, bc->display, nt,bc); - } - -@@ -1062,15 +1157,11 @@ - { - int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; - INFORMATION_t *information=(INFORMATION_t*)((unsigned long)(msg->data+HEADER_LEN)); -- { -- int type, plan; -- char number[32]; -- char keypad[32]; -- dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *)information, &type, &plan, number, sizeof(number)-1, nt, bc); -- dec_ie_keypad(information->KEYPAD, (Q931_info_t *)information, keypad, sizeof(keypad)-1, nt, bc); -- strcpy(bc->info_dad, number); -- strcpy(bc->keypad,keypad); -- } -+ int type, plan; -+ -+ dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *) information, &type, &plan, bc->info_dad, sizeof(bc->info_dad) - 1, nt, bc); -+ dec_ie_keypad(information->KEYPAD, (Q931_info_t *) information, bc->keypad, sizeof(bc->keypad) - 1, nt, bc); -+ - #ifdef DEBUG - printf("Parsing INFORMATION Msg\n"); - #endif -@@ -1084,13 +1175,13 @@ - - information=(INFORMATION_t*)((msg->data+HEADER_LEN)); - -- { -- enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc); -- } -+ enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc); - - { - if (*bc->display) { -+#ifdef DEBUG - printf("Sending %s as Display\n", bc->display); -+#endif - enc_ie_display(&information->DISPLAY, msg, bc->display, nt,bc); - } - } -@@ -1110,7 +1201,6 @@ - - dec_ie_cause(status->CAUSE, (Q931_info_t *)(status), &location, &cause, nt,bc); - if (cause>0) bc->cause=cause; -- ; - - #ifdef DEBUG - printf("Parsing STATUS Msg\n"); -@@ -1161,97 +1251,40 @@ - /** Msg Array **/ - - struct isdn_msg msgs_g[] = { -- {CC_PROCEEDING,L3,EVENT_PROCEEDING, -- parse_proceeding,build_proceeding, -- "PROCEEDING"}, -- {CC_ALERTING,L3,EVENT_ALERTING, -- parse_alerting,build_alerting, -- "ALERTING"}, -- {CC_PROGRESS,L3,EVENT_PROGRESS, -- parse_progress,build_progress, -- "PROGRESS"}, -- {CC_SETUP,L3,EVENT_SETUP, -- parse_setup,build_setup, -- "SETUP"}, -- {CC_CONNECT,L3,EVENT_CONNECT, -- parse_connect,build_connect, -- "CONNECT"}, -- {CC_SETUP_ACKNOWLEDGE,L3,EVENT_SETUP_ACKNOWLEDGE, -- parse_setup_acknowledge,build_setup_acknowledge, -- "SETUP_ACKNOWLEDGE"}, -- {CC_CONNECT_ACKNOWLEDGE ,L3,EVENT_CONNECT_ACKNOWLEDGE , -- parse_connect_acknowledge ,build_connect_acknowledge, -- "CONNECT_ACKNOWLEDGE "}, -- {CC_USER_INFORMATION,L3,EVENT_USER_INFORMATION, -- parse_user_information,build_user_information, -- "USER_INFORMATION"}, -- {CC_SUSPEND_REJECT,L3,EVENT_SUSPEND_REJECT, -- parse_suspend_reject,build_suspend_reject, -- "SUSPEND_REJECT"}, -- {CC_RESUME_REJECT,L3,EVENT_RESUME_REJECT, -- parse_resume_reject,build_resume_reject, -- "RESUME_REJECT"}, -- {CC_HOLD,L3,EVENT_HOLD, -- parse_hold,build_hold, -- "HOLD"}, -- {CC_SUSPEND,L3,EVENT_SUSPEND, -- parse_suspend,build_suspend, -- "SUSPEND"}, -- {CC_RESUME,L3,EVENT_RESUME, -- parse_resume,build_resume, -- "RESUME"}, -- {CC_HOLD_ACKNOWLEDGE,L3,EVENT_HOLD_ACKNOWLEDGE, -- parse_hold_acknowledge,build_hold_acknowledge, -- "HOLD_ACKNOWLEDGE"}, -- {CC_SUSPEND_ACKNOWLEDGE,L3,EVENT_SUSPEND_ACKNOWLEDGE, -- parse_suspend_acknowledge,build_suspend_acknowledge, -- "SUSPEND_ACKNOWLEDGE"}, -- {CC_RESUME_ACKNOWLEDGE,L3,EVENT_RESUME_ACKNOWLEDGE, -- parse_resume_acknowledge,build_resume_acknowledge, -- "RESUME_ACKNOWLEDGE"}, -- {CC_HOLD_REJECT,L3,EVENT_HOLD_REJECT, -- parse_hold_reject,build_hold_reject, -- "HOLD_REJECT"}, -- {CC_RETRIEVE,L3,EVENT_RETRIEVE, -- parse_retrieve,build_retrieve, -- "RETRIEVE"}, -- {CC_RETRIEVE_ACKNOWLEDGE,L3,EVENT_RETRIEVE_ACKNOWLEDGE, -- parse_retrieve_acknowledge,build_retrieve_acknowledge, -- "RETRIEVE_ACKNOWLEDGE"}, -- {CC_RETRIEVE_REJECT,L3,EVENT_RETRIEVE_REJECT, -- parse_retrieve_reject,build_retrieve_reject, -- "RETRIEVE_REJECT"}, -- {CC_DISCONNECT,L3,EVENT_DISCONNECT, -- parse_disconnect,build_disconnect, -- "DISCONNECT"}, -- {CC_RESTART,L3,EVENT_RESTART, -- parse_restart,build_restart, -- "RESTART"}, -- {CC_RELEASE,L3,EVENT_RELEASE, -- parse_release,build_release, -- "RELEASE"}, -- {CC_RELEASE_COMPLETE,L3,EVENT_RELEASE_COMPLETE, -- parse_release_complete,build_release_complete, -- "RELEASE_COMPLETE"}, -- {CC_FACILITY,L3,EVENT_FACILITY, -- parse_facility,build_facility, -- "FACILITY"}, -- {CC_NOTIFY,L3,EVENT_NOTIFY, -- parse_notify,build_notify, -- "NOTIFY"}, -- {CC_STATUS_ENQUIRY,L3,EVENT_STATUS_ENQUIRY, -- parse_status_enquiry,build_status_enquiry, -- "STATUS_ENQUIRY"}, -- {CC_INFORMATION,L3,EVENT_INFORMATION, -- parse_information,build_information, -- "INFORMATION"}, -- {CC_STATUS,L3,EVENT_STATUS, -- parse_status,build_status, -- "STATUS"}, -- {CC_TIMEOUT,L3,EVENT_TIMEOUT, -- parse_timeout,build_timeout, -- "TIMEOUT"}, -- {0,0,0,NULL,NULL,NULL} -+/* *INDENT-OFF* */ -+ /* misdn_msg, event, msg_parser, msg_builder, info */ -+ { CC_PROCEEDING, EVENT_PROCEEDING, parse_proceeding, build_proceeding, "PROCEEDING" }, -+ { CC_ALERTING, EVENT_ALERTING, parse_alerting, build_alerting, "ALERTING" }, -+ { CC_PROGRESS, EVENT_PROGRESS, parse_progress, build_progress, "PROGRESS" }, -+ { CC_SETUP, EVENT_SETUP, parse_setup, build_setup, "SETUP" }, -+ { CC_CONNECT, EVENT_CONNECT, parse_connect, build_connect, "CONNECT" }, -+ { CC_SETUP_ACKNOWLEDGE, EVENT_SETUP_ACKNOWLEDGE, parse_setup_acknowledge, build_setup_acknowledge, "SETUP_ACKNOWLEDGE" }, -+ { CC_CONNECT_ACKNOWLEDGE, EVENT_CONNECT_ACKNOWLEDGE, parse_connect_acknowledge, build_connect_acknowledge, "CONNECT_ACKNOWLEDGE " }, -+ { CC_USER_INFORMATION, EVENT_USER_INFORMATION, parse_user_information, build_user_information, "USER_INFORMATION" }, -+ { CC_SUSPEND_REJECT, EVENT_SUSPEND_REJECT, parse_suspend_reject, build_suspend_reject, "SUSPEND_REJECT" }, -+ { CC_RESUME_REJECT, EVENT_RESUME_REJECT, parse_resume_reject, build_resume_reject, "RESUME_REJECT" }, -+ { CC_HOLD, EVENT_HOLD, parse_hold, build_hold, "HOLD" }, -+ { CC_SUSPEND, EVENT_SUSPEND, parse_suspend, build_suspend, "SUSPEND" }, -+ { CC_RESUME, EVENT_RESUME, parse_resume, build_resume, "RESUME" }, -+ { CC_HOLD_ACKNOWLEDGE, EVENT_HOLD_ACKNOWLEDGE, parse_hold_acknowledge, build_hold_acknowledge, "HOLD_ACKNOWLEDGE" }, -+ { CC_SUSPEND_ACKNOWLEDGE, EVENT_SUSPEND_ACKNOWLEDGE, parse_suspend_acknowledge, build_suspend_acknowledge, "SUSPEND_ACKNOWLEDGE" }, -+ { CC_RESUME_ACKNOWLEDGE, EVENT_RESUME_ACKNOWLEDGE, parse_resume_acknowledge, build_resume_acknowledge, "RESUME_ACKNOWLEDGE" }, -+ { CC_HOLD_REJECT, EVENT_HOLD_REJECT, parse_hold_reject, build_hold_reject, "HOLD_REJECT" }, -+ { CC_RETRIEVE, EVENT_RETRIEVE, parse_retrieve, build_retrieve, "RETRIEVE" }, -+ { CC_RETRIEVE_ACKNOWLEDGE, EVENT_RETRIEVE_ACKNOWLEDGE, parse_retrieve_acknowledge, build_retrieve_acknowledge, "RETRIEVE_ACKNOWLEDGE" }, -+ { CC_RETRIEVE_REJECT, EVENT_RETRIEVE_REJECT, parse_retrieve_reject, build_retrieve_reject, "RETRIEVE_REJECT" }, -+ { CC_DISCONNECT, EVENT_DISCONNECT, parse_disconnect, build_disconnect, "DISCONNECT" }, -+ { CC_RESTART, EVENT_RESTART, parse_restart, build_restart, "RESTART" }, -+ { CC_RELEASE, EVENT_RELEASE, parse_release, build_release, "RELEASE" }, -+ { CC_RELEASE_COMPLETE, EVENT_RELEASE_COMPLETE, parse_release_complete, build_release_complete, "RELEASE_COMPLETE" }, -+ { CC_FACILITY, EVENT_FACILITY, parse_facility, build_facility, "FACILITY" }, -+ { CC_NOTIFY, EVENT_NOTIFY, parse_notify, build_notify, "NOTIFY" }, -+ { CC_STATUS_ENQUIRY, EVENT_STATUS_ENQUIRY, parse_status_enquiry, build_status_enquiry, "STATUS_ENQUIRY" }, -+ { CC_INFORMATION, EVENT_INFORMATION, parse_information, build_information, "INFORMATION" }, -+ { CC_STATUS, EVENT_STATUS, parse_status, build_status, "STATUS" }, -+ { CC_TIMEOUT, EVENT_TIMEOUT, parse_timeout, build_timeout, "TIMEOUT" }, -+ { 0, 0, NULL, NULL, NULL } -+/* *INDENT-ON* */ - }; - - #define msgs_max (sizeof(msgs_g)/sizeof(struct isdn_msg)) -Index: channels/misdn/isdn_lib.c -=================================================================== ---- a/channels/misdn/isdn_lib.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/misdn/isdn_lib.c (.../team/group/issue14292) (revision 178988) -@@ -25,6 +25,22 @@ - #include "isdn_lib_intern.h" - #include "isdn_lib.h" - -+enum event_response_e (*cb_event) (enum event_e event, struct misdn_bchannel *bc, void *user_data); -+ -+void (*cb_log) (int level, int port, char *tmpl, ...) -+ __attribute__ ((format (printf, 3, 4))); -+ -+int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len); -+ -+ -+/* -+ * Define ARRAY_LEN() because I cannot -+ * #include "asterisk/utils.h" -+ */ -+#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) -+ -+#include "asterisk/causes.h" -+ - void misdn_join_conf(struct misdn_bchannel *bc, int conf_id); - void misdn_split_conf(struct misdn_bchannel *bc, int conf_id); - -@@ -137,17 +153,16 @@ - } - - --struct misdn_stack* get_stack_by_bc(struct misdn_bchannel *bc) -+struct misdn_stack *get_stack_by_bc(struct misdn_bchannel *bc) - { -- struct misdn_stack *stack=get_misdn_stack(); -+ struct misdn_stack *stack = get_misdn_stack(); - -- if (!bc) return NULL; -+ if (!bc) -+ return NULL; - -- for ( ; stack; stack=stack->next) { -- int i; -- for (i=0; i <=stack->b_num; i++) { -- if ( bc->port == stack->port) return stack; -- } -+ for ( ; stack; stack = stack->next) { -+ if (bc->port == stack->port) -+ return stack; - } - - return NULL; -@@ -156,19 +171,25 @@ - - void get_show_stack_details(int port, char *buf) - { -- struct misdn_stack *stack=get_misdn_stack(); -- -- for ( ; stack; stack=stack->next) { -- if (stack->port == port) break; -+ struct misdn_stack *stack = get_misdn_stack(); -+ -+ for (; stack; stack = stack->next) { -+ if (stack->port == port) { -+ break; -+ } - } - - if (stack) { -- sprintf(buf, "* Port %d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d", stack->port, stack->nt?"NT":"TE", stack->ptp?"PTP":"PMP", stack->l2link?"UP":"DOWN", stack->l1link?"UP":"DOWN",stack->blocked); -- -+ sprintf(buf, "* Port %2d Type %s Prot. %s L2Link %s L1Link:%s Blocked:%d", -+ stack->port, -+ stack->nt ? "NT" : "TE", -+ stack->ptp ? "PTP" : "PMP", -+ stack->l2link ? "UP " : "DOWN", -+ stack->l1link ? "UP " : "DOWN", -+ stack->blocked); - } else { -- buf[0]=0; -+ buf[0] = 0; - } -- - } - - -@@ -193,8 +214,9 @@ - - - struct misdn_lib { -+ /*! \brief mISDN device handle returned by mISDN_open() */ - int midev; -- int midev_nt; -+ int midev_nt; /* Not used */ - - pthread_t event_thread; - pthread_t event_handler_thread; -@@ -250,8 +272,8 @@ - - static struct misdn_lib *glob_mgr; - --char tone_425_flip[TONE_425_SIZE]; --char tone_silence_flip[TONE_SILENCE_SIZE]; -+static char tone_425_flip[TONE_425_SIZE]; -+static char tone_silence_flip[TONE_SILENCE_SIZE]; - - static void misdn_lib_isdn_event_catcher(void *arg); - static int handle_event_nt(void *dat, void *arg); -@@ -262,9 +284,6 @@ - struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned long l3id); - - /* from isdn_lib.h */ --int init_bc(struct misdn_stack * stack, struct misdn_bchannel *bc, int midev, int port, int bidx, char *msn, int firsttime); --struct misdn_stack* stack_init(int midev, int port, int ptp); --void stack_destroy(struct misdn_stack* stack); - /* user iface */ - int te_lib_init( void ) ; /* returns midev */ - void te_lib_destroy(int midev) ; -@@ -439,8 +458,10 @@ - int misdn_inband_avail(struct misdn_bchannel *bc) - { - -- /*if ! early_bconnect we have never inband available*/ -- if ( ! bc->early_bconnect ) return 0; -+ if (!bc->early_bconnect) { -+ /* We have opted to never receive any available inband recorded messages */ -+ return 0; -+ } - - switch (bc->progress_indicator) { - case INFO_PI_INBAND_AVAILABLE: -@@ -464,7 +485,7 @@ - } - - --void misdn_dump_chanlist() -+void misdn_dump_chanlist(void) - { - struct misdn_stack *stack=get_misdn_stack(); - for ( ; stack; stack=stack->next) { -@@ -473,7 +494,7 @@ - - } - --int set_chan_in_stack(struct misdn_stack *stack, int channel) -+static int set_chan_in_stack(struct misdn_stack *stack, int channel) - { - - cb_log(4,stack->port,"set_chan_in_stack: %d\n",channel); -@@ -517,7 +538,7 @@ - - if (dec) { - for (i = bnums; i >=0; i--) { -- if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 Dchannel ;) and work with chan preselection */ -+ if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */ - if (!stack->channels[i]) { - cb_log (3, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1); - chan=i+1; -@@ -527,7 +548,7 @@ - } - } else { - for (i = 0; i <= bnums; i++) { -- if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 Dchannel ;) and work with chan preselection */ -+ if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */ - if (!stack->channels[i]) { - cb_log (3, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1); - chan=i+1; -@@ -540,13 +561,13 @@ - if (!chan) { - cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n"); - dump_chan_list(stack); -- bc->out_cause=34; -+ bc->out_cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; - return -1; - } - - if (set_chan_in_stack(stack, chan)<0) { - cb_log (0, stack->port, "Channel Already in use:%d\n", chan); -- bc->out_cause=44; -+ bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; - return -1; - } - -@@ -628,6 +649,29 @@ - - static void empty_bc(struct misdn_bchannel *bc) - { -+ bc->caller.presentation = 0; /* allowed */ -+ bc->caller.number_plan = NUMPLAN_ISDN; -+ bc->caller.number_type = NUMTYPE_UNKNOWN; -+ bc->caller.name[0] = 0; -+ bc->caller.number[0] = 0; -+ bc->caller.subaddress[0] = 0; -+ -+ bc->connected.presentation = 0; /* allowed */ -+ bc->connected.number_plan = NUMPLAN_ISDN; -+ bc->connected.number_type = NUMTYPE_UNKNOWN; -+ bc->connected.name[0] = 0; -+ bc->connected.number[0] = 0; -+ bc->connected.subaddress[0] = 0; -+ -+ bc->redirecting.from.presentation = 0; /* allowed */ -+ bc->redirecting.from.number_plan = NUMPLAN_ISDN; -+ bc->redirecting.from.number_type = NUMTYPE_UNKNOWN; -+ bc->redirecting.from.name[0] = 0; -+ bc->redirecting.from.number[0] = 0; -+ bc->redirecting.from.subaddress[0] = 0; -+ -+ bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN; -+ - bc->dummy=0; - - bc->bframe_len=0; -@@ -662,12 +706,6 @@ - bc->generate_tone=0; - bc->tone_cnt=0; - -- bc->dnumplan=NUMPLAN_UNKNOWN; -- bc->onumplan=NUMPLAN_UNKNOWN; -- bc->rnumplan=NUMPLAN_UNKNOWN; -- bc->cpnnumplan=NUMPLAN_UNKNOWN; -- -- - bc->active = 0; - - bc->early_bconnect = 1; -@@ -683,10 +721,15 @@ - - bc->orig=0; - -- bc->cause=16; -- bc->out_cause=16; -- bc->pres=0 ; /* screened */ -+ bc->cause = AST_CAUSE_NORMAL_CLEARING; -+ bc->out_cause = AST_CAUSE_NORMAL_CLEARING; -+ -+ bc->display_connected = 0; /* none */ -+ bc->display_setup = 0; /* none */ - -+ bc->presentation = 0; /* allowed */ -+ bc->set_presentation = 0; -+ - bc->evq=EVENT_NOTHING; - - bc->progress_coding=0; -@@ -703,15 +746,14 @@ - - bc->hdlc=0; - -+ bc->dialed.number_plan = NUMPLAN_ISDN; -+ bc->dialed.number_type = NUMTYPE_UNKNOWN; -+ bc->dialed.number[0] = 0; -+ bc->dialed.subaddress[0] = 0; - - bc->info_dad[0] = 0; - bc->display[0] = 0; - bc->infos_pending[0] = 0; -- bc->cad[0] = 0; -- bc->oad[0] = 0; -- bc->dad[0] = 0; -- bc->rad[0] = 0; -- bc->orig_dad[0] = 0; - bc->uu[0]=0; - bc->uulen=0; - -@@ -915,7 +957,7 @@ - } - } /* end for */ - if (proc_id == MAXPROCS) { -- cb_log(0, stack->port, "Couldnt Create New ProcId.\n"); -+ cb_log(0, stack->port, "Couldn't Create New ProcId.\n"); - return -1; - } - -@@ -967,7 +1009,10 @@ - int setup_bc(struct misdn_bchannel *bc) - { - unsigned char buff[1025]; -- int midev, channel, b_stid, i; -+ int midev; -+ int channel; -+ int b_stid; -+ int i; - mISDN_pid_t pid; - int ret; - -@@ -986,13 +1031,13 @@ - case BCHAN_CLEANED: - break; - default: -- cb_log(4, stack->port, "$$$ bc already upsetted stid :%x (state:%s)\n", b_stid, bc_state2str(bc->bc_state) ); -+ cb_log(4, stack->port, "$$$ bc already setup stid :%x (state:%s)\n", b_stid, bc_state2str(bc->bc_state) ); - return -1; - } - - cb_log(5, stack->port, "$$$ Setting up bc with stid :%x\n", b_stid); - -- /*check if the b_stid is alread initialized*/ -+ /*check if the b_stid is already initialized*/ - for (i=0; i <= stack->b_num; i++) { - if (stack->bc[i].b_stid == b_stid) { - cb_log(0, bc->port, "setup_bc: b_stid:%x already in use !!!\n", b_stid); -@@ -1042,10 +1087,9 @@ - li.name[l-1] = 0; - } - li.pid.layermask = ISDN_LAYER((4)); -- li.pid.protocol[4] = ISDN_PID_L4_B_USER --; -+ li.pid.protocol[4] = ISDN_PID_L4_B_USER; -+ - bc->layer=4; -- - } - - ret = mISDN_new_layer(midev, &li); -@@ -1134,7 +1178,7 @@ - - - /** IFACE **/ --int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, int port, int bidx, char *msn, int firsttime) -+static int init_bc(struct misdn_stack *stack, struct misdn_bchannel *bc, int midev, int port, int bidx, char *msn, int firsttime) - { - unsigned char buff[1025] = ""; - iframe_t *frm = (iframe_t *)buff; -@@ -1147,7 +1191,9 @@ - memset(bc, 0,sizeof(struct misdn_bchannel)); - - bc->send_lock=malloc(sizeof(struct send_lock)); -- -+ if (!bc->send_lock) { -+ return -1; -+ } - pthread_mutex_init(&bc->send_lock->lock, NULL); - - if (msn) { -@@ -1172,6 +1218,9 @@ - clear_ibuffer( ibuf); - - ibuf->rsem=malloc(sizeof(sem_t)); -+ if (!ibuf->rsem) { -+ return -1; -+ } - - bc->astbuf=ibuf; - -@@ -1198,7 +1247,7 @@ - - - --struct misdn_stack* stack_init( int midev, int port, int ptp ) -+static struct misdn_stack *stack_init(int midev, int port, int ptp) - { - int ret; - unsigned char buff[1025]; -@@ -1383,7 +1432,7 @@ - } - - --void stack_destroy(struct misdn_stack* stack) -+static void stack_destroy(struct misdn_stack *stack) - { - char buf[1024]; - if (!stack) return; -@@ -1537,7 +1586,14 @@ - setup_bc(bc); - - if ( *bc->crypt_key ) { -- cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); -+ cb_log(4, stack->port, -+ "ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n", -+ bc->channel, -+ bc->caller.number_type, -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number_type, -+ bc->dialed.number); - manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); - } - -@@ -1559,7 +1615,14 @@ - case EVENT_CONNECT: - - if ( *bc->crypt_key ) { -- cb_log(4, stack->port, "ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s\n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); -+ cb_log(4, stack->port, -+ "ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n", -+ bc->channel, -+ bc->caller.number_type, -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number_type, -+ bc->dialed.number); - manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); - } - case EVENT_ALERTING: -@@ -1642,7 +1705,7 @@ - struct misdn_bchannel dummybc; - - if (!bc) { -- cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on this port.\n", frm->dinfo); -+ cb_log(4, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", frm->dinfo); - misdn_make_dummy(&dummybc, stack->port, frm->dinfo, stack->nt, 0); - - bc=&dummybc; -@@ -1669,7 +1732,7 @@ - dump_chan_list(stack); - - if (bc->stack_holder) { -- cb_log(4,stack->port, "REMOVEING Holder\n"); -+ cb_log(4,stack->port, "REMOVING Holder\n"); - stack_holder_remove( stack, bc); - free(bc); - } -@@ -1688,7 +1751,7 @@ - } - - --/*Emptys bc if it's reserved (no SETUP out yet)*/ -+/* Empties bc if it's reserved (no SETUP out yet) */ - void misdn_lib_release(struct misdn_bchannel *bc) - { - struct misdn_stack *stack=get_stack_by_bc(bc); -@@ -1797,10 +1860,10 @@ - frm.addr=stack->upper_id | FLG_MSG_DOWN; - - frm.prim = CC_RELEASE_CR|INDICATION; -- cb_log(4, stack->port, " --> CC_RELEASE_CR: Faking Realease_cr for %x l3id:%x\n",frm.addr, frm.dinfo); -+ cb_log(4, stack->port, " --> CC_RELEASE_CR: Faking Release_cr for %x l3id:%x\n",frm.addr, frm.dinfo); - /** removing procid **/ - if (!bc) { -- cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x) on this port.\n", hh->dinfo); -+ cb_log(4, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", hh->dinfo); - misdn_make_dummy(&dummybc, stack->port, hh->dinfo, stack->nt, 0); - bc=&dummybc; - } -@@ -1811,7 +1874,7 @@ - stack->procids[bc->l3_id&0xff] = 0 ; - } - } -- else cb_log(0, stack->port, "Couldnt find BC so I couldnt remove the Process!!!! this is a bad port.\n"); -+ else cb_log(0, stack->port, "Couldn't find BC so I couldn't remove the Process!!!! this is a bad port.\n"); - - if (handle_cr(stack, &frm)<0) { - } -@@ -1819,7 +1882,7 @@ - return 0 ; - } - --int -+static int - handle_event_nt(void *dat, void *arg) - { - manager_t *mgr = (manager_t *)dat; -@@ -1841,7 +1904,8 @@ - switch(hh->prim){ - case CC_RETRIEVE|INDICATION: - { -- struct misdn_bchannel *bc, *hold_bc; -+ struct misdn_bchannel *bc; -+ struct misdn_bchannel *hold_bc; - - iframe_t frm; /* fake te frm to add callref to global callreflist */ - frm.dinfo = hh->dinfo; -@@ -1864,7 +1928,7 @@ - cb_log(4, stack->port, "bc_l3id:%x holded_bc_l3id:%x\n",bc->l3_id, hold_bc->l3_id); - - if (hold_bc) { -- cb_log(4, stack->port, "REMOVEING Holder\n"); -+ cb_log(4, stack->port, "REMOVING Holder\n"); - - /*swap the backup to our new channel back*/ - stack_holder_remove(stack, hold_bc); -@@ -2041,7 +2105,7 @@ - cb_log(3 , stack->port, "%% GOT L2 DeActivate Info.\n"); - - if (stack->l2upcnt>3) { -- cb_log(0 , stack->port, "!!! Could not Get the L2 up after 3 Attemps!!!\n"); -+ cb_log(0 , stack->port, "!!! Could not Get the L2 up after 3 Attempts!!!\n"); - } else { - #if 0 - if (stack->nt) misdn_lib_reinit_nt_stack(stack->port); -@@ -2073,7 +2137,7 @@ - bc=find_bc_by_l3id(stack, hh->dinfo); - - if (!bc) { -- cb_log(4, stack->port, " --> Didn't found BC so temporarly creating dummy BC (l3id:%x).\n", hh->dinfo); -+ cb_log(4, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x).\n", hh->dinfo); - misdn_make_dummy(&dummybc, stack->port, hh->dinfo, stack->nt, 0); - bc=&dummybc; - } -@@ -2112,7 +2176,7 @@ - } else { - if (reject) { - switch(bc->cause){ -- case 17: -+ case AST_CAUSE_USER_BUSY: - cb_log(1, stack->port, "Siemens Busy reject..\n"); - - break; -@@ -2430,7 +2494,14 @@ - { - unsigned int *cont = (unsigned int *) &frm->data.p; - -- cb_log(4, stack->port, "PH_CONTROL: channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); -+ cb_log(4, stack->port, -+ "PH_CONTROL: channel:%d caller%d:\"%s\" <%s> dialed%d:%s \n", -+ bc->channel, -+ bc->caller.number_type, -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number_type, -+ bc->dialed.number); - - if ((*cont & ~DTMF_TONE_MASK) == DTMF_TONE_VAL) { - int dtmf = *cont & DTMF_TONE_MASK; -@@ -2674,12 +2745,12 @@ - switch (response) { - case RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE: - -- cb_log(0, stack->port, "TOTALY IGNORING SETUP \n"); -+ cb_log(0, stack->port, "TOTALLY IGNORING SETUP\n"); - - break; - case RESPONSE_IGNORE_SETUP: - /* I think we should send CC_RELEASE_CR, but am not sure*/ -- bc->out_cause=16; -+ bc->out_cause = AST_CAUSE_NORMAL_CLEARING; - - case RESPONSE_RELEASE_SETUP: - misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE); -@@ -2702,7 +2773,7 @@ - } - - if (event == EVENT_RELEASE_COMPLETE) { -- /* release bchannel only after we've anounced the RELEASE_COMPLETE */ -+ /* release bchannel only after we've announced the RELEASE_COMPLETE */ - int channel=bc->channel; - int tmpcause=bc->cause; - int tmp_out_cause=bc->out_cause; -@@ -2711,8 +2782,8 @@ - bc->out_cause=tmp_out_cause; - clean_up_bc(bc); - -- if (tmpcause == 44) { -- cb_log(0,stack->port,"**** Received CAUSE:44, so not cleaning up channel %d\n", channel); -+ if (tmpcause == AST_CAUSE_REQUESTED_CHAN_UNAVAIL) { -+ cb_log(0,stack->port,"**** Received CAUSE:%d, so not cleaning up channel %d\n", AST_CAUSE_REQUESTED_CHAN_UNAVAIL, channel); - cb_log(0,stack->port,"**** This channel is now no longer available,\nplease try to restart it with 'misdn send restart '\n"); - set_chan_in_stack(stack, channel); - bc->channel=channel; -@@ -2739,9 +2810,9 @@ - } else { - struct misdn_bchannel dummybc; - if (frm->prim!=(CC_FACILITY|INDICATION)) -- cb_log(0, stack->port, " --> Didn't find BC so temporarly creating dummy BC (l3id:%x) on this port.\n", frm->dinfo); -+ cb_log(0, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", frm->dinfo); - else -- cb_log(5, stack->port, " --> Using Dummy BC for FACILITy\n"); -+ cb_log(5, stack->port, " --> Using Dummy BC for FACILITY\n"); - - memset (&dummybc,0,sizeof(dummybc)); - dummybc.port=stack->port; -@@ -2783,7 +2854,7 @@ - - for (i=0;i<=stack->b_num; i++) { - if (stack->bc[i].evq != EVENT_NOTHING) { -- cb_log(4, stack->port, "Fireing Queued Event %s because L1 got up\n", isdn_get_info(msgs_g, stack->bc[i].evq, 0)); -+ cb_log(4, stack->port, "Firing Queued Event %s because L1 got up\n", isdn_get_info(msgs_g, stack->bc[i].evq, 0)); - misdn_lib_send_event(&stack->bc[i],stack->bc[i].evq); - stack->bc[i].evq=EVENT_NOTHING; - } -@@ -2969,7 +3040,7 @@ - msg->len=r; - - if (r==0) { -- free_msg(msg); /* danger, cauz usualy freeing in main_loop */ -+ free_msg(msg); /* danger, cause usually freeing in main_loop */ - cb_log(6,0,"Got empty Msg..\n"); - return NULL; - } -@@ -3010,6 +3081,7 @@ - } - } - -+/* This is a thread */ - static void misdn_lib_isdn_event_catcher(void *arg) - { - struct misdn_lib *mgr = arg; -@@ -3026,7 +3098,7 @@ - - frm = (iframe_t*) msg->data; - -- /** When we make a call from NT2Ast we get this frames **/ -+ /** When we make a call from NT2Ast we get these frames **/ - if (frm->len == 0 && frm->addr == 0 && frm->dinfo == 0 && frm->prim == 0 ) { - zero_frm++; - free_msg(msg); -@@ -3058,7 +3130,7 @@ - - /** App Interface **/ - --int te_lib_init() { -+int te_lib_init(void) { - char buff[1025] = ""; - iframe_t *frm=(iframe_t*)buff; - int midev=mISDN_open(); -@@ -3090,7 +3162,7 @@ - char buf[1024]; - mISDN_write_frame(midev, buf, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC); - -- cb_log(4, 0, "Entetity deleted\n"); -+ cb_log(4, 0, "Entity deleted\n"); - mISDN_close(midev); - cb_log(4, 0, "midev closed\n"); - } -@@ -3153,7 +3225,7 @@ - bc->need_disconnect=1; - bc->need_release=1; - bc->need_release_complete=1; -- bc->cause=16; -+ bc->cause = AST_CAUSE_NORMAL_CLEARING; - - if (++mypid>5000) mypid=1; - bc->pid=mypid; -@@ -3244,23 +3316,41 @@ - } - - --static char *fac2str (enum FacFunction func) -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Convert the facility function enum value into a string. -+ * -+ * \return String version of the enum value -+ */ -+static const char *fac2str(enum FacFunction facility) - { -- struct arr_el { -- enum FacFunction p; -- char *s ; -+ static const struct { -+ enum FacFunction facility; -+ char *name; - } arr[] = { -+/* *INDENT-OFF* */ - { Fac_None, "Fac_None" }, -- { Fac_CD, "Fac_CD"}, -+ { Fac_CFActivate, "Fac_CFActivate" }, -+ { Fac_CFDeactivate, "Fac_CFDeactivate" }, -+ { Fac_CD, "Fac_CD" }, -+ { Fac_AOCDCurrency, "Fac_AOCDCurrency" }, -+ { Fac_AOCDChargingUnit, "Fac_AOCDChargingUnit" }, -+/* *INDENT-ON* */ - }; - -- int i; -+ unsigned index; - -- for (i=0; i < sizeof(arr)/sizeof( struct arr_el) ; i ++) -- if ( arr[i].p==func) return arr[i].s; -- -+ for (index = 0; index < ARRAY_LEN(arr); ++index) { -+ if (arr[index].facility == facility) { -+ return arr[index].name; -+ } -+ } /* end for */ -+ - return "unknown"; --} -+} /* end fac2str() */ - - void misdn_lib_log_ies(struct misdn_bchannel *bc) - { -@@ -3272,21 +3362,51 @@ - - if (!stack) return; - -- cb_log(2, stack->port, " --> channel:%d mode:%s cause:%d ocause:%d rad:%s cad:%s\n", bc->channel, stack->nt?"NT":"TE", bc->cause, bc->out_cause, bc->rad, bc->cad); -+ cb_log(2, stack->port, -+ " --> channel:%d mode:%s cause:%d ocause:%d\n", -+ bc->channel, -+ stack->nt ? "NT" : "TE", -+ bc->cause, -+ bc->out_cause); - - cb_log(2, stack->port, -- " --> info_dad:%s onumplan:%c dnumplan:%c rnumplan:%c cpnnumplan:%c\n", -- bc->info_dad, -- bc->onumplan>=0?'0'+bc->onumplan:' ', -- bc->dnumplan>=0?'0'+bc->dnumplan:' ', -- bc->rnumplan>=0?'0'+bc->rnumplan:' ', -- bc->cpnnumplan>=0?'0'+bc->cpnnumplan:' ' -- ); -+ " --> info_dad:%s dialed numtype:%d plan:%d\n", -+ bc->info_dad, -+ bc->dialed.number_type, -+ bc->dialed.number_plan); -+ -+ cb_log(2, stack->port, -+ " --> caller:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n", -+ bc->caller.name, -+ bc->caller.number, -+ bc->caller.number_type, -+ bc->caller.number_plan, -+ bc->caller.presentation, -+ bc->caller.screening); -+ -+ cb_log(2, stack->port, -+ " --> redirecting:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d reason:%d\n", -+ bc->redirecting.from.name, -+ bc->redirecting.from.number, -+ bc->redirecting.from.number_type, -+ bc->redirecting.from.number_plan, -+ bc->redirecting.from.presentation, -+ bc->redirecting.from.screening, -+ bc->redirecting.reason); -+ -+ cb_log(2, stack->port, -+ " --> connected:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n", -+ bc->connected.name, -+ bc->connected.number, -+ bc->connected.number_type, -+ bc->connected.number_plan, -+ bc->connected.presentation, -+ bc->connected.screening); - - cb_log(3, stack->port, " --> caps:%s pi:%x keypad:%s sending_complete:%d\n", bearer2str(bc->capability),bc->progress_indicator, bc->keypad, bc->sending_complete); -- cb_log(4, stack->port, " --> screen:%d --> pres:%d\n", -- bc->screen, bc->pres); - -+ cb_log(4, stack->port, " --> set_pres:%d pres:%d\n", bc->set_presentation, bc->presentation); -+ - cb_log(4, stack->port, " --> addr:%x l3id:%x b_stid:%x layer_id:%x\n", bc->addr, bc->l3_id, bc->b_stid, bc->layer_id); - - cb_log(4, stack->port, " --> facility:%s out_facility:%s\n",fac2str(bc->fac_in.Function),fac2str(bc->fac_out.Function)); -@@ -3296,19 +3416,17 @@ - cb_log(5, stack->port, " --> bc:%p h:%d sh:%d\n", bc, bc->holded, bc->stack_holder); - } - --void misdn_send_lock(struct misdn_bchannel *bc); --void misdn_send_unlock(struct misdn_bchannel *bc); - - #define RETURN(a,b) {retval=a; goto b;} - --void misdn_send_lock(struct misdn_bchannel *bc) -+static void misdn_send_lock(struct misdn_bchannel *bc) - { - //cb_log(0,bc->port,"Locking bc->pid:%d\n", bc->pid); - if (bc->send_lock) - pthread_mutex_lock(&bc->send_lock->lock); - } - --void misdn_send_unlock(struct misdn_bchannel *bc) -+static void misdn_send_unlock(struct misdn_bchannel *bc) - { - //cb_log(0,bc->port,"UnLocking bc->pid:%d\n", bc->pid); - if (bc->send_lock) -@@ -3326,14 +3444,19 @@ - stack = get_stack_by_bc(bc); - - if (!stack) { -- cb_log(0,bc->port,"SENDEVENT: no Stack for event:%s oad:%s dad:%s \n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad); -+ cb_log(0,bc->port, -+ "SENDEVENT: no Stack for event:%s caller:\"%s\" <%s> dialed:%s \n", -+ isdn_get_info(msgs_g, event, 0), -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number); - RETURN(-1,OUT); - } - - misdn_send_lock(bc); - - -- cb_log(6,stack->port,"SENDEVENT: stack->nt:%d stack->uperid:%x\n",stack->nt, stack->upper_id); -+ cb_log(6,stack->port,"SENDEVENT: stack->nt:%d stack->upperid:%x\n",stack->nt, stack->upper_id); - - if ( stack->nt && !stack->l1link) { - /** Queue Event **/ -@@ -3343,7 +3466,13 @@ - RETURN(0,OUT); - } - -- cb_log(1, stack->port, "I SEND:%s oad:%s dad:%s pid:%d\n", isdn_get_info(msgs_g, event, 0), bc->oad, bc->dad, bc->pid); -+ cb_log(1, stack->port, -+ "I SEND:%s caller:\"%s\" <%s> dialed:%s pid:%d\n", -+ isdn_get_info(msgs_g, event, 0), -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number, -+ bc->pid); - cb_log(4, stack->port, " --> bc_state:%s\n",bc_state2str(bc->bc_state)); - misdn_lib_log_ies(bc); - -@@ -3384,7 +3513,14 @@ - if (misdn_cap_is_speech(bc->capability)) { - if ((event==EVENT_CONNECT)||(event==EVENT_RETRIEVE_ACKNOWLEDGE)) { - if ( *bc->crypt_key ) { -- cb_log(4, stack->port, " --> ENABLING BLOWFISH channel:%d oad%d:%s dad%d:%s \n", bc->channel, bc->onumplan,bc->oad, bc->dnumplan,bc->dad); -+ cb_log(4, stack->port, -+ " --> ENABLING BLOWFISH channel:%d caller%d:\"%s\" <%s> dialed%d:%s\n", -+ bc->channel, -+ bc->caller.number_type, -+ bc->caller.name, -+ bc->caller.number, -+ bc->dialed.number_type, -+ bc->dialed.number); - - manager_ph_control_block(bc, BF_ENABLE_KEY, bc->crypt_key, strlen(bc->crypt_key) ); - } -@@ -3476,7 +3612,7 @@ - bc->need_release_complete=0; - - if (!stack->nt) { -- /*create clenaup in TE*/ -+ /*create cleanup in TE*/ - int channel=bc->channel; - - int tmpcause=bc->cause; -@@ -3524,8 +3660,19 @@ - - /* Later we should think about sending bchannel data directly to misdn. */ - msg = isdn_msg_build_event(msgs_g, bc, event, stack->nt); -- msg_queue_tail(&stack->downqueue, msg); -- sem_post(&glob_mgr->new_msg); -+ if (!msg) { -+ /* -+ * The message was not built. -+ * -+ * NOTE: The only time that the message will fail to build -+ * is because the requested FACILITY message is not supported. -+ * A failed malloc() results in exit() being called. -+ */ -+ RETURN(-1, OUT); -+ } else { -+ msg_queue_tail(&stack->downqueue, msg); -+ sem_post(&glob_mgr->new_msg); -+ } - - OUT: - misdn_send_unlock(bc); -@@ -3706,7 +3853,7 @@ - iframe_t *frm; - struct misdn_stack *stack=find_stack_by_port(port); - if (!msg) { -- cb_log(0, port, "misgn_lib_get_port: alloc_msg failed!\n"); -+ cb_log(0, port, "misdn_lib_get_port_info: alloc_msg failed!\n"); - return -1; - } - frm=(iframe_t*)msg->data; -@@ -3735,7 +3882,7 @@ - msg_t *msg=alloc_msg(MAX_MSG_SIZE); - iframe_t *frm; - if (!msg) { -- cb_log(0, bc->port, "misgn_lib_get_port: alloc_msg failed!\n"); -+ cb_log(0, bc->port, "queue_cleanup_bc: alloc_msg failed!\n"); - return -1; - } - frm=(iframe_t*)msg->data; -@@ -3765,7 +3912,7 @@ - return 0; - } - --/*Sends Restart message for every bchnanel*/ -+/*Sends Restart message for every bchannel*/ - int misdn_lib_send_restart(int port, int channel) - { - struct misdn_stack *stack=find_stack_by_port(port); -@@ -3845,8 +3992,9 @@ - - - --sem_t handler_started; -+static sem_t handler_started; - -+/* This is a thread */ - static void manager_event_handler(void *arg) - { - sem_post(&handler_started); -@@ -3889,6 +4037,7 @@ - free_msg(msg); - break; - case MGR_SETSTACK | REQUEST : -+ /* Warning: memory leak here if we get this message */ - break; - default: - mISDN_write(glob_mgr->midev, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC); -@@ -3924,7 +4073,7 @@ - } else { - iframe_t *frm = (iframe_t *)msg->data; - struct misdn_bchannel *bc = find_bc_by_l3id(stack, frm->dinfo); -- if (bc) -+ if (bc) - send_msg(glob_mgr->midev, bc, msg); - else { - if (frm->dinfo == MISDN_ID_GLOBAL || frm->dinfo == MISDN_ID_DUMMY ) { -@@ -3943,8 +4092,10 @@ - } - - --int misdn_lib_maxports_get() { /** BE AWARE WE HAVE NO CB_LOG HERE! **/ -- -+int misdn_lib_maxports_get(void) -+{ -+ /* BE AWARE WE HAVE NO cb_log() HERE! */ -+ - int i = mISDN_open(); - int max=0; - -@@ -3990,7 +4141,6 @@ - } - } - -- - int misdn_lib_init(char *portlist, struct misdn_lib_iface *iface, void *user_data) - { - struct misdn_lib *mgr=calloc(1, sizeof(struct misdn_lib)); -@@ -4052,7 +4202,7 @@ - stack=stack_init(midev, port, ptp); - - if (!stack) { -- perror("init_stack"); -+ perror("stack_init"); - exit(1); - } - -@@ -4099,7 +4249,7 @@ - return (mgr == NULL); - } - --void misdn_lib_destroy() -+void misdn_lib_destroy(void) - { - struct misdn_stack *help; - int i; -@@ -4161,7 +4311,6 @@ - - void manager_bchannel_deactivate(struct misdn_bchannel * bc) - { -- - struct misdn_stack *stack=get_stack_by_bc(bc); - iframe_t dact; - char buf[128]; -@@ -4323,9 +4472,6 @@ - cb_log(4,stack->port, "*HOLDER: add %x\n",holder->l3_id); - - holder->stack_holder=1; -- -- if (!stack ) return ; -- - holder->next=NULL; - - if (!stack->holding) { -@@ -4517,7 +4663,7 @@ - #endif - } - --struct misdn_stack* get_misdn_stack() { -+struct misdn_stack* get_misdn_stack(void) { - return glob_mgr->stack_list; - } - -@@ -4546,7 +4692,8 @@ - cb_log(4,bc->port, "Splitting bc:%x in conf:%d\n",bc->addr,conf_id); - } - --void misdn_lib_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2) { -+void misdn_lib_bridge( struct misdn_bchannel * bc1, struct misdn_bchannel *bc2) -+{ - int conf_id = bc1->pid + 1; - struct misdn_bchannel *bc_list[] = { bc1, bc2, NULL }; - struct misdn_bchannel **bc; -Index: channels/misdn/isdn_lib_intern.h -=================================================================== ---- a/channels/misdn/isdn_lib_intern.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/misdn/isdn_lib_intern.h (.../team/group/issue14292) (revision 178988) -@@ -28,8 +28,10 @@ - #endif - - --ibuffer_t *astbuf; --ibuffer_t *misdnbuf; -+#if 0 -+ibuffer_t *astbuf; /* Not used */ -+ibuffer_t *misdnbuf; /* Not used */ -+#endif - - struct send_lock { - pthread_mutex_t lock; -@@ -38,15 +40,13 @@ - - struct isdn_msg { - unsigned long misdn_msg; -- -- enum layer_e layer; -+ - enum event_e event; -- -+ - void (*msg_parser)(struct isdn_msg *msgs, msg_t *msg, struct misdn_bchannel *bc, int nt); - msg_t *(*msg_builder)(struct isdn_msg *msgs, struct misdn_bchannel *bc, int nt); - char *info; -- --} ; -+} ; - - /* for isdn_msg_parser.c */ - msg_t *create_l3msg(int prim, int mt, int dinfo , int size, int nt); -@@ -57,57 +57,78 @@ - /** is first element because &nst equals &mISDNlist **/ - net_stack_t nst; - manager_t mgr; -- -+ -+ /*! \brief D Channel mISDN driver stack ID (Parent stack ID) */ - int d_stid; -- -+ -+ /*! /brief Number of B channels supported by this port */ - int b_num; -- -+ -+ /*! \brief B Channel mISDN driver stack IDs (Child stack IDs) */ - int b_stids[MAX_BCHANS + 1]; -- -+ -+ /*! \brief TRUE if Point-To-Point(PTP) (Point-To-Multipoint(PTMP) otherwise) */ - int ptp; - -+ /*! \brief Number of consecutive times PTP Layer 2 declared down */ - int l2upcnt; - -- int l2_id; -+ int l2_id; /* Not used */ -+ -+ /*! \brief Lower layer mISDN ID (addr) (Layer 1/3) */ - int lower_id; -+ -+ /*! \brief Upper layer mISDN ID (addr) (Layer 2/4) */ - int upper_id; -- - -+ /*! \brief TRUE if port is blocked */ - int blocked; - -+ /*! \brief TRUE if Layer 2 is UP */ - int l2link; -- -- time_t l2establish; -- -+ -+ time_t l2establish; /* Not used */ -+ -+ /*! \brief TRUE if Layer 1 is UP */ - int l1link; - -+ /*! \brief TRUE if restart has been sent to the other side after stack startup */ - int restart_sent; - -+ /*! \brief mISDN device handle returned by mISDN_open() */ - int midev; -- -+ -+ /*! \brief TRUE if NT side of protocol (TE otherwise) */ - int nt; -- -+ -+ /*! \brief TRUE if ISDN-PRI (ISDN-BRI otherwise) */ - int pri; -- - -+ /*! \brief CR Process ID allocation table. TRUE if ID allocated */ - int procids[0x100+1]; - -+ /*! \brief Queue of Event messages to send to mISDN */ - msg_queue_t downqueue; -- msg_queue_t upqueue; -- int busy; -- -+ msg_queue_t upqueue; /* No code puts anything on this queue */ -+ int busy; /* Not used */ -+ -+ /*! \brief Logical Layer 1 port associated with this stack */ - int port; -+ -+ /*! \brief B Channel record pool array */ - struct misdn_bchannel bc[MAX_BCHANS + 1]; -- -- struct misdn_bchannel* bc_list; -- -+ -+ struct misdn_bchannel* bc_list; /* Not used */ -+ -+ /*! \brief Array of B channels in use (a[0] = B1). TRUE if B channel in use */ - int channels[MAX_BCHANS + 1]; - -- -- struct misdn_bchannel *holding; /* Queue which holds holded channels :) */ -- -+ /*! \brief List of holded channels */ -+ struct misdn_bchannel *holding; -+ -+ /*! \brief Next stack in the list of stacks */ - struct misdn_stack *next; --}; -+}; - - - struct misdn_stack* get_stack_by_bc(struct misdn_bchannel *bc); -Index: channels/misdn/isdn_lib.h -=================================================================== ---- a/channels/misdn/isdn_lib.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/misdn/isdn_lib.h (.../team/group/issue14292) (revision 178988) -@@ -11,7 +11,7 @@ - * the GNU General Public License - */ - --/*! \file -+/*! \file - * \brief Interface to mISDN - * - * \author Christian Richter -@@ -27,9 +27,9 @@ - /** end of init usage **/ - - --/* -+/* - * uncomment the following to make chan_misdn create -- * record files in /tmp/misdn-{rx|tx}-PortChannel format -+ * record files in /tmp/misdn-{rx|tx}-PortChannel format - * */ - - /*#define MISDN_SAVE_DATA*/ -@@ -50,9 +50,9 @@ - int tonedisable, int zerocoeff, int adapt, int nlp); - - void beroec_destroy(beroec_t *ec); --int beroec_cancel_alaw_chunk(beroec_t *ec, -- char *send, -- char *receive , -+int beroec_cancel_alaw_chunk(beroec_t *ec, -+ char *send, -+ char *receive, - int len); - - int beroec_version(void); -@@ -96,15 +96,23 @@ - ENOCHAN=1 - }; - -- - enum mISDN_NUMBER_PLAN { -- NUMPLAN_UNINITIALIZED=-1, -- NUMPLAN_INTERNATIONAL=0x1, -- NUMPLAN_NATIONAL=0x2, -- NUMPLAN_SUBSCRIBER=0x4, -- NUMPLAN_UNKNOWN=0x0 --}; -+ NUMPLAN_UNKNOWN = 0x0, -+ NUMPLAN_ISDN = 0x1, /* ISDN/Telephony numbering plan E.164 */ -+ NUMPLAN_DATA = 0x3, /* Data numbering plan X.121 */ -+ NUMPLAN_TELEX = 0x4, /* Telex numbering plan F.69 */ -+ NUMPLAN_NATIONAL = 0x8, -+ NUMPLAN_PRIVATE = 0x9 -+}; - -+enum mISDN_NUMBER_TYPE { -+ NUMTYPE_UNKNOWN = 0x0, -+ NUMTYPE_INTERNATIONAL = 0x1, -+ NUMTYPE_NATIONAL = 0x2, -+ NUMTYPE_NETWORK_SPECIFIC = 0x3, -+ NUMTYPE_SUBSCRIBER = 0x4, -+ NUMTYPE_ABBREVIATED = 0x5 -+}; - - enum event_response_e { - RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE, -@@ -158,7 +166,7 @@ - EVENT_PORT_ALARM, - EVENT_NEW_CHANNEL, - EVENT_UNKNOWN --}; -+}; - - - enum ie_name_e { -@@ -189,10 +197,23 @@ - INFO_PI_INTERWORKING_NO_RELEASE_POST_ANSWER =0x13 - }; - -+/*! -+ * \brief Q.931 encoded redirecting reason -+ */ -+enum mISDN_REDIRECTING_REASON { -+ mISDN_REDIRECTING_REASON_UNKNOWN = 0x0, -+ mISDN_REDIRECTING_REASON_CALL_FWD_BUSY = 0x1, /* Call forwarding busy or called DTE busy */ -+ mISDN_REDIRECTING_REASON_NO_REPLY = 0x2, /* Call forwarding no reply */ -+ mISDN_REDIRECTING_REASON_DEFLECTION = 0x4, /* Call deflection */ -+ mISDN_REDIRECTING_REASON_OUT_OF_ORDER = 0x9, /* Called DTE out of order */ -+ mISDN_REDIRECTING_REASON_CALL_FWD_DTE = 0xA, /* Call forwarding by the called DTE */ -+ mISDN_REDIRECTING_REASON_CALL_FWD = 0xF /* Call forwarding unconditional or systematic call redirection */ -+}; -+ - enum { /*CODECS*/ - INFO_CODEC_ULAW=2, - INFO_CODEC_ALAW=3 --}; -+}; - - - enum layer_e { -@@ -200,85 +221,222 @@ - L2, - L1, - UNKNOWN --}; -+}; - -+/* Maximum phone number (address) length plus null terminator */ -+#define MISDN_MAX_NUMBER_LEN (31 + 1) - -+/* Maximum name length plus null terminator (From ECMA-164) */ -+#define MISDN_MAX_NAME_LEN (50 + 1) - -+/* Maximum subaddress length plus null terminator */ -+#define MISDN_MAX_SUBADDRESS_LEN (23 + 1) -+ -+/* Maximum keypad facility content length plus null terminator */ -+#define MISDN_MAX_KEYPAD_LEN (31 + 1) -+ -+/*! \brief Connected-Line/Calling/Redirecting ID info struct */ -+struct misdn_party_id { -+ /*! \brief Number presentation restriction code -+ * 0=Allowed, 1=Restricted, 2=Unavailable -+ */ -+ int presentation; -+ -+ /*! \brief Number screening code -+ * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number -+ */ -+ int screening; -+ -+ /*! \brief Type-of-number in ISDN terms for the number */ -+ enum mISDN_NUMBER_TYPE number_type; -+ -+ /*! \brief Type-of-number numbering plan. */ -+ enum mISDN_NUMBER_PLAN number_plan; -+ -+ /*! \brief Subscriber Name -+ * \note The name is currently obtained from Asterisk for -+ * potential use in display ie's since basic ISDN does -+ * not support names directly. -+ */ -+ char name[MISDN_MAX_NAME_LEN]; -+ -+ /*! \brief Phone number (Address) */ -+ char number[MISDN_MAX_NUMBER_LEN]; -+ -+ /*! \brief Subaddress number */ -+ char subaddress[MISDN_MAX_SUBADDRESS_LEN]; -+}; -+ -+/*! \brief Redirecting information struct */ -+struct misdn_party_redirecting { -+ /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */ -+ struct misdn_party_id from; -+ -+ /*! \brief Reason a call is being redirected (Q.931 field value) */ -+ enum mISDN_REDIRECTING_REASON reason; -+}; -+ -+ -+/*! \brief B channel control structure */ - struct misdn_bchannel { -+ /*! \brief B channel send locking structure */ - struct send_lock *send_lock; - -+ /*! \brief Originating/Caller ID information struct -+ * \note The number_type element is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls -+ * \note The number element can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls -+ */ -+ struct misdn_party_id caller; -+ -+ /*! \brief Connected-Party/Connected-Line ID information struct -+ * \note The number_type element is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls -+ */ -+ struct misdn_party_id connected; -+ -+ /*! \brief Redirecting information struct (Where a call diversion or transfer was invoked) -+ * \note The redirecting subaddress is not defined in Q.931 so it is not used. -+ */ -+ struct misdn_party_redirecting redirecting; -+ -+ /*! \brief TRUE if this is a dummy BC record */ - int dummy; - -+ /*! \brief TRUE if NT side of protocol (TE otherwise) */ - int nt; -+ -+ /*! \brief TRUE if ISDN-PRI (ISDN-BRI otherwise) */ - int pri; - -+ /*! \brief Logical Layer 1 port associated with this B channel */ - int port; -+ - /** init stuff **/ -+ /*! \brief B Channel mISDN driver stack ID */ - int b_stid; -+ - /* int b_addr; */ -+ -+ /*! \brief B Channel mISDN driver layer ID from mISDN_new_layer() */ - int layer_id; - -+ /*! \brief B channel layer; set to 3 or 4 */ - int layer; -- -- /*state stuff*/ -+ -+ /* state stuff */ -+ /*! \brief TRUE if DISCONNECT needs to be sent to clear a call */ - int need_disconnect; -+ -+ /*! \brief TRUE if RELEASE needs to be sent to clear a call */ - int need_release; -+ -+ /*! \brief TRUE if RELEASE_COMPLETE needs to be sent to clear a call */ - int need_release_complete; - -+ /*! \brief TRUE if allocate higher B channels first */ - int dec; -- /** var stuff**/ -+ -+ /* var stuff */ -+ /*! \brief Layer 3 process ID */ - int l3_id; -+ -+ /*! \brief B channel process ID (1-5000) */ - int pid; -+ -+ /*! \brief Not used. Saved mISDN stack CONNECT_t ces value */ - int ces; - -+ /*! \brief B channel to restart if received a RESTART message */ - int restart_channel; -+ -+ /*! \brief Assigned B channel number B1, B2... 0 if not assigned */ - int channel; -+ -+ /*! \brief TRUE if the B channel number is preselected */ - int channel_preselected; -- -+ -+ /*! \brief TRUE if B channel record is in use */ - int in_use; -+ -+ /*! \brief Time when empty_bc() last called on this record */ - struct timeval last_used; -+ -+ /*! \brief TRUE if call waiting */ - int cw; -+ -+ /*! \brief B Channel mISDN driver layer ID from mISDN_get_layerid() */ - int addr; - -- char * bframe; -+ /*! \brief B channel speech sample data buffer */ -+ char *bframe; -+ -+ /*! \brief B channel speech sample data buffer size */ - int bframe_len; -- int time_usec; -- -- -+ int time_usec; /* Not used */ -+ -+ /*! \brief Not used. Contents are setup but not used. */ - void *astbuf; - -- void *misdnbuf; -+ void *misdnbuf; /* Not used */ - -+ /*! \brief TRUE if the TE side should choose the B channel to use -+ * \note This value is user configurable in /etc/asterisk/misdn.conf -+ */ - int te_choose_channel; -+ -+ /*! \brief TRUE if the call progress indicators can indicate an inband audio message for the user to listen to -+ * \note This value is user configurable in /etc/asterisk/misdn.conf -+ */ - int early_bconnect; -- -- /* dtmf digit */ -+ -+ /*! \brief Last decoded DTMF digit from mISDN driver */ - int dtmf; -+ -+ /*! \brief TRUE if we should produce DTMF tones ourselves -+ * \note This value is user configurable in /etc/asterisk/misdn.conf -+ */ - int send_dtmf; - -- /* get setup ack */ -+ /*! \brief TRUE if we send SETUP_ACKNOWLEDGE on incoming calls anyway (instead of PROCEEDING). -+ * -+ * This requests additional INFORMATION messages, so we can -+ * wait for digits without issues. -+ * \note This value is user configurable in /etc/asterisk/misdn.conf -+ */ - int need_more_infos; - -- /* may there be more infos ?*/ -+ /*! \brief TRUE if all digits necessary to complete the call are available. -+ * No more INFORMATION messages are needed. -+ */ - int sending_complete; - - -- /* wether we should use jollys dsp or not */ -+ /*! \brief TRUE if we will not use jollys dsp */ - int nodsp; -- -- /* wether we should use our jitter buf system or not */ -+ -+ /*! \brief TRUE if we will not use the jitter buffer system */ - int nojitter; -- -- enum mISDN_NUMBER_PLAN dnumplan; -- enum mISDN_NUMBER_PLAN rnumplan; -- enum mISDN_NUMBER_PLAN onumplan; -- enum mISDN_NUMBER_PLAN cpnnumplan; - -+ /*! \brief Progress Indicator IE coding standard field. -+ * \note Collected from the incoming messages but not used. -+ */ - int progress_coding; -+ -+ /*! \brief Progress Indicator IE location field. -+ * \note Collected from the incoming messages but not used. -+ */ - int progress_location; -+ -+ /*! \brief Progress Indicator IE progress description field. -+ * Used to determine if there is an inband audio message present. -+ */ - int progress_indicator; - -+ /*! \brief Inbound FACILITY message function type and contents */ - struct FacParm fac_in; -+ -+ /*! \brief Outbound FACILITY message function type and contents. -+ * \note Filled in by misdn facility commands before FACILITY message sent. -+ */ - struct FacParm fac_out; - - /* storing the current AOCD info here */ -@@ -287,101 +445,225 @@ - struct FacAOCDCurrency currency; - struct FacAOCDChargingUnit chargingUnit; - } AOCD; -+ /*! \brief TRUE if AOCDtype and AOCD data are ready to export to Asterisk */ - int AOCD_need_export; -- -+ -+ /*! \brief Event waiting for Layer 1 to come up */ - enum event_e evq; -- -+ - /*** CRYPTING STUFF ***/ -- -- int crypt; -- int curprx; -- int curptx; -+ int crypt; /* Initialized, Not used */ -+ int curprx; /* Initialized, Not used */ -+ int curptx; /* Initialized, Not used */ -+ -+ /*! \brief Blowfish encryption key string (secret) */ - char crypt_key[255]; -- -- int crypt_state; -- -- /*char ast_dtmf_buf[255]; -- char misdn_dtmf_buf[255]; */ -- -+ -+ int crypt_state; /* Not used */ - /*** CRYPTING STUFF END***/ -- -+ -+ /*! \brief Seems to have been intended for something to do with the jitter buffer. -+ * \note Used as a boolean. Only initialized to 0 and referenced in a couple places -+ */ - int active; -- int upset; -+ int upset; /* Not used */ - -+ /*! \brief TRUE if tone generator allowed to start */ - int generate_tone; -+ -+ /*! \brief Number of tone samples to generate */ - int tone_cnt; -- -+ -+ /*! \brief Current B Channel state */ - enum bchannel_state bc_state; -+ -+ /*! \brief This is used as a pending bridge join request for when bc_state becomes BCHAN_ACTIVATED */ - enum bchannel_state next_bc_state; - -+ /*! \brief Bridging conference ID */ - int conf_id; -- -+ -+ /*! \brief TRUE if this channel is on hold */ - int holded; -+ -+ /*! \brief TRUE if this channel is on the misdn_stack->holding list -+ * \note If TRUE this implies that the structure is also malloced. -+ */ - int stack_holder; - -- int pres; -- int screen; -- -+ /*! -+ * \brief Put a display ie in the CONNECT message -+ * \details -+ * Put a display ie in the CONNECT message containing the following -+ * information if it is available (nt port only): -+ * 0 - Do not put the connected line information in the display ie. -+ * 1 - Put the available connected line name in the display ie. -+ * 2 - Put the available connected line number in the display ie. -+ * 3 - Put the available connected line name and number in the display ie. -+ */ -+ int display_connected; -+ -+ /*! -+ * \brief Put a display ie in the SETUP message -+ * \details -+ * Put a display ie in the SETUP message containing the following -+ * information if it is available (nt port only): -+ * 0 - Do not put the caller information in the display ie. -+ * 1 - Put the available caller name in the display ie. -+ * 2 - Put the available caller number in the display ie. -+ * 3 - Put the available caller name and number in the display ie. -+ */ -+ int display_setup; -+ -+ /*! \brief User set presentation restriction code -+ * 0=Allowed, 1=Restricted, 2=Unavailable -+ * \note It is settable by the misdn_set_opt() application. -+ */ -+ int presentation; -+ -+ /*! \brief TRUE if the user set the presentation restriction code */ -+ int set_presentation; -+ -+ /*! \brief SETUP message bearer capability field code value */ - int capability; -+ -+ /*! \brief Companding ALaw/uLaw encoding (INFO_CODEC_ALAW / INFO_CODEC_ULAW) */ - int law; -- /** V110 Stuff **/ -+ -+ /* V110 Stuff */ -+ /*! \brief Q.931 Bearer Capability IE Information Transfer Rate field. Initialized to 0x10 (64kbit). Altered by incoming SETUP messages. */ - int rate; -+ -+ /*! \brief Q.931 Bearer Capability IE Transfer Mode field. Initialized to 0 (Circuit). Altered by incoming SETUP messages. */ - int mode; - -+ /*! \brief Q.931 Bearer Capability IE User Information Layer 1 Protocol field code. -+ * \note Collected from the incoming SETUP message but not used. -+ */ - int user1; -+ -+ /*! \brief Q.931 Bearer Capability IE Layer 1 User Rate field. -+ * \note Collected from the incoming SETUP message and exported to Asterisk variable MISDN_URATE. -+ */ - int urate; -+ -+ /*! \brief TRUE if call made in digital HDLC mode -+ * \note This value is user configurable in /etc/asterisk/misdn.conf. -+ * It is also settable by the misdn_set_opt() application. -+ */ - int hdlc; - /* V110 */ -- -+ -+ /*! \brief Dialed/Called information struct */ -+ struct { -+ /*! \brief Type-of-number in ISDN terms for the dialed/called number -+ * \note This value is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls -+ */ -+ enum mISDN_NUMBER_TYPE number_type; -+ -+ /*! \brief Type-of-number numbering plan. */ -+ enum mISDN_NUMBER_PLAN number_plan; -+ -+ /*! \brief Dialed/Called Phone Number (Address) */ -+ char number[MISDN_MAX_NUMBER_LEN]; -+ -+ /*! \brief Dialed/Called Subaddress number */ -+ char subaddress[MISDN_MAX_SUBADDRESS_LEN]; -+ } dialed; -+ -+ /*! \brief Display message that can be displayed by the user phone. -+ * \note Maximum displayable length is 34 or 82 octets. -+ * It is also settable by the misdn_set_opt() application. -+ */ - char display[84]; -- char msn[32]; -- char oad[32]; -- char rad[32]; -- char dad[32]; -- char cad[32]; -- char orig_dad[32]; -- char keypad[32]; - -- char info_dad[64]; -- char infos_pending[64]; -+ /*! \brief Not used. Contents are setup but not used. */ -+ char msn[MISDN_MAX_NUMBER_LEN]; - --/* unsigned char info_keypad[32]; */ -+ /*! \brief Q.931 Keypad Facility IE contents -+ * \note Contents exported and imported to Asterisk variable MISDN_KEYPAD -+ */ -+ char keypad[MISDN_MAX_KEYPAD_LEN]; -+ -+ /*! \brief Current overlap dialing digits to/from INFORMATION messages */ -+ char info_dad[MISDN_MAX_NUMBER_LEN]; -+ -+ /*! \brief Collected digits to go into info_dad[] while waiting for a SETUP_ACKNOWLEDGE to come in. */ -+ char infos_pending[MISDN_MAX_NUMBER_LEN]; -+ -+/* unsigned char info_keypad[MISDN_MAX_KEYPAD_LEN]; */ - /* unsigned char clisub[24]; */ - /* unsigned char cldsub[24]; */ - -+ /*! \brief User-User information string. -+ * \note Contents exported and imported to Asterisk variable MISDN_USERUSER -+ * \note We only support ASCII strings (IA5 characters). -+ */ - char uu[256]; -+ -+ /*! \brief User-User information string length in uu[] */ - int uulen; -- -+ -+ /*! \brief Q.931 Cause for disconnection code (received) -+ * \note Need to use the AST_CAUSE_xxx code definitions in causes.h -+ */ - int cause; -+ -+ /*! \brief Q.931 Cause for disconnection code (sent) -+ * \note Need to use the AST_CAUSE_xxx code definitions in causes.h -+ * \note -1 is used to suppress including the cause code in the RELEASE message. -+ */ - int out_cause; -- -+ - /* struct misdn_bchannel hold_bc; */ -- -+ - /** list stuf **/ - - #ifdef MISDN_1_2 -+ /*! \brief The configuration string for the mISDN dsp pipeline in /etc/asterisk/misdn.conf. */ - char pipeline[128]; - #else -+ /*! \brief TRUE if the echo cancellor is enabled */ - int ec_enable; -+ -+ /*! \brief Number of taps in the echo cancellor when enabled. -+ * \note This value is user configurable in /etc/asterisk/misdn.conf (echocancel) -+ */ - int ec_deftaps; - #endif -- -+ -+ /*! \brief TRUE if the channel was allocated from the available B channels */ - int channel_found; -- -+ -+ /*! \brief Who originated the call (ORG_AST, ORG_MISDN) -+ * \note Set but not used when the misdn_set_opt() application enables echo cancellation. -+ */ - int orig; - -+ /*! \brief Tx gain setting (range -8 to 8) -+ * \note This value is user configurable in /etc/asterisk/misdn.conf. -+ * It is also settable by the misdn_set_opt() application. -+ */ - int txgain; -+ -+ /*! \brief Rx gain setting (range -8 to 8) -+ * \note This value is user configurable in /etc/asterisk/misdn.conf. -+ * It is also settable by the misdn_set_opt() application. -+ */ - int rxgain; -- -+ -+ /*! \brief Next node in the misdn_stack.holding list */ - struct misdn_bchannel *next; - }; - - --enum event_response_e (*cb_event) (enum event_e event, struct misdn_bchannel *bc, void *user_data); --void (*cb_log) (int level, int port, char *tmpl, ...) -+extern enum event_response_e (*cb_event) (enum event_e event, struct misdn_bchannel *bc, void *user_data); -+ -+extern void (*cb_log) (int level, int port, char *tmpl, ...) - __attribute__ ((format (printf, 3, 4))); --int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len); - -+extern int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len); -+ - struct misdn_lib_iface { - enum event_response_e (*cb_event)(enum event_e event, struct misdn_bchannel *bc, void *user_data); - void (*cb_log)(int level, int port, char *tmpl, ...) -@@ -439,7 +721,7 @@ - int misdn_lib_get_port_down(int port); - - int misdn_lib_get_port_up (int port) ; -- -+ - int misdn_lib_maxports_get(void) ; - - void misdn_lib_release(struct misdn_bchannel *bc); -Index: channels/misdn/chan_misdn_config.h -=================================================================== ---- a/channels/misdn/chan_misdn_config.h (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/misdn/chan_misdn_config.h (.../team/group/issue14292) (revision 178988) -@@ -46,10 +46,16 @@ - MISDN_CFG_DIALPLAN, /* int */ - MISDN_CFG_LOCALDIALPLAN, /* int */ - MISDN_CFG_CPNDIALPLAN, /* int */ -- MISDN_CFG_NATPREFIX, /* char[] */ -- MISDN_CFG_INTERNATPREFIX, /* char[] */ -+ MISDN_CFG_TON_PREFIX_UNKNOWN, /* char[] */ -+ MISDN_CFG_TON_PREFIX_INTERNATIONAL, /* char[] */ -+ MISDN_CFG_TON_PREFIX_NATIONAL, /* char[] */ -+ MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC,/* char[] */ -+ MISDN_CFG_TON_PREFIX_SUBSCRIBER, /* char[] */ -+ MISDN_CFG_TON_PREFIX_ABBREVIATED, /* char[] */ - MISDN_CFG_PRES, /* int */ - MISDN_CFG_SCREEN, /* int */ -+ MISDN_CFG_DISPLAY_CONNECTED, /* int */ -+ MISDN_CFG_DISPLAY_SETUP, /* int */ - MISDN_CFG_ALWAYS_IMMEDIATE, /* int (bool) */ - MISDN_CFG_NODIALTONE, /* int (bool) */ - MISDN_CFG_IMMEDIATE, /* int (bool) */ -Index: channels/chan_gtalk.c -=================================================================== ---- a/channels/chan_gtalk.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/chan_gtalk.c (.../team/group/issue14292) (revision 178988) -@@ -43,6 +43,7 @@ - #include - #include - #include -+#include - - #include "asterisk/lock.h" - #include "asterisk/channel.h" -@@ -382,6 +383,7 @@ - int pref_codec = 0; - int alreadysent = 0; - int codecs_num = 0; -+ char *lowerto = NULL; - - iq = iks_new("iq"); - gtalk = iks_new("session"); -@@ -428,7 +430,14 @@ - - iks_insert_attrib(gtalk, "xmlns", "http://www.google.com/session"); - iks_insert_attrib(gtalk, "type",initiator ? "initiate": "accept"); -- iks_insert_attrib(gtalk, "initiator", initiator ? from : to); -+ /* put the initiator attribute to lower case if we receive the call -+ * otherwise GoogleTalk won't establish the session */ -+ if (!initiator) { -+ char c; -+ char *t = lowerto = ast_strdupa(to); -+ while (((c = *t) != '/') && (*t++ = tolower(c))); -+ } -+ iks_insert_attrib(gtalk, "initiator", initiator ? from : lowerto); - iks_insert_attrib(gtalk, "id", sid); - iks_insert_node(iq, gtalk); - iks_insert_node(gtalk, dcodecs); -@@ -448,6 +457,8 @@ - static int gtalk_invite_response(struct gtalk_pvt *p, char *to , char *from, char *sid, int initiator) - { - iks *iq, *session, *transport; -+ char *lowerto = NULL; -+ - iq = iks_new("iq"); - session = iks_new("session"); - transport = iks_new("transport"); -@@ -465,7 +476,14 @@ - ast_aji_increment_mid(p->parent->connection->mid); - iks_insert_attrib(session, "type", "transport-accept"); - iks_insert_attrib(session, "id", sid); -- iks_insert_attrib(session, "initiator", initiator ? from : to); -+ /* put the initiator attribute to lower case if we receive the call -+ * otherwise GoogleTalk won't establish the session */ -+ if (!initiator) { -+ char c; -+ char *t = lowerto = ast_strdupa(to); -+ while (((c = *t) != '/') && (*t++ = tolower(c))); -+ } -+ iks_insert_attrib(session, "initiator", initiator ? from : lowerto); - iks_insert_attrib(session, "xmlns", "http://www.google.com/session"); - iks_insert_attrib(transport, "xmlns", "http://www.google.com/transport/p2p"); - iks_insert_node(iq,session); -@@ -761,6 +779,7 @@ - struct in_addr us; - iks *iq, *gtalk, *candidate, *transport; - char user[17], pass[17], preference[5], port[7]; -+ char *lowerfrom = NULL; - - - iq = iks_new("iq"); -@@ -793,6 +812,9 @@ - - ast_rtp_get_us(p->rtp, &sin); - ast_find_ourip(&us, bindaddr); -+ if (!strcmp(ast_inet_ntoa(us), "127.0.0.1")) { -+ ast_log(LOG_WARNING, "Found a loopback IP on the system, check your network configuration or set the bindaddr attribute."); -+ } - - /* Setup our gtalk candidates */ - ast_copy_string(ours1->name, "rtp", sizeof(ours1->name)); -@@ -839,7 +861,14 @@ - ast_aji_increment_mid(c->mid); - iks_insert_attrib(gtalk, "type", "transport-info"); - iks_insert_attrib(gtalk, "id", sid); -- iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : from); -+ /* put the initiator attribute to lower case if we receive the call -+ * otherwise GoogleTalk won't establish the session */ -+ if (!p->initiator) { -+ char c; -+ char *t = lowerfrom = ast_strdupa(from); -+ while (((c = *t) != '/') && (*t++ = tolower(c))); -+ } -+ iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : lowerfrom); - iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS); - iks_insert_attrib(candidate, "name", tmp->name); - iks_insert_attrib(candidate, "address", tmp->ip); -@@ -1049,6 +1078,7 @@ - { - iks *request, *session = NULL; - int res = -1; -+ char *lowerthem = NULL; - - request = iks_new("iq"); - if (request) { -@@ -1061,7 +1091,14 @@ - if (session) { - iks_insert_attrib(session, "type", action); - iks_insert_attrib(session, "id", p->sid); -- iks_insert_attrib(session, "initiator", p->initiator ? p->us : p->them); -+ /* put the initiator attribute to lower case if we receive the call -+ * otherwise GoogleTalk won't establish the session */ -+ if (!p->initiator) { -+ char c; -+ char *t = lowerthem = ast_strdupa(p->them); -+ while (((c = *t) != '/') && (*t++ = tolower(c))); -+ } -+ iks_insert_attrib(session, "initiator", p->initiator ? p->us : lowerthem); - iks_insert_attrib(session, "xmlns", "http://www.google.com/session"); - iks_insert_node(request, session); - ast_aji_send(client->connection, request); -@@ -1477,6 +1514,7 @@ - struct gtalk *client = p->parent; - iks *iq, *gtalk, *dtmf; - char buffer[2] = {digit, '\0'}; -+ char *lowerthem = NULL; - iq = iks_new("iq"); - gtalk = iks_new("gtalk"); - dtmf = iks_new("dtmf"); -@@ -1495,7 +1533,14 @@ - ast_aji_increment_mid(client->connection->mid); - iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk"); - iks_insert_attrib(gtalk, "action", "session-info"); -- iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: p->them); -+ /* put the initiator attribute to lower case if we receive the call -+ * otherwise GoogleTalk won't establish the session */ -+ if (!p->initiator) { -+ char c; -+ char *t = lowerthem = ast_strdupa(p->them); -+ while (((c = *t) != '/') && (*t++ = tolower(c))); -+ } -+ iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: lowerthem); - iks_insert_attrib(gtalk, "sid", p->sid); - iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf"); - iks_insert_attrib(dtmf, "code", buffer); -@@ -1619,6 +1664,7 @@ - client->connection = ast_aji_get_client(sender); - if (!client->connection) { - ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender); -+ ASTOBJ_UNREF(client, gtalk_member_destroy); - return NULL; - } - } -@@ -1868,8 +1914,12 @@ - struct ast_flags config_flags = { 0 }; - - cfg = ast_config_load(GOOGLE_CONFIG, config_flags); -- if (!cfg) -+ if (!cfg) { - return 0; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", GOOGLE_CONFIG); -+ return 0; -+ } - - /* Copy the default jb config over global_jbconf */ - memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); -@@ -1960,6 +2010,7 @@ - ASTOBJ_UNLOCK(iterator); - }); - ASTOBJ_CONTAINER_LINK(>alk_list, member); -+ ASTOBJ_UNREF(member, gtalk_member_destroy); - } else { - ASTOBJ_UNLOCK(member); - ASTOBJ_UNREF(member, gtalk_member_destroy); -Index: channels/iax2-parser.c -=================================================================== ---- a/channels/iax2-parser.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/channels/iax2-parser.c (.../team/group/issue14292) (revision 178988) -@@ -533,14 +533,14 @@ - sprintf(subclass2, "%c", fh->csub); - subclass = subclass2; - } else if (fh->type == AST_FRAME_IAX) { -- if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) { -+ if (fh->csub >= ARRAY_LEN(iaxs)) { - snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub); - subclass = subclass2; - } else { - subclass = iaxs[(int)fh->csub]; - } - } else if (fh->type == AST_FRAME_CONTROL) { -- if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) { -+ if (fh->csub >= ARRAY_LEN(cmds)) { - snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub); - subclass = subclass2; - } else { -@@ -929,7 +929,7 @@ - for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) { - if (strcmp(tmp, var2->name) == 0) { - ast_str_set(&str, 0, "%s%s", var2->value, tmp2); -- var = ast_variable_new(tmp, str->str, var2->file); -+ var = ast_variable_new(tmp, ast_str_buffer(str), var2->file); - var->next = var2->next; - if (prev) { - prev->next = var; -Index: CREDITS -=================================================================== ---- a/CREDITS (.../tags/1.6.1-rc1) (revision 178988) -+++ b/CREDITS (.../team/group/issue14292) (revision 178988) -@@ -192,6 +192,8 @@ - - See http://voip-info.org/users/view/sergee - serg(AT)voipsolutions.ru - -+Klaus Darillon - the SIPremoveHeader function in chan_sip -+ - === OTHER CONTRIBUTIONS === - John Todd - Monkey sounds and associated teletorture prompt - Michael Jerris - bug marshaling -Index: tests/test_sched.c -=================================================================== ---- a/tests/test_sched.c (.../tags/1.6.1-rc1) (revision 0) -+++ b/tests/test_sched.c (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,247 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2009, Digium, Inc. -+ * -+ * Russell Bryant -+ * -+ * 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 ast_sched performance test module -+ * -+ * \author Russell Bryant -+ */ -+ -+#include "asterisk.h" -+ -+#include -+ -+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -+ -+#include "asterisk/module.h" -+#include "asterisk/cli.h" -+#include "asterisk/utils.h" -+#include "asterisk/sched.h" -+ -+static int sched_cb(const void *data) -+{ -+ return 0; -+} -+ -+static char *handle_cli_sched_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ struct sched_context *con; -+ char *res = CLI_FAILURE; -+ int id1, id2, id3, wait; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "sched test"; -+ e->usage = "" -+ "Usage: sched test\n" -+ " Test scheduler entry ordering.\n" -+ ""; -+ return NULL; -+ case CLI_GENERATE: -+ return NULL; -+ } -+ -+ if (a->argc != e->args) { -+ return CLI_SHOWUSAGE; -+ } -+ -+ ast_cli(a->fd, "Testing scheduler entry ordering ...\n"); -+ -+ if (!(con = sched_context_create())) { -+ ast_cli(a->fd, "Test failed - could not create scheduler context\n"); -+ return CLI_FAILURE; -+ } -+ -+ /* Add 3 scheduler entries, and then remove them, ensuring that the result -+ * of ast_sched_wait() looks appropriate at each step along the way. */ -+ -+ if ((wait = ast_sched_wait(con)) != -1) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned -1, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ if ((id1 = ast_sched_add(con, 100000, sched_cb, NULL)) == -1) { -+ ast_cli(a->fd, "Failed to add scheduler entry\n"); -+ goto return_cleanup; -+ } -+ -+ if ((wait = ast_sched_wait(con)) > 100000) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned <= 100000, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ if ((id2 = ast_sched_add(con, 10000, sched_cb, NULL)) == -1) { -+ ast_cli(a->fd, "Failed to add scheduler entry\n"); -+ goto return_cleanup; -+ } -+ -+ if ((wait = ast_sched_wait(con)) > 10000) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned <= 10000, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ if ((id3 = ast_sched_add(con, 1000, sched_cb, NULL)) == -1) { -+ ast_cli(a->fd, "Failed to add scheduler entry\n"); -+ goto return_cleanup; -+ } -+ -+ if ((wait = ast_sched_wait(con)) > 1000) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned <= 1000, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ if (ast_sched_del(con, id3) == -1) { -+ ast_cli(a->fd, "Failed to remove scheduler entry\n"); -+ goto return_cleanup; -+ } -+ -+ if ((wait = ast_sched_wait(con)) <= 1000) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned > 1000, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ if (ast_sched_del(con, id2) == -1) { -+ ast_cli(a->fd, "Failed to remove scheduler entry\n"); -+ goto return_cleanup; -+ } -+ -+ if ((wait = ast_sched_wait(con)) <= 10000) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned > 10000, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ if (ast_sched_del(con, id1) == -1) { -+ ast_cli(a->fd, "Failed to remove scheduler entry\n"); -+ goto return_cleanup; -+ } -+ -+ if ((wait = ast_sched_wait(con)) != -1) { -+ ast_cli(a->fd, "ast_sched_wait() should have returned -1, returned '%d'\n", -+ wait); -+ goto return_cleanup; -+ } -+ -+ res = CLI_SUCCESS; -+ -+ ast_cli(a->fd, "Test passed!\n"); -+ -+return_cleanup: -+ sched_context_destroy(con); -+ -+ return res; -+} -+ -+static char *handle_cli_sched_bench(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ struct sched_context *con; -+ struct timeval start; -+ unsigned int num, i; -+ int *sched_ids = NULL; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "sched benchmark"; -+ e->usage = "" -+ "Usage: sched test \n" -+ ""; -+ return NULL; -+ case CLI_GENERATE: -+ return NULL; -+ } -+ -+ if (a->argc != e->args + 1) { -+ return CLI_SHOWUSAGE; -+ } -+ -+ if (sscanf(a->argv[e->args], "%u", &num) != 1) { -+ return CLI_SHOWUSAGE; -+ } -+ -+ if (!(con = sched_context_create())) { -+ ast_cli(a->fd, "Test failed - could not create scheduler context\n"); -+ return CLI_FAILURE; -+ } -+ -+ if (!(sched_ids = ast_malloc(sizeof(*sched_ids) * num))) { -+ ast_cli(a->fd, "Test failed - memory allocation failure\n"); -+ goto return_cleanup; -+ } -+ -+ ast_cli(a->fd, "Testing ast_sched_add() performance - timing how long it takes " -+ "to add %u entries at random time intervals from 0 to 60 seconds\n", num); -+ -+ start = ast_tvnow(); -+ -+ for (i = 0; i < num; i++) { -+ int when = abs(ast_random()) % 60000; -+ if ((sched_ids[i] = ast_sched_add(con, when, sched_cb, NULL)) == -1) { -+ ast_cli(a->fd, "Test failed - sched_add returned -1\n"); -+ goto return_cleanup; -+ } -+ } -+ -+ ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start)); -+ -+ ast_cli(a->fd, "Testing ast_sched_del() performance - timing how long it takes " -+ "to delete %u entries with random time intervals from 0 to 60 seconds\n", num); -+ -+ start = ast_tvnow(); -+ -+ for (i = 0; i < num; i++) { -+ if (ast_sched_del(con, sched_ids[i]) == -1) { -+ ast_cli(a->fd, "Test failed - sched_del returned -1\n"); -+ goto return_cleanup; -+ } -+ } -+ -+ ast_cli(a->fd, "Test complete - %" PRIi64 " us\n", ast_tvdiff_us(ast_tvnow(), start)); -+ -+return_cleanup: -+ sched_context_destroy(con); -+ if (sched_ids) { -+ ast_free(sched_ids); -+ } -+ -+ return CLI_SUCCESS; -+} -+ -+static struct ast_cli_entry cli_sched[] = { -+ AST_CLI_DEFINE(handle_cli_sched_bench, "Benchmark ast_sched add/del performance"), -+ AST_CLI_DEFINE(handle_cli_sched_test, "Test scheduler entry ordering"), -+}; -+ -+static int unload_module(void) -+{ -+ ast_cli_unregister_multiple(cli_sched, ARRAY_LEN(cli_sched)); -+ return 0; -+} -+ -+static int load_module(void) -+{ -+ ast_cli_register_multiple(cli_sched, ARRAY_LEN(cli_sched)); -+ return AST_MODULE_LOAD_SUCCESS; -+} -+ -+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ast_sched performance test module"); - -Property changes on: tests/test_sched.c -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: tests/test_heap.c -=================================================================== ---- a/tests/test_heap.c (.../tags/1.6.1-rc1) (revision 0) -+++ b/tests/test_heap.c (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,219 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2009, Digium, Inc. -+ * -+ * Russell Bryant -+ * -+ * 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 Heap data structure test module -+ * -+ * \author Russell Bryant -+ */ -+ -+#include "asterisk.h" -+ -+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -+ -+#include "asterisk/module.h" -+#include "asterisk/cli.h" -+#include "asterisk/utils.h" -+#include "asterisk/heap.h" -+ -+struct node { -+ long val; -+ size_t index; -+}; -+ -+static int node_cmp(void *_n1, void *_n2) -+{ -+ struct node *n1 = _n1; -+ struct node *n2 = _n2; -+ -+ if (n1->val < n2->val) { -+ return -1; -+ } else if (n1->val == n2->val) { -+ return 0; -+ } else { -+ return 1; -+ } -+} -+ -+static int test1(int fd) -+{ -+ struct ast_heap *h; -+ struct node *obj; -+ struct node nodes[3] = { -+ { 1, }, -+ { 2, }, -+ { 3, }, -+ }; -+ -+ if (!(h = ast_heap_create(8, node_cmp, offsetof(struct node, index)))) { -+ return -1; -+ } -+ -+ /* Pushing 1 2 3, and then popping 3 elements */ -+ -+ ast_cli(fd, "Test #1 - Push a few elements onto a heap and make sure that they " -+ "come back off in the right order.\n"); -+ -+ ast_heap_push(h, &nodes[0]); -+ -+ ast_heap_push(h, &nodes[1]); -+ -+ ast_heap_push(h, &nodes[2]); -+ -+ obj = ast_heap_pop(h); -+ if (obj->val != 3) { -+ return -2; -+ } -+ -+ obj = ast_heap_pop(h); -+ if (obj->val != 2) { -+ return -3; -+ } -+ -+ obj = ast_heap_pop(h); -+ if (obj->val != 1) { -+ return -4; -+ } -+ -+ obj = ast_heap_pop(h); -+ if (obj) { -+ return -5; -+ } -+ -+ h = ast_heap_destroy(h); -+ -+ ast_cli(fd, "Test #1 successful.\n"); -+ -+ return 0; -+} -+ -+static int test2(int fd) -+{ -+ struct ast_heap *h = NULL; -+ static const unsigned int one_million = 1000000; -+ struct node *nodes = NULL; -+ struct node *node; -+ unsigned int i = one_million; -+ long last = LONG_MAX, cur; -+ int res = 0; -+ -+ ast_cli(fd, "Test #2 - Push a million random elements on to a heap, " -+ "verify that the heap has been properly constructed, " -+ "and then ensure that the elements are come back off in the proper order\n"); -+ -+ if (!(nodes = ast_malloc(one_million * sizeof(*node)))) { -+ res = -1; -+ goto return_cleanup; -+ } -+ -+ if (!(h = ast_heap_create(20, node_cmp, offsetof(struct node, index)))) { -+ res = -2; -+ goto return_cleanup; -+ } -+ -+ while (i--) { -+ nodes[i].val = ast_random(); -+ ast_heap_push(h, &nodes[i]); -+ } -+ -+ if (ast_heap_verify(h)) { -+ res = -3; -+ goto return_cleanup; -+ } -+ -+ i = 0; -+ while ((node = ast_heap_pop(h))) { -+ cur = node->val; -+ if (cur > last) { -+ ast_cli(fd, "i: %u, cur: %ld, last: %ld\n", i, cur, last); -+ res = -4; -+ goto return_cleanup; -+ } -+ last = cur; -+ i++; -+ } -+ -+ if (i != one_million) { -+ ast_cli(fd, "Stopped popping off after only getting %u nodes\n", i); -+ res = -5; -+ goto return_cleanup; -+ } -+ -+ ast_cli(fd, "Test #2 successful.\n"); -+ -+return_cleanup: -+ if (h) { -+ h = ast_heap_destroy(h); -+ } -+ if (nodes) { -+ ast_free(nodes); -+ } -+ -+ return res; -+} -+ -+static char *handle_cli_heap_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ int res; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "heap test"; -+ e->usage = "" -+ "Usage: heap test\n" -+ ""; -+ return NULL; -+ case CLI_GENERATE: -+ return NULL; -+ } -+ -+ if (a->argc != e->args) { -+ return CLI_SHOWUSAGE; -+ } -+ -+ if ((res = test1(a->fd))) { -+ ast_cli(a->fd, "Test 1 failed! (%d)\n", res); -+ return CLI_FAILURE; -+ } -+ -+ if ((res = test2(a->fd))) { -+ ast_cli(a->fd, "Test 2 failed! (%d)\n", res); -+ return CLI_FAILURE; -+ } -+ -+ return CLI_SUCCESS; -+} -+ -+static struct ast_cli_entry cli_heap[] = { -+ AST_CLI_DEFINE(handle_cli_heap_test, "Test the heap implementation"), -+}; -+ -+static int unload_module(void) -+{ -+ ast_cli_unregister_multiple(cli_heap, ARRAY_LEN(cli_heap)); -+ return 0; -+} -+ -+static int load_module(void) -+{ -+ ast_cli_register_multiple(cli_heap, ARRAY_LEN(cli_heap)); -+ return AST_MODULE_LOAD_SUCCESS; -+} -+ -+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Heap test module"); - -Property changes on: tests/test_heap.c -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: configure.ac -=================================================================== ---- a/configure.ac (.../tags/1.6.1-rc1) (revision 178988) -+++ b/configure.ac (.../team/group/issue14292) (revision 178988) -@@ -32,7 +32,19 @@ - CPPFLAGS=-I/usr/local/include - LDFLAGS=-L/usr/local/lib - ;; -- -+ openbsd*) -+ ac_default_prefix=/usr/local -+ if test ${prefix} = '/usr/local' || test ${prefix} = 'NONE'; then -+ if test ${sysconfdir} = '${prefix}/etc'; then -+ sysconfdir=/etc -+ fi -+ if test ${mandir} = '${prefix}/man'; then -+ mandir=/usr/share/man -+ fi -+ fi -+ CPPFLAGS=-I/usr/local/include -+ LDFLAGS=-L/usr/local/lib -+ ;; - *) - ac_default_prefix=/usr - if test ${prefix} = '/usr' || test ${prefix} = 'NONE'; then -@@ -70,7 +82,7 @@ - AC_SUBST(HOST_VENDOR) - AC_SUBST(HOST_OS) - --WINARCH=0 -+PBX_WINARCH=0 - - case "${host_os}" in - freebsd*) -@@ -87,11 +99,11 @@ - ;; - mingw32) - OSARCH=mingw32 -- WINARCH=1 -+ PBX_WINARCH=1 - ;; - cygwin) - OSARCH=cygwin -- WINARCH=1 -+ PBX_WINARCH=1 - ;; - *) - OSARCH=${host_os} -@@ -99,7 +111,7 @@ - esac - - AC_SUBST(OSARCH) --AC_SUBST(WINARCH) -+AC_SUBST(PBX_WINARCH) - - # check for uname - AC_PATH_TOOL([UNAME], [uname], No) -@@ -162,14 +174,19 @@ - AC_PATH_PROG([LN], [ln], :) - AC_PATH_PROG([DOT], [dot], :) - AC_PATH_PROG([WGET], [wget], :) -+AC_PATH_PROG([CURL], [curl], :) - AC_PATH_PROG([RUBBER], [rubber], :) - AC_PATH_PROG([KPATHSEA], [kpsewhich], :) -+AC_PATH_PROG([XMLSTARLET], [xmlstarlet], :) - if test "${WGET}" != ":" ; then - DOWNLOAD=${WGET} -+else if test "${CURL}" != ":" ; then -+ DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\"" - else - AC_PATH_PROG([FETCH], [fetch], [:]) - DOWNLOAD=${FETCH} - fi -+fi - AC_SUBST(DOWNLOAD) - - AC_CHECK_TOOL([SOXMIX], [soxmix], [:]) -@@ -187,8 +204,9 @@ - - AC_LANG(C) - --AC_ARG_ENABLE(dev-mode, -- [ --enable-dev-mode Turn on developer mode], -+AC_ARG_ENABLE([dev-mode], -+ [AS_HELP_STRING([--enable-dev-mode], -+ [Turn on developer mode])], - [case "${enableval}" in - y|ye|yes) AST_DEVMODE=yes ;; - n|no) AST_DEVMODE=no ;; -@@ -225,9 +243,12 @@ - AST_EXT_LIB_SETUP([ICONV], [Iconv Library], [iconv]) - AST_EXT_LIB_SETUP([IKSEMEL], [Iksemel Jabber Library], [iksemel]) - AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap]) -+AST_EXT_LIB_SETUP([INOTIFY], [inotify support], [inotify]) -+AST_EXT_LIB_SETUP([IODBC], [iODBC], [iodbc]) - AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux Library], [isdnnet]) - AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack]) - AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap]) -+AST_EXT_LIB_SETUP([LIBXML2], [LibXML2], [libxml2]) - AST_EXT_LIB_SETUP([LTDL], [libtool], [ltdl]) - AST_EXT_LIB_SETUP([LUA], [Lua], [lua]) - AST_EXT_LIB_SETUP([MISDN], [mISDN User Library], [misdn]) -@@ -235,7 +256,6 @@ - AST_EXT_LIB_SETUP([NCURSES], [ncurses], [ncurses]) - AST_EXT_LIB_SETUP([NETSNMP], [Net-SNMP], [netsnmp]) - AST_EXT_LIB_SETUP([NEWT], [newt], [newt]) --AST_EXT_LIB_SETUP([UNIXODBC], [unixODBC], [odbc]) - AST_EXT_LIB_SETUP([OGG], [OGG], [ogg]) - AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk]) - AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss]) -@@ -263,11 +283,13 @@ - AST_EXT_LIB_SETUP([TERMCAP], [Termcap], [termcap]) - AST_EXT_LIB_SETUP([TINFO], [Term Info], [tinfo]) - AST_EXT_LIB_SETUP([TONEZONE], [tonezone], [tonezone]) -+AST_EXT_LIB_SETUP([UNIXODBC], [unixODBC], [unixodbc]) - AST_EXT_LIB_SETUP([USB], [usb], [usb]) - AST_EXT_LIB_SETUP([VORBIS], [Vorbis], [vorbis]) - AST_EXT_LIB_SETUP([VPB], [Voicetronix API], [vpb]) - AST_EXT_LIB_SETUP([X11], [X11 support], [x11]) - AST_EXT_LIB_SETUP([ZLIB], [zlib], [z]) -+AST_EXT_LIB_SETUP([TIMERFD], [timerfd], [timerfd]) - - # check for basic system features and functionality before - # checking for package libraries -@@ -320,7 +342,7 @@ - AC_FUNC_STRTOD - AC_FUNC_UTIME_NULL - AC_FUNC_VPRINTF --AC_CHECK_FUNCS([asprintf atexit dup2 endpwent ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtol strtoq unsetenv utime vasprintf]) -+AC_CHECK_FUNCS([asprintf atexit closefrom dup2 endpwent ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtol strtoq unsetenv utime vasprintf getpeereid sysctl swapctl]) - - AC_CHECK_FUNCS([glob]) - -@@ -338,8 +360,9 @@ - AC_DEFINE([HAVE_SYS_POLL_H], 1, [Define to 1 if your system has working sys/poll.h]), - ) - --AC_ARG_ENABLE(internal-poll, -- [ --enable-internal-poll Use Asterisk's poll implementation], -+AC_ARG_ENABLE([internal-poll], -+ [AS_HELP_STRING([--enable-internal-poll], -+ [Use Asterisk's poll implementation])], - [case "${enableval}" in - y|ye|yes) HAS_POLL="";; - n|no) HAS_POLL="${HAS_POLL}" ;; -@@ -463,6 +486,8 @@ - AST_GCC_ATTRIBUTE(sentinel) - AST_GCC_ATTRIBUTE(warn_unused_result) - AST_GCC_ATTRIBUTE(weak) -+AST_GCC_ATTRIBUTE(weak_import) -+AST_GCC_ATTRIBUTE(alias, [alias("foo")]) - - AC_MSG_CHECKING(for -ffunction-sections support) - saved_CFLAGS="${CFLAGS}" -@@ -596,6 +621,10 @@ - - AST_C_DEFINE_CHECK([DAHDI], [DAHDI_CODE], [dahdi/user.h]) - -+AST_C_DEFINE_CHECK([DAHDI_HALF_FULL], [DAHDI_POLICY_HALF_FULL], [dahdi/user.h]) -+ -+AST_C_COMPILE_CHECK([DAHDI_LINEREVERSE_VMWI], [struct dahdi_vmwi_info booger], [dahdi/user.h], , [enhanced dahdi vmwi support]) -+ - # BSD might not have exp2, and/or log2 - AST_EXT_LIB_CHECK([EXP2L], [m], [exp2l]) - AST_EXT_LIB_CHECK([LOG2L], [m], [log2l]) -@@ -645,6 +674,7 @@ - AST_EXT_LIB_CHECK([CEIL], [m], [ceil]) - - AST_C_COMPILE_CHECK([GETIFADDRS], [struct ifaddrs *p; getifaddrs(&p)], [ifaddrs.h], , [getifaddrs() support]) -+AST_C_COMPILE_CHECK([TIMERFD], [timerfd_create(0,0); timerfd_settime(0,0,NULL,NULL);], [sys/timerfd.h], , [timerfd support]) - - GSM_INTERNAL="yes" - AC_SUBST(GSM_INTERNAL) -@@ -1242,6 +1272,10 @@ - LIBS="${saved_libs}" - fi - -+AST_EXT_LIB_CHECK([IODBC], [iodbc], [SQLConnect], [sql.h], [-lpthread]) -+ -+AST_EXT_LIB_CHECK([INOTIFY], [c], [inotify_init], [sys/inotify.h]) -+ - AST_EXT_LIB_CHECK([JACK], [jack], [jack_activate], [jack/jack.h]) - - # Needed by unixodbc -@@ -1249,6 +1283,28 @@ - - AST_EXT_LIB_CHECK([LDAP], [ldap], [ldap_initialize], [ldap.h]) - -+AC_ARG_ENABLE([xmldoc], -+ [AS_HELP_STRING([--disable-xmldoc], -+ [Explicity disable XML documentation])], -+ [case "${enableval}" in -+ y|ye|yes) disable_xmldoc=no ;; -+ n|no) disable_xmldoc=yes ;; -+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-xmldoc) ;; -+ esac], [disable_xmldoc=no]) -+ -+if test "${disable_xmldoc}" != "yes"; then -+ AST_EXT_TOOL_CHECK([LIBXML2], [xml2], , , -+ [#include -+ #include ], -+ [LIBXML_TEST_VERSION]) -+ if test "${PBX_LIBXML2}" != 1; then -+ AC_MSG_NOTICE(*** XML documentation will not be available because the 'libxml2' development package is missing.) -+ AC_MSG_NOTICE(*** Please run the 'configure' script with the '--disable-xmldoc' parameter option) -+ AC_MSG_NOTICE(*** or install the 'libxml2' development package.) -+ exit 1 -+ fi -+fi -+ - AST_EXT_LIB_CHECK([MISDN], [mISDN], [mISDN_open], [mISDNuser/mISDNlib.h]) - - if test "${PBX_MISDN}" = 1; then -@@ -1337,6 +1393,8 @@ - - AST_EXT_LIB_CHECK([PRI], [pri], [pri_new_bri], [libpri.h]) - -+AST_EXT_LIB_CHECK([PRI_PROG_W_CAUSE], [pri], [pri_progress_with_cause], [libpri.h]) -+ - AST_EXT_LIB_CHECK([PRI_INBANDDISCONNECT], [pri], [pri_set_inbanddisconnect], [libpri.h]) - - AST_EXT_LIB_CHECK([RESAMPLE], [resample], [resample_open], [libresample.h], [-lm]) -@@ -1371,7 +1429,7 @@ - PWLIBDIR="${PWLIB_DIR}" - fi - AST_CHECK_PWLIB() -- AST_CHECK_PWLIB_VERSION([PWLib], [PWLIB], [ptbuildopts.h], [1], [9], [2]) -+ AST_CHECK_PWLIB_VERSION([PWLib], [PWLIB], [ptbuildopts.h], [1], [9], [2], [P[[WT]]LIB_VERSION]) - - if test "${HAS_PWLIB:-unset}" != "unset"; then - AST_CHECK_PWLIB_PLATFORM() -@@ -1381,7 +1439,7 @@ - AST_CHECK_PWLIB_BUILD([PWLib], [PWLIB], - [Define if your system has the PWLib libraries.], - [#include "ptlib.h"], -- [BOOL q = PTime::IsDaylightSavings();]) -+ [int q = (int) PTime::IsDaylightSavings();]) - fi - fi - -@@ -1483,7 +1541,12 @@ - - AST_EXT_LIB_CHECK([USB], [usb], [usb_init], [usb.h], []) - --AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc]) -+if test "${OSARCH}" = "OpenBSD"; -+then -+ AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc -logg]) -+else -+ AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc]) -+fi - - AC_LANG_PUSH(C++) - -@@ -1623,9 +1686,38 @@ - fi - fi - -+# build a GENERIC_ODBC result based on the presence of either UnixODBC (preferred) -+# or iODBC -+ -+PBX_GENERIC_ODBC=0 -+ -+if test "${PBX_UNIXODBC}" = 1; then -+ PBX_GENERIC_ODBC=1 -+ GENERIC_ODBC_LIB="${UNIXODBC_LIB}" -+ GENERIC_ODBC_INCLUDE="${UNIXODBC_INCLUDE}" -+elif test "${PBX_IODBC}" = 1; then -+ PBX_GENERIC_ODBC=1 -+ GENERIC_ODBC_LIB="${IODBC_LIB}" -+ GENERIC_ODBC_INCLUDE="${IODBC_INCLUDE}" -+fi -+ -+AC_SUBST([GENERIC_ODBC_LIB]) -+AC_SUBST([GENERIC_ODBC_INCLUDE]) -+AC_SUBST([PBX_GENERIC_ODBC]) -+ - AC_CONFIG_FILES([build_tools/menuselect-deps makeopts channels/h323/Makefile]) - AST_CHECK_MANDATORY - -+if test -f build_tools/menuselect-deps; then -+ # extract old values of all PBX_ variables from menuselect-deps -+ # and preserve them so that menuselect can determine whether -+ # any previously-met dependencies are no longer met and warn -+ # the user appropriately -+ while IFS="=:" read var val old_val; do -+ eval "PBX_${var}=\${PBX_${var}}:${val}" -+ done < build_tools/menuselect-deps -+fi -+ - AC_OUTPUT - - if test "x${silent}" != "xyes" ; then -Index: apps/app_stack.c -=================================================================== ---- a/apps/app_stack.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_stack.c (.../team/group/issue14292) (revision 178988) -@@ -38,38 +38,139 @@ - #include "asterisk/app.h" - #include "asterisk/manager.h" - #include "asterisk/channel.h" -- --/* usage of AGI is optional, so indicate that to the header file */ --#define ASTERISK_AGI_OPTIONAL - #include "asterisk/agi.h" - -+/*** DOCUMENTATION -+ -+ -+ Jump to label, saving return address. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Jumps to the label specified, saving the return address. -+ -+ -+ GosubIf -+ Macro -+ Goto -+ Return -+ StackPop -+ -+ -+ -+ -+ Conditionally jump to label, saving return address. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ If the condition is true, then jump to labeliftrue. If false, jumps to -+ labeliffalse, if specified. In either case, a jump saves the return point -+ in the dialplan, to be returned to with a Return. -+ -+ -+ Gosub -+ Return -+ MacroIf -+ IF -+ GotoIf -+ -+ -+ -+ -+ Return from gosub routine. -+ -+ -+ -+ Return value. -+ -+ -+ -+ Jumps to the last label on the stack, removing it. The return value, if -+ any, is saved in the channel variable GOSUB_RETVAL. -+ -+ -+ Gosub -+ StackPop -+ -+ -+ -+ -+ Remove one address from gosub stack. -+ -+ -+ -+ Removes last label on the stack, discarding it. -+ -+ -+ Return -+ Gosub -+ -+ -+ -+ -+ Manage variables local to the gosub stack frame. -+ -+ -+ -+ -+ -+ Read and write a variable local to the gosub stack frame, once we Return() it will be lost -+ (or it will go back to whatever value it had before the Gosub()). -+ -+ -+ Gosub -+ GosubIf -+ Return -+ -+ -+ -+ -+ Retrieve variables hidden by the local gosub stack frame. -+ -+ -+ -+ -+ -+ -+ Read a variable varname hidden by -+ n levels of gosub stack frames. Note that ${LOCAL_PEEK(0,foo)} -+ is the same as foo, since the value of n -+ peeks under 0 levels of stack frames; in other words, 0 is the current level. If -+ n exceeds the available number of stack frames, then an empty -+ string is returned. -+ -+ -+ Gosub -+ GosubIf -+ Return -+ -+ -+ ***/ - - static const char *app_gosub = "Gosub"; - static const char *app_gosubif = "GosubIf"; - static const char *app_return = "Return"; - static const char *app_pop = "StackPop"; - --static const char *gosub_synopsis = "Jump to label, saving return address"; --static const char *gosubif_synopsis = "Conditionally jump to label, saving return address"; --static const char *return_synopsis = "Return from gosub routine"; --static const char *pop_synopsis = "Remove one address from gosub stack"; -- --static const char *gosub_descrip = --" Gosub([[context,]exten,]priority[(arg1[,...][,argN])]):\n" --"Jumps to the label specified, saving the return address.\n"; --static const char *gosubif_descrip = --" GosubIf(condition?labeliftrue[(arg1[,...])][:labeliffalse[(arg1[,...])]]):\n" --"If the condition is true, then jump to labeliftrue. If false, jumps to\n" --"labeliffalse, if specified. In either case, a jump saves the return point\n" --"in the dialplan, to be returned to with a Return.\n"; --static const char *return_descrip = --" Return([return-value]):\n" --"Jumps to the last label on the stack, removing it. The return value, if\n" --"any, is saved in the channel variable GOSUB_RETVAL.\n"; --static const char *pop_descrip = --" StackPop():\n" --"Removes last label on the stack, discarding it.\n"; -- - static void gosub_free(void *data); - - static struct ast_datastore_info stack_info = { -@@ -298,6 +399,8 @@ - frame_set_var(chan, newframe, argname, args2.argval[i]); - ast_debug(1, "Setting '%s' to '%s'\n", argname, args2.argval[i]); - } -+ snprintf(argname, sizeof(argname), "%d", args2.argc); -+ frame_set_var(chan, newframe, "ARGC", argname); - - /* And finally, save our return address */ - oldlist = stack_store->data; -@@ -397,12 +500,44 @@ - - static struct ast_custom_function local_function = { - .name = "LOCAL", -- .synopsis = "Variables local to the gosub stack frame", -- .syntax = "LOCAL()", - .write = local_write, - .read = local_read, - }; - -+static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -+{ -+ int found = 0, n; -+ struct ast_var_t *variables; -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(n); -+ AST_APP_ARG(name); -+ ); -+ -+ if (!chan) { -+ ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n"); -+ return -1; -+ } -+ -+ AST_STANDARD_APP_ARGS(args, data); -+ n = atoi(args.n); -+ *buf = '\0'; -+ -+ ast_channel_lock(chan); -+ AST_LIST_TRAVERSE(&chan->varshead, variables, entries) { -+ if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) { -+ ast_copy_string(buf, ast_var_value(variables), len); -+ break; -+ } -+ } -+ ast_channel_unlock(chan); -+ return 0; -+} -+ -+static struct ast_custom_function peek_function = { -+ .name = "LOCAL_PEEK", -+ .read = peek_read, -+}; -+ - static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, char **argv) - { - int old_priority, priority; -@@ -461,16 +596,16 @@ - int res; - - ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); -- ast_copy_string(chan->context, "app_stack_gosub_virtual_context", sizeof(chan->context)); -- ast_copy_string(chan->exten, "s", sizeof(chan->exten)); -- chan->priority = 0; - - if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { - struct ast_pbx *pbx = chan->pbx; -+ struct ast_pbx_args args; -+ memset(&args, 0, sizeof(args)); -+ args.no_hangup_chan = 1; - /* Suppress warning about PBX already existing */ - chan->pbx = NULL; - ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); -- ast_pbx_run(chan); -+ ast_pbx_run_args(chan, &args); - ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); - if (chan->pbx) { - ast_free(chan->pbx); -@@ -503,15 +638,8 @@ - - static int unload_module(void) - { -- struct ast_context *con; -- - if (ast_agi_unregister) { -- ast_agi_unregister(ast_module_info->self, &gosub_agi_command); -- -- if ((con = ast_context_find("app_stack_gosub_virtual_context"))) { -- ast_context_remove_extension2(con, "s", 1, NULL, 0); -- ast_context_destroy(con, "app_stack"); /* leave nothing behind */ -- } -+ ast_agi_unregister(ast_module_info->self, &gosub_agi_command); - } - - ast_unregister_application(app_return); -@@ -519,34 +647,23 @@ - ast_unregister_application(app_gosubif); - ast_unregister_application(app_gosub); - ast_custom_function_unregister(&local_function); -+ ast_custom_function_unregister(&peek_function); - - return 0; - } - - static int load_module(void) - { -- struct ast_context *con; -- -- /* usage of AGI is optional, so check to see if the ast_agi_register() -- function is available; if so, use it. -- */ - if (ast_agi_register) { -- con = ast_context_find_or_create(NULL, NULL, "app_stack_gosub_virtual_context", "app_stack"); -- if (!con) { -- ast_log(LOG_ERROR, "Virtual context 'app_stack_gosub_virtual_context' does not exist and unable to create\n"); -- return AST_MODULE_LOAD_DECLINE; -- } else { -- ast_add_extension2(con, 1, "s", 1, NULL, NULL, "KeepAlive", ast_strdup(""), ast_free_ptr, "app_stack"); -- } -- -- ast_agi_register(ast_module_info->self, &gosub_agi_command); -+ ast_agi_register(ast_module_info->self, &gosub_agi_command); - } - -- ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); -- ast_register_application(app_return, return_exec, return_synopsis, return_descrip); -- ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); -- ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); -+ ast_register_application_xml(app_pop, pop_exec); -+ ast_register_application_xml(app_return, return_exec); -+ ast_register_application_xml(app_gosubif, gosubif_exec); -+ ast_register_application_xml(app_gosub, gosub_exec); - ast_custom_function_register(&local_function); -+ ast_custom_function_register(&peek_function); - - return 0; - } -Index: apps/app_chanspy.c -=================================================================== ---- a/apps/app_chanspy.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_chanspy.c (.../team/group/issue14292) (revision 178988) -@@ -46,6 +46,7 @@ - #include "asterisk/say.h" - #include "asterisk/pbx.h" - #include "asterisk/translate.h" -+#include "asterisk/manager.h" - #include "asterisk/module.h" - #include "asterisk/lock.h" - #include "asterisk/options.h" -@@ -53,128 +54,244 @@ - #define AST_NAME_STRLEN 256 - #define NUM_SPYGROUPS 128 - --static const char *tdesc = "Listen to a channel, and optionally whisper into it"; -+/*** DOCUMENTATION -+ -+ -+ Listen to a channel, and optionally whisper into it. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is used to listen to the audio from an Asterisk channel. This includes the audio -+ coming in and "out of the channel being spied on. If the chanprefix parameter is specified, -+ only channels beginning with this string will be spied upon. -+ While spying, the following actions may be performed: -+ - Dialing # cycles the volume level. -+ - Dialing * will stop spying and look for another channel to spy on. -+ - Dialing a series of digits followed by # builds a channel name to append -+ to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing the digits '1234#' -+ while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden if the 'd' option -+ is used -+ The X option supersedes the three features above in that if a valid -+ single digit extension exists in the correct context ChanSpy will exit to it. -+ This also disables choosing a channel based on chanprefix and a digit sequence. -+ -+ -+ ExtenSpy -+ -+ -+ -+ -+ Listen to a channel, and optionally whisper into it. -+ -+ -+ -+ -+ Specify extension. -+ -+ -+ Optionally specify a context, defaults to default. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is used to listen to the audio from an Asterisk channel. This includes -+ the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the -+ specified extension will be selected for spying. If the optional context is not supplied, -+ the current channel's context will be used. -+ While spying, the following actions may be performed: -+ - Dialing # cycles the volume level. -+ - Dialing * will stop spying and look for another channel to spy on. -+ The X option supersedes the three features above in that if a valid -+ single digit extension exists in the correct context ChanSpy will exit to it. -+ This also disables choosing a channel based on chanprefix and a digit sequence. -+ -+ -+ ChanSpy -+ -+ -+ -+ ***/ - static const char *app_chan = "ChanSpy"; --static const char *desc_chan = --" ChanSpy([chanprefix][,options]): This application is used to listen to the\n" --"audio from an Asterisk channel. This includes the audio coming in and\n" --"out of the channel being spied on. If the 'chanprefix' parameter is specified,\n" --"only channels beginning with this string will be spied upon.\n" --" While spying, the following actions may be performed:\n" --" - Dialing # cycles the volume level.\n" --" - Dialing * will stop spying and look for another channel to spy on.\n" --" - Dialing a series of digits followed by # builds a channel name to append\n" --" to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n" --" the digits '1234#' while spying will begin spying on the channel\n" --" 'Agent/1234'. Note that this feature will be overriden if the 'd' option\n" --" is used\n" --" Note: The X option supersedes the three features above in that if a valid\n" --" single digit extension exists in the correct context ChanSpy will\n" --" exit to it. This also disables choosing a channel based on 'chanprefix'\n" --" and a digit sequence.\n" --" Options:\n" --" b - Only spy on channels involved in a bridged call.\n" --" B - Instead of whispering on a single channel barge in on both\n" --" channels involved in the call.\n" --" d - Override the typical numeric DTMF functionality and instead\n" --" use DTMF to switch between spy modes.\n" --" 4 = spy mode\n" --" 5 = whisper mode\n" --" 6 = barge mode\n" --" g(grp) - Only spy on channels in which one or more of the groups \n" --" listed in 'grp' matches one or more groups from the\n" --" SPYGROUP variable set on the channel to be spied upon.\n" --" Note that both 'grp' and SPYGROUP can contain either a\n" --" single group or a colon-delimited list of groups, such\n" --" as 'sales:support:accounting'.\n" --" n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n" --" his/her name. If a context is specified, then that voicemail context will\n" --" be searched when retrieving the name, otherwise the \"default\" context\n" --" will be searched. If no mailbox is specified, then the channel name will\n" --" be used when searching for the name (i.e. if SIP/1000 is the channel being\n" --" spied on and no mailbox is specified, then \"1000\" will be used when searching\n" --" for the name).\n" --" q - Don't play a beep when beginning to spy on a channel, or speak the\n" --" selected channel name.\n" --" r[(basename)] - Record the session to the monitor spool directory. An\n" --" optional base for the filename may be specified. The\n" --" default is 'chanspy'.\n" --" s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n" --" speaking the selected channel name.\n" --" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n" --" negative value refers to a quieter setting.\n" --" w - Enable 'whisper' mode, so the spying channel can talk to\n" --" the spied-on channel.\n" --" W - Enable 'private whisper' mode, so the spying channel can\n" --" talk to the spied-on channel but cannot listen to that\n" --" channel.\n" --" o - Only listen to audio coming from this channel.\n" --" X - Allow the user to exit ChanSpy to a valid single digit\n" --" numeric extension in the current context or the context\n" --" specified by the SPY_EXIT_CONTEXT channel variable. The\n" --" name of the last channel that was spied on will be stored\n" --" in the SPY_CHANNEL variable.\n" --" e(ext) - Enable 'enforced' mode, so the spying channel can\n" --" only monitor extensions whose name is in the 'ext' : \n" --" delimited list.\n" --; - - static const char *app_ext = "ExtenSpy"; --static const char *desc_ext = --" ExtenSpy(exten[@context][,options]): This application is used to listen to the\n" --"audio from an Asterisk channel. This includes the audio coming in and\n" --"out of the channel being spied on. Only channels created by outgoing calls for the\n" --"specified extension will be selected for spying. If the optional context is not\n" --"supplied, the current channel's context will be used.\n" --" While spying, the following actions may be performed:\n" --" - Dialing # cycles the volume level.\n" --" - Dialing * will stop spying and look for another channel to spy on.\n" --" Note: The X option superseeds the two features above in that if a valid\n" --" single digit extension exists in the correct context it ChanSpy will\n" --" exit to it.\n" --" Options:\n" --" b - Only spy on channels involved in a bridged call.\n" --" B - Instead of whispering on a single channel barge in on both\n" --" channels involved in the call.\n" --" d - Override the typical numeric DTMF functionality and instead\n" --" use DTMF to switch between spy modes.\n" --" 4 = spy mode\n" --" 5 = whisper mode\n" --" 6 = barge mode\n" --" g(grp) - Only spy on channels in which one or more of the groups \n" --" listed in 'grp' matches one or more groups from the\n" --" SPYGROUP variable set on the channel to be spied upon.\n" --" Note that both 'grp' and SPYGROUP can contain either a\n" --" single group or a colon-delimited list of groups, such\n" --" as 'sales:support:accounting'.\n" --" n([mailbox][@context]) - Say the name of the person being spied on if that person has recorded\n" --" his/her name. If a context is specified, then that voicemail context will\n" --" be searched when retrieving the name, otherwise the \"default\" context\n" --" will be searched. If no mailbox is specified, then the channel name will\n" --" be used when searching for the name (i.e. if SIP/1000 is the channel being\n" --" spied on and no mailbox is specified, then \"1000\" will be used when searching\n" --" for the name).\n" --" q - Don't play a beep when beginning to spy on a channel, or speak the\n" --" selected channel name.\n" --" r[(basename)] - Record the session to the monitor spool directory. An\n" --" optional base for the filename may be specified. The\n" --" default is 'chanspy'.\n" --" s - Skip the playback of the channel type (i.e. SIP, IAX, etc) when\n" --" speaking the selected channel name.\n" --" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n" --" negative value refers to a quieter setting.\n" --" w - Enable 'whisper' mode, so the spying channel can talk to\n" --" the spied-on channel.\n" --" W - Enable 'private whisper' mode, so the spying channel can\n" --" talk to the spied-on channel but cannot listen to that\n" --" channel.\n" --" o - Only listen to audio coming from this channel.\n" --" X - Allow the user to exit ChanSpy to a valid single digit\n" --" numeric extension in the current context or the context\n" --" specified by the SPY_EXIT_CONTEXT channel variable. The\n" --" name of the last channel that was spied on will be stored\n" --" in the SPY_CHANNEL variable.\n" --; - - enum { - OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ -@@ -340,8 +457,9 @@ - } - ast_mutex_unlock(&spyee_chanspy_ds->lock); - -- if (!spyee) -+ if (!spyee) { - return 0; -+ } - - /* We now hold the channel lock on spyee */ - -@@ -351,7 +469,12 @@ - } - - name = ast_strdupa(spyee->name); -+ - ast_verb(2, "Spying on channel %s\n", name); -+ manager_event(EVENT_FLAG_CALL, "ChanSpyStart", -+ "SpyerChannel: %s\r\n" -+ "SpyeeChannel: %s\r\n", -+ spyer_name, name); - - memset(&csth, 0, sizeof(csth)); - -@@ -495,26 +618,23 @@ - ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); - ast_channel_unlock(chan); - -- if (ast_test_flag(flags, OPTION_WHISPER)) { -- ast_audiohook_lock(&csth.whisper_audiohook); -- ast_audiohook_detach(&csth.whisper_audiohook); -- ast_audiohook_unlock(&csth.whisper_audiohook); -- ast_audiohook_destroy(&csth.whisper_audiohook); -- } -+ ast_audiohook_lock(&csth.whisper_audiohook); -+ ast_audiohook_detach(&csth.whisper_audiohook); -+ ast_audiohook_unlock(&csth.whisper_audiohook); -+ ast_audiohook_destroy(&csth.whisper_audiohook); -+ -+ ast_audiohook_lock(&csth.bridge_whisper_audiohook); -+ ast_audiohook_detach(&csth.bridge_whisper_audiohook); -+ ast_audiohook_unlock(&csth.bridge_whisper_audiohook); -+ ast_audiohook_destroy(&csth.bridge_whisper_audiohook); - -- if (ast_test_flag(flags, OPTION_BARGE)) { -- ast_audiohook_lock(&csth.bridge_whisper_audiohook); -- ast_audiohook_detach(&csth.bridge_whisper_audiohook); -- ast_audiohook_unlock(&csth.bridge_whisper_audiohook); -- ast_audiohook_destroy(&csth.bridge_whisper_audiohook); -- } -- - ast_audiohook_lock(&csth.spy_audiohook); - ast_audiohook_detach(&csth.spy_audiohook); - ast_audiohook_unlock(&csth.spy_audiohook); - ast_audiohook_destroy(&csth.spy_audiohook); - - ast_verb(2, "Done Spying on channel %s\n", name); -+ manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name); - - return running; - } -@@ -717,22 +837,9 @@ - chanspy_ds_free(peer_chanspy_ds), prev = peer, - peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : - next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { -- const char *group; - int igrp = !mygroup; -- char *groups[NUM_SPYGROUPS]; -- char *mygroups[NUM_SPYGROUPS]; -- int num_groups = 0; -- char dup_group[512]; -- int num_mygroups = 0; -- char *dup_mygroup; -- int x; -- int y; -+ int ienf = !myenforced; - char *s; -- char *buffer; -- char *end; -- char *ext; -- char *form_enforced; -- int ienf = !myenforced; - - peer = peer_chanspy_ds->chan; - -@@ -761,7 +868,16 @@ - } - - if (mygroup) { -- dup_mygroup = ast_strdupa(mygroup); -+ int num_groups = 0; -+ int num_mygroups = 0; -+ char dup_group[512]; -+ char dup_mygroup[512]; -+ char *groups[NUM_SPYGROUPS]; -+ char *mygroups[NUM_SPYGROUPS]; -+ const char *group; -+ int x; -+ int y; -+ ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); - num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, - ARRAY_LEN(mygroups)); - -@@ -787,35 +903,28 @@ - } - - if (myenforced) { -+ char ext[AST_CHANNEL_NAME + 3]; -+ char buffer[512]; -+ char *end; - -- /* We don't need to allocate more space than just the -- length of (peer->name) for ext as we will cut the -- channel name's ending before copying into ext */ -+ snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); - -- ext = alloca(strlen(peer->name)); -- -- form_enforced = alloca(strlen(myenforced) + 3); -- -- strcpy(form_enforced, ":"); -- strcat(form_enforced, myenforced); -- strcat(form_enforced, ":"); -- -- buffer = ast_strdupa(peer->name); -- -- if ((end = strchr(buffer, '-'))) { -+ ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1); -+ if ((end = strchr(ext, '-'))) { - *end++ = ':'; - *end = '\0'; - } - -- strcpy(ext, ":"); -- strcat(ext, buffer); -+ ext[0] = ':'; - -- if (strcasestr(form_enforced, ext)) -+ if (strcasestr(buffer, ext)) { - ienf = 1; -+ } - } - -- if (!ienf) -+ if (!ienf) { - continue; -+ } - - strcpy(peer_name, "spy-"); - strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); -@@ -1112,8 +1221,8 @@ - { - int res = 0; - -- res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); -- res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); -+ res |= ast_register_application_xml(app_chan, chanspy_exec); -+ res |= ast_register_application_xml(app_ext, extenspy_exec); - - return res; - } -Index: apps/app_jack.c -=================================================================== ---- a/apps/app_jack.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_jack.c (.../team/group/issue14292) (revision 178988) -@@ -73,18 +73,46 @@ - " running.\n" \ - " c() - By default, Asterisk will use the channel name for the jack client\n" \ - " name. Use this option to specify a custom client name.\n" -- -+/*** DOCUMENTATION -+ -+ -+ Jack Audio Connection Kit -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ When executing this application, two jack ports will be created; -+ one input and one output. Other applications can be hooked up to -+ these ports to access audio coming from, or being send to the channel. -+ -+ -+ ***/ - static char *jack_app = "JACK"; --static char *jack_synopsis = --"JACK (Jack Audio Connection Kit) Application"; --static char *jack_desc = --"JACK([options])\n" --" When this application is executed, two jack ports will be created; one input\n" --"and one output. Other applications can be hooked up to these ports to access\n" --"the audio coming from, or being sent to the channel.\n" --" Valid options:\n" --COMMON_OPTIONS --""; - - struct jack_data { - AST_DECLARE_STRING_FIELDS( -@@ -154,7 +182,7 @@ - ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i))); - } - -- ast_log(LOG_NOTICE, "%s: %s\n", prefix, str->str); -+ ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str)); - } - - static int alloc_resampler(struct jack_data *jack_data, int input) -@@ -982,7 +1010,7 @@ - - static int load_module(void) - { -- if (ast_register_application(jack_app, jack_exec, jack_synopsis, jack_desc)) { -+ if (ast_register_application_xml(jack_app, jack_exec)) { - return AST_MODULE_LOAD_DECLINE; - } - -Index: apps/app_cdr.c -=================================================================== ---- a/apps/app_cdr.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_cdr.c (.../team/group/issue14292) (revision 178988) -@@ -32,14 +32,20 @@ - #include "asterisk/channel.h" - #include "asterisk/module.h" - --static char *nocdr_descrip = --" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n" --"current call.\n"; -+/*** DOCUMENTATION -+ -+ -+ Tell Asterisk to not maintain a CDR for the current call -+ -+ -+ -+ This application will tell Asterisk not to maintain a CDR for the current call. -+ -+ -+ ***/ - - static char *nocdr_app = "NoCDR"; --static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call"; - -- - static int nocdr_exec(struct ast_channel *chan, void *data) - { - if (chan->cdr) -@@ -55,7 +61,7 @@ - - static int load_module(void) - { -- if (ast_register_application(nocdr_app, nocdr_exec, nocdr_synopsis, nocdr_descrip)) -+ if (ast_register_application_xml(nocdr_app, nocdr_exec)) - return AST_MODULE_LOAD_FAILURE; - return AST_MODULE_LOAD_SUCCESS; - } -Index: apps/app_adsiprog.c -=================================================================== ---- a/apps/app_adsiprog.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_adsiprog.c (.../team/group/issue14292) (revision 178988) -@@ -47,14 +47,28 @@ - - static char *app = "ADSIProg"; - --static char *synopsis = "Load Asterisk ADSI Scripts into phone"; -+/*** DOCUMENTATION -+ -+ -+ Load Asterisk ADSI Scripts into phone -+ -+ -+ -+ adsi script to use. If not given uses the default script asterisk.adsi -+ -+ -+ -+ This application programs an ADSI Phone with the given script -+ -+ -+ GetCPEID -+ adsi.conf -+ -+ -+ ***/ - - /* #define DUMP_MESSAGES */ - --static char *descrip = --" ADSIProg(script): This application programs an ADSI Phone with the given\n" --"script. If nothing is specified, the default script (asterisk.adsi) is used.\n"; -- - struct adsi_event { - int id; - char *name; -@@ -828,7 +842,7 @@ - ast_log(LOG_WARNING, "'%s' is not a valid state name at line %d of %s\n", tok, lineno, script); - return 0; - } -- if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) < 0)) { -+ if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) == NULL)) { - ast_log(LOG_WARNING, "State '%s' not declared at line %d of %s\n", sname, lineno, script); - return 0; - } -@@ -1572,7 +1586,7 @@ - - static int load_module(void) - { -- if (ast_register_application(app, adsi_exec, synopsis, descrip)) -+ if (ast_register_application_xml(app, adsi_exec)) - return AST_MODULE_LOAD_FAILURE; - return AST_MODULE_LOAD_SUCCESS; - } -Index: apps/app_read.c -=================================================================== ---- a/apps/app_read.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_read.c (.../team/group/issue14292) (revision 178988) -@@ -36,6 +36,78 @@ - #include "asterisk/module.h" - #include "asterisk/indications.h" - -+/*** DOCUMENTATION -+ -+ -+ Read a variable. -+ -+ -+ -+ The input digits will be stored in the given variable -+ name. -+ -+ -+ -+ file(s) to play before reading digits or tone with option i -+ -+ -+ -+ -+ Maximum acceptable number of digits. Stops reading after -+ maxdigits have been entered (without -+ requiring the user to press the # key). -+ Defaults to 0 - no limit - wait for the -+ user press the # key. Any value below -+ 0 means the same. Max accepted value is -+ 255. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ If greater than 1, that many -+ attempts will be made in the -+ event no data is entered. -+ -+ -+ The number of seconds to wait for a digit response. If greater -+ than 0, that value will override the default timeout. -+ Can be floating point. -+ -+ -+ -+ Reads a #-terminated string of digits a certain number of times from the -+ user in to the given variable. -+ This application sets the following channel variable upon completion: -+ -+ -+ This is the status of the read operation. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ SendDTMF -+ -+ -+ ***/ -+ - enum { - OPT_SKIP = (1 << 0), - OPT_INDICATION = (1 << 1), -@@ -50,32 +122,6 @@ - - static char *app = "Read"; - --static char *synopsis = "Read a variable"; -- --static char *descrip = --" Read(variable[,filename[&filename2...]][,maxdigits][,option][,attempts][,timeout])\n\n" --"Reads a #-terminated string of digits a certain number of times from the\n" --"user in to the given variable.\n" --" filename -- file(s) to play before reading digits or tone with option i\n" --" maxdigits -- maximum acceptable number of digits. Stops reading after\n" --" maxdigits have been entered (without requiring the user to\n" --" press the '#' key).\n" --" Defaults to 0 - no limit - wait for the user press the '#' key.\n" --" Any value below 0 means the same. Max accepted value is 255.\n" --" option -- options are 's' , 'i', 'n'\n" --" 's' to return immediately if the line is not up,\n" --" 'i' to play filename as an indication tone from your indications.conf\n" --" 'n' to read digits even if the line is not up.\n" --" attempts -- if greater than 1, that many attempts will be made in the \n" --" event no data is entered.\n" --" timeout -- The number of seconds to wait for a digit response. If greater\n" --" than 0, that value will override the default timeout. Can be floating point.\n" --"This application sets the following channel variable upon completion:\n" --" READSTATUS - This is the status of the read operation.\n" --" Possible values are:\n" --" OK | ERROR | HANGUP | INTERRUPTED | SKIPPED | TIMEOUT\n"; -- -- - #define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;} - - static int read_exec(struct ast_channel *chan, void *data) -@@ -86,7 +132,7 @@ - int tries = 1, to = 0, x = 0; - double tosec; - char *argcopy = NULL; -- struct tone_zone_sound *ts = NULL; -+ struct ast_tone_zone_sound *ts = NULL; - struct ast_flags flags = {0}; - const char *status = "ERROR"; - -@@ -142,7 +188,7 @@ - return 0; - } - if (ast_test_flag(&flags, OPT_INDICATION)) { -- if (! ast_strlen_zero(arglist.filename)) { -+ if (!ast_strlen_zero(arglist.filename)) { - ts = ast_get_indication_tone(chan->zone, arglist.filename); - } - } -@@ -212,6 +258,10 @@ - } - } - -+ if (ts) { -+ ts = ast_tone_zone_sound_unref(ts); -+ } -+ - if (ast_check_hangup(chan)) - status = "HANGUP"; - pbx_builtin_setvar_helper(chan, "READSTATUS", status); -@@ -225,7 +275,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, read_exec, synopsis, descrip); -+ return ast_register_application_xml(app, read_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read Variable Application"); -Index: apps/app_dictate.c -=================================================================== ---- a/apps/app_dictate.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_dictate.c (.../team/group/issue14292) (revision 178988) -@@ -40,12 +40,23 @@ - #include "asterisk/say.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Virtual Dictation Machine. -+ -+ -+ -+ -+ -+ -+ Start dictation machine using optional base_dir for files. -+ -+ -+ ***/ -+ - static char *app = "Dictate"; --static char *synopsis = "Virtual Dictation Machine"; --static char *desc = " Dictate([[,]])\n" --"Start dictation machine using optional base dir for files.\n"; - -- - typedef enum { - DFLAG_RECORD = (1 << 0), - DFLAG_PLAY = (1 << 1), -@@ -116,7 +127,9 @@ - return -1; - } - -- ast_answer(chan); -+ if (chan->_state != AST_STATE_UP) { -+ ast_answer(chan); -+ } - ast_safe_sleep(chan, 200); - for (res = 0; !res;) { - if (ast_strlen_zero(filename)) { -@@ -332,7 +345,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, dictate_exec, synopsis, desc); -+ return ast_register_application_xml(app, dictate_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine"); -Index: apps/app_festival.c -=================================================================== ---- a/apps/app_festival.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_festival.c (.../team/group/issue14292) (revision 178988) -@@ -54,16 +54,25 @@ - #define MAXLEN 180 - #define MAXFESTLEN 2048 - -+/*** DOCUMENTATION -+ -+ -+ Say text to the user. -+ -+ -+ -+ -+ -+ -+ Connect to Festival, send the argument, get back the waveform, play it to the user, -+ allowing any given interrupt keys to immediately terminate and return the value, or -+ any to allow any number back (useful in dialplan). -+ -+ -+ ***/ -+ - static char *app = "Festival"; - --static char *synopsis = "Say text to the user"; -- --static char *descrip = --" Festival(text[,intkeys]): Connect to Festival, send the argument, get back the waveform,\n" --"play it to the user, allowing any given interrupt keys to immediately terminate and return\n" --"the value, or 'any' to allow any number back (useful in dialplan)\n"; -- -- - static char *socket_receive_file_to_buff(int fd, int *size) - { - /* Receive file (probably a waveform file) from socket using -@@ -305,7 +314,11 @@ - if (!cfg) { - ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG); - return -1; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " FESTIVAL_CONFIG " is in an invalid format. Aborting.\n"); -+ return -1; - } -+ - if (!(host = ast_variable_retrieve(cfg, "general", "host"))) { - host = "localhost"; - } -@@ -532,9 +545,12 @@ - if (!cfg) { - ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG); - return AST_MODULE_LOAD_DECLINE; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " FESTIVAL_CONFIG " is in an invalid format. Aborting.\n"); -+ return AST_MODULE_LOAD_DECLINE; - } - ast_config_destroy(cfg); -- return ast_register_application(app, festival_exec, synopsis, descrip); -+ return ast_register_application_xml(app, festival_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Festival Interface"); -Index: apps/app_softhangup.c -=================================================================== ---- a/apps/app_softhangup.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_softhangup.c (.../team/group/issue14292) (revision 178988) -@@ -36,13 +36,28 @@ - #include "asterisk/lock.h" - #include "asterisk/app.h" - --static char *synopsis = "Soft Hangup Application"; -+/*** DOCUMENTATION -+ -+ -+ Hangs up the requested channel. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Hangs up the requested channel. If there are no channels to -+ hangup, the application will report it. -+ -+ - --static char *desc = " SoftHangup(Technology/resource[,options]):\n" --"Hangs up the requested channel. If there are no channels to hangup,\n" --"the application will report it.\n" --" Options:\n" --" 'a' - hang up all channels on a specified device instead of a single resource\n"; -+ ***/ - - static char *app = "SoftHangup"; - -@@ -114,7 +129,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, softhangup_exec, synopsis, desc); -+ return ast_register_application_xml(app, softhangup_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hangs up the requested channel"); -Index: apps/app_playtones.c -=================================================================== ---- a/apps/app_playtones.c (.../tags/1.6.1-rc1) (revision 0) -+++ b/apps/app_playtones.c (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,129 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2009, Digium, Inc. -+ * -+ * Russell Bryant -+ * -+ * 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 Playtones application -+ * -+ * \author Russell Bryant -+ * -+ * \ingroup applications -+ */ -+ -+#include "asterisk.h" -+ -+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -+ -+#include "asterisk/module.h" -+#include "asterisk/pbx.h" -+#include "asterisk/channel.h" -+#include "asterisk/indications.h" -+ -+static const char playtones_app[] = "PlayTones"; -+static const char stopplaytones_app[] = "StopPlayTones"; -+ -+/*** DOCUMENTATION -+ -+ -+ Play a tone list. -+ -+ -+ -+ Arg is either the tone name defined in the indications.conf -+ configuration file, or a directly specified list of frequencies and durations. -+ -+ -+ -+ Plays a tone list. Execution will continue with the next step in the dialplan -+ immediately while the tones continue to play. -+ See the sample indications.conf for a description of the -+ specification of a tonelist. -+ -+ -+ StopPlayTones -+ -+ -+ -+ -+ Stop playing a tone list. -+ -+ -+ -+ Stop playing a tone list, initiated by PlayTones(). -+ -+ -+ PlayTones -+ -+ -+ ***/ -+ -+static int handle_playtones(struct ast_channel *chan, void *data) -+{ -+ struct ast_tone_zone_sound *ts; -+ int res; -+ const char *str = data; -+ -+ if (ast_strlen_zero(str)) { -+ ast_log(LOG_NOTICE,"Nothing to play\n"); -+ return -1; -+ } -+ -+ ts = ast_get_indication_tone(chan->zone, str); -+ -+ if (ts) { -+ res = ast_playtones_start(chan, 0, ts->data, 0); -+ ts = ast_tone_zone_sound_unref(ts); -+ } else { -+ res = ast_playtones_start(chan, 0, str, 0); -+ } -+ -+ if (res) { -+ ast_log(LOG_NOTICE, "Unable to start playtones\n"); -+ } -+ -+ return res; -+} -+ -+static int handle_stopplaytones(struct ast_channel *chan, void *data) -+{ -+ ast_playtones_stop(chan); -+ -+ return 0; -+} -+ -+static int unload_module(void) -+{ -+ int res; -+ -+ res = ast_unregister_application(playtones_app); -+ res |= ast_unregister_application(stopplaytones_app); -+ -+ return res; -+} -+ -+static int load_module(void) -+{ -+ int res; -+ -+ res = ast_register_application_xml(playtones_app, handle_playtones); -+ res |= ast_register_application_xml(stopplaytones_app, handle_stopplaytones); -+ -+ return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; -+} -+ -+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playtones Application"); - -Property changes on: apps/app_playtones.c -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: apps/app_dahdiscan.c -=================================================================== ---- a/apps/app_dahdiscan.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_dahdiscan.c (.../team/group/issue14292) (revision 178988) -@@ -52,16 +52,24 @@ - #include "asterisk/say.h" - #include "asterisk/options.h" - -+/*** DOCUMENTATION -+ -+ -+ Scan DAHDI channels to monitor calls. -+ -+ -+ -+ Limit scanning to a channel group by setting this option. -+ -+ -+ -+ Allows a call center manager to monitor DAHDI channels in a -+ convenient way. Use # to select the next channel and use * to exit. -+ -+ -+ ***/ - static char *app = "DAHDIScan"; - --static char *synopsis = "Scan DAHDI channels to monitor calls"; -- --static char *descrip = --" DAHDIScan([group]) allows a call center manager to monitor DAHDI channels in\n" --"a convenient way. Use '#' to select the next channel and use '*' to exit\n" --"Limit scanning to a channel GROUP by setting the option group argument.\n"; -- -- - #define CONF_SIZE 160 - - static struct ast_channel *get_dahdi_channel_locked(int num) { -@@ -363,7 +371,7 @@ - - static int load_module(void) - { -- return ((ast_register_application(app, conf_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); -+ return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan DAHDI channels application"); -Index: apps/app_alarmreceiver.c -=================================================================== ---- a/apps/app_alarmreceiver.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_alarmreceiver.c (.../team/group/issue14292) (revision 178988) -@@ -63,19 +63,28 @@ - typedef struct event_node event_node_t; - - static char *app = "AlarmReceiver"; -+/*** DOCUMENTATION -+ -+ -+ Provide support for receiving alarm reports from a burglar or fire alarm panel. -+ -+ -+ -+ This application should be called whenever there is an alarm panel calling in to dump its events. -+ The application will handshake with the alarm panel, and receive events, validate them, handshake them, -+ and store them until the panel hangs up. Once the panel hangs up, the application will run the system -+ command specified by the eventcmd setting in alarmreceiver.conf and pipe the -+ events to the standard input of the application. -+ The configuration file also contains settings for DTMF timing, and for the loudness of the -+ acknowledgement tones. -+ Only 1 signalling format is supported at this time: Ademco Contact ID. -+ -+ -+ alarmreceiver.conf -+ -+ -+ ***/ - --static char *synopsis = "Provide support for receiving alarm reports from a burglar or fire alarm panel"; --static char *descrip = --" AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n" --"Contact ID. This application should be called whenever there is an alarm\n" --"panel calling in to dump its events. The application will handshake with the\n" --"alarm panel, and receive events, validate them, handshake them, and store them\n" --"until the panel hangs up. Once the panel hangs up, the application will run the\n" --"system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n" --"the events to the standard input of the application. The configuration file also\n" --"contains settings for DTMF timing, and for the loudness of the acknowledgement\n" --"tones.\n"; -- - /* Config Variables */ - static int fdtimeout = 2000; - static int sdtimeout = 200; -@@ -639,6 +648,9 @@ - if (!cfg) { - ast_verb(4, "AlarmReceiver: No config file\n"); - return 0; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", ALMRCV_CONFIG); -+ return 0; - } else { - p = ast_variable_retrieve(cfg, "general", "eventcmd"); - if (p) { -@@ -708,7 +720,7 @@ - static int load_module(void) - { - if (load_config()) { -- if (ast_register_application(app, alarmreceiver_exec, synopsis, descrip)) -+ if (ast_register_application_xml(app, alarmreceiver_exec)) - return AST_MODULE_LOAD_FAILURE; - return AST_MODULE_LOAD_SUCCESS; - } else -Index: apps/app_image.c -=================================================================== ---- a/apps/app_image.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_image.c (.../team/group/issue14292) (revision 178988) -@@ -35,17 +35,40 @@ - - static char *app = "SendImage"; - --static char *synopsis = "Send an image file"; -+/*** DOCUMENTATION -+ -+ -+ Sends an image file. -+ -+ -+ -+ Path of the filename (image) to send. -+ -+ -+ -+ Send an image file on a channel supporting it. -+ Result of transmission will be stored in SENDIMAGESTATUS -+ -+ -+ -+ Transmission succeeded. -+ -+ -+ Transmission failed. -+ -+ -+ Image transmission not supported by channel. -+ -+ -+ -+ -+ -+ SendText -+ SendURL -+ -+ -+ ***/ - --static char *descrip = --" SendImage(filename): Sends an image on a channel.\n" --"Result of transmission will be stored in SENDIMAGESTATUS\n" --"channel variable:\n" --" SUCCESS Transmission succeeded\n" --" FAILURE Transmission failed\n" --" UNSUPPORTED Image transmission not supported by channel\n"; -- -- - static int sendimage_exec(struct ast_channel *chan, void *data) - { - -@@ -76,7 +99,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, sendimage_exec, synopsis, descrip); -+ return ast_register_application_xml(app, sendimage_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Image Transmission Application"); -Index: apps/app_getcpeid.c -=================================================================== ---- a/apps/app_getcpeid.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_getcpeid.c (.../team/group/issue14292) (revision 178988) -@@ -36,15 +36,20 @@ - #include "asterisk/module.h" - #include "asterisk/adsi.h" - -+/*** DOCUMENTATION -+ -+ -+ Get ADSI CPE ID. -+ -+ -+ -+ Obtains and displays ADSI CPE ID and other information in order -+ to properly setup dahdi.conf for on-hook operations. -+ -+ -+ ***/ - static char *app = "GetCPEID"; - --static char *synopsis = "Get ADSI CPE ID"; -- --static char *descrip = --" GetCPEID(): Obtains and displays ADSI CPE ID and other information in order\n" --"to properly setup dahdi.conf for on-hook operations.\n"; -- -- - static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice) - { - int justify[5] = { ADSI_JUST_CENT, ADSI_JUST_LEFT, ADSI_JUST_LEFT, ADSI_JUST_LEFT }; -@@ -124,7 +129,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, cpeid_exec, synopsis, descrip); -+ return ast_register_application_xml(app, cpeid_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get ADSI CPE ID"); -Index: apps/app_talkdetect.c -=================================================================== ---- a/apps/app_talkdetect.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_talkdetect.c (.../team/group/issue14292) (revision 178988) -@@ -39,22 +39,40 @@ - #include "asterisk/dsp.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Background a file with talk detect. -+ -+ -+ -+ -+ If not specified, defaults to 1000. -+ -+ -+ If not specified, defaults to 100. -+ -+ -+ If not specified, defaults to infinity. -+ -+ -+ If not specified, defaults to infinity. -+ -+ -+ -+ Plays back filename, waiting for interruption from a given digit (the digit -+ must start the beginning of a valid extension, or it will be ignored). During -+ the playback of the file, audio is monitored in the receive direction, and if -+ a period of non-silence which is greater than min ms yet less than -+ max ms is followed by silence for at least sil ms, -+ which occurs during the first analysistime ms, then the audio playback is -+ aborted and processing jumps to the talk extension, if available. -+ -+ -+ ***/ -+ - static char *app = "BackgroundDetect"; - --static char *synopsis = "Background a file with talk detect"; -- --static char *descrip = --" BackgroundDetect([,[,[,[,]]]]):\n" --"Plays back , waiting for interruption from a given digit (the digit\n" --"must start the beginning of a valid extension, or it will be ignored). During\n" --"the playback of the file, audio is monitored in the receive direction, and if\n" --"a period of non-silence which is greater than ms yet less than ms\n" --"is followed by silence for at least ms, which occurs during the first\n" --" ms, then the audio playback is aborted and processing jumps to\n" --"the extension, if available. If unspecified, , , , and\n" --" default to 1000, 100, infinity, and infinity respectively.\n"; -- -- - static int background_detect_exec(struct ast_channel *chan, void *data) - { - int res = 0; -@@ -227,7 +245,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, background_detect_exec, synopsis, descrip); -+ return ast_register_application_xml(app, background_detect_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection"); -Index: apps/app_db.c -=================================================================== ---- a/apps/app_db.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_db.c (.../team/group/issue14292) (revision 178988) -@@ -39,23 +39,50 @@ - #include "asterisk/astdb.h" - #include "asterisk/lock.h" - -+/*** DOCUMENTATION -+ -+ -+ Delete a key from the asterisk database. -+ -+ -+ -+ -+ -+ -+ This application will delete a key from the Asterisk -+ database. -+ This application has been DEPRECATED in favor of the DB_DELETE function. -+ -+ -+ DB_DELETE -+ DBdeltree -+ DB -+ -+ -+ -+ -+ Delete a family or keytree from the asterisk database. -+ -+ -+ -+ -+ -+ -+ This application will delete a family or keytree -+ from the Asterisk database. -+ -+ -+ DB_DELETE -+ DBdel -+ DB -+ -+ -+ ***/ -+ - /*! \todo XXX Remove this application after 1.4 is relased */ --static char *d_descrip = --" DBdel(family/key): This application will delete a key from the Asterisk\n" --"database.\n" --" This application has been DEPRECATED in favor of the DB_DELETE function.\n"; -- --static char *dt_descrip = --" DBdeltree(family[/keytree]): This application will delete a family or keytree\n" --"from the Asterisk database\n"; -- - static char *d_app = "DBdel"; - static char *dt_app = "DBdeltree"; - --static char *d_synopsis = "Delete a key from the database"; --static char *dt_synopsis = "Delete a family or keytree from the database"; -- -- - static int deltree_exec(struct ast_channel *chan, void *data) - { - char *argv, *family, *keytree; -@@ -130,8 +157,8 @@ - { - int retval; - -- retval = ast_register_application(d_app, del_exec, d_synopsis, d_descrip); -- retval |= ast_register_application(dt_app, deltree_exec, dt_synopsis, dt_descrip); -+ retval = ast_register_application_xml(d_app, del_exec); -+ retval |= ast_register_application_xml(dt_app, deltree_exec); - - return retval; - } -Index: apps/app_controlplayback.c -=================================================================== ---- a/apps/app_controlplayback.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_controlplayback.c (.../team/group/issue14292) (revision 178988) -@@ -33,32 +33,67 @@ - #include "asterisk/app.h" - #include "asterisk/module.h" - -+/*** DOCUMENTATION -+ -+ -+ Play a file with fast forward and rewind. -+ -+ -+ -+ -+ This is number of milliseconds to skip when rewinding or -+ fast-forwarding. -+ -+ -+ Fast-forward when this DTMF digit is received. (defaults to #) -+ -+ -+ Rewind when this DTMF digit is received. (defaults to *) -+ -+ -+ Stop playback when this DTMF digit is received. -+ -+ -+ Pause playback when this DTMF digit is received. -+ -+ -+ Restart playback when this DTMF digit is received. -+ -+ -+ -+ -+ -+ -+ -+ -+ This application will play back the given filename. -+ It sets the following channel variables upon completion: -+ -+ -+ Contains the status of the attempt as a text string -+ -+ -+ -+ -+ -+ Contains the offset in ms into the file where playback -+ was at when it stopped. -1 is end of file. -+ -+ -+ If the playback is stopped by the user this variable contains -+ the key that was pressed. -+ -+ -+ -+ -+ ***/ - static const char *app = "ControlPlayback"; - --static const char *synopsis = "Play a file with fast forward and rewind"; -- --static const char *descrip = --" ControlPlayback(file[,skipms[,ff[,rew[,stop[,pause[,restart,options]]]]]]]):\n" --"This application will play back the given filename. By default, the '*' key\n" --"can be used to rewind, and the '#' key can be used to fast-forward.\n" --"Parameters:\n" --" skipms - This is number of milliseconds to skip when rewinding or\n" --" fast-forwarding.\n" --" ff - Fast-forward when this DTMF digit is received.\n" --" rew - Rewind when this DTMF digit is received.\n" --" stop - Stop playback when this DTMF digit is received.\n" --" pause - Pause playback when this DTMF digit is received.\n" --" restart - Restart playback when this DTMF digit is received.\n" --"Options:\n" --" o(#) - Start at # ms from the beginning of the file.\n" --"This application sets the following channel variables upon completion:\n" --" CPLAYBACKSTATUS - This variable contains the status of the attempt as a text\n" --" string, one of: SUCCESS | USERSTOPPED | ERROR\n" --" CPLAYBACKOFFSET - This contains the offset in ms into the file where\n" --" playback was at when it stopped. -1 is end of file.\n" --" CPLAYBACKSTOPKEY - If the playback is stopped by the user this variable contains\n" --" the key that was pressed.\n"; -- - enum { - OPT_OFFSET = (1 << 1), - }; -@@ -185,7 +220,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, controlplayback_exec, synopsis, descrip); -+ return ast_register_application_xml(app, controlplayback_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application"); -Index: apps/app_setcallerid.c -=================================================================== ---- a/apps/app_setcallerid.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_setcallerid.c (.../team/group/issue14292) (revision 178988) -@@ -38,27 +38,52 @@ - #include "asterisk/image.h" - #include "asterisk/callerid.h" - -+/*** DOCUMENTATION -+ -+ -+ Set CallerID Presentation. -+ -+ -+ -+ -+ -+ Presentation Allowed, Not Screened. -+ -+ -+ Presentation Allowed, Passed Screen. -+ -+ -+ Presentation Allowed, Failed Screen. -+ -+ -+ Presentation Allowed, Network Number. -+ -+ -+ Presentation Prohibited, Not Screened. -+ -+ -+ Presentation Prohibited, Passed Screen. -+ -+ -+ Presentation Prohibited, Failed Screen. -+ -+ -+ Presentation Prohibited, Network Number. -+ -+ -+ Number Unavailable. -+ -+ -+ -+ -+ -+ Set Caller*ID presentation on a call. -+ -+ -+ ***/ -+ - static char *app2 = "SetCallerPres"; - --static char *synopsis2 = "Set CallerID Presentation"; -- -- --static char *descrip2 = --" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n" --" Valid presentations are:\n" --"\n" --" allowed_not_screened : Presentation Allowed, Not Screened\n" --" allowed_passed_screen : Presentation Allowed, Passed Screen\n" --" allowed_failed_screen : Presentation Allowed, Failed Screen\n" --" allowed : Presentation Allowed, Network Number\n" --" prohib_not_screened : Presentation Prohibited, Not Screened\n" --" prohib_passed_screen : Presentation Prohibited, Passed Screen\n" --" prohib_failed_screen : Presentation Prohibited, Failed Screen\n" --" prohib : Presentation Prohibited, Network Number\n" --" unavailable : Number Unavailable\n" --"\n" --; -- - static int setcallerid_pres_exec(struct ast_channel *chan, void *data) - { - int pres = -1; -@@ -91,7 +116,7 @@ - - static int load_module(void) - { -- return ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2); -+ return ast_register_application_xml(app2, setcallerid_pres_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Presentation Application"); -Index: apps/app_mp3.c -=================================================================== ---- a/apps/app_mp3.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_mp3.c (.../team/group/issue14292) (revision 178988) -@@ -44,16 +44,26 @@ - #define LOCAL_MPG_123 "/usr/local/bin/mpg123" - #define MPG_123 "/usr/bin/mpg123" - -+/*** DOCUMENTATION -+ -+ -+ Play an MP3 file or stream. -+ -+ -+ -+ Location of the file to be played. -+ (argument passed to mpg123) -+ -+ -+ -+ Executes mpg123 to play the given location, which typically would be a filename or a URL. -+ User can exit by pressing any key on the dialpad, or by hanging up. -+ -+ -+ -+ ***/ - static char *app = "MP3Player"; - --static char *synopsis = "Play an MP3 file or stream"; -- --static char *descrip = --" MP3Player(location): Executes mpg123 to play the given location,\n" --"which typically would be a filename or a URL. User can exit by pressing\n" --"any key on the dialpad, or by hanging up."; -- -- - static int mp3play(char *filename, int fd) - { - int res; -@@ -221,7 +231,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, mp3_exec, synopsis, descrip); -+ return ast_register_application_xml(app, mp3_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application"); -Index: apps/app_zapateller.c -=================================================================== ---- a/apps/app_zapateller.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_zapateller.c (.../team/group/issue14292) (revision 178988) -@@ -37,24 +37,43 @@ - #include "asterisk/translate.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Block telemarketers with SIT. -+ -+ -+ -+ Comma delimited list of options. -+ -+ -+ -+ -+ -+ -+ -+ Generates special information tone to block telemarketers from calling you. -+ This application will set the following channel variable upon completion: -+ -+ -+ This will contain the last action accomplished by the -+ Zapateller application. Possible values include: -+ -+ -+ -+ -+ -+ -+ -+ ***/ -+ - static char *app = "Zapateller"; - --static char *synopsis = "Block telemarketers with SIT"; -- --static char *descrip = --" Zapateller(options): Generates special information tone to block\n" --"telemarketers from calling you. Options is a pipe-delimited list of\n" --"options. The following options are available:\n" --" 'answer' - causes the line to be answered before playing the tone,\n" --" 'nocallerid' - causes Zapateller to only play the tone if there is no\n" --" callerid information available. Options should be\n" --" separated by , characters\n\n" --" This application will set the following channel variable upon completion:\n" --" ZAPATELLERSTATUS - This will contain the last action accomplished by the\n" --" Zapateller application. Possible values include:\n" --" NOTHING | ANSWERED | ZAPPED\n\n"; -- -- - static int zapateller_exec(struct ast_channel *chan, void *data) - { - int res = 0; -@@ -107,7 +126,7 @@ - - static int load_module(void) - { -- return ((ast_register_application(app, zapateller_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); -+ return ((ast_register_application_xml(app, zapateller_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Block Telemarketers with Special Information Tone"); -Index: apps/app_senddtmf.c -=================================================================== ---- a/apps/app_senddtmf.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_senddtmf.c (.../team/group/issue14292) (revision 178988) -@@ -35,19 +35,33 @@ - #include "asterisk/manager.h" - #include "asterisk/channel.h" - -+/*** DOCUMENTATION -+ -+ -+ Sends arbitrary DTMF digits -+ -+ -+ -+ List of digits 0-9,*#,abcd -+ -+ -+ Amount of time to wait in ms between tones. (defaults to .25s) -+ -+ -+ Duration of each digit -+ -+ -+ -+ DTMF digits sent to a channel with half second pause -+ It will pass all digits or terminate if it encounters an error. -+ -+ -+ Read -+ -+ -+ ***/ - static char *app = "SendDTMF"; - --static char *synopsis = "Sends arbitrary DTMF digits"; -- --static char *descrip = --" SendDTMF(digits[,[timeout_ms][,duration_ms]]): Sends DTMF digits on a channel. \n" --" Accepted digits: 0-9, *#abcd, (default .25s pause between digits)\n" --" The application will either pass the assigned digits or terminate if it\n" --" encounters an error.\n" --" Optional Params: \n" --" timeout_ms: pause between digits.\n" --" duration_ms: duration of each digit.\n"; -- - static int senddtmf_exec(struct ast_channel *chan, void *vdata) - { - int res = 0; -@@ -121,7 +135,7 @@ - int res; - - res = ast_manager_register2( "PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf, "Play DTMF signal on a specific channel.", mandescr_playdtmf ); -- res |= ast_register_application(app, senddtmf_exec, synopsis, descrip); -+ res |= ast_register_application_xml(app, senddtmf_exec); - - return res; - } -Index: apps/app_rpt.c -=================================================================== ---- a/apps/app_rpt.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_rpt.c (.../team/group/issue14292) (revision 178988) -@@ -318,6 +318,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -359,6 +360,8 @@ - #include "asterisk/cdr.h" - #include "asterisk/options.h" - #include "asterisk/manager.h" -+#include "asterisk/app.h" -+ - #include - - #ifdef NEW_ASTERISK -@@ -597,8 +600,8 @@ - int mode; - struct rpt_link mylink; - char param[TELEPARAMSIZE]; -- int submode; -- unsigned int parrot; -+ intptr_t submode; -+ uintptr_t parrot; - pthread_t threadid; - } ; - -@@ -1966,7 +1969,7 @@ - sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url, - myrpt->name,(unsigned int) now,seq); - if (pairs) sprintf(str + strlen(str),"&%s",pairs); -- if (!(pid = fork())) -+ if (!(pid = ast_safe_fork(0))) - { - execv(astrs[0],astrs); - ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]); -@@ -2010,7 +2013,7 @@ - ourcfg = ast_config_load(myrpt->p.extnodefile); - #endif - /* if file not there, just bail */ -- if (!ourcfg) -+ if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID) - { - ast_mutex_unlock(&nodelookuplock); - return(NULL); -@@ -2236,7 +2239,7 @@ - #else - cfg = ast_config_load("rpt.conf"); - #endif -- if (!cfg) { -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { - ast_mutex_unlock(&rpt_vars[n].lock); - ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n"); - pthread_exit(NULL); -@@ -4969,7 +4972,7 @@ - - case PARROT: /* Repeat stuff */ - -- sprintf(mystr,PARROTFILE,myrpt->name,mytele->parrot); -+ sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot); - if (ast_fileexists(mystr,NULL,mychannel->language) <= 0) - { - imdone = 1; -@@ -4977,14 +4980,14 @@ - break; - } - wait_interval(myrpt, DLY_PARROT, mychannel); -- sprintf(mystr,PARROTFILE,myrpt->name,mytele->parrot); -+ sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot); - res = ast_streamfile(mychannel, mystr, mychannel->language); - if (!res) - res = ast_waitstream(mychannel, ""); - else - ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); - ast_stopstream(mychannel); -- sprintf(mystr,PARROTFILE,myrpt->name,mytele->parrot); -+ sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot); - strcat(mystr,".wav"); - unlink(mystr); - imdone = 1; -@@ -5252,7 +5255,7 @@ - memset((char *)tele,0,sizeof(struct rpt_tele)); - tele->rpt = myrpt; - tele->mode = mode; -- if (mode == PARROT) tele->parrot = (unsigned int) data; -+ if (mode == PARROT) tele->parrot = (uintptr_t) data; - else mylink = (struct rpt_link *) data; - rpt_mutex_lock(&myrpt->lock); - if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) || -@@ -5266,7 +5269,7 @@ - strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1); - tele->param[TELEPARAMSIZE - 1] = 0; - } -- if (mode == REMXXX) tele->submode = (int) data; -+ if (mode == REMXXX) tele->submode = (intptr_t) data; - insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next); - rpt_mutex_unlock(&myrpt->lock); - pthread_attr_init(&attr); -@@ -6373,6 +6376,7 @@ - static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) - { - char string[16]; -+ int res; - - int i, r; - -@@ -6381,7 +6385,7 @@ - - switch(myatoi(param)){ - case 1: /* System reset */ -- system("killall -9 asterisk"); -+ res = system("killall -9 asterisk"); - return DC_COMPLETE; - - case 2: -@@ -9634,7 +9638,8 @@ - static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) - { - char *s,*s1,*s2; -- int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode; -+ int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0; -+ intptr_t p; - char multimode = 0; - char oc,*cp,*cp1,*cp2; - char tmp[20], freq[20] = "", savestr[20] = ""; -@@ -11986,7 +11991,7 @@ - ast_closestream(myrpt->parrotstream); - myrpt->parrotstream = NULL; - myrpt->parrotstate = 2; -- rpt_telemetry(myrpt,PARROT,(struct rpt_link *) myrpt->parrotcnt++); -+ rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); - } - if (myrpt->cmdAction.state == CMD_STATE_READY) - { /* there is a command waiting to be processed */ -@@ -12929,7 +12934,7 @@ - rpt_vars[n].cfg = ast_config_load("rpt.conf"); - #endif - cfg = rpt_vars[n].cfg; -- if (!cfg) { -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n"); - pthread_exit(NULL); - } -@@ -13659,7 +13664,7 @@ - donodelog(myrpt,str); - } - if (!phone_mode) send_newkey(chan); -- return AST_PBX_KEEPALIVE; -+ return 0; - } - /* well, then it is a remote */ - rpt_mutex_lock(&myrpt->lock); -@@ -14675,7 +14680,7 @@ - - if(myrpt->remote){ /* Remote base ? */ - char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr; -- char offset,powerlevel,rxplon,txplon,remoteon,remmode,reportfmstuff; -+ char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff; - char offsetc,powerlevelc; - - loginuser = loginlevel = freq = rxpl = txpl = NULL; -@@ -15108,8 +15113,7 @@ - res = ast_unregister_application(app); - - #ifdef NEW_ASTERISK -- ast_cli_unregister_multiple(rpt_cli,sizeof(rpt_cli) / -- sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(rpt_cli, ARRAY_LEN(rpt_cli)); - #else - /* Unregister cli extensions */ - ast_cli_unregister(&cli_debug); -@@ -15141,8 +15145,7 @@ - ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL); - - #ifdef NEW_ASTERISK -- ast_cli_register_multiple(rpt_cli,sizeof(rpt_cli) / -- sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(rpt_cli, ARRAY_LEN(rpt_cli)); - res = 0; - #else - /* Register cli extensions */ -Index: apps/app_mixmonitor.c -=================================================================== ---- a/apps/app_mixmonitor.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_mixmonitor.c (.../team/group/issue14292) (revision 178988) -@@ -46,38 +46,87 @@ - #include "asterisk/app.h" - #include "asterisk/channel.h" - -+/*** DOCUMENTATION -+ -+ -+ Record a call and mix the audio during the recording. -+ -+ -+ -+ -+ If filename is an absolute path, uses that path, otherwise -+ creates the file in the configured monitoring directory from asterisk.conf. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Will be executed when the recording is over. -+ Any strings matching ^{X} will be unescaped to X. -+ All variables will be evaluated at the time MixMonitor is called. -+ -+ -+ -+ Records the audio on the current channel to the specified file. -+ -+ -+ Will contain the filename used to record. -+ -+ -+ -+ -+ Monitor -+ StopMixMonitor -+ PauseMonitor -+ UnpauseMonitor -+ -+ -+ -+ -+ Stop recording a call through MixMonitor. -+ -+ -+ -+ Stops the audio recording that was started with a call to MixMonitor() -+ on the current channel. -+ -+ -+ MixMonitor -+ -+ -+ -+ ***/ -+ - #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 - - static const char *app = "MixMonitor"; --static const char *synopsis = "Record a call and mix the audio during the recording"; --static const char *desc = "" --" MixMonitor(.[,[,]]):\n" --"Records the audio on the current channel to the specified file.\n" --"If the filename is an absolute path, uses that path, otherwise\n" --"creates the file in the configured monitoring directory from\n" --"asterisk.conf.\n\n" --"Valid options:\n" --" a - Append to the file instead of overwriting it.\n" --" b - Only save audio to the file while the channel is bridged.\n" --" Note: Does not include conferences or sounds played to each bridged\n" --" party.\n" --" v() - Adjust the heard volume by a factor of (range -4 to 4)\n" --" V() - Adjust the spoken volume by a factor of (range -4 to 4)\n" --" W() - Adjust the both heard and spoken volumes by a factor of \n" --" (range -4 to 4)\n\n" --" will be executed when the recording is over\n" --"Any strings matching ^{X} will be unescaped to ${X}.\n" --"All variables will be evaluated at the time MixMonitor is called.\n" --"The variable MIXMONITOR_FILENAME will contain the filename used to record.\n" --""; - - static const char *stop_app = "StopMixMonitor"; --static const char *stop_synopsis = "Stop recording a call through MixMonitor"; --static const char *stop_desc = "" --" StopMixMonitor():\n" --"Stops the audio recording that was started with a call to MixMonitor()\n" --"on the current channel.\n" --""; - - struct module_symbols *me; - -@@ -89,7 +138,7 @@ - char *post_process; - char *name; - unsigned int flags; -- struct ast_channel *chan; -+ struct mixmonitor_ds *mixmonitor_ds; - }; - - enum { -@@ -115,6 +164,50 @@ - AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME), - }); - -+/* This structure is used as a means of making sure that our pointer to -+ * the channel we are monitoring remains valid. This is very similar to -+ * what is used in app_chanspy.c. -+ */ -+struct mixmonitor_ds { -+ struct ast_channel *chan; -+ /* These condition variables are used to be sure that the channel -+ * hangup code completes before the mixmonitor thread attempts to -+ * free this structure. The combination of a bookean flag and a -+ * ast_cond_t ensure that no matter what order the threads run in, -+ * we are guaranteed to never have the waiting thread block forever -+ * in the case that the signaling thread runs first. -+ */ -+ unsigned int destruction_ok; -+ ast_cond_t destruction_condition; -+ ast_mutex_t lock; -+}; -+ -+static void mixmonitor_ds_destroy(void *data) -+{ -+ struct mixmonitor_ds *mixmonitor_ds = data; -+ -+ ast_mutex_lock(&mixmonitor_ds->lock); -+ mixmonitor_ds->chan = NULL; -+ mixmonitor_ds->destruction_ok = 1; -+ ast_cond_signal(&mixmonitor_ds->destruction_condition); -+ ast_mutex_unlock(&mixmonitor_ds->lock); -+} -+ -+static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) -+{ -+ struct mixmonitor_ds *mixmonitor_ds = data; -+ -+ ast_mutex_lock(&mixmonitor_ds->lock); -+ mixmonitor_ds->chan = new_chan; -+ ast_mutex_unlock(&mixmonitor_ds->lock); -+} -+ -+static struct ast_datastore_info mixmonitor_ds_info = { -+ .type = "mixmonitor", -+ .destroy = mixmonitor_ds_destroy, -+ .chan_fixup = mixmonitor_ds_chan_fixup, -+}; -+ - static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) - { - struct ast_channel *peer = NULL; -@@ -156,7 +249,9 @@ - if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) - continue; - -- if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || ast_bridged_channel(mixmonitor->chan)) { -+ ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); -+ if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) { -+ ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); - /* Initialize the file if not already done so */ - if (!fs && !errflag) { - oflags = O_CREAT | O_WRONLY; -@@ -176,6 +271,8 @@ - /* Write out frame */ - if (fs) - ast_writestream(fs, fr); -+ } else { -+ ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); - } - - /* All done! free it. */ -@@ -197,12 +294,48 @@ - ast_safe_system(mixmonitor->post_process); - } - -+ ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock); -+ if (!mixmonitor->mixmonitor_ds->destruction_ok) { -+ ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock); -+ } -+ ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock); -+ ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock); -+ ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition); -+ ast_free(mixmonitor->mixmonitor_ds); - ast_free(mixmonitor); - -- - return NULL; - } - -+static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan) -+{ -+ struct ast_datastore *datastore = NULL; -+ struct mixmonitor_ds *mixmonitor_ds; -+ -+ if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) { -+ return -1; -+ } -+ -+ ast_mutex_init(&mixmonitor_ds->lock); -+ ast_cond_init(&mixmonitor_ds->destruction_condition, NULL); -+ -+ if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) { -+ ast_free(mixmonitor_ds); -+ return -1; -+ } -+ -+ /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */ -+ mixmonitor_ds->chan = chan; -+ datastore->data = mixmonitor_ds; -+ -+ ast_channel_lock(chan); -+ ast_channel_datastore_add(chan, datastore); -+ ast_channel_unlock(chan); -+ -+ mixmonitor->mixmonitor_ds = mixmonitor_ds; -+ return 0; -+} -+ - static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, - int readvol, int writevol, const char *post_process) - { -@@ -236,7 +369,9 @@ - - /* Copy over flags and channel name */ - mixmonitor->flags = flags; -- mixmonitor->chan = chan; -+ if (setup_mixmonitor_ds(mixmonitor, chan)) { -+ return; -+ } - mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor); - strcpy(mixmonitor->name, chan->name); - if (!ast_strlen_zero(postprocess2)) { -@@ -269,7 +404,6 @@ - } - - ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor); -- - } - - static int mixmonitor_exec(struct ast_channel *chan, void *data) -@@ -365,7 +499,7 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "mixmonitor [start|stop]"; -+ e->command = "mixmonitor {start|stop} {} [args]"; - e->usage = - "Usage: mixmonitor [args]\n" - " The optional arguments are passed to the MixMonitor\n" -@@ -403,7 +537,7 @@ - { - int res; - -- ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); - res = ast_unregister_application(stop_app); - res |= ast_unregister_application(app); - -@@ -414,9 +548,9 @@ - { - int res; - -- ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry)); -- res = ast_register_application(app, mixmonitor_exec, synopsis, desc); -- res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc); -+ ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); -+ res = ast_register_application_xml(app, mixmonitor_exec); -+ res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); - - return res; - } -Index: apps/app_ivrdemo.c -=================================================================== ---- a/apps/app_ivrdemo.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_ivrdemo.c (.../team/group/issue14292) (revision 178988) -@@ -40,11 +40,22 @@ - #include "asterisk/lock.h" - #include "asterisk/app.h" - --static char *tdesc = "IVR Demo Application"; -+/*** DOCUMENTATION -+ -+ -+ IVR Demo Application. -+ -+ -+ -+ -+ -+ This is a skeleton application that shows you the basic structure to create your -+ own asterisk applications and demonstrates the IVR demo. -+ -+ -+ ***/ -+ - static char *app = "IVRDemo"; --static char *synopsis = --" This is a skeleton application that shows you the basic structure to create your\n" --"own asterisk applications and demonstrates the IVR demo.\n"; - - static int ivr_demo_func(struct ast_channel *chan, void *data) - { -@@ -109,7 +120,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, skel_exec, tdesc, synopsis); -+ return ast_register_application_xml(app, skel_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "IVR Demo Application"); -Index: apps/app_milliwatt.c -=================================================================== ---- a/apps/app_milliwatt.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_milliwatt.c (.../team/group/issue14292) (revision 178988) -@@ -25,10 +25,6 @@ - * \ingroup applications - */ - --/*** MODULEINFO -- res_indications -- ***/ -- - #include "asterisk.h" - - ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -@@ -37,17 +33,30 @@ - #include "asterisk/channel.h" - #include "asterisk/pbx.h" - -+/*** DOCUMENTATION -+ -+ -+ Generate a Constant 1004Hz tone at 0dbm (mu-law). -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Previous versions of this application generated the tone at 1000Hz. If for -+ some reason you would prefer that behavior, supply the o option to get the -+ old behavior. -+ -+ -+ ***/ -+ - static char *app = "Milliwatt"; - --static char *synopsis = "Generate a Constant 1004Hz tone at 0dbm (mu-law)"; -- --static char *descrip = --" Milliwatt([options]): Generate a Constant 1004Hz tone at 0dbm.\n" --"Previous versions of this application generated the tone at 1000Hz. If for\n" --"some reason you would prefer that behavior, supply the 'o' option to get the\n" --"old behavior.\n" --""; -- - static char digital_milliwatt[] = {0x1e,0x0b,0x0b,0x1e,0x9e,0x8b,0x8b,0x9e} ; - - static void *milliwatt_alloc(struct ast_channel *chan, void *params) -@@ -161,7 +170,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, milliwatt_exec, synopsis, descrip); -+ return ast_register_application_xml(app, milliwatt_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Digital Milliwatt (mu-law) Test Application"); -Index: apps/app_parkandannounce.c -=================================================================== ---- a/apps/app_parkandannounce.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_parkandannounce.c (.../team/group/issue14292) (revision 178988) -@@ -43,29 +43,48 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Park and Announce. -+ -+ -+ -+ -+ Colon-separated list of files to announce. The word -+ PARKED will be replaced by a say_digits of the extension in which -+ the call is parked. -+ -+ -+ -+ -+ Time in seconds before the call returns into the return -+ context. -+ -+ -+ The app_dial style resource to call to make the -+ announcement. Console/dsp calls the console. -+ -+ -+ The goto-style label to jump the call back into after -+ timeout. Default priority+1. -+ -+ -+ -+ Park a call into the parkinglot and announce the call to another channel. -+ The variable PARKEDAT will contain the parking extension -+ into which the call was placed. Use with the Local channel to allow the dialplan to make -+ use of this information. -+ -+ -+ Park -+ ParkedCall -+ -+ -+ ***/ -+ - static char *app = "ParkAndAnnounce"; - --static char *synopsis = "Park and Announce"; -- --static char *descrip = --" ParkAndAnnounce(announce:template,timeout,dial[,return_context]):\n" --"Park a call into the parkinglot and announce the call to another channel.\n" --"\n" --"announce template: Colon-separated list of files to announce. The word PARKED\n" --" will be replaced by a say_digits of the extension in which\n" --" the call is parked.\n" --"timeout: Time in seconds before the call returns into the return\n" --" context.\n" --"dial: The app_dial style resource to call to make the\n" --" announcement. Console/dsp calls the console.\n" --"return_context: The goto-style label to jump the call back into after\n" --" timeout. Default .\n" --"\n" --"The variable ${PARKEDAT} will contain the parking extension into which the\n" --"call was placed. Use with the Local channel to allow the dialplan to make\n" --"use of this information.\n"; -- -- - static int parkandannounce_exec(struct ast_channel *chan, void *data) - { - int res = -1; -@@ -184,7 +203,7 @@ - static int load_module(void) - { - /* return ast_register_application(app, park_exec); */ -- return ast_register_application(app, parkandannounce_exec, synopsis, descrip); -+ return ast_register_application_xml(app, parkandannounce_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application"); -Index: apps/app_readfile.c -=================================================================== ---- a/apps/app_readfile.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_readfile.c (.../team/group/issue14292) (revision 178988) -@@ -35,17 +35,38 @@ - #include "asterisk/app.h" - #include "asterisk/module.h" - -+/*** DOCUMENTATION -+ -+ -+ Read the contents of a text file into a channel variable. -+ -+ -+ -+ Result stored here. -+ -+ -+ -+ The name of the file to read. -+ -+ -+ Maximum number of characters to capture. -+ If not specified defaults to max. -+ -+ -+ -+ -+ Read the contents of a text file into channel variable varname -+ ReadFile has been deprecated in favor of Set(varname=${FILE(file,0,length)}) -+ -+ -+ System -+ Read -+ -+ -+ ***/ -+ - static char *app_readfile = "ReadFile"; - --static char *readfile_synopsis = "Read the contents of a text file into a channel variable"; -- --static char *readfile_descrip = --"ReadFile(varname=file,length)\n" --" varname - Result stored here.\n" --" file - The name of the file to read.\n" --" length - Maximum number of characters to capture.\n"; -- -- - static int readfile_exec(struct ast_channel *chan, void *data) - { - int res=0; -@@ -101,7 +122,7 @@ - - static int load_module(void) - { -- return ast_register_application(app_readfile, readfile_exec, readfile_synopsis, readfile_descrip); -+ return ast_register_application_xml(app_readfile, readfile_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stores output of file into a variable"); -Index: apps/app_meetme.c -=================================================================== ---- a/apps/app_meetme.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_meetme.c (.../team/group/issue14292) (revision 178988) -@@ -63,6 +63,365 @@ - #include "enter.h" - #include "leave.h" - -+/*** DOCUMENTATION -+ -+ -+ MeetMe conference bridge. -+ -+ -+ -+ The conference number -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Enters the user into a specified MeetMe conference. If the confno -+ is omitted, the user will be prompted to enter one. User can exit the conference by hangup, or -+ if the p option is specified, by pressing #. -+ The DAHDI kernel modules and at least one hardware driver (or dahdi_dummy) -+ must be present for conferencing to operate properly. In addition, the chan_dahdi channel driver -+ must be loaded for the i and r options to operate at -+ all. -+ -+ -+ MeetMeCount -+ MeetMeAdmin -+ MeetMeChannelAdmin -+ -+ -+ -+ -+ MeetMe participant count. -+ -+ -+ -+ Conference number. -+ -+ -+ -+ -+ Plays back the number of users in the specified MeetMe conference. -+ If var is specified, playback will be skipped and the value -+ will be returned in the variable. Upon application completion, MeetMeCount will hangup -+ the channel, unless priority n+1 exists, in which case priority progress will -+ continue. -+ -+ -+ MeetMe -+ -+ -+ -+ -+ MeetMe conference administration. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Run admin command for conference confno. -+ Will additionally set the variable MEETMEADMINSTATUS with one of -+ the following values: -+ -+ -+ -+ Invalid arguments. -+ -+ -+ User specified was not found. -+ -+ -+ Another failure occurred. -+ -+ -+ The operation was completed successfully. -+ -+ -+ -+ -+ -+ MeetMe -+ -+ -+ -+ -+ MeetMe conference Administration (channel specific). -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Run admin command for a specific -+ channel in any coference. -+ -+ -+ -+ -+ Shared Line Appearance Station. -+ -+ -+ -+ Station name -+ -+ -+ -+ This application should be executed by an SLA station. The argument depends -+ on how the call was initiated. If the phone was just taken off hook, then the argument -+ station should be just the station name. If the call was -+ initiated by pressing a line key, then the station name should be preceded by an underscore -+ and the trunk name associated with that line button. -+ For example: station1_line1 -+ On exit, this application will set the variable SLASTATION_STATUS to -+ one of the following values: -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Shared Line Appearance Trunk. -+ -+ -+ -+ Trunk name -+ -+ -+ -+ -+ -+ -+ -+ -+ This application should be executed by an SLA trunk on an inbound call. The channel calling -+ this application should correspond to the SLA trunk with the name trunk -+ that is being passed as an argument. -+ On exit, this application will set the variable SLATRUNK_STATUS to -+ one of the following values: -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ***/ -+ - #define CONFIG_FILE_NAME "meetme.conf" - #define SLA_CONFIG_FILE "sla.conf" - -@@ -143,6 +502,8 @@ - CONFFLAG_EMPTY = (1 << 18), - CONFFLAG_EMPTYNOPIN = (1 << 19), - CONFFLAG_ALWAYSPROMPT = (1 << 20), -+ /*! If set, treat talking users as muted users */ -+ CONFFLAG_OPTIMIZETALKER = (1 << 21), - /*! If set, won't speak the extra prompt when the first person - * enters the conference */ - CONFFLAG_NOONLYPERSON = (1 << 22), -@@ -187,6 +548,7 @@ - AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ), - AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ), - AST_APP_OPTION('m', CONFFLAG_STARTMUTED ), -+ AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ), - AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ), - AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS ), - AST_APP_OPTION('q', CONFFLAG_QUIET ), -@@ -210,151 +572,19 @@ - static const char *slastation_app = "SLAStation"; - static const char *slatrunk_app = "SLATrunk"; - --static const char *synopsis = "MeetMe conference bridge"; --static const char *synopsis2 = "MeetMe participant count"; --static const char *synopsis3 = "MeetMe conference Administration"; --static const char *synopsis4 = "MeetMe conference Administration (channel specific)"; --static const char *slastation_synopsis = "Shared Line Appearance Station"; --static const char *slatrunk_synopsis = "Shared Line Appearance Trunk"; -- - /* Lookup RealTime conferences based on confno and current time */ - static int rt_schedule; - static int fuzzystart; - static int earlyalert; - static int endalert; -+static int extendby; - - /* Log participant count to the RealTime backend */ - static int rt_log_members; - --static const char *descrip = --" MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n" --"conference. If the conference number is omitted, the user will be prompted\n" --"to enter one. User can exit the conference by hangup, or if the 'p' option\n" --"is specified, by pressing '#'.\n" --"Please note: The DAHDI kernel modules and at least one hardware driver (or dahdi_dummy)\n" --" must be present for conferencing to operate properly. In addition, the chan_dahdi\n" --" channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n" --"The option string may contain zero or more of the following characters:\n" --" 'a' -- set admin mode\n" --" 'A' -- set marked mode\n" --" 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n" --" Default: conf-background.agi (Note: This does not work with\n" --" non-DAHDI channels in the same conference)\n" --" 'c' -- announce user(s) count on joining a conference\n" --" 'C' -- continue in dialplan when kicked out of conference\n" --" 'd' -- dynamically add conference\n" --" 'D' -- dynamically add conference, prompting for a PIN\n" --" 'e' -- select an empty conference\n" --" 'E' -- select an empty pinless conference\n" --" 'F' -- Pass DTMF through the conference.\n" --" 'i' -- announce user join/leave with review\n" --" 'I' -- announce user join/leave without review\n" --" 'l' -- set listen only mode (Listen only, no talking)\n" --" 'm' -- set initially muted\n" --" 'M[()]'\n" --" -- enable music on hold when the conference has a single caller.\n" --" Optionally, specify a musiconhold class to use. If one is not\n" --" provided, it will use the channel's currently set music class,\n" --" or \"default\".\n" --" 'o' -- set talker optimization - treats talkers who aren't speaking as\n" --" being muted, meaning (a) No encode is done on transmission and\n" --" (b) Received audio that is not registered as talking is omitted\n" --" causing no buildup in background noise\n" --" 'p[()]'\n" --" -- allow user to exit the conference by pressing '#' (default)\n" --" or any of the defined keys. If keys contain '*' this will override\n" --" option 's'. The key used is set to channel variable MEETME_EXIT_KEY.\n" --" 'P' -- always prompt for the pin even if it is specified\n" --" 'q' -- quiet mode (don't play enter/leave sounds)\n" --" 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n" --" using format ${MEETME_RECORDINGFORMAT}). Default filename is\n" --" meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n" --" wav.\n" --" 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n" --" 't' -- set talk only mode. (Talk only, no listening)\n" --" 'T' -- set talker detection (sent to manager interface and meetme list)\n" --" 'w[()]'\n" --" -- wait until the marked user enters the conference\n" --" 'x' -- close the conference when last marked user exits\n" --" 'X' -- allow user to exit the conference by entering a valid single\n" --" digit extension ${MEETME_EXIT_CONTEXT} or the current context\n" --" if that variable is not defined.\n" --" '1' -- do not play message when first person enters\n" --" 'S(x)' -- Kick the user 'x' seconds *after* he entered into the conference.\n" --" 'L(x[:y][:z])' - Limit the conference 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" --" * CONF_LIMIT_TIMEOUT_FILE File to play when time is up.\n" --" * CONF_LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n" --" The default is to say the time remaining.\n" --""; -- --static const char *descrip2 = --" MeetMeCount(confno[,var]): Plays back the number of users in the specified\n" --"MeetMe conference. If var is specified, playback will be skipped and the value\n" --"will be returned in the variable. Upon app completion, MeetMeCount will hangup\n" --"the channel, unless priority n+1 exists, in which case priority progress will\n" --"continue.\n" --""; -- --static const char *descrip3 = --" MeetMeAdmin(confno,command[,user]): Run admin command for conference\n" --" 'e' -- Eject last user that joined\n" --" 'k' -- Kick one user out of conference\n" --" 'K' -- Kick all users out of conference\n" --" 'l' -- Unlock conference\n" --" 'L' -- Lock conference\n" --" 'm' -- Unmute one user\n" --" 'M' -- Mute one user\n" --" 'n' -- Unmute all users in the conference\n" --" 'N' -- Mute all non-admin users in the conference\n" --" 'r' -- Reset one user's volume settings\n" --" 'R' -- Reset all users volume settings\n" --" 's' -- Lower entire conference speaking volume\n" --" 'S' -- Raise entire conference speaking volume\n" --" 't' -- Lower one user's talk volume\n" --" 'T' -- Raise one user's talk volume\n" --" 'u' -- Lower one user's listen volume\n" --" 'U' -- Raise one user's listen volume\n" --" 'v' -- Lower entire conference listening volume\n" --" 'V' -- Raise entire conference listening volume\n" --""; -- --static const char *descrip4 = --" MeetMeChannelAdmin(channel,command): Run admin command for a specific\n" --"channel in any coference.\n" --" 'k' -- Kick the specified user out of the conference he is in\n" --" 'm' -- Unmute the specified user\n" --" 'M' -- Mute the specified user\n" --""; -- --static const char *slastation_desc = --" SLAStation():\n" --"This application should be executed by an SLA station. The argument depends\n" --"on how the call was initiated. If the phone was just taken off hook, then\n" --"the argument \"station\" should be just the station name. If the call was\n" --"initiated by pressing a line key, then the station name should be preceded\n" --"by an underscore and the trunk name associated with that line button.\n" --"For example: \"station1_line1\"." --" On exit, this application will set the variable SLASTATION_STATUS to\n" --"one of the following values:\n" --" FAILURE | CONGESTION | SUCCESS\n" --""; -- --static const char *slatrunk_desc = --" SLATrunk([,options]):\n" --"This application should be executed by an SLA trunk on an inbound call.\n" --"The channel calling this application should correspond to the SLA trunk\n" --"with the name \"trunk\" that is being passed as an argument.\n" --" On exit, this application will set the variable SLATRUNK_STATUS to\n" --"one of the following values:\n" --" FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n" --" The available options are:\n" --" M[()] - Play back the specified MOH class instead of ringing\n" --""; -- - #define MAX_CONFNUM 80 - #define MAX_PIN 80 -+#define OPTIONS_LEN 32 - - enum announcetypes { - CONF_HASJOIN, -@@ -397,6 +627,9 @@ - char pinadmin[MAX_PIN]; /*!< If protected by a admin PIN */ - char uniqueid[32]; - long endtime; /*!< When to end the conf if scheduled */ -+ const char *useropts; /*!< RealTime user flags */ -+ const char *adminopts; /*!< RealTime moderator flags */ -+ const char *bookid; /*!< RealTime conference id */ - struct ast_frame *transframe[32]; - struct ast_frame *origframe; - struct ast_trans_pvt *transpath[32]; -@@ -909,7 +1142,6 @@ - return cnf; - } - -- - static char *complete_meetmecmd(const char *line, const char *word, int pos, int state) - { - static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL}; -@@ -965,18 +1197,17 @@ - } - AST_LIST_UNLOCK(&confs); - return usr ? ast_strdup(usrno) : NULL; -- } else if (strstr(line, "list") && (state == 0)) -- return ast_strdup("concise"); -+ } - } - - return NULL; - } - --static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) - { - /* Process the command */ -+ struct ast_conf_user *user; - struct ast_conference *cnf; -- struct ast_conf_user *user; - int hr, min, sec; - int i = 0, total = 0; - time_t now; -@@ -986,17 +1217,15 @@ - - switch (cmd) { - case CLI_INIT: -- e->command = "meetme"; -+ e->command = "meetme list [concise]"; - e->usage = -- "Usage: meetme (un)lock|(un)mute|kick|list [concise] \n" -- " Executes a command for the conference or on a conferee\n"; -+ "Usage: meetme list [concise] \n" -+ " List all or a specific conference.\n"; - return NULL; - case CLI_GENERATE: - return complete_meetmecmd(a->line, a->word, a->pos, a->n); - } - -- if (a->argc > 8) -- ast_cli(a->fd, "Invalid Arguments.\n"); - /* Check for length so no buffer will overflow... */ - for (i = 0; i < a->argc; i++) { - if (strlen(a->argv[i]) > 100) -@@ -1008,9 +1237,9 @@ - return CLI_FAILURE; - } - -- if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) { -- /* 'MeetMe': List all the conferences */ -- int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise")); -+ if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) { -+ /* List all the conferences */ -+ int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise")); - now = time(NULL); - AST_LIST_LOCK(&confs); - if (AST_LIST_EMPTY(&confs)) { -@@ -1034,7 +1263,7 @@ - min = ((now - cnf->start) % 3600) / 60; - sec = (now - cnf->start) % 60; - if (!concise) { -- ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No"); -+ ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No"); - } else { - ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n", - cnf->confno, -@@ -1053,59 +1282,12 @@ - } - ast_free(cmdline); - return CLI_SUCCESS; -- } -- if (a->argc < 3) { -- ast_free(cmdline); -- return CLI_SHOWUSAGE; -- } -- -- ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */ -- if (strstr(a->argv[1], "lock")) { -- if (strcmp(a->argv[1], "lock") == 0) { -- /* Lock */ -- ast_str_append(&cmdline, 0, ",L"); -- } else { -- /* Unlock */ -- ast_str_append(&cmdline, 0, ",l"); -- } -- } else if (strstr(a->argv[1], "mute")) { -- if (a->argc < 4) { -- ast_free(cmdline); -- return CLI_SHOWUSAGE; -- } -- if (strcmp(a->argv[1], "mute") == 0) { -- /* Mute */ -- if (strcmp(a->argv[3], "all") == 0) { -- ast_str_append(&cmdline, 0, ",N"); -- } else { -- ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]); -- } -- } else { -- /* Unmute */ -- if (strcmp(a->argv[3], "all") == 0) { -- ast_str_append(&cmdline, 0, ",n"); -- } else { -- ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]); -- } -- } -- } else if (strcmp(a->argv[1], "kick") == 0) { -- if (a->argc < 4) { -- ast_free(cmdline); -- return CLI_SHOWUSAGE; -- } -- if (strcmp(a->argv[3], "all") == 0) { -- /* Kick all */ -- ast_str_append(&cmdline, 0, ",K"); -- } else { -- /* Kick a single user */ -- ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]); -- } - } else if (strcmp(a->argv[1], "list") == 0) { - int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise"))); - /* List all the users in a conference */ - if (AST_LIST_EMPTY(&confs)) { - if (!concise) { -- ast_cli(a->fd, "No active conferences.\n"); -+ ast_cli(a->fd, "No active MeetMe conferences.\n"); - } - ast_free(cmdline); - return CLI_SUCCESS; -@@ -1160,14 +1342,105 @@ - AST_LIST_UNLOCK(&confs); - ast_free(cmdline); - return CLI_SUCCESS; -+ } -+ if (a->argc < 2) { -+ ast_free(cmdline); -+ return CLI_SHOWUSAGE; -+ } -+ -+ ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline)); -+ -+ admin_exec(NULL, ast_str_buffer(cmdline)); -+ ast_free(cmdline); -+ -+ return CLI_SUCCESS; -+} -+ -+ -+static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ /* Process the command */ -+ struct ast_str *cmdline = NULL; -+ int i = 0; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "meetme {lock|unlock|mute|unmute|kick}"; -+ e->usage = -+ "Usage: meetme (un)lock|(un)mute|kick \n" -+ " Executes a command for the conference or on a conferee\n"; -+ return NULL; -+ case CLI_GENERATE: -+ return complete_meetmecmd(a->line, a->word, a->pos, a->n); -+ } -+ -+ if (a->argc > 8) -+ ast_cli(a->fd, "Invalid Arguments.\n"); -+ /* Check for length so no buffer will overflow... */ -+ for (i = 0; i < a->argc; i++) { -+ if (strlen(a->argv[i]) > 100) -+ ast_cli(a->fd, "Invalid Arguments.\n"); -+ } -+ -+ /* Max confno length */ -+ if (!(cmdline = ast_str_create(MAX_CONFNUM))) { -+ return CLI_FAILURE; -+ } -+ -+ if (a->argc < 1) { -+ ast_free(cmdline); -+ return CLI_SHOWUSAGE; -+ } -+ -+ ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */ -+ if (strstr(a->argv[1], "lock")) { -+ if (strcmp(a->argv[1], "lock") == 0) { -+ /* Lock */ -+ ast_str_append(&cmdline, 0, ",L"); -+ } else { -+ /* Unlock */ -+ ast_str_append(&cmdline, 0, ",l"); -+ } -+ } else if (strstr(a->argv[1], "mute")) { -+ if (a->argc < 4) { -+ ast_free(cmdline); -+ return CLI_SHOWUSAGE; -+ } -+ if (strcmp(a->argv[1], "mute") == 0) { -+ /* Mute */ -+ if (strcmp(a->argv[3], "all") == 0) { -+ ast_str_append(&cmdline, 0, ",N"); -+ } else { -+ ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]); -+ } -+ } else { -+ /* Unmute */ -+ if (strcmp(a->argv[3], "all") == 0) { -+ ast_str_append(&cmdline, 0, ",n"); -+ } else { -+ ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]); -+ } -+ } -+ } else if (strcmp(a->argv[1], "kick") == 0) { -+ if (a->argc < 4) { -+ ast_free(cmdline); -+ return CLI_SHOWUSAGE; -+ } -+ if (strcmp(a->argv[3], "all") == 0) { -+ /* Kick all */ -+ ast_str_append(&cmdline, 0, ",K"); -+ } else { -+ /* Kick a single user */ -+ ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]); -+ } - } else { - ast_free(cmdline); - return CLI_SHOWUSAGE; - } - -- ast_debug(1, "Cmdline: %s\n", cmdline->str); -+ ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline)); - -- admin_exec(NULL, cmdline->str); -+ admin_exec(NULL, ast_str_buffer(cmdline)); - ast_free(cmdline); - - return CLI_SUCCESS; -@@ -1333,6 +1606,7 @@ - - static struct ast_cli_entry cli_meetme[] = { - AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"), -+ AST_CLI_DEFINE(meetme_show_cmd, "List all or one conference"), - AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"), - AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"), - }; -@@ -1524,8 +1798,9 @@ - AST_LIST_LOCK(&confs); - if (ast_atomic_dec_and_test(&conf->refcount)) { - /* Take the conference room number out of an inuse state */ -- if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) -+ if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) { - conf_map[confno_int] = 0; -+ } - conf_free(conf); - res = 1; - } -@@ -1534,6 +1809,68 @@ - return res; - } - -+static int rt_extend_conf(char *confno) -+{ -+ char currenttime[32]; -+ char endtime[32]; -+ struct timeval now; -+ struct ast_tm tm; -+ struct ast_variable *var, *orig_var; -+ char bookid[8]; -+ -+ if (!extendby) { -+ return 0; -+ } -+ -+ now = ast_tvnow(); -+ -+ ast_localtime(&now, &tm, NULL); -+ ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); -+ -+ var = ast_load_realtime("meetme", "confno", -+ confno, "startTime<= ", currenttime, -+ "endtime>= ", currenttime, NULL); -+ -+ orig_var = var; -+ -+ /* Identify the specific RealTime conference */ -+ while (var) { -+ if (!strcasecmp(var->name, "bookid")) { -+ ast_copy_string(bookid, var->value, sizeof(bookid)); -+ } -+ if (!strcasecmp(var->name, "endtime")) { -+ ast_copy_string(endtime, var->value, sizeof(endtime)); -+ } -+ -+ var = var->next; -+ } -+ ast_variables_destroy(orig_var); -+ -+ ast_strptime(endtime, DATE_FORMAT, &tm); -+ now = ast_mktime(&tm, NULL); -+ -+ now.tv_sec += extendby; -+ -+ ast_localtime(&now, &tm, NULL); -+ ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); -+ strcat(currenttime, "0"); /* Seconds needs to be 00 */ -+ -+ var = ast_load_realtime("meetme", "confno", -+ confno, "startTime<= ", currenttime, -+ "endtime>= ", currenttime, NULL); -+ -+ /* If there is no conflict with extending the conference, update the DB */ -+ if (!var) { -+ ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime); -+ ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL); -+ return 0; -+ -+ } -+ -+ ast_variables_destroy(var); -+ return -1; -+} -+ - static void conf_start_moh(struct ast_channel *chan, const char *musicclass) - { - char *original_moh; -@@ -1568,7 +1905,7 @@ - { - struct announce_listitem *current; - struct ast_conference *conf = data; -- int res = 0; -+ int res; - char filename[PATH_MAX] = ""; - AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list; - AST_LIST_HEAD_INIT_NOLOCK(&local_list); -@@ -1639,7 +1976,6 @@ - int ms; - int nfds; - int res; -- int flags; - int retrydahdi; - int origfd; - int musiconhold = 0; -@@ -1998,24 +2334,13 @@ - dahdiretry: - origfd = chan->fds[0]; - if (retrydahdi) { -- fd = open("/dev/dahdi/pseudo", O_RDWR); -+ /* open pseudo in non-blocking mode */ -+ fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK); - if (fd < 0) { - ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); - goto outrun; - } - using_pseudo = 1; -- /* Make non-blocking */ -- flags = fcntl(fd, F_GETFL); -- if (flags < 0) { -- ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); -- close(fd); -- goto outrun; -- } -- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { -- ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); -- close(fd); -- goto outrun; -- } - /* Setup buffering information */ - memset(&bi, 0, sizeof(bi)); - bi.bufsize = CONF_SIZE / 2; -@@ -2159,7 +2484,7 @@ - x = 1; - ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); - } -- if (!(confflags & CONFFLAG_MONITOR) && !(dsp = ast_dsp_new())) { -+ if ((confflags & CONFFLAG_OPTIMIZETALKER) && !(confflags & CONFFLAG_MONITOR) && !(dsp = ast_dsp_new())) { - ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); - res = -1; - } -@@ -2170,10 +2495,41 @@ - ms = -1; - now = ast_tvnow(); - -- if (rt_schedule) { -+ if (rt_schedule && conf->endtime) { -+ char currenttime[32]; -+ long localendtime = 0; -+ int extended = 0; -+ struct ast_tm tm; -+ struct ast_variable *var, *origvar; -+ struct timeval tmp; -+ - if (now.tv_sec % 60 == 0) { - if (!checked) { -- if (now.tv_sec >= conf->endtime) { -+ ast_localtime(&now, &tm, NULL); -+ ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm); -+ var = origvar = ast_load_realtime("meetme", "confno", -+ conf->confno, "starttime <=", currenttime, -+ "endtime >=", currenttime, NULL); -+ -+ for ( ; var; var = var->next) { -+ if (!strcasecmp(var->name, "endtime")) { -+ struct ast_tm endtime_tm; -+ ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm); -+ tmp = ast_mktime(&endtime_tm, NULL); -+ localendtime = tmp.tv_sec; -+ } -+ } -+ ast_variables_destroy(origvar); -+ -+ /* A conference can be extended from the -+ Admin/User menu or by an external source */ -+ if (localendtime > conf->endtime){ -+ conf->endtime = localendtime; -+ extended = 1; -+ } -+ -+ if (conf->endtime && (now.tv_sec >= conf->endtime)) { -+ ast_verbose("Quitting time...\n"); - goto outrun; - } - -@@ -2187,27 +2543,34 @@ - announcement_played = 1; - } - } -+ -+ if (extended) { -+ announcement_played = 0; -+ } -+ - checked = 1; -- - } - } else { - checked = 0; - } - } - -- if (user->kicktime && (user->kicktime <= now.tv_sec)) -+ if (user->kicktime && (user->kicktime <= now.tv_sec)) { - break; -+ } - - to = -1; - if (user->timelimit) { - int minutes = 0, seconds = 0, remain = 0; - - to = ast_tvdiff_ms(nexteventts, now); -- if (to < 0) -+ if (to < 0) { - to = 0; -+ } - time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time); -- if (time_left_ms < to) -+ if (time_left_ms < to) { - to = time_left_ms; -+ } - - if (time_left_ms <= 0) { - if (user->end_sound) { -@@ -2250,22 +2613,25 @@ - } - } - } -- if (user->warning_freq) -+ if (user->warning_freq) { - nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000)); -- else -+ } else { - nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); -+ } - } - } - - now = ast_tvnow(); -- if (timeout && now.tv_sec >= timeout) -+ if (timeout && now.tv_sec >= timeout) { - break; -+ } - - /* if we have just exited from the menu, and the user had a channel-driver - volume adjustment, restore it - */ -- if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) -+ if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) { - set_talk_volume(user, user->listen.desired); -+ } - - menu_was_active = menu_active; - -@@ -2277,16 +2643,20 @@ - if (currentmarked == 1 && conf->users > 1) { - ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); - if (conf->users - 1 == 1) { -- if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) -+ if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) { - ast_waitstream(chan, ""); -+ } - } else { -- if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) -+ if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) { - ast_waitstream(chan, ""); -+ } - } - } -- if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) -- if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) -+ if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) { -+ if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) { - ast_waitstream(chan, ""); -+ } -+ } - } - - c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); -@@ -2297,12 +2667,15 @@ - if (confflags & CONFFLAG_WAITMARKED) { - if (currentmarked == 0) { - if (lastmarked != 0) { -- if (!(confflags & CONFFLAG_QUIET)) -- if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) -+ if (!(confflags & CONFFLAG_QUIET)) { -+ if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) { - ast_waitstream(chan, ""); -+ } -+ } - if (confflags & CONFFLAG_MARKEDEXIT) { -- if (confflags & CONFFLAG_KICK_CONTINUE) -+ if (confflags & CONFFLAG_KICK_CONTINUE) { - ret = 0; -+ } - break; - } else { - dahdic.confmode = DAHDI_CONF_CONF; -@@ -2320,12 +2693,13 @@ - } else if (currentmarked >= 1 && lastmarked == 0) { - /* Marked user entered, so cancel timeout */ - timeout = 0; -- if (confflags & CONFFLAG_MONITOR) -+ if (confflags & CONFFLAG_MONITOR) { - dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER; -- else if (confflags & CONFFLAG_TALKER) -+ } else if (confflags & CONFFLAG_TALKER) { - dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER; -- else -+ } else { - dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER; -+ } - if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); -@@ -2336,8 +2710,9 @@ - musiconhold = 0; - } - if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) { -- if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) -+ if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) { - ast_waitstream(chan, ""); -+ } - conf_play(chan, conf, ENTER); - } - } -@@ -2360,10 +2735,11 @@ - - /* Leave if the last marked user left */ - if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) { -- if (confflags & CONFFLAG_KICK_CONTINUE) -+ if (confflags & CONFFLAG_KICK_CONTINUE) { - ret = 0; -- else -+ } else { - ret = -1; -+ } - break; - } - -@@ -2443,8 +2819,9 @@ - } - - /* Perform an extra hangup check just in case */ -- if (ast_check_hangup(chan)) -+ if (ast_check_hangup(chan)) { - break; -+ } - - if (c) { - char dtmfstr[2] = ""; -@@ -2460,26 +2837,30 @@ - user->dahdichannel = !retrydahdi; - goto dahdiretry; - } -- if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) -+ if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { - f = ast_read_noaudio(c); -- else -+ } else { - f = ast_read(c); -- if (!f) -+ } -+ if (!f) { - break; -+ } - if (f->frametype == AST_FRAME_DTMF) { - dtmfstr[0] = f->subclass; - dtmfstr[1] = '\0'; - } - - if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) { -- if (user->talk.actual) -+ if (user->talk.actual) { - ast_frame_adjust_volume(f, user->talk.actual); -+ } - -- if (!(confflags & CONFFLAG_MONITOR)) { -+ if ((confflags & CONFFLAG_OPTIMIZETALKER) && !(confflags & CONFFLAG_MONITOR)) { - int totalsilence; - -- if (user->talking == -1) -+ if (user->talking == -1) { - user->talking = 0; -+ } - - res = ast_dsp_silence(dsp, f, &totalsilence); - if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { -@@ -2495,7 +2876,7 @@ - } - if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) { - user->talking = 0; -- if (confflags & CONFFLAG_MONITORTALKER) -+ if (confflags & CONFFLAG_MONITORTALKER) { - manager_event(EVENT_FLAG_CALL, "MeetmeTalking", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" -@@ -2503,6 +2884,7 @@ - "Usernum: %d\r\n" - "Status: off\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); -+ } - } - } - if (using_pseudo) { -@@ -2518,12 +2900,14 @@ - don't want to block, but we do want to at least *try* - to write out all the samples. - */ -- if (user->talking) -+ if (user->talking && !(confflags & CONFFLAG_OPTIMIZETALKER)) { - careful_write(fd, f->data.ptr, f->datalen, 0); -+ } - } - } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { -- if (confflags & CONFFLAG_PASS_DTMF) -+ if (confflags & CONFFLAG_PASS_DTMF) { - conf_queue_dtmf(conf, user, f); -+ } - if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) { - ast_log(LOG_WARNING, "Error setting conference\n"); - close(fd); -@@ -2534,8 +2918,9 @@ - /* if we are entering the menu, and the user has a channel-driver - volume adjustment, clear it - */ -- if (!menu_active && user->talk.desired && !user->talk.actual) -+ if (!menu_active && user->talk.desired && !user->talk.actual) { - set_talk_volume(user, 0); -+ } - - if (musiconhold) { - ast_moh_stop(chan); -@@ -2545,57 +2930,82 @@ - if (!menu_active) { - menu_active = 1; - /* Record this sound! */ -- if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) { -+ if (!ast_streamfile(chan, "conf-adminmenu-162", chan->language)) { - dtmf = ast_waitstream(chan, AST_DIGIT_ANY); - ast_stopstream(chan); -- } else -+ } else { - dtmf = 0; -- } else -+ } -+ } else { - dtmf = f->subclass; -+ } - if (dtmf) { - switch(dtmf) { - case '1': /* Un/Mute */ - menu_active = 0; - - /* for admin, change both admin and use flags */ -- if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) -+ if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) { - user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); -- else -+ } else { - user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); -+ } - - if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { -- if (!ast_streamfile(chan, "conf-muted", chan->language)) -+ if (!ast_streamfile(chan, "conf-muted", chan->language)) { - ast_waitstream(chan, ""); -+ } - } else { -- if (!ast_streamfile(chan, "conf-unmuted", chan->language)) -+ if (!ast_streamfile(chan, "conf-unmuted", chan->language)) { - ast_waitstream(chan, ""); -+ } - } - break; - case '2': /* Un/Lock the Conference */ - menu_active = 0; - if (conf->locked) { - conf->locked = 0; -- if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) -+ if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) { - ast_waitstream(chan, ""); -+ } - } else { - conf->locked = 1; -- if (!ast_streamfile(chan, "conf-lockednow", chan->language)) -+ if (!ast_streamfile(chan, "conf-lockednow", chan->language)) { - ast_waitstream(chan, ""); -+ } - } - break; - case '3': /* Eject last user */ - menu_active = 0; - usr = AST_LIST_LAST(&conf->userlist); -- if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) { -- if (!ast_streamfile(chan, "conf-errormenu", chan->language)) -+ if ((usr->chan->name == chan->name) || (usr->userflags & CONFFLAG_ADMIN)) { -+ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) { - ast_waitstream(chan, ""); -- } else -+ } -+ } else { - usr->adminflags |= ADMINFLAG_KICKME; -+ } - ast_stopstream(chan); - break; - case '4': - tweak_listen_volume(user, VOL_DOWN); - break; -+ case '5': -+ /* Extend RT conference */ -+ if (rt_schedule) { -+ if (!rt_extend_conf(conf->confno)) { -+ if (!ast_streamfile(chan, "conf-extended", chan->language)) { -+ ast_waitstream(chan, ""); -+ } -+ } else { -+ if (!ast_streamfile(chan, "conf-nonextended", chan->language)) { -+ ast_waitstream(chan, ""); -+ } -+ } -+ ast_stopstream(chan); -+ } -+ menu_active = 0; -+ break; - case '6': - tweak_listen_volume(user, VOL_UP); - break; -@@ -2611,8 +3021,9 @@ - default: - menu_active = 0; - /* Play an error message! */ -- if (!ast_streamfile(chan, "conf-errormenu", chan->language)) -+ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) { - ast_waitstream(chan, ""); -+ } - break; - } - } -@@ -2620,15 +3031,17 @@ - /* User menu */ - if (!menu_active) { - menu_active = 1; -- if (!ast_streamfile(chan, "conf-usermenu", chan->language)) { -+ if (!ast_streamfile(chan, "conf-usermenu-162", chan->language)) { - dtmf = ast_waitstream(chan, AST_DIGIT_ANY); - ast_stopstream(chan); -- } else -+ } else { - dtmf = 0; -- } else -+ } -+ } else { - dtmf = f->subclass; -+ } - if (dtmf) { -- switch(dtmf) { -+ switch (dtmf) { - case '1': /* Un/Mute */ - menu_active = 0; - -@@ -2637,25 +3050,37 @@ - - /* they can't override the admin mute state */ - if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) { -- if (!ast_streamfile(chan, "conf-muted", chan->language)) -+ if (!ast_streamfile(chan, "conf-muted", chan->language)) { - ast_waitstream(chan, ""); -+ } - } else { -- if (!ast_streamfile(chan, "conf-unmuted", chan->language)) -+ if (!ast_streamfile(chan, "conf-unmuted", chan->language)) { - ast_waitstream(chan, ""); -+ } - } - break; - case '2': - menu_active = 0; -- if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) -+ if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) { - user->adminflags |= ADMINFLAG_T_REQUEST; -+ } - -- if (user->adminflags & ADMINFLAG_T_REQUEST) -- if (!ast_streamfile(chan, "beep", chan->language)) -+ if (user->adminflags & ADMINFLAG_T_REQUEST) { -+ if (!ast_streamfile(chan, "beep", chan->language)) { - ast_waitstream(chan, ""); -+ } -+ } - break; - case '4': - tweak_listen_volume(user, VOL_DOWN); - break; -+ case '5': -+ /* Extend RT conference */ -+ if (rt_schedule) { -+ rt_extend_conf(conf->confno); -+ } -+ menu_active = 0; -+ break; - case '6': - tweak_listen_volume(user, VOL_UP); - break; -@@ -2670,14 +3095,16 @@ - break; - default: - menu_active = 0; -- if (!ast_streamfile(chan, "conf-errormenu", chan->language)) -+ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) { - ast_waitstream(chan, ""); -+ } - break; - } - } - } -- if (musiconhold) -+ if (musiconhold) { - conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]); -+ } - - if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { - ast_log(LOG_WARNING, "Error setting conference\n"); -@@ -2687,10 +3114,11 @@ - } - - conf_flush(fd, chan); -- /* Since this option could absorb dtmf meant for the previous (menu), we have to check this one last */ -+ /* Since this option could absorb DTMF meant for the previous (menu), we have to check this one last */ - } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) { -- if (confflags & CONFFLAG_PASS_DTMF) -+ if (confflags & CONFFLAG_PASS_DTMF) { - conf_queue_dtmf(conf, user, f); -+ } - - if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) { - ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext); -@@ -2703,8 +3131,9 @@ - } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) { - pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr); - -- if (confflags & CONFFLAG_PASS_DTMF) -+ if (confflags & CONFFLAG_PASS_DTMF) { - conf_queue_dtmf(conf, user, f); -+ } - ret = 0; - ast_frfree(f); - break; -@@ -2737,32 +3166,39 @@ - fr.samples = res / 2; - fr.data.ptr = buf; - fr.offset = AST_FRIENDLY_OFFSET; -- if (!user->listen.actual && -- ((confflags & CONFFLAG_MONITOR) || -+ if (!user->listen.actual && -+ ((confflags & CONFFLAG_MONITOR) || - (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) || -- (!user->talking)) ) { -+ (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER)) -+ )) { - int idx; -- for (idx = 0; idx < AST_FRAME_BITS; idx++) -- if (chan->rawwriteformat & (1 << idx)) -+ for (idx = 0; idx < AST_FRAME_BITS; idx++) { -+ if (chan->rawwriteformat & (1 << idx)) { - break; -- if (idx >= AST_FRAME_BITS) -+ } -+ } -+ if (idx >= AST_FRAME_BITS) { - goto bailoutandtrynormal; -+ } - ast_mutex_lock(&conf->listenlock); - if (!conf->transframe[idx]) { - if (conf->origframe) { -- if (!conf->transpath[idx]) -+ if (!conf->transpath[idx]) { - conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR); -+ } - if (conf->transpath[idx]) { - conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0); -- if (!conf->transframe[idx]) -+ if (!conf->transframe[idx]) { - conf->transframe[idx] = &ast_null_frame; -+ } - } - } - } - if (conf->transframe[idx]) { - if (conf->transframe[idx]->frametype != AST_FRAME_NULL) { -- if (can_write(chan, confflags) && ast_write(chan, conf->transframe[idx])) -+ if (can_write(chan, confflags) && ast_write(chan, conf->transframe[idx])) { - ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name); -+ } - } - } else { - ast_mutex_unlock(&conf->listenlock); -@@ -2771,25 +3207,28 @@ - ast_mutex_unlock(&conf->listenlock); - } else { - bailoutandtrynormal: -- if (user->listen.actual) -+ if (user->listen.actual) { - ast_frame_adjust_volume(&fr, user->listen.actual); -+ } - if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) { - ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name); - } - } -- } else -+ } else { - ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); -+ } - } - lastmarked = currentmarked; - } - } - -- if (musiconhold) -+ if (musiconhold) { - ast_moh_stop(chan); -+ } - -- if (using_pseudo) -+ if (using_pseudo) { - close(fd); -- else { -+ } else { - /* Take out of conference */ - dahdic.chan = 0; - dahdic.confno = 0; -@@ -2801,8 +3240,9 @@ - - reset_volumes(user); - -- if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) -+ if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { - conf_play(chan, conf, LEAVE); -+ } - - if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) { - struct announce_listitem *item; -@@ -2825,8 +3265,9 @@ - outrun: - AST_LIST_LOCK(&confs); - -- if (dsp) -+ if (dsp) { - ast_dsp_free(dsp); -+ } - - if (user->user_no) { /* Only cleanup users who really joined! */ - now = ast_tvnow(); -@@ -2861,16 +3302,18 @@ - NULL); - ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL); - } -- if (confflags & CONFFLAG_MARKEDUSER) -+ if (confflags & CONFFLAG_MARKEDUSER) { - conf->markedusers--; -+ } - } - /* Remove ourselves from the list */ - AST_LIST_REMOVE(&conf->userlist, user, list); - - /* Change any states */ -- if (!conf->users) -+ if (!conf->users) { - ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno); -- -+ } -+ - /* Return the number of seconds the user was in the conf */ - snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime)); - pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); -@@ -2882,10 +3325,9 @@ - } - - static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic, -- char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, -- char *optargs[], int *too_early) -+ char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, int *too_early) - { -- struct ast_variable *var; -+ struct ast_variable *var, *origvar; - struct ast_conference *cnf; - - *too_early = 0; -@@ -2907,8 +3349,10 @@ - struct timeval now; - char currenttime[19] = ""; - char eatime[19] = ""; -- char useropts[32] = ""; -- char adminopts[32] = ""; -+ char bookid[19] = ""; -+ char recordingtmp[AST_MAX_EXTENSION] = ""; -+ char useropts[OPTIONS_LEN]; /* Used for RealTime conferences */ -+ char adminopts[OPTIONS_LEN]; - struct ast_tm tm, etm; - struct timeval endtime = { .tv_sec = 0 }; - -@@ -2943,12 +3387,14 @@ - var = ast_load_realtime("meetme", "confno", - confno, "starttime <= ", eatime, "endtime >= ", - currenttime, NULL); -- if (var) -+ if (var) { - *too_early = 1; -+ } - } - -- } else -+ } else { - var = ast_load_realtime("meetme", "confno", confno, NULL); -+ } - - if (!var) - return NULL; -@@ -2961,35 +3407,27 @@ - return NULL; - } - -- while (var) { -+ for (origvar = var; var; var = var->next) { - if (!strcasecmp(var->name, "pin")) { - pin = ast_strdupa(var->value); - } else if (!strcasecmp(var->name, "adminpin")) { - pinadmin = ast_strdupa(var->value); -+ } else if (!strcasecmp(var->name, "bookId")) { -+ ast_copy_string(bookid, var->value, sizeof(bookid)); - } else if (!strcasecmp(var->name, "opts")) { -- ast_copy_string(useropts, var->value, sizeof(useropts)); -+ ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN])); - } else if (!strcasecmp(var->name, "maxusers")) { - maxusers = atoi(var->value); - } else if (!strcasecmp(var->name, "adminopts")) { -- ast_copy_string(adminopts, var->value, sizeof(adminopts)); -+ ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN])); - } else if (!strcasecmp(var->name, "endtime")) { -- union { -- struct ast_tm atm; -- struct tm tm; -- } t = { { 0, }, }; -- strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm); -- /* strptime does not determine if a time is -- * in DST or not. Set tm_isdst to -1 to -- * allow ast_mktime to adjust for DST -- * if needed */ -- t.tm.tm_isdst = -1; -- endtime = ast_mktime(&t.atm, NULL); -+ struct ast_tm endtime_tm; -+ ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm); -+ endtime = ast_mktime(&endtime_tm, NULL); - } -- -- var = var->next; - } - -- ast_variables_destroy(var); -+ ast_variables_destroy(origvar); - - cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan); - -@@ -2997,6 +3435,12 @@ - cnf->maxusers = maxusers; - cnf->endalert = endalert; - cnf->endtime = endtime.tv_sec; -+ cnf->useropts = ast_strdup(useropts); -+ cnf->adminopts = ast_strdup(adminopts); -+ cnf->bookid = ast_strdup(bookid); -+ snprintf(recordingtmp, sizeof(recordingtmp), "%s/meetme/meetme-conf-rec-%s-%s", ast_config_AST_SPOOL_DIR, confno, bookid); -+ cnf->recordingfilename = ast_strdup(recordingtmp); -+ cnf->recordingformat = ast_strdup("wav"); - } - } - -@@ -3066,6 +3510,9 @@ - if (!cfg) { - ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME); - return NULL; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n"); -+ return NULL; - } - for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) { - if (strcasecmp(var->name, "conf")) -@@ -3094,8 +3541,9 @@ - /* Correct for the user selecting 'D' instead of 'd' to have - someone join into a conference that has already been created - with a pin. */ -- if (dynamic_pin[0] == 'q') -+ if (dynamic_pin[0] == 'q') { - dynamic_pin[0] = '\0'; -+ } - } - - if (cnf) { -@@ -3153,8 +3601,9 @@ - snprintf(val, sizeof(val), "%d", count); - pbx_builtin_setvar_helper(chan, args.varname, val); - } else { -- if (chan->_state != AST_STATE_UP) -+ if (chan->_state != AST_STATE_UP) { - ast_answer(chan); -+ } - res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */ - } - -@@ -3228,7 +3677,7 @@ - /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */ - if ((empty_no_pin) || (!dynamic)) { - cfg = ast_config_load(CONFIG_FILE_NAME, config_flags); -- if (cfg) { -+ if (cfg && cfg != CONFIG_STATUS_FILEINVALID) { - var = ast_variable_browse(cfg, "rooms"); - while (var) { - if (!strcasecmp(var->name, "conf")) { -@@ -3317,8 +3766,9 @@ - sizeof(the_pin), 1, &confflags); - if (!cnf) { - int too_early = 0; -+ - cnf = find_conf_realtime(chan, confno, 1, dynamic, -- the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early); -+ the_pin, sizeof(the_pin), 1, &confflags,&too_early); - if (rt_schedule && too_early) - allowretry = 0; - } -@@ -3354,8 +3804,17 @@ - !strcasecmp(pin, cnf->pinadmin))) { - /* Pin correct */ - allowretry = 0; -- if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) -- ast_set_flag(&confflags, CONFFLAG_ADMIN); -+ if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) { -+ if (!ast_strlen_zero(cnf->adminopts)) { -+ char *opts = ast_strdupa(cnf->adminopts); -+ ast_app_parse_options(meetme_opts, &confflags, optargs, opts); -+ } -+ } else { -+ if (!ast_strlen_zero(cnf->useropts)) { -+ char *opts = ast_strdupa(cnf->useropts); -+ ast_app_parse_options(meetme_opts, &confflags, optargs, opts); -+ } -+ } - /* Run the conference */ - res = conf_run(chan, cnf, confflags.flags, optargs); - break; -@@ -3364,8 +3823,7 @@ - if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) { - res = ast_waitstream(chan, AST_DIGIT_ANY); - ast_stopstream(chan); -- } -- else { -+ } else { - ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n"); - break; - } -@@ -3435,9 +3893,11 @@ - AST_APP_ARG(command); - AST_APP_ARG(user); - ); -+ int res = 0; - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n"); -+ pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE"); - return -1; - } - -@@ -3446,6 +3906,7 @@ - - if (!args.command) { - ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n"); -+ pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE"); - return -1; - } - -@@ -3458,6 +3919,7 @@ - if (!cnf) { - ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno); - AST_LIST_UNLOCK(&confs); -+ pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND"); - return 0; - } - -@@ -3481,93 +3943,124 @@ - user = AST_LIST_LAST(&cnf->userlist); - if (!(user->userflags & CONFFLAG_ADMIN)) - user->adminflags |= ADMINFLAG_KICKME; -- else -+ else { -+ res = -1; - ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n"); -+ } - break; - case 77: /* M: Mute */ - if (user) { - user->adminflags |= ADMINFLAG_MUTED; -- } else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 78: /* N: Mute all (non-admin) users */ - AST_LIST_TRAVERSE(&cnf->userlist, user, list) { -- if (!(user->userflags & CONFFLAG_ADMIN)) -+ if (!(user->userflags & CONFFLAG_ADMIN)) { - user->adminflags |= ADMINFLAG_MUTED; -+ } - } - break; - case 109: /* m: Unmute */ - if (user) { - user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); -- } else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 110: /* n: Unmute all users */ -- AST_LIST_TRAVERSE(&cnf->userlist, user, list) -+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) { - user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); -+ } - break; - case 107: /* k: Kick user */ -- if (user) -+ if (user) { - user->adminflags |= ADMINFLAG_KICKME; -- else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 118: /* v: Lower all users listen volume */ -- AST_LIST_TRAVERSE(&cnf->userlist, user, list) -+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) { - tweak_listen_volume(user, VOL_DOWN); -+ } - break; - case 86: /* V: Raise all users listen volume */ -- AST_LIST_TRAVERSE(&cnf->userlist, user, list) -+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) { - tweak_listen_volume(user, VOL_UP); -+ } - break; - case 115: /* s: Lower all users speaking volume */ -- AST_LIST_TRAVERSE(&cnf->userlist, user, list) -+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) { - tweak_talk_volume(user, VOL_DOWN); -+ } - break; - case 83: /* S: Raise all users speaking volume */ -- AST_LIST_TRAVERSE(&cnf->userlist, user, list) -+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) { - tweak_talk_volume(user, VOL_UP); -+ } - break; - case 82: /* R: Reset all volume levels */ -- AST_LIST_TRAVERSE(&cnf->userlist, user, list) -+ AST_LIST_TRAVERSE(&cnf->userlist, user, list) { - reset_volumes(user); -+ } - break; - case 114: /* r: Reset user's volume level */ -- if (user) -+ if (user) { - reset_volumes(user); -- else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 85: /* U: Raise user's listen volume */ -- if (user) -+ if (user) { - tweak_listen_volume(user, VOL_UP); -- else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 117: /* u: Lower user's listen volume */ -- if (user) -+ if (user) { - tweak_listen_volume(user, VOL_DOWN); -- else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 84: /* T: Raise user's talk volume */ -- if (user) -+ if (user) { - tweak_talk_volume(user, VOL_UP); -- else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; - case 116: /* t: Lower user's talk volume */ -- if (user) -+ if (user) { - tweak_talk_volume(user, VOL_DOWN); -- else -+ } else { -+ res = -2; - ast_log(LOG_NOTICE, "Specified User not found!\n"); -+ } - break; -+ case 'E': /* E: Extend conference */ -+ if (rt_extend_conf(args.confno)) { -+ res = -1; -+ } -+ break; - } - - AST_LIST_UNLOCK(&confs); - - dispose_conf(cnf); -- -+ pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK"); -+ - return 0; - } - -@@ -3874,8 +4367,12 @@ - struct ast_flags config_flags = { 0 }; - const char *val; - -- if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) -+ if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) { - return; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n"); -+ return; -+ } - - audio_buffers = DEFAULT_AUDIO_BUFFERS; - -@@ -3884,6 +4381,7 @@ - fuzzystart = 0; - earlyalert = 0; - endalert = 0; -+ extendby = 0; - - /* Logging of participants defaults to ON for compatibility reasons */ - rt_log_members = 1; -@@ -3923,6 +4421,12 @@ - endalert = 0; - } - } -+ if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) { -+ if ((sscanf(val, "%d", &extendby) != 1)) { -+ ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val); -+ extendby = 0; -+ } -+ } - - ast_config_destroy(cfg); - } -@@ -4107,7 +4611,7 @@ - ast_set_flag(&conf_flags, - CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION); - answer_trunk_chan(trunk_ref->chan); -- conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan); -+ conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan); - if (conf) { - conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL); - dispose_conf(conf); -@@ -4117,7 +4621,7 @@ - if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) && - trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) { - ast_str_append(&conf_name, 0, ",K"); -- admin_exec(NULL, conf_name->str); -+ admin_exec(NULL, ast_str_buffer(conf_name)); - trunk_ref->trunk->hold_stations = 0; - sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL); - } -@@ -5709,10 +6213,14 @@ - ast_cond_init(&sla.cond, NULL); - } - -- if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) -+ if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) { - return 0; /* Treat no config as normal */ -- else if (cfg == CONFIG_STATUS_FILEUNCHANGED) -+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - return 0; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n"); -+ return 0; -+ } - - if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid"))) - sla.attempt_callerid = ast_true(val); -@@ -5879,14 +6387,12 @@ - action_meetmeunmute, "Unmute a Meetme user"); - res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING, - action_meetmelist, "List participants in a conference", mandescr_meetmelist); -- res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4); -- res |= ast_register_application(app3, admin_exec, synopsis3, descrip3); -- res |= ast_register_application(app2, count_exec, synopsis2, descrip2); -- res |= ast_register_application(app, conf_exec, synopsis, descrip); -- res |= ast_register_application(slastation_app, sla_station_exec, -- slastation_synopsis, slastation_desc); -- res |= ast_register_application(slatrunk_app, sla_trunk_exec, -- slatrunk_synopsis, slatrunk_desc); -+ res |= ast_register_application_xml(app4, channel_admin_exec); -+ res |= ast_register_application_xml(app3, admin_exec); -+ res |= ast_register_application_xml(app2, count_exec); -+ res |= ast_register_application_xml(app, conf_exec); -+ res |= ast_register_application_xml(slastation_app, sla_station_exec); -+ res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec); - - res |= ast_devstate_prov_add("Meetme", meetmestate); - res |= ast_devstate_prov_add("SLA", sla_state); -Index: apps/app_test.c -=================================================================== ---- a/apps/app_test.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_test.c (.../team/group/issue14292) (revision 178988) -@@ -41,18 +41,41 @@ - #include "asterisk/pbx.h" - #include "asterisk/utils.h" - --static char *tests_descrip = -- " TestServer(): Perform test server function and write call report.\n" -- "Results stored in /var/log/asterisk/testreports/-server.txt"; -+/*** DOCUMENTATION -+ -+ -+ Execute Interface Test Server. -+ -+ -+ -+ Perform test server function and write call report. Results stored in -+ /var/log/asterisk/testreports/<testid>-server.txt -+ -+ -+ TestClient -+ -+ -+ -+ -+ Execute Interface Test Client. -+ -+ -+ -+ An ID to identify this test. -+ -+ -+ -+ Executes test client with given testid. Results stored in -+ /var/log/asterisk/testreports/<testid>-client.txt -+ -+ -+ TestServer -+ -+ -+ ***/ -+ - static char *tests_app = "TestServer"; --static char *tests_synopsis = "Execute Interface Test Server"; -- --static char *testc_descrip = -- " TestClient(testid): Executes test client with given testid.\n" -- "Results stored in /var/log/asterisk/testreports/-client.txt"; -- - static char *testc_app = "TestClient"; --static char *testc_synopsis = "Execute Interface Test Client"; - - static int measurenoise(struct ast_channel *chan, int ms, char *who) - { -@@ -458,8 +481,8 @@ - { - int res; - -- res = ast_register_application(testc_app, testclient_exec, testc_synopsis, testc_descrip); -- res |= ast_register_application(tests_app, testserver_exec, tests_synopsis, tests_descrip); -+ res = ast_register_application_xml(testc_app, testclient_exec); -+ res |= ast_register_application_xml(tests_app, testserver_exec); - - return res; - } -Index: apps/app_morsecode.c -=================================================================== ---- a/apps/app_morsecode.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_morsecode.c (.../team/group/issue14292) (revision 178988) -@@ -34,18 +34,37 @@ - #include "asterisk/module.h" - #include "asterisk/indications.h" - -+/*** DOCUMENTATION -+ -+ -+ Plays morse code. -+ -+ -+ -+ String to playback as morse code to channel -+ -+ -+ -+ Plays the Morse code equivalent of the passed string. -+ -+ This application uses the following variables: -+ -+ -+ Use this value in (ms) for length of dit -+ -+ -+ The pitch of the tone in (Hz), default is 800 -+ -+ -+ -+ -+ SayAlpha -+ SayPhonetic -+ -+ -+ ***/ - static char *app_morsecode = "Morsecode"; - --static char *morsecode_synopsis = "Plays morse code"; -- --static char *morsecode_descrip = --" Morsecode():\n" --"Plays the Morse code equivalent of the passed string. If the variable\n" --"MORSEDITLEN is set, it will use that value for the length (in ms) of the dit\n" --"(defaults to 80). Additionally, if MORSETONE is set, it will use that tone\n" --"(in Hz). The tone default is 800.\n"; -- -- - static char *morsecode[] = { - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 0-15 */ - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 16-31 */ -@@ -159,7 +178,7 @@ - - static int load_module(void) - { -- return ast_register_application(app_morsecode, morsecode_exec, morsecode_synopsis, morsecode_descrip); -+ return ast_register_application_xml(app_morsecode, morsecode_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Morse code"); -Index: apps/app_ices.c -=================================================================== ---- a/apps/app_ices.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_ices.c (.../team/group/issue14292) (revision 178988) -@@ -45,21 +45,30 @@ - #include "asterisk/translate.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Encode and stream using 'ices'. -+ -+ -+ -+ ICES configuration file. -+ -+ -+ -+ Streams to an icecast server using ices (available separately). -+ A configuration file must be supplied for ices (see contrib/asterisk-ices.xml). -+ ICES version 2 cient and server required. -+ -+ -+ -+ ***/ -+ - #define path_BIN "/usr/bin/" - #define path_LOCAL "/usr/local/bin/" - - static char *app = "ICES"; - --static char *synopsis = "Encode and stream using 'ices'"; -- --static char *descrip = --" ICES(config.xml) Streams to an icecast server using ices\n" --"(available separately). A configuration file must be supplied\n" --"for ices (see contrib/asterisk-ices.xml). \n" --"\n" --"- ICES version 2 cient and server required.\n"; -- -- - static int icesencode(char *filename, int fd) - { - int res; -@@ -199,7 +208,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, ices_exec, synopsis, descrip); -+ return ast_register_application_xml(app, ices_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices"); -Index: apps/app_exec.c -=================================================================== ---- a/apps/app_exec.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_exec.c (.../team/group/issue14292) (revision 178988) -@@ -36,6 +36,80 @@ - #include "asterisk/module.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Executes dialplan application. -+ -+ -+ -+ Application name and arguments of the dialplan application to execute. -+ -+ -+ -+ -+ Allows an arbitrary application to be invoked even when not -+ hard coded into the dialplan. If the underlying application -+ terminates the dialplan, or if the application cannot be found, -+ Exec will terminate the dialplan. -+ To invoke external applications, see the application System. -+ If you would like to catch any error instead, see TryExec. -+ -+ -+ -+ -+ Executes dialplan application, always returning. -+ -+ -+ -+ -+ -+ -+ -+ Allows an arbitrary application to be invoked even when not -+ hard coded into the dialplan. To invoke external applications -+ see the application System. Always returns to the dialplan. -+ The channel variable TRYSTATUS will be set to one of: -+ -+ -+ -+ -+ If the application returned zero. -+ -+ -+ If the application returned non-zero. -+ -+ -+ If the application was not found or was not specified. -+ -+ -+ -+ -+ -+ -+ -+ Executes dialplan application, conditionally. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ If expr is true, execute and return the -+ result of appiftrue(args). -+ If expr is true, but appiftrue is not found, -+ then the application will return a non-zero value. -+ -+ -+ ***/ -+ - /* Maximum length of any variable */ - #define MAXRESULT 1024 - -@@ -52,35 +126,8 @@ - */ - - static char *app_exec = "Exec"; --static char *exec_synopsis = "Executes dialplan application"; --static char *exec_descrip = --" Exec(appname(arguments)):\n" --"Allows an arbitrary application to be invoked even when not\n" --"hardcoded into the dialplan. If the underlying application\n" --"terminates the dialplan, or if the application cannot be found,\n" --"Exec will terminate the dialplan.\n" --" To invoke external applications, see the application System.\n" --" If you would like to catch any error instead, see TryExec.\n"; -- - static char *app_tryexec = "TryExec"; --static char *tryexec_synopsis = "Executes dialplan application, always returning"; --static char *tryexec_descrip = --" TryExec(appname(arguments)):\n" --"Allows an arbitrary application to be invoked even when not\n" --"hardcoded into the dialplan. To invoke external applications\n" --"see the application System. Always returns to the dialplan.\n" --"The channel variable TRYSTATUS will be set to one of:\n" --" SUCCESS if the application returned zero\n" --" FAILED if the application returned non-zero\n" --" NOAPP if the application was not found or was not specified\n"; -- - static char *app_execif = "ExecIf"; --static char *execif_synopsis = "Executes dialplan application, conditionally"; --static char *execif_descrip = --" ExecIF (?()[:()])\n" --"If is true, execute and return the result of ().\n" --"If is true, but is not found, then the application\n" --"will return a non-zero value.\n"; - - static int exec_exec(struct ast_channel *chan, void *data) - { -@@ -237,9 +284,9 @@ - - static int load_module(void) - { -- int res = ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip); -- res |= ast_register_application(app_tryexec, tryexec_exec, tryexec_synopsis, tryexec_descrip); -- res |= ast_register_application(app_execif, execif_exec, execif_synopsis, execif_descrip); -+ int res = ast_register_application_xml(app_exec, exec_exec); -+ res |= ast_register_application_xml(app_tryexec, tryexec_exec); -+ res |= ast_register_application_xml(app_execif, execif_exec); - return res; - } - -Index: apps/app_channelredirect.c -=================================================================== ---- a/apps/app_channelredirect.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_channelredirect.c (.../team/group/issue14292) (revision 178988) -@@ -35,14 +35,32 @@ - #include "asterisk/app.h" - #include "asterisk/features.h" - -+/*** DOCUMENTATION -+ -+ -+ Redirects given channel to a dialplan target -+ -+ -+ -+ -+ -+ -+ -+ -+ Sends the specified channel to the specified extension priority -+ -+ This application sets the following channel variables upon completion -+ -+ -+ -+ -+ Are set to the result of the redirection -+ -+ -+ -+ -+ ***/ - static char *app = "ChannelRedirect"; --static char *synopsis = "Redirects given channel to a dialplan target."; --static char *descrip = --"ChannelRedirect(channel,[[context,]extension,]priority)\n" --" Sends the specified channel to the specified extension priority\n" --"This application sets the following channel variables upon completion:\n" --" CHANNELREDIRECT_STATUS - Are set to the result of the redirection\n" --" either NOCHANNEL or SUCCESS\n"; - - static int asyncgoto_exec(struct ast_channel *chan, void *data) - { -@@ -92,7 +110,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, asyncgoto_exec, synopsis, descrip) ? -+ return ast_register_application_xml(app, asyncgoto_exec) ? - AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; - } - -Index: apps/app_forkcdr.c -=================================================================== ---- a/apps/app_forkcdr.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_forkcdr.c (.../team/group/issue14292) (revision 178988) -@@ -37,92 +37,111 @@ - #include "asterisk/app.h" - #include "asterisk/module.h" - -+/*** DOCUMENTATION -+ -+ -+ Forks the Call Data Record. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Causes the Call Data Record to fork an additional cdr record starting from the time -+ of the fork call. This new cdr record will be linked to end of the list of cdr records attached -+ to the channel. The original CDR has a LOCKED flag set, which forces most cdr operations to skip -+ it, except for the functions that set the answer and end times, which ignore the LOCKED flag. This -+ allows all the cdr records in the channel to be 'ended' together when the channel is closed. -+ The CDR() func (when setting CDR values) normally ignores the LOCKED flag also, but has options -+ to vary its behavior. The 'T' option (described below), can override this behavior, but beware -+ the risks. -+ First, this app finds the last cdr record in the list, and makes a copy of it. This new copy -+ will be the newly forked cdr record. Next, this new record is linked to the end of the cdr record list. -+ Next, The new cdr record is RESET (unless you use an option to prevent this) -+ This means that: -+ 1. All flags are unset on the cdr record -+ 2. the start, end, and answer times are all set to zero. -+ 3. the billsec and duration fields are set to zero. -+ 4. the start time is set to the current time. -+ 5. the disposition is set to NULL. -+ Next, unless you specified the v option, all variables will be removed from -+ the original cdr record. Thus, the v option allows any CDR variables to be replicated -+ to all new forked cdr records. Without the v option, the variables on the original -+ are effectively moved to the new forked cdr record. -+ Next, if the s option is set, the provided variable and value are set on the -+ original cdr record. -+ Next, if the a option is given, and the original cdr record has an answer time -+ set, then the new forked cdr record will have its answer time set to its start time. If the old answer -+ time were carried forward, the answer time would be earlier than the start time, giving strange -+ duration and billsec times. -+ If the d option was specified, the disposition is copied from -+ the original cdr record to the new forked cdr. If the D option was specified, -+ the destination channel field in the new forked CDR is erased. If the e option -+ was specified, the 'end' time for the original cdr record is set to the current time. Future hang-up or -+ ending events will not override this time stamp. If the A option is specified, -+ the original cdr record will have it ANS_LOCKED flag set, which prevent future answer events from updating -+ the original cdr record's disposition. Normally, an ANSWERED event would mark all cdr -+ records in the chain as ANSWERED. If the T option is specified, -+ the original cdr record will have its DONT_TOUCH flag set, which will force the -+ cdr_answer, cdr_end, and cdr_setvar functions to leave that cdr record alone. -+ And, last but not least, the original cdr record has its LOCKED flag set. Almost all internal -+ CDR functions (except for the funcs that set the end, and answer times, and set a variable) will honor -+ this flag and leave a LOCKED cdr record alone. This means that the newly created forked cdr record -+ will be affected by events transpiring within Asterisk, with the previously noted exceptions. -+ -+ -+ CDR -+ NoCDR -+ ResetCDR -+ -+ -+ ***/ -+ - static char *app = "ForkCDR"; --static char *synopsis = --"Forks the Call Data Record"; --static char *descrip = --" ForkCDR([options]): Causes the Call Data Record to fork an additional\n" --"cdr record starting from the time of the fork call. This new cdr record will\n" --"be linked to end of the list of cdr records attached to the channel. The original CDR is\n" --"has a LOCKED flag set, which forces most cdr operations to skip it, except\n" --"for the functions that set the answer and end times, which ignore the LOCKED\n" --"flag. This allows all the cdr records in the channel to be 'ended' together\n" --"when the channel is closed.\n" --"The CDR() func (when setting CDR values) normally ignores the LOCKED flag also,\n" --"but has options to vary its behavior. The 'T' option (described below), can\n" --"override this behavior, but beware the risks.\n" --"\n" --"Detailed Behavior Description:\n" --"First, this app finds the last cdr record in the list, and makes\n" --"a copy of it. This new copy will be the newly forked cdr record.\n" --"Next, this new record is linked to the end of the cdr record list.\n" --"Next, The new cdr record is RESET (unless you use an option to prevent this)\n" --"This means that:\n" --" 1. All flags are unset on the cdr record\n" --" 2. the start, end, and answer times are all set to zero.\n" --" 3. the billsec and duration fields are set to zero.\n" --" 4. the start time is set to the current time.\n" --" 5. the disposition is set to NULL.\n" --"Next, unless you specified the 'v' option, all variables will be\n" --"removed from the original cdr record. Thus, the 'v' option allows\n" --"any CDR variables to be replicated to all new forked cdr records.\n" --"Without the 'v' option, the variables on the original are effectively\n" --"moved to the new forked cdr record.\n" --"Next, if the 's' option is set, the provided variable and value\n" --"are set on the original cdr record.\n" --"Next, if the 'a' option is given, and the original cdr record has an\n" --"answer time set, then the new forked cdr record will have its answer\n" --"time set to its start time. If the old answer time were carried forward,\n" --"the answer time would be earlier than the start time, giving strange\n" --"duration and billsec times.\n" --"Next, if the 'd' option was specified, the disposition is copied from\n" --"the original cdr record to the new forked cdr.\n" --"Next, if the 'D' option was specified, the destination channel field\n" --"in the new forked CDR is erased.\n" --"Next, if the 'e' option was specified, the 'end' time for the original\n" --"cdr record is set to the current time. Future hang-up or ending events\n" --"will not override this time stamp.\n" --"Next, If the 'A' option is specified, the original cdr record will have\n" --"it ANS_LOCKED flag set, which prevent future answer events\n" --"from updating the original cdr record's disposition. Normally, an\n" --"'ANSWERED' event would mark all cdr records in the chain as 'ANSWERED'.\n" --"Next, if the 'T' option is specified, the original cdr record will have\n" --"its 'DONT_TOUCH' flag set, which will force the cdr_answer, cdr_end, and\n" --"cdr_setvar functions to leave that cdr record alone.\n" --"And, last but not least, the original cdr record has its LOCKED flag\n" --"set. Almost all internal CDR functions (except for the funcs that set\n" --"the end, and answer times, and set a variable) will honor this flag\n" --"and leave a LOCKED cdr record alone.\n" --"This means that the newly created forked cdr record will affected\n" --"by events transpiring within Asterisk, with the previously noted\n" --"exceptions.\n" --" Options:\n" --" a - update the answer time on the NEW CDR just after it's been inited..\n" --" The new CDR may have been answered already, the reset that forkcdr.\n" --" does will erase the answer time. This will bring it back, but\n" --" the answer time will be a copy of the fork/start time. It will.\n" --" only do this if the initial cdr was indeed already answered..\n" --" A - Lock the original CDR against the answer time being updated.\n" --" This will allow the disposition on the original CDR to remain the same.\n" --" d - Copy the disposition forward from the old cdr, after the .\n" --" init..\n" --" D - Clear the dstchannel on the new CDR after reset..\n" --" e - end the original CDR. Do this after all the necc. data.\n" --" is copied from the original CDR to the new forked CDR..\n" --" R - do NOT reset the new cdr..\n" --" s(name=val) - Set the CDR var 'name' in the original CDR, with value.\n" --" 'val'.\n" --" T - Mark the original CDR with a DONT_TOUCH flag. setvar, answer, and end\n" --" cdr funcs will obey this flag; normally they don't honor the LOCKED\n" --" flag set on the original CDR record.\n" --" Beware-- using this flag may cause CDR's not to have their end times\n" --" updated! It is suggested that if you specify this flag, you might\n" --" wish to use the 'e' flag as well!\n" --" v - When the new CDR is forked, it gets a copy of the vars attached\n" --" to the current CDR. The vars attached to the original CDR are removed\n" --" unless this option is specified.\n"; - -- - enum { - OPT_SETANS = (1 << 0), - OPT_SETDISP = (1 << 1), -@@ -247,7 +266,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, forkcdr_exec, synopsis, descrip); -+ return ast_register_application_xml(app, forkcdr_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities"); -Index: apps/app_skel.c -=================================================================== ---- a/apps/app_skel.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_skel.c (.../team/group/issue14292) (revision 178988) -@@ -14,6 +14,9 @@ - * 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. -+ * -+ * Please follow coding guidelines -+ * http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES - */ - - /*! \file -@@ -41,11 +44,35 @@ - #include "asterisk/lock.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Simple one line explaination. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is a template to build other applications from. -+ It shows you the basic structure to create your own Asterisk applications. -+ -+ -+ ***/ -+ - static char *app = "Skel"; --static char *synopsis = --"Skeleton application."; --static char *descrip = "This application is a template to build other applications from.\n" -- " It shows you the basic structure to create your own Asterisk applications.\n"; - - enum { - OPTION_A = (1 << 0), -@@ -89,20 +116,25 @@ - - AST_STANDARD_APP_ARGS(args, parse); - -- if (args.argc == 2) -+ if (args.argc == 2) { - ast_app_parse_options(app_opts, &flags, opts, args.options); -+ } - -- if (!ast_strlen_zero(args.dummy)) -+ if (!ast_strlen_zero(args.dummy)) { - ast_log(LOG_NOTICE, "Dummy value is : %s\n", args.dummy); -+ } - -- if (ast_test_flag(&flags, OPTION_A)) -+ if (ast_test_flag(&flags, OPTION_A)) { - ast_log(LOG_NOTICE, "Option A is set\n"); -+ } - -- if (ast_test_flag(&flags, OPTION_B)) -+ if (ast_test_flag(&flags, OPTION_B)) { - ast_log(LOG_NOTICE, "Option B is set with : %s\n", opts[OPTION_ARG_B] ? opts[OPTION_ARG_B] : ""); -+ } - -- if (ast_test_flag(&flags, OPTION_C)) -+ if (ast_test_flag(&flags, OPTION_C)) { - ast_log(LOG_NOTICE, "Option C is set with : %s\n", opts[OPTION_ARG_C] ? opts[OPTION_ARG_C] : ""); -+ } - - return res; - } -@@ -114,7 +146,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, app_exec, synopsis, descrip) ? -+ return ast_register_application_xml(app, app_exec) ? - AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; - } - -Index: apps/app_directed_pickup.c -=================================================================== ---- a/apps/app_directed_pickup.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_directed_pickup.c (.../team/group/issue14292) (revision 178988) -@@ -40,35 +40,70 @@ - #include "asterisk/lock.h" - #include "asterisk/app.h" - #include "asterisk/features.h" -+#include "asterisk/callerid.h" - - #define PICKUPMARK "PICKUPMARK" - -+/*** DOCUMENTATION -+ -+ -+ Directed extension call pickup. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application can pickup any ringing channel that is calling -+ the specified extension. If no context -+ is specified, the current context will be used. If you use the special string PICKUPMARK -+ for the context parameter, for example 10@PICKUPMARK, this application -+ tries to find a channel which has defined a PICKUPMARK -+ channel variable with the same value as extension -+ (in this example, 10). When no parameter is specified, the application -+ will pickup a channel matching the pickup group of the active channel. -+ -+ -+ -+ -+ Pickup a ringing channel. -+ -+ -+ -+ -+ -+ -+ This will pickup a specified channel if ringing. -+ -+ -+ ***/ -+ - static const char *app = "Pickup"; --static const char *synopsis = "Directed Call Pickup"; --static const char *descrip = --" Pickup([extension[@context][&extension2@[context]...]]): This application can\n" --"pickup any ringing channel that is calling the specified extension. If no\n" --"context is specified, the current context will be used. If you use the special\n" --"string \"PICKUPMARK\" for the context parameter, for example 10@PICKUPMARK,\n" --"this application tries to find a channel which has defined a ${PICKUPMARK}\n" --"channel variable with the same value as \"extension\" (in this example, \"10\").\n" --"When no parameter is specified, the application will pickup a channel matching\n" --"the pickup group of the active channel."; -- - static const char *app2 = "PickupChan"; --static const char *synopsis2 = "Pickup a ringing channel"; --static const char *descrip2 = --" PickupChan(channel[&channel...]): This application can pickup any ringing channel\n"; -- - /*! \todo This application should return a result code, like PICKUPRESULT */ - - /* Perform actual pickup between two channels */ - static int pickup_do(struct ast_channel *chan, struct ast_channel *target) - { - int res = 0; -+ struct ast_party_connected_line connected_caller; - - ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name); - -+ connected_caller = target->connected; -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_connected_line_update(chan, &connected_caller); -+ -+ ast_party_connected_line_collect_caller(&connected_caller, &chan->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_queue_connected_line_update(chan, &connected_caller); -+ - if ((res = ast_answer(chan))) { - ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); - return -1; -@@ -97,11 +132,17 @@ - } - - /*! \brief Helper Function to walk through ALL channels checking NAME and STATE */ --static struct ast_channel *my_ast_get_channel_by_name_locked(char *channame) -+static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame) - { - struct ast_channel *chan; -- char *chkchan = alloca(strlen(channame) + 2); -+ char *chkchan; -+ size_t channame_len, chkchan_len; - -+ channame_len = strlen(channame); -+ chkchan_len = channame_len + 2; -+ -+ chkchan = alloca(chkchan_len); -+ - /* need to append a '-' for the comparison so we check full channel name, - * i.e SIP/hgc- , use a temporary variable so original stays the same for - * debugging. -@@ -109,11 +150,12 @@ - strcpy(chkchan, channame); - strcat(chkchan, "-"); - -- for (chan = ast_walk_channel_by_name_prefix_locked(NULL, channame, strlen(channame)); -+ for (chan = ast_walk_channel_by_name_prefix_locked(NULL, channame, channame_len); - chan; -- chan = ast_walk_channel_by_name_prefix_locked(chan, channame, strlen(channame))) { -- if (!strncasecmp(chan->name, chkchan, strlen(chkchan)) && can_pickup(chan)) -+ chan = ast_walk_channel_by_name_prefix_locked(chan, channame, channame_len)) { -+ if (!strncasecmp(chan->name, chkchan, chkchan_len) && can_pickup(chan)) { - return chan; -+ } - ast_channel_unlock(chan); - } - return NULL; -@@ -137,45 +179,64 @@ - return res; - } - -+struct pickup_criteria { -+ const char *exten; -+ const char *context; -+}; -+ -+static int find_by_exten(struct ast_channel *c, void *data) -+{ -+ struct pickup_criteria *info = data; -+ -+ return (!strcasecmp(c->macroexten, info->exten) || !strcasecmp(c->exten, info->exten)) && -+ !strcasecmp(c->dialcontext, info->context) && -+ can_pickup(c); -+} -+ - /* Attempt to pick up specified extension with context */ - static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context) - { -- int res = -1; - struct ast_channel *target = NULL; -+ struct pickup_criteria search = { -+ .exten = exten, -+ .context = context, -+ }; - -- while ((target = ast_channel_walk_locked(target))) { -- if ((!strcasecmp(target->macroexten, exten) || !strcasecmp(target->exten, exten)) && -- !strcasecmp(target->dialcontext, context) && -- can_pickup(target)) { -- res = pickup_do(chan, target); -- ast_channel_unlock(target); -- break; -- } -+ target = ast_channel_search_locked(find_by_exten, &search); -+ -+ if (target) { -+ int res = pickup_do(chan, target); - ast_channel_unlock(target); -+ target = NULL; -+ return res; - } - -- return res; -+ return -1; - } - -+static int find_by_mark(struct ast_channel *c, void *data) -+{ -+ const char *mark = data; -+ const char *tmp; -+ -+ return (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) && -+ !strcasecmp(tmp, mark) && -+ can_pickup(c); -+} -+ - /* Attempt to pick up specified mark */ - static int pickup_by_mark(struct ast_channel *chan, const char *mark) - { -- int res = -1; -- const char *tmp = NULL; -- struct ast_channel *target = NULL; -+ struct ast_channel *target = ast_channel_search_locked(find_by_mark, (char *) mark); - -- while ((target = ast_channel_walk_locked(target))) { -- if ((tmp = pbx_builtin_getvar_helper(target, PICKUPMARK)) && -- !strcasecmp(tmp, mark) && -- can_pickup(target)) { -- res = pickup_do(chan, target); -- ast_channel_unlock(target); -- break; -- } -+ if (target) { -+ int res = pickup_do(chan, target); - ast_channel_unlock(target); -+ target = NULL; -+ return res; - } - -- return res; -+ return -1; - } - - /* application entry point for Pickup() */ -@@ -248,8 +309,8 @@ - { - int res; - -- res = ast_register_application(app, pickup_exec, synopsis, descrip); -- res |= ast_register_application(app2, pickupchan_exec, synopsis2, descrip2); -+ res = ast_register_application_xml(app, pickup_exec); -+ res |= ast_register_application_xml(app2, pickupchan_exec); - - return res; - } -Index: apps/app_minivm.c -=================================================================== ---- a/apps/app_minivm.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_minivm.c (.../team/group/issue14292) (revision 178988) -@@ -170,7 +170,238 @@ - #include "asterisk/utils.h" - #include "asterisk/linkedlists.h" - #include "asterisk/callerid.h" -+#include "asterisk/event.h" - -+/*** DOCUMENTATION -+ -+ -+ Receive Mini-Voicemail and forward via e-mail. -+ -+ -+ -+ -+ Voicemail username -+ -+ -+ Voicemail domain -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is part of the Mini-Voicemail system, configured in minivm.conf -+ MiniVM records audio file in configured format and forwards message to e-mail and pager. -+ If there's no user account for that address, a temporary account will be used with default options. -+ The recorded file name and path will be stored in MVM_FILENAME and the duration -+ of the message will be stored in MVM_DURATION -+ If the caller hangs up after the recording, the only way to send the message and clean up is to -+ execute in the h extension. The application will exit if any of the following DTMF digits -+ are received and the requested extension exist in the current context. -+ -+ -+ This is the status of the record operation -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Play Mini-Voicemail prompts. -+ -+ -+ -+ -+ Voicemail username -+ -+ -+ Voicemail domain -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is part of the Mini-Voicemail system, configured in minivm.conf. -+ MinivmGreet() plays default prompts or user specific prompts for an account. -+ Busy and unavailable messages can be choosen, but will be overridden if a temporary -+ message exists for the account. -+ -+ -+ This is the status of the greeting playback. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Notify voicemail owner about new messages. -+ -+ -+ -+ -+ Voicemail username -+ -+ -+ Voicemail domain -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is part of the Mini-Voicemail system, configured in minivm.conf. -+ MiniVMnotify forwards messages about new voicemail to e-mail and pager. If there's no user -+ account for that address, a temporary account will be used with default options (set in -+ minivm.conf). -+ If the channel variable MVM_COUNTER is set, this will be used in the message -+ file name and available in the template for the message. -+ If no template is given, the default email template will be used to send email and default pager -+ template to send paging message (if the user account is configured with a paging address. -+ -+ -+ This is the status of the notification attempt -+ -+ -+ -+ -+ -+ -+ -+ -+ Delete Mini-Voicemail voicemail messages. -+ -+ -+ -+ File to delete -+ -+ -+ -+ This application is part of the Mini-Voicemail system, configured in minivm.conf. -+ It deletes voicemail file set in MVM_FILENAME or given filename. -+ -+ -+ This is the status of the delete operation. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Record account specific messages. -+ -+ -+ -+ -+ Voicemail username -+ -+ -+ Voicemail domain -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application is part of the Mini-Voicemail system, configured in minivm.conf. -+ Use this application to record account specific audio/video messages for busy, unavailable -+ and temporary messages. -+ Account specific directories will be created if they do not exist. -+ -+ -+ This is the result of the attempt to record the specified greeting. -+ FAILED is set if the file can't be created. -+ -+ -+ -+ -+ -+ -+ -+ -+ Send Message Waiting Notification to subscriber(s) of mailbox. -+ -+ -+ -+ -+ Voicemail username -+ -+ -+ Voicemail domain -+ -+ -+ -+ Number of urgent messages in mailbox. -+ -+ -+ Number of new messages in mailbox. -+ -+ -+ Number of old messages in mailbox. -+ -+ -+ -+ This application is part of the Mini-Voicemail system, configured in minivm.conf. -+ MinivmMWI is used to send message waiting indication to any devices whose channels have -+ subscribed to the mailbox passed in the first parameter. -+ -+ -+***/ -+ - #ifndef TRUE - #define TRUE 1 - #endif -@@ -220,95 +451,10 @@ - static char *app_minivm_notify = "MinivmNotify"; /* Notify about voicemail by using one of several methods */ - static char *app_minivm_delete = "MinivmDelete"; /* Notify about voicemail by using one of several methods */ - static char *app_minivm_accmess = "MinivmAccMess"; /* Record personal voicemail messages */ -+static char *app_minivm_mwi = "MinivmMWI"; - --static char *synopsis_minivm_record = "Receive Mini-Voicemail and forward via e-mail"; --static char *descrip_minivm_record = -- " MinivmRecord(username@domain[,options]):\n" -- "This application is part of the Mini-Voicemail system, configured in minivm.conf.\n" -- "MiniVM records audio file in configured format and forwards message to e-mail and pager.\n" -- "If there's no user account for that address, a temporary account will\n" -- "be used with default options.\n" -- "The recorded file name and path will be stored in MVM_FILENAME and the \n" -- "duration of the message will be stored in MVM_DURATION\n" -- "\nNote: If the caller hangs up after the recording, the only way to send\n" -- "the message and clean up is to execute in the \"h\" extension.\n" -- "\nThe application will exit if any of the following DTMF digits are \n" -- "received and the requested extension exist in the current context.\n" -- " 0 - Jump to the 'o' extension in the current dialplan context.\n" -- " * - Jump to the 'a' extension in the current dialplan context.\n" -- "\n" -- "Result is given in channel variable MVM_RECORD_STATUS\n" -- " The possible values are: SUCCESS | USEREXIT | FAILED\n\n" -- " Options:\n" -- " g(#) - Use the specified amount of gain when recording the voicemail\n" -- " message. The units are whole-number decibels (dB).\n" -- "\n"; - --static char *synopsis_minivm_greet = "Play Mini-Voicemail prompts"; --static char *descrip_minivm_greet = -- " MinivmGreet(username@domain[,options]):\n" -- "This application is part of the Mini-Voicemail system, configured in minivm.conf.\n" -- "MinivmGreet() plays default prompts or user specific prompts for an account.\n" -- "Busy and unavailable messages can be choosen, but will be overridden if a temporary\n" -- "message exists for the account.\n" -- "\n" -- "Result is given in channel variable MVM_GREET_STATUS\n" -- " The possible values are: SUCCESS | USEREXIT | FAILED\n\n" -- " Options:\n" -- " b - Play the 'busy' greeting to the calling party.\n" -- " s - Skip the playback of instructions for leaving a message to the\n" -- " calling party.\n" -- " u - Play the 'unavailable greeting.\n" -- "\n"; - --static char *synopsis_minivm_notify = "Notify voicemail owner about new messages."; --static char *descrip_minivm_notify = -- " MinivmNotify(username@domain[,template]):\n" -- "This application is part of the Mini-Voicemail system, configured in minivm.conf.\n" -- "MiniVMnotify forwards messages about new voicemail to e-mail and pager.\n" -- "If there's no user account for that address, a temporary account will\n" -- "be used with default options (set in minivm.conf).\n" -- "The recorded file name and path will be read from MVM_FILENAME and the \n" -- "duration of the message will be accessed from MVM_DURATION (set by MinivmRecord() )\n" -- "If the channel variable MVM_COUNTER is set, this will be used in the\n" -- "message file name and available in the template for the message.\n" -- "If not template is given, the default email template will be used to send email and\n" -- "default pager template to send paging message (if the user account is configured with\n" -- "a paging address.\n" -- "\n" -- "Result is given in channel variable MVM_NOTIFY_STATUS\n" -- " The possible values are: SUCCESS | FAILED\n" -- "\n"; -- --static char *synopsis_minivm_delete = "Delete Mini-Voicemail voicemail messages"; --static char *descrip_minivm_delete = -- " MinivmDelete(filename):\n" -- "This application is part of the Mini-Voicemail system, configured in minivm.conf.\n" -- "It deletes voicemail file set in MVM_FILENAME or given filename.\n" -- "\n" -- "Result is given in channel variable MVM_DELETE_STATUS\n" -- " The possible values are: SUCCESS | FAILED\n" -- " FAILED is set if the file does not exist or can't be deleted.\n" -- "\n"; -- --static char *synopsis_minivm_accmess = "Record account specific messages"; --static char *descrip_minivm_accmess = -- " MinivmAccmess(username@domain,option):\n" -- "This application is part of the Mini-Voicemail system, configured in minivm.conf.\n" -- "Use this application to record account specific audio/video messages for\n" -- "busy, unavailable and temporary messages.\n" -- "Account specific directories will be created if they do not exist.\n" -- "\nThe option selects message to be recorded:\n" -- " u Unavailable\n" -- " b Busy\n" -- " t Temporary (overrides busy and unavailable)\n" -- " n Account name\n" -- "\n" -- "Result is given in channel variable MVM_ACCMESS_STATUS\n" -- " The possible values are: SUCCESS | FAILED\n" -- " FAILED is set if the file can't be created.\n" -- "\n"; -- - enum { - OPT_SILENT = (1 << 0), - OPT_BUSY_GREETING = (1 << 1), -@@ -1621,6 +1767,74 @@ - return res; - } - -+/*! \brief Queue a message waiting event */ -+static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int new, int old) -+{ -+ struct ast_event *event; -+ char *mailbox, *context; -+ -+ mailbox = ast_strdupa(mbx); -+ context = ast_strdupa(ctx); -+ if (ast_strlen_zero(context)) { -+ context = "default"; -+ } -+ -+ if (!(event = ast_event_new(AST_EVENT_MWI, -+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, -+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, -+ AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent), -+ AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old, -+ AST_EVENT_IE_END))) { -+ return; -+ } -+ -+ ast_event_queue_and_cache(event, -+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, -+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, -+ AST_EVENT_IE_END); -+} -+ -+/*! \brief Send MWI using interal Asterisk event subsystem */ -+static int minivm_mwi_exec(struct ast_channel *chan, void *data) -+{ -+ int argc; -+ char *argv[4]; -+ int res = 0; -+ char *tmpptr; -+ char tmp[PATH_MAX]; -+ char *mailbox; -+ char *domain; -+ if (ast_strlen_zero(data)) { -+ ast_log(LOG_ERROR, "Minivm needs at least an account argument \n"); -+ return -1; -+ } -+ tmpptr = ast_strdupa((char *)data); -+ if (!tmpptr) { -+ ast_log(LOG_ERROR, "Out of memory\n"); -+ return -1; -+ } -+ argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv)); -+ if (argc < 4) { -+ ast_log(LOG_ERROR, "%d arguments passed to MiniVM_MWI, need 4.\n", argc); -+ return -1; -+ } -+ ast_copy_string(tmp, argv[0], sizeof(tmp)); -+ mailbox = tmp; -+ domain = strchr(tmp, '@'); -+ if (domain) { -+ *domain = '\0'; -+ domain++; -+ } -+ if (ast_strlen_zero(domain) || ast_strlen_zero(mailbox)) { -+ ast_log(LOG_ERROR, "Need mailbox@context as argument. Sorry. Argument 0 %s\n", argv[0]); -+ return -1; -+ } -+ queue_mwi_event(mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); -+ -+ return res; -+} -+ -+ - /*! \brief Notify voicemail account owners - either generic template or user specific */ - static int minivm_notify_exec(struct ast_channel *chan, void *data) - { -@@ -2174,7 +2388,7 @@ - - global_stats.voicemailaccounts++; - -- ast_debug(2, "MINIVM :: Created account %s@%s - tz %s etemplate %s %s\n", username, domain, ast_strlen_zero(vmu->zonetag) ? "" : vmu->zonetag, ast_strlen_zero(vmu->etemplate) ? "" : vmu->etemplate, realtime ? "(realtime)" : ""); -+ ast_debug(2, "MVM :: Created account %s@%s - tz %s etemplate %s %s\n", username, domain, ast_strlen_zero(vmu->zonetag) ? "" : vmu->zonetag, ast_strlen_zero(vmu->etemplate) ? "" : vmu->etemplate, realtime ? "(realtime)" : ""); - return 0; - } - -@@ -2370,8 +2584,12 @@ - struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; - - cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags); -- if (cfg == CONFIG_STATUS_FILEUNCHANGED) -+ if (cfg == CONFIG_STATUS_FILEUNCHANGED) { - return 0; -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n"); -+ return 0; -+ } - - ast_mutex_lock(&minivmlock); - -@@ -3055,11 +3273,12 @@ - { - int res; - -- res = ast_register_application(app_minivm_record, minivm_record_exec, synopsis_minivm_record, descrip_minivm_record); -- res = ast_register_application(app_minivm_greet, minivm_greet_exec, synopsis_minivm_greet, descrip_minivm_greet); -- res = ast_register_application(app_minivm_notify, minivm_notify_exec, synopsis_minivm_notify, descrip_minivm_notify); -- res = ast_register_application(app_minivm_delete, minivm_delete_exec, synopsis_minivm_delete, descrip_minivm_delete); -- res = ast_register_application(app_minivm_accmess, minivm_accmess_exec, synopsis_minivm_accmess, descrip_minivm_accmess); -+ res = ast_register_application_xml(app_minivm_record, minivm_record_exec); -+ res = ast_register_application_xml(app_minivm_greet, minivm_greet_exec); -+ res = ast_register_application_xml(app_minivm_notify, minivm_notify_exec); -+ res = ast_register_application_xml(app_minivm_delete, minivm_delete_exec); -+ res = ast_register_application_xml(app_minivm_accmess, minivm_accmess_exec); -+ res = ast_register_application_xml(app_minivm_mwi, minivm_mwi_exec); - - ast_custom_function_register(&minivm_account_function); - ast_custom_function_register(&minivm_counter_function); -@@ -3069,7 +3288,7 @@ - if ((res = load_config(0))) - return(res); - -- ast_cli_register_multiple(cli_minivm, sizeof(cli_minivm)/sizeof(cli_minivm[0])); -+ ast_cli_register_multiple(cli_minivm, ARRAY_LEN(cli_minivm)); - - /* compute the location of the voicemail spool directory */ - snprintf(MVM_SPOOL_DIR, sizeof(MVM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR); -@@ -3113,7 +3332,7 @@ - res |= ast_unregister_application(app_minivm_notify); - res |= ast_unregister_application(app_minivm_delete); - res |= ast_unregister_application(app_minivm_accmess); -- ast_cli_unregister_multiple(cli_minivm, sizeof(cli_minivm)/sizeof(cli_minivm[0])); -+ ast_cli_unregister_multiple(cli_minivm, ARRAY_LEN(cli_minivm)); - ast_custom_function_unregister(&minivm_account_function); - ast_custom_function_unregister(&minivm_counter_function); - -Index: apps/app_dumpchan.c -=================================================================== ---- a/apps/app_dumpchan.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_dumpchan.c (.../team/group/issue14292) (revision 178988) -@@ -35,17 +35,33 @@ - #include "asterisk/pbx.h" - #include "asterisk/module.h" - #include "asterisk/channel.h" -+#include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Dump Info About The Calling Channel. -+ -+ -+ -+ Minimun verbose level -+ -+ -+ -+ Displays information on channel and listing of all channel -+ variables. If level is specified, output is only -+ displayed when the verbose level is currently set to that number -+ or greater. -+ -+ -+ NoOp -+ Verbose -+ -+ -+ ***/ -+ - static char *app = "DumpChan"; --static char *synopsis = "Dump Info About The Calling Channel"; --static char *desc = -- " DumpChan([])\n" -- "Displays information on channel and listing of all channel\n" -- "variables. If min_verbose_level is specified, output is only\n" -- "displayed when the verbose level is currently set to that number\n" -- "or greater. \n"; - -- - static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) - { - struct timeval now; -@@ -133,7 +149,7 @@ - - static int dumpchan_exec(struct ast_channel *chan, void *data) - { -- struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX very large! */ -+ struct ast_str *vars = ast_str_thread_get(&global_app_buf, 16); - char info[1024]; - int level = 0; - static char *line = "================================================================================"; -@@ -141,10 +157,11 @@ - if (!ast_strlen_zero(data)) - level = atoi(data); - -- pbx_builtin_serialize_variables(chan, &vars); -- serialize_showchan(chan, info, sizeof(info)); -- if (option_verbose >= level) -- ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, vars->str, line); -+ if (option_verbose >= level) { -+ serialize_showchan(chan, info, sizeof(info)); -+ pbx_builtin_serialize_variables(chan, &vars); -+ ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, ast_str_buffer(vars), line); -+ } - - return 0; - } -@@ -156,7 +173,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, dumpchan_exec, synopsis, desc); -+ return ast_register_application_xml(app, dumpchan_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dump Info About The Calling Channel"); -Index: apps/app_macro.c -=================================================================== ---- a/apps/app_macro.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_macro.c (.../team/group/issue14292) (revision 178988) -@@ -37,66 +37,124 @@ - #include "asterisk/utils.h" - #include "asterisk/lock.h" - -+/*** DOCUMENTATION -+ -+ -+ Macro Implementation. -+ -+ -+ -+ The name of the macro -+ -+ -+ -+ -+ -+ -+ -+ Executes a macro using the context macro-name, -+ jumping to the s extension of that context and executing each step, -+ then returning when the steps end. -+ The calling extension, context, and priority are stored in MACRO_EXTEN, -+ MACRO_CONTEXT and MACRO_PRIORITY respectively. Arguments -+ become ARG1, ARG2, etc in the macro context. -+ If you Goto out of the Macro context, the Macro will terminate and control will be returned -+ at the location of the Goto. -+ If MACRO_OFFSET is set at termination, Macro will attempt to continue -+ at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise. -+ Extensions: While a macro is being executed, it becomes the current context. This means that if -+ a hangup occurs, for instance, that the macro will be searched for an h extension, -+ NOT the context from which the macro was called. So, make sure to define all appropriate extensions -+ in your macro! (Note: AEL does not use macros) -+ Because of the way Macro is implemented (it executes the priorities contained within -+ it via sub-engine), and a fixed per-thread memory stack allowance, macros are limited to 7 levels -+ of nesting (macro calling macro calling macro, etc.); It may be possible that stack-intensive -+ applications in deeply nested macros could cause asterisk to crash earlier than this limit. -+ It is advised that if you need to deeply nest macro calls, that you use the Gosub application -+ (now allows arguments like a Macro) with explict Return() calls instead. -+ -+ -+ MacroExit -+ Goto -+ Gosub -+ -+ -+ -+ -+ Conditional Macro implementation. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Executes macro defined in macroiftrue if -+ expr is true (otherwise macroiffalse -+ if provided) -+ Arguments and return values as in application Macro() -+ -+ -+ GotoIf -+ GosubIf -+ IF -+ -+ -+ -+ -+ Exclusive Macro Implementation. -+ -+ -+ -+ The name of the macro -+ -+ -+ -+ -+ -+ Executes macro defined in the context macro-name. -+ Only one call at a time may run the macro. (we'll wait if another call is busy -+ executing in the Macro) -+ Arguments and return values as in application Macro() -+ -+ -+ Macro -+ -+ -+ -+ -+ Exit from Macro. -+ -+ -+ -+ Causes the currently running macro to exit as if it had -+ ended normally by running out of priorities to execute. -+ If used outside a macro, will likely cause unexpected behavior. -+ -+ -+ Macro -+ -+ -+ ***/ -+ - #define MAX_ARGS 80 - - /* special result value used to force macro exit */ - #define MACRO_EXIT_RESULT 1024 - --static char *descrip = --" Macro(macroname,arg1,arg2...): Executes a macro using the context\n" --"'macro-', jumping to the 's' extension of that context and\n" --"executing each step, then returning when the steps end. \n" --"The calling extension, context, and priority are stored in ${MACRO_EXTEN}, \n" --"${MACRO_CONTEXT} and ${MACRO_PRIORITY} respectively. Arguments become\n" --"${ARG1}, ${ARG2}, etc in the macro context.\n" --"If you Goto out of the Macro context, the Macro will terminate and control\n" --"will be returned at the location of the Goto.\n" --"If ${MACRO_OFFSET} is set at termination, Macro will attempt to continue\n" --"at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n" --"Extensions: While a macro is being executed, it becomes the current context.\n" --" This means that if a hangup occurs, for instance, that the macro\n" --" will be searched for an 'h' extension, NOT the context from which\n" --" the macro was called. So, make sure to define all appropriate\n" --" extensions in your macro! (Note: AEL does not use macros)\n" --"WARNING: Because of the way Macro is implemented (it executes the priorities\n" --" contained within it via sub-engine), and a fixed per-thread\n" --" memory stack allowance, macros are limited to 7 levels\n" --" of nesting (macro calling macro calling macro, etc.); It\n" --" may be possible that stack-intensive applications in deeply nested macros\n" --" could cause asterisk to crash earlier than this limit. It is advised that\n" --" if you need to deeply nest macro calls, that you use the Gosub application\n" --" (now allows arguments like a Macro) with explict Return() calls instead.\n"; -- --static char *if_descrip = --" MacroIf(?macroname_a[,arg1][:macroname_b[,arg1]])\n" --"Executes macro defined in if is true\n" --"(otherwise if provided)\n" --"Arguments and return values as in application Macro()\n"; -- --static char *exclusive_descrip = --" MacroExclusive(macroname,arg1,arg2...):\n" --"Executes macro defined in the context 'macro-macroname'\n" --"Only one call at a time may run the macro.\n" --"(we'll wait if another call is busy executing in the Macro)\n" --"Arguments and return values as in application Macro()\n"; -- --static char *exit_descrip = --" MacroExit():\n" --"Causes the currently running macro to exit as if it had\n" --"ended normally by running out of priorities to execute.\n" --"If used outside a macro, will likely cause unexpected\n" --"behavior.\n"; -- - static char *app = "Macro"; - static char *if_app = "MacroIf"; - static char *exclusive_app = "MacroExclusive"; - static char *exit_app = "MacroExit"; - --static char *synopsis = "Macro Implementation"; --static char *if_synopsis = "Conditional Macro Implementation"; --static char *exclusive_synopsis = "Exclusive Macro Implementation"; --static char *exit_synopsis = "Exit From Macro"; -- - static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); - - struct ast_datastore_info macro_ds_info = { -@@ -553,10 +611,10 @@ - { - int res; - -- res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip); -- res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip); -- res |= ast_register_application(exclusive_app, macroexclusive_exec, exclusive_synopsis, exclusive_descrip); -- res |= ast_register_application(app, macro_exec, synopsis, descrip); -+ res = ast_register_application_xml(exit_app, macro_exit_exec); -+ res |= ast_register_application_xml(if_app, macroif_exec); -+ res |= ast_register_application_xml(exclusive_app, macroexclusive_exec); -+ res |= ast_register_application_xml(app, macro_exec); - - return res; - } -Index: apps/app_sms.c -=================================================================== ---- a/apps/app_sms.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_sms.c (.../team/group/issue14292) (revision 178988) -@@ -53,6 +53,55 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Communicates with SMS service centres and SMS capable analogue phones. -+ -+ -+ -+ The name of the queue used in /var/spool/asterisk/sms -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ SMS handles exchange of SMS data with a call to/from SMS capable phone or SMS PSTN service center. -+ Can send and/or receive SMS messages. Works to ETSI ES 201 912; compatible with BT SMS PSTN service in -+ UK and Telecom Italia in Italy. -+ Typical usage is to use to handle calls from the SMS service centre CLI, or to set up a call using -+ outgoing or manager interface to connect service centre to SMS(). -+ "Messages are processed as per text file message queues. smsq (a separate software) is a command to -+ generate message queues and send messages. -+ The protocol has tight delay bounds. Please use short frames and disable/keep short the -+ jitter buffer on the ATA to make sure that respones (ACK etc.) are received in time. -+ -+ -+ ***/ -+ - /* #define OUTALAW */ /* enable this to output Alaw rather than linear */ - - /* ToDo */ -@@ -68,33 +117,6 @@ - - static char *app = "SMS"; - --static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones"; -- --static char *descrip = -- " SMS(name,[a][s][t][p(d)][r][o],addr,body):\n" -- "SMS handles exchange of SMS data with a call to/from SMS capable\n" -- "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n" -- "Works to ETSI ES 201 912; compatible with BT SMS PSTN service in UK\n" -- "and Telecom Italia in Italy.\n" -- "Typical usage is to use to handle calls from the SMS service centre CLI,\n" -- "or to set up a call using 'outgoing' or manager interface to connect\n" -- "service centre to SMS()\n" -- "name is the name of the queue used in /var/spool/asterisk/sms\n" -- "Arguments:\n" -- " a - answer, i.e. send initial FSK packet.\n" -- " s - act as service centre talking to a phone.\n" -- " t - use protocol 2 (default used is protocol 1).\n" -- " p(N) - set the initial delay to N ms (default is 300).\n" -- " addr and body are a deprecated format to send messages out.\n" -- " r - set the Status Report Request (SRR) bit.\n" -- " o - the body should be coded as octets not 7-bit symbols.\n" -- "Messages are processed as per text file message queues.\n" -- "smsq (a separate software) is a command to generate message\n" -- "queues and send messages.\n" -- "NOTE: the protocol has tight delay bounds. Please use short frames\n" -- "and disable/keep short the jitter buffer on the ATA to make sure that\n" -- "respones (ACK etc.) are received in time.\n"; -- - /* - * 80 samples of a single period of the wave. At 8000 Hz, it means these - * are the samples of a 100 Hz signal. -@@ -2036,7 +2058,7 @@ - } - #endif - snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR); -- return ast_register_application(app, sms_exec, synopsis, descrip); -+ return ast_register_application_xml(app, sms_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler"); -Index: apps/app_verbose.c -=================================================================== ---- a/apps/app_verbose.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_verbose.c (.../team/group/issue14292) (revision 178988) -@@ -33,18 +33,45 @@ - #include "asterisk/channel.h" - - static char *app_verbose = "Verbose"; --static char *verbose_synopsis = "Send arbitrary text to verbose output"; --static char *verbose_descrip = --"Verbose([,])\n" --" level must be an integer value. If not specified, defaults to 0.\n"; -- - static char *app_log = "Log"; --static char *log_synopsis = "Send arbitrary text to a selected log level"; --static char *log_descrip = --"Log(,)\n" --" level must be one of ERROR, WARNING, NOTICE, DEBUG, VERBOSE, DTMF\n"; - -+/*** DOCUMENTATION -+ -+ -+ Send arbitrary text to verbose output. -+ -+ -+ -+ Must be an integer value. If not specified, defaults to 0. -+ -+ -+ Output text message. -+ -+ -+ -+ Sends an arbitrary text message to verbose output. -+ -+ -+ -+ -+ Send arbitrary text to a selected log level. -+ -+ -+ -+ Level must be one of ERROR, WARNING, NOTICE, -+ DEBUG, VERBOSE or DTMF. -+ -+ -+ Output text message. -+ -+ -+ -+ Sends an arbitrary text message to a selected log level. -+ -+ -+ ***/ - -+ - static int verbose_exec(struct ast_channel *chan, void *data) - { - int vsize; -@@ -149,8 +176,8 @@ - { - int res; - -- res = ast_register_application(app_log, log_exec, log_synopsis, log_descrip); -- res |= ast_register_application(app_verbose, verbose_exec, verbose_synopsis, verbose_descrip); -+ res = ast_register_application_xml(app_log, log_exec); -+ res |= ast_register_application_xml(app_verbose, verbose_exec); - - return res; - } -Index: apps/app_voicemail.c -=================================================================== ---- a/apps/app_voicemail.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_voicemail.c (.../team/group/issue14292) (revision 178988) -@@ -47,7 +47,7 @@ - /*** MAKEOPTS - - -- unixodbc -+ generic_odbc - ltdl - IMAP_STORAGE - no -@@ -55,7 +55,7 @@ - - imap_tk - ODBC_STORAGE -- ssl -+ openssl - no - - -@@ -116,6 +116,191 @@ - #endif - - #ifdef IMAP_STORAGE -+#include "asterisk/threadstorage.h" -+#endif -+ -+/*** DOCUMENTATION -+ -+ -+ Leave a Voicemail message. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application allows the calling party to leave a message for the specified -+ list of mailboxes. When multiple mailboxes are specified, the greeting will be taken from -+ the first mailbox specified. Dialplan execution will stop if the specified mailbox does not -+ exist. -+ The Voicemail application will exit if any of the following DTMF digits are received: -+ -+ -+ Jump to the o extension in the current dialplan context. -+ -+ -+ Jump to the a extension in the current dialplan context. -+ -+ -+ This application will set the following channel variable upon completion: -+ -+ -+ This indicates the status of the execution of the VoiceMail application. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Check Voicemail messages. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application allows the calling party to check voicemail messages. A specific -+ mailbox, and optional corresponding context, -+ may be specified. If a mailbox is not provided, the calling party will -+ be prompted to enter one. If a context is not specified, the -+ default context will be used. -+ -+ -+ -+ -+ Check to see if Voicemail mailbox exists. -+ -+ -+ -+ -+ -+ -+ -+ None options. -+ -+ -+ -+ Check to see if the specified mailbox exists. If no voicemail -+ context is specified, the default context -+ will be used. -+ This application will set the following channel variable upon completion: -+ -+ -+ This will contain the status of the execution of the MailboxExists application. -+ Possible values include: -+ -+ -+ -+ -+ -+ -+ -+ -+ Authenticate with Voicemail passwords. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This application behaves the same way as the Authenticate application, but the passwords -+ are taken from voicemail.conf. If the mailbox is -+ specified, only that mailbox's password will be considered valid. If the mailbox -+ is not specified, the channel variable AUTH_MAILBOX will be set with the authenticated -+ mailbox. -+ -+ -+ -+ -+ Tell if a mailbox is configured. -+ -+ -+ -+ -+ -+ -+ Returns a boolean of whether the corresponding mailbox exists. -+ If context is not specified, defaults to the default -+ context. -+ -+ -+ ***/ -+ -+#ifdef IMAP_STORAGE - static char imapserver[48]; - static char imapport[8]; - static char imapflags[128]; -@@ -132,6 +317,8 @@ - struct vm_state; - struct ast_vm_user; - -+AST_THREADSTORAGE(ts_vmstate); -+ - /* Forward declarations for IMAP */ - static int init_mailstream(struct vm_state *vms, int box); - static void write_file(char *filename, char *buffer, unsigned long len); -@@ -375,6 +562,8 @@ - char password[80]; /*!< Secret pin code, numbers only */ - char fullname[80]; /*!< Full name, for directory app */ - char email[80]; /*!< E-mail address */ -+ char *emailsubject; /*!< E-mail subject */ -+ char *emailbody; /*!< E-mail body */ - char pager[80]; /*!< E-mail address to pager (no attachment) */ - char serveremail[80]; /*!< From: Mail address */ - char mailcmd[160]; /*!< Configurable mail command */ -@@ -393,6 +582,7 @@ - #ifdef IMAP_STORAGE - char imapuser[80]; /*!< IMAP server login */ - char imappassword[80]; /*!< IMAP server password if authpassword not defined */ -+ char imapvmshareid[80]; /*!< Shared mailbox ID to use rather than the dialed one */ - #endif - double volgain; /*!< Volume gain for voicemails sent via email */ - AST_LIST_ENTRY(ast_vm_user) list; -@@ -496,77 +686,6 @@ - - static char *addesc = "Comedian Mail"; - --static char *synopsis_vm = "Leave a Voicemail message"; -- --static char *descrip_vm = -- " VoiceMail(mailbox[@context][&mailbox[@context]][...][,options]): This\n" -- "application allows the calling party to leave a message for the specified\n" -- "list of mailboxes. When multiple mailboxes are specified, the greeting will\n" -- "be taken from the first mailbox specified. Dialplan execution will stop if the\n" -- "specified mailbox does not exist.\n" -- " The Voicemail application will exit if any of the following DTMF digits are\n" -- "received:\n" -- " 0 - Jump to the 'o' extension in the current dialplan context.\n" -- " * - Jump to the 'a' extension in the current dialplan context.\n" -- " This application will set the following channel variable upon completion:\n" -- " VMSTATUS - This indicates the status of the execution of the VoiceMail\n" -- " application. The possible values are:\n" -- " SUCCESS | USEREXIT | FAILED\n\n" -- " Options:\n" -- " b - Play the 'busy' greeting to the calling party.\n" -- " d([c]) - Accept digits for a new extension in context c, if played during\n" -- " the greeting. Context defaults to the current context.\n" -- " g(#) - Use the specified amount of gain when recording the voicemail\n" -- " message. The units are whole-number decibels (dB).\n" -- " Only works on supported technologies, which is DAHDI only.\n" -- " s - Skip the playback of instructions for leaving a message to the\n" -- " calling party.\n" -- " u - Play the 'unavailable' greeting.\n" -- " U - Mark message as Urgent.\n" -- " P - Mark message as PRIORITY.\n"; -- --static char *synopsis_vmain = "Check Voicemail messages"; -- --static char *descrip_vmain = -- " VoiceMailMain([mailbox][@context][,options]): This application allows the\n" -- "calling party to check voicemail messages. A specific mailbox, and optional\n" -- "corresponding context, may be specified. If a mailbox is not provided, the\n" -- "calling party will be prompted to enter one. If a context is not specified,\n" -- "the 'default' context will be used.\n\n" -- " Options:\n" -- " p - Consider the mailbox parameter as a prefix to the mailbox that\n" -- " is entered by the caller.\n" -- " g(#) - Use the specified amount of gain when recording a voicemail\n" -- " message. The units are whole-number decibels (dB).\n" -- " s - Skip checking the passcode for the mailbox.\n" -- " a(#) - Skip folder prompt and go directly to folder specified.\n" -- " Defaults to INBOX\n"; -- --static char *synopsis_vm_box_exists = --"Check to see if Voicemail mailbox exists"; -- --static char *descrip_vm_box_exists = -- " MailboxExists(mailbox[@context][,options]): Check to see if the specified\n" -- "mailbox exists. If no voicemail context is specified, the 'default' context\n" -- "will be used.\n" -- " This application will set the following channel variable upon completion:\n" -- " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n" -- " MailboxExists application. Possible values include:\n" -- " SUCCESS | FAILED\n\n" -- " Options: (none)\n"; -- --static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords"; -- --static char *descrip_vmauthenticate = -- " VMAuthenticate([mailbox][@context][,options]): This application behaves the\n" -- "same way as the Authenticate application, but the passwords are taken from\n" -- "voicemail.conf.\n" -- " If the mailbox is specified, only that mailbox's password will be considered\n" -- "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n" -- "be set with the authenticated mailbox.\n\n" -- " Options:\n" -- " s - Skip playing the initial prompts.\n"; -- - /* Leave a message */ - static char *app = "VoiceMail"; - -@@ -744,6 +863,8 @@ - if (maxdeletedmsg) - vmu->maxdeletedmsg = maxdeletedmsg; - vmu->volgain = volgain; -+ vmu->emailsubject = NULL; -+ vmu->emailbody = NULL; - } - - /*! -@@ -772,6 +893,8 @@ - ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser)); - } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) { - ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword)); -+ } else if (!strcasecmp(var, "imapvmshareid")) { -+ ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid)); - #endif - } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) { - ast_set2_flag(vmu, ast_true(value), VM_DELETE); -@@ -947,7 +1070,7 @@ - if (strlen(password) > 10) { - ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL); - } -- res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, SENTINEL); -+ res = ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL); - if (res > 0) { - ast_copy_string(vmu->password, password, sizeof(vmu->password)); - res = 0; -@@ -983,34 +1106,37 @@ - */ - static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var) - { -- struct ast_variable *tmp; -- tmp = var; -- while (tmp) { -- if (!strcasecmp(tmp->name, "vmsecret")) { -- ast_copy_string(retval->password, tmp->value, sizeof(retval->password)); -- } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) { /* don't overwrite vmsecret if it exists */ -+ for (; var; var = var->next) { -+ if (!strcasecmp(var->name, "vmsecret")) { -+ ast_copy_string(retval->password, var->value, sizeof(retval->password)); -+ } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) { /* don't overwrite vmsecret if it exists */ - if (ast_strlen_zero(retval->password)) -- ast_copy_string(retval->password, tmp->value, sizeof(retval->password)); -- } else if (!strcasecmp(tmp->name, "uniqueid")) { -- ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid)); -- } else if (!strcasecmp(tmp->name, "pager")) { -- ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager)); -- } else if (!strcasecmp(tmp->name, "email")) { -- ast_copy_string(retval->email, tmp->value, sizeof(retval->email)); -- } else if (!strcasecmp(tmp->name, "fullname")) { -- ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname)); -- } else if (!strcasecmp(tmp->name, "context")) { -- ast_copy_string(retval->context, tmp->value, sizeof(retval->context)); -+ ast_copy_string(retval->password, var->value, sizeof(retval->password)); -+ } else if (!strcasecmp(var->name, "uniqueid")) { -+ ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid)); -+ } else if (!strcasecmp(var->name, "pager")) { -+ ast_copy_string(retval->pager, var->value, sizeof(retval->pager)); -+ } else if (!strcasecmp(var->name, "email")) { -+ ast_copy_string(retval->email, var->value, sizeof(retval->email)); -+ } else if (!strcasecmp(var->name, "fullname")) { -+ ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname)); -+ } else if (!strcasecmp(var->name, "context")) { -+ ast_copy_string(retval->context, var->value, sizeof(retval->context)); -+ } else if (!strcasecmp(var->name, "emailsubject")) { -+ retval->emailsubject = ast_strdup(var->value); -+ } else if (!strcasecmp(var->name, "emailbody")) { -+ retval->emailbody = ast_strdup(var->value); - #ifdef IMAP_STORAGE -- } else if (!strcasecmp(tmp->name, "imapuser")) { -- ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser)); -- } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) { -- ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword)); -+ } else if (!strcasecmp(var->name, "imapuser")) { -+ ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser)); -+ } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) { -+ ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword)); -+ } else if (!strcasecmp(var->name, "imapvmshareid")) { -+ ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid)); - #endif - } else -- apply_option(retval, tmp->name, tmp->value); -- tmp = tmp->next; -- } -+ apply_option(retval, var->name, var->value); -+ } - } - - /*! -@@ -1158,7 +1284,7 @@ - return; - - /* check voicemail.conf */ -- if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags))) { -+ if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) { - while ((category = ast_category_browse(cfg, category))) { - if (!strcasecmp(category, vmu->context)) { - if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) { -@@ -1182,13 +1308,13 @@ - /* save the results */ - reset_user_pw(vmu->context, vmu->mailbox, newpassword); - ast_copy_string(vmu->password, newpassword, sizeof(vmu->password)); -- config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail"); -+ ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail"); - } - category = NULL; - var = NULL; - /* check users.conf and update the password stored for the mailbox*/ - /* if no vmsecret entry exists create one. */ -- if ((cfg = ast_config_load("users.conf", config_flags))) { -+ if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) { - ast_debug(4, "we are looking for %s\n", vmu->mailbox); - while ((category = ast_category_browse(cfg, category))) { - ast_debug(4, "users.conf: %s\n", category); -@@ -1212,7 +1338,7 @@ - /* save the results and clean things up */ - reset_user_pw(vmu->context, vmu->mailbox, newpassword); - ast_copy_string(vmu->password, newpassword, sizeof(vmu->password)); -- config_text_file_save("users.conf", cfg, "AppVoicemail"); -+ ast_config_text_file_save("users.conf", cfg, "AppVoicemail"); - } - } - -@@ -1314,13 +1440,22 @@ - "Deleted", - "Urgent" - }; -- return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown"; -+ return (id >= 0 && id < ARRAY_LEN(msgs)) ? msgs[id] : "Unknown"; - } - - static void free_user(struct ast_vm_user *vmu) - { -- if (ast_test_flag(vmu, VM_ALLOCED)) -+ if (ast_test_flag(vmu, VM_ALLOCED)) { -+ if (vmu->emailbody != NULL) { -+ ast_free(vmu->emailbody); -+ vmu->emailbody = NULL; -+ } -+ if (vmu->emailsubject != NULL) { -+ ast_free(vmu->emailsubject); -+ vmu->emailsubject = NULL; -+ } - ast_free(vmu); -+ } - } - - /* All IMAP-specific functions should go in this block. This -@@ -1668,7 +1803,7 @@ - if (ret == 0) { - ast_mutex_lock(&vms_p->lock); - pgm = mail_newsearchpgm (); -- hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox); -+ hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox)); - pgm->header = hdr; - if (fold != 1) { - pgm->unseen = 1; -@@ -2115,7 +2250,7 @@ - pgm = mail_newsearchpgm(); - - /* Check IMAP folder for Asterisk messages only... */ -- hdr = mail_newsearchheader("X-Asterisk-VM-Extension", vmu->mailbox); -+ hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox)); - pgm->header = hdr; - pgm->deleted = 0; - pgm->undeleted = 1; -@@ -2384,7 +2519,7 @@ - pquota = pquota->next; - } - -- if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 2))) { -+ if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) { - ast_log(AST_LOG_ERROR, "No state found.\n"); - return; - } -@@ -2447,6 +2582,9 @@ - { - struct vm_state *vms_p; - -+ if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) { -+ return vms_p; -+ } - if (option_debug > 4) - ast_log(AST_LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser); - if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) -@@ -2469,6 +2607,12 @@ - { - struct vmstate *vlist = NULL; - -+ if (interactive) { -+ struct vm_state *vms; -+ vms = pthread_getspecific(ts_vmstate.key); -+ return vms; -+ } -+ - AST_LIST_LOCK(&vmstates); - AST_LIST_TRAVERSE(&vmstates, vlist, list) { - if (!vlist->vms) { -@@ -2498,6 +2642,12 @@ - struct vmstate *vlist = NULL; - const char *local_context = S_OR(context, "default"); - -+ if (interactive) { -+ struct vm_state *vms; -+ vms = pthread_getspecific(ts_vmstate.key); -+ return vms; -+ } -+ - AST_LIST_LOCK(&vmstates); - AST_LIST_TRAVERSE(&vmstates, vlist, list) { - if (!vlist->vms) { -@@ -2544,9 +2694,13 @@ - /* get a pointer to the persistent store */ - vms->persist_vms = altvms; - /* Reuse the mailstream? */ -+#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS - vms->mailstream = altvms->mailstream; -- /* vms->mailstream = NIL; */ -+#else -+ vms->mailstream = NIL; -+#endif - } -+ return; - } - - if (!(v = ast_calloc(1, sizeof(*v)))) -@@ -2573,6 +2727,10 @@ - altvms->newmessages = vms->newmessages; - altvms->oldmessages = vms->oldmessages; - altvms->updated = 1; -+ vms->mailstream = mail_close(vms->mailstream); -+ -+ /* Interactive states are not stored within the persistent list */ -+ return; - } - - ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username); -@@ -3212,7 +3370,7 @@ - res = -1; - break; - } -- if (cfg) { -+ if (cfg && cfg != CONFIG_STATUS_FILEINVALID) { - if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) { - idata.context = ""; - } -@@ -3945,10 +4103,11 @@ - } else { - fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email); - } -- if (!ast_strlen_zero(emailsubject)) { -+ if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) { -+ char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject; - struct ast_channel *ast; - if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) { -- int vmlen = strlen(emailsubject) * 3 + 200; -+ int vmlen = strlen(e_subj) * 3 + 200; - /* Only allocate more space if the previous was not large enough */ - if (vmlen > len_passdata) { - passdata = alloca(vmlen); -@@ -3957,7 +4116,7 @@ - - memset(passdata, 0, len_passdata); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, len_passdata, category, flag); -- pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata); -+ pbx_substitute_variables_helper(ast, e_subj, passdata, len_passdata); - if (check_mime(passdata)) { - int first_line = 1; - char *ptr; -@@ -3997,8 +4156,12 @@ - /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */ - fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring); - fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context); -+#ifdef IMAP_STORAGE -+ fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox)); -+#else - fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox); -- /* flag added for Urgent */ -+#endif -+ /* flag added for Urgent */ - fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag); - fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority); - fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name); -@@ -4030,15 +4193,16 @@ - fprintf(p, "--%s" ENDL, bound); - } - fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset); -- if (emailbody) { -+ if (emailbody || vmu->emailbody) { -+ char* e_body = vmu->emailbody ? vmu->emailbody : emailbody; - struct ast_channel *ast; - if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) { - char *passdata; -- int vmlen = strlen(emailbody)*3 + 200; -+ int vmlen = strlen(e_body) * 3 + 200; - passdata = alloca(vmlen); - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category, flag); -- pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen); -+ pbx_substitute_variables_helper(ast, e_body, passdata, vmlen); - fprintf(p, "%s" ENDL, passdata); - ast_channel_free(ast); - } else -@@ -4784,8 +4948,6 @@ - int ausemacro = 0; - int ousemacro = 0; - int ouseexten = 0; -- int rtmsgid = 0; -- char tmpid[16]; - char tmpdur[16]; - char priority[16]; - char origtime[16]; -@@ -5078,7 +5240,7 @@ - snprintf(priority, sizeof(priority), "%d", chan->priority); - snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL)); - get_date(date, sizeof(date)); -- rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", S_OR(category,""), SENTINEL); -+ ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", S_OR(category,""), "filename", tmptxtfile, SENTINEL); - } - - /* Store information */ -@@ -5122,8 +5284,7 @@ - ast_filedelete(tmptxtfile, NULL); - unlink(tmptxtfile); - if (ast_check_realtime("voicemail_data")) { -- snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); -- ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL); -+ ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL); - } - } else { - fprintf(txt, "duration=%d\n", duration); -@@ -5138,8 +5299,7 @@ - unlink(tmptxtfile); - ast_unlock_path(dir); - if (ast_check_realtime("voicemail_data")) { -- snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); -- ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL); -+ ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL); - } - } else { - #ifndef IMAP_STORAGE -@@ -5165,9 +5325,8 @@ - - ast_unlock_path(dir); - if (ast_check_realtime("voicemail_data")) { -- snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); - snprintf(tmpdur, sizeof(tmpdur), "%d", duration); -- ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, SENTINEL); -+ ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL); - } - /* We must store the file first, before copying the message, because - * ODBC storage does the entire copy with SQL. -@@ -5277,9 +5436,12 @@ - - ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box)); - ast_mutex_lock(&vms->lock); -+ /* if save to Old folder, put in INBOX as read */ - if (box == OLD_FOLDER) { - mail_setflag(vms->mailstream, sequence, "\\Seen"); -+ mail_clearflag(vms->mailstream, sequence, "\\Unseen"); - } else if (box == NEW_FOLDER) { -+ mail_setflag(vms->mailstream, sequence, "\\Unseen"); - mail_clearflag(vms->mailstream, sequence, "\\Seen"); - } - if (!strcasecmp(mbox(NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) { -@@ -5926,7 +6088,7 @@ - strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1); - strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1); - -- if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) { -+ if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) { - *duration = atoi(duration_str); - } else { - *duration = 0; -@@ -5988,7 +6150,7 @@ - msg_cat = ast_category_get(msg_cfg, "message"); - snprintf(duration_buf, 11, "%ld", *duration); - if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) { -- config_text_file_save(textfile, msg_cfg, "app_voicemail"); -+ ast_config_text_file_save(textfile, msg_cfg, "app_voicemail"); - } - } - -@@ -6641,7 +6803,7 @@ - snprintf(filename, sizeof(filename), "%s.txt", vms->fn); - RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context); - msg_cfg = ast_config_load(filename, config_flags); -- if (!msg_cfg) { -+ if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename); - return 0; - } -@@ -8778,9 +8940,13 @@ - adsi_begin(chan, &useadsi); - - #ifdef IMAP_STORAGE -+ pthread_once(&ts_vmstate.once, ts_vmstate.key_init); -+ pthread_setspecific(ts_vmstate.key, &vms); -+ - vms.interactive = 1; - vms.updated = 1; -- ast_copy_string(vms.context, vmu->context, sizeof(vms.context)); -+ if (vmu) -+ ast_copy_string(vms.context, vmu->context, sizeof(vms.context)); - vmstate_insert(&vms); - init_vm_state(&vms); - #endif -@@ -9347,6 +9513,9 @@ - if (vms.heard) - ast_free(vms.heard); - -+#ifdef IMAP_STORAGE -+ pthread_setspecific(ts_vmstate.key, NULL); -+#endif - return res; - } - -@@ -9525,17 +9694,17 @@ - - AST_NONSTANDARD_APP_ARGS(arg, args, '@'); - -+ if (ast_strlen_zero(arg.mbox)) { -+ ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument ([@])\n"); -+ return -1; -+ } -+ - ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len); - return 0; - } - - static struct ast_custom_function mailbox_exists_acf = { - .name = "MAILBOX_EXISTS", -- .synopsis = "Tell if a mailbox is configured", -- .desc = --"Returns a boolean of whether the corresponding mailbox exists. If context\n" --"is not specified, defaults to the \"default\" context.\n", -- .syntax = "MAILBOX_EXISTS([@])", - .read = acf_mailbox_exists, - }; - -@@ -10087,13 +10256,15 @@ - AST_LIST_UNLOCK(&zones); - } - --static char *substitute_escapes(const char *value) -+static const char *substitute_escapes(const char *value) - { -- char *current, *result; -+ char *current; - - /* Add 16 for fudge factor */ -- struct ast_str *str = ast_str_create(strlen(value) + 16); -+ struct ast_str *str = ast_str_thread_get(&global_app_buf, strlen(value) + 16); - -+ ast_str_reset(str); -+ - /* Substitute strings \r, \n, and \t into the appropriate characters */ - for (current = (char *) value; *current; current++) { - if (*current == '\\') { -@@ -10126,10 +10297,7 @@ - } - } - -- result = ast_strdup(str->str); -- ast_free(str); -- -- return result; -+ return ast_str_buffer(str); - } - - static int load_config(int reload) -@@ -10148,13 +10316,27 @@ - ast_unload_realtime("voicemail_data"); - - if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { -- if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) -+ if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { - return 0; -+ } else if (ucfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n"); -+ ucfg = NULL; -+ } - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags); -+ if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_config_destroy(ucfg); -+ ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n"); -+ return 0; -+ } -+ } else if (cfg == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n"); -+ return 0; - } else { - ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED); -- ucfg = ast_config_load("users.conf", config_flags); -+ if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) { -+ ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n"); -+ ucfg = NULL; -+ } - } - #ifdef IMAP_STORAGE - ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder)); -@@ -10735,13 +10917,13 @@ - emailsubject = ast_strdup(val); - } - if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) { -- emailbody = substitute_escapes(val); -+ emailbody = ast_strdup(substitute_escapes(val)); - } - if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) { - pagersubject = ast_strdup(val); - } - if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) { -- pagerbody = substitute_escapes(val); -+ pagerbody = ast_strdup(substitute_escapes(val)); - } - AST_LIST_UNLOCK(&users); - ast_config_destroy(cfg); -@@ -10790,7 +10972,7 @@ - res |= ast_unregister_application(app4); - res |= ast_custom_function_unregister(&mailbox_exists_acf); - res |= ast_manager_unregister("VoicemailUsersList"); -- ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry)); -+ ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail)); - ast_uninstall_vm_functions(); - - if (poll_thread != AST_PTHREADT_NULL) -@@ -10821,16 +11003,16 @@ - if ((res = load_config(0))) - return res; - -- res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm); -- res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain); -- res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists); -- res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate); -+ res = ast_register_application_xml(app, vm_exec); -+ res |= ast_register_application_xml(app2, vm_execmain); -+ res |= ast_register_application_xml(app3, vm_box_exists); -+ res |= ast_register_application_xml(app4, vmauthenticate); - res |= ast_custom_function_register(&mailbox_exists_acf); - res |= ast_manager_register("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users, "List All Voicemail User Information"); - if (res) - return res; - -- ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry)); -+ ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail)); - - ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname); - ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL); -@@ -10931,7 +11113,7 @@ - RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context); - msg_cfg = ast_config_load(filename, config_flags); - DISPOSE(vms->curdir, vms->curmsg); -- if (!msg_cfg) { -+ if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename); - return 0; - } -Index: apps/app_dial.c -=================================================================== ---- a/apps/app_dial.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_dial.c (.../team/group/issue14292) (revision 178988) -@@ -62,204 +62,417 @@ - #include "asterisk/global_datastores.h" - #include "asterisk/dsp.h" - --static char *app = "Dial"; -+/*** DOCUMENTATION -+ -+ -+ Attempt to connect to another device or endpoint and bridge the call. -+ -+ -+ -+ -+ Specification of the device(s) to dial. These must be in the format of -+ Technology/Resource, where Technology -+ represents a particular channel driver, and Resource -+ represents a resource available to that particular channel driver. -+ -+ -+ Optional extra devices to dial in parallel -+ If you need more then one enter them as -+ Technology2/Resource2&Technology3/Resourse3&..... -+ -+ -+ -+ Specifies the number of seconds we attempt to dial the specified devices -+ If not specified, this defaults to 136 years. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ The optional URL will be sent to the called party if the channel driver supports it. -+ -+ -+ -+ This application will place calls to one or more specified channels. As soon -+ as one of the requested channels answers, the originating channel will be -+ answered, if it has not already been answered. These two channels will then -+ be active in a bridged call. All other channels that were requested will then -+ be hung up. - --static char *synopsis = "Place a call and connect to the current channel"; -+ Unless there is a timeout specified, the Dial application will wait -+ indefinitely until one of the called channels answers, the user hangs up, or -+ if all of the called channels are busy or unavailable. Dialplan executing will -+ continue if no requested channels can be called, or if the timeout expires. -+ This application will report normal termination if the originating channel -+ hangs up, or if the call is bridged and either of the parties in the bridge -+ ends the call. -+ If the OUTBOUND_GROUP variable is set, all peer channels created by this -+ application will be put into that group (as in Set(GROUP()=...). -+ If the OUTBOUND_GROUP_ONCE variable is set, all peer channels created by this -+ application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP, -+ however, the variable will be unset after use. - --static char *descrip = --" Dial(Technology/resource[&Tech2/resource2...][,timeout][,options][,URL]):\n" --"This application will place calls to one or more specified channels. As soon\n" --"as one of the requested channels answers, the originating channel will be\n" --"answered, if it has not already been answered. These two channels will then\n" --"be active in a bridged call. All other channels that were requested will then\n" --"be hung up.\n" --" Unless there is a timeout specified, the Dial application will wait\n" --"indefinitely until one of the called channels answers, the user hangs up, or\n" --"if all of the called channels are busy or unavailable. Dialplan executing will\n" --"continue if no requested channels can be called, or if the timeout expires.\n\n" --" This application sets the following channel variables upon completion:\n" --" DIALEDTIME - This is the time from dialing a channel until when it\n" --" is disconnected.\n" --" ANSWEREDTIME - This is the amount of time for actual call.\n" --" DIALSTATUS - This is the status of the call:\n" --" CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n" --" DONTCALL | TORTURE | INVALIDARGS\n" --" For the Privacy and Screening Modes, the DIALSTATUS variable will be set to\n" --"DONTCALL if the called party chooses to send the calling party to the 'Go Away'\n" --"script. The DIALSTATUS variable will be set to TORTURE if the called party\n" --"wants to send the caller to the 'torture' script.\n" --" This application will report normal termination if the originating channel\n" --"hangs up, or if the call is bridged and either of the parties in the bridge\n" --"ends the call.\n" --" The optional URL will be sent to the called party if the channel supports it.\n" --" If the OUTBOUND_GROUP variable is set, all peer channels created by this\n" --"application will be put into that group (as in Set(GROUP()=...).\n" --" If the OUTBOUND_GROUP_ONCE variable is set, all peer channels created by this\n" --"application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP,\n" --"however, the variable will be unset after use.\n\n" --" Options:\n" --" A(x) - Play an announcement to the called party, using 'x' as the file.\n" --" C - Reset the CDR for this call.\n" --" c - If DIAL cancels this call, always set the flag to tell the channel\n" --" driver that the call is answered elsewhere.\n" --" d - Allow the calling user to dial a 1 digit extension while waiting for\n" --" a call to be answered. Exit to that extension if it exists in the\n" --" current context, or the context defined in the EXITCONTEXT variable,\n" --" if it exists.\n" --" D([called][:calling]) - Send the specified DTMF strings *after* the called\n" --" party has answered, but before the call gets bridged. The 'called'\n" --" DTMF string is sent to the called party, and the 'calling' DTMF\n" --" string is sent to the calling party. Both parameters can be used\n" --" alone.\n" --" e - execute the 'h' extension for peer after the call ends. This\n" --" operation will not be performed if the peer was parked\n" --" f - Force the callerid of the *calling* channel to be set as the\n" --" extension associated with the channel using a dialplan 'hint'.\n" --" For example, some PSTNs do not allow CallerID to be set to anything\n" --" other than the number assigned to the caller.\n" --" F(context^exten^pri) - When the caller hangs up, transfer the called party\n" --" to the specified context and extension and continue execution.\n" --" g - Proceed with dialplan execution at the current extension if the\n" --" destination channel hangs up.\n" --" G(context^exten^pri) - If the call is answered, transfer the calling party to\n" --" the specified priority and the called party to the specified priority+1.\n" --" Optionally, an extension, or extension and context may be specified. \n" --" Otherwise, the current extension is used. You cannot use any additional\n" --" action post answer options in conjunction with this option.\n" --" h - Allow the called party to hang up by sending the '*' DTMF digit, or\n" --" whatever sequence was defined in the featuremap section for\n" --" 'disconnect' in features.conf\n" --" H - Allow the calling party to hang up by hitting the '*' DTMF digit, or\n" --" whatever sequence was defined in the featuremap section for\n" --" 'disconnect' in features.conf\n" --" i - Asterisk will ignore any forwarding requests it may receive on this\n" --" dial attempt.\n" --" k - Allow the called party to enable parking of the call by sending\n" --" the DTMF sequence defined for call parking in the featuremap section of features.conf.\n" --" K - Allow the calling party to enable parking of the call by sending\n" --" the DTMF sequence defined for call parking in the featuremap section of features.conf.\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" --" * LIMIT_PLAYAUDIO_CALLER yes|no (default yes)\n" --" Play sounds to the caller.\n" --" * LIMIT_PLAYAUDIO_CALLEE yes|no\n" --" Play sounds to the callee.\n" --" * LIMIT_TIMEOUT_FILE File to play when time is up.\n" --" * LIMIT_CONNECT_FILE File to play when call begins.\n" --" * LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n" --" The default is to say the time remaining.\n" --" m([class]) - Provide hold music to the calling party until a requested\n" --" channel answers. A specific MusicOnHold class can be\n" --" specified.\n" --" M(x[^arg]) - Execute the Macro for the *called* channel before connecting\n" --" to the calling channel. Arguments can be specified to the Macro\n" --" using '^' as a delimiter. The Macro can set the variable\n" --" MACRO_RESULT to specify the following actions after the Macro is\n" --" finished executing.\n" --" * ABORT Hangup both legs of the call.\n" --" * CONGESTION Behave as if line congestion was encountered.\n" --" * BUSY Behave as if a busy signal was encountered.\n" --" * CONTINUE Hangup the called party and allow the calling party\n" --" to continue dialplan execution at the next priority.\n" --" * GOTO:^^ - Transfer the call to the\n" --" specified priority. Optionally, an extension, or\n" --" extension and priority can be specified.\n" --" You cannot use any additional action post answer options in conjunction\n" --" with this option. Also, pbx services are not run on the peer (called) channel,\n" --" so you will not be able to set timeouts via the TIMEOUT() function in this macro.\n" --" n - This option is a modifier for the screen/privacy mode. It specifies\n" --" that no introductions are to be saved in the priv-callerintros\n" --" directory.\n" --" N - This option is a modifier for the screen/privacy mode. It specifies\n" --" that if callerID is present, do not screen the call.\n" --" o - Specify that the CallerID that was present on the *calling* channel\n" --" be set as the CallerID on the *called* channel. This was the\n" --" behavior of Asterisk 1.0 and earlier.\n" --" O([x]) - \"Operator Services\" mode (DAHDI channel to DAHDI channel\n" --" only, if specified on non-DAHDI interface, it will be ignored).\n" --" When the destination answers (presumably an operator services\n" --" station), the originator no longer has control of their line.\n" --" They may hang up, but the switch will not release their line\n" --" until the destination party hangs up (the operator). Specified\n" --" without an arg, or with 1 as an arg, the originator hanging up\n" --" will cause the phone to ring back immediately. With a 2 specified,\n" --" when the \"operator\" flashes the trunk, it will ring their phone\n" --" back.\n" --" p - This option enables screening mode. This is basically Privacy mode\n" --" without memory.\n" --" P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n" --" it is provided. The current extension is used if a database\n" --" 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" --" S(x) - Hang up the call after 'x' seconds *after* the called party has\n" --" answered the call.\n" --" t - Allow the called party to transfer the calling party by sending the\n" --" DTMF sequence defined in the blindxfer setting in the featuremap section\n" --" of features.conf.\n" --" T - Allow the calling party to transfer the called party by sending the\n" --" DTMF sequence defined in the blindxfer setting in the featuremap section\n" --" of features.conf.\n" --" U(x[^arg]) - Execute via Gosub the routine 'x' for the *called* channel before connecting\n" --" to the calling channel. Arguments can be specified to the Gosub\n" --" using '^' as a delimiter. The Gosub routine can set the variable\n" --" GOSUB_RESULT to specify the following actions after the Gosub returns.\n" --" * ABORT Hangup both legs of the call.\n" --" * CONGESTION Behave as if line congestion was encountered.\n" --" * BUSY Behave as if a busy signal was encountered.\n" --" * CONTINUE Hangup the called party and allow the calling party\n" --" to continue dialplan execution at the next priority.\n" --" * GOTO:^^ - Transfer the call to the\n" --" specified priority. Optionally, an extension, or\n" --" extension and priority can be specified.\n" --" You cannot use any additional action post answer options in conjunction\n" --" with this option. Also, pbx services are not run on the peer (called) channel,\n" --" so you will not be able to set timeouts via the TIMEOUT() function in this routine.\n" --" w - Allow the called party to enable recording of the call by sending\n" --" the DTMF sequence defined in the automon setting in the featuremap section\n" --" of features.conf.\n" --" W - Allow the calling party to enable recording of the call by sending\n" --" the DTMF sequence defined in the automon setting in the featuremap section\n" --" of features.conf.\n" --" x - Allow the called party to enable recording of the call by sending\n" --" the DTMF sequence defined in the automixmon setting in the featuremap section\n" --" of features.conf.\n" --" X - Allow the calling party to enable recording of the call by sending\n" --" the DTMF sequence defined in the automixmon setting in the featuremap section\n" --" of features.conf.\n"; -+ This application sets the following channel variables: -+ -+ -+ This is the time from dialing a channel until when it is disconnected. -+ -+ -+ This is the amount of time for actual call. -+ -+ -+ This is the status of the call -+ -+ -+ -+ -+ -+ -+ -+ For the Privacy and Screening Modes. -+ Will be set if the called party chooses to send the calling party to the 'Go Away' script. -+ -+ -+ For the Privacy and Screening Modes. -+ Will be set if the called party chooses to send the calling party to the 'torture' script. -+ -+ -+ -+ -+ -+ -+ -+ -+ Place a call, retrying on failure allowing an optional exit extension. -+ -+ -+ -+ Filename of sound that will be played when no channel can be reached -+ -+ -+ Number of seconds to wait after a dial attempt failed before a new attempt is made -+ -+ -+ Number of retries -+ When this is reached flow will continue at the next priority in the dialplan -+ -+ -+ Same format as arguments provided to the Dial application -+ -+ -+ -+ This application will attempt to place a call using the normal Dial application. -+ If no channel can be reached, the announce file will be played. -+ Then, it will wait sleep number of seconds before retrying the call. -+ After retries number of attempts, the calling channel will continue at the next priority in the dialplan. -+ If the retries setting is set to 0, this application will retry endlessly. -+ While waiting to retry a call, a 1 digit extension may be dialed. If that -+ extension exists in either the context defined in EXITCONTEXT or the current -+ one, The call will jump to that extension immediately. -+ The dialargs are specified in the same format that arguments are provided -+ to the Dial application. -+ -+ -+ ***/ - --/* RetryDial App by Anthony Minessale II Jan/2005 */ -+static char *app = "Dial"; - static char *rapp = "RetryDial"; --static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension."; --static char *rdescrip = --" RetryDial(announce,sleep,retries,dialargs): This application will attempt to\n" --"place a call using the normal Dial application. If no channel can be reached,\n" --"the 'announce' file will be played. Then, it will wait 'sleep' number of\n" --"seconds before retrying the call. After 'retries' number of attempts, the\n" --"calling channel will continue at the next priority in the dialplan. If the\n" --"'retries' setting is set to 0, this application will retry endlessly.\n" --" While waiting to retry a call, a 1 digit extension may be dialed. If that\n" --"extension exists in either the context defined in ${EXITCONTEXT} or the current\n" --"one, The call will jump to that extension immediately.\n" --" The 'dialargs' are specified in the same format that arguments are provided\n" --"to the Dial application.\n"; - - enum { - OPT_ANNOUNCE = (1 << 0), - OPT_RESETCDR = (1 << 1), - OPT_DTMF_EXIT = (1 << 2), - OPT_SENDDTMF = (1 << 3), -- OPT_FORCECLID = (1 << 4), -+ OPT_FORCE_CALLERID = (1 << 4), - OPT_GO_ON = (1 << 5), - OPT_CALLEE_HANGUP = (1 << 6), - OPT_CALLER_HANGUP = (1 << 7), -+ OPT_PEER_H = (1 << 8), - OPT_DURATION_LIMIT = (1 << 9), - OPT_MUSICBACK = (1 << 10), - OPT_CALLEE_MACRO = (1 << 11), - OPT_SCREEN_NOINTRO = (1 << 12), -- OPT_SCREEN_NOCLID = (1 << 13), -- OPT_ORIGINAL_CLID = (1 << 14), -+ OPT_SCREEN_NOCALLERID = (1 << 13), -+ OPT_IGNORE_CONNECTEDLINE = (1 << 14), - OPT_SCREENING = (1 << 15), - OPT_PRIVACY = (1 << 16), - OPT_RINGBACK = (1 << 17), -@@ -280,9 +493,10 @@ - - #define DIAL_STILLGOING (1 << 31) - #define DIAL_NOFORWARDHTML ((uint64_t)1 << 32) /* flags are now 64 bits, so keep it up! */ --#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33) --#define OPT_PEER_H ((uint64_t)1 << 34) --#define OPT_CALLEE_GO_ON ((uint64_t)1 << 35) -+#define DIAL_NOCONNECTEDLINE ((uint64_t)1 << 33) -+#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 34) -+#define OPT_PEER_H ((uint64_t)1 << 35) -+#define OPT_CALLEE_GO_ON ((uint64_t)1 << 36) - - enum { - OPT_ARG_ANNOUNCE = 0, -@@ -296,6 +510,7 @@ - OPT_ARG_PRIVACY, - OPT_ARG_DURATION_STOP, - OPT_ARG_OPERMODE, -+ OPT_ARG_FORCE_CALLERID, - /* note: this entry _MUST_ be the last one in the enum */ - OPT_ARG_ARRAY_SIZE, - }; -@@ -307,13 +522,14 @@ - AST_APP_OPTION('d', OPT_DTMF_EXIT), - AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF), - AST_APP_OPTION('e', OPT_PEER_H), -- AST_APP_OPTION('f', OPT_FORCECLID), -+ AST_APP_OPTION_ARG('f', OPT_FORCE_CALLERID, OPT_ARG_FORCE_CALLERID), - AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON), - AST_APP_OPTION('g', OPT_GO_ON), - AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO), - AST_APP_OPTION('h', OPT_CALLEE_HANGUP), - AST_APP_OPTION('H', OPT_CALLER_HANGUP), - AST_APP_OPTION('i', OPT_IGNORE_FORWARDING), -+ AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE), - AST_APP_OPTION('k', OPT_CALLEE_PARK), - AST_APP_OPTION('K', OPT_CALLER_PARK), - AST_APP_OPTION('k', OPT_CALLEE_PARK), -@@ -322,8 +538,7 @@ - AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK), - AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO), - AST_APP_OPTION('n', OPT_SCREEN_NOINTRO), -- AST_APP_OPTION('N', OPT_SCREEN_NOCLID), -- AST_APP_OPTION('o', OPT_ORIGINAL_CLID), -+ AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID), - AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE), - AST_APP_OPTION('p', OPT_SCREENING), - AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY), -@@ -350,6 +565,7 @@ - struct chanlist *next; - struct ast_channel *chan; - uint64_t flags; -+ struct ast_party_connected_line connected; - }; - - -@@ -360,8 +576,12 @@ - while (outgoing) { - /* Hangup any existing lines we have open */ - if (outgoing->chan && (outgoing->chan != exception)) { -- if (answered_elsewhere) -+ if (answered_elsewhere) { -+ /* The flag is used for local channel inheritance and stuff */ - ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); -+ /* This is for the channel drivers */ -+ outgoing->chan->hangupcause = AST_CAUSE_ANSWERED_ELSEWHERE; -+ } - ast_hangup(outgoing->chan); - } - oo = outgoing; -@@ -415,12 +635,13 @@ - } - } - --/* free the buffer if allocated, and set the pointer to the second arg */ --#define S_REPLACE(s, new_val) \ -- do { \ -- if (s) \ -- ast_free(s); \ -- s = (new_val); \ -+/*! \brief free the buffer if allocated, and set the pointer to the second arg */ -+#define S_REPLACE(s, new_val) \ -+ do { \ -+ if (s) { \ -+ ast_free(s); \ -+ } \ -+ s = (new_val); \ - } while (0) - - static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri) -@@ -441,15 +662,6 @@ - return 0; - } - -- --static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan) --{ -- const char *context = S_OR(chan->macrocontext, chan->context); -- const char *exten = S_OR(chan->macroexten, chan->exten); -- -- return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : ""; --} -- - static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring) - { - manager_event(EVENT_FLAG_CALL, "Dial", -@@ -489,6 +701,8 @@ - struct ast_channel *original = o->chan; - struct ast_channel *c = o->chan; /* the winner */ - struct ast_channel *in = num->chan; /* the input channel */ -+ struct ast_party_redirecting *apr = &o->chan->redirecting; -+ struct ast_party_connected_line *apc = &o->chan->connected; - char *stuff; - char *tech; - int cause; -@@ -529,28 +743,24 @@ - handle_cause(cause, num); - ast_hangup(original); - } else { -- char *new_cid_num, *new_cid_name; -- struct ast_channel *src; -- - ast_rtp_make_compatible(c, in, single); -- if (ast_test_flag64(o, OPT_FORCECLID)) { -- new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten)); -- new_cid_name = NULL; /* XXX no name ? */ -- src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */ -- } else { -- new_cid_num = ast_strdup(in->cid.cid_num); -- new_cid_name = ast_strdup(in->cid.cid_name); -- src = in; -- } -- ast_string_field_set(c, accountcode, src->accountcode); -- c->cdrflags = src->cdrflags; -- S_REPLACE(c->cid.cid_num, new_cid_num); -- S_REPLACE(c->cid.cid_name, new_cid_name); - -- if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */ -- S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani)); -- } -- S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten))); -+ ast_string_field_set(c, accountcode, in->accountcode); -+ c->cdrflags = in->cdrflags; -+ -+ ast_set_redirecting(c, apr); -+ S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(original->cid.cid_rdnis, S_OR(in->macroexten, in->exten)))); -+ -+ c->cid.cid_tns = in->cid.cid_tns; -+ -+ ast_party_caller_copy(&c->cid, &in->cid); -+ ast_party_connected_line_copy(&c->connected, apc); -+ -+ S_REPLACE(in->cid.cid_rdnis, ast_strdup(c->cid.cid_rdnis)); -+ ast_redirecting_update(in, apr); -+ -+ ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE); -+ - if (ast_call(c, tmpchan, 0)) { - ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); - ast_clear_flag64(o, DIAL_STILLGOING); -@@ -560,11 +770,6 @@ - num->nochan++; - } else { - senddialevent(in, c, stuff); -- /* After calling, set callerid to extension */ -- if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) { -- char cidname[AST_MAX_EXTENSION] = ""; -- ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL); -- } - /* Hangup the original channel now, in case we needed it */ - ast_hangup(original); - } -@@ -593,16 +798,25 @@ - int orig = *to; - struct ast_channel *peer = NULL; - /* single is set if only one destination is enabled */ -- int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK); -+ int single = outgoing && !outgoing->next; - #ifdef HAVE_EPOLL - struct chanlist *epollo; - #endif -+ struct ast_party_connected_line connected_caller; - - if (single) { - /* Turn off hold music, etc */ -- ast_deactivate_generator(in); -+ if (!ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK)) -+ ast_deactivate_generator(in); -+ - /* If we are calling a single channel, make them compatible for in-band tone purpose */ - ast_channel_make_compatible(outgoing->chan, in); -+ -+ if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_NOCONNECTEDLINE)) { -+ ast_party_connected_line_collect_caller(&connected_caller, &outgoing->chan->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_connected_line_update(in, &connected_caller); -+ } - } - - #ifdef HAVE_EPOLL -@@ -649,6 +863,15 @@ - if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) { - if (!peer) { - ast_verb(3, "%s answered %s\n", c->name, in->name); -+ if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { -+ if (o->connected.id.number) { -+ ast_connected_line_update(in, &o->connected); -+ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) { -+ ast_party_connected_line_collect_caller(&connected_caller, &c->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_connected_line_update(in, &connected_caller); -+ } -+ } - peer = c; - ast_copy_flags64(peerflags, o, - OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | -@@ -687,6 +910,15 @@ - /* This is our guy if someone answered. */ - if (!peer) { - ast_verb(3, "%s answered %s\n", c->name, in->name); -+ if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { -+ if (o->connected.id.number) { -+ ast_connected_line_update(in, &o->connected); -+ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) { -+ ast_party_connected_line_collect_caller(&connected_caller, &c->cid); -+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; -+ ast_connected_line_update(in, &connected_caller); -+ } -+ } - peer = c; - if (peer->cdr) { - peer->cdr->answer = ast_tvnow(); -@@ -751,6 +983,29 @@ - ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name); - ast_indicate(in, AST_CONTROL_SRCUPDATE); - break; -+ case AST_CONTROL_CONNECTED_LINE: -+ if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { -+ ast_verb(3, "Connected line update to %s prevented.\n", in->name); -+ } else if (!single) { -+ struct ast_party_connected_line connected; -+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", c->name, in->name); -+ ast_party_connected_line_set_init(&connected, &o->connected); -+ ast_parse_connected_line_data(f->data.ptr, f->datalen, &connected); -+ ast_party_connected_line_set(&o->connected, &connected); -+ ast_party_connected_line_free(&connected); -+ } else { -+ ast_verb(3, "%s connected line has changed, passing it to %s\n", c->name, in->name); -+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); -+ } -+ break; -+ case AST_CONTROL_REDIRECTING: -+ if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { -+ ast_verb(3, "Redirecting update to %s prevented.\n", in->name); -+ } else { -+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name); -+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); -+ } -+ break; - case AST_CONTROL_PROCEEDING: - ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name); - if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) -@@ -865,7 +1120,9 @@ - ((f->subclass == AST_CONTROL_HOLD) || - (f->subclass == AST_CONTROL_UNHOLD) || - (f->subclass == AST_CONTROL_VIDUPDATE) || -- (f->subclass == AST_CONTROL_SRCUPDATE))) { -+ (f->subclass == AST_CONTROL_SRCUPDATE) || -+ (f->subclass == AST_CONTROL_CONNECTED_LINE) || -+ (f->subclass == AST_CONTROL_REDIRECTING))) { - ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); - ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); - } -@@ -1184,11 +1441,11 @@ - - ast_copy_string(pa->privcid, l, sizeof(pa->privcid)); - -- if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) { -- /* if callerid is set and OPT_SCREEN_NOCLID is set also */ -+ if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCALLERID)) { -+ /* if callerid is set and OPT_SCREEN_NOCALLERID is set also */ - ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid); - pa->privdb_val = AST_PRIVACY_ALLOW; -- } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) { -+ } else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) { - ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val); - } - -@@ -1249,19 +1506,6 @@ - return 1; /* success */ - } - --static void set_dial_features(struct ast_flags64 *opts, struct ast_dial_features *features) --{ -- struct ast_flags64 perm_opts = {.flags = 0}; -- -- ast_copy_flags64(&perm_opts, opts, -- OPT_CALLER_TRANSFER | OPT_CALLER_PARK | OPT_CALLER_MONITOR | OPT_CALLER_MIXMONITOR | OPT_CALLER_HANGUP | -- OPT_CALLEE_TRANSFER | OPT_CALLEE_PARK | OPT_CALLEE_MONITOR | OPT_CALLEE_MIXMONITOR | OPT_CALLEE_HANGUP); -- -- memset(features->options, 0, sizeof(features->options)); -- -- ast_app_options2str64(dial_exec_options, &perm_opts, features->options, sizeof(features->options)); --} -- - static void end_bridge_callback(void *data) - { - char buf[80]; -@@ -1301,7 +1545,7 @@ - struct cause_args num = { chan, 0, 0, 0 }; - int cause; - char numsubst[256]; -- char cidname[AST_MAX_EXTENSION] = ""; -+ char *cid_num = NULL, *cid_name = NULL; - - struct ast_bridge_config config = { { 0, } }; - struct timeval calldurationlimit = { 0, }; -@@ -1325,9 +1569,6 @@ - struct ast_flags64 opts = { 0, }; - char *opt_args[OPT_ARG_ARRAY_SIZE]; - struct ast_datastore *datastore = NULL; -- struct ast_datastore *ds_caller_features = NULL; -- struct ast_datastore *ds_callee_features = NULL; -- struct ast_dial_features *caller_features; - int fulldial = 0, num_dialed = 0; - - /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ -@@ -1359,6 +1600,7 @@ - goto done; - } - -+ - if (ast_test_flag64(&opts, OPT_OPERMODE)) { - opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]); - ast_verb(3, "Setting operator services mode to %d.\n", opermode); -@@ -1384,6 +1626,8 @@ - goto done; - } - -+ if (ast_test_flag64(&opts, OPT_FORCE_CALLERID) && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CALLERID])) -+ ast_callerid_parse(opt_args[OPT_ARG_FORCE_CALLERID], &cid_name, &cid_num); - if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr) - ast_cdr_reset(chan->cdr, NULL); - if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY])) -@@ -1396,6 +1640,10 @@ - res = -1; /* reset default */ - } - -+ if (ast_test_flag64(&opts, OPT_DTMF_EXIT)) { -+ __ast_answer(chan, 0, 0); -+ } -+ - if (continue_exec) - *continue_exec = 0; - -@@ -1409,30 +1657,8 @@ - outbound_group = ast_strdupa(outbound_group); - } - ast_channel_unlock(chan); -- ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING); -+ ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE | OPT_FORCE_CALLERID); - -- /* Create datastore for channel dial features for caller */ -- if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { -- ast_log(LOG_WARNING, "Unable to create channel datastore for dial features. Aborting!\n"); -- goto out; -- } -- -- if (!(caller_features = ast_malloc(sizeof(*caller_features)))) { -- ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n"); -- goto out; -- } -- -- ast_copy_flags(&(caller_features->features_callee), &(config.features_caller), AST_FLAGS_ALL); -- caller_features->is_caller = 1; -- set_dial_features(&opts, caller_features); -- -- ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; -- ds_caller_features->data = caller_features; -- -- ast_channel_lock(chan); -- ast_channel_datastore_add(chan, ds_caller_features); -- ast_channel_unlock(chan); -- - /* loop through the list of dial destinations */ - rest = args.peers; - while ((cur = strsep(&rest, "&")) ) { -@@ -1444,7 +1670,6 @@ - char *tech = strsep(&number, "/"); - /* find if we already dialed this interface */ - struct ast_dialed_interface *di; -- struct ast_dial_features *callee_features; - AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; - num_dialed++; - if (!number) { -@@ -1461,7 +1686,7 @@ - OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | - OPT_CALLEE_PARK | OPT_CALLER_PARK | - OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | -- OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); -+ OPT_RINGBACK | OPT_MUSICBACK); - ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); - } - ast_copy_string(numsubst, number, sizeof(numsubst)); -@@ -1469,6 +1694,14 @@ - - ast_channel_lock(chan); - datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); -+ /* If the incoming channel has previously had connected line information -+ * set on it (perhaps through the CONNECTED_LINE dialplan function) then -+ * seed the calllist's connected line information with this previously -+ * acquired info -+ */ -+ if (chan->connected.id.number) { -+ ast_party_connected_line_copy(&tmp->connected, &chan->connected); -+ } - ast_channel_unlock(chan); - - if (datastore) -@@ -1552,27 +1785,56 @@ - tc->data = "(Outgoing Line)"; - memset(&tc->whentohangup, 0, sizeof(tc->whentohangup)); - -- S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num)); -- S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name)); -- S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani)); -+ /* If the new channel has no callerid, try to guess what it should be */ -+ if (ast_strlen_zero(tc->cid.cid_num)) { -+ if (!ast_strlen_zero(chan->connected.id.number)) { -+ ast_set_callerid(tc, chan->connected.id.number, chan->connected.id.name, chan->connected.ani); -+ } else if (!ast_strlen_zero(chan->cid.cid_dnid)) { -+ ast_set_callerid(tc, chan->cid.cid_dnid, NULL, NULL); -+ } else if (!ast_strlen_zero(S_OR(chan->macroexten, chan->exten))) { -+ ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), NULL, NULL); -+ } -+ ast_set_flag64(tmp, DIAL_NOCONNECTEDLINE); -+ } -+ -+ if (ast_test_flag64(peerflags, OPT_FORCE_CALLERID)) { -+ struct ast_party_connected_line connected; -+ -+ ast_party_connected_line_set_init(&connected, &tc->connected); -+ connected.id.number = cid_num; -+ connected.id.name = cid_name; -+ connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; -+ ast_set_connected_line(tc, &connected); -+ } else { -+ ast_copy_caller_to_connected(&tc->connected, &chan->cid); -+ } -+ - S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); -- -+ ast_party_redirecting_copy(&tc->redirecting, &chan->redirecting); -+ -+ tc->cid.cid_tns = chan->cid.cid_tns; -+ - ast_string_field_set(tc, accountcode, chan->accountcode); - tc->cdrflags = chan->cdrflags; - if (ast_strlen_zero(tc->musicclass)) - ast_string_field_set(tc, musicclass, chan->musicclass); -- /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */ -- tc->cid.cid_pres = chan->cid.cid_pres; -- tc->cid.cid_ton = chan->cid.cid_ton; -- tc->cid.cid_tns = chan->cid.cid_tns; -- tc->cid.cid_ani2 = chan->cid.cid_ani2; -+ -+ /* Pass ADSI CPE and transfer capability */ - tc->adsicpe = chan->adsicpe; - tc->transfercapability = chan->transfercapability; - - /* If we have an outbound group, set this peer channel to it */ - if (outbound_group) - ast_app_group_set_channel(tc, outbound_group); -+ /* If the calling channel has the ANSWERED_ELSEWHERE flag set, inherit it. This is to support local channels */ -+ if (ast_test_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE)) -+ ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE); - -+ /* Check if we're forced by configuration */ -+ if (ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE)) -+ ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE); -+ -+ - /* Inherit context and extension */ - ast_string_field_set(tc, dialcontext, ast_strlen_zero(chan->macrocontext) ? chan->context : chan->macrocontext); - if (!ast_strlen_zero(chan->macroexten)) -@@ -1580,30 +1842,6 @@ - else - ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten)); - -- /* Save callee features */ -- if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { -- ast_log(LOG_WARNING, "Unable to create channel datastore for dial features. Aborting!\n"); -- ast_free(tmp); -- goto out; -- } -- -- if (!(callee_features = ast_malloc(sizeof(*callee_features)))) { -- ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n"); -- ast_free(tmp); -- goto out; -- } -- -- ast_copy_flags(&(callee_features->features_callee), &(config.features_callee), AST_FLAGS_ALL); -- callee_features->is_caller = 0; -- set_dial_features(&opts, callee_features); -- -- ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; -- ds_callee_features->data = callee_features; -- -- ast_channel_lock(chan); -- ast_channel_datastore_add(tc, ds_callee_features); -- ast_channel_unlock(chan); -- - res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */ - - /* Save the info in cdr's that we called them */ -@@ -1625,8 +1863,6 @@ - } else { - senddialevent(chan, tc, numsubst); - ast_verb(3, "Called %s\n", numsubst); -- if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) -- ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL); - } - /* Put them in the list of outgoing thingies... We're ready now. - XXX If we're forcibly removed, these outgoing calls won't get -@@ -2002,11 +2238,7 @@ - res = -1; - goto done; - } -- if (opermode && !strncmp(chan->tech->type, "DAHDI", 5) && !strncmp(peer->name, "DAHDI", 5)) { -- /* what's this special handling for dahdi <-> dahdi ? -- * A: dahdi to dahdi calls are natively bridged at the kernel driver -- * level, so we need to ensure that this mode gets propagated -- * all the way down. */ -+ if (opermode) { - struct oprmode oprmode; - - oprmode.peer = peer; -@@ -2224,8 +2456,8 @@ - else - ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial"); - -- res = ast_register_application(app, dial_exec, synopsis, descrip); -- res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip); -+ res = ast_register_application_xml(app, dial_exec); -+ res |= ast_register_application_xml(rapp, retrydial_exec); - - return res; - } -Index: apps/app_nbscat.c -=================================================================== ---- a/apps/app_nbscat.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_nbscat.c (.../team/group/issue14292) (revision 178988) -@@ -43,6 +43,19 @@ - #include "asterisk/translate.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Play an NBS local stream. -+ -+ -+ -+ Executes nbscat to listen to the local NBS stream. -+ User can exit by pressing any key. -+ -+ -+ ***/ -+ - #define LOCAL_NBSCAT "/usr/local/bin/nbscat8k" - #define NBSCAT "/usr/bin/nbscat8k" - -@@ -52,13 +65,6 @@ - - static char *app = "NBScat"; - --static char *synopsis = "Play an NBS local stream"; -- --static char *descrip = --" NBScat(): Executes nbscat to listen to the local NBS stream.\n" --"User can exit by pressing any key.\n"; -- -- - static int NBScatplay(int fd) - { - int res; -@@ -204,7 +210,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, NBScat_exec, synopsis, descrip); -+ return ast_register_application_xml(app, NBScat_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application"); -Index: apps/app_page.c -=================================================================== ---- a/apps/app_page.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_page.c (.../team/group/issue14292) (revision 178988) -@@ -44,26 +44,69 @@ - #include "asterisk/devicestate.h" - #include "asterisk/dial.h" - -+/*** DOCUMENTATION -+ -+ -+ Page series of phones -+ -+ -+ -+ -+ Specification of the device(s) to dial. These must be in the format of -+ Technology/Resource, where Technology -+ represents a particular channel driver, and Resource represents a resource -+ available to that particular channel driver. -+ -+ -+ Optional extra devices to dial inparallel -+ If you need more then one enter them as Technology2/Resource2& -+ Technology3/Resourse3&..... -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Specify the length of time that the system will attempt to connect a call. -+ After this duration, any intercom calls that have not been answered will be hung up by the -+ system. -+ -+ -+ -+ Places outbound calls to the given technology/resource -+ and dumps them into a conference bridge as muted participants. The original -+ caller is dumped into the conference as a speaker and the room is -+ destroyed when the original callers leaves. -+ -+ -+ MeetMe -+ -+ -+ ***/ - static const char *app_page= "Page"; - --static const char *page_synopsis = "Pages phones"; -- --static const char *page_descrip = --"Page(Technology/Resource&Technology2/Resource2[,options])\n" --" Places outbound calls to the given technology / resource and dumps\n" --"them into a conference bridge as muted participants. The original\n" --"caller is dumped into the conference as a speaker and the room is\n" --"destroyed when the original caller leaves. Valid options are:\n" --" d - full duplex audio\n" --" q - quiet, do not play beep to caller\n" --" r - record the page into a file (see 'r' for app_meetme)\n" --" s - only dial channel if devicestate says it is not in use\n"; -- - enum { - PAGE_DUPLEX = (1 << 0), - PAGE_QUIET = (1 << 1), - PAGE_RECORD = (1 << 2), - PAGE_SKIP = (1 << 3), -+ PAGE_IGNORE_FORWARDS = (1 << 4), - } page_opt_flags; - - AST_APP_OPTIONS(page_opts, { -@@ -71,12 +114,13 @@ - AST_APP_OPTION('q', PAGE_QUIET), - AST_APP_OPTION('r', PAGE_RECORD), - AST_APP_OPTION('s', PAGE_SKIP), -+ AST_APP_OPTION('i', PAGE_IGNORE_FORWARDS), - }); - - - static int page_exec(struct ast_channel *chan, void *data) - { -- char *options, *tech, *resource, *tmp, *tmp2; -+ char *tech, *resource, *tmp; - char meetmeopts[88], originator[AST_CHANNEL_NAME], *opts[0]; - struct ast_flags flags = { 0 }; - unsigned int confid = ast_random(); -@@ -84,7 +128,15 @@ - int res = 0, pos = 0, i = 0; - struct ast_dial **dial_list; - unsigned int num_dials; -+ int timeout = 0; -+ char *parse; - -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(devices); -+ AST_APP_ARG(options); -+ AST_APP_ARG(timeout); -+ ); -+ - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n"); - return -1; -@@ -95,27 +147,34 @@ - return -1; - }; - -- options = ast_strdupa(data); -+ parse = ast_strdupa(data); - -+ AST_STANDARD_APP_ARGS(args, parse); -+ - ast_copy_string(originator, chan->name, sizeof(originator)); -- if ((tmp = strchr(originator, '-'))) -+ if ((tmp = strchr(originator, '-'))) { - *tmp = '\0'; -+ } - -- tmp = strsep(&options, ","); -- if (options) -- ast_app_parse_options(page_opts, &flags, opts, options); -+ if (!ast_strlen_zero(args.options)) { -+ ast_app_parse_options(page_opts, &flags, opts, args.options); -+ } - -+ if (!ast_strlen_zero(args.timeout)) { -+ timeout = atoi(args.timeout); -+ } -+ - snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe,%ud,%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"), - (ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") ); - - /* Count number of extensions in list by number of ampersands + 1 */ - num_dials = 1; -- tmp2 = tmp; -- while (*tmp2) { -- if (*tmp2 == '&') { -+ tmp = args.devices; -+ while (*tmp) { -+ if (*tmp == '&') { - num_dials++; - } -- tmp2++; -+ tmp++; - } - - if (!(dial_list = ast_calloc(num_dials, sizeof(struct ast_dial *)))) { -@@ -124,7 +183,7 @@ - } - - /* Go through parsing/calling each device */ -- while ((tech = strsep(&tmp, "&"))) { -+ while ((tech = strsep(&args.devices, "&"))) { - int state = 0; - struct ast_dial *dial = NULL; - -@@ -142,9 +201,9 @@ - if (ast_test_flag(&flags, PAGE_SKIP)) { - state = ast_device_state(tech); - if (state == AST_DEVICE_UNKNOWN) { -- ast_log(LOG_WARNING, "Destination '%s' has device state '%s'. Paging anyway.\n", tech, devstate2str(state)); -+ ast_log(LOG_WARNING, "Destination '%s' has device state '%s'. Paging anyway.\n", tech, ast_devstate2str(state)); - } else if (state != AST_DEVICE_NOT_INUSE) { -- ast_log(LOG_WARNING, "Destination '%s' has device state '%s'.\n", tech, devstate2str(state)); -+ ast_log(LOG_WARNING, "Destination '%s' has device state '%s'.\n", tech, ast_devstate2str(state)); - continue; - } - } -@@ -158,11 +217,22 @@ - } - - /* Append technology and resource */ -- ast_dial_append(dial, tech, resource); -+ if (ast_dial_append(dial, tech, resource) == -1) { -+ ast_log(LOG_ERROR, "Failed to add %s to outbound dial\n", tech); -+ continue; -+ } - - /* Set ANSWER_EXEC as global option */ - ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts); - -+ if (timeout) { -+ ast_dial_set_global_timeout(dial, timeout * 1000); -+ } -+ -+ if (ast_test_flag(&flags, PAGE_IGNORE_FORWARDS)) { -+ ast_dial_option_global_enable(dial, AST_DIAL_OPTION_DISABLE_CALL_FORWARDING, NULL); -+ } -+ - /* Run this dial in async mode */ - ast_dial_run(dial, chan, 1); - -@@ -206,7 +276,7 @@ - - static int load_module(void) - { -- return ast_register_application(app_page, page_exec, page_synopsis, page_descrip); -+ return ast_register_application_xml(app_page, page_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Page Multiple Phones"); -Index: apps/app_echo.c -=================================================================== ---- a/apps/app_echo.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_echo.c (.../team/group/issue14292) (revision 178988) -@@ -33,16 +33,21 @@ - #include "asterisk/module.h" - #include "asterisk/channel.h" - -+/*** DOCUMENTATION -+ -+ -+ Echo audio, video, DTMF back to the calling party -+ -+ -+ -+ Echos back any audio, video or DTMF frames read from the calling -+ channel back to itself. Note: If '#' detected application exits -+ -+ -+ ***/ -+ - static char *app = "Echo"; - --static char *synopsis = "Echo audio, video, or DTMF back to the calling party"; -- --static char *descrip = --" Echo(): This application will echo any audio, video, or DTMF frames read from\n" --"the calling channel back to itself. If the DTMF digit '#' is received, the\n" --"application will exit.\n"; -- -- - static int echo_exec(struct ast_channel *chan, void *data) - { - int res = -1; -@@ -81,7 +86,7 @@ - - static int load_module(void) - { -- return ast_register_application(app, echo_exec, synopsis, descrip); -+ return ast_register_application_xml(app, echo_exec); - } - - AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Echo Application"); -Index: apps/app_waitforsilence.c -=================================================================== ---- a/apps/app_waitforsilence.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_waitforsilence.c (.../team/group/issue14292) (revision 178988) -@@ -48,37 +48,79 @@ - #include "asterisk/dsp.h" - #include "asterisk/module.h" - -+/*** DOCUMENTATION -+ -+ -+ Waits for a specified amount of silence. -+ -+ -+ -+ -+ If not specified, defaults to 1. -+ -+ -+ Is specified only to avoid an infinite loop in cases where silence is never achieved. -+ -+ -+ -+ Waits for up to silencerequired milliseconds of silence, -+ iterations times. An optional timeout -+ specified the number of seconds to return after, even if we do not receive the specified amount of silence. -+ Use timeout with caution, as it may defeat the purpose of this application, which -+ is to wait indefinitely until silence is detected on the line. This is particularly useful for reverse-911-type -+ call broadcast applications where you need to wait for an answering machine to complete its spiel before -+ playing a message. -+ Typically you will want to include two or more calls to WaitForSilence when dealing with an answering -+ machine; first waiting for the spiel to finish, then waiting for the beep, etc. -+ Examples: -+ WaitForSilence(500,2) will wait for 1/2 second of silence, twice -+ WaitForSilence(1000) will wait for 1 second of silence, once -+ WaitForSilence(300,3,10) will wait for 300ms silence, 3 times, and returns after 10 sec, even if silence -+ is not detected -+ Sets the channel variable WAITSTATUS to one of these values: -+ -+ -+ -+ if exited with silence detected. -+ -+ -+ if exited without silence detected after timeout. -+ -+ -+ -+ -+ -+ WaitForNoise -+ -+ -+ -+ -+ Waits for a specified amount of noise. -+ -+ -+ -+ -+ If not specified, defaults to 1. -+ -+ -+ Is specified only to avoid an infinite loop in cases where silence is never achieved. -+ -+ -+ -+ Waits for up to noiserequired milliseconds of noise, -+ iterations times. An optional timeout -+ specified the number of seconds to return after, even if we do not receive the specified amount of noise. -+ Use timeout with caution, as it may defeat the purpose of this application, which -+ is to wait indefinitely until noise is detected on the line. -+ -+ -+ WaitForSilence -+ -+ -+ ***/ -+ - static char *app_silence = "WaitForSilence"; --static char *synopsis_silence = "Waits for a specified amount of silence"; --static char *descrip_silence = --" WaitForSilence(silencerequired[,iterations][,timeout]):\n" --"Wait for Silence: Waits for up to 'silencerequired' \n" --"milliseconds of silence, 'iterations' times or once if omitted.\n" --"An optional timeout specified the number of seconds to return\n" --"after, even if we do not receive the specified amount of silence.\n" --"Use 'timeout' with caution, as it may defeat the purpose of this\n" --"application, which is to wait indefinitely until silence is detected\n" --"on the line. This is particularly useful for reverse-911-type\n" --"call broadcast applications where you need to wait for an answering\n" --"machine to complete its spiel before playing a message.\n" --"The timeout parameter is specified only to avoid an infinite loop in\n" --"cases where silence is never achieved. Typically you will want to\n" --"include two or more calls to WaitForSilence when dealing with an answering\n" --"machine; first waiting for the spiel to finish, then waiting for the beep, etc.\n\n" -- "Examples:\n" --" - WaitForSilence(500,2) will wait for 1/2 second of silence, twice\n" --" - WaitForSilence(1000) will wait for 1 second of silence, once\n" --" - WaitForSilence(300,3,10) will wait for 300ms silence, 3 times,\n" --" and returns after 10 sec, even if silence is not detected\n\n" --"Sets the channel variable WAITSTATUS with to one of these values:\n" --"SILENCE - if exited with silence detected\n" --"TIMEOUT - if exited without silence detected after timeout\n"; -- - static char *app_noise = "WaitForNoise"; --static char *synopsis_noise = "Waits for a specified amount of noise"; --static char *descrip_noise = --"WaitForNoise(noiserequired[,iterations][,timeout]) \n" --"Wait for Noise: The same as Wait for Silance but waits for noise that is above the threshold specified\n"; - - static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) { - struct ast_frame *f = NULL; -@@ -168,7 +210,9 @@ - int iterations = 1, i; - time_t waitstart; - -- res = ast_answer(chan); /* Answer the channel */ -+ if (chan->_state != AST_STATE_UP) { -+ res = ast_answer(chan); /* Answer the channel */ -+ } - - if (!data || ( (sscanf(data, "%d,%d,%d", &timereqd, &iterations, &timeout) != 3) && - (sscanf(data, "%d,%d", &timereqd, &iterations) != 2) && -@@ -211,8 +255,8 @@ - { - int res; - -- res = ast_register_application(app_silence, waitforsilence_exec, synopsis_silence, descrip_silence); -- res |= ast_register_application(app_noise, waitfornoise_exec, synopsis_noise, descrip_noise); -+ res = ast_register_application_xml(app_silence, waitforsilence_exec); -+ res |= ast_register_application_xml(app_noise, waitfornoise_exec); - return res; - } - -Index: apps/app_sayunixtime.c -=================================================================== ---- a/apps/app_sayunixtime.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_sayunixtime.c (.../team/group/issue14292) (revision 178988) -@@ -36,29 +36,59 @@ - #include "asterisk/say.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Says a specified time in a custom format. -+ -+ -+ -+ time, in seconds since Jan 1, 1970. May be negative. Defaults to now. -+ -+ -+ timezone, see /usr/share/zoneinfo for a list. Defaults to machine default. -+ -+ -+ a format the time is to be said in. See voicemail.conf. -+ Defaults to ABdY "digits/at" IMp -+ -+ -+ -+ Uses some of the sound files stored in /var/lib/asterisk/sounds to construct a phrase -+ saying the specified date and/or time in the specified format. -+ -+ -+ STRFTIME -+ STRPTIME -+ IFTIME -+ -+ -+ -+ -+ Says a specified time in a custom format. -+ -+ -+ -+ time, in seconds since Jan 1, 1970. May be negative. Defaults to now. -+ -+ -+ timezone, see /usr/share/zoneinfo for a list. Defaults to machine default. -+ -+ -+ a format the time is to be said in. See voicemail.conf. -+ Defaults to ABdY "digits/at" IMp -+ -+ -+ -+ Say the date and time in a specified format. -+ -+ -+ -+ ***/ -+ - static char *app_sayunixtime = "SayUnixTime"; - static char *app_datetime = "DateTime"; - --static char *sayunixtime_synopsis = "Says a specified time in a custom format"; -- --static char *sayunixtime_descrip = --"SayUnixTime([unixtime][,[timezone][,format]])\n" --" unixtime - time, in seconds since Jan 1, 1970. May be negative.\n" --" defaults to now.\n" --" timezone - timezone, see /usr/share/zoneinfo for a list.\n" --" defaults to machine default.\n" --" format - a format the time is to be said in. See voicemail.conf.\n" --" defaults to \"ABdY 'digits/at' IMp\"\n"; --static char *datetime_descrip = --"DateTime([unixtime][,[timezone][,format]])\n" --" unixtime - time, in seconds since Jan 1, 1970. May be negative.\n" --" defaults to now.\n" --" timezone - timezone, see /usr/share/zoneinfo for a list.\n" --" defaults to machine default.\n" --" format: - a format the time is to be said in. See voicemail.conf.\n" --" defaults to \"ABdY 'digits/at' IMp\"\n"; -- -- - static int sayunixtime_exec(struct ast_channel *chan, void *data) - { - AST_DECLARE_APP_ARGS(args, -@@ -103,8 +133,8 @@ - { - int res; - -- res = ast_register_application(app_sayunixtime, sayunixtime_exec, sayunixtime_synopsis, sayunixtime_descrip); -- res |= ast_register_application(app_datetime, sayunixtime_exec, sayunixtime_synopsis, datetime_descrip); -+ res = ast_register_application_xml(app_sayunixtime, sayunixtime_exec); -+ res |= ast_register_application_xml(app_datetime, sayunixtime_exec); - - return res; - } -Index: apps/app_readexten.c -=================================================================== ---- a/apps/app_readexten.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/apps/app_readexten.c (.../team/group/issue14292) (revision 178988) -@@ -1,10 +1,9 @@ - /* - * Asterisk -- An open source telephony toolkit. - * -- * Copyright (C) 2007 Dave Chappell -+ * Copyright (C) 2007-2008, Trinity College Computing Center -+ * Written by David Chappell - * -- * David Chappell -- * - * 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; -@@ -36,6 +35,82 @@ - #include "asterisk/indications.h" - #include "asterisk/channel.h" - -+/*** DOCUMENTATION -+ -+ -+ Read an extension into a variable. -+ -+ -+ -+ -+ File to play before reading digits or tone with option i -+ -+ -+ Context in which to match extensions. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ An integer number of seconds to wait for a digit response. If -+ greater than 0, that value will override the default timeout. -+ -+ -+ -+ Reads a # terminated string of digits from the user into the given variable. -+ Will set READEXTENSTATUS on exit with one of the following statuses: -+ -+ -+ -+ A valid extension exists in ${variable}. -+ -+ -+ No extension was entered in the specified time. Also sets ${variable} to "t". -+ -+ -+ An invalid extension, ${INVALID_EXTEN}, was entered. Also sets ${variable} to "i". -+ -+ -+ Line was not up and the option 's' was specified. -+ -+ -+ Invalid arguments were passed. -+ -+ -+ -+ -+ -+ -+ -+ Determine whether an extension exists or not. -+ -+ -+ -+ Defaults to the current context -+ -+ -+ -+ Priority defaults to 1. -+ -+ -+ -+ Returns a true value if the indicated context, -+ extension, and priority exist. -+ -+ -+ ***/ -+ - enum { - OPT_SKIP = (1 << 0), - OPT_INDICATION = (1 << 1), -@@ -50,28 +125,6 @@ - - static char *app = "ReadExten"; - --static char *synopsis = "Read an extension into a variable"; -- --static char *descrip = --" ReadExten([,[][,[][,[ - - -+ -+ -+ -+ - - - -@@ -28,6 +32,10 @@ - - - -+ -+ -+ -+ - - - -@@ -42,6 +50,10 @@ - - - -+ -+ -+ -+ - - - -@@ -59,6 +71,10 @@ - - - -+ -+ -+ -+ - - - -@@ -73,4 +89,10 @@ - - - -+ -+ -+ -+ -+ -+ - -Index: Makefile -=================================================================== ---- a/Makefile (.../tags/1.6.1-rc1) (revision 178988) -+++ b/Makefile (.../team/group/issue14292) (revision 178988) -@@ -106,6 +106,9 @@ - ASTCFLAGS+=$(COPTS) - ASTLDFLAGS+=$(LDOPTS) - -+# libxml2 cflags -+ASTCFLAGS+=$(LIBXML2_INCLUDE) -+ - #Uncomment this to see all build commands instead of 'quiet' output - #NOISY_BUILD=yes - -@@ -143,7 +146,7 @@ - ASTSBINDIR=$(sbindir) - ASTSPOOLDIR=$(localstatedir)/spool/asterisk - ASTLOGDIR=$(localstatedir)/log/asterisk -- ASTVARRUNDIR=$(localstatedir)/run -+ ASTVARRUNDIR=$(localstatedir)/run/asterisk - ASTMANDIR=$(mandir) - ifneq ($(findstring BSD,$(OSARCH)),) - ASTVARLIBDIR=$(prefix)/share/asterisk -@@ -269,7 +272,7 @@ - endif - - ifeq ($(OSARCH),OpenBSD) -- ASTCFLAGS+=-pthread -+ ASTCFLAGS+=-pthread -ftrampolines - endif - - ifeq ($(OSARCH),SunOS) -@@ -303,7 +306,7 @@ - MOD_SUBDIRS_MENUSELECT_TREE:=$(MOD_SUBDIRS:%=%-menuselect-tree) - - ifneq ($(findstring darwin,$(OSARCH)),) -- ASTCFLAGS+=-D__Darwin__ -+ ASTCFLAGS+=-D__Darwin__ -fnested-functions - SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace - else - # These are used for all but Darwin -@@ -317,6 +320,10 @@ - SOLINK=-shared -fpic -L/usr/local/ssl/lib -lrt - endif - -+ifeq ($(OSARCH),OpenBSD) -+ SOLINK=-shared -fpic -+endif -+ - # comment to print directories during submakes - #PRINT_DIR=yes - -@@ -351,7 +358,7 @@ - @echo " + $(mK) install +" - @echo " +-------------------------------------------+" - --_all: cleantest makeopts $(SUBDIRS) -+_all: cleantest makeopts $(SUBDIRS) doc/core-en_US.xml - - makeopts: configure - @echo "****" -@@ -486,6 +493,29 @@ - mkdir -p $(DESTDIR)$(AGI_DIR) - $(MAKE) -C sounds install - -+doc/core-en_US.xml: $(foreach dir,$(MOD_SUBDIRS),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) -+ @echo -n "Building Documentation For: " -+ @echo "" > $@ -+ @echo "" >> $@ -+ @echo "" >> $@ -+ @for x in $(MOD_SUBDIRS); do \ -+ echo -n "$$x " ; \ -+ for i in $$x/*.c; do \ -+ $(AWK) -f build_tools/get_documentation $$i >> $@ ; \ -+ done ; \ -+ done -+ @echo -+ @echo "" >> $@ -+ -+validate-docs: doc/core-en_US.xml -+ifeq ($(XMLSTARLET),:) -+ @echo "---------------------------------------------------------------" -+ @echo "--- Please install xmlstarlet to validate the documentation ---" -+ @echo "---------------------------------------------------------------" -+else -+ $(XMLSTARLET) val -d doc/appdocsxml.dtd $< -+endif -+ - update: - @if [ -d .svn ]; then \ - echo "Updating from Subversion..." ; \ -@@ -534,12 +564,16 @@ - if [ -n "$(OLDHEADERS)" ]; then \ - rm -f $(addprefix $(DESTDIR)$(ASTHEADERDIR)/,$(OLDHEADERS)) ;\ - fi -+ mkdir -p $(DESTDIR)$(ASTDATADIR)/documentation -+ mkdir -p $(DESTDIR)$(ASTDATADIR)/documentation/thirdparty - mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-csv - mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-custom - mkdir -p $(DESTDIR)$(ASTDATADIR)/keys - mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware - mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware/iax - mkdir -p $(DESTDIR)$(ASTMANDIR)/man8 -+ $(INSTALL) -m 644 doc/core-*.xml $(DESTDIR)$(ASTDATADIR)/documentation -+ $(INSTALL) -m 644 doc/appdocsxml.dtd $(DESTDIR)$(ASTVARLIBDIR)/documentation - $(INSTALL) -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTDATADIR)/keys - $(INSTALL) -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTDATADIR)/keys - $(INSTALL) -m 644 doc/asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8 -@@ -608,6 +642,8 @@ - @echo " +-------------------------------------------+" - @$(MAKE) -s oldmodcheck - -+isntall: install -+ - upgrade: bininstall - - # XXX why *.adsi is installed first ? -@@ -659,7 +695,7 @@ - echo "astrundir => $(ASTVARRUNDIR)" ; \ - echo "astlogdir => $(ASTLOGDIR)" ; \ - echo "" ; \ -- echo ";[options]" ; \ -+ echo "[options]" ; \ - echo ";verbose = 3" ; \ - echo ";debug = 3" ; \ - echo ";alwaysfork = yes ; same as -F at startup" ; \ -@@ -688,6 +724,9 @@ - echo ";transcode_via_sln = yes ; Build transcode paths via SLINEAR, instead of directly" ; \ - echo ";runuser = asterisk ; The user to run as" ; \ - echo ";rungroup = asterisk ; The group to run as" ; \ -+ echo ";lightbackground = yes ; If your terminal is set for a light-colored background" ; \ -+ echo "documentation_language = en_US ; Set the Language you want Documentation displayed in. Value is in the same format as locale names" ; \ -+ echo ";hideconnect = yes ; Hide messages displayed when a remote console connects and disconnects" ; \ - echo "" ; \ - echo "; Changing the following lines may compromise your security." ; \ - echo ";[files]" ; \ -@@ -766,20 +805,28 @@ - config: - @if [ "${OSARCH}" = "linux-gnu" ]; then \ - if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ -- $(INSTALL) -m 755 contrib/init.d/rc.redhat.asterisk $(DESTDIR)/etc/rc.d/init.d/asterisk; \ -+ cat contrib/init.d/rc.redhat.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR);s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)/etc/rc.d/init.d/asterisk ;\ -+ chmod 755 $(DESTDIR)/etc/rc.d/init.d/asterisk;\ - if [ -z "$(DESTDIR)" ]; then /sbin/chkconfig --add asterisk; fi; \ - elif [ -f /etc/debian_version ]; then \ -- $(INSTALL) -m 755 contrib/init.d/rc.debian.asterisk $(DESTDIR)/etc/init.d/asterisk; \ -+ cat contrib/init.d/rc.debian.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR);s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)/etc/init.d/asterisk ;\ -+ chmod 755 $(DESTDIR)/etc/init.d/asterisk;\ - if [ -z "$(DESTDIR)" ]; then /usr/sbin/update-rc.d asterisk start 50 2 3 4 5 . stop 91 2 3 4 5 .; fi; \ - elif [ -f /etc/gentoo-release ]; then \ -- $(INSTALL) -m 755 contrib/init.d/rc.gentoo.asterisk $(DESTDIR)/etc/init.d/asterisk; \ -+ cat contrib/init.d/rc.gentoo.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR);s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)/etc/init.d/asterisk ;\ -+ chmod 755 $(DESTDIR)/etc/init.d/asterisk;\ - if [ -z "$(DESTDIR)" ]; then /sbin/rc-update add asterisk default; fi; \ - elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ]; then \ -- $(INSTALL) -m 755 contrib/init.d/rc.mandriva.asterisk $(DESTDIR)/etc/rc.d/init.d/asterisk; \ -+ cat contrib/init.d/rc.mandriva.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR);s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)/etc/rc.d/init.d/asterisk ;\ -+ chmod 755 $(DESTDIR)/etc/rc.d/init.d/asterisk;\ - if [ -z "$(DESTDIR)" ]; then /sbin/chkconfig --add asterisk; fi; \ - elif [ -f /etc/SuSE-release -o -f /etc/novell-release ]; then \ -- $(INSTALL) -m 755 contrib/init.d/rc.suse.asterisk $(DESTDIR)/etc/init.d/asterisk; \ -+ cat contrib/init.d/rc.suse.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR);s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)/etc/init.d/asterisk ;\ -+ chmod 755 $(DESTDIR)/etc/init.d/asterisk;\ - if [ -z "$(DESTDIR)" ]; then /sbin/chkconfig --add asterisk; fi; \ -+ elif [ -f /etc/arch-release -o -f /etc/arch-release ]; then \ -+ cat contrib/init.d/rc.archlinux.asterisk | sed 's|__ASTERISK_ETC_DIR__|$(ASTETCDIR);s|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)/etc/rc.d/asterisk ;\ -+ chmod 755 $(DESTDIR)/etc/rc.d/asterisk;\ - elif [ -f /etc/slackware-version ]; then \ - echo "Slackware is not currently supported, although an init script does exist for it." \ - else \ -@@ -904,7 +951,7 @@ - asterisk.pdf: - $(MAKE) -C doc/tex asterisk.pdf - --.PHONY: menuselect menuselect.makeopts main sounds clean dist-clean distclean all prereqs cleantest uninstall _uninstall uninstall-all pdf dont-optimize $(SUBDIRS_INSTALL) $(SUBDIRS_DIST_CLEAN) $(SUBDIRS_CLEAN) $(SUBDIRS_UNINSTALL) $(SUBDIRS) $(MOD_SUBDIRS_EMBED_LDSCRIPT) $(MOD_SUBDIRS_EMBED_LDFLAGS) $(MOD_SUBDIRS_EMBED_LIBS) badshell installdirs _clean -+.PHONY: menuselect menuselect.makeopts main sounds clean dist-clean distclean all prereqs cleantest uninstall _uninstall uninstall-all pdf dont-optimize $(SUBDIRS_INSTALL) $(SUBDIRS_DIST_CLEAN) $(SUBDIRS_CLEAN) $(SUBDIRS_UNINSTALL) $(SUBDIRS) $(MOD_SUBDIRS_EMBED_LDSCRIPT) $(MOD_SUBDIRS_EMBED_LDFLAGS) $(MOD_SUBDIRS_EMBED_LIBS) badshell installdirs validate-docs _clean - - FORCE: - -Index: funcs/func_rand.c -=================================================================== ---- a/funcs/func_rand.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_rand.c (.../team/group/issue14292) (revision 178988) -@@ -34,6 +34,24 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Choose a random number in a range. -+ -+ -+ -+ -+ -+ -+ Choose a random number between min and max. -+ min defaults to 0, if not specified, while max defaults -+ to RAND_MAX (2147483647 on many systems). -+ Example: Set(junky=${RAND(1,8)}); -+ Sets junky to a random number between 1 and 8, inclusive. -+ -+ -+ ***/ - static int acf_rand_exec(struct ast_channel *chan, const char *cmd, - char *parse, char *buffer, size_t buflen) - { -@@ -68,13 +86,6 @@ - - static struct ast_custom_function acf_rand = { - .name = "RAND", -- .synopsis = "Choose a random number in a range", -- .syntax = "RAND([min][,max])", -- .desc = -- "Choose a random number between min and max. Min defaults to 0, if not\n" -- "specified, while max defaults to RAND_MAX (2147483647 on many systems).\n" -- " Example: Set(junky=${RAND(1,8)}); \n" -- " Sets junky to a random number between 1 and 8, inclusive.\n", - .read = acf_rand_exec, - }; - -Index: funcs/func_base64.c -=================================================================== ---- a/funcs/func_base64.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_base64.c (.../team/group/issue14292) (revision 178988) -@@ -30,6 +30,35 @@ - #include "asterisk/pbx.h" /* function register/unregister */ - #include "asterisk/utils.h" - -+/*** DOCUMENTATION -+ -+ -+ Encode a string in base64. -+ -+ -+ -+ Input string -+ -+ -+ -+ Returns the base64 string. -+ -+ -+ -+ -+ Decode a base64 string. -+ -+ -+ -+ Input string. -+ -+ -+ -+ Returns the plain text string. -+ -+ -+ ***/ -+ - static int base64_encode(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -58,17 +87,11 @@ - - static struct ast_custom_function base64_encode_function = { - .name = "BASE64_ENCODE", -- .synopsis = "Encode a string in base64", -- .desc = "Returns the base64 string\n", -- .syntax = "BASE64_ENCODE()", - .read = base64_encode, - }; - - static struct ast_custom_function base64_decode_function = { - .name = "BASE64_DECODE", -- .synopsis = "Decode a base64 string", -- .desc = "Returns the plain text string\n", -- .syntax = "BASE64_DECODE()", - .read = base64_decode, - }; - -Index: funcs/func_speex.c -=================================================================== ---- a/funcs/func_speex.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_speex.c (.../team/group/issue14292) (revision 178988) -@@ -48,6 +48,52 @@ - - #define DEFAULT_AGC_LEVEL 8000.0 - -+/*** DOCUMENTATION -+ -+ -+ Apply automatic gain control to audio on a channel. -+ -+ -+ -+ This can be either rx or tx -+ -+ -+ -+ The AGC function will apply automatic gain control to the audio on the -+ channel that it is executed on. Using rx for audio received -+ and tx for audio transmitted to the channel. When using this -+ function you set a target audio level. It is primarily intended for use with -+ analog lines, but could be useful for other channels as well. The target volume -+ is set with a number between 1-32768. The larger the number -+ the louder (more gain) the channel will receive. -+ Examples: -+ exten => 1,1,Set(AGC(rx)=8000) -+ exten => 1,2,Set(AGC(tx)=off) -+ -+ -+ -+ -+ Apply noise reduction to audio on a channel. -+ -+ -+ -+ This can be either rx or tx -+ the values that can be set to this are either on and -+ off -+ -+ -+ -+ The DENOISE function will apply noise reduction to audio on the channel -+ that it is executed on. It is very useful for noisy analog lines, especially -+ when adjusting gains or using AGC. Use rx for audio received from the channel -+ and tx to apply the filter to the audio being sent to the channel. -+ Examples: -+ exten => 1,1,Set(DENOISE(rx)=on) -+ exten => 1,2,Set(DENOISE(tx)=off) -+ -+ -+ ***/ -+ - struct speex_direction_info { - SpeexPreprocessState *state; /*!< speex preprocess state object */ - int agc; /*!< audio gain control is enabled or not */ -@@ -290,39 +336,12 @@ - - static struct ast_custom_function agc_function = { - .name = "AGC", -- .synopsis = "Apply automatic gain control to audio on a channel", -- .desc = -- " The AGC function will apply automatic gain control to audio on the channel\n" -- "that this function is executed on. Use rx for audio received from the channel\n" -- "and tx to apply AGC to the audio being sent to the channel. When using this\n" -- "function, you set a target audio level. It is primarily intended for use with\n" -- "analog lines, but could be useful for other channels, as well. The target volume\n" -- "is set with a number between 1 and 32768. Larger numbers are louder.\n" -- " Example Usage:\n" -- " Set(AGC(rx)=8000)\n" -- " Set(AGC(tx)=8000)\n" -- " Set(AGC(rx)=off)\n" -- " Set(AGC(tx)=off)\n" -- "", - .write = speex_write, - .read = speex_read - }; - - static struct ast_custom_function denoise_function = { - .name = "DENOISE", -- .synopsis = "Apply noise reduction to audio on a channel", -- .desc = -- " The DENOISE function will apply noise reduction to audio on the channel\n" -- "that this function is executed on. It is especially useful for noisy analog\n" -- "lines, especially when adjusting gains or using AGC. Use rx for audio\n" -- "received from the channel and tx to apply the filter to the audio being sent\n" -- "to the channel.\n" -- " Example Usage:\n" -- " Set(DENOISE(rx)=on)\n" -- " Set(DENOISE(tx)=on)\n" -- " Set(DENOISE(rx)=off)\n" -- " Set(DENOISE(tx)=off)\n" -- "", - .write = speex_write, - .read = speex_read - }; -Index: funcs/func_module.c -=================================================================== ---- a/funcs/func_module.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_module.c (.../team/group/issue14292) (revision 178988) -@@ -28,6 +28,24 @@ - #include "asterisk/module.h" - #include "asterisk/pbx.h" - -+/*** DOCUMENTATION -+ -+ -+ Checks if an Asterisk module is loaded in memory. -+ -+ -+ -+ Module name complete with .so -+ -+ -+ -+ Checks if a module is loaded. Use the full module name -+ as shown by the list in module list. -+ Returns 1 if module exists in memory, otherwise 0 -+ -+ -+ ***/ -+ - static int ifmodule_read(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -46,12 +64,7 @@ - - static struct ast_custom_function ifmodule_function = { - .name = "IFMODULE", -- .synopsis = "Checks if an Asterisk module is loaded in memory", -- .syntax = "IFMODULE()", - .read = ifmodule_read, -- .desc = "Checks if a module is loaded. Use the full module name\n" -- "as shown by the list in \"module list\". \n" -- "Returns \"1\" if module exists in memory, otherwise \"0\".\n", - }; - - -Index: funcs/func_md5.c -=================================================================== ---- a/funcs/func_md5.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_md5.c (.../team/group/issue14292) (revision 178988) -@@ -33,6 +33,20 @@ - #include "asterisk/module.h" - #include "asterisk/pbx.h" - -+/*** DOCUMENTATION -+ -+ -+ Computes an MD5 digest. -+ -+ -+ -+ -+ -+ Computes an MD5 digest. -+ -+ -+ ***/ -+ - static int md5(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -49,8 +63,6 @@ - - static struct ast_custom_function md5_function = { - .name = "MD5", -- .synopsis = "Computes an MD5 digest", -- .syntax = "MD5()", - .read = md5, - }; - -Index: funcs/func_dialgroup.c -=================================================================== ---- a/funcs/func_dialgroup.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_dialgroup.c (.../team/group/issue14292) (revision 178988) -@@ -39,6 +39,40 @@ - #include "asterisk/astobj2.h" - #include "asterisk/astdb.h" - -+/*** DOCUMENTATION -+ -+ -+ Manages a group of users for dialing. -+ -+ -+ -+ -+ The operation name, possible values are: -+ add - add a channel name or interface (write-only) -+ del - remove a channel name or interface (write-only) -+ -+ -+ -+ Presents an interface meant to be used in concert with the Dial -+ application, by presenting a list of channels which should be dialled when -+ referenced. -+ When DIALGROUP is read from, the argument is interpreted as the particular -+ group for which a dial should be attempted. When DIALGROUP is written to -+ with no arguments, the entire list is replaced with the argument specified. -+ Functionality is similar to a queue, except that when no interfaces are -+ available, execution may continue in the dialplan. This is useful when -+ you want certain people to be the first to answer any calls, with immediate -+ fallback to a queue when the front line people are busy or unavailable, but -+ you still want front line people to log in and out of that group, just like -+ a queue. -+ Example: -+ exten => 1,1,Set(DIALGROUP(mygroup,add)=SIP/10) -+ exten => 1,n,Set(DIALGROUP(mygroup,add)=SIP/20) -+ exten => 1,n,Dial(${DIALGROUP(mygroup)}) -+ -+ -+ ***/ -+ - static struct ao2_container *group_container = NULL; - - struct group_entry { -@@ -232,24 +266,6 @@ - - static struct ast_custom_function dialgroup_function = { - .name = "DIALGROUP", -- .synopsis = "Manages a group of users for dialing", -- .syntax = "DIALGROUP([,op])", -- .desc = --" DIALGROUP presents an interface meant to be used in concert with the Dial\n" --"application, by presenting a list of channels which should be dialled when\n" --"referenced.\n" --" When DIALGROUP is read from, the argument is interpreted as the particular\n" --"group for which a dial should be attempted. When DIALGROUP is written to\n" --"with no arguments, the entire list is replaced with the argument specified.\n" --"Other operations are as follows:\n" --" add - add a channel name or interface (write-only)\n" --" del - remove a channel name or interface (write-only)\n\n" --"Functionality is similar to a queue, except that when no interfaces are\n" --"available, execution may continue in the dialplan. This is useful when\n" --"you want certain people to be the first to answer any calls, with immediate\n" --"fallback to a queue when the front line people are busy or unavailable, but\n" --"you still want front line people to log in and out of that group, just like\n" --"a queue.\n", - .read = dialgroup_read, - .write = dialgroup_write, - }; -Index: funcs/func_env.c -=================================================================== ---- a/funcs/func_env.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_env.c (.../team/group/issue14292) (revision 178988) -@@ -33,6 +33,59 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Gets or sets the environment variable specified. -+ -+ -+ -+ Environment variable name -+ -+ -+ -+ -+ -+ -+ -+ Does a check on the specified file. -+ -+ -+ -+ Flag may be one of the following: -+ d - Checks if the file is a directory. -+ e - Checks if the file exists. -+ f - Checks if the file is a regular file. -+ m - Returns the file mode (in octal) -+ s - Returns the size (in bytes) of the file -+ A - Returns the epoch at which the file was last accessed. -+ C - Returns the epoch at which the inode was last changed. -+ M - Returns the epoch at which the file was last modified. -+ -+ -+ -+ -+ -+ -+ -+ -+ Obtains the contents of a file. -+ -+ -+ -+ -+ Maybe specified as any number. if negative offset specifies the number -+ of bytes back from the end of the file. -+ -+ -+ If specified, will limit the length of the data read to that size. -+ -+ -+ -+ -+ -+ ***/ -+ - static int env_read(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -151,43 +204,23 @@ - - static struct ast_custom_function env_function = { - .name = "ENV", -- .synopsis = "Gets or sets the environment variable specified", -- .syntax = "ENV()", - .read = env_read, -- .write = env_write, -+ .write = env_write - }; - - static struct ast_custom_function stat_function = { - .name = "STAT", -- .synopsis = "Does a check on the specified file", -- .syntax = "STAT(,)", -- .read = stat_read, -- .desc = -- "flag may be one of the following:\n" -- " d - Checks if the file is a directory\n" -- " e - Checks if the file exists\n" -- " f - Checks if the file is a regular file\n" -- " m - Returns the file mode (in octal)\n" -- " s - Returns the size (in bytes) of the file\n" -- " A - Returns the epoch at which the file was last accessed\n" -- " C - Returns the epoch at which the inode was last changed\n" -- " M - Returns the epoch at which the file was last modified\n", -+ .read = stat_read - }; - - static struct ast_custom_function file_function = { - .name = "FILE", -- .synopsis = "Obtains the contents of a file", -- .syntax = "FILE(,,)", -- .read = file_read, -+ .read = file_read - /* - * Some enterprising programmer could probably add write functionality - * to FILE(), although I'm not sure how useful it would be. Hence why - * it's called FILE and not READFILE (like the app was). - */ -- .desc = --" may be specified as any number. If negative, specifies\n" --" the number of bytes back from the end of the file.\n" --", if specified, will limit the length of the data read to that size.\n", - }; - - static int unload_module(void) -Index: funcs/func_strings.c -=================================================================== ---- a/funcs/func_strings.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_strings.c (.../team/group/issue14292) (revision 178988) -@@ -39,6 +39,240 @@ - #include "asterisk/app.h" - #include "asterisk/localtime.h" - -+AST_THREADSTORAGE(result_buf); -+ -+/*** DOCUMENTATION -+ -+ -+ Count the fields with an arbitrary delimiter -+ -+ -+ -+ -+ -+ -+ Example: ${FIELDQTY(ex-amp-le,-)} returns 3 -+ -+ -+ -+ Remove an item from a list, by name. -+ -+ -+ -+ -+ -+ -+ Remove value from the list contained in the varname -+ variable, where the list delimiter is specified by the delim parameter. This is -+ very useful for removing a single channel name from a list of channels, for example. -+ -+ -+ -+ -+ Filter the string to include only the allowed characters -+ -+ -+ -+ -+ -+ -+ Permits all characters listed in allowed-chars, -+ filtering all others outs. In addition to literally listing the characters, -+ you may also use ranges of characters (delimited by a - -+ Hexadecimal characters started with a \x(i.e. \x20) -+ Octal characters started with a \0 (i.e. \040) -+ Also \t,\n and \r are recognized. -+ If you want the - character it needs to be prefixed with a -+ \ -+ -+ -+ -+ -+ Check string against a regular expression. -+ -+ -+ -+ -+ -+ -+ Return 1 on regular expression match or 0 otherwise -+ Please note that the space following the double quotes separating the -+ regex from the data is optional and if present, is skipped. If a space is -+ desired at the beginning of the data, then put two spaces there; the second -+ will not be skipped. -+ -+ -+ -+ -+ Clear the keys from a specified hashname. -+ -+ -+ -+ -+ -+ Clears all keys out of the specified hashname. -+ -+ -+ -+ -+ Implementation of a dialplan associative array -+ -+ -+ -+ -+ -+ -+ In two arguments mode, gets and sets values to corresponding keys within -+ a named associative array. The single-argument mode will only work when assigned -+ to from a function defined by func_odbc -+ -+ -+ -+ -+ Retrieve the keys of the HASH() function. -+ -+ -+ -+ -+ -+ Returns a comma-delimited list of the current keys of the associative array -+ defined by the HASH() function. Note that if you iterate over the keys of -+ the result, adding keys during iteration will cause the result of the HASHKEYS() -+ function to change. -+ -+ -+ -+ -+ Hash the letters in string into equivalent keypad numbers. -+ -+ -+ -+ -+ -+ Example: ${KEYPADHASH(Les)} returns "537" -+ -+ -+ -+ -+ Allows setting multiple variables at once. -+ -+ -+ -+ -+ -+ -+ -+ The comma-delimited list passed as a value to which the function is set will -+ be interpreted as a set of values to which the comma-delimited list of -+ variable names in the argument should be set. -+ Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2 -+ -+ -+ -+ -+ Returns the epoch of the arbitrary date/time string structured as described by the format. -+ -+ -+ -+ -+ -+ -+ -+ This is useful for converting a date into EPOCH time, -+ possibly to pass to an application like SayUnixTime or to calculate the difference -+ between the two date strings -+ Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835 -+ -+ -+ -+ -+ Returns the current date/time in the specified format. -+ -+ -+ -+ -+ -+ -+ -+ STRFTIME supports all of the same formats as the underlying C function -+ strftime(3). -+ It also supports the following format: %[n]q - fractions of a second, -+ with leading zeros. -+ Example: %3q will give milliseconds and %1q -+ will give tenths of a second. The default is set at milliseconds (n=3). -+ The common case is to use it in combination with %S, as in %S.%3q. -+ -+ -+ strftime(3) -+ -+ -+ -+ -+ Evaluate stored variables -+ -+ -+ -+ -+ -+ Using EVAL basically causes a string to be evaluated twice. -+ When a variable or expression is in the dialplan, it will be -+ evaluated at runtime. However, if the results of the evaluation -+ is in fact another variable or expression, using EVAL will have it -+ evaluated a second time. -+ Example: If the MYVAR contains -+ OTHERVAR, then the result of ${EVAL( -+ MYVAR)} in the dialplan will be the -+ contents of OTHERVAR. Normally just -+ putting MYVAR in the dialplan the result -+ would be OTHERVAR. -+ -+ -+ -+ -+ Convert string to all uppercase letters. -+ -+ -+ -+ -+ -+ Example: ${TOUPPER(Example)} returns "EXAMPLE" -+ -+ -+ -+ -+ Convert string to all lowercase letters. -+ -+ -+ -+ -+ -+ Example: ${TOLOWER(Example)} returns "example" -+ -+ -+ -+ -+ Return the length of the string given. -+ -+ -+ -+ -+ -+ Example: ${LEN(example)} returns 7 -+ -+ -+ -+ -+ Quotes a given string, escaping embedded quotes as necessary -+ -+ -+ -+ -+ -+ Example: ${QUOTE(ab"c"de)} will return "abcde" -+ -+ -+ ***/ -+ - static int function_fieldqty(struct ast_channel *chan, const char *cmd, - char *parse, char *buf, size_t len) - { -@@ -75,11 +309,105 @@ - - static struct ast_custom_function fieldqty_function = { - .name = "FIELDQTY", -- .synopsis = "Count the fields, with an arbitrary delimiter", -- .syntax = "FIELDQTY(,)", - .read = function_fieldqty, - }; - -+static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) -+{ -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(listname); -+ AST_APP_ARG(delimiter); -+ AST_APP_ARG(fieldvalue); -+ ); -+ const char *orig_list, *ptr; -+ const char *begin, *cur, *next; -+ int dlen, flen, first = 1; -+ struct ast_str *result = ast_str_thread_get(&result_buf, 16); -+ char *delim; -+ -+ AST_STANDARD_APP_ARGS(args, parse); -+ -+ if (args.argc < 3) { -+ ast_log(LOG_ERROR, "Usage: LISTFILTER(,,)\n"); -+ return -1; -+ } -+ -+ /* If we don't lock the channel, the variable could disappear out from underneath us. */ -+ if (chan) { -+ ast_channel_lock(chan); -+ } -+ if (!(orig_list = pbx_builtin_getvar_helper(chan, args.listname))) { -+ ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname); -+ if (chan) { -+ ast_channel_unlock(chan); -+ } -+ return -1; -+ } -+ -+ /* If the string isn't there, just copy out the string and be done with it. */ -+ if (!(ptr = strstr(orig_list, args.fieldvalue))) { -+ ast_copy_string(buf, orig_list, len); -+ if (chan) { -+ ast_channel_unlock(chan); -+ } -+ return 0; -+ } -+ -+ dlen = strlen(args.delimiter); -+ delim = alloca(dlen + 1); -+ ast_get_encoded_str(args.delimiter, delim, dlen + 1); -+ -+ if ((dlen = strlen(delim)) == 0) { -+ delim = ","; -+ dlen = 1; -+ } -+ -+ flen = strlen(args.fieldvalue); -+ -+ ast_str_reset(result); -+ /* Enough space for any result */ -+ ast_str_make_space(&result, strlen(orig_list) + 1); -+ -+ begin = orig_list; -+ next = strstr(begin, delim); -+ -+ do { -+ /* Find next boundary */ -+ if (next) { -+ cur = next; -+ next = strstr(cur + dlen, delim); -+ } else { -+ cur = strchr(begin + dlen, '\0'); -+ } -+ -+ if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) { -+ /* Skip field */ -+ begin += flen + dlen; -+ } else { -+ /* Copy field to output */ -+ if (!first) { -+ ast_str_append(&result, 0, "%s", delim); -+ } -+ -+ ast_str_append_substr(&result, 0, begin, cur - begin + 1); -+ first = 0; -+ begin = cur + dlen; -+ } -+ } while (*cur != '\0'); -+ if (chan) { -+ ast_channel_unlock(chan); -+ } -+ -+ ast_copy_string(buf, ast_str_buffer(result), len); -+ -+ return 0; -+} -+ -+static struct ast_custom_function listfilter_function = { -+ .name = "LISTFILTER", -+ .read = listfilter, -+}; -+ - static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, - size_t len) - { -@@ -99,7 +427,7 @@ - } - - /* Expand ranges */ -- for (; *(args.allowed) && allowedlen < sizeof(allowed); (args.allowed)++) { -+ for (; *(args.allowed) && allowedlen < sizeof(allowed); ) { - char c1 = 0, c2 = 0; - size_t consumed = 0; - -@@ -141,16 +469,7 @@ - - static struct ast_custom_function filter_function = { - .name = "FILTER", -- .synopsis = "Filter the string to include only the allowed characters", -- .syntax = "FILTER(,)", - .read = filter, -- .desc = --"Permits all characters listed in , filtering all others out.\n" --"In addition to literally listing the characters, you may also use ranges of\n" --"characters (delimited by a '-'), as well as hexadecimal characters started\n" --"with a \\x (i.e. \\x20) and octal characters started with \\0 (i.e. \\040).\n" --"Also, \\t, \\n, and \\r are recognized. If you want a literal '-' character,\n" --"simply prefix it with a '\\'\n", - }; - - static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, -@@ -192,13 +511,6 @@ - - static struct ast_custom_function regex_function = { - .name = "REGEX", -- .synopsis = "Regular Expression", -- .desc = -- "Returns 1 if data matches regular expression, or 0 otherwise.\n" -- "Please note that the space following the double quotes separating the regex from the data\n" -- "is optional and if present, is skipped. If a space is desired at the beginning of the data,\n" -- "then put two spaces there; the second will not be skipped.\n", -- .syntax = "REGEX(\"\" )", - .read = regex, - }; - -@@ -206,10 +518,6 @@ - #define HASH_FORMAT HASH_PREFIX "%s~" - - static char *app_clearhash = "ClearHash"; --static char *syn_clearhash = "Clear the keys from a specified hashname"; --static char *desc_clearhash = --"ClearHash()\n" --" Clears all keys out of the specified hashname\n"; - - /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */ - static void clearvar_prefix(struct ast_channel *chan, const char *prefix) -@@ -388,195 +696,20 @@ - - static struct ast_custom_function hash_function = { - .name = "HASH", -- .synopsis = "Implementation of a dialplan associative array", -- .syntax = "HASH(hashname[,hashkey])", - .write = hash_write, - .read = hash_read, -- .desc = -- "In two argument mode, gets and sets values to corresponding keys within a named\n" -- "associative array. The single-argument mode will only work when assigned to from\n" -- "a function defined by func_odbc.so.\n", - }; - - static struct ast_custom_function hashkeys_function = { - .name = "HASHKEYS", -- .synopsis = "Retrieve the keys of a HASH()", -- .syntax = "HASHKEYS()", - .read = hashkeys_read, -- .desc = -- "Returns a comma-delimited list of the current keys of an associative array\n" -- "defined by the HASH() function. Note that if you iterate over the keys of\n" -- "the result, adding keys during iteration will cause the result of the HASHKEYS\n" -- "function to change.\n", - }; - - 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", - }; - --static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) --{ --#define SPRINTF_FLAG 0 --#define SPRINTF_WIDTH 1 --#define SPRINTF_PRECISION 2 --#define SPRINTF_LENGTH 3 --#define SPRINTF_CONVERSION 4 -- int i, state = -1, argcount = 0; -- char *formatstart = NULL, *bufptr = buf; -- char formatbuf[256] = ""; -- int tmpi; -- double tmpd; -- AST_DECLARE_APP_ARGS(arg, -- AST_APP_ARG(format); -- AST_APP_ARG(var)[100]; -- ); -- -- AST_STANDARD_APP_ARGS(arg, data); -- -- /* Scan the format, converting each argument into the requisite format type. */ -- for (i = 0; arg.format[i]; i++) { -- switch (state) { -- case SPRINTF_FLAG: -- if (strchr("#0- +'I", arg.format[i])) -- break; -- state = SPRINTF_WIDTH; -- case SPRINTF_WIDTH: -- if (arg.format[i] >= '0' && arg.format[i] <= '9') -- break; -- -- /* Next character must be a period to go into a precision */ -- if (arg.format[i] == '.') { -- state = SPRINTF_PRECISION; -- } else { -- state = SPRINTF_LENGTH; -- i--; -- } -- break; -- case SPRINTF_PRECISION: -- if (arg.format[i] >= '0' && arg.format[i] <= '9') -- break; -- state = SPRINTF_LENGTH; -- case SPRINTF_LENGTH: -- if (strchr("hl", arg.format[i])) { -- if (arg.format[i + 1] == arg.format[i]) -- i++; -- state = SPRINTF_CONVERSION; -- break; -- } else if (strchr("Lqjzt", arg.format[i])) { -- state = SPRINTF_CONVERSION; -- break; -- } -- state = SPRINTF_CONVERSION; -- case SPRINTF_CONVERSION: -- if (strchr("diouxXc", arg.format[i])) { -- /* Integer */ -- -- /* Isolate this format alone */ -- ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -- formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -- -- /* Convert the argument into the required type */ -- if (arg.var[argcount]) { -- if (sscanf(arg.var[argcount++], "%d", &tmpi) != 1) { -- ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf); -- goto sprintf_fail; -- } -- } else { -- ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n"); -- goto sprintf_fail; -- } -- -- /* Format the argument */ -- snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi); -- -- /* Update the position of the next parameter to print */ -- bufptr = strchr(buf, '\0'); -- } else if (strchr("eEfFgGaA", arg.format[i])) { -- /* Double */ -- -- /* Isolate this format alone */ -- ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -- formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -- -- /* Convert the argument into the required type */ -- if (arg.var[argcount]) { -- if (sscanf(arg.var[argcount++], "%lf", &tmpd) != 1) { -- ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf); -- goto sprintf_fail; -- } -- } else { -- ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n"); -- goto sprintf_fail; -- } -- -- /* Format the argument */ -- snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd); -- -- /* Update the position of the next parameter to print */ -- bufptr = strchr(buf, '\0'); -- } else if (arg.format[i] == 's') { -- /* String */ -- -- /* Isolate this format alone */ -- ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -- formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -- -- /* Format the argument */ -- snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]); -- -- /* Update the position of the next parameter to print */ -- bufptr = strchr(buf, '\0'); -- } else if (arg.format[i] == '%') { -- /* Literal data to copy */ -- *bufptr++ = arg.format[i]; -- } else { -- /* Not supported */ -- -- /* Isolate this format alone */ -- ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -- formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -- -- ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]); -- goto sprintf_fail; -- } -- state = -1; -- break; -- default: -- if (arg.format[i] == '%') { -- state = SPRINTF_FLAG; -- formatstart = &arg.format[i]; -- break; -- } else { -- /* Literal data to copy */ -- *bufptr++ = arg.format[i]; -- } -- } -- } -- *bufptr = '\0'; -- return 0; --sprintf_fail: -- return -1; --} -- --static struct ast_custom_function sprintf_function = { -- .name = "SPRINTF", -- .synopsis = "Format a variable according to a format string", -- .syntax = "SPRINTF(,[,...])", -- .read = acf_sprintf, -- .desc = --"Parses the format string specified and returns a string matching that format.\n" --"Supports most options supported by sprintf(3). Returns a shortened string if\n" --"a format specifier is not recognized.\n", --}; -- - static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) - { - char *bufptr = buf, *dataptr = data; -@@ -601,8 +734,6 @@ - - static struct ast_custom_function quote_function = { - .name = "QUOTE", -- .synopsis = "Quotes a given string, escaping embedded quotes as necessary", -- .syntax = "QUOTE()", - .read = quote, - }; - -@@ -622,8 +753,6 @@ - - static struct ast_custom_function len_function = { - .name = "LEN", -- .synopsis = "Returns the length of the argument given", -- .syntax = "LEN()", - .read = len, - }; - -@@ -658,16 +787,6 @@ - - static struct ast_custom_function strftime_function = { - .name = "STRFTIME", -- .synopsis = "Returns the current date/time in a specified format.", -- .syntax = "STRFTIME([][,[timezone][,format]])", -- .desc = --"STRFTIME sports all of the same formats as the underlying C function\n" --"strftime(3) - see the man page for details. It also supports the\n" --"following format:\n" --" %[n]q - fractions of a second, with leading zeroes. For example, %3q will\n" --" give milliseconds and %1q will give tenths of a second. The default\n" --" is to output milliseconds (n=3). The common case is to use it in\n" --" combination with %S, as in \"%S.%3q\".\n", - .read = acf_strftime, - }; - -@@ -679,10 +798,7 @@ - AST_APP_ARG(timezone); - AST_APP_ARG(format); - ); -- union { -- struct ast_tm atm; -- struct tm time; -- } t = { { 0, }, }; -+ struct ast_tm tm; - - buf[0] = '\0'; - -@@ -700,13 +816,11 @@ - return -1; - } - -- if (!strptime(args.timestring, args.format, &t.time)) { -- ast_log(LOG_WARNING, "C function strptime() output nothing?!!\n"); -+ if (!ast_strptime(args.timestring, args.format, &tm)) { -+ ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n"); - } else { - struct timeval when; -- /* Since strptime(3) does not check DST, force ast_mktime() to calculate it. */ -- t.atm.tm_isdst = -1; -- when = ast_mktime(&t.atm, args.timezone); -+ when = ast_mktime(&tm, args.timezone); - snprintf(buf, buflen, "%d", (int) when.tv_sec); - } - -@@ -715,16 +829,6 @@ - - static struct ast_custom_function strptime_function = { - .name = "STRPTIME", -- .synopsis = -- "Returns the epoch of the arbitrary date/time string structured as described in the format.", -- .syntax = "STRPTIME(,,)", -- .desc = -- "This is useful for converting a date into an EPOCH time, possibly to pass to\n" -- "an application like SayUnixTime or to calculate the difference between two\n" -- "date strings.\n" -- "\n" -- "Example:\n" -- " ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835\n", - .read = acf_strptime, - }; - -@@ -743,17 +847,6 @@ - - static struct ast_custom_function eval_function = { - .name = "EVAL", -- .synopsis = "Evaluate stored variables.", -- .syntax = "EVAL()", -- .desc = "Using EVAL basically causes a string to be evaluated twice.\n" -- "When a variable or expression is in the dialplan, it will be\n" -- "evaluated at runtime. However, if the result of the evaluation\n" -- "is in fact a variable or expression, using EVAL will have it\n" -- "evaluated a second time. For example, if the variable ${MYVAR}\n" -- "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n" -- "in the dialplan will be the contents of the variable, OTHERVAR.\n" -- "Normally, by just putting ${MYVAR} in the dialplan, you would be\n" -- "left with \"${OTHERVAR}\".\n", - .read = function_eval, - }; - -@@ -794,10 +887,7 @@ - - static struct ast_custom_function keypadhash_function = { - .name = "KEYPADHASH", -- .synopsis = "Hash the letters in the string into the equivalent keypad numbers.", -- .syntax = "KEYPADHASH()", - .read = keypadhash, -- .desc = "Example: ${KEYPADHASH(Les)} returns \"537\"\n", - }; - - static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) -@@ -811,10 +901,7 @@ - - static struct ast_custom_function toupper_function = { - .name = "TOUPPER", -- .synopsis = "Convert the string to upper case.", -- .syntax = "TOUPPER()", - .read = string_toupper, -- .desc = "Example: ${TOUPPER(Example)} returns \"EXAMPLE\"\n", - }; - - static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) -@@ -828,10 +915,7 @@ - - static struct ast_custom_function tolower_function = { - .name = "TOLOWER", -- .synopsis = "Convert the string to lower case.", -- .syntax = "TOLOWER()", - .read = string_tolower, -- .desc = "Example: ${TOLOWER(Example)} returns \"example\"\n", - }; - - static int unload_module(void) -@@ -840,6 +924,7 @@ - - res |= ast_custom_function_unregister(&fieldqty_function); - res |= ast_custom_function_unregister(&filter_function); -+ res |= ast_custom_function_unregister(&listfilter_function); - res |= ast_custom_function_unregister(®ex_function); - res |= ast_custom_function_unregister(&array_function); - res |= ast_custom_function_unregister("e_function); -@@ -848,7 +933,6 @@ - res |= ast_custom_function_unregister(&strptime_function); - res |= ast_custom_function_unregister(&eval_function); - res |= ast_custom_function_unregister(&keypadhash_function); -- res |= ast_custom_function_unregister(&sprintf_function); - res |= ast_custom_function_unregister(&hashkeys_function); - res |= ast_custom_function_unregister(&hash_function); - res |= ast_unregister_application(app_clearhash); -@@ -864,6 +948,7 @@ - - res |= ast_custom_function_register(&fieldqty_function); - res |= ast_custom_function_register(&filter_function); -+ res |= ast_custom_function_register(&listfilter_function); - res |= ast_custom_function_register(®ex_function); - res |= ast_custom_function_register(&array_function); - res |= ast_custom_function_register("e_function); -@@ -872,10 +957,9 @@ - res |= ast_custom_function_register(&strptime_function); - res |= ast_custom_function_register(&eval_function); - res |= ast_custom_function_register(&keypadhash_function); -- res |= ast_custom_function_register(&sprintf_function); - res |= ast_custom_function_register(&hashkeys_function); - res |= ast_custom_function_register(&hash_function); -- res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash); -+ res |= ast_register_application_xml(app_clearhash, exec_clearhash); - res |= ast_custom_function_register(&toupper_function); - res |= ast_custom_function_register(&tolower_function); - -Index: funcs/func_vmcount.c -=================================================================== ---- a/funcs/func_vmcount.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_vmcount.c (.../team/group/issue14292) (revision 178988) -@@ -39,6 +39,30 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Count the voicemails in a specified mailbox. -+ -+ -+ -+ -+ -+ If not specified, defaults to default. -+ -+ -+ -+ If not specified, defaults to INBOX -+ -+ -+ -+ Count the number of voicemails in a specified mailbox, you could also specify -+ the context and the mailbox folder. -+ Example: exten => s,1,Set(foo=${VMCOUNT(125)}) -+ -+ -+ ***/ -+ - static int acf_vmcount_exec(struct ast_channel *chan, const char *cmd, char *argsstr, char *buf, size_t len) - { - char *context; -@@ -72,11 +96,6 @@ - - struct ast_custom_function acf_vmcount = { - .name = "VMCOUNT", -- .synopsis = "Counts the voicemail in a specified mailbox", -- .syntax = "VMCOUNT(vmbox[@context][,folder])", -- .desc = -- " context - defaults to \"default\"\n" -- " folder - defaults to \"INBOX\"\n", - .read = acf_vmcount_exec, - }; - -Index: funcs/func_sha1.c -=================================================================== ---- a/funcs/func_sha1.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_sha1.c (.../team/group/issue14292) (revision 178988) -@@ -31,6 +31,25 @@ - #include "asterisk/module.h" - #include "asterisk/pbx.h" - -+/*** DOCUMENTATION -+ -+ -+ Computes a SHA1 digest. -+ -+ -+ -+ Input string -+ -+ -+ -+ Generate a SHA1 digest via the SHA1 algorythm. -+ Example: Set(sha1hash=${SHA1(junky)}) -+ Sets the asterisk variable sha1hash to the string 60fa5675b9303eb62f99a9cd47f9f5837d18f9a0 -+ which is known as his hash -+ -+ -+ ***/ -+ - static int sha1(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -54,13 +73,7 @@ - - static struct ast_custom_function sha1_function = { - .name = "SHA1", -- .synopsis = "Computes a SHA1 digest", -- .syntax = "SHA1()", - .read = sha1, -- .desc = "Generate a SHA1 digest via the SHA1 algorythm.\n" -- " Example: Set(sha1hash=${SHA1(junky)})\n" -- " Sets the asterisk variable sha1hash to the string '60fa5675b9303eb62f99a9cd47f9f5837d18f9a0'\n" -- " which is known as his hash\n", - }; - - static int unload_module(void) -Index: funcs/func_logic.c -=================================================================== ---- a/funcs/func_logic.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_logic.c (.../team/group/issue14292) (revision 178988) -@@ -34,6 +34,83 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Check if a value is NULL. -+ -+ -+ -+ -+ -+ Returns 1 if NULL or 0 otherwise. -+ -+ -+ -+ -+ SET assigns a value to a channel variable. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Test the existence of a value. -+ -+ -+ -+ -+ -+ Returns 1 if exists, 0 otherwise. -+ -+ -+ -+ -+ Check for an expresion. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Returns the data following ? if true, else the data following : -+ -+ -+ -+ -+ Temporal Conditional. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Returns the data following ? if true, else the data following : -+ -+ -+ -+ -+ Retrieve the value of a variable from another channel. -+ -+ -+ -+ -+ -+ -+ -+ -+ ***/ -+ - static int isnull(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -71,6 +148,7 @@ - - if (!ast_build_timing(&timing, expr)) { - ast_log(LOG_WARNING, "Invalid Time Spec.\n"); -+ ast_destroy_timing(&timing); - return -1; - } - -@@ -80,6 +158,7 @@ - iffalse = ast_strip_quoted(iffalse, "\"", "\""); - - ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len); -+ ast_destroy_timing(&timing); - - return 0; - } -@@ -168,46 +247,31 @@ - - static struct ast_custom_function isnull_function = { - .name = "ISNULL", -- .synopsis = "NULL Test: Returns 1 if NULL or 0 otherwise", -- .syntax = "ISNULL()", - .read = isnull, - }; - - static struct ast_custom_function set_function = { - .name = "SET", -- .synopsis = "SET assigns a value to a channel variable", -- .syntax = "SET(=[])", - .read = set, - }; - - static struct ast_custom_function exists_function = { - .name = "EXISTS", -- .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise", -- .syntax = "EXISTS()", - .read = exists, - }; - - static struct ast_custom_function if_function = { - .name = "IF", -- .synopsis = -- "Conditional: Returns the data following '?' if true, else the data following ':'", -- .syntax = "IF(?[][:])", - .read = acf_if, - }; - - static struct ast_custom_function if_time_function = { - .name = "IFTIME", -- .synopsis = -- "Temporal Conditional: Returns the data following '?' if true, else the data following ':'", -- .syntax = "IFTIME(?[][:])", - .read = iftime, - }; - - static struct ast_custom_function import_function = { - .name = "IMPORT", -- .synopsis = -- "Retrieve the value of a variable from another channel\n", -- .syntax = "IMPORT(channel,variable)", - .read = acf_import, - }; - -Index: funcs/func_uri.c -=================================================================== ---- a/funcs/func_uri.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_uri.c (.../team/group/issue14292) (revision 178988) -@@ -38,6 +38,35 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Encodes a string to URI-safe encoding according to RFC 2396. -+ -+ -+ -+ Input string to be encoded. -+ -+ -+ -+ Returns the encoded string defined in data. -+ -+ -+ -+ -+ Decodes a URI-encoded string according to RFC 2396. -+ -+ -+ -+ Input string to be decoded. -+ -+ -+ -+ Returns the decoded URI-encoded data string. -+ -+ -+ ***/ -+ - /*! \brief uriencode: Encode URL according to RFC 2396 */ - static int uriencode(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) -@@ -69,15 +98,11 @@ - - static struct ast_custom_function urldecode_function = { - .name = "URIDECODE", -- .synopsis = "Decodes a URI-encoded string according to RFC 2396.", -- .syntax = "URIDECODE()", - .read = uridecode, - }; - - static struct ast_custom_function urlencode_function = { - .name = "URIENCODE", -- .synopsis = "Encodes a string to URI-safe encoding according to RFC 2396.", -- .syntax = "URIENCODE()", - .read = uriencode, - }; - -Index: funcs/func_enum.c -=================================================================== ---- a/funcs/func_enum.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_enum.c (.../team/group/issue14292) (revision 178988) -@@ -46,6 +46,109 @@ - #include "asterisk/enum.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Initiate an ENUM query. -+ -+ -+ -+ -+ If no method-type is given, the default will be -+ sip. -+ -+ -+ If no zone-suffix is given, the default will be -+ e164.arpa -+ -+ -+ -+ This will do a ENUM lookup of the given phone number. -+ -+ -+ -+ -+ Retrieve results from a ENUMQUERY. -+ -+ -+ -+ The identifier returned by the ENUMQUERY function. -+ -+ -+ The number of the result that you want to retrieve. -+ Results start at 1. If this argument is specified -+ as getnum, then it will return the total number of results -+ that are available. -+ -+ -+ -+ This function will retrieve results from a previous use -+ of the ENUMQUERY function. -+ -+ -+ -+ -+ General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers. -+ -+ -+ -+ -+ If no method-type is given, the default will be -+ sip. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ If no record# is given, -+ defaults to 1. -+ -+ -+ If no zone-suffix is given, the default will be -+ e164.arpa -+ -+ -+ -+ For more information see doc/asterisk.pdf. -+ -+ -+ -+ -+ TXTCIDNAME looks up a caller name via DNS. -+ -+ -+ -+ -+ If no zone-suffix is given, the default will be -+ e164.arpa -+ -+ -+ -+ This function looks up the given phone number in DNS to retrieve -+ the caller id name. The result will either be blank or be the value -+ found in the TXT record in DNS. -+ -+ -+ ***/ -+ - static char *synopsis = "Syntax: ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])\n"; - - static int function_enum(struct ast_channel *chan, const char *cmd, char *data, -@@ -295,44 +398,16 @@ - - static struct ast_custom_function enum_query_function = { - .name = "ENUMQUERY", -- .synopsis = "Initiate an ENUM query", -- .syntax = "ENUMQUERY(number[,Method-type[,zone-suffix]])", -- .desc = "This will do a ENUM lookup of the given phone number.\n" -- "If no method-tpye is given, the default will be sip. If no\n" -- "zone-suffix is given, the default will be \"e164.arpa\".\n" -- "The result of this function will be a numeric ID that can\n" -- "be used to retrieve the results using the ENUMRESULT function.\n", - .read = enum_query_read, - }; - - static struct ast_custom_function enum_result_function = { - .name = "ENUMRESULT", -- .synopsis = "Retrieve results from a ENUMQUERY", -- .syntax = "ENUMRESULT(id,resultnum)", -- .desc = "This function will retrieve results from a previous use\n" -- "of the ENUMQUERY function.\n" -- " id - This argument is the identifier returned by the ENUMQUERY function.\n" -- " resultnum - This is the number of the result that you want to retrieve.\n" -- " Results start at 1. If this argument is specified as \"getnum\",\n" -- " then it will return the total number of results that are available.\n", - .read = enum_result_read, - }; - - static struct ast_custom_function enum_function = { - .name = "ENUMLOOKUP", -- .synopsis = -- "General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers", -- .syntax = -- "ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])", -- .desc = -- "Option 'c' returns an integer count of the number of NAPTRs of a certain RR type.\n" -- "Combination of 'c' and Method-type of 'ALL' will return a count of all NAPTRs for the record.\n" -- "Option 'u' returns the full URI and does not strip off the URI-scheme.\n" -- "Option 's' triggers ISN specific rewriting\n" -- "Option 'i' looks for branches into an Infrastructure ENUM tree\n" -- "Option 'd' for a direct DNS lookup without any flipping of digits\n" -- "Defaults are: Method-type=sip, no options, record=1, zone-suffix=e164.arpa\n\n" -- "For more information, see doc/asterisk.pdf", - .read = function_enum, - }; - -@@ -370,12 +445,6 @@ - - static struct ast_custom_function txtcidname_function = { - .name = "TXTCIDNAME", -- .synopsis = "TXTCIDNAME looks up a caller name via DNS", -- .syntax = "TXTCIDNAME([,zone-suffix])", -- .desc = -- "This function looks up the given phone number in DNS to retrieve\n" -- "the caller id name. The result will either be blank or be the value\n" -- "found in the TXT record in DNS. The default zone-suffix is e164.arpa.\n", - .read = function_txtcidname, - }; - -Index: funcs/func_audiohookinherit.c -=================================================================== ---- a/funcs/func_audiohookinherit.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_audiohookinherit.c (.../team/group/issue14292) (revision 178988) -@@ -36,6 +36,58 @@ - #include "asterisk/pbx.h" - #include "asterisk/module.h" - -+/*** DOCUMENTATION -+ -+ -+ Set whether an audiohook may be inherited to another channel -+ -+ -+ -+ The built-in sources in Asterisk are -+ -+ -+ -+ -+ -+ -+ -+ Note that the names are not case-sensitive -+ -+ -+ -+ By enabling audiohook inheritance on the channel, you are giving -+ permission for an audiohook to be inherited by a descendent channel. -+ Inheritance may be be disabled at any point as well. -+ -+ Example scenario: -+ exten => 2000,1,MixMonitor(blah.wav) -+ exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes) -+ exten => 2000,n,Dial(SIP/2000) -+ -+ -+ exten => 4000,1,Dial(SIP/4000) -+ -+ -+ exten => 5000,1,MixMonitor(blah2.wav) -+ exten => 5000,n,Dial(SIP/5000) -+ -+ -+ In this basic dialplan scenario, let's consider the following sample calls -+ Call 1: Caller dials 2000. The person who answers then executes an attended -+ transfer to 4000. -+ Result: Since extension 2000 set MixMonitor to be inheritable, after the -+ transfer to 4000 has completed, the call will continue to be recorded -+ to blah.wav -+ -+ -+ Call 2: Caller dials 5000. The person who answers then executes an attended -+ transfer to 4000. -+ Result: Since extension 5000 did not set MixMonitor to be inheritable, the -+ recording will stop once the call has been transferred to 4000. -+ -+ -+ ***/ -+ - struct inheritable_audiohook { - AST_LIST_ENTRY(inheritable_audiohook) list; - char source[1]; -@@ -222,34 +274,6 @@ - - static struct ast_custom_function inheritance_function = { - .name = "AUDIOHOOK_INHERIT", -- .synopsis = "Set whether an audiohook may be inherited to another channel", -- .syntax = "AUDIOHOOK_INHERIT(source)", -- .desc = -- "By enabling audiohook inheritance on the channel, you are giving\n" -- "permission for an audiohook to be inherited by a descendent channel.\n" -- "Inheritance may be be disabled at any point as well.\n" -- "\n" -- " Example scenario:\n" -- " exten => 2000,1,MixMonitor(blah.wav)\n" -- " exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)\n" -- " exten => 2000,n,Dial(SIP/2000)\n" -- "\n" -- " exten => 4000,1,Dial(SIP/4000)\n" -- "\n" -- " exten => 5000,1,MixMonitor(blah2.wav)\n" -- " exten => 5000,n,Dial(SIP/5000)\n" -- "\n" -- " In this basic dialplan scenario, let's consider the following sample calls\n" -- " Call 1: Caller dials 2000. The person who answers then executes an attended\n" -- " transfer to 4000.\n" -- " Result: Since extension 2000 set MixMonitor to be inheritable, after the\n" -- " transfer to 400 has completed, the call will continue to be recorded\n" -- " to blah.wav\n" -- "\n" -- " Call 2: Caller dials 5000. The person who answers then executes an attended\n" -- " transfer to 4000.\n" -- " Result: Since extension 5000 did not set MixMonitor to be inheritable, the\n" -- " recording will stop once the call has been transferred to 4000.\n", - .write = func_inheritance_write, - }; - -Index: funcs/func_config.c -=================================================================== ---- a/funcs/func_config.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_config.c (.../team/group/issue14292) (revision 178988) -@@ -36,6 +36,23 @@ - #include "asterisk/pbx.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Retrieve a variable from a configuration file. -+ -+ -+ -+ -+ -+ -+ -+ This function reads a variable from an Asterisk configuration file. -+ -+ -+ -+***/ -+ - struct config_item { - AST_RWLIST_ENTRY(config_item) entry; - struct ast_config *cfg; -@@ -82,7 +99,7 @@ - return -1; - } - -- if (!(cfg = ast_config_load(args.filename, cfg_flags))) { -+ if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { - return -1; - } - -@@ -107,7 +124,7 @@ - strcpy(cur->filename, args.filename); - - ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED); -- if (!(cfg = ast_config_load(args.filename, cfg_flags))) { -+ if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { - ast_free(cur); - AST_RWLIST_UNLOCK(&configs); - return -1; -@@ -160,11 +177,6 @@ - - static struct ast_custom_function config_function = { - .name = "AST_CONFIG", -- .syntax = "AST_CONFIG(config_file,category,variable_name)", -- .synopsis = "Retrieve a variable from a configuration file", -- .desc = -- " This function reads a variable from an Asterisk configuration file.\n" -- "", - .read = config_function_read, - }; - -Index: funcs/func_groupcount.c -=================================================================== ---- a/funcs/func_groupcount.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_groupcount.c (.../team/group/issue14292) (revision 178988) -@@ -31,6 +31,67 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Counts the number of channels in the specified group. -+ -+ -+ -+ Group name. -+ -+ -+ Category name -+ -+ -+ -+ Calculates the group count for the specified group, or uses the -+ channel's current group if not specifed (and non-empty). -+ -+ -+ -+ -+ Counts the number of channels in the groups matching the specified pattern. -+ -+ -+ -+ A standard regular expression used to match a group name. -+ -+ -+ Category name. -+ -+ -+ -+ Calculates the group count for all groups that match the specified pattern. -+ Uses standard regular expression matching (see regex(7)). -+ -+ -+ -+ -+ Gets or sets the channel group. -+ -+ -+ -+ Category name. -+ -+ -+ -+ category can be employed for more fine grained group management. Each channel -+ can only be member of exactly one group per category. -+ -+ -+ -+ -+ Gets a list of the groups set on a channel. -+ -+ -+ -+ Gets a list of the groups set on a channel. -+ -+ -+ -+ ***/ -+ - static int group_count_function_read(struct ast_channel *chan, const char *cmd, - char *data, char *buf, size_t len) - { -@@ -72,11 +133,6 @@ - - static struct ast_custom_function group_count_function = { - .name = "GROUP_COUNT", -- .syntax = "GROUP_COUNT([groupname][@category])", -- .synopsis = "Counts the number of channels in the specified group", -- .desc = -- "Calculates the group count for the specified group, or uses the\n" -- "channel's current group if not specifed (and non-empty).\n", - .read = group_count_function_read, - }; - -@@ -102,12 +158,6 @@ - - static struct ast_custom_function group_match_count_function = { - .name = "GROUP_MATCH_COUNT", -- .syntax = "GROUP_MATCH_COUNT(groupmatch[@category])", -- .synopsis = -- "Counts the number of channels in the groups matching the specified pattern", -- .desc = -- "Calculates the group count for all groups that match the specified pattern.\n" -- "Uses standard regular expression matching (see regex(7)).\n", - .read = group_match_count_function_read, - .write = NULL, - }; -@@ -159,9 +209,6 @@ - - static struct ast_custom_function group_function = { - .name = "GROUP", -- .syntax = "GROUP([category])", -- .synopsis = "Gets or sets the channel group.", -- .desc = "Gets or sets the channel group.\n", - .read = group_function_read, - .write = group_function_write, - }; -@@ -204,9 +251,6 @@ - - static struct ast_custom_function group_list_function = { - .name = "GROUP_LIST", -- .syntax = "GROUP_LIST()", -- .synopsis = "Gets a list of the groups set on a channel.", -- .desc = "Gets a list of the groups set on a channel.\n", - .read = group_list_function_read, - .write = NULL, - }; -Index: funcs/func_odbc.c -=================================================================== ---- a/funcs/func_odbc.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_odbc.c (.../team/group/issue14292) (revision 178988) -@@ -2,6 +2,7 @@ - * Asterisk -- An open source telephony toolkit. - * - * Copyright (c) 2005, 2006 Tilghman Lesher -+ * Copyright (c) 2008 Digium, Inc. - * - * Tilghman Lesher - * -@@ -27,8 +28,6 @@ - */ - - /*** MODULEINFO -- unixodbc -- ltdl - res_odbc - ***/ - -@@ -43,7 +42,61 @@ - #include "asterisk/config.h" - #include "asterisk/res_odbc.h" - #include "asterisk/app.h" -+#include "asterisk/cli.h" -+#include "asterisk/strings.h" - -+/*** DOCUMENTATION -+ -+ -+ Fetch a row from a multirow query. -+ -+ -+ -+ -+ -+ For queries which are marked as mode=multirow, the original -+ query returns a result-id from which results -+ may be fetched. This function implements the actual fetch of the results. -+ This also sets ODBC_FETCH_STATUS. -+ -+ -+ -+ If rows are available. -+ -+ -+ If no rows are available. -+ -+ -+ -+ -+ -+ -+ -+ Clear the resultset of a sucessful multirow query. -+ -+ -+ -+ -+ -+ For queries which are marked as mode=multirow, this will clear -+ any remaining rows of the specified resultset. -+ -+ -+ -+ -+ Escapes single ticks for use in SQL statements. -+ -+ -+ -+ -+ -+ Used in SQL templates to escape data which may contain single ticks -+ ' which are otherwise used to delimit data. -+ Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}' -+ -+ -+ ***/ -+ - static char *config = "func_odbc.conf"; - - enum { -@@ -57,6 +110,7 @@ - char writehandle[5][30]; - char sql_read[2048]; - char sql_write[2048]; -+ char sql_insert[2048]; - unsigned int flags; - int rowlimit; - struct ast_custom_function *acf; -@@ -85,6 +139,8 @@ - - static int resultcount = 0; - -+AST_THREADSTORAGE(sql_buf); -+AST_THREADSTORAGE(sql2_buf); - AST_THREADSTORAGE(coldata_buf); - AST_THREADSTORAGE(colnames_buf); - -@@ -109,15 +165,32 @@ - - 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"); -+ ast_log(LOG_WARNING, "SQL Alloc Handle failed (%d)!\n", res); - return NULL; - } - - res = SQLExecDirect(stmt, (unsigned char *)sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -- ast_log(LOG_WARNING, "SQL Exec Direct failed![%s]\n", sql); -+ if (res == SQL_ERROR) { -+ int i; -+ SQLINTEGER nativeerror=0, numfields=0; -+ SQLSMALLINT diagbytes=0; -+ unsigned char state[10], diagnostic[256]; -+ -+ 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; -+ } -+ } -+ } -+ -+ ast_log(LOG_WARNING, "SQL Exec Direct failed (%d)![%s]\n", res, sql); - SQLCloseCursor(stmt); -- SQLFreeHandle (SQL_HANDLE_STMT, stmt); -+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); - return NULL; - } - -@@ -133,6 +206,7 @@ - struct acf_odbc_query *query; - char *t, varname[15]; - int i, dsn, bogus_chan = 0; -+ int transactional = 0; - AST_DECLARE_APP_ARGS(values, - AST_APP_ARG(field)[100]; - ); -@@ -141,7 +215,9 @@ - ); - SQLHSTMT stmt = NULL; - SQLLEN rows=0; -- struct ast_str *buf = ast_str_create(16); -+ struct ast_str *buf = ast_str_thread_get(&sql_buf, 16); -+ struct ast_str *insertbuf = ast_str_thread_get(&sql2_buf, 16); -+ const char *status = "FAILURE"; - - if (!buf) { - return -1; -@@ -157,7 +233,7 @@ - if (!query) { - ast_log(LOG_ERROR, "No such function '%s'\n", cmd); - AST_RWLIST_UNLOCK(&queries); -- ast_free(buf); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); - return -1; - } - -@@ -169,7 +245,8 @@ - if (chan) - ast_autoservice_start(chan); - -- ast_str_make_space(&buf, strlen(query->sql_write) * 2); -+ ast_str_make_space(&buf, strlen(query->sql_write) * 2 + 300); -+ ast_str_make_space(&insertbuf, strlen(query->sql_insert) * 2 + 300); - - /* Parse our arguments */ - t = value ? ast_strdupa(value) : ""; -@@ -179,9 +256,11 @@ - AST_RWLIST_UNLOCK(&queries); - if (chan) - ast_autoservice_stop(chan); -- if (bogus_chan) -+ if (bogus_chan) { - ast_channel_free(chan); -- ast_free(buf); -+ } else { -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); -+ } - return -1; - } - -@@ -201,7 +280,8 @@ - /* Additionally set the value as a whole (but push an empty string if value is NULL) */ - pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); - -- pbx_substitute_variables_helper(chan, query->sql_write, buf->str, buf->len - 1); -+ ast_str_substitute_variables(&buf, 0, chan, query->sql_write); -+ ast_str_substitute_variables(&insertbuf, 0, chan, query->sql_insert); - - /* Restore prior values */ - for (i = 0; i < args.argc; i++) { -@@ -215,42 +295,79 @@ - } - pbx_builtin_setvar_helper(chan, "VALUE", NULL); - -- AST_RWLIST_UNLOCK(&queries); -+ /*!\note -+ * Okay, this part is confusing. Transactions belong to a single database -+ * handle. Therefore, when working with transactions, we CANNOT failover -+ * to multiple DSNs. We MUST have a single handle all the way through the -+ * transaction, or else we CANNOT enforce atomicity. -+ */ -+ for (dsn = 0; dsn < 5; dsn++) { -+ if (transactional) { -+ /* This can only happen second time through or greater. */ -+ ast_log(LOG_WARNING, "Transactions do not work well with multiple DSNs for 'writehandle'\n"); -+ } - -- for (dsn = 0; dsn < 5; dsn++) { - if (!ast_strlen_zero(query->writehandle[dsn])) { -- obj = ast_odbc_request_obj(query->writehandle[dsn], 0); -- if (obj) -- stmt = ast_odbc_direct_execute(obj, generic_execute, buf->str); -+ if ((obj = ast_odbc_retrieve_transaction_obj(chan, query->writehandle[dsn]))) { -+ transactional = 1; -+ } else { -+ obj = ast_odbc_request_obj(query->writehandle[dsn], 0); -+ transactional = 0; -+ } -+ if (obj && (stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(buf)))) { -+ break; -+ } - } -- if (stmt) -- break; -+ -+ if (obj && !transactional) { -+ ast_odbc_release_obj(obj); -+ } - } - -- if (stmt) { -- /* Rows affected */ -+ if (stmt && rows == 0 && ast_str_strlen(insertbuf) != 0) { -+ SQLCloseCursor(stmt); -+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); -+ for (dsn = 0; dsn < 5; dsn++) { -+ if (!ast_strlen_zero(query->writehandle[dsn])) { -+ obj = ast_odbc_request_obj(query->writehandle[dsn], 0); -+ if (obj) { -+ stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(insertbuf)); -+ } -+ } -+ if (stmt) { -+ status = "FAILOVER"; -+ SQLRowCount(stmt, &rows); -+ break; -+ } -+ } -+ } else if (stmt) { -+ status = "SUCCESS"; - SQLRowCount(stmt, &rows); - } - -+ AST_RWLIST_UNLOCK(&queries); -+ - /* 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); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); - - if (stmt) { - SQLCloseCursor(stmt); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - } -- if (obj) -+ if (obj && !transactional) { - ast_odbc_release_obj(obj); -+ obj = NULL; -+ } - - if (chan) - ast_autoservice_stop(chan); - if (bogus_chan) - ast_channel_free(chan); -- ast_free(buf); - - return 0; - } -@@ -271,9 +388,11 @@ - SQLSMALLINT collength; - struct odbc_datastore *resultset = NULL; - struct odbc_datastore_row *row = NULL; -- struct ast_str *sql = ast_str_create(16); -+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 16); -+ const char *status = "FAILURE"; - - if (!sql) { -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); - return -1; - } - -@@ -290,17 +409,19 @@ - ast_log(LOG_ERROR, "No such function '%s'\n", cmd); - AST_RWLIST_UNLOCK(&queries); - pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); -- ast_free(sql); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); - return -1; - } - - if (!chan) { -- if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) -+ if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) { - bogus_chan = 1; -+ } - } - -- if (chan) -+ if (chan) { - ast_autoservice_start(chan); -+ } - - AST_STANDARD_APP_ARGS(args, s); - for (x = 0; x < args.argc; x++) { -@@ -308,8 +429,7 @@ - pbx_builtin_pushvar_helper(chan, varname, args.field[x]); - } - -- ast_str_make_space(&sql, strlen(query->sql_read) * 2); -- pbx_substitute_variables_helper(chan, query->sql_read, sql->str, sql->len - 1); -+ ast_str_substitute_variables(&sql, 0, chan, query->sql_read); - - /* Restore prior values */ - for (x = 0; x < args.argc; x++) { -@@ -322,48 +442,56 @@ - if (ast_test_flag(query, OPT_MULTIROW)) { - resultset = ast_calloc(1, sizeof(*resultset)); - AST_LIST_HEAD_INIT(resultset); -- if (query->rowlimit) -+ if (query->rowlimit) { - rowlimit = query->rowlimit; -- else -+ } else { - rowlimit = INT_MAX; -+ } - } - AST_RWLIST_UNLOCK(&queries); - - for (dsn = 0; dsn < 5; dsn++) { - if (!ast_strlen_zero(query->readhandle[dsn])) { - obj = ast_odbc_request_obj(query->readhandle[dsn], 0); -- if (obj) -- stmt = ast_odbc_direct_execute(obj, generic_execute, sql->str); -+ if (obj) { -+ stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)); -+ } - } -- if (stmt) -+ if (stmt) { - break; -+ } - } - - if (!stmt) { -- ast_log(LOG_ERROR, "Unable to execute query [%s]\n", sql->str); -- if (obj) -+ ast_log(LOG_ERROR, "Unable to execute query [%s]\n", ast_str_buffer(sql)); -+ if (obj) { - ast_odbc_release_obj(obj); -+ obj = NULL; -+ } - pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); -- if (chan) -+ if (chan) { - ast_autoservice_stop(chan); -- if (bogus_chan) -+ } -+ if (bogus_chan) { - ast_channel_free(chan); -- ast_free(sql); -+ } - return -1; - } - - 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->str); -+ ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); - SQLCloseCursor(stmt); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); -+ obj = NULL; - pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); -- if (chan) -+ if (chan) { - ast_autoservice_stop(chan); -- if (bogus_chan) -+ } -+ if (bogus_chan) { - ast_channel_free(chan); -- ast_free(sql); -+ } - return -1; - } - -@@ -371,29 +499,35 @@ - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - int res1 = -1; - if (res == SQL_NO_DATA) { -- ast_verb(4, "Found no rows [%s]\n", sql->str); -+ ast_verb(4, "Found no rows [%s]\n", ast_str_buffer(sql)); - res1 = 0; - buf[0] = '\0'; - ast_copy_string(rowcount, "0", sizeof(rowcount)); -+ status = "NODATA"; - } else { -- ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str); -+ ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); -+ status = "FETCHERROR"; - } - SQLCloseCursor(stmt); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); -+ obj = NULL; - pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); - if (chan) - ast_autoservice_stop(chan); - if (bogus_chan) - ast_channel_free(chan); -- ast_free(sql); - return res1; - } - -+ status = "SUCCESS"; -+ - for (y = 0; y < rowlimit; y++) { - for (x = 0; x < colcount; x++) { - int i; - struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16); -+ char *ptrcoldata; - - if (y == 0) { - char colname[256]; -@@ -405,51 +539,37 @@ - snprintf(colname, sizeof(colname), "field%d", x); - } - -- if (coldata->len < maxcol + 1) { -- ast_str_make_space(&coldata, maxcol + 1); -- } -+ ast_str_make_space(&coldata, maxcol + 1); - -- if (colnames->used) { -+ if (ast_str_strlen(colnames)) { - ast_str_append(&colnames, 0, ","); - } -- ast_str_make_space(&colnames, strlen(colname) * 2 + 1 + colnames->used); -+ ast_str_append_escapecommas(&colnames, 0, colname, sizeof(colname)); - -- /* Copy data, encoding '\' and ',' for the argument parser */ -- for (i = 0; i < sizeof(colname); i++) { -- if (escapecommas && (colname[i] == '\\' || colname[i] == ',')) { -- colnames->str[colnames->used++] = '\\'; -- } -- colnames->str[colnames->used++] = colname[i]; -- -- if (colname[i] == '\0') { -- colnames->used--; -- break; -- } -- } -- - if (resultset) { -- void *tmp = ast_realloc(resultset, sizeof(*resultset) + colnames->used + 1); -+ void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1); - if (!tmp) { - ast_log(LOG_ERROR, "No space for a new resultset?\n"); - ast_free(resultset); - SQLCloseCursor(stmt); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); -+ obj = NULL; - pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); - if (chan) - ast_autoservice_stop(chan); - if (bogus_chan) - ast_channel_free(chan); -- ast_free(sql); - return -1; - } - resultset = tmp; -- strcpy((char *)resultset + sizeof(*resultset), colnames->str); -+ strcpy((char *)resultset + sizeof(*resultset), ast_str_buffer(colnames)); - } - } - - buflen = strlen(buf); -- res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata->str, coldata->len, &indicator); -+ res = ast_odbc_ast_str_SQLGetData(&coldata, -1, stmt, x + 1, SQL_CHAR, &indicator); - if (indicator == SQL_NULL_DATA) { - ast_debug(3, "Got NULL data\n"); - ast_str_reset(coldata); -@@ -457,41 +577,45 @@ - } - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -- ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql->str); -+ ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", ast_str_buffer(sql)); - y = -1; - buf[0] = '\0'; - goto end_acf_read; - } - -- ast_debug(2, "Got coldata of '%s'\n", coldata->str); -- coldata->used = strlen(coldata->str); -+ ast_debug(2, "Got coldata of '%s'\n", ast_str_buffer(coldata)); - -+ if (buflen) { -+ buf[buflen++] = ','; -+ } -+ - /* Copy data, encoding '\' and ',' for the argument parser */ -- for (i = 0; i < coldata->used; i++) { -- if (escapecommas && (coldata->str[i] == '\\' || coldata->str[i] == ',')) { -+ ptrcoldata = ast_str_buffer(coldata); -+ for (i = 0; i < ast_str_strlen(coldata); i++) { -+ if (escapecommas && (ptrcoldata[i] == '\\' || ptrcoldata[i] == ',')) { - buf[buflen++] = '\\'; - } -- buf[buflen++] = coldata->str[i]; -+ buf[buflen++] = ptrcoldata[i]; - -- if (buflen >= len - 2) -+ if (buflen >= len - 2) { - break; -+ } - -- if (coldata->str[i] == '\0') -+ if (ptrcoldata[i] == '\0') { - break; -+ } - } - -- buf[buflen++] = ','; - buf[buflen] = '\0'; - ast_debug(2, "buf is now set to '%s'\n", buf); - } -- /* Trim trailing comma */ -- buf[buflen - 1] = '\0'; - ast_debug(2, "buf is now set to '%s'\n", buf); - - if (resultset) { -- row = ast_calloc(1, sizeof(*row) + buflen); -+ row = ast_calloc(1, sizeof(*row) + buflen + 1); - if (!row) { - ast_log(LOG_ERROR, "Unable to allocate space for more rows in this resultset.\n"); -+ status = "MEMERROR"; - goto end_acf_read; - } - strcpy((char *)row + sizeof(*row), buf); -@@ -500,8 +624,10 @@ - /* Get next row */ - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -- if (res != SQL_NO_DATA) -- ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql->str); -+ if (res != SQL_NO_DATA) { -+ ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); -+ } -+ /* Number of rows in the resultset */ - y++; - break; - } -@@ -511,7 +637,8 @@ - end_acf_read: - snprintf(rowcount, sizeof(rowcount), "%d", y); - pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); -- pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames->str); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); -+ pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(colnames)); - if (resultset) { - int uid; - struct ast_datastore *odbc_store; -@@ -520,15 +647,16 @@ - odbc_store = ast_datastore_alloc(&odbc_info, buf); - if (!odbc_store) { - ast_log(LOG_ERROR, "Rows retrieved, but unable to store it in the channel. Results fail.\n"); -+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", "MEMERROR"); - odbc_datastore_free(resultset); - SQLCloseCursor(stmt); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); -+ obj = NULL; - if (chan) - ast_autoservice_stop(chan); - if (bogus_chan) - ast_channel_free(chan); -- ast_free(sql); - return -1; - } - odbc_store->data = resultset; -@@ -537,11 +665,11 @@ - SQLCloseCursor(stmt); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); -+ obj = NULL; - if (chan) - ast_autoservice_stop(chan); - if (bogus_chan) - ast_channel_free(chan); -- ast_free(sql); - return 0; - } - -@@ -563,12 +691,6 @@ - - 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, - }; -@@ -580,6 +702,7 @@ - struct odbc_datastore_row *row; - store = ast_channel_datastore_find(chan, &odbc_info, data); - if (!store) { -+ pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE"); - return -1; - } - resultset = store->data; -@@ -590,33 +713,24 @@ - /* Cleanup datastore */ - ast_channel_datastore_remove(chan, store); - ast_datastore_free(store); -+ pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "FAILURE"); - return -1; - } - pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", resultset->names); - ast_copy_string(buf, row->data, len); - ast_free(row); -+ pbx_builtin_setvar_helper(chan, "ODBC_FETCH_STATUS", "SUCCESS"); - return 0; - } - - static struct ast_custom_function fetch_function = { - .name = "ODBC_FETCH", -- .synopsis = "Fetch a row from a multirow query", -- .syntax = "ODBC_FETCH()", -- .desc = --"For queries which are marked as mode=multirow, the original query returns a\n" --"result-id from which results may be fetched. This function implements the\n" --"actual fetch of the results.\n", - .read = acf_fetch, - .write = NULL, - }; - - static char *app_odbcfinish = "ODBCFinish"; --static char *syn_odbcfinish = "Clear the resultset of a successful multirow query"; --static char *desc_odbcfinish = --"ODBCFinish()\n" --" Clears any remaining rows of the specified resultset\n"; - -- - static int exec_odbcfinish(struct ast_channel *chan, void *data) - { - struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data); -@@ -631,7 +745,6 @@ - { - const char *tmp; - int i; -- int res; - - if (!cfg || !catg) { - return EINVAL; -@@ -699,6 +812,10 @@ - return EINVAL; - } - -+ if ((tmp = ast_variable_retrieve(cfg, catg, "insertsql"))) { -+ ast_copy_string((*query)->sql_insert, tmp, sizeof((*query)->sql_insert)); -+ } -+ - /* Allow escaping of embedded commas in fields to be turned off */ - ast_set_flag((*query), OPT_ESCAPECOMMAS); - if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { -@@ -719,6 +836,12 @@ - *query = NULL; - return ENOMEM; - } -+ if (ast_string_field_init((*query)->acf, 128)) { -+ ast_free((*query)->acf); -+ ast_free(*query); -+ *query = NULL; -+ return ENOMEM; -+ } - - if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { - if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) { -@@ -731,68 +854,90 @@ - } - - if (!((*query)->acf->name)) { -+ ast_string_field_free_memory((*query)->acf); - ast_free((*query)->acf); - ast_free(*query); - *query = NULL; - return ENOMEM; - } - -- if (asprintf((char **)&((*query)->acf->syntax), "%s([...[,]])", (*query)->acf->name) < 0) { -- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); -- (*query)->acf->syntax = NULL; -+ if ((tmp = ast_variable_retrieve(cfg, catg, "syntax")) && !ast_strlen_zero(tmp)) { -+ ast_string_field_build((*query)->acf, syntax, "%s(%s)", (*query)->acf->name, tmp); -+ } else { -+ ast_string_field_build((*query)->acf, syntax, "%s([...[,]])", (*query)->acf->name); - } - -- if (!((*query)->acf->syntax)) { -+ if (ast_strlen_zero((*query)->acf->syntax)) { - ast_free((char *)(*query)->acf->name); -+ ast_string_field_free_memory((*query)->acf); - ast_free((*query)->acf); - ast_free(*query); - *query = NULL; - return ENOMEM; - } - -- (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; -+ if ((tmp = ast_variable_retrieve(cfg, catg, "synopsis")) && !ast_strlen_zero(tmp)) { -+ ast_string_field_set((*query)->acf, synopsis, tmp); -+ } else { -+ ast_string_field_set((*query)->acf, synopsis, "Runs the referenced query with the specified arguments"); -+ } - -- res = 0; -+ if (ast_strlen_zero((*query)->acf->synopsis)) { -+ ast_free((char *)(*query)->acf->name); -+ ast_string_field_free_memory((*query)->acf); -+ ast_free((*query)->acf); -+ ast_free(*query); -+ *query = NULL; -+ return ENOMEM; -+ } -+ - if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { -- res = 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); -+ ast_string_field_build((*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" -+ "%s" -+ "\nRead:\n%s\n\nWrite:\n%s\n%s%s%s", -+ ast_strlen_zero((*query)->sql_insert) ? "" : -+ "If the write query affects no rows, the insert query will be\n" -+ "performed.\n", -+ (*query)->sql_read, -+ (*query)->sql_write, -+ ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n", -+ ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, -+ ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); - } else if (!ast_strlen_zero((*query)->sql_read)) { -- res = 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); -+ ast_string_field_build((*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)) { -- res = 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); -+ ast_string_field_build((*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.\n%sSQL:\n%s\n%s%s%s", -+ ast_strlen_zero((*query)->sql_insert) ? "" : -+ "If the write query affects no rows, the insert query will be\n" -+ "performed.\n", -+ (*query)->sql_write, -+ ast_strlen_zero((*query)->sql_insert) ? "" : "Insert:\n", -+ ast_strlen_zero((*query)->sql_insert) ? "" : (*query)->sql_insert, -+ ast_strlen_zero((*query)->sql_insert) ? "" : "\n"); - } else { -- ast_free((char *)(*query)->acf->syntax); -+ ast_string_field_free_memory((*query)->acf); - ast_free((char *)(*query)->acf->name); - ast_free((*query)->acf); - ast_free(*query); -- ast_log(LOG_WARNING, "Section %s was found, but there was no SQL to execute. Ignoring.\n", catg); -+ ast_log(LOG_WARNING, "Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg); - return EINVAL; - } - -- if (res < 0) { -- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); -- (*query)->acf->desc = NULL; -- } -- -- -- if (!((*query)->acf->desc)) { -- ast_free((char *)(*query)->acf->syntax); -+ if (ast_strlen_zero((*query)->acf->desc)) { -+ ast_string_field_free_memory((*query)->acf); - ast_free((char *)(*query)->acf->name); - ast_free((*query)->acf); - ast_free(*query); -@@ -821,10 +966,7 @@ - if (query->acf) { - if (query->acf->name) - ast_free((char *)query->acf->name); -- if (query->acf->syntax) -- ast_free((char *)query->acf->syntax); -- if (query->acf->desc) -- ast_free((char *)query->acf->desc); -+ ast_string_field_free_memory(query->acf); - ast_free(query->acf); - } - ast_free(query); -@@ -832,6 +974,351 @@ - return 0; - } - -+static char *cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(field)[100]; -+ ); -+ struct ast_str *sql; -+ char *char_args, varname[10]; -+ struct acf_odbc_query *query; -+ struct ast_channel *chan; -+ int i; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "odbc read"; -+ e->usage = -+ "Usage: odbc read [exec]\n" -+ " Evaluates the SQL provided in the ODBC function , and\n" -+ " optionally executes the function. This function is intended for\n" -+ " testing purposes. Remember to quote arguments containing spaces.\n"; -+ return NULL; -+ case CLI_GENERATE: -+ if (a->pos == 2) { -+ int wordlen = strlen(a->word), which = 0; -+ /* Complete function name */ -+ AST_RWLIST_RDLOCK(&queries); -+ AST_RWLIST_TRAVERSE(&queries, query, list) { -+ if (!strncasecmp(query->acf->name, a->word, wordlen)) { -+ if (++which > a->n) { -+ char *res = ast_strdup(query->acf->name); -+ AST_RWLIST_UNLOCK(&queries); -+ return res; -+ } -+ } -+ } -+ AST_RWLIST_UNLOCK(&queries); -+ return NULL; -+ } else if (a->pos == 4) { -+ return a->n == 0 ? ast_strdup("exec") : NULL; -+ } else { -+ return NULL; -+ } -+ } -+ -+ if (a->argc < 4 || a->argc > 5) { -+ return CLI_SHOWUSAGE; -+ } -+ -+ sql = ast_str_thread_get(&sql_buf, 16); -+ if (!sql) { -+ return CLI_FAILURE; -+ } -+ -+ AST_RWLIST_RDLOCK(&queries); -+ AST_RWLIST_TRAVERSE(&queries, query, list) { -+ if (!strcmp(query->acf->name, a->argv[2])) { -+ break; -+ } -+ } -+ -+ if (!query) { -+ ast_cli(a->fd, "No such query '%s'\n", a->argv[2]); -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SHOWUSAGE; -+ } -+ -+ if (ast_strlen_zero(query->sql_read)) { -+ ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]); -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+ } -+ -+ ast_str_make_space(&sql, strlen(query->sql_read) * 2 + 300); -+ -+ /* Evaluate function */ -+ char_args = ast_strdupa(a->argv[3]); -+ -+ chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"); -+ -+ AST_STANDARD_APP_ARGS(args, char_args); -+ for (i = 0; i < args.argc; i++) { -+ snprintf(varname, sizeof(varname), "ARG%d", i + 1); -+ pbx_builtin_pushvar_helper(chan, varname, args.field[i]); -+ } -+ -+ ast_str_substitute_variables(&sql, 0, chan, query->sql_read); -+ ast_channel_free(chan); -+ -+ if (a->argc == 5 && !strcmp(a->argv[4], "exec")) { -+ /* Execute the query */ -+ struct odbc_obj *obj = NULL; -+ int dsn, executed = 0; -+ SQLHSTMT stmt; -+ int rows = 0, res, x; -+ SQLSMALLINT colcount = 0, collength; -+ SQLLEN indicator; -+ struct ast_str *coldata = ast_str_thread_get(&coldata_buf, 16); -+ char colname[256]; -+ SQLULEN maxcol; -+ -+ for (dsn = 0; dsn < 5; dsn++) { -+ if (ast_strlen_zero(query->readhandle[dsn])) { -+ continue; -+ } -+ ast_debug(1, "Found handle %s\n", query->readhandle[dsn]); -+ if (!(obj = ast_odbc_request_obj(query->readhandle[dsn], 0))) { -+ continue; -+ } -+ -+ ast_debug(1, "Got obj\n"); -+ if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ continue; -+ } -+ -+ executed = 1; -+ -+ res = SQLNumResultCols(stmt, &colcount); -+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -+ ast_cli(a->fd, "SQL Column Count error!\n[%s]\n\n", ast_str_buffer(sql)); -+ SQLCloseCursor(stmt); -+ SQLFreeHandle (SQL_HANDLE_STMT, stmt); -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+ } -+ -+ res = SQLFetch(stmt); -+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -+ SQLCloseCursor(stmt); -+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ if (res == SQL_NO_DATA) { -+ ast_cli(a->fd, "Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn], ast_str_buffer(sql)); -+ break; -+ } else { -+ ast_cli(a->fd, "Error %d in FETCH [%s]\n", res, ast_str_buffer(sql)); -+ } -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+ } -+ for (;;) { -+ for (x = 0; x < colcount; x++) { -+ res = SQLDescribeCol(stmt, x + 1, (unsigned char *)colname, sizeof(colname), &collength, NULL, &maxcol, NULL, NULL); -+ if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) { -+ snprintf(colname, sizeof(colname), "field%d", x); -+ } -+ -+ res = ast_odbc_ast_str_SQLGetData(&coldata, maxcol, stmt, x + 1, SQL_CHAR, &indicator); -+ if (indicator == SQL_NULL_DATA) { -+ ast_str_set(&coldata, 0, "(nil)"); -+ res = SQL_SUCCESS; -+ } -+ -+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -+ ast_cli(a->fd, "SQL Get Data error %d!\n[%s]\n\n", res, ast_str_buffer(sql)); -+ SQLCloseCursor(stmt); -+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+ } -+ -+ ast_cli(a->fd, "%-20.20s %s\n", colname, ast_str_buffer(coldata)); -+ } -+ rows++; -+ -+ /* Get next row */ -+ res = SQLFetch(stmt); -+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { -+ break; -+ } -+ ast_cli(a->fd, "%-20.20s %s\n", "----------", "----------"); -+ } -+ SQLCloseCursor(stmt); -+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ ast_cli(a->fd, "Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ? "" : "s", dsn, query->readhandle[dsn]); -+ break; -+ } -+ if (obj) { -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ } -+ -+ if (!executed) { -+ ast_cli(a->fd, "Failed to execute query. [%s]\n", ast_str_buffer(sql)); -+ } -+ } else { /* No execution, just print out the resulting SQL */ -+ ast_cli(a->fd, "%s\n", ast_str_buffer(sql)); -+ } -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+} -+ -+static char *cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) -+{ -+ AST_DECLARE_APP_ARGS(values, -+ AST_APP_ARG(field)[100]; -+ ); -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(field)[100]; -+ ); -+ struct ast_str *sql; -+ char *char_args, *char_values, varname[10]; -+ struct acf_odbc_query *query; -+ struct ast_channel *chan; -+ int i; -+ -+ switch (cmd) { -+ case CLI_INIT: -+ e->command = "odbc write"; -+ e->usage = -+ "Usage: odbc write [exec]\n" -+ " Evaluates the SQL provided in the ODBC function , and\n" -+ " optionally executes the function. This function is intended for\n" -+ " testing purposes. Remember to quote arguments containing spaces.\n"; -+ return NULL; -+ case CLI_GENERATE: -+ if (a->pos == 2) { -+ int wordlen = strlen(a->word), which = 0; -+ /* Complete function name */ -+ AST_RWLIST_RDLOCK(&queries); -+ AST_RWLIST_TRAVERSE(&queries, query, list) { -+ if (!strncasecmp(query->acf->name, a->word, wordlen)) { -+ if (++which > a->n) { -+ char *res = ast_strdup(query->acf->name); -+ AST_RWLIST_UNLOCK(&queries); -+ return res; -+ } -+ } -+ } -+ AST_RWLIST_UNLOCK(&queries); -+ return NULL; -+ } else if (a->pos == 5) { -+ return a->n == 0 ? ast_strdup("exec") : NULL; -+ } else { -+ return NULL; -+ } -+ } -+ -+ if (a->argc < 5 || a->argc > 6) { -+ return CLI_SHOWUSAGE; -+ } -+ -+ sql = ast_str_thread_get(&sql_buf, 16); -+ if (!sql) { -+ return CLI_FAILURE; -+ } -+ -+ AST_RWLIST_RDLOCK(&queries); -+ AST_RWLIST_TRAVERSE(&queries, query, list) { -+ if (!strcmp(query->acf->name, a->argv[2])) { -+ break; -+ } -+ } -+ -+ if (!query) { -+ ast_cli(a->fd, "No such query '%s'\n", a->argv[2]); -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SHOWUSAGE; -+ } -+ -+ if (ast_strlen_zero(query->sql_write)) { -+ ast_cli(a->fd, "The function %s has no writesql parameter.\n", a->argv[2]); -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+ } -+ -+ ast_str_make_space(&sql, strlen(query->sql_write) * 2 + 300); -+ -+ /* Evaluate function */ -+ char_args = ast_strdupa(a->argv[3]); -+ char_values = ast_strdupa(a->argv[4]); -+ -+ chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"); -+ -+ AST_STANDARD_APP_ARGS(args, char_args); -+ for (i = 0; i < args.argc; i++) { -+ snprintf(varname, sizeof(varname), "ARG%d", i + 1); -+ pbx_builtin_pushvar_helper(chan, varname, args.field[i]); -+ } -+ -+ /* Parse values, just like arguments */ -+ AST_STANDARD_APP_ARGS(values, char_values); -+ for (i = 0; i < values.argc; i++) { -+ snprintf(varname, sizeof(varname), "VAL%d", i + 1); -+ pbx_builtin_pushvar_helper(chan, varname, values.field[i]); -+ } -+ -+ /* Additionally set the value as a whole (but push an empty string if value is NULL) */ -+ pbx_builtin_pushvar_helper(chan, "VALUE", S_OR(a->argv[4], "")); -+ ast_str_substitute_variables(&sql, 0, chan, query->sql_write); -+ ast_debug(1, "SQL is %s\n", ast_str_buffer(sql)); -+ ast_channel_free(chan); -+ -+ if (a->argc == 6 && !strcmp(a->argv[5], "exec")) { -+ /* Execute the query */ -+ struct odbc_obj *obj = NULL; -+ int dsn, executed = 0; -+ SQLHSTMT stmt; -+ SQLLEN rows = -1; -+ -+ for (dsn = 0; dsn < 5; dsn++) { -+ if (ast_strlen_zero(query->writehandle[dsn])) { -+ continue; -+ } -+ if (!(obj = ast_odbc_request_obj(query->writehandle[dsn], 0))) { -+ continue; -+ } -+ if (!(stmt = ast_odbc_direct_execute(obj, generic_execute, ast_str_buffer(sql)))) { -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ continue; -+ } -+ -+ SQLRowCount(stmt, &rows); -+ SQLCloseCursor(stmt); -+ SQLFreeHandle(SQL_HANDLE_STMT, stmt); -+ ast_odbc_release_obj(obj); -+ obj = NULL; -+ ast_cli(a->fd, "Affected %d rows. Query executed on handle %d [%s]\n", (int)rows, dsn, query->writehandle[dsn]); -+ executed = 1; -+ break; -+ } -+ -+ if (!executed) { -+ ast_cli(a->fd, "Failed to execute query.\n"); -+ } -+ } else { /* No execution, just print out the resulting SQL */ -+ ast_cli(a->fd, "%s\n", ast_str_buffer(sql)); -+ } -+ AST_RWLIST_UNLOCK(&queries); -+ return CLI_SUCCESS; -+} -+ -+static struct ast_cli_entry cli_func_odbc[] = { -+ AST_CLI_DEFINE(cli_odbc_write, "Test setting a func_odbc function"), -+ AST_CLI_DEFINE(cli_odbc_read, "Test reading a func_odbc function"), -+}; -+ - static int load_module(void) - { - int res = 0; -@@ -840,11 +1327,11 @@ - struct ast_flags config_flags = { 0 }; - - res |= ast_custom_function_register(&fetch_function); -- res |= ast_register_application(app_odbcfinish, exec_odbcfinish, syn_odbcfinish, desc_odbcfinish); -+ res |= ast_register_application_xml(app_odbcfinish, exec_odbcfinish); - AST_RWLIST_WRLOCK(&queries); - - cfg = ast_config_load(config, config_flags); -- if (!cfg) { -+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) { - ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); - AST_RWLIST_UNLOCK(&queries); - return AST_MODULE_LOAD_DECLINE; -@@ -871,6 +1358,7 @@ - - ast_config_destroy(cfg); - res |= ast_custom_function_register(&escape_function); -+ ast_cli_register_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc)); - - AST_RWLIST_UNLOCK(&queries); - return res; -@@ -891,6 +1379,7 @@ - res |= ast_custom_function_unregister(&escape_function); - res |= ast_custom_function_unregister(&fetch_function); - res |= ast_unregister_application(app_odbcfinish); -+ ast_cli_unregister_multiple(cli_func_odbc, ARRAY_LEN(cli_func_odbc)); - - /* Allow any threads waiting for this lock to pass (avoids a race) */ - AST_RWLIST_UNLOCK(&queries); -@@ -910,7 +1399,7 @@ - struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED }; - - cfg = ast_config_load(config, config_flags); -- if (cfg == CONFIG_STATUS_FILEUNCHANGED) -+ if (cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) - return 0; - - AST_RWLIST_WRLOCK(&queries); -Index: funcs/func_shell.c -=================================================================== ---- a/funcs/func_shell.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_shell.c (.../team/group/issue14292) (revision 178988) -@@ -63,19 +63,31 @@ - return 0; - } - -+/*** DOCUMENTATION -+ -+ -+ Executes a command as if you were at a shell. -+ -+ -+ -+ This is the argument to the function, the command you want to pass to the shell. -+ -+ -+ -+ Returns the value from a system command -+ Example: Set(foo=${SHELL(echo \bar\)}) -+ When using the SHELL() dialplan function, your \SHELL\ is /bin/sh, -+ which may differ as to the underlying shell, depending upon your production -+ platform. Also keep in mind that if you are using a common path, you should -+ be mindful of race conditions that could result from two calls running -+ SHELL() simultaneously. -+ -+ -+ -+ ***/ - static struct ast_custom_function shell_function = { - .name = "SHELL", -- .synopsis = "Executes a command as if you were at a shell.", -- .syntax = "SHELL()", - .read = shell_helper, -- .desc = --"Returns the value from a system command\n" --" Example: Set(foo=${SHELL(echo \"bar\")})\n" --" Note: When using the SHELL() dialplan function, your \"SHELL\" is /bin/sh,\n" --" which may differ as to the underlying shell, depending upon your production\n" --" platform. Also keep in mind that if you are using a common path, you should\n" --" be mindful of race conditions that could result from two calls running\n" --" SHELL() simultaneously.\n", - }; - - static int unload_module(void) -Index: funcs/func_volume.c -=================================================================== ---- a/funcs/func_volume.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_volume.c (.../team/group/issue14292) (revision 178988) -@@ -36,6 +36,26 @@ - #include "asterisk/utils.h" - #include "asterisk/audiohook.h" - -+/*** DOCUMENTATION -+ -+ -+ Set the TX or RX volume of a channel. -+ -+ -+ -+ Must be TX or RX. -+ -+ -+ -+ The VOLUME function can be used to increase or decrease the tx or -+ rx gain of any channel. -+ For example: -+ Set(VOLUME(TX)=3) -+ Set(VOLUME(RX)=2) -+ -+ -+ ***/ -+ - struct volume_information { - struct ast_audiohook audiohook; - int tx_gain; -@@ -137,13 +157,6 @@ - - static struct ast_custom_function volume_function = { - .name = "VOLUME", -- .synopsis = "Set the TX or RX volume of a channel", -- .syntax = "VOLUME(TX|RX)", -- .desc = -- " The VOLUME function can be used to increase or decrease the tx or\n" -- "rx gain of any channel. For example:\n" -- " Set(VOLUME(TX)=3)\n" -- " Set(VOLUME(RX)=2)\n", - .write = volume_write, - }; - -Index: funcs/func_aes.c -=================================================================== ---- a/funcs/func_aes.c (.../tags/1.6.1-rc1) (revision 0) -+++ b/funcs/func_aes.c (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,163 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2009, Digium, Inc. -+ * -+ * 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 AES encryption/decryption dialplan functions -+ * -+ * \author David Vossel -+ * \ingroup functions -+ */ -+ -+ -+#include "asterisk.h" -+ -+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -+ -+#include "asterisk/module.h" -+#include "asterisk/pbx.h" -+#include "asterisk/app.h" -+#include "asterisk/aes.h" -+ -+#define AES_BLOCK_SIZE 16 -+ -+/*** DOCUMENTATION -+ -+ -+ Encrypt a string with AES given a 16 character key. -+ -+ -+ -+ AES Key -+ -+ -+ Input string -+ -+ -+ -+ Returns an AES encrypted string encoded in base64. -+ -+ -+ -+ -+ Decrypt a string encoded in base64 with AES given a 16 character key. -+ -+ -+ -+ AES Key -+ -+ -+ Input string. -+ -+ -+ -+ Returns the plain text string. -+ -+ -+ ***/ -+ -+ -+static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, -+ char *buf, size_t len) -+{ -+ unsigned char curblock[AES_BLOCK_SIZE] = { 0, }; -+ char *tmp; -+ char *tmpP; -+ int data_len, encrypt; -+ ast_aes_encrypt_key ecx; /* AES 128 Encryption context */ -+ ast_aes_decrypt_key dcx; -+ -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(key); -+ AST_APP_ARG(data); -+ ); -+ -+ AST_STANDARD_APP_ARGS(args, data); -+ -+ if (ast_strlen_zero(args.data) || ast_strlen_zero(args.key)) { -+ ast_log(LOG_WARNING, "Syntax: %s(,) - missing argument!\n", cmd); -+ return -1; -+ } -+ -+ if (strlen(args.key) != AES_BLOCK_SIZE) { /* key must be of 16 characters in length, 128 bits */ -+ ast_log(LOG_WARNING, "Syntax: %s(,) - parameter must be exactly 16 characters!\n", cmd); -+ return -1; -+ } -+ -+ ast_aes_encrypt_key((unsigned char *) args.key, &ecx); /* encryption: plaintext -> encryptedtext -> base64 */ -+ ast_aes_decrypt_key((unsigned char *) args.key, &dcx); /* decryption: base64 -> encryptedtext -> plaintext */ -+ tmp = ast_calloc(1, len); /* requires a tmp buffer for the base64 decode */ -+ tmpP = tmp; -+ encrypt = strcmp("AES_DECRYPT", cmd); /* -1 if encrypting, 0 if decrypting */ -+ -+ if (encrypt) { /* if decrypting first decode src to base64 */ -+ ast_copy_string(tmp, args.data, len); -+ data_len = strlen(tmp); -+ } else { -+ data_len = ast_base64decode((unsigned char *) tmp, args.data, len); -+ } -+ -+ if (data_len >= len) { /* make sure to not go over buffer len */ -+ ast_log(LOG_WARNING, "Syntax: %s(,) - exceeds buffer length. Result may be truncated!\n", cmd); -+ data_len = len - 1; -+ } -+ -+ while (data_len > 0) { -+ memset(curblock, 0, AES_BLOCK_SIZE); -+ memcpy(curblock, tmpP, (data_len < AES_BLOCK_SIZE) ? data_len : AES_BLOCK_SIZE); -+ if (encrypt) { -+ ast_aes_encrypt(curblock, (unsigned char *) tmpP, &ecx); -+ } else { -+ ast_aes_decrypt(curblock, (unsigned char *) tmpP, &dcx); -+ } -+ tmpP += AES_BLOCK_SIZE; -+ data_len -= AES_BLOCK_SIZE; -+ } -+ -+ if (encrypt) { /* if encrypting encode result to base64 */ -+ ast_base64encode(buf, (unsigned char *) tmp, strlen(tmp), len); -+ } else { -+ memcpy(buf, tmp, len); -+ } -+ ast_free(tmp); -+ -+ return 0; -+} -+ -+static struct ast_custom_function aes_encrypt_function = { -+ .name = "AES_ENCRYPT", -+ .read = aes_helper, -+}; -+ -+static struct ast_custom_function aes_decrypt_function = { -+ .name = "AES_DECRYPT", -+ .read = aes_helper, -+}; -+ -+static int unload_module(void) -+{ -+ int res = ast_custom_function_unregister(&aes_decrypt_function); -+ return res | ast_custom_function_unregister(&aes_encrypt_function); -+} -+ -+static int load_module(void) -+{ -+ int res = ast_custom_function_register(&aes_decrypt_function); -+ res |= ast_custom_function_register(&aes_encrypt_function); -+ return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; -+} -+ -+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "AES dialplan functions"); - -Property changes on: funcs/func_aes.c -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: funcs/Makefile -=================================================================== ---- a/funcs/Makefile (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/Makefile (.../team/group/issue14292) (revision 178988) -@@ -19,4 +19,9 @@ - - include $(ASTTOPDIR)/Makefile.moddir_rules - --func_strings.o: ASTCFLAGS+=-Wno-format-nonliteral -+# the SPRINTF() function in func_sprintf accepts format specifiers -+# and thus passes them to snprintf() as non-literal strings; the compiler -+# can't check the string and arguments to ensure they match, so this -+# warning must be disabled; for safety reasons, SPRINTF() is kept in -+# a separate module so that as little code as possible is left unchecked -+func_sprintf.o: ASTCFLAGS+=-Wno-format-nonliteral -Index: funcs/func_dialplan.c -=================================================================== ---- a/funcs/func_dialplan.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_dialplan.c (.../team/group/issue14292) (revision 178988) -@@ -33,6 +33,23 @@ - #include "asterisk/pbx.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Checks the existence of a dialplan target. -+ -+ -+ -+ -+ -+ -+ -+ This function returns 1 if the target exits. Otherwise, it returns 0. -+ -+ -+ -+ ***/ -+ - static int isexten_function_read(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -87,9 +104,6 @@ - - static struct ast_custom_function isexten_function = { - .name = "DIALPLAN_EXISTS", -- .syntax = "DIALPLAN_EXISTS(context[,extension[,priority]])", -- .synopsis = "Checks the existence of a dialplan target.", -- .desc = "This function returns 1 if the target exits. Otherwise, it returns 0.\n", - .read = isexten_function_read, - }; - -Index: funcs/func_db.c -=================================================================== ---- a/funcs/func_db.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_db.c (.../team/group/issue14292) (revision 178988) -@@ -40,12 +40,74 @@ - #include "asterisk/app.h" - #include "asterisk/astdb.h" - -+/*** DOCUMENTATION -+ -+ -+ Read from or write to the Asterisk database. -+ -+ -+ -+ -+ -+ -+ This function will read from or write a value to the Asterisk database. On a -+ read, this function returns the corresponding value from the database, or blank -+ if it does not exist. Reading a database value will also set the variable -+ DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS -+ function. -+ -+ -+ DBdel -+ DB_DELETE -+ DBdeltree -+ DB_EXISTS -+ -+ -+ -+ -+ Check to see if a key exists in the Asterisk database. -+ -+ -+ -+ -+ -+ -+ This function will check to see if a key exists in the Asterisk -+ database. If it exists, the function will return 1. If not, -+ it will return 0. Checking for existence of a database key will -+ also set the variable DB_RESULT to the key's value if it exists. -+ -+ -+ DB -+ -+ -+ -+ -+ Return a value from the database and delete it. -+ -+ -+ -+ -+ -+ -+ This function will retrieve a value from the Asterisk database -+ and then remove that key from the database. DB_RESULT -+ will be set to the key's value if it exists. -+ -+ -+ DBdel -+ DB -+ DBdeltree -+ -+ -+ ***/ -+ - static int function_db_read(struct ast_channel *chan, const char *cmd, - char *parse, char *buf, size_t len) - { - AST_DECLARE_APP_ARGS(args, -- AST_APP_ARG(family); -- AST_APP_ARG(key); -+ AST_APP_ARG(family); -+ AST_APP_ARG(key); - ); - - buf[0] = '\0'; -@@ -64,8 +126,9 @@ - - if (ast_db_get(args.family, args.key, buf, len - 1)) { - ast_debug(1, "DB: %s/%s not found in database.\n", args.family, args.key); -- } else -+ } else { - pbx_builtin_setvar_helper(chan, "DB_RESULT", buf); -+ } - - return 0; - } -@@ -74,8 +137,8 @@ - const char *value) - { - AST_DECLARE_APP_ARGS(args, -- AST_APP_ARG(family); -- AST_APP_ARG(key); -+ AST_APP_ARG(family); -+ AST_APP_ARG(key); - ); - - if (ast_strlen_zero(parse)) { -@@ -90,22 +153,15 @@ - return -1; - } - -- if (ast_db_put(args.family, args.key, (char *) value)) -+ if (ast_db_put(args.family, args.key, value)) { - ast_log(LOG_WARNING, "DB: Error writing value to database.\n"); -+ } - - return 0; - } - - static struct ast_custom_function db_function = { - .name = "DB", -- .synopsis = "Read from or write to the Asterisk database", -- .syntax = "DB(/)", -- .desc = --"This function will read from or write a value to the Asterisk database. On a\n" --"read, this function returns the corresponding value from the database, or blank\n" --"if it does not exist. Reading a database value will also set the variable\n" --"DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS\n" --"function.\n", - .read = function_db_read, - .write = function_db_write, - }; -@@ -114,8 +170,8 @@ - char *parse, char *buf, size_t len) - { - AST_DECLARE_APP_ARGS(args, -- AST_APP_ARG(family); -- AST_APP_ARG(key); -+ AST_APP_ARG(family); -+ AST_APP_ARG(key); - ); - - buf[0] = '\0'; -@@ -132,9 +188,9 @@ - return -1; - } - -- if (ast_db_get(args.family, args.key, buf, len - 1)) -+ if (ast_db_get(args.family, args.key, buf, len - 1)) { - strcpy(buf, "0"); -- else { -+ } else { - pbx_builtin_setvar_helper(chan, "DB_RESULT", buf); - strcpy(buf, "1"); - } -@@ -144,13 +200,6 @@ - - static struct ast_custom_function db_exists_function = { - .name = "DB_EXISTS", -- .synopsis = "Check to see if a key exists in the Asterisk database", -- .syntax = "DB_EXISTS(/)", -- .desc = -- "This function will check to see if a key exists in the Asterisk\n" -- "database. If it exists, the function will return \"1\". If not,\n" -- "it will return \"0\". Checking for existence of a database key will\n" -- "also set the variable DB_RESULT to the key's value if it exists.\n", - .read = function_db_exists, - }; - -@@ -158,8 +207,8 @@ - char *parse, char *buf, size_t len) - { - AST_DECLARE_APP_ARGS(args, -- AST_APP_ARG(family); -- AST_APP_ARG(key); -+ AST_APP_ARG(family); -+ AST_APP_ARG(key); - ); - - buf[0] = '\0'; -@@ -183,6 +232,7 @@ - ast_debug(1, "DB_DELETE: %s/%s could not be deleted from the database\n", args.family, args.key); - } - } -+ - pbx_builtin_setvar_helper(chan, "DB_RESULT", buf); - - return 0; -@@ -191,12 +241,6 @@ - - static struct ast_custom_function db_delete_function = { - .name = "DB_DELETE", -- .synopsis = "Return a value from the database and delete it", -- .syntax = "DB_DELETE(/)", -- .desc = -- "This function will retrieve a value from the Asterisk database\n" -- " and then remove that key from the database. DB_RESULT\n" -- "will be set to the key's value if it exists.\n", - .read = function_db_delete, - }; - -Index: funcs/func_sprintf.c -=================================================================== ---- a/funcs/func_sprintf.c (.../tags/1.6.1-rc1) (revision 0) -+++ b/funcs/func_sprintf.c (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,230 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2005-2006, Digium, Inc. -+ * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved. -+ * Portions Copyright (C) 2005, Anthony Minessale II -+ * -+ * 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 String manipulation dialplan functions -+ * -+ * \author Tilghman Lesher -+ * \author Anothony Minessale II -+ * \ingroup functions -+ */ -+ -+#include "asterisk.h" -+ -+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -+ -+#include -+ -+#include "asterisk/module.h" -+#include "asterisk/channel.h" -+#include "asterisk/pbx.h" -+#include "asterisk/utils.h" -+#include "asterisk/app.h" -+ -+AST_THREADSTORAGE(result_buf); -+ -+/*** DOCUMENTATION -+ -+ -+ Format a variable according to a format string. -+ -+ -+ -+ -+ -+ -+ -+ -+ Parses the format string specified and returns a string matching -+ that format. Supports most options found in sprintf(3). -+ Returns a shortened string if a format specifier is not recognized. -+ -+ -+ sprintf(3) -+ -+ -+ ***/ -+static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -+{ -+#define SPRINTF_FLAG 0 -+#define SPRINTF_WIDTH 1 -+#define SPRINTF_PRECISION 2 -+#define SPRINTF_LENGTH 3 -+#define SPRINTF_CONVERSION 4 -+ int i, state = -1, argcount = 0; -+ char *formatstart = NULL, *bufptr = buf; -+ char formatbuf[256] = ""; -+ int tmpi; -+ double tmpd; -+ AST_DECLARE_APP_ARGS(arg, -+ AST_APP_ARG(format); -+ AST_APP_ARG(var)[100]; -+ ); -+ -+ AST_STANDARD_APP_ARGS(arg, data); -+ -+ /* Scan the format, converting each argument into the requisite format type. */ -+ for (i = 0; arg.format[i]; i++) { -+ switch (state) { -+ case SPRINTF_FLAG: -+ if (strchr("#0- +'I", arg.format[i])) -+ break; -+ state = SPRINTF_WIDTH; -+ case SPRINTF_WIDTH: -+ if (arg.format[i] >= '0' && arg.format[i] <= '9') -+ break; -+ -+ /* Next character must be a period to go into a precision */ -+ if (arg.format[i] == '.') { -+ state = SPRINTF_PRECISION; -+ } else { -+ state = SPRINTF_LENGTH; -+ i--; -+ } -+ break; -+ case SPRINTF_PRECISION: -+ if (arg.format[i] >= '0' && arg.format[i] <= '9') -+ break; -+ state = SPRINTF_LENGTH; -+ case SPRINTF_LENGTH: -+ if (strchr("hl", arg.format[i])) { -+ if (arg.format[i + 1] == arg.format[i]) -+ i++; -+ state = SPRINTF_CONVERSION; -+ break; -+ } else if (strchr("Lqjzt", arg.format[i])) { -+ state = SPRINTF_CONVERSION; -+ break; -+ } -+ state = SPRINTF_CONVERSION; -+ case SPRINTF_CONVERSION: -+ if (strchr("diouxXc", arg.format[i])) { -+ /* Integer */ -+ -+ /* Isolate this format alone */ -+ ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -+ formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -+ -+ /* Convert the argument into the required type */ -+ if (arg.var[argcount]) { -+ if (sscanf(arg.var[argcount++], "%d", &tmpi) != 1) { -+ ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf); -+ goto sprintf_fail; -+ } -+ } else { -+ ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n"); -+ goto sprintf_fail; -+ } -+ -+ /* Format the argument */ -+ snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi); -+ -+ /* Update the position of the next parameter to print */ -+ bufptr = strchr(buf, '\0'); -+ } else if (strchr("eEfFgGaA", arg.format[i])) { -+ /* Double */ -+ -+ /* Isolate this format alone */ -+ ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -+ formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -+ -+ /* Convert the argument into the required type */ -+ if (arg.var[argcount]) { -+ if (sscanf(arg.var[argcount++], "%lf", &tmpd) != 1) { -+ ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf); -+ goto sprintf_fail; -+ } -+ } else { -+ ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n"); -+ goto sprintf_fail; -+ } -+ -+ /* Format the argument */ -+ snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd); -+ -+ /* Update the position of the next parameter to print */ -+ bufptr = strchr(buf, '\0'); -+ } else if (arg.format[i] == 's') { -+ /* String */ -+ -+ /* Isolate this format alone */ -+ ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -+ formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -+ -+ /* Format the argument */ -+ snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]); -+ -+ /* Update the position of the next parameter to print */ -+ bufptr = strchr(buf, '\0'); -+ } else if (arg.format[i] == '%') { -+ /* Literal data to copy */ -+ *bufptr++ = arg.format[i]; -+ } else { -+ /* Not supported */ -+ -+ /* Isolate this format alone */ -+ ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); -+ formatbuf[&arg.format[i] - formatstart + 1] = '\0'; -+ -+ ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]); -+ goto sprintf_fail; -+ } -+ state = -1; -+ break; -+ default: -+ if (arg.format[i] == '%') { -+ state = SPRINTF_FLAG; -+ formatstart = &arg.format[i]; -+ break; -+ } else { -+ /* Literal data to copy */ -+ *bufptr++ = arg.format[i]; -+ } -+ } -+ } -+ *bufptr = '\0'; -+ return 0; -+sprintf_fail: -+ return -1; -+} -+ -+static struct ast_custom_function sprintf_function = { -+ .name = "SPRINTF", -+ .read = acf_sprintf, -+}; -+ -+static int unload_module(void) -+{ -+ int res = 0; -+ -+ res |= ast_custom_function_unregister(&sprintf_function); -+ -+ return res; -+} -+ -+static int load_module(void) -+{ -+ int res = 0; -+ -+ res |= ast_custom_function_register(&sprintf_function); -+ -+ return res; -+} -+ -+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SPRINTF dialplan function"); - -Property changes on: funcs/func_sprintf.c -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: funcs/func_version.c -=================================================================== ---- a/funcs/func_version.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_version.c (.../team/group/issue14292) (revision 178988) -@@ -34,6 +34,49 @@ - #include "asterisk/ast_version.h" - #include "asterisk/build.h" - -+/*** DOCUMENTATION -+ -+ -+ Return the Version info for this Asterisk. -+ -+ -+ -+ The possible values are: -+ -+ -+ A string of digits is returned (right now fixed at 999999). -+ -+ -+ The string representing the user's name whose account -+ was used to configure Asterisk, is returned. -+ -+ -+ The string representing the name of the host on which Asterisk was configured, is returned. -+ -+ -+ The string representing the type of machine on which Asterisk was configured, is returned. -+ -+ -+ The string representing the OS of the machine on which Asterisk was configured, is returned. -+ -+ -+ The string representing the date on which Asterisk was configured, is returned. -+ -+ -+ The string representing the kernel version of the machine on which Asterisk -+ was configured, is returned. -+ -+ -+ -+ -+ -+ If there are no arguments, return the version of Asterisk in this format: SVN-branch-1.4-r44830M -+ Example: Set(junky=${VERSION()}; -+ Sets junky to the string SVN-branch-1.6-r74830M, or possibly, SVN-trunk-r45126M. -+ -+ -+ ***/ -+ - static int acf_version_exec(struct ast_channel *chan, const char *cmd, - char *parse, char *buffer, size_t buflen) - { -@@ -70,19 +113,6 @@ - - static struct ast_custom_function acf_version = { - .name = "VERSION", -- .synopsis = "Return the Version info for this Asterisk", -- .syntax = "VERSION([info])", -- .desc = -- "If there are no arguments, return the version of Asterisk in this format: SVN-branch-1.4-r44830M\n" -- "If the argument is 'ASTERISK_VERSION_NUM', a string of digits is returned (right now fixed at 999999).\n" -- "If the argument is 'BUILD_USER', the string representing the user's name whose account was used to configure Asterisk, is returned.\n" -- "If the argument is 'BUILD_HOSTNAME', the string representing the name of the host on which Asterisk was configured, is returned.\n" -- "If the argument is 'BUILD_MACHINE', the string representing the type of machine on which Asterisk was configured, is returned.\n" -- "If the argument is 'BUILD_OS', the string representing the OS of the machine on which Asterisk was configured, is returned.\n" -- "If the argument is 'BUILD_DATE', the string representing the date on which Asterisk was configured, is returned.\n" -- "If the argument is 'BUILD_KERNEL', the string representing the kernel version of the machine on which Asterisk was configured, is returned .\n" -- " Example: Set(junky=${VERSION()}; \n" -- " Sets junky to the string 'SVN-branch-1.6-r74830M', or possibly, 'SVN-trunk-r45126M'.\n", - .read = acf_version_exec, - }; - -Index: funcs/func_timeout.c -=================================================================== ---- a/funcs/func_timeout.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_timeout.c (.../team/group/issue14292) (revision 178988) -@@ -34,6 +34,42 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Gets or sets timeouts on the channel. Timeout values are in seconds. -+ -+ -+ -+ The timeout that will be manipulated. The possible timeout types -+ are: absolute, digit or -+ response -+ -+ -+ -+ The timeouts that can be manipulated are: -+ absolute: The absolute maximum amount of time permitted for a call. -+ Setting of 0 disables the timeout. -+ digit: The maximum amount of time permitted between digits when the -+ user is typing in an extension. When this timeout expires, -+ after the user has started to type in an extension, the -+ extension will be considered complete, and will be -+ interpreted. Note that if an extension typed in is valid, -+ it will not have to timeout to be tested, so typically at -+ the expiry of this timeout, the extension will be considered -+ invalid (and thus control would be passed to the i -+ extension, or if it doesn't exist the call would be -+ terminated). The default timeout is 5 seconds. -+ response: The maximum amount of time permitted after falling through a -+ series of priorities for a channel in which the user may -+ begin typing an extension. If the user does not type an -+ extension in this amount of time, control will pass to the -+ t extension if it exists, and if not the call would be -+ terminated. The default timeout is 10 seconds. -+ -+ -+ ***/ -+ - static int timeout_read(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) - { -@@ -154,29 +190,6 @@ - - static struct ast_custom_function timeout_function = { - .name = "TIMEOUT", -- .synopsis = "Gets or sets timeouts on the channel. Timeout values are in seconds.", -- .syntax = "TIMEOUT(timeouttype)", -- .desc = -- "Gets or sets various channel timeouts. The timeouts that can be\n" -- "manipulated are:\n" "\n" -- "absolute: The absolute maximum amount of time permitted for a call. A\n" -- " setting of 0 disables the timeout.\n" "\n" -- "digit: The maximum amount of time permitted between digits when the\n" -- " user is typing in an extension. When this timeout expires,\n" -- " after the user has started to type in an extension, the\n" -- " extension will be considered complete, and will be\n" -- " interpreted. Note that if an extension typed in is valid,\n" -- " it will not have to timeout to be tested, so typically at\n" -- " the expiry of this timeout, the extension will be considered\n" -- " invalid (and thus control would be passed to the 'i'\n" -- " extension, or if it doesn't exist the call would be\n" -- " terminated). The default timeout is 5 seconds.\n" "\n" -- "response: The maximum amount of time permitted after falling through a\n" -- " series of priorities for a channel in which the user may\n" -- " begin typing an extension. If the user does not type an\n" -- " extension in this amount of time, control will pass to the\n" -- " 't' extension if it exists, and if not the call would be\n" -- " terminated. The default timeout is 10 seconds.\n", - .read = timeout_read, - .write = timeout_write, - }; -Index: funcs/func_lock.c -=================================================================== ---- a/funcs/func_lock.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_lock.c (.../team/group/issue14292) (revision 178988) -@@ -37,6 +37,53 @@ - #include "asterisk/module.h" - #include "asterisk/linkedlists.h" - -+/*** DOCUMENTATION -+ -+ -+ Attempt to obtain a named mutex. -+ -+ -+ -+ -+ -+ Attempts to grab a named lock exclusively, and prevents other channels from -+ obtaining the same lock. LOCK will wait for the lock to become available. -+ Returns 1 if the lock was obtained or 0 on error. -+ To avoid the possibility of a deadlock, LOCK will only attempt to -+ obtain the lock for 3 seconds if the channel already has another lock. -+ -+ -+ -+ -+ Attempt to obtain a named mutex. -+ -+ -+ -+ -+ -+ Attempts to grab a named lock exclusively, and prevents other channels -+ from obtaining the same lock. Returns 1 if the lock was -+ available or 0 otherwise. -+ -+ -+ -+ -+ Unlocks a named mutex. -+ -+ -+ -+ -+ -+ Unlocks a previously locked mutex. Returns 1 if the channel -+ had a lock or 0 otherwise. -+ It is generally unnecessary to unlock in a hangup routine, as any locks -+ held are automatically freed when the channel is destroyed. -+ -+ -+ ***/ -+ -+ -+ - AST_LIST_HEAD_STATIC(locklist, lock_frame); - - static void lock_free(void *data); -@@ -276,36 +323,16 @@ - - static struct ast_custom_function lock_function = { - .name = "LOCK", -- .synopsis = "Attempt to obtain a named mutex", -- .desc = --"Attempts to grab a named lock exclusively, and prevents other channels from\n" --"obtaining the same lock. LOCK will wait for the lock to become available.\n" --"Returns 1 if the lock was obtained or 0 on error.\n\n" --"Note: to avoid the possibility of a deadlock, LOCK will only attempt to\n" --"obtain the lock for 3 seconds if the channel already has another lock.\n", -- .syntax = "LOCK()", - .read = lock_read, - }; - - static struct ast_custom_function trylock_function = { - .name = "TRYLOCK", -- .synopsis = "Attempt to obtain a named mutex", -- .desc = --"Attempts to grab a named lock exclusively, and prevents other channels\n" --"from obtaining the same lock. Returns 1 if the lock was available or 0\n" --"otherwise.\n", -- .syntax = "TRYLOCK()", - .read = trylock_read, - }; - - static struct ast_custom_function unlock_function = { - .name = "UNLOCK", -- .synopsis = "Unlocks a named mutex", -- .desc = --"Unlocks a previously locked mutex. Note that it is generally unnecessary to\n" --"unlock in a hangup routine, as any locks held are automatically freed when the\n" --"channel is destroyed. Returns 1 if the channel had a lock or 0 otherwise.\n", -- .syntax = "UNLOCK()", - .read = unlock_read, - }; - -Index: funcs/func_math.c -=================================================================== ---- a/funcs/func_math.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_math.c (.../team/group/issue14292) (revision 178988) -@@ -39,6 +39,35 @@ - #include "asterisk/app.h" - #include "asterisk/config.h" - -+/*** DOCUMENTATION -+ -+ -+ Performs Mathematical Functions. -+ -+ -+ -+ Is of the form: -+ number1opnumber2 -+ where the possible values for op -+ are: -+ +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,%gt;,>=,<=,== (and behave as their C equivalents) -+ -+ -+ Wanted type of result: -+ f, float - float(default) -+ i, int - integer -+ h, hex - hex -+ c, char - char -+ -+ -+ -+ Performs mathematical functions based on two parameters and an operator. The returned -+ value type is type -+ Example: Set(i=${MATH(123%16,int)}) - sets var i=11 -+ -+ -+ ***/ -+ - enum TypeOfFunctions { - ADDFUNCTION, - DIVIDEFUNCTION, -@@ -306,17 +335,6 @@ - - static struct ast_custom_function math_function = { - .name = "MATH", -- .synopsis = "Performs Mathematical Functions", -- .syntax = "MATH([,])", -- .desc = "Perform calculation on number1 to number2. Valid ops are: \n" -- " +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,>,>=,<=,==\n" -- "and behave as their C equivalents.\n" -- " - wanted type of result:\n" -- " f, float - float(default)\n" -- " i, int - integer,\n" -- " h, hex - hex,\n" -- " c, char - char\n" -- "Example: Set(i=${MATH(123%16,int)}) - sets var i=11", - .read = math - }; - -Index: funcs/func_cut.c -=================================================================== ---- a/funcs/func_cut.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_cut.c (.../team/group/issue14292) (revision 178988) -@@ -34,6 +34,49 @@ - #include "asterisk/module.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ Sorts a list of key/vals into a list of keys, based upon the vals. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Takes a comma-separated list of keys and values, each separated by a colon, and returns a -+ comma-separated list of the keys, sorted by their values. Values will be evaluated as -+ floating-point numbers. -+ -+ -+ -+ -+ Slices and dices strings, based upon a named delimiter. -+ -+ -+ -+ Variable you want cut -+ -+ -+ Delimiter, defaults to - -+ -+ -+ Number of the field you want (1-based offset), may also be specified as a range (with -) -+ or group of ranges and fields (with &) -+ -+ -+ -+ Cut out information from a string (varname), based upon a named delimiter. -+ -+ -+ ***/ -+ - /* Maximum length of any variable */ - #define MAXRESULT 1024 - -@@ -249,25 +292,11 @@ - - struct ast_custom_function acf_sort = { - .name = "SORT", -- .synopsis = "Sorts a list of key/vals into a list of keys, based upon the vals", -- .syntax = "SORT(key1:val1[...][,keyN:valN])", -- .desc = --"Takes a comma-separated list of keys and values, each separated by a colon, and returns a\n" --"comma-separated list of the keys, sorted by their values. Values will be evaluated as\n" --"floating-point numbers.\n", - .read = acf_sort_exec, - }; - - struct ast_custom_function acf_cut = { - .name = "CUT", -- .synopsis = "Slices and dices strings, based upon a named delimiter.", -- .syntax = "CUT(,,)", -- .desc = --" varname - variable you want cut\n" --" char-delim - defaults to '-'\n" --" range-spec - number of the field you want (1-based offset)\n" --" may also be specified as a range (with -)\n" --" or group of ranges and fields (with &)\n", - .read = acf_cut_exec, - }; - -Index: funcs/func_redirecting.c -=================================================================== ---- a/funcs/func_redirecting.c (.../tags/1.6.1-rc1) (revision 0) -+++ b/funcs/func_redirecting.c (.../team/group/issue14292) (revision 178988) -@@ -0,0 +1,444 @@ -+/* -+ * Asterisk -- An open source telephony toolkit. -+ * -+ * Copyright (C) 2008 Digium, Inc. -+ * -+ * Richard Mudgett -+ * -+ * 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 Redirecting data dialplan function -+ * \ingroup functions -+ * -+ * \author Richard Mudgett -+ * -+ * See Also: -+ * \arg \ref AstCREDITS -+ */ -+ -+ -+#include "asterisk.h" -+ -+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") -+ -+/* ------------------------------------------------------------------- */ -+ -+ -+#include -+#include -+#include -+#include -+ -+#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/options.h" -+#include "asterisk/callerid.h" -+ -+enum ID_FIELD_STATUS { -+ ID_FIELD_VALID, -+ ID_FIELD_INVALID, -+ ID_FIELD_UNKNOWN -+}; -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Read values from the party id struct. -+ * -+ * \param buf Buffer to fill with read value. -+ * \param len Length of the buffer -+ * \param data Remaining function datatype string -+ * -+ * \retval ID_FIELD_VALID on success. -+ * \retval ID_FIELD_UNKNOWN on unknown field name. -+ */ -+static enum ID_FIELD_STATUS redirecting_id_read(char *buf, size_t len, char *data, const struct ast_party_id *id) -+{ -+ enum ID_FIELD_STATUS status; -+ -+ status = ID_FIELD_VALID; -+ -+ if (!strncasecmp("all", data, 3)) { -+ snprintf(buf, len, "\"%s\" <%s>", -+ S_OR(id->name, ""), -+ S_OR(id->number, "")); -+ } else if (!strncasecmp("name", data, 4)) { -+ if (id->name) { -+ ast_copy_string(buf, id->name, len); -+ } -+ } else if (!strncasecmp("num", data, 3)) { -+ if (id->number) { -+ ast_copy_string(buf, id->number, len); -+ } -+ } else if (!strncasecmp("ton", data, 3)) { -+ snprintf(buf, len, "%d", id->number_type); -+ } else if (!strncasecmp("pres", data, 4)) { -+ ast_copy_string(buf, ast_named_caller_presentation(id->number_presentation), len); -+ } else { -+ status = ID_FIELD_UNKNOWN; -+ } -+ -+ return status; -+} /* end redirecting_id_read() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Read values from the redirecting information struct. -+ * -+ * \param chan Asterisk channel to read -+ * \param cmd Not used -+ * \param data Redirecting function datatype string -+ * \param buf Buffer to fill with read value. -+ * \param len Length of the buffer -+ * -+ * \retval 0 on success. -+ * \retval -1 on error. -+ */ -+static int redirecting_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -+{ -+ /* Ensure that the buffer is empty */ -+ *buf = 0; -+ -+ if (!chan) -+ return -1; -+ -+ ast_channel_lock(chan); -+ -+ if (!strncasecmp("from-", data, 5)) { -+ struct ast_party_id from_id; -+ -+ from_id = chan->redirecting.from; -+ from_id.number = chan->cid.cid_rdnis; -+ switch (redirecting_id_read(buf, len, data + 5, &from_id)) { -+ case ID_FIELD_VALID: -+ case ID_FIELD_INVALID: -+ break; -+ -+ default: -+ ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); -+ break; -+ } /* end switch */ -+ } else if (!strncasecmp("to-", data, 3)) { -+ switch (redirecting_id_read(buf, len, data + 3, &chan->redirecting.to)) { -+ case ID_FIELD_VALID: -+ case ID_FIELD_INVALID: -+ break; -+ -+ default: -+ ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); -+ break; -+ } /* end switch */ -+ } else if (!strncasecmp("pres", data, 4)) { -+ ast_copy_string(buf, ast_named_caller_presentation(chan->redirecting.from.number_presentation), len); -+ } else if (!strncasecmp("reason", data, 6)) { -+ ast_copy_string(buf, ast_redirecting_reason_name(chan->redirecting.reason), len); -+ } else if (!strncasecmp("count", data, 5)) { -+ snprintf(buf, len, "%d", chan->redirecting.count); -+ } else { -+ ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); -+ } -+ -+ ast_channel_unlock(chan); -+ -+ return 0; -+} /* end redirecting_read() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Write new values to the party id struct -+ * -+ * \param id Party ID struct to write values -+ * \param data Remaining function datatype string -+ * \param value Value to assign to the party id. -+ * -+ * \retval ID_FIELD_VALID on success. -+ * \retval ID_FIELD_INVALID on error with field value. -+ * \retval ID_FIELD_UNKNOWN on unknown field name. -+ */ -+static enum ID_FIELD_STATUS redirecting_id_write(struct ast_party_id *id, char *data, const char *value) -+{ -+ char *val; -+ enum ID_FIELD_STATUS status; -+ -+ status = ID_FIELD_VALID; -+ -+ if (!strncasecmp("all", data, 3)) { -+ char name[256]; -+ char num[256]; -+ -+ ast_callerid_split(value, name, sizeof(name), num, sizeof(num)); -+ id->name = ast_strdup(name); -+ id->number = ast_strdup(num); -+ } else if (!strncasecmp("name", data, 4)) { -+ id->name = ast_strdup(value); -+ ast_trim_blanks(id->name); -+ } else if (!strncasecmp("num", data, 3)) { -+ id->number = ast_strdup(value); -+ ast_trim_blanks(id->number); -+ } else if (!strncasecmp("ton", data, 3)) { -+ val = ast_strdupa(value); -+ ast_trim_blanks(val); -+ -+ if (('0' <= val[0]) && (val[0] <= '9')) { -+ id->number_type = atoi(val); -+ } else { -+ ast_log(LOG_ERROR, "Unknown redirecting type of number '%s', value unchanged\n", val); -+ status = ID_FIELD_INVALID; -+ } -+ } else if (!strncasecmp("pres", data, 4)) { -+ int pres; -+ -+ val = ast_strdupa(value); -+ ast_trim_blanks(val); -+ -+ if (('0' <= val[0]) && (val[0] <= '9')) { -+ pres = atoi(val); -+ } else { -+ pres = ast_parse_caller_presentation(val); -+ } -+ -+ if (pres < 0) { -+ ast_log(LOG_ERROR, "Unknown redirecting number presentation '%s', value unchanged\n", val); -+ status = ID_FIELD_INVALID; -+ } else { -+ id->number_presentation = pres; -+ } -+ } else { -+ status = ID_FIELD_UNKNOWN; -+ } -+ -+ return status; -+} /* end redirecting_id_write() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Write new values to the redirecting information struct. -+ * -+ * \param chan Asterisk channel to update -+ * \param cmd Not used -+ * \param data Redirecting function datatype string -+ * \param value Value to assign to the redirecting information struct. -+ * -+ * \retval 0 on success. -+ * \retval -1 on error. -+ */ -+static int redirecting_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) -+{ -+ struct ast_party_redirecting redirecting; -+ char *val; -+ char *option; -+ void (*set_it)(struct ast_channel *chan, const struct ast_party_redirecting *redirecting); -+ -+ if (!value || !chan) { -+ return -1; -+ } -+ -+ /* Determine if the update indication inhibit option is present */ -+ option = strchr(data, ','); -+ if (option) { -+ option = ast_skip_blanks(option + 1); -+ switch (*option) { -+ case 'i': -+ set_it = ast_set_redirecting; -+ break; -+ -+ default: -+ ast_log(LOG_ERROR, "Unknown redirecting option '%s'.\n", option); -+ return 0; -+ } /* end switch */ -+ } -+ else { -+ set_it = ast_redirecting_update; -+ } -+ -+ ast_channel_lock(chan); -+ ast_party_redirecting_set_init(&redirecting, &chan->redirecting); -+ ast_channel_unlock(chan); -+ -+ value = ast_skip_blanks(value); -+ -+ if (!strncasecmp("from-", data, 5)) { -+ switch (redirecting_id_write(&redirecting.from, data + 5, value)) { -+ case ID_FIELD_VALID: -+ set_it(chan, &redirecting); -+ ast_party_redirecting_free(&redirecting); -+ break; -+ -+ case ID_FIELD_INVALID: -+ break; -+ -+ default: -+ ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); -+ break; -+ } /* end switch */ -+ } else if (!strncasecmp("to-", data, 3)) { -+ switch (redirecting_id_write(&redirecting.to, data + 3, value)) { -+ case ID_FIELD_VALID: -+ set_it(chan, &redirecting); -+ ast_party_redirecting_free(&redirecting); -+ break; -+ -+ case ID_FIELD_INVALID: -+ break; -+ -+ default: -+ ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); -+ break; -+ } /* end switch */ -+ } else if (!strncasecmp("pres", data, 4)) { -+ int pres; -+ -+ val = ast_strdupa(value); -+ ast_trim_blanks(val); -+ -+ if (('0' <= val[0]) && (val[0] <= '9')) { -+ pres = atoi(val); -+ } else { -+ pres = ast_parse_caller_presentation(val); -+ } -+ -+ if (pres < 0) { -+ ast_log(LOG_ERROR, "Unknown redirecting number presentation '%s', value unchanged\n", val); -+ } else { -+ redirecting.from.number_presentation = pres; -+ redirecting.to.number_presentation = pres; -+ set_it(chan, &redirecting); -+ } -+ } else if (!strncasecmp("reason", data, 6)) { -+ int reason; -+ -+ val = ast_strdupa(value); -+ ast_trim_blanks(val); -+ -+ if (('0' <= val[0]) && (val[0] <= '9')) { -+ reason = atoi(val); -+ } else { -+ reason = ast_redirecting_reason_parse(val); -+ } -+ -+ if (reason < 0) { -+ ast_log(LOG_ERROR, "Unknown redirecting reason '%s', value unchanged\n", val); -+ } else { -+ redirecting.reason = reason; -+ set_it(chan, &redirecting); -+ } -+ } else if (!strncasecmp("count", data, 5)) { -+ val = ast_strdupa(value); -+ ast_trim_blanks(val); -+ -+ if (('0' <= val[0]) && (val[0] <= '9')) { -+ redirecting.count = atoi(val); -+ set_it(chan, &redirecting); -+ } else { -+ ast_log(LOG_ERROR, "Unknown redirecting count '%s', value unchanged\n", val); -+ } -+ } else { -+ ast_log(LOG_ERROR, "Unknown redirecting data type '%s'.\n", data); -+ } -+ -+ return 0; -+} /* end redirecting_write() */ -+ -+ -+ -+ -+static struct ast_custom_function redirecting_function = { -+ .name = "REDIRECTING", -+ .synopsis = "Gets or sets Redirecting data on the channel.", -+ .syntax = "REDIRECTING(datatype[,i])", -+ .desc = -+ "Gets or sets Redirecting data on the channel.\n" -+ "The optional update Inhibit option prevents the channel\n" -+ "from sending out protocol messages because of the value\n" -+ "being set.\n" -+ "The allowable datatypes are:\n" -+ "\"from-all\", \"from-name\", \"from-num\", \"from-ton\",\n" -+ "\"to-all\", \"to-name\", \"to-num\", \"to-ton\",\n" -+ "\"pres\", \"reason\", and \"count\"\n" -+ "The reason datatype can be set to the following:\n" -+ "unknown - Unknown\n" -+ "cfb - Call Forwarding Busy\n" -+ "cfnr - Call Forwarding No Reply\n" -+ "unavailable - Callee is Unavailable\n" -+ "time_of_day - Time of Day\n" -+ "dnd - Do Not Disturb\n" -+ "deflection - Call Deflection\n" -+ "follow_me - Follow Me\n" -+ "out_of_order - Called DTE Out-Of-Order\n" -+ "away - Callee is Away\n" -+ "cf_dte - Call Forwarding By The Called DTE\n" -+ "cfu - Call Forwarding Unconditional\n", -+ .read = redirecting_read, -+ .write = redirecting_write, -+}; -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Unload the function module -+ * -+ * \retval 0 on success. -+ * \retval -1 on error. -+ */ -+static int unload_module(void) -+{ -+ return ast_custom_function_unregister(&redirecting_function); -+} /* end unload_module() */ -+ -+ -+ -+ -+/* ******************************************************************* */ -+/*! -+ * \internal -+ * \brief Load and initialize the function module. -+ * -+ * \retval 0 on success. -+ * \retval -1 on error. -+ */ -+static int load_module(void) -+{ -+ return ast_custom_function_register(&redirecting_function); -+} /* end load_module() */ -+ -+ -+ -+ -+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Redirecting data dialplan function"); -+ -+ -+/* ------------------------------------------------------------------- */ -+/* end func_redirecting.c */ - -Property changes on: funcs/func_redirecting.c -___________________________________________________________________ -Added: svn:eol-style - + native -Added: svn:mime-type - + text/plain -Added: svn:keywords - + Author Date Id Revision - -Index: funcs/func_global.c -=================================================================== ---- a/funcs/func_global.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_global.c (.../team/group/issue14292) (revision 178988) -@@ -37,6 +37,51 @@ - #include "asterisk/app.h" - #include "asterisk/manager.h" - -+/*** DOCUMENTATION -+ -+ -+ Gets or sets the global variable specified. -+ -+ -+ -+ Global variable name -+ -+ -+ -+ Set or get the value of a global variable specified in varname -+ -+ -+ -+ -+ Gets or sets the shared variable specified. -+ -+ -+ -+ Variable name -+ -+ -+ If not specified will default to current channel. It is the complete -+ channel name: SIP/12-abcd1234 or the prefix only SIP/12. -+ -+ -+ -+ Implements a shared variable area, in which you may share variables between -+ channels. -+ The variables used in this space are separate from the general namespace of -+ the channel and thus SHARED(foo) and foo -+ represent two completely different variables, despite sharing the same name. -+ Finally, realize that there is an inherent race between channels operating -+ at the same time, fiddling with each others' internal variables, which is why -+ this special variable namespace exists; it is to remind you that variables in -+ the SHARED namespace may change at any time, without warning. You should -+ therefore take special care to ensure that when using the SHARED namespace, -+ you retrieve the variable and store it in a regular channel variable before -+ using it in a set of calculations (or you might be surprised by the result). -+ -+ -+ -+ ***/ -+ - static void shared_variable_free(void *data); - - static struct ast_datastore_info shared_variable_info = { -@@ -76,8 +121,6 @@ - - static struct ast_custom_function global_function = { - .name = "GLOBAL", -- .synopsis = "Gets or sets the global variable specified", -- .syntax = "GLOBAL()", - .read = global_read, - .write = global_write, - }; -@@ -203,25 +246,6 @@ - - static struct ast_custom_function shared_function = { - .name = "SHARED", -- .synopsis = "Gets or sets the shared variable specified", -- .syntax = "SHARED([,])", -- .desc = --"Implements a shared variable area, in which you may share variables between\n" --"channels. If channel is unspecified, defaults to the current channel. Note\n" --"that the channel name may be the complete name (i.e. SIP/12-abcd1234) or the\n" --"prefix only (i.e. SIP/12).\n" --"\n" --"The variables used in this space are separate from the general namespace of\n" --"the channel and thus ${SHARED(foo)} and ${foo} represent two completely\n" --"different variables, despite sharing the same name.\n" --"\n" --"Finally, realize that there is an inherent race between channels operating\n" --"at the same time, fiddling with each others' internal variables, which is why\n" --"this special variable namespace exists; it is to remind you that variables in\n" --"the SHARED namespace may change at any time, without warning. You should\n" --"therefore take special care to ensure that when using the SHARED namespace,\n" --"you retrieve the variable and store it in a regular channel variable before\n" --"using it in a set of calculations (or you might be surprised by the result).\n", - .read = shared_read, - .write = shared_write, - }; -Index: funcs/func_extstate.c -=================================================================== ---- a/funcs/func_extstate.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_extstate.c (.../team/group/issue14292) (revision 178988) -@@ -36,6 +36,29 @@ - #include "asterisk/utils.h" - #include "asterisk/devicestate.h" - -+/*** DOCUMENTATION -+ -+ -+ Get an extension's state. -+ -+ -+ -+ -+ If it is not specified defaults to default. -+ -+ -+ -+ The EXTENSION_STATE function can be used to retrieve the state from any -+ hinted extension. For example: -+ NoOp(1234@default has state ${EXTENSION_STATE(1234)}) -+ NoOp(4567@home has state ${EXTENSION_STATE(4567@home)}) -+ The possible values returned by this function are: -+ UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING | -+ RINGINUSE | HOLDINUSE | ONHOLD -+ -+ -+ ***/ -+ - static const char *ast_extstate_str(int state) - { - const char *res = "UNKNOWN"; -@@ -98,17 +121,6 @@ - - static struct ast_custom_function extstate_function = { - .name = "EXTENSION_STATE", -- .synopsis = "Get an extension's state", -- .syntax = "EXTENSION_STATE(extension[@context])", -- .desc = -- " The EXTENSION_STATE function can be used to retrieve the state from any\n" -- "hinted extension. For example:\n" -- " NoOp(1234@default has state ${EXTENSION_STATE(1234)})\n" -- " NoOp(4567@home has state ${EXTENSION_STATE(4567@home)})\n" -- "\n" -- " The possible values returned by this function are:\n" -- "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n" -- "RINGINUSE | HOLDINUSE | ONHOLD\n", - .read = extstate_read, - }; - -Index: funcs/func_realtime.c -=================================================================== ---- a/funcs/func_realtime.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_realtime.c (.../team/group/issue14292) (revision 178988) -@@ -37,6 +37,110 @@ - #include "asterisk/utils.h" - #include "asterisk/app.h" - -+/*** DOCUMENTATION -+ -+ -+ RealTime Read/Write Functions. -+ -+ -+ -+ -+ -+ -+ Use delim1 with delim2 on -+ read and field without delim2 on -+ write -+ If we are reading and delim1 is not specified, defaults -+ to , -+ -+ -+ Parameter only used when reading, if not specified defaults to = -+ -+ -+ -+ This function will read or write values from/to a RealTime repository. -+ REALTIME(....) will read names/values from the repository, and -+ REALTIME(....)= will write a new value/field to the repository. On a -+ read, this function returns a delimited text string. The name/value -+ pairs are delimited by delim1, and the name and value are delimited -+ between each other with delim2. -+ If there is no match, NULL will be returned by the function. -+ On a write, this function will always return NULL. -+ -+ -+ -+ -+ RealTime Store Function. -+ -+ -+ -+ -+ -+ -+ -+ -+ This function will insert a new set of values into the RealTime repository. -+ If RT engine provides an unique ID of the stored record, REALTIME_STORE(...)=.. -+ creates channel variable named RTSTOREID, which contains value of unique ID. -+ Currently, a maximum of 30 field/value pairs is supported. -+ -+ -+ -+ -+ RealTime Destroy Function. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ This function acts in the same way as REALTIME(....) does, except that -+ it destroys the matched record in the RT engine. -+ -+ -+ -+ -+ RealTime query function. -+ -+ -+ -+ -+ -+ -+ -+ -+ This function retrieves a single item, fieldname -+ from the RT engine, where fieldmatch contains the value -+ value. When written to, the REALTIME_FIELD() function -+ performs identically to the REALTIME() function. -+ -+ -+ -+ -+ RealTime query function. -+ -+ -+ -+ -+ -+ -+ -+ This function retrieves a single record from the RT engine, where -+ fieldmatch contains the value -+ value and formats the output suitably, such that -+ it can be assigned to the HASH() function. The HASH() function then provides -+ a suitable method for retrieving each field value of the record. -+ -+ -+ ***/ -+ -+AST_THREADSTORAGE(buf1); -+AST_THREADSTORAGE(buf2); -+AST_THREADSTORAGE(buf3); -+ - static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) - { - struct ast_variable *var, *head; -@@ -84,7 +188,7 @@ - out = ast_str_alloca(resultslen); - for (var = head; var; var = var->next) - ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1); -- ast_copy_string(buf, out->str, len); -+ ast_copy_string(buf, ast_str_buffer(out), len); - - if (chan) - ast_autoservice_stop(chan); -@@ -103,7 +207,7 @@ - ); - - if (ast_strlen_zero(data)) { -- ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch,value,newcol) - missing argument!\n"); -+ ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value,newcol) - missing argument!\n", cmd); - return -1; - } - -@@ -124,6 +228,82 @@ - return 0; - } - -+static int realtimefield_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -+{ -+ struct ast_variable *var, *head; -+ struct ast_str *escapebuf = ast_str_thread_get(&buf1, 16); -+ struct ast_str *fields = ast_str_thread_get(&buf2, 16); -+ struct ast_str *values = ast_str_thread_get(&buf3, 16); -+ int first = 0; -+ enum { rtfield, rthash } which; -+ AST_DECLARE_APP_ARGS(args, -+ AST_APP_ARG(family); -+ AST_APP_ARG(fieldmatch); -+ AST_APP_ARG(value); -+ AST_APP_ARG(fieldname); -+ ); -+ -+ if (!strcmp(cmd, "REALTIME_FIELD")) { -+ which = rtfield; -+ } else { -+ which = rthash; -+ } -+ -+ if (ast_strlen_zero(data)) { -+ ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : ""); -+ return -1; -+ } -+ -+ AST_STANDARD_APP_ARGS(args, data); -+ -+ if ((which == rtfield && args.argc != 4) || (which == rthash && args.argc != 3)) { -+ ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,value%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : ""); -+ return -1; -+ } -+ -+ if (chan) { -+ ast_autoservice_start(chan); -+ } -+ -+ if (!(head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL))) { -+ if (chan) { -+ ast_autoservice_stop(chan); -+ } -+ return -1; -+ } -+ -+ ast_str_reset(fields); -+ ast_str_reset(values); -+ -+ for (var = head; var; var = var->next) { -+ if (which == rtfield) { -+ ast_debug(1, "Comparing %s to %s\n", var->name, args.fieldname); -+ if (!strcasecmp(var->name, args.fieldname)) { -+ ast_debug(1, "Match! Value is %s\n", var->value); -+ ast_copy_string(buf, var->value, len); -+ break; -+ } -+ } else if (which == rthash) { -+ ast_debug(1, "Setting hash key %s to value %s\n", var->name, var->value); -+ ast_str_append(&fields, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->name, INT_MAX)); -+ ast_str_append(&values, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->value, INT_MAX)); -+ first = 0; -+ } -+ } -+ ast_variables_destroy(head); -+ -+ if (which == rthash) { -+ pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields)); -+ ast_copy_string(buf, ast_str_buffer(values), len); -+ } -+ -+ if (chan) { -+ ast_autoservice_stop(chan); -+ } -+ -+ return 0; -+} -+ - static int function_realtime_store(struct ast_channel *chan, const char *cmd, char *data, const char *value) - { - int res = 0; -@@ -220,7 +400,7 @@ - for (var = head; var; var = var->next) { - ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1); - } -- ast_copy_string(buf, out->str, len); -+ ast_copy_string(buf, ast_str_buffer(out), len); - - ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL); - -@@ -232,39 +412,28 @@ - - struct ast_custom_function realtime_function = { - .name = "REALTIME", -- .synopsis = "RealTime Read/Write Functions", -- .syntax = "REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) on read\n" -- "REALTIME(family,fieldmatch,value,field) on write", -- .desc = "This function will read or write values from/to a RealTime repository.\n" -- "REALTIME(....) will read names/values from the repository, and \n" -- "REALTIME(....)= will write a new value/field to the repository. On a\n" -- "read, this function returns a delimited text string. The name/value \n" -- "pairs are delimited by delim1, and the name and value are delimited \n" -- "between each other with delim2. The default for delim1 is ',' and \n" -- "the default for delim2 is '='. If there is no match, NULL will be \n" -- "returned by the function. On a write, this function will always \n" -- "return NULL. \n", - .read = function_realtime_read, - .write = function_realtime_write, - }; - -+struct ast_custom_function realtimefield_function = { -+ .name = "REALTIME_FIELD", -+ .read = realtimefield_read, -+ .write = function_realtime_write, -+}; -+ -+struct ast_custom_function realtimehash_function = { -+ .name = "REALTIME_HASH", -+ .read = realtimefield_read, -+}; -+ - struct ast_custom_function realtime_store_function = { - .name = "REALTIME_STORE", -- .synopsis = "RealTime Store Function", -- .syntax = "REALTIME_STORE(family,field1,field2,...,field30) = value1,value2,...,value30", -- .desc = "This function will insert a new set of values into the RealTime repository.\n" -- "If RT engine provides an unique ID of the stored record, REALTIME_STORE(...)=..\n" -- "creates channel variable named RTSTOREID, which contains value of unique ID.\n" -- "Currently, a maximum of 30 field/value pairs is supported.\n", - .write = function_realtime_store, - }; - - struct ast_custom_function realtime_destroy_function = { - .name = "REALTIME_DESTROY", -- .synopsis = "RealTime Destroy Function", -- .syntax = "REALTIME_DESTROY(family,fieldmatch[,value[,delim1[,delim2]]])\n", -- .desc = "This function acts in the same way as REALTIME(....) does, except that\n" -- "it destroys matched record in RT engine.\n", - .read = function_realtime_readdestroy, - }; - -@@ -274,6 +443,8 @@ - res |= ast_custom_function_unregister(&realtime_function); - res |= ast_custom_function_unregister(&realtime_store_function); - res |= ast_custom_function_unregister(&realtime_destroy_function); -+ res |= ast_custom_function_unregister(&realtimefield_function); -+ res |= ast_custom_function_unregister(&realtimehash_function); - return res; - } - -@@ -283,6 +454,8 @@ - res |= ast_custom_function_register(&realtime_function); - res |= ast_custom_function_register(&realtime_store_function); - res |= ast_custom_function_register(&realtime_destroy_function); -+ res |= ast_custom_function_register(&realtimefield_function); -+ res |= ast_custom_function_register(&realtimehash_function); - return res; - } - -Index: funcs/func_curl.c -=================================================================== ---- a/funcs/func_curl.c (.../tags/1.6.1-rc1) (revision 178988) -+++ b/funcs/func_curl.c (.../team/group/issue14292) (revision 178988) -@@ -50,16 +50,316 @@ - #include "asterisk/utils.h" - #include "asterisk/threadstorage.h" - -+#define CURLVERSION_ATLEAST(a,b,c) \ -+ ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c)))) -+ -+#define CURLOPT_SPECIAL_HASHCOMPAT -500 -+ -+static void curlds_free(void *data); -+ -+static struct ast_datastore_info curl_info = { -+ .type = "CURL", -+ .destroy = curlds_free, -+}; -+ -+struct curl_settings { -+ AST_LIST_ENTRY(curl_settings) list; -+ CURLoption key; -+ void *value; -+}; -+ -+AST_LIST_HEAD_STATIC(global_curl_info, curl_settings); -+ -+static void curlds_free(void *data) -+{ -+ AST_LIST_HEAD(global_curl_info, curl_settings) *list = data; -+ struct curl_settings *setting; -+ if (!list) { -+ return; -+ } -+ while ((setting = AST_LIST_REMOVE_HEAD(list, list))) { -+ free(setting); -+ } -+ AST_LIST_HEAD_DESTROY(list); -+} -+ -+enum optiontype { -+ OT_BOOLEAN, -+ OT_INTEGER, -+ OT_INTEGER_MS, -+ OT_STRING, -+ OT_ENUM, -+}; -+ -+static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype *ot) -+{ -+ if (!strcasecmp(name, "header")) { -+ *key = CURLOPT_HEADER; -+ *ot = OT_BOOLEAN; -+ } else if (!strcasecmp(name, "proxy")) { -+ *key = CURLOPT_PROXY; -+ *ot = OT_STRING; -+ } else if (!strcasecmp(name, "proxyport")) { -+ *key = CURLOPT_PROXYPORT; -+ *ot = OT_INTEGER; -+ } else if (!strcasecmp(name, "proxytype")) { -+ *key = CURLOPT_PROXYTYPE; -+ *ot = OT_ENUM; -+ } else if (!strcasecmp(name, "dnstimeout")) { -+ *key = CURLOPT_DNS_CACHE_TIMEOUT; -+ *ot = OT_INTEGER; -+ } else if (!strcasecmp(name, "userpwd")) { -+ *key = CURLOPT_USERPWD; -+ *ot = OT_STRING; -+ } else if (!strcasecmp(name, "proxyuserpwd")) { -+ *key = CURLOPT_PROXYUSERPWD; -+ *ot = OT_STRING; -+ } else if (!strcasecmp(name, "maxredirs")) { -+ *key = CURLOPT_MAXREDIRS; -+ *ot = OT_INTEGER; -+ } else if (!strcasecmp(name, "referer")) { -+ *key = CURLOPT_REFERER; -+ *ot = OT_STRING; -+ } else if (!strcasecmp(name, "useragent")) { -+ *key = CURLOPT_USERAGENT; -+ *ot = OT_STRING; -+ } else if (!strcasecmp(name, "cookie")) { -+ *key = CURLOPT_COOKIE; -+ *ot = OT_STRING; -+ } else if (!strcasecmp(name, "ftptimeout")) { -+ *key = CURLOPT_FTP_RESPONSE_TIMEOUT; -+ *ot = OT_INTEGER; -+ } else if (!strcasecmp(name, "httptimeout")) { -+#if CURLVERSION_ATLEAST(7,16,2) -+ *key = CURLOPT_TIMEOUT_MS; -+ *ot = OT_INTEGER_MS; -+#else -+ *key = CURLOPT_TIMEOUT; -+ *ot = OT_INTEGER; -+#endif -+ } else if (!strcasecmp(name, "conntimeout")) { -+#if CURLVERSION_ATLEAST(7,16,2) -+ *key = CURLOPT_CONNECTTIMEOUT_MS; -+ *ot = OT_INTEGER_MS; -+#else -+ *key = CURLOPT_CONNECTTIMEOUT; -+ *ot = OT_INTEGER; -+#endif -+ } else if (!strcasecmp(name, "ftptext")) { -+ *key = CURLOPT_TRANSFERTEXT; -+ *ot = OT_BOOLEAN; -+ } else if (!strcasecmp(name, "hashcompat")) { -+ *key = CURLOPT_SPECIAL_HASHCOMPAT; -+ *ot = OT_BOOLEAN; -+ } else { -+ return -1; -+ } -+ return 0; -+} -+ -+static int acf_curlopt_write(struct ast_channel *chan, const char *cmd, char *name, const char *value) -+{ -+ struct ast_datastore *store; -+ struct global_curl_info *list; -+ struct curl_settings *cur, *new = NULL; -+ CURLoption key; -+ enum optiontype ot; -+ -+ if (chan) { -+ if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) { -+ /* Create a new datastore */ -+ if (!(store = ast_datastore_alloc(&curl_info, NULL))) { -+ ast_log(LOG_ERROR, "Unable to allocate new datastore. Cannot set any CURL options\n"); -+ return -1; -+ } -+ -+ if (!(list = ast_calloc(1, sizeof(*list)))) { -+ ast_log(LOG_ERROR, "Unable to allocate list head. Cannot set any CURL options\n"); -+ ast_datastore_free(store); -+ } -+ -+ store->data = list; -+ AST_LIST_HEAD_INIT(list); -+ ast_channel_datastore_add(chan, store); -+ } else { -+ list = store->data; -+ } -+ } else { -+ /* Populate the global structure */ -+ list = &global_curl_info; -+ } -+ -+ if (!parse_curlopt_key(name, &key, &ot)) { -+ if (ot == OT_BOOLEAN) { -+ if ((new = ast_calloc(1, sizeof(*new)))) { -+ new->value = (void *)((long) ast_true(value)); -+ } -+ } else if (ot == OT_INTEGER) { -+ long tmp = atol(value); -+ if ((new = ast_calloc(1, sizeof(*new)))) { -+ new->value = (void *)tmp; -+ } -+ } else if (ot == OT_INTEGER_MS) { -+ long tmp = atof(value) * 1000.0; -+ if ((new = ast_calloc(1, sizeof(*new)))) { -+ new->value = (void *)tmp; -+ } -+ } else if (ot == OT_STRING) { -+ if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) { -+ new->value = (char *)new + sizeof(*new); -+ strcpy(new->value, value); -+ } -+ } else if (ot == OT_ENUM) { -+ if (key == CURLOPT_PROXYTYPE) { -+ long ptype = -+#if CURLVERSION_ATLEAST(7,10,0) -+ CURLPROXY_HTTP; -+#else -+ CURLPROXY_SOCKS5; -+#endif -+ if (0) { -+#if CURLVERSION_ATLEAST(7,15,2) -+ } else if (!strcasecmp(value, "socks4")) { -+ ptype = CURLPROXY_SOCKS4; -+#endif -+#if CURLVERSION_ATLEAST(7,18,0) -+ } else if (!strcasecmp(value, "socks4a")) { -+ ptype = CURLPROXY_SOCKS4A; -+#endif -+#if CURLVERSION_ATLEAST(7,18,0) -+ } else if (!strcasecmp(value, "socks5")) { -+ ptype = CURLPROXY_SOCKS5; -+#endif -+#if CURLVERSION_ATLEAST(7,18,0) -+ } else if (!strncasecmp(value, "socks5", 6)) { -+ ptype = CURLPROXY_SOCKS5_HOSTNAME; -+#endif -+ } -+ -+ if ((new = ast_calloc(1, sizeof(*new)))) { -+ new->value = (void *)ptype; -+ } -+ } else { -+ /* Highly unlikely */ -+ goto yuck; -+ } -+ } -+ -+ /* Memory allocation error */ -+ if (!new) { -+ return -1; -+ } -+ -+ new->key = key; -+ } else { -+yuck: -+ ast_log(LOG_ERROR, "Unrecognized option: %s\n", name); -+ return -1; -+ } -+ -+ /* Remove any existing entry */ -+ AST_LIST_LOCK(list); -+ AST_LIST_TRAVERSE_SAFE_BEGIN(list, cur, list) { -+ if (cur->key == new->key) { -+ AST_LIST_REMOVE_CURRENT(list); -+ free(cur); -+ break; -+ } -+ } -+ AST_LIST_TRAVERSE_SAFE_END -+ -+ /* Insert new entry */ -+ ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value); -+ AST_LIST_INSERT_TAIL(list, new, list); -+ AST_LIST_UNLOCK(list); -+ -+ return 0; -+} -+ -+static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) -+{ -+ struct ast_datastore *store; -+ struct global_curl_info *list[2] = { &global_curl_info, NULL }; -+ struct curl_settings *cur = NULL; -+ CURLoption key; -+ enum optiontype ot; -+ int i; -+ -+ if (parse_curlopt_key(data, &key, &ot)) { -+ ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data); -+ return -1; -+ } -+ -+ if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) { -+ list[0] = store->data; -+ list[1] = &global_curl_info; -+ } -+ -+ for (i = 0; i < 2; i++) { -+ if (!list[i]) { -+ break; -+ } -+ AST_LIST_LOCK(list[i]); -+ AST_LIST_TRAVERSE(list[i], cur, list) { -+ if (cur->key == key) { -+ if (ot == OT_BOOLEAN || ot == OT_INTEGER) { -+ snprintf(buf, len, "%ld", (long)cur->value); -+ } else if (ot == OT_INTEGER_MS) { -+ if ((long)cur->value % 1000 == 0) { -+ snprintf(buf, len, "%ld", (long)cur->value / 1000); -+ } else { -+ snprintf(buf, len, "%.3f", (double)((long)cur->value) / 1000.0); -+ } -+ } else if (ot == OT_STRING) { -+ ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value); -+ ast_copy_string(buf, cur->value, len); -+ } else if (key == CURLOPT_PROXYTYPE) { -+ if (0) { -+#if CURLVERSION_ATLEAST(7,15,2) -+ } else if ((long)cur->value == CURLPROXY_SOCKS4) { -+ ast_copy_string(buf, "socks4", len); -+#endif -+#if CURLVERSION_ATLEAST(7,18,0) -+ } else if ((long)cur->value == CURLPROXY_SOCKS4A) { -+ ast_copy_string(buf, "socks4a", len); -+#endif -+ } else if ((long)cur->value == CURLPROXY_SOCKS5) { -+ ast_copy_string(buf, "socks5", len); -+#if CURLVERSION_ATLEAST(7,18,0) -+ } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) { -+ ast_copy_string(buf, "socks5hostname", len); -+#endif -+#if CURLVERSION_ATLEAST(7,10,0) -+ } else if ((long)cur->value == CURLPROXY_HTTP) { -+ ast_copy_string(buf, "http", len); -+#endif -+ } else { -+ ast_copy_string(buf, "unknown", len); -+ } -+ } -+ break; -+ } -+ } -+ AST_LIST_UNLOCK(list[i]); -+ if (cur) { -+ break; -+ } -+ } -+ -+ return cur ? 0 : -1; -+} -+ - static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) - { - register int realsize = size * nmemb; -- struct ast_str **str = (struct ast_str **)data; -+ struct ast_str **pstr = (struct ast_str **)data; - -- if (ast_str_make_space(str, (*str)->used + realsize + 1) == 0) { -- memcpy(&(*str)->str[(*str)->used], ptr, realsize); -- (*str)->used += realsize; -- } -+ ast_debug(3, "Called with data=%p, str=%p, realsize=%d, len=%zu, used=%zu\n", data, *pstr, realsize, ast_str_size(*pstr), ast_str_strlen(*pstr)); - -+ ast_str_append_substr(pstr, 0, ptr, realsize); -+ -+ ast_debug(3, "Now, len=%zu, used=%zu\n", ast_str_size(*pstr), ast_str_strlen(*pstr)); -+ - return realsize; - } - -@@ -91,29 +391,6 @@ - - AST_THREADSTORAGE_CUSTOM(curl_instance, curl_instance_init, curl_instance_cleanup); - --static int curl_internal(struct ast_str **chunk, char *url, char *post) --{ -- CURL **curl; -- -- if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) -- return -1; -- -- curl_easy_setopt(*curl, CURLOPT_URL, url); -- curl_easy_setopt(*curl, CURLOPT_WRITEDATA, (void *) chunk); -- -- if (post) { -- curl_easy_setopt(*curl, CURLOPT_POST, 1); -- curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, post); -- } -- -- curl_easy_perform(*curl); -- -- if (post) -- curl_easy_setopt(*curl, CURLOPT_POST, 0); -- -- return 0; --} -- - static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len) - { - struct ast_str *str = ast_str_create(16); -@@ -122,6 +399,11 @@ - AST_APP_ARG(url); - AST_APP_ARG(postdata); - ); -+ CURL **curl; -+ struct curl_settings *cur; -+ struct ast_datastore *store = NULL; -+ int hashcompat = 0; -+ AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL; - - *buf = '\0'; - -@@ -133,21 +415,81 @@ - - AST_STANDARD_APP_ARGS(args, info); - -- if (chan) -+ if (chan) { - ast_autoservice_start(chan); -+ } - -- if (!curl_internal(&str, args.url, args.postdata)) { -- if (str->used) { -- str->str[str->used] = '\0'; -- if (str->str[str->used - 1] == '\n') { -- str->str[str->used - 1] = '\0'; -+ if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) { -+ ast_log(LOG_ERROR, "Cannot allocate curl structure\n"); -+ return -1; -+ } -+ -+ AST_LIST_LOCK(&global_curl_info); -+ AST_LIST_TRAVERSE(&global_curl_info, cur, list) { -+ if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { -+ hashcompat = (cur->value != NULL) ? 1 : 0; -+ } else { -+ curl_easy_setopt(*curl, cur->key, cur->value); -+ } -+ } -+ -+ if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) { -+ list = store->data; -+ AST_LIST_LOCK(list); -+ AST_LIST_TRAVERSE(list, cur, list) { -+ if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { -+ hashcompat = (cur->value != NULL) ? 1 : 0; -+ } else { -+ curl_easy_setopt(*curl, cur->key, cur->value); - } -+ } -+ } - -- ast_copy_string(buf, str->str, len); -+ curl_easy_setopt(*curl, CURLOPT_URL, args.url); -+ curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &str); -+ -+ if (args.postdata) { -+ curl_easy_setopt(*curl, CURLOPT_POST, 1); -+ curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata); -+ } -+ -+ curl_easy_perform(*curl); -+ -+ if (store) { -+ AST_LIST_UNLOCK(list); -+ } -+ AST_LIST_UNLOCK(&global_curl_info); -+ -+ if (args.postdata) { -+ curl_easy_setopt(*curl, CURLOPT_POST, 0); -+ } -+ -+ if (ast_str_strlen(str)) { -+ ast_str_trim_blanks(str); -+ -+ ast_debug(3, "str='%s'\n", ast_str_buffer(str)); -+ if (hashcompat) { -+ char *remainder = ast_str_buffer(str); -+ char *piece; -+ struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2); -+ struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2); -+ int rowcount = 0; -+ while ((piece = strsep(&remainder, "&"))) { -+ char *name = strsep(&piece, "="); -+ ast_uri_decode(piece); -+ ast_uri_decode(name); -+ ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", name); -+ ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", piece); -+ rowcount++; -+ } -+ pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields)); -+ ast_copy_string(buf, ast_str_buffer(values), len); -+ ast_free(fields); -+ ast_free(values); -+ } else { -+ ast_copy_string(buf, ast_str_buffer(str), len); - } - ret = 0; -- } else { -- ast_log(LOG_ERROR, "Cannot allocate curl structure\n"); - } - ast_free(str); - -@@ -167,11 +509,38 @@ - .read = acf_curl_exec, - }; - -+struct ast_custom_function acf_curlopt = { -+ .name = "CURLOPT", -+ .synopsis = "Set options for use with the CURL() function", -+ .syntax = "CURLOPT(