summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
authorMichael Mason <ms13sp@gmail.com>2009-04-09 12:54:18 +0000
committerMichael Mason <ms13sp@gmail.com>2009-04-09 12:54:18 +0000
commitf3eeb22d210991904604139571612c08c3d4c9e9 (patch)
tree7f72789b4bc545ac5e1e5d4c878b04eca35dd201 /testing
parentd57b27efc7a102c9dd3eea2b246f328a79ef4b68 (diff)
parentb0830b40592bc7c808cf5bceb5519360ef0b6322 (diff)
downloadaports-f3eeb22d210991904604139571612c08c3d4c9e9.tar.bz2
aports-f3eeb22d210991904604139571612c08c3d4c9e9.tar.xz
Merge branch 'master' of git://dev.alpinelinux.org/aports
Diffstat (limited to 'testing')
-rw-r--r--testing/asterisk/APKBUILD10
-rw-r--r--testing/asterisk/asterisk-03-1.6.1-rc1-i14292.patch106423
-rw-r--r--testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch41697
-rw-r--r--testing/asterisk/asterisk-07-issue14068.patch1423
4 files changed, 43126 insertions, 106427 deletions
diff --git a/testing/asterisk/APKBUILD b/testing/asterisk/APKBUILD
index 22b70b4c..39fde65a 100644
--- a/testing/asterisk/APKBUILD
+++ b/testing/asterisk/APKBUILD
@@ -1,7 +1,7 @@
# Contributor: Timo Teras <timo.teras@iki.fi>
# Maintainer: Timo Teras <timo.teras@iki.fi>
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 b61de722..00000000
--- 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 @@
- </member>
- <member name="CHANNEL_TRACE" displayname="Enable CHANNEL(trace) function">
- </member>
-+ <member name="SKINNY_DEVMODE" displayname="Enable Skinny Dev Mode">
-+ </member>
- </category>
-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 @@
- <defaultenabled>no</defaultenabled>
- </member>
- <member name="G711_REDUCED_BRANCHING" displayname="New ulaw/alaw codec, reduced branching (might help it run faster in some architectures)">
-- <defaultenabled>yes</defaultenabled>
- <depend>G711_NEW_ALGORITHM</depend>
- </member>
- <member name="TEST_CODING_TABLES" displayname="New ulaw/alaw codec, turn on table tests on init">
-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 @@
- <mwi msg.mwi.1.callBackMode="contact" msg.mwi.1.callBack="${VOICEMAIL_EXTEN}" />
- </msg>
- <nat nat.ip="" nat.signalPort="" nat.mediaPortStart=""/>
-- <user_preferences up.oneTouchVoiceMail="1" up.welcomeSoundEnabled="0" />
-+ <user_preferences up.oneTouchVoiceMail="1" up.welcomeSoundEnabled="0" up.mwiVisible="1" />
- <volume voice.volume.persist.handset="1" voice.volume.persist.headset="1" />
- <SNTP tcpIpApp.sntp.address="time" tcpIpApp.sntp.gmtOffset="${TZOFFSET}" tcpIpApp.sntp.daylightSavings.enable="${DST_ENABLE}" tcpIpApp.sntp.daylightSavings.fixedDayEnable="0" tcpIpApp.sntp.daylightSavings.start.month="${DST_START_MONTH}" tcpIpApp.sntp.daylightSavings.start.date="${DST_START_MDAY}" tcpIpApp.sntp.daylightSavings.start.hour="${DST_START_HOUR}" tcpIpApp.sntp.daylightSavings.stop.month="${DST_END_MONTH}" tcpIpApp.sntp.daylightSavings.stop.date="${DST_END_MDAY}" tcpIpApp.sntp.daylightSavings.stop.hour="${DST_END_HOUR}" />
- <HTTPD httpd.enabled="1" />
-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 @@
- <?xml version="1.0" standalone="yes"?>
-- <APPLICATION APP_FILE_PATH="sip.ld" CONFIG_FILES="${IF($[${STAT(e|${CUSTOM_CONFIG})}] ? "custom.cfg, ")}config/${TOLOWER(${MAC})}, sip.cfg" MISC_FILES="" LOG_FILE_DIRECTORY=""/>
-+ <APPLICATION APP_FILE_PATH="sip.ld" CONFIG_FILES="${IF($[${STAT(e|${CUSTOM_CONFIG})}] ? "custom.cfg, ")}config/${MAC}, sip.cfg" MISC_FILES="" LOG_FILE_DIRECTORY=""/>
-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 <dahdi/user.h>
-+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 <dahdi/user.h>
-+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 <sys/timerfd.h>
-+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 <sql.h>
-+_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 <sql.h>
-+_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 <sys/inotify.h>
-+_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 <sys/inotify.h>
-+_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 <libxml/tree.h>
-+ #include <libxml/parser.h>" != 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 <libxml/tree.h>
-+ #include <libxml/parser.h>
-+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 <libpri.h>
-+_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 <libpri.h>
-+_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 <vorbis/codec.h>
-+_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 <vorbis/codec.h>
-+_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 <conf$$subs.sed
-+rm -f conf$$subs.sed
-+cat >>$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 <arpa/inet.h>
-
- #include <list>
-@@ -63,8 +66,6 @@
- #include "cisco-h225.h"
- #include "caps_h323.h"
-
--#include <ptbuildopts.h>
--
- #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 <arpa/inet.h>
-
- /*
-@@ -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 <ptclib/asner.h>
-+#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 <ptbuildopts.h>
-+#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
-- <depend>ossaudio</depend>
-+ <depend>oss</depend>
- <depend>usb</depend>
- <defaultenabled>no</defaultenabled>
- ***/
-@@ -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 <markster@digium.com>
-- *
-- * 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
-+ <application name="DAHDISendKeypadFacility" language="en_US">
-+ <synopsis>
-+ Send digits out of band over a PRI.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="digits" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will send the given string of digits in a Keypad
-+ Facility IE over the current channel.</para>
-+ </description>
-+ </application>
-+ <application name="DAHDISendCallreroutingFacility" language="en_US">
-+ <synopsis>
-+ Send QSIG call rerouting facility over a PRI.
-+ </synopsis>
-+ <syntax argsep=",">
-+ <parameter name="destination" required="true">
-+ <para>Destination number.</para>
-+ </parameter>
-+ <parameter name="original">
-+ <para>Original called number.</para>
-+ </parameter>
-+ <parameter name="reason">
-+ <para>Diversion reason, if not specified defaults to <literal>unknown</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will send a Callrerouting Facility IE over the
-+ current channel.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- #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 <maxcount> 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 - <callingnum>|<callernum>\n");
-+ } else if (ast_strlen_zero(callingnum)) {
-+ flag = 1;
-+ ast_verb(3, "DAHDIQsigCheckCcbsnr: no caller number - <callingnum>|<callernum>\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) <callingnum>|<callernum>\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 <callingnum>|<callernum>\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 <CCBR/CCNR>|<callingnum>|<callernum>|<callername>|<context>|<priority>\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 <CCBS/CCNR>|<callingnum>|<callernum>|<callername>|<context>|<priority>\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 "<Unknown>";
-- }
-+ }
- }
-+#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 : "<Unknown Caller>", 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/<channel#>[c|r<cadance#>|d][/extension])
-+ * Dial(DAHDI/<trunk_group#>:<crv#>[c|r<cadance#>|d][/extension])
-+ * Dial(DAHDI/(g|G|r|R)<group#(0-63)>[c|r<cadance#>|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<cadance#> - 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, "<unspecified>"),
- pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
- } else {
-- ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
-+ 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 <span>\n"
-+ case CLI_INIT:
-+ e->command = "pri set debug {on|off|0|1|2} span";
-+ e->usage =
-+ "Usage: pri set debug {<level>|on|off} span <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 <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 <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 <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 <chan num>\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 <trunkgroup> | group <group> | context <context> ]\n"
- " Shows a list of available channels with optional filtering\n"
- " <group> 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 <chan num>\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 <rx|tx> <chan#> <gain>\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 @@
- " <gain> 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 <rx|tx> <chan#> <gain>\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 @@
- " <gain> 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 <chan#> <on|off>\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 <span>\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 <linkset>\n"
-+ e->command = "ss7 set debug {on|off} linkset";
-+ e->usage =
-+ "Usage: ss7 set debug {on|off} linkset <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 <linkset> <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 <linkset number>\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 <linkset> <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 <linkset number>\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 <span>\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" <number>, 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|<trace level>)\n"
-+ "Usage: h323 set trace (on|off|<trace level>)\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
-- <depend>vpbapi</depend>
-+ <depend>vpb</depend>
- ***/
-
- #include <vpbapi.h>
-@@ -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
- <depend>chan_local</depend>
- ***/
-@@ -199,6 +272,208 @@
- #include "asterisk/event.h"
- #include "asterisk/tcptls.h"
-
-+/*** DOCUMENTATION
-+ <application name="SIPDtmfMode" language="en_US">
-+ <synopsis>
-+ Change the dtmfmode for a SIP call.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mode" required="true">
-+ <enumlist>
-+ <enum name="inband" />
-+ <enum name="info" />
-+ <enum name="rfc2833" />
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Changes the dtmfmode for a SIP call.</para>
-+ </description>
-+ </application>
-+ <application name="SIPAddHeader" language="en_US">
-+ <synopsis>
-+ Add a SIP header to the outbound call.
-+ </synopsis>
-+ <syntax argsep=":">
-+ <parameter name="Header" required="true" />
-+ <parameter name="Content" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Adds a header to a SIP call placed with DIAL.</para>
-+ <para>Remember to use the X-header if you are adding non-standard SIP
-+ headers, like <literal>X-Asterisk-Accountcode:</literal>. Use this with care.
-+ Adding the wrong headers may jeopardize the SIP dialog.</para>
-+ <para>Always returns <literal>0</literal>.</para>
-+ </description>
-+ </application>
-+ <application name="SIPRemoveHeader" language="en_US">
-+ <synopsis>
-+ Remove SIP headers previously added with SIPAddHeader
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Header" required="false" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>For example you have added these 2 headers:</para>
-+ <para>SIPAddHeader(P-Asserted-Identity: sip:foo@bar);</para>
-+ <para>SIPAddHeader(P-Preferred-Identity: sip:bar@foo);</para>
-+ <para></para>
-+ <para>// remove all headers</para>
-+ <para>SIPRemoveHeader();</para>
-+ <para>// remove all P- headers</para>
-+ <para>SIPRemoveHeader(P-);</para>
-+ <para>// remove only the PAI header (note the : at the end)</para>
-+ <para>SIPRemoveHeader(P-Asserted-Identity:);</para>
-+ <para></para>
-+ <para>Always returns <literal>0</literal>.</para>
-+ </description>
-+ </application>
-+ <function name="SIP_HEADER" language="en_US">
-+ <synopsis>
-+ Gets the specified SIP header.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="name" required="true" />
-+ <parameter name="number">
-+ <para>If not specified, defaults to <literal>1</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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 <literal>1</literal>.</para>
-+ </description>
-+ </function>
-+ <function name="SIPPEER" language="en_US">
-+ <synopsis>
-+ Gets SIP peer information.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="peername" required="true" />
-+ <parameter name="item">
-+ <enumlist>
-+ <enum name="ip">
-+ <para>(default) The ip address.</para>
-+ </enum>
-+ <enum name="port">
-+ <para>The port number.</para>
-+ </enum>
-+ <enum name="mailbox">
-+ <para>The configured mailbox.</para>
-+ </enum>
-+ <enum name="context">
-+ <para>The configured context.</para>
-+ </enum>
-+ <enum name="expire">
-+ <para>The epoch time of the next expire.</para>
-+ </enum>
-+ <enum name="dynamic">
-+ <para>Is it dynamic? (yes/no).</para>
-+ </enum>
-+ <enum name="callerid_name">
-+ <para>The configured Caller ID name.</para>
-+ </enum>
-+ <enum name="callerid_num">
-+ <para>The configured Caller ID number.</para>
-+ </enum>
-+ <enum name="callgroup">
-+ <para>The configured Callgroup.</para>
-+ </enum>
-+ <enum name="pickupgroup">
-+ <para>The configured Pickupgroup.</para>
-+ </enum>
-+ <enum name="codecs">
-+ <para>The configured codecs.</para>
-+ </enum>
-+ <enum name="status">
-+ <para>Status (if qualify=yes).</para>
-+ </enum>
-+ <enum name="regexten">
-+ <para>Registration extension.</para>
-+ </enum>
-+ <enum name="limit">
-+ <para>Call limit (call-limit).</para>
-+ </enum>
-+ <enum name="busylevel">
-+ <para>Configured call level for signalling busy.</para>
-+ </enum>
-+ <enum name="curcalls">
-+ <para>Current amount of calls. Only available if call-limit is set.</para>
-+ </enum>
-+ <enum name="language">
-+ <para>Default language for peer.</para>
-+ </enum>
-+ <enum name="accountcode">
-+ <para>Account code for this peer.</para>
-+ </enum>
-+ <enum name="useragent">
-+ <para>Current user agent id for peer.</para>
-+ </enum>
-+ <enum name="chanvar[name]">
-+ <para>A channel variable configured with setvar for this peer.</para>
-+ </enum>
-+ <enum name="codec[x]">
-+ <para>Preferred codec index number <replaceable>x</replaceable> (beginning with zero).</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description />
-+ </function>
-+ <function name="SIPCHANINFO" language="en_US">
-+ <synopsis>
-+ Gets the specified SIP parameter from the current channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="item" required="true">
-+ <enumlist>
-+ <enum name="peerip">
-+ <para>The IP address of the peer.</para>
-+ </enum>
-+ <enum name="recvip">
-+ <para>The source IP address of the peer.</para>
-+ </enum>
-+ <enum name="from">
-+ <para>The URI from the <literal>From:</literal> header.</para>
-+ </enum>
-+ <enum name="uri">
-+ <para>The URI from the <literal>Contact:</literal> header.</para>
-+ </enum>
-+ <enum name="useragent">
-+ <para>The useragent.</para>
-+ </enum>
-+ <enum name="peername">
-+ <para>The name of the peer.</para>
-+ </enum>
-+ <enum name="t38passthrough">
-+ <para><literal>1</literal> if T38 is offered or enabled in this channel,
-+ otherwise <literal>0</literal>.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description />
-+ </function>
-+ <function name="CHECKSIPDOMAIN" language="en_US">
-+ <synopsis>
-+ Checks if domain is a local domain.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="domain" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function checks if the <replaceable>domain</replaceable> 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 <literal>domain=</literal> configuration in <filename>sip.conf</filename>.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- #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 <brackets> 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\" <anonymous@anonymous.invalid>";
-+
-+ 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\" <sip:%s@%s>", lid_name, lid_num, fromdomain);
-+ }
-+ add_header(req, "P-Asserted-Identity", tmp);
-+ } else {
-+ snprintf(tmp, sizeof(tmp), "\"%s\" <sip:%s@%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, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport);
- else
- ast_string_field_build(p, our_contact, "<sip:%s%s%s>", 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, "<sip:%s%s%s:%d;transport=%s>", 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\" <sip:%s@%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\" <sip:%s@%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), "<sip:%s@%s>;reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason);
-+ } else {
-+ snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%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, "<?xml version=\"1.0\"?>\n");
-- ast_str_append(&tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full":"partial", mto);
-- if ((state & AST_EXTENSION_RINGING) && global_notifyringing)
-- ast_str_append(&tmp, 0, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
-- else
-+ ast_str_append(&tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full" : "partial", mto);
-+ if ((state & AST_EXTENSION_RINGING) && 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,
-+ "<dialog id=\"%s\" call-id=\"pickup-%s\" direction=\"recipient\">\n"
-+ "<remote>\n"
-+ /* See the limitations of this above. Luckily the phone seems to still be
-+ happy when these values are not correct. */
-+ "<identity display=\"%s\">%s</identity>\n"
-+ "<target uri=\"%s\"/>\n"
-+ "</remote>\n"
-+ "<local>\n"
-+ "<identity>%s</identity>\n"
-+ "<target uri=\"%s\"/>\n"
-+ "</local>\n",
-+ p->exten, p->callid, local_display, local_target, local_target, mto, mto);
-+ } else {
- ast_str_append(&tmp, 0, "<dialog id=\"%s\">\n", p->exten);
-+ }
- ast_str_append(&tmp, 0, "<state>%s</state>\n", statestring);
- if (state == AST_EXTENSION_ONHOLD) {
- ast_str_append(&tmp, 0, "<local>\n<target uri=\"%s\">\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: <name>=<value> At least one variable pair must be specified.\n"
- " ActionID: <id> 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), "<sip:%s@%s>", dest, c);
-+ snprintf(referto, sizeof(referto), "<sip%s:%s@%s>", use_tls ? "s" : "", dest, c);
- else
-- snprintf(referto, sizeof(referto), "<sip:%s>", dest);
-+ snprintf(referto, sizeof(referto), "<sip%s:%s>", 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 <brackets> 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 : "<none>", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "<none>" );
-+ 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 : "<none>", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "<none>" );
- }
-
- 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 [<name>|all|like <pattern>]|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)?"<Not set>":"<Set>");
- ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"<Not set>":"<Set>");
-+ ast_cli(fd, " Remote Secret: %s\n", ast_strlen_zero(peer->remotesecret)?"<Not set>":"<Set>");
- 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)?"<Secret set>":(!ast_strlen_zero(auth->md5secret)?"<MD5secret set>" : "<Not set>"));
-@@ -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) ? "<not set>" : global_outboundproxy.name,
-- global_outboundproxy.force ? "(forced)" : "");
-+ ast_cli(a->fd, " Outb. proxy: %s %s\n", ast_strlen_zero(sip_cfg.outboundproxy.name) ? "<not set>" : 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(<name>[,<number>])",
-- .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(<domain|IP>)",
- .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(<peername>[,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 : "<no from tag>", totag ? totag : "<no to tag>");
-+ if (sipdebug)
-+ ast_debug(4, "Invite/replaces: Will use Replace-Call-ID : %s Fromtag: %s Totag: %s\n",
-+ replace_id,
-+ fromtag ? fromtag : "<no from tag>",
-+ totag ? totag : "<no to tag>");
-
-+ /* 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, &current->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: <none>\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, &regseconds, 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(&reg_string, "%s:%s@%s/%s", peer->username, peer->secret, peer->tohost, callback) < 0) {
-+ if (asprintf(&reg_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(&regl, 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(&regl); /* 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(&regl, sip_registry_destroy);
- ASTOBJ_CONTAINER_DESTROY(&regl);
-+ 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
-+ <application name="AgentLogin" language="en_US">
-+ <synopsis>
-+ Call agent login.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="AgentNo" />
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="s">
-+ <para>silent login - do not announce the login ok segment after
-+ agent logged on/off</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Asks the agent to login to the system. Always returns <literal>-1</literal>.
-+ While logged in, the agent can receive calls and will hear a <literal>beep</literal>
-+ when a new call comes in. The agent can dump the call by pressing the star key.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Queue</ref>
-+ <ref type="application">AddQueueMember</ref>
-+ <ref type="application">RemoveQueueMember</ref>
-+ <ref type="application">PauseQueueMember</ref>
-+ <ref type="application">UnpauseQueueMember</ref>
-+ <ref type="function">AGENT</ref>
-+ <ref type="filename">agents.conf</ref>
-+ <ref type="filename">queues.conf</ref>
-+ </see-also>
-+ </application>
-+ <application name="AgentMonitorOutgoing" language="en_US">
-+ <synopsis>
-+ Record agent's outgoing call.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="d">
-+ <para>make the app return <literal>-1</literal> if there is an error condition.</para>
-+ </option>
-+ <option name="c">
-+ <para>change the CDR so that the source of the call is
-+ <literal>Agent/agent_id</literal></para>
-+ </option>
-+ <option name="n">
-+ <para>don't generate the warnings when there is no callerid or the
-+ agentid is not known. It's handy if you want to have one context
-+ for agent and non-agent calls.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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
-+ <filename>agents.conf</filename> file.</para>
-+ <para>Normally the app returns <literal>0</literal> unless the options are passed.</para>
-+ </description>
-+ <see-also>
-+ <ref type="filename">agents.conf</ref>
-+ </see-also>
-+ </application>
-+ <function name="AGENT" language="en_US">
-+ <synopsis>
-+ Gets information about an Agent
-+ </synopsis>
-+ <syntax argsep=":">
-+ <parameter name="agentid" required="true" />
-+ <parameter name="item">
-+ <para>The valid items to retrieve are:</para>
-+ <enumlist>
-+ <enum name="status">
-+ <para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
-+ </enum>
-+ <enum name="password">
-+ <para>The password of the agent</para>
-+ </enum>
-+ <enum name="name">
-+ <para>The name of the agent</para>
-+ </enum>
-+ <enum name="mohclass">
-+ <para>MusicOnHold class</para>
-+ </enum>
-+ <enum name="exten">
-+ <para>The callback extension for the Agent (AgentCallbackLogin)</para>
-+ </enum>
-+ <enum name="channel">
-+ <para>The name of the active channel for the Agent (AgentLogin)</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description />
-+ </function>
-+ ***/
-+
- 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(<agentid>[: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 [<device>]";
- 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 [<device>]\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
-+ <application name="IAX2Provision" language="en_US">
-+ <synopsis>
-+ Provision a calling IAXy with a given template.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="template">
-+ <para>If not specified, defaults to <literal>default</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Provisions the calling IAXy (assuming the calling entity is in fact an IAXy) with the
-+ given <replaceable>template</replaceable>. Returns <literal>-1</literal> on error
-+ or <literal>0</literal> on success.</para>
-+ </description>
-+ </application>
-+ <function name="IAXPEER" language="en_US">
-+ <synopsis>
-+ Gets IAX peer information.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="peername" required="true">
-+ <enumlist>
-+ <enum name="CURRENTCHANNEL">
-+ <para>If <replaceable>peername</replaceable> is specified to this value, return the IP address of the
-+ endpoint of the current channel</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ <parameter name="item">
-+ <para>If <replaceable>peername</replaceable> is specified, valid items are:</para>
-+ <enumlist>
-+ <enum name="ip">
-+ <para>(default) The IP address.</para>
-+ </enum>
-+ <enum name="status">
-+ <para>The peer's status (if <literal>qualify=yes</literal>)</para>
-+ </enum>
-+ <enum name="mailbox">
-+ <para>The configured mailbox.</para>
-+ </enum>
-+ <enum name="context">
-+ <para>The configured context.</para>
-+ </enum>
-+ <enum name="expire">
-+ <para>The epoch time of the next expire.</para>
-+ </enum>
-+ <enum name="dynamic">
-+ <para>Is it dynamic? (yes/no).</para>
-+ </enum>
-+ <enum name="callerid_name">
-+ <para>The configured Caller ID name.</para>
-+ </enum>
-+ <enum name="callerid_num">
-+ <para>The configured Caller ID number.</para>
-+ </enum>
-+ <enum name="codecs">
-+ <para>The configured codecs.</para>
-+ </enum>
-+ <enum name="codec[x]">
-+ <para>Preferred codec index number <replaceable>x</replaceable> (beginning
-+ with <literal>0</literal>)</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description />
-+ <see-also>
-+ <ref type="function">SIPPEER</ref>
-+ </see-also>
-+ </function>
-+ <function name="IAXVAR" language="en_US">
-+ <synopsis>
-+ Sets or retrieves a remote variable.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true" />
-+ </syntax>
-+ <description />
-+ </function>
-+ ***/
-+
- /* 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) ? "<Not set>" : "<Set>");
-@@ -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, "<unspecified>"));
- 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(&registrations);
-+ AST_LIST_TRAVERSE(&registrations, 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, "<Unregistered>", 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(&registrations);
-+
-+ 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(<varname>)",
- .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 : "<Unknown>");
-- 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 : "<Unknown>");
-+ 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 : "<Unknown>",
- iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
-
-- 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 : "<Unknown>",
- iaxs[iaxs[fr->callno]->bridgecallno]->owner ? iaxs[iaxs[fr->callno]->bridgecallno]->owner->name : "<Unknown>");
-@@ -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(&registrations);
- while ((reg = AST_LIST_REMOVE_HEAD(&registrations, 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(<peername|CURRENTCHANNEL>[,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
-- <depend>ossaudio</depend>
-+ <depend>oss</depend>
- ***/
-
- #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 [<device>]";
- 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 <signal.h>
- #include <sys/file.h>
- #include <semaphore.h>
-+#include <ctype.h>
-
- #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 <level> [only] | [port <port> [only]]\n"
-+ "Usage: misdn set debug {on|off|<level>} [only] | [port <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[,<args>]\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[,<args>]\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: <id> 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 <DeviceId|DeviceName>\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: <name> The device name you want to check.\n"
-+" ActionID: <id> 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: <name> 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 <DeviceId|DeviceName>\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: <id> 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 <Line> [ on <DeviceID|DeviceName> ]\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, "<not set>"));
-- 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, "<not set>"));
-- ast_cli(a->fd, "Accountcode: %s\n", S_OR(l->accountcode, "<not set>"));
-- 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, "<not set>"));
-- ast_cli(a->fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
-- 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, "<not set>"));
-- ast_cli(a->fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
-- ast_cli(a->fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
-- ast_cli(a->fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
-- ast_cli(a->fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
-- ast_cli(a->fd, "MWIblink: %d\n", l->mwiblink);
-- ast_cli(a->fd, "Regextension: %s\n", S_OR(l->regexten, "<not set>"));
-- ast_cli(a->fd, "Regcontext: %s\n", S_OR(l->regcontext, "<not set>"));
-- ast_cli(a->fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "<not set>"));
-- ast_cli(a->fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "<not set>"));
-- ast_cli(a->fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
-- ast_cli(a->fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "<not set>"));
-- 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, "<not set>"));
-+ 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, "<not set>"));
-+ ast_cli(fd, "Accountcode: %s\n", S_OR(l->accountcode, "<not set>"));
-+ ast_cli(fd, "AmaFlag: %s\n", ast_cdr_flags2str(l->amaflags));
-+ ast_cli(fd, "CallerId Number: %s\n", S_OR(l->cid_num, "<not set>"));
-+ ast_cli(fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
-+ 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, "<not set>"));
-+ ast_cli(fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
-+ ast_cli(fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
-+ ast_cli(fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
-+ ast_cli(fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
-+ ast_cli(fd, "MWIblink: %d\n", l->mwiblink);
-+ ast_cli(fd, "Regextension: %s\n", S_OR(l->regexten, "<not set>"));
-+ ast_cli(fd, "Regcontext: %s\n", S_OR(l->regcontext, "<not set>"));
-+ ast_cli(fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "<not set>"));
-+ ast_cli(fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "<not set>"));
-+ ast_cli(fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
-+ ast_cli(fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "<not set>"));
-+ 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, "<not set>"));
-+ 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, "<not set>"));
-+ astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "<not set>"));
-+ 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, "<not set>"));
-+ astman_append(s, "CFwdBusy: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
-+ astman_append(s, "CFwdNoAnswer: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
-+ astman_append(s, "VoicemailBox: %s\r\n", S_OR(l->mailbox, "<not set>"));
-+ astman_append(s, "VoicemailNumber: %s\r\n", S_OR(l->vmexten, "<not set>"));
-+ astman_append(s, "MWIblink: %d\r\n", l->mwiblink);
-+ astman_append(s, "RegExtension: %s\r\n", S_OR(l->regexten, "<not set>"));
-+ astman_append(s, "Regcontext: %s\r\n", S_OR(l->regcontext, "<not set>"));
-+ astman_append(s, "MoHInterpret: %s\r\n", S_OR(l->mohinterpret, "<not set>"));
-+ astman_append(s, "MoHSuggest: %s\r\n", S_OR(l->mohsuggest, "<not set>"));
-+ astman_append(s, "LastDialedNr: %s\r\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
-+ astman_append(s, "LastCallerID: %s\r\n", S_OR(l->lastcallerid, "<not set>"));
-+ 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: <name> The line name you want to check.\n"
-+" ActionID: <id> 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: <name> 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 <Line> [ on <DeviceID|DeviceName> ]\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
-- <depend>asound</depend>
-+ <depend>alsa</depend>
- ***/
-
- #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 <port> <channel>'\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 <crich@beronet.com>
-@@ -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 <sys/signal.h>
- #include <iksemel.h>
- #include <pthread.h>
-+#include <ctype.h>
-
- #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(&gtalk_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 <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief ast_sched performance test module
-+ *
-+ * \author Russell Bryant <russell@digium.com>
-+ */
-+
-+#include "asterisk.h"
-+
-+#include <inttypes.h>
-+
-+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 <num>\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 <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief Heap data structure test module
-+ *
-+ * \author Russell Bryant <russell@digium.com>
-+ */
-+
-+#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 <libxml/tree.h>
-+ #include <libxml/parser.h>],
-+ [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
-+ <application name="Gosub" language="en_US">
-+ <synopsis>
-+ Jump to label, saving return address.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="context" />
-+ <parameter name="exten" />
-+ <parameter name="priority" required="true" hasparams="optional">
-+ <argument name="arg1" multiple="true" required="true" />
-+ <argument name="argN" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Jumps to the label specified, saving the return address.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">GosubIf</ref>
-+ <ref type="application">Macro</ref>
-+ <ref type="application">Goto</ref>
-+ <ref type="application">Return</ref>
-+ <ref type="application">StackPop</ref>
-+ </see-also>
-+ </application>
-+ <application name="GosubIf" language="en_US">
-+ <synopsis>
-+ Conditionally jump to label, saving return address.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="condition" required="true" />
-+ <parameter name="destination" required="true" argsep=":">
-+ <argument name="labeliftrue" hasparams="optional">
-+ <argument name="arg1" required="true" multiple="true" />
-+ <argument name="argN" />
-+ </argument>
-+ <argument name="labeliffalse" hasparams="optional">
-+ <argument name="arg1" required="true" multiple="true" />
-+ <argument name="argN" />
-+ </argument>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Gosub</ref>
-+ <ref type="application">Return</ref>
-+ <ref type="application">MacroIf</ref>
-+ <ref type="function">IF</ref>
-+ <ref type="application">GotoIf</ref>
-+ </see-also>
-+ </application>
-+ <application name="Return" language="en_US">
-+ <synopsis>
-+ Return from gosub routine.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="value">
-+ <para>Return value.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Jumps to the last label on the stack, removing it. The return <replaceable>value</replaceable>, if
-+ any, is saved in the channel variable <variable>GOSUB_RETVAL</variable>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Gosub</ref>
-+ <ref type="application">StackPop</ref>
-+ </see-also>
-+ </application>
-+ <application name="StackPop" language="en_US">
-+ <synopsis>
-+ Remove one address from gosub stack.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Removes last label on the stack, discarding it.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Return</ref>
-+ <ref type="application">Gosub</ref>
-+ </see-also>
-+ </application>
-+ <function name="LOCAL" language="en_US">
-+ <synopsis>
-+ Manage variables local to the gosub stack frame.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>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()).</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Gosub</ref>
-+ <ref type="application">GosubIf</ref>
-+ <ref type="application">Return</ref>
-+ </see-also>
-+ </function>
-+ <function name="LOCAL_PEEK" language="en_US">
-+ <synopsis>
-+ Retrieve variables hidden by the local gosub stack frame.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="n" required="true" />
-+ <parameter name="varname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Read a variable <replaceable>varname</replaceable> hidden by
-+ <replaceable>n</replaceable> levels of gosub stack frames. Note that ${LOCAL_PEEK(0,foo)}
-+ is the same as <variable>foo</variable>, since the value of <replaceable>n</replaceable>
-+ peeks under 0 levels of stack frames; in other words, 0 is the current level. If
-+ <replaceable>n</replaceable> exceeds the available number of stack frames, then an empty
-+ string is returned.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Gosub</ref>
-+ <ref type="application">GosubIf</ref>
-+ <ref type="application">Return</ref>
-+ </see-also>
-+ </function>
-+ ***/
-
- 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(<varname>)",
- .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
-+ <application name="ChanSpy" language="en_US">
-+ <synopsis>
-+ Listen to a channel, and optionally whisper into it.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="chanprefix" />
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="b">
-+ <para>Only spy on channels involved in a bridged call.</para>
-+ </option>
-+ <option name="B">
-+ <para>Instead of whispering on a single channel barge in on both
-+ channels involved in the call.</para>
-+ </option>
-+ <option name="d">
-+ <para>Override the typical numeric DTMF functionality and instead
-+ use DTMF to switch between spy modes.</para>
-+ <enumlist>
-+ <enum name="4">
-+ <para>spy mode</para>
-+ </enum>
-+ <enum name="5">
-+ <para>whisper mode</para>
-+ </enum>
-+ <enum name="6">
-+ <para>barge mode</para>
-+ </enum>
-+ </enumlist>
-+ </option>
-+ <option name="g">
-+ <argument name="grp" required="true">
-+ <para>Only spy on channels in which one or more of the groups
-+ listed in <replaceable>grp</replaceable> matches one or more groups from the
-+ <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
-+ </argument>
-+ <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
-+ either a single group or a colon-delimited list of groups, such
-+ as <literal>sales:support:accounting</literal>.</para></note>
-+ </option>
-+ <option name="n" argsep="@">
-+ <para>Say the name of the person being spied on if that person has recorded
-+ his/her name. If a context is specified, then that voicemail context will
-+ be searched when retrieving the name, otherwise the <literal>default</literal> context
-+ be used when searching for the name (i.e. if SIP/1000 is the channel being
-+ spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
-+ for the name).</para>
-+ <argument name="mailbox" />
-+ <argument name="context" />
-+ </option>
-+ <option name="q">
-+ <para>Don't play a beep when beginning to spy on a channel, or speak the
-+ selected channel name.</para>
-+ </option>
-+ <option name="r">
-+ <para>Record the session to the monitor spool directory. An optional base for the filename
-+ may be specified. The default is <literal>chanspy</literal>.</para>
-+ <argument name="basename" />
-+ </option>
-+ <option name="s">
-+ <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
-+ speaking the selected channel name.</para>
-+ </option>
-+ <option name="v">
-+ <argument name="value" />
-+ <para>Adjust the initial volume in the range from <literal>-4</literal>
-+ to <literal>4</literal>. A negative value refers to a quieter setting.</para>
-+ </option>
-+ <option name="w">
-+ <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
-+ the spied-on channel.</para>
-+ </option>
-+ <option name="W">
-+ <para>Enable <literal>private whisper</literal> mode, so the spying channel can
-+ talk to the spied-on channel but cannot listen to that channel.</para>
-+ </option>
-+ <option name="o">
-+ <para>Only listen to audio coming from this channel.</para>
-+ </option>
-+ <option name="X">
-+ <para>Allow the user to exit ChanSpy to a valid single digit
-+ numeric extension in the current context or the context
-+ specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
-+ name of the last channel that was spied on will be stored
-+ in the <variable>SPY_CHANNEL</variable> variable.</para>
-+ </option>
-+ <option name="e">
-+ <argument name="ext" required="true" />
-+ <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
-+ only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
-+ list.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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 <literal>chanprefix</literal> parameter is specified,
-+ only channels beginning with this string will be spied upon.</para>
-+ <para>While spying, the following actions may be performed:</para>
-+ <para> - Dialing <literal>#</literal> cycles the volume level.</para>
-+ <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
-+ <para> - Dialing a series of digits followed by <literal>#</literal> 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</para>
-+ <note><para>The <replaceable>X</replaceable> 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 <literal>chanprefix</literal> and a digit sequence.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="application">ExtenSpy</ref>
-+ </see-also>
-+ </application>
-+ <application name="ExtenSpy" language="en_US">
-+ <synopsis>
-+ Listen to a channel, and optionally whisper into it.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="exten" required="true" argsep="@">
-+ <argument name="exten" required="true">
-+ <para>Specify extension.</para>
-+ </argument>
-+ <argument name="context">
-+ <para>Optionally specify a context, defaults to <literal>default</literal>.</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="b">
-+ <para>Only spy on channels involved in a bridged call.</para>
-+ </option>
-+ <option name="B">
-+ <para>Instead of whispering on a single channel barge in on both
-+ channels involved in the call.</para>
-+ </option>
-+ <option name="d">
-+ <para>Override the typical numeric DTMF functionality and instead
-+ use DTMF to switch between spy modes.</para>
-+ <enumlist>
-+ <enum name="4">
-+ <para>spy mode</para>
-+ </enum>
-+ <enum name="5">
-+ <para>whisper mode</para>
-+ </enum>
-+ <enum name="6">
-+ <para>barge mode</para>
-+ </enum>
-+ </enumlist>
-+ </option>
-+ <option name="g">
-+ <argument name="grp" required="true">
-+ <para>Only spy on channels in which one or more of the groups
-+ listed in <replaceable>grp</replaceable> matches one or more groups from the
-+ <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
-+ </argument>
-+ <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
-+ either a single group or a colon-delimited list of groups, such
-+ as <literal>sales:support:accounting</literal>.</para></note>
-+ </option>
-+ <option name="n" argsep="@">
-+ <para>Say the name of the person being spied on if that person has recorded
-+ his/her name. If a context is specified, then that voicemail context will
-+ be searched when retrieving the name, otherwise the <literal>default</literal> context
-+ be used when searching for the name (i.e. if SIP/1000 is the channel being
-+ spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
-+ for the name).</para>
-+ <argument name="mailbox" />
-+ <argument name="context" />
-+ </option>
-+ <option name="q">
-+ <para>Don't play a beep when beginning to spy on a channel, or speak the
-+ selected channel name.</para>
-+ </option>
-+ <option name="r">
-+ <para>Record the session to the monitor spool directory. An optional base for the filename
-+ may be specified. The default is <literal>chanspy</literal>.</para>
-+ <argument name="basename" />
-+ </option>
-+ <option name="s">
-+ <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
-+ speaking the selected channel name.</para>
-+ </option>
-+ <option name="v">
-+ <argument name="value" />
-+ <para>Adjust the initial volume in the range from <literal>-4</literal>
-+ to <literal>4</literal>. A negative value refers to a quieter setting.</para>
-+ </option>
-+ <option name="w">
-+ <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
-+ the spied-on channel.</para>
-+ </option>
-+ <option name="W">
-+ <para>Enable <literal>private whisper</literal> mode, so the spying channel can
-+ talk to the spied-on channel but cannot listen to that channel.</para>
-+ </option>
-+ <option name="o">
-+ <para>Only listen to audio coming from this channel.</para>
-+ </option>
-+ <option name="X">
-+ <para>Allow the user to exit ChanSpy to a valid single digit
-+ numeric extension in the current context or the context
-+ specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
-+ name of the last channel that was spied on will be stored
-+ in the <variable>SPY_CHANNEL</variable> variable.</para>
-+ </option>
-+ <option name="e">
-+ <argument name="ext" required="true" />
-+ <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
-+ only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
-+ list.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>While spying, the following actions may be performed:</para>
-+ <para> - Dialing <literal>#</literal> cycles the volume level.</para>
-+ <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
-+ <note><para>The <replaceable>X</replaceable> 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 <literal>chanprefix</literal> and a digit sequence.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="application">ChanSpy</ref>
-+ </see-also>
-+ </application>
-+
-+ ***/
- 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(<name>) - 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
-+ <application name="JACK" language="en_US">
-+ <synopsis>
-+ Jack Audio Connection Kit
-+ </synopsis>
-+ <syntax>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="s">
-+ <argument name="name" required="true">
-+ <para>Connect to the specified jack server name</para>
-+ </argument>
-+ </option>
-+ <option name="i">
-+ <argument name="name" required="true">
-+ <para>Connect the output port that gets created to the specified jack input port</para>
-+ </argument>
-+ </option>
-+ <option name="o">
-+ <argument name="name" required="true">
-+ <para>Connect the input port that gets created to the specified jack output port</para>
-+ </argument>
-+ </option>
-+ <option name="c">
-+ <argument name="name" required="true">
-+ <para>By default, Asterisk will use the channel name for the jack client name.</para>
-+ <para>Use this option to specify a custom client name.</para>
-+ </argument>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ </application>
-+ ***/
- 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
-+ <application name="NoCDR" language="en_US">
-+ <synopsis>
-+ Tell Asterisk to not maintain a CDR for the current call
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>This application will tell Asterisk not to maintain a CDR for the current call.</para>
-+ </description>
-+ </application>
-+ ***/
-
- 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
-+ <application name="ADSIProg" language="en_US">
-+ <synopsis>
-+ Load Asterisk ADSI Scripts into phone
-+ </synopsis>
-+ <syntax>
-+ <parameter name="script" required="false">
-+ <para>adsi script to use. If not given uses the default script <filename>asterisk.adsi</filename></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application programs an ADSI Phone with the given script</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">GetCPEID</ref>
-+ <ref type="filename">adsi.conf</ref>
-+ </see-also>
-+ </application>
-+ ***/
-
- /* #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
-+ <application name="Read" language="en_US">
-+ <synopsis>
-+ Read a variable.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="variable" required="true">
-+ <para>The input digits will be stored in the given <replaceable>variable</replaceable>
-+ name.</para>
-+ </parameter>
-+ <parameter name="filenames" argsep="&amp;">
-+ <argument name="filename" required="true">
-+ <para>file(s) to play before reading digits or tone with option i</para>
-+ </argument>
-+ <argument name="filename2" multiple="true" />
-+ </parameter>
-+ <parameter name="maxdigits">
-+ <para>Maximum acceptable number of digits. Stops reading after
-+ <replaceable>maxdigits</replaceable> have been entered (without
-+ requiring the user to press the <literal>#</literal> key).</para>
-+ <para>Defaults to <literal>0</literal> - no limit - wait for the
-+ user press the <literal>#</literal> key. Any value below
-+ <literal>0</literal> means the same. Max accepted value is
-+ <literal>255</literal>.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="s">
-+ <para>to return immediately if the line is not up.</para>
-+ </option>
-+ <option name="i">
-+ <para>to play filename as an indication tone from your
-+ <filename>indications.conf</filename>.</para>
-+ </option>
-+ <option name="n">
-+ <para>to read digits even if the line is not up.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="attempts">
-+ <para>If greater than <literal>1</literal>, that many
-+ <replaceable>attempts</replaceable> will be made in the
-+ event no data is entered.</para>
-+ </parameter>
-+ <parameter name="timeout">
-+ <para>The number of seconds to wait for a digit response. If greater
-+ than <literal>0</literal>, that value will override the default timeout.
-+ Can be floating point.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Reads a #-terminated string of digits a certain number of times from the
-+ user in to the given <replaceable>variable</replaceable>.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="READSTATUS">
-+ <para>This is the status of the read operation.</para>
-+ <value name="OK" />
-+ <value name="ERROR" />
-+ <value name="HANGUP" />
-+ <value name="INTERRUPTED" />
-+ <value name="SKIPPED" />
-+ <value name="TIMEOUT" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">SendDTMF</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="Dictate" language="en_US">
-+ <synopsis>
-+ Virtual Dictation Machine.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="base_dir" />
-+ <parameter name="filename" />
-+ </syntax>
-+ <description>
-+ <para>Start dictation machine using optional <replaceable>base_dir</replaceable> for files.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- static char *app = "Dictate";
--static char *synopsis = "Virtual Dictation Machine";
--static char *desc = " Dictate([<base_dir>[,<filename>]])\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
-+ <application name="Festival" language="en_US">
-+ <synopsis>
-+ Say text to the user.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="text" required="true" />
-+ <parameter name="intkeys" />
-+ </syntax>
-+ <description>
-+ <para>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
-+ <literal>any</literal> to allow any number back (useful in dialplan).</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="SoftHangup" language="en_US">
-+ <synopsis>
-+ Hangs up the requested channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Technology/Resource" required="true" />
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Hang up all channels on a specified device instead of a single resource</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Hangs up the requested channel. If there are no channels to
-+ hangup, the application will report it.</para>
-+ </description>
-+ </application>
-
--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 <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*!
-+ * \file
-+ * \brief Playtones application
-+ *
-+ * \author Russell Bryant <russell@digium.com>
-+ *
-+ * \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
-+ <application name="PlayTones" language="en_US">
-+ <synopsis>
-+ Play a tone list.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="arg" required="true">
-+ <para>Arg is either the tone name defined in the <filename>indications.conf</filename>
-+ configuration file, or a directly specified list of frequencies and durations.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Plays a tone list. Execution will continue with the next step in the dialplan
-+ immediately while the tones continue to play.</para>
-+ <para>See the sample <filename>indications.conf</filename> for a description of the
-+ specification of a tonelist.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">StopPlayTones</ref>
-+ </see-also>
-+ </application>
-+ <application name="StopPlayTones" language="en_US">
-+ <synopsis>
-+ Stop playing a tone list.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Stop playing a tone list, initiated by PlayTones().</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">PlayTones</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
-+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
-+ <application name="DAHDIScan" language="en_US">
-+ <synopsis>
-+ Scan DAHDI channels to monitor calls.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="group">
-+ <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Allows a call center manager to monitor DAHDI channels in a
-+ convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
-+ </description>
-+ </application>
-+ ***/
- 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
-+ <application name="AlarmReceiver" language="en_US">
-+ <synopsis>
-+ Provide support for receiving alarm reports from a burglar or fire alarm panel.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>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 <filename>alarmreceiver.conf</filename> 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.</para>
-+ <note><para>Only 1 signalling format is supported at this time: Ademco Contact ID.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="filename">alarmreceiver.conf</ref>
-+ </see-also>
-+ </application>
-+ ***/
-
--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
-+ <application name="SendImage" language="en_US">
-+ <synopsis>
-+ Sends an image file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true">
-+ <para>Path of the filename (image) to send.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Send an image file on a channel supporting it.</para>
-+ <para>Result of transmission will be stored in <variable>SENDIMAGESTATUS</variable></para>
-+ <variablelist>
-+ <variable name="SENDIMAGESTATUS">
-+ <value name="SUCCESS">
-+ Transmission succeeded.
-+ </value>
-+ <value name="FAILURE">
-+ Transmission failed.
-+ </value>
-+ <value name="UNSUPPORTED">
-+ Image transmission not supported by channel.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">SendText</ref>
-+ <ref type="application">SendURL</ref>
-+ </see-also>
-+ </application>
-+ ***/
-
--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
-+ <application name="GetCPEID" language="en_US">
-+ <synopsis>
-+ Get ADSI CPE ID.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Obtains and displays ADSI CPE ID and other information in order
-+ to properly setup <filename>dahdi.conf</filename> for on-hook operations.</para>
-+ </description>
-+ </application>
-+ ***/
- 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
-+ <application name="BackgroundDetect" language="en_US">
-+ <synopsis>
-+ Background a file with talk detect.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true" />
-+ <parameter name="sil">
-+ <para>If not specified, defaults to <literal>1000</literal>.</para>
-+ </parameter>
-+ <parameter name="min">
-+ <para>If not specified, defaults to <literal>100</literal>.</para>
-+ </parameter>
-+ <parameter name="max">
-+ <para>If not specified, defaults to <literal>infinity</literal>.</para>
-+ </parameter>
-+ <parameter name="analysistime">
-+ <para>If not specified, defaults to <literal>infinity</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Plays back <replaceable>filename</replaceable>, 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 <replaceable>min</replaceable> ms yet less than
-+ <replaceable>max</replaceable> ms is followed by silence for at least <replaceable>sil</replaceable> ms,
-+ which occurs during the first <replaceable>analysistime</replaceable> ms, then the audio playback is
-+ aborted and processing jumps to the <replaceable>talk</replaceable> extension, if available.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- static char *app = "BackgroundDetect";
-
--static char *synopsis = "Background a file with talk detect";
--
--static char *descrip =
--" BackgroundDetect(<filename>[,<sil>[,<min>[,<max>[,<analysistime>]]]]):\n"
--"Plays back <filename>, 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 <min> ms yet less than <max> ms\n"
--"is followed by silence for at least <sil> ms, which occurs during the first\n"
--"<analysistime> ms, then the audio playback is aborted and processing jumps to\n"
--"the <talk> extension, if available. If unspecified, <sil>, <min>, <max>, and\n"
--"<analysistime> 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
-+ <application name="DBdel" language="en_US">
-+ <synopsis>
-+ Delete a key from the asterisk database.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will delete a <replaceable>key</replaceable> from the Asterisk
-+ database.</para>
-+ <note><para>This application has been DEPRECATED in favor of the DB_DELETE function.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="function">DB_DELETE</ref>
-+ <ref type="application">DBdeltree</ref>
-+ <ref type="function">DB</ref>
-+ </see-also>
-+ </application>
-+ <application name="DBdeltree" language="en_US">
-+ <synopsis>
-+ Delete a family or keytree from the asterisk database.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="family" required="true" />
-+ <parameter name="keytree" />
-+ </syntax>
-+ <description>
-+ <para>This application will delete a <replaceable>family</replaceable> or <replaceable>keytree</replaceable>
-+ from the Asterisk database.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">DB_DELETE</ref>
-+ <ref type="application">DBdel</ref>
-+ <ref type="function">DB</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- /*! \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
-+ <application name="ControlPlayback" language="en_US">
-+ <synopsis>
-+ Play a file with fast forward and rewind.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true" />
-+ <parameter name="skipms">
-+ <para>This is number of milliseconds to skip when rewinding or
-+ fast-forwarding.</para>
-+ </parameter>
-+ <parameter name="ff">
-+ <para>Fast-forward when this DTMF digit is received. (defaults to <literal>#</literal>)</para>
-+ </parameter>
-+ <parameter name="rew">
-+ <para>Rewind when this DTMF digit is received. (defaults to <literal>*</literal>)</para>
-+ </parameter>
-+ <parameter name="stop">
-+ <para>Stop playback when this DTMF digit is received.</para>
-+ </parameter>
-+ <parameter name="pause">
-+ <para>Pause playback when this DTMF digit is received.</para>
-+ </parameter>
-+ <parameter name="restart">
-+ <para>Restart playback when this DTMF digit is received.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="o">
-+ <argument name="time" required="true">
-+ <para>Start at <replaceable>time</replaceable> ms from the
-+ beginning of the file.</para>
-+ </argument>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will play back the given <replaceable>filename</replaceable>.</para>
-+ <para>It sets the following channel variables upon completion:</para>
-+ <variablelist>
-+ <variable name="CPLAYBACKSTATUS">
-+ <para>Contains the status of the attempt as a text string</para>
-+ <value name="SUCCESS" />
-+ <value name="USERSTOPPED" />
-+ <value name="ERROR" />
-+ </variable>
-+ <variable name="CPLAYBACKOFFSET">
-+ <para>Contains the offset in ms into the file where playback
-+ was at when it stopped. <literal>-1</literal> is end of file.</para>
-+ </variable>
-+ <variable name="CPLAYBACKSTOPKEY">
-+ <para>If the playback is stopped by the user this variable contains
-+ the key that was pressed.</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
- 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
-+ <application name="SetCallerPres" language="en_US">
-+ <synopsis>
-+ Set CallerID Presentation.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="presentation" required="true">
-+ <enumlist>
-+ <enum name="allowed_not_screened">
-+ <para>Presentation Allowed, Not Screened.</para>
-+ </enum>
-+ <enum name="allowed_passed_screen">
-+ <para>Presentation Allowed, Passed Screen.</para>
-+ </enum>
-+ <enum name="allowed_failed_screen">
-+ <para>Presentation Allowed, Failed Screen.</para>
-+ </enum>
-+ <enum name="allowed">
-+ <para>Presentation Allowed, Network Number.</para>
-+ </enum>
-+ <enum name="prohib_not_screened">
-+ <para>Presentation Prohibited, Not Screened.</para>
-+ </enum>
-+ <enum name="prohib_passed_screen">
-+ <para>Presentation Prohibited, Passed Screen.</para>
-+ </enum>
-+ <enum name="prohib_failed_screen">
-+ <para>Presentation Prohibited, Failed Screen.</para>
-+ </enum>
-+ <enum name="prohib">
-+ <para>Presentation Prohibited, Network Number.</para>
-+ </enum>
-+ <enum name="unavailable">
-+ <para>Number Unavailable.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Set Caller*ID presentation on a call.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="MP3Player" language="en_US">
-+ <synopsis>
-+ Play an MP3 file or stream.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Location" required="true">
-+ <para>Location of the file to be played.
-+ (argument passed to mpg123)</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ </application>
-+
-+ ***/
- 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
-+ <application name="Zapateller" language="en_US">
-+ <synopsis>
-+ Block telemarketers with SIT.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="options" required="true">
-+ <para>Comma delimited list of options.</para>
-+ <optionlist>
-+ <option name="answer">
-+ <para>Causes the line to be answered before playing the tone.</para>
-+ </option>
-+ <option name="nocallerid">
-+ <para>Causes Zapateller to only play the tone if there is no
-+ callerid information available.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Generates special information tone to block telemarketers from calling you.</para>
-+ <para>This application will set the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="ZAPATELLERSTATUS">
-+ <para>This will contain the last action accomplished by the
-+ Zapateller application. Possible values include:</para>
-+ <value name="NOTHING" />
-+ <value name="ANSWERED" />
-+ <value name="ZAPPED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="SendDTMF" language="en_US">
-+ <synopsis>
-+ Sends arbitrary DTMF digits
-+ </synopsis>
-+ <syntax>
-+ <parameter name="digits" required="true">
-+ <para>List of digits 0-9,*#,abcd</para>
-+ </parameter>
-+ <parameter name="timeout_ms" required="false">
-+ <para>Amount of time to wait in ms between tones. (defaults to .25s)</para>
-+ </parameter>
-+ <parameter name="duration_ms" required="false">
-+ <para>Duration of each digit</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>DTMF digits sent to a channel with half second pause</para>
-+ <para>It will pass all digits or terminate if it encounters an error.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Read</ref>
-+ </see-also>
-+ </application>
-+ ***/
- 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 <signal.h>
- #include <stdio.h>
-+#include <stdint.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
-@@ -359,6 +360,8 @@
- #include "asterisk/cdr.h"
- #include "asterisk/options.h"
- #include "asterisk/manager.h"
-+#include "asterisk/app.h"
-+
- #include <termios.h>
-
- #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
-+ <application name="MixMonitor" language="en_US">
-+ <synopsis>
-+ Record a call and mix the audio during the recording.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="file" required="true" argsep=".">
-+ <argument name="filename" required="true">
-+ <para>If <replaceable>filename</replaceable> is an absolute path, uses that path, otherwise
-+ creates the file in the configured monitoring directory from <filename>asterisk.conf.</filename></para>
-+ </argument>
-+ <argument name="extension" required="true" />
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Append to the file instead of overwriting it.</para>
-+ </option>
-+ <option name="b">
-+ <para>Only save audio to the file while the channel is bridged.</para>
-+ <note><para>Does not include conferences or sounds played to each bridged party</para></note>
-+ </option>
-+ <option name="v">
-+ <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
-+ (range <literal>-4</literal> to <literal>4</literal>)</para>
-+ <argument name="x" required="true" />
-+ </option>
-+ <option name="V">
-+ <para>Adjust the <emphasis>spoken</emphasis> volume by a factor
-+ of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
-+ <argument name="x" required="true" />
-+ </option>
-+ <option name="W">
-+ <para>Adjust both, <emphasis>heard and spoken</emphasis> volumes by a factor
-+ of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
-+ <argument name="x" required="true" />
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="command">
-+ <para>Will be executed when the recording is over.</para>
-+ <para>Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.</para>
-+ <para>All variables will be evaluated at the time MixMonitor is called.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Records the audio on the current channel to the specified file.</para>
-+ <variablelist>
-+ <variable name="MIXMONITOR_FILENAME">
-+ <para>Will contain the filename used to record.</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">Monitor</ref>
-+ <ref type="application">StopMixMonitor</ref>
-+ <ref type="application">PauseMonitor</ref>
-+ <ref type="application">UnpauseMonitor</ref>
-+ </see-also>
-+ </application>
-+ <application name="StopMixMonitor" language="en_US">
-+ <synopsis>
-+ Stop recording a call through MixMonitor.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal>
-+ on the current channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">MixMonitor</ref>
-+ </see-also>
-+ </application>
-+
-+ ***/
-+
- #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(<file>.<ext>[,<options>[,<command>]]):\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(<x>) - Adjust the heard volume by a factor of <x> (range -4 to 4)\n"
--" V(<x>) - Adjust the spoken volume by a factor of <x> (range -4 to 4)\n"
--" W(<x>) - Adjust the both heard and spoken volumes by a factor of <x>\n"
--" (range -4 to 4)\n\n"
--"<command> 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} {<chan_name>} [args]";
- e->usage =
- "Usage: mixmonitor <start|stop> <chan_name> [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
-+ <application name="IVRDemo" language="en_US">
-+ <synopsis>
-+ IVR Demo Application.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This is a skeleton application that shows you the basic structure to create your
-+ own asterisk applications and demonstrates the IVR demo.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-- <depend>res_indications</depend>
-- ***/
--
- #include "asterisk.h"
-
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-@@ -37,17 +33,30 @@
- #include "asterisk/channel.h"
- #include "asterisk/pbx.h"
-
-+/*** DOCUMENTATION
-+ <application name="Milliwatt" language="en_US">
-+ <synopsis>
-+ Generate a Constant 1004Hz tone at 0dbm (mu-law).
-+ </synopsis>
-+ <syntax>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="o">
-+ <para>Generate the tone at 1000Hz like previous version.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Previous versions of this application generated the tone at 1000Hz. If for
-+ some reason you would prefer that behavior, supply the <literal>o</literal> option to get the
-+ old behavior.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="ParkAndAnnounce" language="en_US">
-+ <synopsis>
-+ Park and Announce.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="announce_template" required="true" argsep=":">
-+ <argument name="announce" required="true">
-+ <para>Colon-separated list of files to announce. The word
-+ <literal>PARKED</literal> will be replaced by a say_digits of the extension in which
-+ the call is parked.</para>
-+ </argument>
-+ <argument name="announce1" multiple="true" />
-+ </parameter>
-+ <parameter name="timeout" required="true">
-+ <para>Time in seconds before the call returns into the return
-+ context.</para>
-+ </parameter>
-+ <parameter name="dial" required="true">
-+ <para>The app_dial style resource to call to make the
-+ announcement. Console/dsp calls the console.</para>
-+ </parameter>
-+ <parameter name="return_context">
-+ <para>The goto-style label to jump the call back into after
-+ timeout. Default <literal>priority+1</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Park a call into the parkinglot and announce the call to another channel.</para>
-+ <para>The variable <variable>PARKEDAT</variable> 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.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Park</ref>
-+ <ref type="application">ParkedCall</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- 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 <priority+1>.\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
-+ <application name="ReadFile" language="en_US">
-+ <synopsis>
-+ Read the contents of a text file into a channel variable.
-+ </synopsis>
-+ <syntax argsep="=">
-+ <parameter name="varname" required="true">
-+ <para>Result stored here.</para>
-+ </parameter>
-+ <parameter name="fileparams" required="true">
-+ <argument name="file" required="true">
-+ <para>The name of the file to read.</para>
-+ </argument>
-+ <argument name="length" required="false">
-+ <para>Maximum number of characters to capture.</para>
-+ <para>If not specified defaults to max.</para>
-+ </argument>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Read the contents of a text file into channel variable <replaceable>varname</replaceable></para>
-+ <warning><para>ReadFile has been deprecated in favor of Set(varname=${FILE(file,0,length)})</para></warning>
-+ </description>
-+ <see-also>
-+ <ref type="application">System</ref>
-+ <ref type="application">Read</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="MeetMe" language="en_US">
-+ <synopsis>
-+ MeetMe conference bridge.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="confno">
-+ <para>The conference number</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Set admin mode.</para>
-+ </option>
-+ <option name="A">
-+ <para>Set marked mode.</para>
-+ </option>
-+ <option name="b">
-+ <para>Run AGI script specified in <variable>MEETME_AGI_BACKGROUND</variable>
-+ Default: <literal>conf-background.agi</literal>.</para>
-+ <note><para>This does not work with non-DAHDI channels in the same
-+ conference).</para></note>
-+ </option>
-+ <option name="c">
-+ <para>Announce user(s) count on joining a conference.</para>
-+ </option>
-+ <option name="C">
-+ <para>Continue in dialplan when kicked out of conference.</para>
-+ </option>
-+ <option name="d">
-+ <para>Dynamically add conference.</para>
-+ </option>
-+ <option name="D">
-+ <para>Dynamically add conference, prompting for a PIN.</para>
-+ </option>
-+ <option name="e">
-+ <para>Select an empty conference.</para>
-+ </option>
-+ <option name="E">
-+ <para>Select an empty pinless conference.</para>
-+ </option>
-+ <option name="F">
-+ <para>Pass DTMF through the conference.</para>
-+ </option>
-+ <option name="i">
-+ <para>Announce user join/leave with review.</para>
-+ </option>
-+ <option name="I">
-+ <para>Announce user join/leave without review.</para>
-+ </option>
-+ <option name="l">
-+ <para>Set listen only mode (Listen only, no talking).</para>
-+ </option>
-+ <option name="m">
-+ <para>Set initially muted.</para>
-+ </option>
-+ <option name="M" hasparams="optional">
-+ <para>Enable music on hold when the conference has a single caller. Optionally,
-+ specify a musiconhold class to use. If one is not provided, it will use the
-+ channel's currently set music class, or <literal>default</literal>.</para>
-+ <argument name="class" required="true" />
-+ </option>
-+ <option name="o">
-+ <para>Set talker optimization - treats talkers who aren't speaking as
-+ being muted, meaning (a) No encode is done on transmission and (b)
-+ Received audio that is not registered as talking is omitted causing no
-+ buildup in background noise.</para>
-+ </option>
-+ <option name="p" hasparams="optional">
-+ <para>Allow user to exit the conference by pressing <literal>#</literal> (default)
-+ or any of the defined keys. If keys contain <literal>*</literal> this will override
-+ option <literal>s</literal>. The key used is set to channel variable
-+ <variable>MEETME_EXIT_KEY</variable>.</para>
-+ <argument name="keys" required="true" />
-+ </option>
-+ <option name="P">
-+ <para>Always prompt for the pin even if it is specified.</para>
-+ </option>
-+ <option name="q">
-+ <para>Quiet mode (don't play enter/leave sounds).</para>
-+ </option>
-+ <option name="r">
-+ <para>Record conference (records as <variable>MEETME_RECORDINGFILE</variable>
-+ using format <variable>MEETME_RECORDINGFORMAT</variable>. Default filename is
-+ <literal>meetme-conf-rec-${CONFNO}-${UNIQUEID}</literal> and the default format is
-+ wav.</para>
-+ </option>
-+ <option name="s">
-+ <para>Present menu (user or admin) when <literal>*</literal> is received
-+ (send to menu).</para>
-+ </option>
-+ <option name="t">
-+ <para>Set talk only mode. (Talk only, no listening).</para>
-+ </option>
-+ <option name="T">
-+ <para>Set talker detection (sent to manager interface and meetme list).</para>
-+ </option>
-+ <option name="W" hasparams="optional">
-+ <para>Wait until the marked user enters the conference.</para>
-+ <argument name="secs" required="true" />
-+ </option>
-+ <option name="x">
-+ <para>Close the conference when last marked user exits</para>
-+ </option>
-+ <option name="X">
-+ <para>Allow user to exit the conference by entering a valid single digit
-+ extension <variable>MEETME_EXIT_CONTEXT</variable> or the current context
-+ if that variable is not defined.</para>
-+ </option>
-+ <option name="1">
-+ <para>Do not play message when first person enters</para>
-+ </option>
-+ <option name="S">
-+ <para>Kick the user <replaceable>x</replaceable> seconds <emphasis>after</emphasis> he entered into
-+ the conference.</para>
-+ <argument name="x" required="true" />
-+ </option>
-+ <option name="L" argsep=":">
-+ <para>Limit the conference to <replaceable>x</replaceable> ms. Play a warning when
-+ <replaceable>y</replaceable> ms are left. Repeat the warning every <replaceable>z</replaceable> ms.
-+ The following special variables can be used with this option:</para>
-+ <variablelist>
-+ <variable name="CONF_LIMIT_TIMEOUT_FILE">
-+ <para>File to play when time is up.</para>
-+ </variable>
-+ <variable name="CONF_LIMIT_WARNING_FILE">
-+ <para>File to play as warning if <replaceable>y</replaceable> is defined. The
-+ default is to say the time remaining.</para>
-+ </variable>
-+ </variablelist>
-+ <argument name="x" />
-+ <argument name="y" />
-+ <argument name="z" />
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="pin" />
-+ </syntax>
-+ <description>
-+ <para>Enters the user into a specified MeetMe conference. If the <replaceable>confno</replaceable>
-+ is omitted, the user will be prompted to enter one. User can exit the conference by hangup, or
-+ if the <literal>p</literal> option is specified, by pressing <literal>#</literal>.</para>
-+ <note><para>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 <literal>i</literal> and <literal>r</literal> options to operate at
-+ all.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="application">MeetMeCount</ref>
-+ <ref type="application">MeetMeAdmin</ref>
-+ <ref type="application">MeetMeChannelAdmin</ref>
-+ </see-also>
-+ </application>
-+ <application name="MeetMeCount" language="en_US">
-+ <synopsis>
-+ MeetMe participant count.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="confno" required="true">
-+ <para>Conference number.</para>
-+ </parameter>
-+ <parameter name="var" />
-+ </syntax>
-+ <description>
-+ <para>Plays back the number of users in the specified MeetMe conference.
-+ If <replaceable>var</replaceable> 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 <literal>n+1</literal> exists, in which case priority progress will
-+ continue.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">MeetMe</ref>
-+ </see-also>
-+ </application>
-+ <application name="MeetMeAdmin" language="en_US">
-+ <synopsis>
-+ MeetMe conference administration.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="confno" required="true" />
-+ <parameter name="command" required="true">
-+ <optionlist>
-+ <option name="e">
-+ <para>Eject last user that joined.</para>
-+ </option>
-+ <option name="E">
-+ <para>Extend conference end time, if scheduled.</para>
-+ </option>
-+ <option name="k">
-+ <para>Kick one user out of conference.</para>
-+ </option>
-+ <option name="K">
-+ <para>Kick all users out of conference.</para>
-+ </option>
-+ <option name="l">
-+ <para>Unlock conference.</para>
-+ </option>
-+ <option name="L">
-+ <para>Lock conference.</para>
-+ </option>
-+ <option name="m">
-+ <para>Unmute one user.</para>
-+ </option>
-+ <option name="M">
-+ <para>Mute one user.</para>
-+ </option>
-+ <option name="n">
-+ <para>Unmute all users in the conference.</para>
-+ </option>
-+ <option name="N">
-+ <para>Mute all non-admin users in the conference.</para>
-+ </option>
-+ <option name="r">
-+ <para>Reset one user's volume settings.</para>
-+ </option>
-+ <option name="R">
-+ <para>Reset all users volume settings.</para>
-+ </option>
-+ <option name="s">
-+ <para>Lower entire conference speaking volume.</para>
-+ </option>
-+ <option name="S">
-+ <para>Raise entire conference speaking volume.</para>
-+ </option>
-+ <option name="t">
-+ <para>Lower one user's talk volume.</para>
-+ </option>
-+ <option name="T">
-+ <para>Raise one user's talk volume.</para>
-+ </option>
-+ <option name="u">
-+ <para>Lower one user's listen volume.</para>
-+ </option>
-+ <option name="U">
-+ <para>Raise one user's listen volume.</para>
-+ </option>
-+ <option name="v">
-+ <para>Lower entire conference listening volume.</para>
-+ </option>
-+ <option name="V">
-+ <para>Raise entire conference listening volume.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="user" />
-+ </syntax>
-+ <description>
-+ <para>Run admin <replaceable>command</replaceable> for conference <replaceable>confno</replaceable>.</para>
-+ <para>Will additionally set the variable <variable>MEETMEADMINSTATUS</variable> with one of
-+ the following values:</para>
-+ <variablelist>
-+ <variable name="MEETMEADMINSTATUS">
-+ <value name="NOPARSE">
-+ Invalid arguments.
-+ </value>
-+ <value name="NOTFOUND">
-+ User specified was not found.
-+ </value>
-+ <value name="FAILED">
-+ Another failure occurred.
-+ </value>
-+ <value name="OK">
-+ The operation was completed successfully.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">MeetMe</ref>
-+ </see-also>
-+ </application>
-+ <application name="MeetMeChannelAdmin" language="en_US">
-+ <synopsis>
-+ MeetMe conference Administration (channel specific).
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channel" required="true" />
-+ <parameter name="command" required="true">
-+ <optionlist>
-+ <option name="k">
-+ <para>Kick the specified user out of the conference he is in.</para>
-+ </option>
-+ <option name="m">
-+ <para>Unmute the specified user.</para>
-+ </option>
-+ <option name="M">
-+ <para>Mute the specified user.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Run admin <replaceable>command</replaceable> for a specific
-+ <replaceable>channel</replaceable> in any coference.</para>
-+ </description>
-+ </application>
-+ <application name="SLAStation" language="en_US">
-+ <synopsis>
-+ Shared Line Appearance Station.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="station" required="true">
-+ <para>Station name</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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
-+ <replaceable>station</replaceable> 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.</para>
-+ <para>For example: <literal>station1_line1</literal></para>
-+ <para>On exit, this application will set the variable <variable>SLASTATION_STATUS</variable> to
-+ one of the following values:</para>
-+ <variablelist>
-+ <variable name="SLASTATION_STATUS">
-+ <value name="FAILURE" />
-+ <value name="CONGESTION" />
-+ <value name="SUCCESS" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="SLATrunk" language="en_US">
-+ <synopsis>
-+ Shared Line Appearance Trunk.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="trunk" required="true">
-+ <para>Trunk name</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="M" hasparams="optional">
-+ <para>Play back the specified MOH <replaceable>class</replaceable>
-+ instead of ringing</para>
-+ <argument name="class" required="true" />
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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 <replaceable>trunk</replaceable>
-+ that is being passed as an argument.</para>
-+ <para>On exit, this application will set the variable <variable>SLATRUNK_STATUS</variable> to
-+ one of the following values:</para>
-+ <variablelist>
-+ <variable name="SLATRUNK_STATUS">
-+ <value name="FAILURE" />
-+ <value name="SUCCESS" />
-+ <value name="UNANSWERED" />
-+ <value name="RINGTIMEOUT" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
-+
- #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[(<class>)]'\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[(<keys>)]'\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[(<secs>)]'\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(<station name>):\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(<trunk name>[,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[(<class>)] - 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] <confno> <usernumber>\n"
-- " Executes a command for the conference or on a conferee\n";
-+ "Usage: meetme list [concise] <confno> \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 <confno> <usernumber>\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/<testid>-server.txt";
-+/*** DOCUMENTATION
-+ <application name="TestServer" language="en_US">
-+ <synopsis>
-+ Execute Interface Test Server.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Perform test server function and write call report. Results stored in
-+ <filename>/var/log/asterisk/testreports/&lt;testid&gt;-server.txt</filename></para>
-+ </description>
-+ <see-also>
-+ <ref type="application">TestClient</ref>
-+ </see-also>
-+ </application>
-+ <application name="TestClient" language="en_US">
-+ <synopsis>
-+ Execute Interface Test Client.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="testid" required="true">
-+ <para>An ID to identify this test.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Executes test client with given <replaceable>testid</replaceable>. Results stored in
-+ <filename>/var/log/asterisk/testreports/&lt;testid&gt;-client.txt</filename></para>
-+ </description>
-+ <see-also>
-+ <ref type="application">TestServer</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- 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/<testid>-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
-+ <application name="Morsecode" language="en_US">
-+ <synopsis>
-+ Plays morse code.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true">
-+ <para>String to playback as morse code to channel</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Plays the Morse code equivalent of the passed string.</para>
-+
-+ <para>This application uses the following variables:</para>
-+ <variablelist>
-+ <variable name="MORSEDITLEN">
-+ <para>Use this value in (ms) for length of dit</para>
-+ </variable>
-+ <variable name="MORSETONE">
-+ <para>The pitch of the tone in (Hz), default is 800</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">SayAlpha</ref>
-+ <ref type="application">SayPhonetic</ref>
-+ </see-also>
-+ </application>
-+ ***/
- static char *app_morsecode = "Morsecode";
-
--static char *morsecode_synopsis = "Plays morse code";
--
--static char *morsecode_descrip =
--" Morsecode(<string>):\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
-+ <application name="ICES" language="en_US">
-+ <synopsis>
-+ Encode and stream using 'ices'.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="config" required="true">
-+ <para>ICES configuration file.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Streams to an icecast server using ices (available separately).
-+ A configuration file must be supplied for ices (see contrib/asterisk-ices.xml).</para>
-+ <note><para>ICES version 2 cient and server required.</para></note>
-+ </description>
-+ </application>
-+
-+ ***/
-+
- #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
-+ <application name="Exec" language="en_US">
-+ <synopsis>
-+ Executes dialplan application.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="appname" required="true" hasparams="true">
-+ <para>Application name and arguments of the dialplan application to execute.</para>
-+ <argument name="arguments" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>To invoke external applications, see the application System.
-+ If you would like to catch any error instead, see TryExec.</para>
-+ </description>
-+ </application>
-+ <application name="TryExec" language="en_US">
-+ <synopsis>
-+ Executes dialplan application, always returning.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="appname" required="true" hasparams="true">
-+ <argument name="arguments" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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:
-+ </para>
-+ <variablelist>
-+ <variable name="TRYSTATUS">
-+ <value name="SUCCESS">
-+ If the application returned zero.
-+ </value>
-+ <value name="FAILED">
-+ If the application returned non-zero.
-+ </value>
-+ <value name="NOAPP">
-+ If the application was not found or was not specified.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="ExecIf" language="en_US">
-+ <synopsis>
-+ Executes dialplan application, conditionally.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="expression" required="true" />
-+ <parameter name="execapp" required="true" argsep=":">
-+ <argument name="appiftrue" required="true" hasparams="true">
-+ <argument name="args" required="true" />
-+ </argument>
-+ <argument name="appiffalse" required="false" hasparams="true">
-+ <argument name="args" required="true" />
-+ </argument>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>If <replaceable>expr</replaceable> is true, execute and return the
-+ result of <replaceable>appiftrue(args)</replaceable>.</para>
-+ <para>If <replaceable>expr</replaceable> is true, but <replaceable>appiftrue</replaceable> is not found,
-+ then the application will return a non-zero value.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- /* 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 (<expr>?<appiftrue>(<args>)[:<appiffalse>(<args>)])\n"
--"If <expr> is true, execute and return the result of <appiftrue>(<args>).\n"
--"If <expr> is true, but <appiftrue> 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
-+ <application name="ChannelRedirect" language="en_US">
-+ <synopsis>
-+ Redirects given channel to a dialplan target
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channel" required="true" />
-+ <parameter name="context" required="false" />
-+ <parameter name="extension" required="false" />
-+ <parameter name="priority" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Sends the specified channel to the specified extension priority</para>
-+
-+ <para>This application sets the following channel variables upon completion</para>
-+ <variablelist>
-+ <variable name="CHANNELREDIRECT_STATUS">
-+ <value name="NOCHANNEL" />
-+ <value name="SUCCESS" />
-+ <para>Are set to the result of the redirection</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
- 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
-+ <application name="ForkCDR" language="en_US">
-+ <synopsis>
-+ Forks the Call Data Record.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Update the answer time on the NEW CDR just after it's been inited.
-+ The new CDR may have been answered already, the reset that forkcdr does
-+ will erase the answer time. This will bring it back, but the answer time
-+ will be a copy of the fork/start time. It will only do this if the initial
-+ cdr was indeed already answered.</para>
-+ </option>
-+ <option name="A">
-+ <para>Lock the original CDR against the answer time being updated. This
-+ will allow the disposition on the original CDR to remain the same.</para>
-+ </option>
-+ <option name="d">
-+ <para>Copy the disposition forward from the old cdr, after the init.</para>
-+ </option>
-+ <option name="D">
-+ <para>Clear the <literal>dstchannel</literal> on the new CDR after
-+ reset.</para>
-+ </option>
-+ <option name="e">
-+ <para>End the original CDR. Do this after all the necc. data.</para>
-+ </option>
-+ <option name="r">
-+ <para>Do <emphasis>NOT</emphasis> reset the new cdr.</para>
-+ </option>
-+ <option name="s(name=val)">
-+ <para>Set the CDR var <replaceable>name</replaceable> in the original CDR,
-+ with value <replaceable>val</replaceable>.</para>
-+ </option>
-+ <option name="T">
-+ <para>Mark the original CDR with a DONT_TOUCH flag. setvar, answer, and end
-+ cdr funcs will obey this flag; normally they don't honor the LOCKED flag
-+ set on the original CDR record.</para>
-+ <note><para>Using this flag may cause CDR's not to have their end times
-+ updated! It is suggested that if you specify this flag, you might wish
-+ to use the <literal>e</literal> flag as well!.</para></note>
-+ </option>
-+ <option name="v">
-+ <para>When the new CDR is forked, it gets a copy of the vars attached to
-+ the current CDR. The vars attached to the original CDR are removed unless
-+ this option is specified.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para> 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.</para>
-+ <para>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.</para>
-+ <para>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)</para>
-+ <para>This means that:</para>
-+ <para> 1. All flags are unset on the cdr record</para>
-+ <para> 2. the start, end, and answer times are all set to zero.</para>
-+ <para> 3. the billsec and duration fields are set to zero.</para>
-+ <para> 4. the start time is set to the current time.</para>
-+ <para> 5. the disposition is set to NULL.</para>
-+ <para>Next, unless you specified the <literal>v</literal> option, all variables will be removed from
-+ the original cdr record. Thus, the <literal>v</literal> option allows any CDR variables to be replicated
-+ to all new forked cdr records. Without the <literal>v</literal> option, the variables on the original
-+ are effectively moved to the new forked cdr record.</para>
-+ <para>Next, if the <literal>s</literal> option is set, the provided variable and value are set on the
-+ original cdr record.</para>
-+ <para>Next, if the <literal>a</literal> 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.</para>
-+ <para>If the <literal>d</literal> option was specified, the disposition is copied from
-+ the original cdr record to the new forked cdr. If the <literal>D</literal> option was specified,
-+ the destination channel field in the new forked CDR is erased. If the <literal>e</literal> 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 <literal>A</literal> 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 <literal>ANSWERED</literal> event would mark all cdr
-+ records in the chain as <literal>ANSWERED</literal>. If the <literal>T</literal> option is specified,
-+ the original cdr record will have its <literal>DONT_TOUCH</literal> flag set, which will force the
-+ cdr_answer, cdr_end, and cdr_setvar functions to leave that cdr record alone.</para>
-+ <para>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.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">CDR</ref>
-+ <ref type="application">NoCDR</ref>
-+ <ref type="application">ResetCDR</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="Skel" language="en_US">
-+ <synopsis>
-+ Simple one line explaination.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="dummy" required="true"/>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Option A.</para>
-+ </option>
-+ <option name="b">
-+ <para>Option B.</para>
-+ </option>
-+ <option name="c">
-+ <para>Option C.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is a template to build other applications from.
-+ It shows you the basic structure to create your own Asterisk applications.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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] : "<unspecified>");
-+ }
-
-- 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] : "<unspecified>");
-+ }
-
- 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
-+ <application name="Pickup" language="en_US">
-+ <synopsis>
-+ Directed extension call pickup.
-+ </synopsis>
-+ <syntax argsep="&amp;">
-+ <parameter name="ext" argsep="@" required="true">
-+ <argument name="extension" required="true"/>
-+ <argument name="context" />
-+ </parameter>
-+ <parameter name="ext2" argsep="@" multiple="true">
-+ <argument name="extension2" required="true"/>
-+ <argument name="context2"/>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application can pickup any ringing channel that is calling
-+ the specified <replaceable>extension</replaceable>. If no <replaceable>context</replaceable>
-+ is specified, the current context will be used. If you use the special string <literal>PICKUPMARK</literal>
-+ for the context parameter, for example 10@PICKUPMARK, this application
-+ tries to find a channel which has defined a <variable>PICKUPMARK</variable>
-+ channel variable with the same value as <replaceable>extension</replaceable>
-+ (in this example, <literal>10</literal>). When no parameter is specified, the application
-+ will pickup a channel matching the pickup group of the active channel.</para>
-+ </description>
-+ </application>
-+ <application name="PickupChan" language="en_US">
-+ <synopsis>
-+ Pickup a ringing channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channel" required="true" />
-+ <parameter name="channel2" multiple="true" />
-+ </syntax>
-+ <description>
-+ <para>This will pickup a specified <replaceable>channel</replaceable> if ringing.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-+<application name="MinivmRecord" language="en_US">
-+ <synopsis>
-+ Receive Mini-Voicemail and forward via e-mail.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="username" required="true">
-+ <para>Voicemail username</para>
-+ </argument>
-+ <argument name="domain" required="true">
-+ <para>Voicemail domain</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="0">
-+ <para>Jump to the <literal>o</literal> extension in the current dialplan context.</para>
-+ </option>
-+ <option name="*">
-+ <para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
-+ </option>
-+ <option name="g">
-+ <argument name="gain">
-+ <para>Amount of gain to use</para>
-+ </argument>
-+ <para>Use the specified amount of gain when recording the voicemail message.
-+ The units are whole-number decibels (dB).</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is part of the Mini-Voicemail system, configured in <filename>minivm.conf</filename></para>
-+ <para>MiniVM records audio file in configured format and forwards message to e-mail and pager.</para>
-+ <para>If there's no user account for that address, a temporary account will be used with default options.</para>
-+ <para>The recorded file name and path will be stored in <variable>MVM_FILENAME</variable> and the duration
-+ of the message will be stored in <variable>MVM_DURATION</variable></para>
-+ <note><para>If the caller hangs up after the recording, the only way to send the message and clean up is to
-+ execute in the <literal>h</literal> extension. The application will exit if any of the following DTMF digits
-+ are received and the requested extension exist in the current context.</para></note>
-+ <variablelist>
-+ <variable name="MVM_RECORD_STATUS">
-+ <para>This is the status of the record operation</para>
-+ <value name="SUCCESS" />
-+ <value name="USEREXIT" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+</application>
-+<application name="MinivmGreet" language="en_US">
-+ <synopsis>
-+ Play Mini-Voicemail prompts.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="username" required="true">
-+ <para>Voicemail username</para>
-+ </argument>
-+ <argument name="domain" required="true">
-+ <para>Voicemail domain</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="b">
-+ <para>Play the <literal>busy</literal> greeting to the calling party.</para>
-+ </option>
-+ <option name="s">
-+ <para>Skip the playback of instructions for leaving a message to the calling party.</para>
-+ </option>
-+ <option name="u">
-+ <para>Play the <literal>unavailable</literal> greeting.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is part of the Mini-Voicemail system, configured in minivm.conf.</para>
-+ <para>MinivmGreet() plays default prompts or user specific prompts for an account.</para>
-+ <para>Busy and unavailable messages can be choosen, but will be overridden if a temporary
-+ message exists for the account.</para>
-+ <variablelist>
-+ <variable name="MVM_GREET_STATUS">
-+ <para>This is the status of the greeting playback.</para>
-+ <value name="SUCCESS" />
-+ <value name="USEREXIT" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+</application>
-+<application name="MinivmNotify" language="en_US">
-+ <synopsis>
-+ Notify voicemail owner about new messages.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="username" required="true">
-+ <para>Voicemail username</para>
-+ </argument>
-+ <argument name="domain" required="true">
-+ <para>Voicemail domain</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="template">
-+ <para>E-mail template to use for voicemail notification</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is part of the Mini-Voicemail system, configured in minivm.conf.</para>
-+ <para>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
-+ <filename>minivm.conf</filename>).</para>
-+ <para>If the channel variable <variable>MVM_COUNTER</variable> is set, this will be used in the message
-+ file name and available in the template for the message.</para>
-+ <para>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.</para>
-+ <variablelist>
-+ <variable name="MVM_NOTIFY_STATUS">
-+ <para>This is the status of the notification attempt</para>
-+ <value name="SUCCESS" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+</application>
-+<application name="MinivmDelete" language="en_US">
-+ <synopsis>
-+ Delete Mini-Voicemail voicemail messages.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true">
-+ <para>File to delete</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is part of the Mini-Voicemail system, configured in <filename>minivm.conf</filename>.</para>
-+ <para>It deletes voicemail file set in MVM_FILENAME or given filename.</para>
-+ <variablelist>
-+ <variable name="MVM_DELETE_STATUS">
-+ <para>This is the status of the delete operation.</para>
-+ <value name="SUCCESS" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+</application>
-+
-+<application name="MinivmAccMess" language="en_US">
-+ <synopsis>
-+ Record account specific messages.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="username" required="true">
-+ <para>Voicemail username</para>
-+ </argument>
-+ <argument name="domain" required="true">
-+ <para>Voicemail domain</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="u">
-+ <para>Record the <literal>unavailable</literal> greeting.</para>
-+ </option>
-+ <option name="b">
-+ <para>Record the <literal>busy</literal> greeting.</para>
-+ </option>
-+ <option name="t">
-+ <para>Record the temporary greeting.</para>
-+ </option>
-+ <option name="n">
-+ <para>Account name.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is part of the Mini-Voicemail system, configured in <filename>minivm.conf</filename>.</para>
-+ <para>Use this application to record account specific audio/video messages for busy, unavailable
-+ and temporary messages.</para>
-+ <para>Account specific directories will be created if they do not exist.</para>
-+ <variablelist>
-+ <variable name="MVM_ACCMESS_STATUS">
-+ <para>This is the result of the attempt to record the specified greeting.</para>
-+ <para><literal>FAILED</literal> is set if the file can't be created.</para>
-+ <value name="SUCCESS" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+</application>
-+<application name="MinivmMWI" language="en_US">
-+ <synopsis>
-+ Send Message Waiting Notification to subscriber(s) of mailbox.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="username" required="true">
-+ <para>Voicemail username</para>
-+ </argument>
-+ <argument name="domain" required="true">
-+ <para>Voicemail domain</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="urgent" required="true">
-+ <para>Number of urgent messages in mailbox.</para>
-+ </parameter>
-+ <parameter name="new" required="true">
-+ <para>Number of new messages in mailbox.</para>
-+ </parameter>
-+ <parameter name="old" required="true">
-+ <para>Number of old messages in mailbox.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is part of the Mini-Voicemail system, configured in <filename>minivm.conf</filename>.</para>
-+ <para>MinivmMWI is used to send message waiting indication to any devices whose channels have
-+ subscribed to the mailbox passed in the first parameter.</para>
-+ </description>
-+</application>
-+***/
-+
- #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
-+ <application name="DumpChan" language="en_US">
-+ <synopsis>
-+ Dump Info About The Calling Channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="level">
-+ <para>Minimun verbose level</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Displays information on channel and listing of all channel
-+ variables. If <replaceable>level</replaceable> is specified, output is only
-+ displayed when the verbose level is currently set to that number
-+ or greater.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">NoOp</ref>
-+ <ref type="application">Verbose</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- static char *app = "DumpChan";
--static char *synopsis = "Dump Info About The Calling Channel";
--static char *desc =
-- " DumpChan([<min_verbose_level>])\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
-+ <application name="Macro" language="en_US">
-+ <synopsis>
-+ Macro Implementation.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="name" required="true">
-+ <para>The name of the macro</para>
-+ </parameter>
-+ <parameter name="args">
-+ <argument name="arg1" required="true" />
-+ <argument name="arg2" multiple="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Executes a macro using the context macro-<replaceable>name</replaceable>,
-+ jumping to the <literal>s</literal> extension of that context and executing each step,
-+ then returning when the steps end.</para>
-+ <para>The calling extension, context, and priority are stored in <variable>MACRO_EXTEN</variable>,
-+ <variable>MACRO_CONTEXT</variable> and <variable>MACRO_PRIORITY</variable> respectively. Arguments
-+ become <variable>ARG1</variable>, <variable>ARG2</variable>, etc in the macro context.</para>
-+ <para>If you Goto out of the Macro context, the Macro will terminate and control will be returned
-+ at the location of the Goto.</para>
-+ <para>If <variable>MACRO_OFFSET</variable> is set at termination, Macro will attempt to continue
-+ at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.</para>
-+ <para>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 <literal>h</literal> 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)</para>
-+ <warning><para>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.</para></warning>
-+ </description>
-+ <see-also>
-+ <ref type="application">MacroExit</ref>
-+ <ref type="application">Goto</ref>
-+ <ref type="application">Gosub</ref>
-+ </see-also>
-+ </application>
-+ <application name="MacroIf" language="en_US">
-+ <synopsis>
-+ Conditional Macro implementation.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="expr" required="true" />
-+ <parameter name="destination" required="true" argsep=":">
-+ <argument name="macroiftrue" required="true">
-+ <argument name="macroiftrue" required="true" />
-+ <argument name="arg1" multiple="true" />
-+ </argument>
-+ <argument name="macroiffalse">
-+ <argument name="macroiffalse" required="true" />
-+ <argument name="arg1" multiple="true" />
-+ </argument>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Executes macro defined in <replaceable>macroiftrue</replaceable> if
-+ <replaceable>expr</replaceable> is true (otherwise <replaceable>macroiffalse</replaceable>
-+ if provided)</para>
-+ <para>Arguments and return values as in application Macro()</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">GotoIf</ref>
-+ <ref type="application">GosubIf</ref>
-+ <ref type="function">IF</ref>
-+ </see-also>
-+ </application>
-+ <application name="MacroExclusive" language="en_US">
-+ <synopsis>
-+ Exclusive Macro Implementation.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="name" required="true">
-+ <para>The name of the macro</para>
-+ </parameter>
-+ <parameter name="arg1" />
-+ <parameter name="arg2" multiple="true" />
-+ </syntax>
-+ <description>
-+ <para>Executes macro defined in the context macro-<replaceable>name</replaceable>.
-+ Only one call at a time may run the macro. (we'll wait if another call is busy
-+ executing in the Macro)</para>
-+ <para>Arguments and return values as in application Macro()</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Macro</ref>
-+ </see-also>
-+ </application>
-+ <application name="MacroExit" language="en_US">
-+ <synopsis>
-+ Exit from Macro.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Macro</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- #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-<macroname>', 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(<expr>?macroname_a[,arg1][:macroname_b[,arg1]])\n"
--"Executes macro defined in <macroname_a> if <expr> is true\n"
--"(otherwise <macroname_b> 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
-+ <application name="SMS" language="en_US">
-+ <synopsis>
-+ Communicates with SMS service centres and SMS capable analogue phones.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="name" required="true">
-+ <para>The name of the queue used in <filename>/var/spool/asterisk/sms</filename></para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Answer, i.e. send initial FSK packet.</para>
-+ </option>
-+ <option name="s">
-+ <para>Act as service centre talking to a phone.</para>
-+ </option>
-+ <option name="t">
-+ <para>Use protocol 2 (default used is protocol 1).</para>
-+ </option>
-+ <option name="p">
-+ <para>Set the initial delay to N ms (default is <literal>300</literal>).
-+ addr and body are a deprecated format to send messages out.</para>
-+ </option>
-+ <option name="r">
-+ <para>Set the Status Report Request (SRR) bit.</para>
-+ </option>
-+ <option name="o">
-+ <para>The body should be coded as octets not 7-bit symbols.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="addr" />
-+ <parameter name="body" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>Typical usage is to use to handle calls from the SMS service centre CLI, or to set up a call using
-+ <literal>outgoing</literal> or manager interface to connect service centre to SMS().</para>
-+ <para>"Messages are processed as per text file message queues. smsq (a separate software) is a command to
-+ generate message queues and send messages.</para>
-+ <note><para>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.</para></note>
-+ </description>
-+ </application>
-+ ***/
-+
- /* #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([<level>,]<message>)\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(<level>,<message>)\n"
--" level must be one of ERROR, WARNING, NOTICE, DEBUG, VERBOSE, DTMF\n";
-
-+/*** DOCUMENTATION
-+ <application name="Verbose" language="en_US">
-+ <synopsis>
-+ Send arbitrary text to verbose output.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="level">
-+ <para>Must be an integer value. If not specified, defaults to 0.</para>
-+ </parameter>
-+ <parameter name="message" required="true">
-+ <para>Output text message.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Sends an arbitrary text message to verbose output.</para>
-+ </description>
-+ </application>
-+ <application name="Log" language="en_US">
-+ <synopsis>
-+ Send arbitrary text to a selected log level.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="level">
-+ <para>Level must be one of <literal>ERROR</literal>, <literal>WARNING</literal>, <literal>NOTICE</literal>,
-+ <literal>DEBUG</literal>, <literal>VERBOSE</literal> or <literal>DTMF</literal>.</para>
-+ </parameter>
-+ <parameter name="message" required="true">
-+ <para>Output text message.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Sends an arbitrary text message to a selected log level.</para>
-+ </description>
-+ </application>
-+ ***/
-
-+
- 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
- <category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" remove_on_change="apps/app_voicemail.o apps/app_voicemail.so apps/app_directory.o apps/app_directory.so">
- <member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
-- <depend>unixodbc</depend>
-+ <depend>generic_odbc</depend>
- <depend>ltdl</depend>
- <conflict>IMAP_STORAGE</conflict>
- <defaultenabled>no</defaultenabled>
-@@ -55,7 +55,7 @@
- <member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
- <depend>imap_tk</depend>
- <conflict>ODBC_STORAGE</conflict>
-- <use>ssl</use>
-+ <use>openssl</use>
- <defaultenabled>no</defaultenabled>
- </member>
- </category>
-@@ -116,6 +116,191 @@
- #endif
-
- #ifdef IMAP_STORAGE
-+#include "asterisk/threadstorage.h"
-+#endif
-+
-+/*** DOCUMENTATION
-+ <application name="VoiceMail" language="en_US">
-+ <synopsis>
-+ Leave a Voicemail message.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailboxs" argsep="&amp;" required="true">
-+ <argument name="mailbox1" argsep="@" required="true">
-+ <argument name="mailbox" required="true" />
-+ <argument name="context" />
-+ </argument>
-+ <argument name="mailbox2" argsep="@" multiple="true">
-+ <argument name="mailbox" required="true" />
-+ <argument name="context" />
-+ </argument>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="b">
-+ <para>Play the <literal>busy</literal> greeting to the calling party.</para>
-+ </option>
-+ <option name="d">
-+ <argument name="c" />
-+ <para>Accept digits for a new extension in context <replaceable>c</replaceable>,
-+ if played during the greeting. Context defaults to the current context.</para>
-+ </option>
-+ <option name="g">
-+ <argument name="#" required="true" />
-+ <para>Use the specified amount of gain when recording the voicemail
-+ message. The units are whole-number decibels (dB). Only works on supported
-+ technologies, which is DAHDI only.</para>
-+ </option>
-+ <option name="s">
-+ <para>Skip the playback of instructions for leaving a message to the
-+ calling party.</para>
-+ </option>
-+ <option name="u">
-+ <para>Play the <literal>unavailable</literal> greeting.</para>
-+ </option>
-+ <option name="U">
-+ <para>Mark message as <literal>URGENT</literal>.</para>
-+ </option>
-+ <option name="P">
-+ <para>Mark message as <literal>PRIORITY</literal>.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>The Voicemail application will exit if any of the following DTMF digits are received:</para>
-+ <enumlist>
-+ <enum name="0">
-+ <para>Jump to the <literal>o</literal> extension in the current dialplan context.</para>
-+ </enum>
-+ <enum name="*">
-+ <para>Jump to the <literal>a</literal> extension in the current dialplan context.</para>
-+ </enum>
-+ </enumlist>
-+ <para>This application will set the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="VMSTATUS">
-+ <para>This indicates the status of the execution of the VoiceMail application.</para>
-+ <value name="SUCCESS" />
-+ <value name="USEREXIT" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="VoiceMailMain" language="en_US">
-+ <synopsis>
-+ Check Voicemail messages.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="mailbox" />
-+ <argument name="context" />
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="p">
-+ <para>Consider the <replaceable>mailbox</replaceable> parameter as a prefix to
-+ the mailbox that is entered by the caller.</para>
-+ </option>
-+ <option name="g">
-+ <argument name="#" required="true" />
-+ <para>Use the specified amount of gain when recording a voicemail message.
-+ The units are whole-number decibels (dB).</para>
-+ </option>
-+ <option name="s">
-+ <para>Skip checking the passcode for the mailbox.</para>
-+ </option>
-+ <option name="a">
-+ <argument name="folder" required="true" />
-+ <para>Skip folder prompt and go directly to <replaceable>folder</replaceable> specified.
-+ Defaults to <literal>INBOX</literal>.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application allows the calling party to check voicemail messages. A specific
-+ <replaceable>mailbox</replaceable>, and optional corresponding <replaceable>context</replaceable>,
-+ may be specified. If a <replaceable>mailbox</replaceable> is not provided, the calling party will
-+ be prompted to enter one. If a <replaceable>context</replaceable> is not specified, the
-+ <literal>default</literal> context will be used.</para>
-+ </description>
-+ </application>
-+ <application name="MailboxExists" language="en_US">
-+ <synopsis>
-+ Check to see if Voicemail mailbox exists.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="mailbox" required="true" />
-+ <argument name="context" />
-+ </parameter>
-+ <parameter name="options">
-+ <para>None options.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Check to see if the specified <replaceable>mailbox</replaceable> exists. If no voicemail
-+ <replaceable>context</replaceable> is specified, the <literal>default</literal> context
-+ will be used.</para>
-+ <para>This application will set the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="VMBOXEXISTSSTATUS">
-+ <para>This will contain the status of the execution of the MailboxExists application.
-+ Possible values include:</para>
-+ <value name="SUCCESS" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="VMAuthenticate" language="en_US">
-+ <synopsis>
-+ Authenticate with Voicemail passwords.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="mailbox" required="true" argsep="@">
-+ <argument name="mailbox" />
-+ <argument name="context" />
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="s">
-+ <para>Skip playing the initial prompts.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application behaves the same way as the Authenticate application, but the passwords
-+ are taken from <filename>voicemail.conf</filename>. If the <replaceable>mailbox</replaceable> is
-+ specified, only that mailbox's password will be considered valid. If the <replaceable>mailbox</replaceable>
-+ is not specified, the channel variable <variable>AUTH_MAILBOX</variable> will be set with the authenticated
-+ mailbox.</para>
-+ </description>
-+ </application>
-+ <function name="MAILBOX_EXISTS" language="en_US">
-+ <synopsis>
-+ Tell if a mailbox is configured.
-+ </synopsis>
-+ <syntax argsep="@">
-+ <parameter name="mailbox" required="true" />
-+ <parameter name="context" />
-+ </syntax>
-+ <description>
-+ <para>Returns a boolean of whether the corresponding <replaceable>mailbox</replaceable> exists.
-+ If <replaceable>context</replaceable> is not specified, defaults to the <literal>default</literal>
-+ context.</para>
-+ </description>
-+ </function>
-+ ***/
-+
-+#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 (<mailbox>[@<context>])\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(<vmbox>[@<context>])",
- .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
-+ <application name="Dial" language="en_US">
-+ <synopsis>
-+ Attempt to connect to another device or endpoint and bridge the call.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Technology/Resource" required="true" argsep="&amp;">
-+ <argument name="Technology/Resource" required="true">
-+ <para>Specification of the device(s) to dial. These must be in the format of
-+ <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable>
-+ represents a particular channel driver, and <replaceable>Resource</replaceable>
-+ represents a resource available to that particular channel driver.</para>
-+ </argument>
-+ <argument name="Technology2/Resource2" required="false" multiple="true">
-+ <para>Optional extra devices to dial in parallel</para>
-+ <para>If you need more then one enter them as
-+ Technology2/Resource2&amp;Technology3/Resourse3&amp;.....</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="timeout" required="false">
-+ <para>Specifies the number of seconds we attempt to dial the specified devices</para>
-+ <para>If not specified, this defaults to 136 years.</para>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="A">
-+ <argument name="x" required="true">
-+ <para>The file to play to the called party</para>
-+ </argument>
-+ <para>Play an announcement to the called party, where <replaceable>x</replaceable> is the prompt to be played</para>
-+ </option>
-+ <option name="C">
-+ <para>Reset the call detail record (CDR) for this call.</para>
-+ </option>
-+ <option name="c">
-+ <para>If the Dial() application cancels this call, always set the flag to tell the channel
-+ driver that the call is answered elsewhere.</para>
-+ </option>
-+ <option name="d">
-+ <para>Allow the calling user to dial a 1 digit extension while waiting for
-+ a call to be answered. Exit to that extension if it exists in the
-+ current context, or the context defined in the <variable>EXITCONTEXT</variable> variable,
-+ if it exists.</para>
-+ </option>
-+ <option name="D" argsep=":">
-+ <argument name="called" />
-+ <argument name="calling" />
-+ <para>Send the specified DTMF strings <emphasis>after</emphasis> the called
-+ party has answered, but before the call gets bridged. The
-+ <replaceable>called</replaceable> DTMF string is sent to the called party, and the
-+ <replaceable>calling</replaceable> DTMF string is sent to the calling party. Both arguments
-+ can be used alone.</para>
-+ </option>
-+ <option name="e">
-+ <para>Execute the <literal>h</literal> extension for peer after the call ends. This
-+ operation will not be performed if the peer was parked</para>
-+ </option>
-+ <option name="f">
-+ <argument name="x" required="true">
-+ <para>The CallerID to force the outgoing channel to be set to</para>
-+ </argument>
-+ <para>Force the callerid of the <emphasis>calling</emphasis> channel to be set to <replaceable>x</replaceable></para>
-+ </option>
-+ <option name="F" argsep="^">
-+ <argument name="context" required="false" />
-+ <argument name="exten" required="false" />
-+ <argument name="priority" required="true" />
-+ <para>When the caller hangs up, transfer the called party
-+ to the specified destination and continue execution at that location.</para>
-+ </option>
-+ <option name="g">
-+ <para>Proceed with dialplan execution at the next priority in the current extension if the
-+ destination channel hangs up.</para>
-+ </option>
-+ <option name="G" argsep="^">
-+ <argument name="context" required="false" />
-+ <argument name="exten" required="false" />
-+ <argument name="priority" required="true" />
-+ <para>If the call is answered, transfer the calling party to
-+ the specified <replaceable>priority</replaceable> and the called party to the specified
-+ <replaceable>priority</replaceable> plus one.</para>
-+ <note>
-+ <para>You cannot use any additional action post answer options in conjunction with this option.</para>
-+ </note>
-+ </option>
-+ <option name="h">
-+ <para>Allow the called party to hang up by sending the <literal>*</literal> DTMF digit.</para>
-+ </option>
-+ <option name="H">
-+ <para>Allow the calling party to hang up by hitting the <literal>*</literal> DTMF digit.</para>
-+ </option>
-+ <option name="i">
-+ <para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
-+ </option>
-+ <option name="I">
-+ <para>Asterisk will ignore any connected line update requests or redirecting party update
-+ requests it may receiveon this dial attempt.</para>
-+ </option>
-+ <option name="k">
-+ <para>Allow the called party to enable parking of the call by sending
-+ the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="K">
-+ <para>Allow the calling party to enable parking of the call by sending
-+ the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="L" argsep=":">
-+ <argument name="x" required="true">
-+ <para>Maximum call time, in milliseconds</para>
-+ </argument>
-+ <argument name="y">
-+ <para>Warning time, in milliseconds</para>
-+ </argument>
-+ <argument name="z">
-+ <para>Repeat time, in milliseconds</para>
-+ </argument>
-+ <para>Limit the call to <replaceable>x</replaceable> milliseconds. Play a warning when <replaceable>y</replaceable> milliseconds are
-+ left. Repeat the warning every <replaceable>z</replaceable> milliseconds until time expires.</para>
-+ <para>This option is affected by the following variables:</para>
-+ <variablelist>
-+ <variable name="LIMIT_PLAYAUDIO_CALLER">
-+ <value name="yes" default="true" />
-+ <value name="no" />
-+ <para>If set, this variable causes Asterisk to play the prompts to the caller.</para>
-+ </variable>
-+ <variable name="LIMIT_PLAYAUDIO_CALLEE">
-+ <value name="yes" />
-+ <value name="no" default="true"/>
-+ <para>If set, this variable causes Asterisk to play the prompts to the callee.</para>
-+ </variable>
-+ <variable name="LIMIT_TIMEOUT_FILE">
-+ <value name="filename"/>
-+ <para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play when the timeout is reached.
-+ If not set, the time remaining will be announced.</para>
-+ </variable>
-+ <variable name="LIMIT_CONNECT_FILE">
-+ <value name="filename"/>
-+ <para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play when the call begins.
-+ If not set, the time remaining will be announced.</para>
-+ </variable>
-+ <variable name="LIMIT_WARNING_FILE">
-+ <value name="filename"/>
-+ <para>If specified, <replaceable>filename</replaceable> specifies the sound prompt to play as
-+ a warning when time <replaceable>x</replaceable> is reached. If not set, the time remaining will be announced.</para>
-+ </variable>
-+ </variablelist>
-+ </option>
-+ <option name="m">
-+ <argument name="class" required="false"/>
-+ <para>Provide hold music to the calling party until a requested
-+ channel answers. A specific music on hold <replaceable>class</replaceable>
-+ (as defined in <filename>musiconhold.conf</filename>) can be specified.</para>
-+ </option>
-+ <option name="M" argsep="^">
-+ <argument name="macro" required="true">
-+ <para>Name of the macro that should be executed.</para>
-+ </argument>
-+ <argument name="arg" multiple="true">
-+ <para>Macro arguments</para>
-+ </argument>
-+ <para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel
-+ before connecting to the calling channel. Arguments can be specified to the Macro
-+ using <literal>^</literal> as a delimiter. The macro can set the variable
-+ <variable>MACRO_RESULT</variable> to specify the following actions after the macro is
-+ finished executing:</para>
-+ <variablelist>
-+ <variable name="MACRO_RESULT">
-+ <para>If set, this action will be taken after the macro finished executing.</para>
-+ <value name="ABORT">
-+ Hangup both legs of the call
-+ </value>
-+ <value name="CONGESTION">
-+ Behave as if line congestion was encountered
-+ </value>
-+ <value name="BUSY">
-+ Behave as if a busy signal was encountered
-+ </value>
-+ <value name="CONTINUE">
-+ Hangup the called party and allow the calling party to continue dialplan execution at the next priority
-+ </value>
-+ <!-- TODO: Fix this syntax up, once we've figured out how to specify the GOTO syntax -->
-+ <value name="GOTO:&lt;context&gt;^&lt;exten&gt;^&lt;priority&gt;">
-+ Transfer the call to the specified destination.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ <note>
-+ <para>You cannot use any additional action post answer options in conjunction
-+ with this option. Also, pbx services are not run on the peer (called) channel,
-+ so you will not be able to set timeouts via the TIMEOUT() function in this macro.</para>
-+ </note>
-+ </option>
-+ <option name="n">
-+ <para>This option is a modifier for the call screening/privacy mode. (See the
-+ <literal>p</literal> and <literal>P</literal> options.) It specifies
-+ that no introductions are to be saved in the <directory>priv-callerintros</directory>
-+ directory.</para>
-+ </option>
-+ <option name="N">
-+ <para>This option is a modifier for the call screening/privacy mode. It specifies
-+ that if Caller*ID is present, do not screen the call.</para>
-+ </option>
-+ <option name="o">
-+ <para>Specify that the Caller*ID that was present on the <emphasis>calling</emphasis> channel
-+ be set as the Caller*ID on the <emphasis>called</emphasis> channel. This was the
-+ behavior of Asterisk 1.0 and earlier.</para>
-+ </option>
-+ <option name="O">
-+ <argument name="mode">
-+ <para>With <replaceable>mode</replaceable> either not specified or set to <literal>1</literal>,
-+ the originator hanging up will cause the phone to ring back immediately.</para>
-+ <para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator
-+ flashes the trunk, it will ring their phone back.</para>
-+ </argument>
-+ <para>Enables <emphasis>operator services</emphasis> mode. This option only
-+ works when bridging a DAHDI channel to another DAHDI channel
-+ only. if specified on non-DAHDI interfaces, it will be ignored.
-+ When the destination answers (presumably an operator services
-+ station), the originator no longer has control of their line.
-+ They may hang up, but the switch will not release their line
-+ until the destination party (the operator) hangs up.</para>
-+ </option>
-+ <option name="p">
-+ <para>This option enables screening mode. This is basically Privacy mode
-+ without memory.</para>
-+ </option>
-+ <option name="P">
-+ <argument name="x" />
-+ <para>Enable privacy mode. Use <replaceable>x</replaceable> as the family/key in the AstDB database if
-+ it is provided. The current extension is used if a database family/key is not specified.</para>
-+ </option>
-+ <option name="r">
-+ <para>Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling
-+ party until the called channel has answered.</para>
-+ </option>
-+ <option name="S">
-+ <argument name="x" required="true" />
-+ <para>Hang up the call <replaceable>x</replaceable> seconds <emphasis>after</emphasis> the called party has
-+ answered the call.</para>
-+ </option>
-+ <option name="t">
-+ <para>Allow the called party to transfer the calling party by sending the
-+ DTMF sequence defined in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="T">
-+ <para>Allow the calling party to transfer the called party by sending the
-+ DTMF sequence defined in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="U" argsep="^">
-+ <argument name="x" required="true">
-+ <para>Name of the subroutine to execute via Gosub</para>
-+ </argument>
-+ <argument name="arg" multiple="true" required="false">
-+ <para>Arguments for the Gosub routine</para>
-+ </argument>
-+ <para>Execute via Gosub the routine <replaceable>x</replaceable> for the <emphasis>called</emphasis> channel before connecting
-+ to the calling channel. Arguments can be specified to the Gosub
-+ using <literal>^</literal> as a delimiter. The Gosub routine can set the variable
-+ <variable>GOSUB_RESULT</variable> to specify the following actions after the Gosub returns.</para>
-+ <variablelist>
-+ <variable name="GOSUB_RESULT">
-+ <value name="ABORT">
-+ Hangup both legs of the call.
-+ </value>
-+ <value name="CONGESTION">
-+ Behave as if line congestion was encountered.
-+ </value>
-+ <value name="BUSY">
-+ Behave as if a busy signal was encountered.
-+ </value>
-+ <value name="CONTINUE">
-+ Hangup the called party and allow the calling party
-+ to continue dialplan execution at the next priority.
-+ </value>
-+ <!-- TODO: Fix this syntax up, once we've figured out how to specify the GOTO syntax -->
-+ <value name="GOTO:&lt;context&gt;^&lt;exten&gt;^&lt;priority&gt;">
-+ Transfer the call to the specified priority. Optionally, an extension, or
-+ extension and priority can be specified.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ <note>
-+ <para>You cannot use any additional action post answer options in conjunction
-+ with this option. Also, pbx services are not run on the peer (called) channel,
-+ so you will not be able to set timeouts via the TIMEOUT() function in this routine.</para>
-+ </note>
-+ </option>
-+ <option name="w">
-+ <para>Allow the called party to enable recording of the call by sending
-+ the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="W">
-+ <para>Allow the calling party to enable recording of the call by sending
-+ the DTMF sequence defined for one-touch recording in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="x">
-+ <para>Allow the called party to enable recording of the call by sending
-+ the DTMF sequence defined for one-touch automixmonitor in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="X">
-+ <para>Allow the calling party to enable recording of the call by sending
-+ the DTMF sequence defined for one-touch automixmonitor in <filename>features.conf</filename>.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="URL">
-+ <para>The optional URL will be sent to the called party if the channel driver supports it.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-
--static char *synopsis = "Place a call and connect to the current channel";
-+ <para>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.</para>
-+ <para>If the <variable>OUTBOUND_GROUP</variable> variable is set, all peer channels created by this
-+ application will be put into that group (as in Set(GROUP()=...).
-+ If the <variable>OUTBOUND_GROUP_ONCE</variable> 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.</para>
-
--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:<context>^<exten>^<priority> - 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:<context>^<exten>^<priority> - 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";
-+ <para>This application sets the following channel variables:</para>
-+ <variablelist>
-+ <variable name="DIALEDTIME">
-+ <para>This is the time from dialing a channel until when it is disconnected.</para>
-+ </variable>
-+ <variable name="ANSWEREDTIME">
-+ <para>This is the amount of time for actual call.</para>
-+ </variable>
-+ <variable name="DIALSTATUS">
-+ <para>This is the status of the call</para>
-+ <value name="CHANUNAVAIL" />
-+ <value name="CONGESTION" />
-+ <value name="NOANSWER" />
-+ <value name="BUSY" />
-+ <value name="ANSWER" />
-+ <value name="CANCEL" />
-+ <value name="DONTCALL">
-+ For the Privacy and Screening Modes.
-+ Will be set if the called party chooses to send the calling party to the 'Go Away' script.
-+ </value>
-+ <value name="TORTURE">
-+ For the Privacy and Screening Modes.
-+ Will be set if the called party chooses to send the calling party to the 'torture' script.
-+ </value>
-+ <value name="INVALIDARGS" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="RetryDial" language="en_US">
-+ <synopsis>
-+ Place a call, retrying on failure allowing an optional exit extension.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="announce" required="true">
-+ <para>Filename of sound that will be played when no channel can be reached</para>
-+ </parameter>
-+ <parameter name="sleep" required="true">
-+ <para>Number of seconds to wait after a dial attempt failed before a new attempt is made</para>
-+ </parameter>
-+ <parameter name="retries" required="true">
-+ <para>Number of retries</para>
-+ <para>When this is reached flow will continue at the next priority in the dialplan</para>
-+ </parameter>
-+ <parameter name="dialargs" required="true">
-+ <para>Same format as arguments provided to the Dial application</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will attempt to place a call using the normal Dial application.
-+ If no channel can be reached, the <replaceable>announce</replaceable> file will be played.
-+ Then, it will wait <replaceable>sleep</replaceable> number of seconds before retrying the call.
-+ After <replaceable>retries</replaceable> number of attempts, the calling channel will continue at the next priority in the dialplan.
-+ If the <replaceable>retries</replaceable> 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 <variable>EXITCONTEXT</variable> or the current
-+ one, The call will jump to that extension immediately.
-+ The <replaceable>dialargs</replaceable> are specified in the same format that arguments are provided
-+ to the Dial application.</para>
-+ </description>
-+ </application>
-+ ***/
-
--/* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> 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
-+ <application name="NBScat" language="en_US">
-+ <synopsis>
-+ Play an NBS local stream.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Executes nbscat to listen to the local NBS stream.
-+ User can exit by pressing any key.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- #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
-+ <application name="Page" language="en_US">
-+ <synopsis>
-+ Page series of phones
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Technology/Resource" required="true" argsep="&amp;">
-+ <argument name="Technology/Resource" required="true">
-+ <para>Specification of the device(s) to dial. These must be in the format of
-+ <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable>
-+ represents a particular channel driver, and <replaceable>Resource</replaceable> represents a resource
-+ available to that particular channel driver.</para>
-+ </argument>
-+ <argument name="Technology2/Resource2" multiple="true">
-+ <para>Optional extra devices to dial inparallel</para>
-+ <para>If you need more then one enter them as Technology2/Resource2&amp;
-+ Technology3/Resourse3&amp;.....</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="d">
-+ <para>Full duplex audio</para>
-+ </option>
-+ <option name="i">
-+ <para>Ignore attempts to forward the call</para>
-+ </option>
-+ <option name="q">
-+ <para>Quiet, do not play beep to caller</para>
-+ </option>
-+ <option name="r">
-+ <para>Record the page into a file (meetme option <literal>r</literal>)</para>
-+ </option>
-+ <option name="s">
-+ <para>Only dial a channel if its device state says that it is <literal>NOT_INUSE</literal></para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="timeout">
-+ <para>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.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Places outbound calls to the given <replaceable>technology</replaceable>/<replaceable>resource</replaceable>
-+ 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.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">MeetMe</ref>
-+ </see-also>
-+ </application>
-+ ***/
- 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
-+ <application name="Echo" language="en_US">
-+ <synopsis>
-+ Echo audio, video, DTMF back to the calling party
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Echos back any audio, video or DTMF frames read from the calling
-+ channel back to itself. Note: If '#' detected application exits</para>
-+ </description>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="WaitForSilence" language="en_US">
-+ <synopsis>
-+ Waits for a specified amount of silence.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="silencerequired" required="true" />
-+ <parameter name="iterations">
-+ <para>If not specified, defaults to <literal>1</literal>.</para>
-+ </parameter>
-+ <parameter name="timeout">
-+ <para>Is specified only to avoid an infinite loop in cases where silence is never achieved.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Waits for up to <replaceable>silencerequired</replaceable> milliseconds of silence,
-+ <replaceable>iterations</replaceable> times. An optional <replaceable>timeout</replaceable>
-+ specified the number of seconds to return after, even if we do not receive the specified amount of silence.
-+ Use <replaceable>timeout</replaceable> 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.</para>
-+ <para>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.</para>
-+ <para>Examples:</para>
-+ <para>WaitForSilence(500,2) will wait for 1/2 second of silence, twice</para>
-+ <para>WaitForSilence(1000) will wait for 1 second of silence, once</para>
-+ <para>WaitForSilence(300,3,10) will wait for 300ms silence, 3 times, and returns after 10 sec, even if silence
-+ is not detected</para>
-+ <para>Sets the channel variable <variable>WAITSTATUS</variable> to one of these values:</para>
-+ <variablelist>
-+ <variable name="WAITSTATUS">
-+ <value name="SILENCE">
-+ if exited with silence detected.
-+ </value>
-+ <value name="TIMEOUT">
-+ if exited without silence detected after timeout.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">WaitForNoise</ref>
-+ </see-also>
-+ </application>
-+ <application name="WaitForNoise" language="en_US">
-+ <synopsis>
-+ Waits for a specified amount of noise.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="noiserequired" required="true" />
-+ <parameter name="iterations">
-+ <para>If not specified, defaults to <literal>1</literal>.</para>
-+ </parameter>
-+ <parameter name="timeout">
-+ <para>Is specified only to avoid an infinite loop in cases where silence is never achieved.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Waits for up to <replaceable>noiserequired</replaceable> milliseconds of noise,
-+ <replaceable>iterations</replaceable> times. An optional <replaceable>timeout</replaceable>
-+ specified the number of seconds to return after, even if we do not receive the specified amount of noise.
-+ Use <replaceable>timeout</replaceable> with caution, as it may defeat the purpose of this application, which
-+ is to wait indefinitely until noise is detected on the line.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">WaitForSilence</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- 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
-+ <application name="SayUnixTime" language="en_US">
-+ <synopsis>
-+ Says a specified time in a custom format.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="unixtime">
-+ <para>time, in seconds since Jan 1, 1970. May be negative. Defaults to now.</para>
-+ </parameter>
-+ <parameter name="timezone">
-+ <para>timezone, see <directory>/usr/share/zoneinfo</directory> for a list. Defaults to machine default.</para>
-+ </parameter>
-+ <parameter name="format">
-+ <para>a format the time is to be said in. See <filename>voicemail.conf</filename>.
-+ Defaults to <literal>ABdY "digits/at" IMp</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Uses some of the sound files stored in <directory>/var/lib/asterisk/sounds</directory> to construct a phrase
-+ saying the specified date and/or time in the specified format. </para>
-+ </description>
-+ <see-also>
-+ <ref type="function">STRFTIME</ref>
-+ <ref type="function">STRPTIME</ref>
-+ <ref type="function">IFTIME</ref>
-+ </see-also>
-+ </application>
-+ <application name="DateTime" language="en_US">
-+ <synopsis>
-+ Says a specified time in a custom format.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="unixtime">
-+ <para>time, in seconds since Jan 1, 1970. May be negative. Defaults to now.</para>
-+ </parameter>
-+ <parameter name="timezone">
-+ <para>timezone, see <filename>/usr/share/zoneinfo</filename> for a list. Defaults to machine default.</para>
-+ </parameter>
-+ <parameter name="format">
-+ <para>a format the time is to be said in. See <filename>voicemail.conf</filename>.
-+ Defaults to <literal>ABdY "digits/at" IMp</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Say the date and time in a specified format.</para>
-+ </description>
-+ </application>
-+
-+ ***/
-+
- 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@trincoll.edu>
- *
-- * David Chappell <David.Chappell@trincoll.edu>
-- *
- * 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
-+ <application name="ReadExten" language="en_US">
-+ <synopsis>
-+ Read an extension into a variable.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="variable" required="true" />
-+ <parameter name="filename">
-+ <para>File to play before reading digits or tone with option <literal>i</literal></para>
-+ </parameter>
-+ <parameter name="context">
-+ <para>Context in which to match extensions.</para>
-+ </parameter>
-+ <parameter name="option">
-+ <optionlist>
-+ <option name="s">
-+ <para>Return immediately if the channel is not answered.</para>
-+ </option>
-+ <option name="i">
-+ <para>Play <replaceable>filename</replaceable> as an indication tone from your
-+ <filename>indications.conf</filename></para>
-+ </option>
-+ <option name="n">
-+ <para>Read digits even if the channel is not answered.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="timeout">
-+ <para>An integer number of seconds to wait for a digit response. If
-+ greater than <literal>0</literal>, that value will override the default timeout.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Reads a <literal>#</literal> terminated string of digits from the user into the given variable.</para>
-+ <para>Will set READEXTENSTATUS on exit with one of the following statuses:</para>
-+ <variablelist>
-+ <variable name="READEXTENSTATUS">
-+ <value name="OK">
-+ A valid extension exists in ${variable}.
-+ </value>
-+ <value name="TIMEOUT">
-+ No extension was entered in the specified time. Also sets ${variable} to "t".
-+ </value>
-+ <value name="INVALID">
-+ An invalid extension, ${INVALID_EXTEN}, was entered. Also sets ${variable} to "i".
-+ </value>
-+ <value name="SKIP">
-+ Line was not up and the option 's' was specified.
-+ </value>
-+ <value name="ERROR">
-+ Invalid arguments were passed.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <function name="VALID_EXTEN" language="en_US">
-+ <synopsis>
-+ Determine whether an extension exists or not.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="context">
-+ <para>Defaults to the current context</para>
-+ </parameter>
-+ <parameter name="extension" required="true" />
-+ <parameter name="priority">
-+ <para>Priority defaults to <literal>1</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns a true value if the indicated <replaceable>context</replaceable>,
-+ <replaceable>extension</replaceable>, and <replaceable>priority</replaceable> exist.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<variable>[,[<filename>][,[<context>][,[<option>][,<timeout>]]]])\n\n"
--"Reads a #-terminated string of digits from the user into the given variable.\n"
--" filename file to play before reading digits or tone with option i\n"
--" context context in which to match extensions\n"
--" option options are:\n"
--" s - Return immediately if the channel is not answered,\n"
--" i - Play filename as an indication tone from your\n"
--" indications.conf\n"
--" n - Read digits even if the channel is not answered.\n"
--" timeout An integer number of seconds to wait for a digit response. If\n"
--" greater than 0, that value will override the default timeout.\n\n"
--"ReadExten will set READEXTENSTATUS on exit with one of the following statuses:\n"
--" OK A valid extension exists in ${variable}\n"
--" TIMEOUT No extension was entered in the specified time\n"
--" INVALID An invalid extension, ${INVALID_EXTEN}, was entered\n"
--" SKIP Line was not up and the option 's' was specified\n"
--" ERROR Invalid arguments were passed\n";
--
--
- static int readexten_exec(struct ast_channel *chan, void *data)
- {
- int res = 0;
-@@ -79,7 +132,7 @@
- int maxdigits = sizeof(exten) - 1;
- int timeout = 0, digit_timeout = 0, x = 0;
- char *argcopy = NULL, *status = "";
-- struct tone_zone_sound *ts = NULL;
-+ struct ast_tone_zone_sound *ts = NULL;
- struct ast_flags flags = {0};
-
- AST_DECLARE_APP_ARGS(arglist,
-@@ -100,7 +153,7 @@
- AST_STANDARD_APP_ARGS(arglist, argcopy);
-
- if (ast_strlen_zero(arglist.variable)) {
-- ast_log(LOG_WARNING, "Invalid! Usage: ReadExten(variable[|filename][|context][|options][|timeout])\n\n");
-+ ast_log(LOG_WARNING, "Usage: ReadExten(variable[,filename[,context[,options[,timeout]]]])\n");
- pbx_builtin_setvar_helper(chan, "READEXTENSTATUS", "ERROR");
- return 0;
- }
-@@ -126,8 +179,9 @@
- if (digit_timeout <= 0)
- digit_timeout = chan->pbx ? chan->pbx->dtimeoutms : 5000;
-
-- if (ast_test_flag(&flags, OPT_INDICATION) && !ast_strlen_zero(arglist.filename))
-+ if (ast_test_flag(&flags, OPT_INDICATION) && !ast_strlen_zero(arglist.filename)) {
- ts = ast_get_indication_tone(chan->zone, arglist.filename);
-+ }
-
- do {
- if (chan->_state != AST_STATE_UP) {
-@@ -164,10 +218,12 @@
- timeout = digit_timeout;
-
- if (res < 1) { /* timeout expired or hangup */
-- if (ast_check_hangup(chan))
-+ if (ast_check_hangup(chan)) {
- status = "HANGUP";
-- else
-+ } else {
-+ pbx_builtin_setvar_helper(chan, arglist.variable, "t");
- status = "TIMEOUT";
-+ }
- break;
- }
-
-@@ -189,11 +245,16 @@
- status = "OK";
- } else {
- ast_debug(3, "User dialed invalid extension '%s' in context '%s' on %s\n", exten, arglist.context, chan->name);
-+ pbx_builtin_setvar_helper(chan, arglist.variable, "i");
- pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
- status = "INVALID";
- }
- } while (0);
-
-+ if (ts) {
-+ ts = ast_tone_zone_sound_unref(ts);
-+ }
-+
- pbx_builtin_setvar_helper(chan, "READEXTENSTATUS", status);
-
- return status[0] == 'H' ? -1 : 0;
-@@ -233,11 +294,6 @@
-
- static struct ast_custom_function acf_isexten = {
- .name = "VALID_EXTEN",
-- .synopsis = "Determine whether an extension exists or not",
-- .syntax = "VALID_EXTEN([<context>],<extension>[,<priority>])",
-- .desc =
--"Returns a true value if the indicated context, extension, and priority exist.\n"
--"Context defaults to the current context, priority defaults to 1.\n",
- .read = acf_isexten_exec,
- };
-
-@@ -251,7 +307,7 @@
-
- static int load_module(void)
- {
-- int res = ast_register_application(app, readexten_exec, synopsis, descrip);
-+ int res = ast_register_application_xml(app, readexten_exec);
- res |= ast_custom_function_register(&acf_isexten);
- return res;
- }
-Index: apps/app_dahdiras.c
-===================================================================
---- a/apps/app_dahdiras.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_dahdiras.c (.../team/group/issue14292) (revision 178988)
-@@ -52,18 +52,29 @@
- #include "asterisk/module.h"
- #include "asterisk/app.h"
-
--static char *app = "DAHDIRAS";
-+/*** DOCUMENTATION
-+ <application name="DAHDIRAS" language="en_US">
-+ <synopsis>
-+ Executes DAHDI ISDN RAS application.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="args" required="true">
-+ <para>A list of parameters to pass to the pppd daemon,
-+ separated by <literal>,</literal> characters.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Executes a RAS server using pppd on the given channel.
-+ The channel must be a clear channel (i.e. PRI source) and a DAHDI
-+ channel to be able to use this function (No modem emulation is included).</para>
-+ <para>Your pppd must be patched to be DAHDI aware.</para>
-+ </description>
-+ </application>
-
--static char *synopsis = "Executes DAHDI ISDN RAS application";
-+ ***/
-
--static char *descrip =
--" DAHDIRAS(args): Executes a RAS server using pppd on the given channel.\n"
--"The channel must be a clear channel (i.e. PRI source) and a DAHDI\n"
--"channel to be able to use this function (No modem emulation is included).\n"
--"Your pppd must be patched to be DAHDI aware. Arguments should be\n"
--"separated by , characters.\n";
-+static char *app = "DAHDIRAS";
-
--
- #define PPP_MAX_ARGS 32
- #define PPP_EXEC "/usr/sbin/pppd"
-
-@@ -218,7 +229,7 @@
-
- static int load_module(void)
- {
-- return ((ast_register_application(app, dahdiras_exec, synopsis, descrip)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
-+ return ((ast_register_application_xml(app, dahdiras_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI ISDN Remote Access Server");
-Index: apps/app_disa.c
-===================================================================
---- a/apps/app_disa.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_disa.c (.../team/group/issue14292) (revision 178988)
-@@ -45,51 +45,73 @@
- #include "asterisk/callerid.h"
- #include "asterisk/stringfields.h"
-
-+/*** DOCUMENTATION
-+ <application name="DISA" language="en_US">
-+ <synopsis>
-+ Direct Inward System Access.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="passcode|filename" required="true">
-+ <para>If you need to present a DISA dialtone without entering a password,
-+ simply set <replaceable>passcode</replaceable> to <literal>no-password</literal></para>
-+ <para>You may specified a <replaceable>filename</replaceable> instead of a
-+ <replaceable>passcode</replaceable>, this filename must contain individual passcodes</para>
-+ </parameter>
-+ <parameter name="context">
-+ <para>Specifies the dialplan context in which the user-entered extension
-+ will be matched. If no context is specified, the DISA application defaults
-+ to the <literal>disa</literal> context. Presumably a normal system will have a special
-+ context set up for DISA use with some or a lot of restrictions.</para>
-+ </parameter>
-+ <parameter name="cid">
-+ <para>Specifies a new (different) callerid to be used for this call.</para>
-+ </parameter>
-+ <parameter name="mailbox" argsep="@">
-+ <para>Will cause a stutter-dialtone (indication <emphasis>dialrecall</emphasis>)
-+ to be used, if the specified mailbox contains any new messages.</para>
-+ <argument name="mailbox" required="true" />
-+ <argument name="context" required="false" />
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="n">
-+ <para>The DISA application will not answer initially.</para>
-+ </option>
-+ <option name="p">
-+ <para>The extension entered will be considered complete when a <literal>#</literal>
-+ is entered.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>The DISA, Direct Inward System Access, application allows someone from
-+ outside the telephone switch (PBX) to obtain an <emphasis>internal</emphasis> system
-+ dialtone and to place calls from it as if they were placing a call from
-+ within the switch.
-+ DISA plays a dialtone. The user enters their numeric passcode, followed by
-+ the pound sign <literal>#</literal>. If the passcode is correct, the user is then given
-+ system dialtone within <replaceable>context</replaceable> on which a call may be placed.
-+ If the user enters an invalid extension and extension <literal>i</literal> exists in the specified
-+ <replaceable>context</replaceable>, it will be used.
-+ </para>
-+ <para>Be aware that using this may compromise the security of your PBX.</para>
-+ <para>The arguments to this application (in <filename>extensions.conf</filename>) allow either
-+ specification of a single global <replaceable>passcode</replaceable> (that everyone uses), or
-+ individual passcodes contained in a file (<replaceable>filename</replaceable>).</para>
-+ <para>The file that contains the passcodes (if used) allows a complete
-+ specification of all of the same arguments available on the command
-+ line, with the sole exception of the options. The file may contain blank
-+ lines, or comments starting with <literal>#</literal> or <literal>;</literal>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Authenticate</ref>
-+ <ref type="application">VMAuthenticate</ref>
-+ </see-also>
-+ </application>
-+ ***/
- static char *app = "DISA";
-
--static char *synopsis = "DISA (Direct Inward System Access)";
--
--static char *descrip =
--"DISA(<numeric passcode>[,<context>[,<cid>[,mailbox[,options]]]]) or\n"
--"DISA(<filename>[,,,,options])\n"
--"The DISA, Direct Inward System Access, application allows someone from \n"
--"outside the telephone switch (PBX) to obtain an \"internal\" system \n"
--"dialtone and to place calls from it as if they were placing a call from \n"
--"within the switch.\n"
--"DISA plays a dialtone. The user enters their numeric passcode, followed by\n"
--"the pound sign (#). If the passcode is correct, the user is then given\n"
--"system dialtone within <context> on which a call may be placed. If the user\n"
--"enters an invalid extension and extension \"i\" exists in the specified\n"
--"context, it will be used.\n"
--"\n"
--"If you need to present a DISA dialtone without entering a password, simply\n"
--"set <passcode> to \"no-password\".\n"
--"\n"
--"Be aware that using this may compromise the security of your PBX.\n"
--"\n"
--"The arguments to this application (in extensions.conf) allow either\n"
--"specification of a single global passcode (that everyone uses), or\n"
--"individual passcodes contained in a file.\n"
--"\n"
--"The file that contains the passcodes (if used) allows a complete\n"
--"specification of all of the same arguments available on the command\n"
--"line, with the sole exception of the options. The file may contain blank\n"
--"lines, or comments starting with \"#\" or \";\".\n"
--"\n"
--"<context> specifies the dialplan context in which the user-entered extension\n"
--"will be matched. If no context is specified, the DISA application defaults\n"
--"the context to \"disa\". Presumably a normal system will have a special\n"
--"context set up for DISA use with some or a lot of restrictions.\n"
--"\n"
--"<cid> specifies a new (different) callerid to be used for this call.\n"
--"\n"
--"<mailbox[@context]> will cause a stutter-dialtone (indication \"dialrecall\")\n"
--"to be used, if the specified mailbox contains any new messages.\n"
--"\n"
--"The following options are available:\n"
--" n - the DISA application will not answer initially.\n"
--" p - the extension entered will be considered complete when a '#' is entered.\n";
--
- enum {
- NOANSWER_FLAG = (1 << 0),
- POUND_TO_END_FLAG = (1 << 1),
-@@ -102,15 +124,20 @@
-
- static void play_dialtone(struct ast_channel *chan, char *mailbox)
- {
-- const struct tone_zone_sound *ts = NULL;
-- if(ast_app_has_voicemail(mailbox, NULL))
-+ struct ast_tone_zone_sound *ts = NULL;
-+
-+ if (ast_app_has_voicemail(mailbox, NULL)) {
- ts = ast_get_indication_tone(chan->zone, "dialrecall");
-- else
-+ } else {
- ts = ast_get_indication_tone(chan->zone, "dial");
-- if (ts)
-+ }
-+
-+ if (ts) {
- ast_playtones_start(chan, 0, ts->data, 0);
-- else
-+ ts = ast_tone_zone_sound_unref(ts);
-+ } else {
- ast_tonepair_start(chan, 350, 440, 0, 0);
-+ }
- }
-
- static int disa_exec(struct ast_channel *chan, void *data)
-@@ -369,7 +396,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, disa_exec, synopsis, descrip) ?
-+ return ast_register_application_xml(app, disa_exec) ?
- AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
- }
-
-Index: apps/app_userevent.c
-===================================================================
---- a/apps/app_userevent.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_userevent.c (.../team/group/issue14292) (revision 178988)
-@@ -30,22 +30,32 @@
- #include "asterisk/manager.h"
- #include "asterisk/app.h"
-
-+/*** DOCUMENTATION
-+ <application name="UserEvent" language="en_US">
-+ <synopsis>
-+ Send an arbitrary event to the manager interface.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="eventname" required="true" />
-+ <parameter name="body" />
-+ </syntax>
-+ <description>
-+ <para>Sends an arbitrary event to the manager interface, with an optional
-+ <replaceable>body</replaceable> representing additional arguments. The
-+ <replaceable>body</replaceable> may be specified as
-+ a <literal>|</literal> delimited list of headers. Each additional
-+ argument will be placed on a new line in the event. The format of the
-+ event will be:</para>
-+ <para> Event: UserEvent</para>
-+ <para> UserEvent: &lt;specified event name&gt;</para>
-+ <para> [body]</para>
-+ <para>If no <replaceable>body</replaceable> is specified, only Event and UserEvent headers will be present.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- static char *app = "UserEvent";
-
--static char *synopsis = "Send an arbitrary event to the manager interface";
--
--static char *descrip =
--" UserEvent(eventname[,body]): Sends an arbitrary event to the manager\n"
--"interface, with an optional body representing additional arguments. The\n"
--"body may be specified as a | delimeted list of headers. Each additional\n"
--"argument will be placed on a new line in the event. The format of the\n"
--"event will be:\n"
--" Event: UserEvent\n"
--" UserEvent: <specified event name>\n"
--" [body]\n"
--"If no body is specified, only Event and UserEvent headers will be present.\n";
--
--
- static int userevent_exec(struct ast_channel *chan, void *data)
- {
- char *parse;
-@@ -75,7 +85,7 @@
- ast_str_append(&body, 0, "%s\r\n", args.extra[x]);
- }
-
-- manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", args.eventname, body->str);
-+ manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", args.eventname, ast_str_buffer(body));
- ast_free(body);
-
- return 0;
-@@ -88,7 +98,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, userevent_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, userevent_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Custom User Event Application");
-Index: apps/app_chanisavail.c
-===================================================================
---- a/apps/app_chanisavail.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_chanisavail.c (.../team/group/issue14292) (revision 178988)
-@@ -43,23 +43,55 @@
-
- static char *app = "ChanIsAvail";
-
--static char *synopsis = "Check channel availability";
-+/*** DOCUMENTATION
-+ <application name="ChanIsAvail" language="en_US">
-+ <synopsis>
-+ Check channel availability
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Technology/Resource" required="true" argsep="&amp;">
-+ <argument name="Technology2/Resource2" multiple="true">
-+ <para>Optional extra devices to check</para>
-+ <para>If you need more then one enter them as
-+ Technology2/Resource2&amp;Technology3/Resourse3&amp;.....</para>
-+ </argument>
-+ <para>Specification of the device(s) to check. These must be in the format of
-+ <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable>
-+ represents a particular channel driver, and <replaceable>Resource</replaceable>
-+ represents a resource available to that particular channel driver.</para>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="a">
-+ <para>Check for all available channels, not only the first one</para>
-+ </option>
-+ <option name="s">
-+ <para>Consider the channel unavailable if the channel is in use at all</para>
-+ </option>
-+ <option name="t" implies="s">
-+ <para>Simply checks if specified channels exist in the channel list</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will check to see if any of the specified channels are available.</para>
-+ <para>This application sets the following channel variables:</para>
-+ <variablelist>
-+ <variable name="AVAILCHAN">
-+ <para>The name of the available channel, if one exists</para>
-+ </variable>
-+ <variable name="AVAILORIGCHAN">
-+ <para>The canonical channel name that was used to create the channel</para>
-+ </variable>
-+ <variable name="AVAILSTATUS">
-+ <para>The status code for the available channel</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
-
--static char *descrip =
--" ChanIsAvail(Technology/resource[&Technology2/resource2...][,options]): \n"
--"This application will check to see if any of the specified channels are\n"
--"available.\n"
--" Options:\n"
--" a - Check for all available channels, not only the first one.\n"
--" s - Consider the channel unavailable if the channel is in use at all.\n"
--" t - Simply checks if specified channels exist in the channel list\n"
--" (implies option s).\n"
--"This application sets the following channel variable upon completion:\n"
--" AVAILCHAN - the name of the available channel, if one exists\n"
--" AVAILORIGCHAN - the canonical channel name that was used to create the channel\n"
--" AVAILSTATUS - the status code for the available channel\n";
--
--
- static int chanavail_exec(struct ast_channel *chan, void *data)
- {
- int inuse=-1, option_state=0, string_compare=0, option_all_avail=0;
-@@ -128,13 +160,13 @@
- status = inuse = ast_device_state(trychan);
- }
- if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
-- ast_str_append(&tmp_availchan, 0, "%s%s", tmp_availchan->used ? "&" : "", tempchan->name);
-+ ast_str_append(&tmp_availchan, 0, "%s%s", ast_str_strlen(tmp_availchan) ? "&" : "", tempchan->name);
-
- snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
-- ast_str_append(&tmp_availorig, 0, "%s%s", tmp_availorig->used ? "&" : "", tmp);
-+ ast_str_append(&tmp_availorig, 0, "%s%s", ast_str_strlen(tmp_availorig) ? "&" : "", tmp);
-
- snprintf(tmp, sizeof(tmp), "%d", status);
-- ast_str_append(&tmp_availstat, 0, "%s%s", tmp_availstat->used ? "&" : "", tmp);
-+ ast_str_append(&tmp_availstat, 0, "%s%s", ast_str_strlen(tmp_availstat) ? "&" : "", tmp);
-
- ast_hangup(tempchan);
- tempchan = NULL;
-@@ -144,16 +176,16 @@
- }
- } else {
- snprintf(tmp, sizeof(tmp), "%d", status);
-- ast_str_append(&tmp_availstat, 0, "%s%s", tmp_availstat->used ? "&" : "", tmp);
-+ ast_str_append(&tmp_availstat, 0, "%s%s", ast_str_strlen(tmp_availstat) ? "&" : "", tmp);
- }
- cur = rest;
- } while (cur);
- }
-
-- pbx_builtin_setvar_helper(chan, "AVAILCHAN", tmp_availchan->str);
-+ pbx_builtin_setvar_helper(chan, "AVAILCHAN", ast_str_buffer(tmp_availchan));
- /* Store the originally used channel too */
-- pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp_availorig->str);
-- pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp_availstat->str);
-+ pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", ast_str_buffer(tmp_availorig));
-+ pbx_builtin_setvar_helper(chan, "AVAILSTATUS", ast_str_buffer(tmp_availstat));
-
- return 0;
- }
-@@ -165,7 +197,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, chanavail_exec, synopsis, descrip) ?
-+ return ast_register_application_xml(app, chanavail_exec) ?
- AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
- }
-
-Index: apps/app_system.c
-===================================================================
---- a/apps/app_system.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_system.c (.../team/group/issue14292) (revision 178988)
-@@ -33,35 +33,77 @@
- #include "asterisk/module.h"
- #include "asterisk/app.h"
- #include "asterisk/channel.h" /* autoservice */
-+#include "asterisk/strings.h"
-+#include "asterisk/threadstorage.h"
-
-+/*** DOCUMENTATION
-+ <application name="System" language="en_US">
-+ <synopsis>
-+ Execute a system command.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="command" required="true">
-+ <para>Command to execute</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Executes a command by using system(). If the command
-+ fails, the console should report a fallthrough.</para>
-+ <para>Result of execution is returned in the <variable>SYSTEMSTATUS</variable> channel variable:</para>
-+ <variablelist>
-+ <variable name="SYSTEMSTATUS">
-+ <value name="FAILURE">
-+ Could not execute the specified command.
-+ </value>
-+ <value name="SUCCESS">
-+ Specified command successfully executed.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="TrySystem" language="en_US">
-+ <synopsis>
-+ Try executing a system command.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="command" required="true">
-+ <para>Command to execute</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Executes a command by using system().</para>
-+ <para>Result of execution is returned in the <variable>SYSTEMSTATUS</variable> channel variable:</para>
-+ <variablelist>
-+ <variable name="SYSTEMSTATUS">
-+ <value name="FAILURE">
-+ Could not execute the specified command.
-+ </value>
-+ <value name="SUCCESS">
-+ Specified command successfully executed.
-+ </value>
-+ <value name="APPERROR">
-+ Specified command successfully executed, but returned error code.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+
-+ ***/
-+
-+AST_THREADSTORAGE(buf_buf);
-+
- static char *app = "System";
-
- static char *app2 = "TrySystem";
-
--static char *synopsis = "Execute a system command";
--
--static char *synopsis2 = "Try executing a system command";
--
- static char *chanvar = "SYSTEMSTATUS";
-
--static char *descrip =
--" System(command): Executes a command by using system(). If the command\n"
--"fails, the console should report a fallthrough. \n"
--"Result of execution is returned in the SYSTEMSTATUS channel variable:\n"
--" FAILURE Could not execute the specified command\n"
--" SUCCESS Specified command successfully executed\n";
--
--static char *descrip2 =
--" TrySystem(command): Executes a command by using system().\n"
--"on any situation.\n"
--"Result of execution is returned in the SYSTEMSTATUS channel variable:\n"
--" FAILURE Could not execute the specified command\n"
--" SUCCESS Specified command successfully executed\n"
--" APPERROR Specified command successfully executed, but returned error code\n";
--
- static int system_exec_helper(struct ast_channel *chan, void *data, int failmode)
- {
- int res = 0;
-+ struct ast_str *buf = ast_str_thread_get(&buf_buf, 16);
-
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "System requires an argument(command)\n");
-@@ -72,7 +114,9 @@
- ast_autoservice_start(chan);
-
- /* Do our thing here */
-- res = ast_safe_system((char *)data);
-+ ast_str_get_encoded_str(&buf, 0, (char *) data);
-+ res = ast_safe_system(ast_str_buffer(buf));
-+
- if ((res < 0) && (errno != ECHILD)) {
- ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
- pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
-@@ -120,8 +164,8 @@
- {
- int res;
-
-- res = ast_register_application(app2, trysystem_exec, synopsis2, descrip2);
-- res |= ast_register_application(app, system_exec, synopsis, descrip);
-+ res = ast_register_application_xml(app2, trysystem_exec);
-+ res |= ast_register_application_xml(app, system_exec);
-
- return res;
- }
-Index: apps/app_transfer.c
-===================================================================
---- a/apps/app_transfer.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_transfer.c (.../team/group/issue14292) (revision 178988)
-@@ -36,23 +36,44 @@
- #include "asterisk/app.h"
- #include "asterisk/channel.h"
-
-+/*** DOCUMENTATION
-+ <application name="Transfer" language="en_US">
-+ <synopsis>
-+ Transfer caller to remote extension.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="dest" required="true" argsep="/">
-+ <argument name="Tech" />
-+ <argument name="destination" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Requests the remote caller be transferred
-+ to a given destination. If TECH (SIP, IAX2, LOCAL etc) is used, only
-+ an incoming call with the same channel technology will be transfered.
-+ Note that for SIP, if you transfer before call is setup, a 302 redirect
-+ SIP message will be returned to the caller.</para>
-+ <para>The result of the application will be reported in the <variable>TRANSFERSTATUS</variable>
-+ channel variable:</para>
-+ <variablelist>
-+ <variable name="TRANSFERSTATUS">
-+ <value name="SUCCESS">
-+ Transfer succeeded.
-+ </value>
-+ <value name="FAILURE">
-+ Transfer failed.
-+ </value>
-+ <value name="UNSUPPORTED">
-+ Transfer unsupported by channel driver.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
-
- static const char *app = "Transfer";
-
--static const char *synopsis = "Transfer caller to remote extension";
--
--static const char *descrip =
--" Transfer([Tech/]dest): Requests the remote caller be transferred\n"
--"to a given destination. If TECH (SIP, IAX2, LOCAL etc) is used, only\n"
--"an incoming call with the same channel technology will be transfered.\n"
--"Note that for SIP, if you transfer before call is setup, a 302 redirect\n"
--"SIP message will be returned to the caller.\n"
--"\nThe result of the application will be reported in the TRANSFERSTATUS\n"
--"channel variable:\n"
--" SUCCESS Transfer succeeded\n"
--" FAILURE Transfer failed\n"
--" UNSUPPORTED Transfer unsupported by channel driver\n";
--
- static int transfer_exec(struct ast_channel *chan, void *data)
- {
- int res;
-@@ -115,7 +136,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, transfer_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, transfer_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Transfers a caller to another extension");
-Index: apps/app_playback.c
-===================================================================
---- a/apps/app_playback.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_playback.c (.../team/group/issue14292) (revision 178988)
-@@ -39,27 +39,50 @@
- #include "asterisk/say.h" /* provides config-file based 'say' functions */
- #include "asterisk/cli.h"
-
-+/*** DOCUMENTATION
-+ <application name="Playback" language="en_US">
-+ <synopsis>
-+ Play a file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filenames" required="true" argsep="&amp;">
-+ <argument name="filename" required="true" />
-+ <argument name="filename2" multiple="true" />
-+ </parameter>
-+ <parameter name="options">
-+ <para>Comma separated list of options</para>
-+ <optionlist>
-+ <option name="skip">
-+ <para>Do not play if not answered</para>
-+ </option>
-+ <option name="noanswer">
-+ <para>Playback without answering, otherwise the channel will
-+ be answered before the sound is played.</para>
-+ <note><para>Not all channel types support playing messages while still on hook.</para></note>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Plays back given filenames (do not put extension of wav/alaw etc).
-+ The playback command answer the channel if no options are specified.
-+ If the file is non-existant it will fail</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="PLAYBACKSTATUS">
-+ <para>The status of the playback attempt as a text string.</para>
-+ <value name="SUCCESS"/>
-+ <value name="FAILED"/>
-+ </variable>
-+ </variablelist>
-+ <para>See Also: Background (application) -- for playing sound files that are interruptible</para>
-+ <para>WaitExten (application) -- wait for digits from caller, optionally play music on hold</para>
-+ </description>
-+ </application>
-+ ***/
-+
- static char *app = "Playback";
-
--static char *synopsis = "Play a file";
--
--static char *descrip =
--" Playback(filename[&filename2...][,option]): Plays back given filenames (do not put\n"
--"extension). Options may also be included following a comma.\n"
--"The 'skip' option causes the playback of the message to be skipped if the channel\n"
--"is not in the 'up' state (i.e. it hasn't been answered yet). If 'skip' is \n"
--"specified, the application will return immediately should the channel not be\n"
--"off hook. Otherwise, unless 'noanswer' is specified, the channel will\n"
--"be answered before the sound is played. Not all channels support playing\n"
--"messages while still on hook.\n"
--"This application sets the following channel variable upon completion:\n"
--" PLAYBACKSTATUS The status of the playback attempt as a text string, one of\n"
--" SUCCESS | FAILED\n"
--"See Also: Background (application) -- for playing soundfiles that are interruptible\n"
--" WaitExten (application) -- wait for digits from caller, optionally play music on hold\n"
--;
--
--
- static struct ast_config *say_cfg = NULL;
- /* save the say' api calls.
- * The first entry is NULL if we have the standard source,
-@@ -461,8 +484,12 @@
- struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
- struct ast_config *newcfg;
-
-- if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
-+ if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
- return 0;
-+ } else if (newcfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "Config file say.conf is in an invalid format. Aborting.\n");
-+ return 0;
-+ }
-
- if (say_cfg) {
- ast_config_destroy(say_cfg);
-@@ -492,7 +519,7 @@
-
- res = ast_unregister_application(app);
-
-- ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_playback, ARRAY_LEN(cli_playback));
-
- if (say_cfg)
- ast_config_destroy(say_cfg);
-@@ -506,7 +533,7 @@
- struct ast_flags config_flags = { 0 };
-
- say_cfg = ast_config_load("say.conf", config_flags);
-- if (say_cfg) {
-+ if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {
- for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {
- if (ast_extension_match(v->name, "mode")) {
- say_init_mode(v->value);
-@@ -515,8 +542,8 @@
- }
- }
-
-- ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
-- return ast_register_application(app, playback_exec, synopsis, descrip);
-+ ast_cli_register_multiple(cli_playback, ARRAY_LEN(cli_playback));
-+ return ast_register_application_xml(app, playback_exec);
- }
-
- AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
-Index: apps/app_speech_utils.c
-===================================================================
---- a/apps/app_speech_utils.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_speech_utils.c (.../team/group/issue14292) (revision 178988)
-@@ -37,63 +37,214 @@
- #include "asterisk/app.h"
- #include "asterisk/speech.h"
-
--/* Descriptions for each application */
--static char *speechcreate_descrip =
--" SpeechCreate(engine name):\n"
--"This application creates information to be used by all the other applications.\n"
--"It must be called before doing any speech recognition activities such as activating a grammar.\n"
--"It takes the engine name to use as the argument, if not specified the default engine will be used.\n";
-+/*** DOCUMENTATION
-+ <application name="SpeechCreate" language="en_US">
-+ <synopsis>
-+ Create a Speech Structure.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="engine_name" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application creates information to be used by all the other applications.
-+ It must be called before doing any speech recognition activities such as activating a grammar.
-+ It takes the engine name to use as the argument, if not specified the default engine will be used.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechActivateGrammar" language="en_US">
-+ <synopsis>
-+ Activate a grammar.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="grammar_name" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This activates the specified grammar to be recognized by the engine.
-+ A grammar tells the speech recognition engine what to recognize, and how to portray it back to you
-+ in the dialplan. The grammar name is the only argument to this application.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechStart" language="en_US">
-+ <synopsis>
-+ Start recognizing voice in the audio stream.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Tell the speech recognition engine that it should start trying to get results from audio being
-+ fed to it.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechBackground" language="en_US">
-+ <synopsis>
-+ Play a sound file and wait for speech to be recognized.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="sound_file" required="true" />
-+ <parameter name="timeout">
-+ <para>Timeout integer in seconds. Note the timeout will only start
-+ once the sound file has stopped playing.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="n">
-+ <para>Don't answer the channel if it has not already been answered.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application plays a sound file and waits for the person to speak. Once they start speaking playback
-+ of the file stops, and silence is heard. Once they stop talking the processing sound is played to indicate
-+ the speech recognition engine is working. Once results are available the application returns and results
-+ (score and text) are available using dialplan functions.</para>
-+ <para>The first text and score are ${SPEECH_TEXT(0)} AND ${SPEECH_SCORE(0)} while the second are ${SPEECH_TEXT(1)}
-+ and ${SPEECH_SCORE(1)}.</para>
-+ <para>The first argument is the sound file and the second is the timeout integer in seconds.</para>
-+
-+ </description>
-+ </application>
-+ <application name="SpeechDeactivateGrammar" language="en_US">
-+ <synopsis>
-+ Deactivate a grammar.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="grammar_name" required="true">
-+ <para>The grammar name to deactivate</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This deactivates the specified grammar so that it is no longer recognized.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechProcessingSound" language="en_US">
-+ <synopsis>
-+ Change background processing sound.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="sound_file" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This changes the processing sound that SpeechBackground plays back when the speech recognition engine is
-+ processing and working to get results.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechDestroy" language="en_US">
-+ <synopsis>
-+ End speech recognition.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>This destroys the information used by all the other speech recognition applications.
-+ If you call this application but end up wanting to recognize more speech, you must call SpeechCreate()
-+ again before calling any other application.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechLoadGrammar" language="en_US">
-+ <synopsis>
-+ Load a grammar.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="grammar_name" required="true" />
-+ <parameter name="path" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Load a grammar only on the channel, not globally.</para>
-+ </description>
-+ </application>
-+ <application name="SpeechUnloadGrammar" language="en_US">
-+ <synopsis>
-+ Unload a grammar.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="grammar_name" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Unload a grammar.</para>
-+ </description>
-+ </application>
-+ <function name="SPEECH_SCORE" language="en_US">
-+ <synopsis>
-+ Gets the confidence score of a result.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="nbest_number" />
-+ <parameter name="result_number" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Gets the confidence score of a result.</para>
-+ </description>
-+ </function>
-+ <function name="SPEECH_TEXT" language="en_US">
-+ <synopsis>
-+ Gets the recognized text of a result.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="nbest_number" />
-+ <parameter name="result_number" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Gets the recognized text of a result.</para>
-+ </description>
-+ </function>
-+ <function name="SPEECH_GRAMMAR" language="en_US">
-+ <synopsis>
-+ Gets the matched grammar of a result if available.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="nbest_number" />
-+ <parameter name="result_number" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Gets the matched grammar of a result if available.</para>
-+ </description>
-+ </function>
-+ <function name="SPEECH_ENGINE" language="en_US">
-+ <synopsis>
-+ Change a speech engine specific attribute.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="name" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Changes a speech engine specific attribute.</para>
-+ </description>
-+ </function>
-+ <function name="SPEECH_RESULTS_TYPE" language="en_US">
-+ <synopsis>
-+ Sets the type of results that will be returned.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Sets the type of results that will be returned. Valid options are normal or nbest.</para>
-+ </description>
-+ </function>
-+ <function name="SPEECH" language="en_US">
-+ <synopsis>
-+ Gets information about speech recognition results.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="argument" required="true">
-+ <enumlist>
-+ <enum name="status">
-+ <para>Returns <literal>1</literal> upon speech object existing,
-+ or <literal>0</literal> if not</para>
-+ </enum>
-+ <enum name="spoke">
-+ <para>Returns <literal>1</literal> if spoker spoke,
-+ or <literal>0</literal> if not</para>
-+ </enum>
-+ <enum name="results">
-+ <para>Returns number of results that were recognized.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Gets information about speech recognition results.</para>
-+ </description>
-+ </function>
-+ ***/
-
--static char *speechactivategrammar_descrip =
--" SpeechActivateGrammar(Grammar Name):\n"
--"This activates the specified grammar to be recognized by the engine.\n"
--"A grammar tells the speech recognition engine what to recognize, and how to portray it back to you \n"
--"in the dialplan. The grammar name is the only argument to this application.\n";
--
--static char *speechstart_descrip =
--" SpeechStart():\n"
--"Tell the speech recognition engine that it should start trying to get results from audio being \n"
--"fed to it. This has no arguments.\n";
--
--static char *speechbackground_descrip =
--" SpeechBackground(<Sound File>[,Timeout[,options]]):\n"
--"This application plays a sound file and waits for the person to speak. Once they start speaking playback\n"
--"of the file stops, and silence is heard. Once they stop talking the processing sound is played to indicate\n"
--"the speech recognition engine is working. Once results are available the application returns and results \n"
--"(score and text) are available using dialplan functions.\n"
--" The first text and score are ${SPEECH_TEXT(0)} AND ${SPEECH_SCORE(0)} while the second are ${SPEECH_TEXT(1)}\n"
--"and ${SPEECH_SCORE(1)}.\n"
--" The first argument is the sound file and the second is the timeout integer in seconds. Note the timeout will\n"
--"only start once the sound file has stopped playing. The third argument specifies options:\n"
--" Valid Options:\n"
--" n - Don't answer the channel if it has not already been answered.\n";
--
--static char *speechdeactivategrammar_descrip =
--" SpeechDeactivateGrammar(Grammar Name):\n"
--"This deactivates the specified grammar so that it is no longer recognized.\n"
--"The only argument is the grammar name to deactivate.\n";
--
--static char *speechprocessingsound_descrip =
--" SpeechProcessingSound(Sound File):\n"
--"This changes the processing sound that SpeechBackground plays back when the speech recognition engine is\n"
--"processing and working to get results.\n"
--"It takes the sound file as the only argument.\n";
--
--static char *speechdestroy_descrip =
--" SpeechDestroy():\n"
--"This destroys the information used by all the other speech recognition applications.\n"
--"If you call this application but end up wanting to recognize more speech, you must call SpeechCreate\n"
-- "again before calling any other application. It takes no arguments.\n";
--
--static char *speechload_descrip =
--" SpeechLoadGrammar(Grammar Name,Path):\n"
--"Load a grammar only on the channel, not globally.\n"
--"It takes the grammar name as first argument and path as second.\n";
--
--static char *speechunload_descrip =
--" SpeechUnloadGrammar(Grammar Name):\n"
--"Unload a grammar. It takes the grammar name as the only argument.\n";
--
- /*! \brief Helper function used by datastores to destroy the speech structure upon hangup */
- static void destroy_callback(void *data)
- {
-@@ -181,10 +332,6 @@
-
- static struct ast_custom_function speech_score_function = {
- .name = "SPEECH_SCORE",
-- .synopsis = "Gets the confidence score of a result.",
-- .syntax = "SPEECH_SCORE([nbest number/]result number)",
-- .desc =
-- "Gets the confidence score of a result.\n",
- .read = speech_score,
- .write = NULL,
- };
-@@ -211,10 +358,6 @@
-
- static struct ast_custom_function speech_text_function = {
- .name = "SPEECH_TEXT",
-- .synopsis = "Gets the recognized text of a result.",
-- .syntax = "SPEECH_TEXT([nbest number/]result number)",
-- .desc =
-- "Gets the recognized text of a result.\n",
- .read = speech_text,
- .write = NULL,
- };
-@@ -241,10 +384,6 @@
-
- static struct ast_custom_function speech_grammar_function = {
- .name = "SPEECH_GRAMMAR",
-- .synopsis = "Gets the matched grammar of a result if available.",
-- .syntax = "SPEECH_GRAMMAR([nbest number/]result number)",
-- .desc =
-- "Gets the matched grammar of a result if available.\n",
- .read = speech_grammar,
- .write = NULL,
- };
-@@ -265,10 +404,6 @@
-
- static struct ast_custom_function speech_engine_function = {
- .name = "SPEECH_ENGINE",
-- .synopsis = "Change a speech engine specific attribute.",
-- .syntax = "SPEECH_ENGINE(name)=value",
-- .desc =
-- "Changes a speech engine specific attribute.\n",
- .read = NULL,
- .write = speech_engine_write,
- };
-@@ -291,10 +426,6 @@
-
- static struct ast_custom_function speech_results_type_function = {
- .name = "SPEECH_RESULTS_TYPE",
-- .synopsis = "Sets the type of results that will be returned.",
-- .syntax = "SPEECH_RESULTS_TYPE()=results type",
-- .desc =
-- "Sets the type of results that will be returned. Valid options are normal or nbest.",
- .read = NULL,
- .write = speech_results_type_write,
- };
-@@ -343,13 +474,6 @@
-
- static struct ast_custom_function speech_function = {
- .name = "SPEECH",
-- .synopsis = "Gets information about speech recognition results.",
-- .syntax = "SPEECH(argument)",
-- .desc =
-- "Gets information about speech recognition results.\n"
-- "status: Returns 1 upon speech object existing, or 0 if not\n"
-- "spoke: Returns 1 if spoker spoke, or 0 if not\n"
-- "results: Returns number of results that were recognized\n",
- .read = speech_read,
- .write = NULL,
- };
-@@ -376,6 +500,7 @@
- pbx_builtin_setvar_helper(chan, "ERROR", "1");
- return 0;
- }
-+ pbx_builtin_setvar_helper(chan, "ERROR", NULL);
- datastore->data = speech;
- ast_channel_datastore_add(chan, datastore);
-
-@@ -810,15 +935,15 @@
- {
- int res = 0;
-
-- res = ast_register_application("SpeechCreate", speech_create, "Create a Speech Structure", speechcreate_descrip);
-- res |= ast_register_application("SpeechLoadGrammar", speech_load, "Load a Grammar", speechload_descrip);
-- res |= ast_register_application("SpeechUnloadGrammar", speech_unload, "Unload a Grammar", speechunload_descrip);
-- res |= ast_register_application("SpeechActivateGrammar", speech_activate, "Activate a Grammar", speechactivategrammar_descrip);
-- res |= ast_register_application("SpeechDeactivateGrammar", speech_deactivate, "Deactivate a Grammar", speechdeactivategrammar_descrip);
-- res |= ast_register_application("SpeechStart", speech_start, "Start recognizing voice in the audio stream", speechstart_descrip);
-- res |= ast_register_application("SpeechBackground", speech_background, "Play a sound file and wait for speech to be recognized", speechbackground_descrip);
-- res |= ast_register_application("SpeechDestroy", speech_destroy, "End speech recognition", speechdestroy_descrip);
-- res |= ast_register_application("SpeechProcessingSound", speech_processing_sound, "Change background processing sound", speechprocessingsound_descrip);
-+ res = ast_register_application_xml("SpeechCreate", speech_create);
-+ res |= ast_register_application_xml("SpeechLoadGrammar", speech_load);
-+ res |= ast_register_application_xml("SpeechUnloadGrammar", speech_unload);
-+ res |= ast_register_application_xml("SpeechActivateGrammar", speech_activate);
-+ res |= ast_register_application_xml("SpeechDeactivateGrammar", speech_deactivate);
-+ res |= ast_register_application_xml("SpeechStart", speech_start);
-+ res |= ast_register_application_xml("SpeechBackground", speech_background);
-+ res |= ast_register_application_xml("SpeechDestroy", speech_destroy);
-+ res |= ast_register_application_xml("SpeechProcessingSound", speech_processing_sound);
- res |= ast_custom_function_register(&speech_function);
- res |= ast_custom_function_register(&speech_score_function);
- res |= ast_custom_function_register(&speech_text_function);
-Index: apps/app_osplookup.c
-===================================================================
---- a/apps/app_osplookup.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_osplookup.c (.../team/group/issue14292) (revision 178988)
-@@ -30,7 +30,7 @@
-
- /*** MODULEINFO
- <depend>osptk</depend>
-- <depend>ssl</depend>
-+ <depend>openssl</depend>
- ***/
-
- #include "asterisk.h"
-@@ -713,7 +713,7 @@
- unsigned int* timelimit)
- {
- int res;
-- struct osp_provider* p;
-+ struct osp_provider* p = NULL;
- char dest[OSP_NORSTR_SIZE];
-
- *transaction = OSP_INVALID_HANDLE;
-@@ -861,7 +861,7 @@
- struct osp_result* result)
- {
- int res;
-- struct osp_provider* p;
-+ struct osp_provider* p = NULL;
- char source[OSP_NORSTR_SIZE];
- char callingnum[OSP_NORSTR_SIZE];
- char callednum[OSP_NORSTR_SIZE];
-@@ -1076,7 +1076,7 @@
- struct osp_result* result)
- {
- int res;
-- struct osp_provider* p;
-+ struct osp_provider* p = NULL;
- char callingnum[OSP_NORSTR_SIZE];
- char callednum[OSP_NORSTR_SIZE];
- char destination[OSP_NORSTR_SIZE];
-@@ -1776,8 +1776,12 @@
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- int error = OSPC_ERR_NO_ERROR;
-
-- if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
-+ if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == 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", OSP_CONFIG_FILE);
-+ return 0;
-+ }
-
- if (cfg) {
- if (reload)
-Index: apps/app_sendtext.c
-===================================================================
---- a/apps/app_sendtext.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_sendtext.c (.../team/group/issue14292) (revision 178988)
-@@ -37,20 +37,41 @@
- #include "asterisk/module.h"
- #include "asterisk/app.h"
-
-+/*** DOCUMENTATION
-+ <application name="SendText" language="en_US">
-+ <synopsis>
-+ Send a Text Message.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="text" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Sends <replaceable>text</replaceable> to current channel (callee).</para>
-+ <para>Result of transmission will be stored in the <variable>SENDTEXTSTATUS</variable></para>
-+ <variablelist>
-+ <variable name="SENDTEXTSTATUS">
-+ <value name="SUCCESS">
-+ Transmission succeeded.
-+ </value>
-+ <value name="FAILURE">
-+ Transmission failed.
-+ </value>
-+ <value name="UNSUPPORTED">
-+ Text transmission not supported by channel.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ <note><para>At this moment, text is supposed to be 7 bit ASCII in most channels.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="application">SendImage</ref>
-+ <ref type="application">SendURL</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- static const char *app = "SendText";
-
--static const char *synopsis = "Send a Text Message";
--
--static const char *descrip =
--" SendText(text): Sends text to current channel (callee).\n"
--"Result of transmission will be stored in the SENDTEXTSTATUS\n"
--"channel variable:\n"
--" SUCCESS Transmission succeeded\n"
--" FAILURE Transmission failed\n"
--" UNSUPPORTED Text transmission not supported by channel\n"
--"\n"
--"At this moment, text is supposed to be 7 bit ASCII in most channels.\n";
--
- static int sendtext_exec(struct ast_channel *chan, void *data)
- {
- int res = 0;
-@@ -91,7 +112,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, sendtext_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, sendtext_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send Text Applications");
-Index: apps/app_amd.c
-===================================================================
---- a/apps/app_amd.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_amd.c (.../team/group/issue14292) (revision 178988)
-@@ -39,45 +39,92 @@
- #include "asterisk/config.h"
- #include "asterisk/app.h"
-
-+/*** DOCUMENTATION
-+ <application name="AMD" language="en_US">
-+ <synopsis>
-+ Attempt to detect answering machines.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="initialSilence" required="false">
-+ <para>Is maximum initial silence duration before greeting.</para>
-+ <para>If this is exceeded set as MACHINE</para>
-+ </parameter>
-+ <parameter name="greeting" required="false">
-+ <para>is the maximum length of a greeting.</para>
-+ <para>If this is exceeded set as MACHINE</para>
-+ </parameter>
-+ <parameter name="afterGreetingSilence" required="false">
-+ <para>Is the silence after detecting a greeting.</para>
-+ <para>If this is exceeded set as HUMAN</para>
-+ </parameter>
-+ <parameter name="totalAnalysis Time" required="false">
-+ <para>Is the maximum time allowed for the algorithm</para>
-+ <para>to decide HUMAN or MACHINE</para>
-+ </parameter>
-+ <parameter name="miniumWordLength" required="false">
-+ <para>Is the minimum duration of Voice considered to be a word</para>
-+ </parameter>
-+ <parameter name="betweenWordSilence" required="false">
-+ <para>Is the minimum duration of silence after a word to
-+ consider the audio that follows to be a new word</para>
-+ </parameter>
-+ <parameter name="maximumNumberOfWords" required="false">
-+ <para>Is the maximum number of words in a greeting</para>
-+ <para>If this is exceeded set as MACHINE</para>
-+ </parameter>
-+ <parameter name="silenceThreshold" required="false">
-+ <para>How long do we consider silence</para>
-+ </parameter>
-+ <parameter name="maximumWordLength" required="false">
-+ <para>Is the maximum duration of a word to accept.</para>
-+ <para>If exceeded set as MACHINE</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application attempts to detect answering machines at the beginning
-+ of outbound calls. Simply call this application after the call
-+ has been answered (outbound only, of course).</para>
-+ <para>When loaded, AMD reads amd.conf and uses the parameters specified as
-+ default values. Those default values get overwritten when the calling AMD
-+ with parameters.</para>
-+ <para>This application sets the following channel variables:</para>
-+ <variablelist>
-+ <variable name="AMDSTATUS">
-+ <para>This is the status of the answering machine detection</para>
-+ <value name="MACHINE" />
-+ <value name="HUMAN" />
-+ <value name="NOTSURE" />
-+ <value name="HANGUP" />
-+ </variable>
-+ <variable name="AMDCAUSE">
-+ <para>Indicates the cause that led to the conclusion</para>
-+ <value name="TOOLONG">
-+ Total Time.
-+ </value>
-+ <value name="INITIALSILENCE">
-+ Silence Duration - Initial Silence.
-+ </value>
-+ <value name="HUMAN">
-+ Silence Duration - afterGreetingSilence.
-+ </value>
-+ <value name="LONGGREETING">
-+ Voice Duration - Greeting.
-+ </value>
-+ <value name="MAXWORDLENGTH">
-+ Word Count - maximum number of words.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">WaitForSilence</ref>
-+ <ref type="application">WaitForNoise</ref>
-+ </see-also>
-+ </application>
-
-+ ***/
-+
- static char *app = "AMD";
--static char *synopsis = "Attempts to detect answering machines";
--static char *descrip =
--" AMD([initialSilence],[greeting],[afterGreetingSilence],[totalAnalysisTime]\n"
--" ,[minimumWordLength],[betweenWordsSilence],[maximumNumberOfWords]\n"
--" ,[silenceThreshold],[|maximumWordLength])\n"
--" This application attempts to detect answering machines at the beginning\n"
--" of outbound calls. Simply call this application after the call\n"
--" has been answered (outbound only, of course).\n"
--" When loaded, AMD reads amd.conf and uses the parameters specified as\n"
--" default values. Those default values get overwritten when calling AMD\n"
--" with parameters.\n"
--"- 'initialSilence' is the maximum silence duration before the greeting. If\n"
--" exceeded then MACHINE.\n"
--"- 'greeting' is the maximum length of a greeting. If exceeded then MACHINE.\n"
--"- 'afterGreetingSilence' is the silence after detecting a greeting.\n"
--" If exceeded then HUMAN.\n"
--"- 'totalAnalysisTime' is the maximum time allowed for the algorithm to decide\n"
--" on a HUMAN or MACHINE.\n"
--"- 'minimumWordLength'is the minimum duration of Voice to considered as a word.\n"
--"- 'betweenWordsSilence' is the minimum duration of silence after a word to \n"
--" consider the audio that follows as a new word.\n"
--"- 'maximumNumberOfWords'is the maximum number of words in the greeting. \n"
--" If exceeded then MACHINE.\n"
--"- 'silenceThreshold' is the silence threshold.\n"
--"- 'maximumWordLength' is the maximum duration of a word to accept. If exceeded then MACHINE\n"
--"This application sets the following channel variables upon completion:\n"
--" AMDSTATUS - This is the status of the answering machine detection.\n"
--" Possible values are:\n"
--" MACHINE | HUMAN | NOTSURE | HANGUP\n"
--" AMDCAUSE - Indicates the cause that led to the conclusion.\n"
--" Possible values are:\n"
--" TOOLONG-<%d total_time>\n"
--" INITIALSILENCE-<%d silenceDuration>-<%d initialSilence>\n"
--" HUMAN-<%d silenceDuration>-<%d afterGreetingSilence>\n"
--" MAXWORDS-<%d wordsCount>-<%d maximumNumberOfWords>\n"
--" LONGGREETING-<%d voiceDuration>-<%d greeting>\n"
--" MAXWORDLENGTH-<%d consecutiveVoiceDuration>\n";
-
- #define STATE_IN_WORD 1
- #define STATE_IN_SILENCE 2
-@@ -376,8 +423,12 @@
- if (!(cfg = ast_config_load("amd.conf", config_flags))) {
- ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
- return -1;
-- } 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 amd.conf is in an invalid format. Aborting.\n");
-+ return -1;
-+ }
-
- cat = ast_category_browse(cfg, NULL);
-
-@@ -433,7 +484,7 @@
- {
- if (load_config(0))
- return AST_MODULE_LOAD_DECLINE;
-- if (ast_register_application(app, amd_exec, synopsis, descrip))
-+ if (ast_register_application_xml(app, amd_exec))
- return AST_MODULE_LOAD_FAILURE;
- return AST_MODULE_LOAD_SUCCESS;
- }
-Index: apps/app_url.c
-===================================================================
---- a/apps/app_url.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_url.c (.../team/group/issue14292) (revision 178988)
-@@ -34,25 +34,54 @@
- #include "asterisk/app.h"
- #include "asterisk/channel.h"
-
-+/*** DOCUMENTATION
-+ <application name="SendURL" language="en_US">
-+ <synopsis>
-+ Send a URL.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="URL" required="true" />
-+ <parameter name="option">
-+ <optionlist>
-+ <option name="w">
-+ <para>Execution will wait for an acknowledgement that the
-+ URL has been loaded before continuing.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Requests client go to <replaceable>URL</replaceable> (IAX2) or sends the
-+ URL to the client (other channels).</para>
-+ <para>Result is returned in the <variable>SENDURLSTATUS</variable> channel variable:</para>
-+ <variablelist>
-+ <variable name="SENDURLSTATUS">
-+ <value name="SUCCESS">
-+ URL successfully sent to client.
-+ </value>
-+ <value name="FAILURE">
-+ Failed to send URL.
-+ </value>
-+ <value name="NOLOAD">
-+ Client failed to load URL (wait enabled).
-+ </value>
-+ <value name="UNSUPPORTED">
-+ Channel does not support URL transport.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ <para>SendURL continues normally if the URL was sent correctly or if the channel
-+ does not support HTML transport. Otherwise, the channel is hung up.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">SendImage</ref>
-+ <ref type="application">SendText</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- static char *app = "SendURL";
-
--static char *synopsis = "Send a URL";
--
--static char *descrip =
--" SendURL(URL[,option]): Requests client go to URL (IAX2) or sends the \n"
--"URL to the client (other channels).\n"
--"Result is returned in the SENDURLSTATUS channel variable:\n"
--" SUCCESS URL successfully sent to client\n"
--" FAILURE Failed to send URL\n"
--" NOLOAD Client failed to load URL (wait enabled)\n"
--" UNSUPPORTED Channel does not support URL transport\n"
--"\n"
--"If the option 'w' is specified, execution will wait for an\n"
--"acknowledgement that the URL has been loaded before continuing\n"
--"\n"
--"SendURL continues normally if the URL was sent correctly or if the channel\n"
--"does not support HTML transport. Otherwise, the channel is hung up.\n";
--
- enum {
- OPTION_WAIT = (1 << 0),
- } option_flags;
-@@ -143,7 +172,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, sendurl_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, sendurl_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send URL Applications");
-Index: apps/app_externalivr.c
-===================================================================
---- a/apps/app_externalivr.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_externalivr.c (.../team/group/issue14292) (revision 178988)
-@@ -122,8 +122,8 @@
- ast_str_append(&tmp, 0, ",%s", data);
- }
-
-- fprintf(handle, "%s\n", tmp->str);
-- ast_debug(1, "sent '%s'\n", tmp->str);
-+ fprintf(handle, "%s\n", ast_str_buffer(tmp));
-+ ast_debug(1, "sent '%s'\n", ast_str_buffer(tmp));
- }
-
- static void *gen_alloc(struct ast_channel *chan, void *params)
-@@ -276,7 +276,7 @@
-
- ast_str_append(&newstring, 0, "%s=%s,", variable, value);
- ast_channel_unlock(chan);
-- ast_copy_string(outbuf, newstring->str, outbuflen);
-+ ast_copy_string(outbuf, ast_str_buffer(newstring), outbuflen);
- }
- }
-
-@@ -322,7 +322,7 @@
-
- static int app_exec(struct ast_channel *chan, void *data)
- {
-- struct ast_flags flags;
-+ struct ast_flags flags = { 0, };
- char *opts[0];
- struct playlist_entry *entry;
- int child_stdin[2] = { 0, 0 };
-@@ -659,7 +659,8 @@
- continue;
-
- if (input[0] == 'P') {
-- send_eivr_event(eivr_events, 'P', args->str, chan);
-+ struct ast_str *tmp = (struct ast_str *) args;
-+ send_eivr_event(eivr_events, 'P', ast_str_buffer(tmp), chan);
- } else if ( input[0] == 'T' ) {
- ast_chan_log(LOG_WARNING, chan, "Answering channel if needed and starting generator\n");
- if (chan->_state != AST_STATE_UP) {
-Index: apps/app_directory.c
-===================================================================
---- a/apps/app_directory.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_directory.c (.../team/group/issue14292) (revision 178988)
-@@ -42,49 +42,79 @@
- #include "asterisk/app.h"
- #include "asterisk/utils.h"
-
-+/*** DOCUMENTATION
-+ <application name="Directory" language="en_US">
-+ <synopsis>
-+ Provide directory of voicemail extensions.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="vm-context">
-+ <para>This is the context within voicemail.conf to use for the Directory. If not specified and
-+ <literal>searchcontexts=no</literal> in <filename>voicemail.conf</filename>, then <literal>default</literal>
-+ will be assumed.</para>
-+ </parameter>
-+ <parameter name="dial-context" required="false">
-+ <para>This is the dialplan context to use when looking for an
-+ extension that the user has selected, or when jumping to the
-+ <literal>o</literal> or <literal>a</literal> extension.</para>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="e">
-+ <para>In addition to the name, also read the extension number to the
-+ caller before presenting dialing options.</para>
-+ </option>
-+ <option name="f">
-+ <para>Allow the caller to enter the first name of a user in the
-+ directory instead of using the last name. If specified, the
-+ optional number argument will be used for the number of
-+ characters the user should enter.</para>
-+ <argument name="n" required="true" />
-+ </option>
-+ <option name="l">
-+ <para>Allow the caller to enter the last name of a user in the
-+ directory. This is the default. If specified, the
-+ optional number argument will be used for the number of
-+ characters the user should enter.</para>
-+ <argument name="n" required="true" />
-+ </option>
-+ <option name="b">
-+ <para> Allow the caller to enter either the first or the last name
-+ of a user in the directory. If specified, the optional number
-+ argument will be used for the number of characters the user should enter.</para>
-+ <argument name="n" required="true" />
-+ </option>
-+ <option name="m">
-+ <para>Instead of reading each name sequentially and asking for
-+ confirmation, create a menu of up to 8 names.</para>
-+ </option>
-+ <option name="p">
-+ <para>Pause for n milliseconds after the digits are typed. This is
-+ helpful for people with cellphones, who are not holding the
-+ receiver to their ear while entering DTMF.</para>
-+ <argument name="n" required="true" />
-+ </option>
-+ </optionlist>
-+ <note><para>Only one of the <replaceable>f</replaceable>, <replaceable>l</replaceable>, or <replaceable>b</replaceable>
-+ options may be specified. <emphasis>If more than one is specified</emphasis>, then Directory will act as
-+ if <replaceable>b</replaceable> was specified. The number
-+ of characters for the user to type defaults to <literal>3</literal>.</para></note>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will present the calling channel with a directory of extensions from which they can search
-+ by name. The list of names and corresponding extensions is retrieved from the
-+ voicemail configuration file, <filename>voicemail.conf</filename>.</para>
-+ <para>This application will immediately exit if one of the following DTMF digits are
-+ received and the extension to jump to exists:</para>
-+ <para><literal>0</literal> - Jump to the 'o' extension, if it exists.</para>
-+ <para><literal>*</literal> - Jump to the 'a' extension, if it exists.</para>
-+ </description>
-+ </application>
-+
-+ ***/
- static char *app = "Directory";
-
--static char *synopsis = "Provide directory of voicemail extensions";
--static char *descrip =
--" Directory(vm-context[,dial-context[,options]]): This application will present\n"
--"the calling channel with a directory of extensions from which they can search\n"
--"by name. The list of names and corresponding extensions is retrieved from the\n"
--"voicemail configuration file, voicemail.conf.\n"
--" This application will immediately exit if one of the following DTMF digits are\n"
--"received and the extension to jump to exists:\n"
--" 0 - Jump to the 'o' extension, if it exists.\n"
--" * - Jump to the 'a' extension, if it exists.\n\n"
--" Parameters:\n"
--" vm-context - This is the context within voicemail.conf to use for the\n"
--" Directory.\n"
--" dial-context - This is the dialplan context to use when looking for an\n"
--" extension that the user has selected, or when jumping to the\n"
--" 'o' or 'a' extension.\n\n"
--" Options:\n"
--" e In addition to the name, also read the extension number to the\n"
--" caller before presenting dialing options.\n"
--" f[(<n>)] Allow the caller to enter the first name of a user in the\n"
--" directory instead of using the last name. If specified, the\n"
--" optional number argument will be used for the number of\n"
--" characters the user should enter.\n"
--" l[(<n>)] Allow the caller to enter the last name of a user in the\n"
--" directory. This is the default. If specified, the\n"
--" optional number argument will be used for the number of\n"
--" characters the user should enter.\n"
--" b[(<n>)] Allow the caller to enter either the first or the last name\n"
--" of a user in the directory. If specified, the optional number\n"
--" argument will be used for the number of characters the user\n"
--" should enter.\n"
--" m Instead of reading each name sequentially and asking for\n"
--" confirmation, create a menu of up to 8 names.\n"
--" p(<n>) Pause for n milliseconds after the digits are typed. This is\n"
--" helpful for people with cellphones, who are not holding the\n"
--" receiver to their ear while entering DTMF.\n"
--"\n"
--" Only one of the f, l, or b options may be specified. If more than one is\n"
--" specified, then Directory will act as if 'b' was specified. The number\n"
--" of characters for the user to type defaults to 3.\n";
--
- /* For simplicity, I'm keeping the format compatible with the voicemail config,
- but i'm open to suggestions for isolating it */
-
-@@ -112,6 +142,7 @@
- struct directory_item {
- char exten[AST_MAX_EXTENSION + 1];
- char name[AST_MAX_EXTENSION + 1];
-+ char context[AST_MAX_CONTEXT + 1];
- char key[50]; /* Text to order items. Either lastname+firstname or firstname+lastname */
-
- AST_LIST_ENTRY(directory_item) entry;
-@@ -234,25 +265,25 @@
- return res;
- }
-
--static int select_entry(struct ast_channel *chan, const char *context, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
-+static int select_entry(struct ast_channel *chan, const char *dialcontext, const struct directory_item *item, struct ast_flags *flags)
- {
-- ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, dialcontext);
-+ ast_debug(1, "Selecting '%s' - %s@%s\n", item->name, item->exten, S_OR(dialcontext, item->context));
-
- if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
- /* We still want to set the exten though */
- ast_copy_string(chan->exten, item->exten, sizeof(chan->exten));
-- } else if (ast_goto_if_exists(chan, dialcontext, item->exten, 1)) {
-+ } else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
- ast_log(LOG_WARNING,
- "Can't find extension '%s' in context '%s'. "
- "Did you pass the wrong context to Directory?\n",
-- item->exten, dialcontext);
-+ item->exten, S_OR(dialcontext, item->context));
- return -1;
- }
-
- return 0;
- }
-
--static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *context, const char *dialcontext, struct ast_flags *flags)
-+static int select_item_seq(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags)
- {
- struct directory_item *item, **ptr;
- int i, res, loop;
-@@ -261,7 +292,7 @@
- item = *ptr;
-
- for (loop = 3 ; loop > 0; loop--) {
-- res = play_mailbox_owner(chan, context, item->exten, item->name, flags);
-+ res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
-
- if (!res)
- res = ast_stream_and_wait(chan, "dir-instr", AST_DIGIT_ANY);
-@@ -270,7 +301,7 @@
- ast_stopstream(chan);
-
- if (res == '1') { /* Name selected */
-- return select_entry(chan, context, dialcontext, item, flags) ? -1 : 1;
-+ return select_entry(chan, dialcontext, item, flags) ? -1 : 1;
- } else if (res == '*') {
- /* Skip to next match in list */
- break;
-@@ -287,7 +318,7 @@
- return 0;
- }
-
--static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *context, const char *dialcontext, struct ast_flags *flags)
-+static int select_item_menu(struct ast_channel *chan, struct directory_item **items, int count, const char *dialcontext, struct ast_flags *flags)
- {
- struct directory_item **block, *item;
- int i, limit, res = 0;
-@@ -315,7 +346,7 @@
- if (!res)
- res = ast_waitstream(chan, AST_DIGIT_ANY);
- if (!res)
-- res = play_mailbox_owner(chan, context, item->exten, item->name, flags);
-+ res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
- if (!res)
- res = ast_waitstream(chan, AST_DIGIT_ANY);
- if (!res)
-@@ -334,7 +365,7 @@
- }
-
- if (res && res > '0' && res < '1' + limit) {
-- return select_entry(chan, context, dialcontext, block[res - '1'], flags) ? -1 : 1;
-+ return select_entry(chan, dialcontext, block[res - '1'], flags) ? -1 : 1;
- }
-
- if (res < 0)
-@@ -355,7 +386,7 @@
- struct ast_variable *var;
- char *mailbox;
- const char *fullname;
-- const char *hidefromdir;
-+ const char *hidefromdir, *searchcontexts = NULL;
- char tmp[100];
- struct ast_flags config_flags = { 0 };
-
-@@ -366,56 +397,74 @@
- /* Loading config failed. */
- ast_log(LOG_WARNING, "Loading config failed.\n");
- return NULL;
-+ } else if (cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
-+ return NULL;
- }
-
- /* Get realtime entries, categorized by their mailbox number
- and present in the requested context */
-- rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
-+ if (ast_strlen_zero(context) && (searchcontexts = ast_variable_retrieve(cfg, "general", "searchcontexts"))) {
-+ if (ast_true(searchcontexts)) {
-+ rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", SENTINEL);
-+ context = NULL;
-+ } else {
-+ rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", "default", SENTINEL);
-+ context = "default";
-+ }
-+ } else {
-+ rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, SENTINEL);
-+ }
-
- /* if there are no results, just return the entries from the config file */
-- if (!rtdata)
-+ if (!rtdata) {
- return cfg;
--
-- /* Does the context exist within the config file? If not, make one */
-- cat = ast_category_get(cfg, context);
-- if (!cat) {
-- cat = ast_category_new(context, "", 99999);
-- if (!cat) {
-- ast_log(LOG_WARNING, "Out of memory\n");
-- ast_config_destroy(cfg);
-- if (rtdata) {
-- ast_config_destroy(rtdata);
-- }
-- return NULL;
-- }
-- ast_category_append(cfg, cat);
- }
-
- mailbox = NULL;
- while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
-+ const char *context = ast_variable_retrieve(rtdata, mailbox, "context");
-+
- fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
- if (ast_true((hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir")))) {
- /* Skip hidden */
- continue;
- }
- snprintf(tmp, sizeof(tmp), "no-password,%s", S_OR(fullname, ""));
-- var = ast_variable_new(mailbox, tmp, "");
-- if (var)
-+
-+ /* Does the context exist within the config file? If not, make one */
-+ if (!(cat = ast_category_get(cfg, context))) {
-+ if (!(cat = ast_category_new(context, "", 99999))) {
-+ ast_log(LOG_WARNING, "Out of memory\n");
-+ ast_config_destroy(cfg);
-+ if (rtdata) {
-+ ast_config_destroy(rtdata);
-+ }
-+ return NULL;
-+ }
-+ ast_category_append(cfg, cat);
-+ }
-+
-+ if ((var = ast_variable_new(mailbox, tmp, ""))) {
- ast_variable_append(cat, var);
-- else
-+ } else {
- ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
-+ }
- }
- ast_config_destroy(rtdata);
-
- return cfg;
- }
-
--static int check_match(struct directory_item **result, const char *item_fullname, const char *item_ext, const char *pattern_ext, int use_first_name)
-+static int check_match(struct directory_item **result, const char *item_context, const char *item_fullname, const char *item_ext, const char *pattern_ext, int use_first_name)
- {
- struct directory_item *item;
- const char *key = NULL;
- int namelen;
-
-+ if (ast_strlen_zero(item_fullname)) {
-+ return 0;
-+ }
-
- /* Set key to last name or first name depending on search mode */
- if (!use_first_name)
-@@ -429,10 +478,13 @@
- if (compare(key, pattern_ext))
- return 0;
-
-+ ast_debug(1, "Found match %s@%s\n", item_ext, item_context);
-+
- /* Match */
- item = ast_calloc(1, sizeof(*item));
- if (!item)
- return -1;
-+ ast_copy_string(item->context, item_context, sizeof(item->context));
- ast_copy_string(item->name, item_fullname, sizeof(item->name));
- ast_copy_string(item->exten, item_ext, sizeof(item->exten));
-
-@@ -451,7 +503,7 @@
-
- typedef AST_LIST_HEAD_NOLOCK(, directory_item) itemlist;
-
--static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
-+static int search_directory_sub(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
- {
- struct ast_variable *v;
- char buf[AST_MAX_EXTENSION + 1], *pos, *bufptr, *cat;
-@@ -475,10 +527,10 @@
-
- res = 0;
- if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
-- res = check_match(&item, pos, v->name, ext, 0 /* use_first_name */);
-+ res = check_match(&item, context, pos, v->name, ext, 0 /* use_first_name */);
- }
- if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
-- res = check_match(&item, pos, v->name, ext, 1 /* use_first_name */);
-+ res = check_match(&item, context, pos, v->name, ext, 1 /* use_first_name */);
- }
-
- if (!res)
-@@ -504,10 +556,10 @@
-
- res = 0;
- if (ast_test_flag(&flags, OPT_LISTBYLASTNAME)) {
-- res = check_match(&item, position, cat, ext, 0 /* use_first_name */);
-+ res = check_match(&item, context, position, cat, ext, 0 /* use_first_name */);
- }
- if (!res && ast_test_flag(&flags, OPT_LISTBYFIRSTNAME)) {
-- res = check_match(&item, position, cat, ext, 1 /* use_first_name */);
-+ res = check_match(&item, context, position, cat, ext, 1 /* use_first_name */);
- }
-
- if (!res)
-@@ -521,6 +573,35 @@
- return 0;
- }
-
-+static int search_directory(const char *context, struct ast_config *vmcfg, struct ast_config *ucfg, const char *ext, struct ast_flags flags, itemlist *alist)
-+{
-+ const char *searchcontexts = ast_variable_retrieve(vmcfg, "general", "searchcontexts");
-+ if (ast_strlen_zero(context)) {
-+ if (!ast_strlen_zero(searchcontexts) && ast_true(searchcontexts)) {
-+ /* Browse each context for a match */
-+ int res;
-+ const char *catg;
-+ for (catg = ast_category_browse(vmcfg, NULL); catg; catg = ast_category_browse(vmcfg, catg)) {
-+ if (!strcmp(catg, "general") || !strcmp(catg, "zonemessages")) {
-+ continue;
-+ }
-+
-+ if ((res = search_directory_sub(catg, vmcfg, ucfg, ext, flags, alist))) {
-+ return res;
-+ }
-+ }
-+ return 0;
-+ } else {
-+ ast_debug(1, "Searching by category default\n");
-+ return search_directory_sub("default", vmcfg, ucfg, ext, flags, alist);
-+ }
-+ } else {
-+ /* Browse only the listed context for a match */
-+ ast_debug(1, "Searching by category %s\n", context);
-+ return search_directory_sub(context, vmcfg, ucfg, ext, flags, alist);
-+ }
-+}
-+
- static void sort_items(struct directory_item **sorted, int count)
- {
- int reordered, i;
-@@ -565,18 +646,11 @@
- int count, i;
- char ext[10] = "";
-
-- if (ast_strlen_zero(context)) {
-- ast_log(LOG_WARNING,
-- "Directory must be called with an argument "
-- "(context in which to interpret extensions)\n");
-- return -1;
-- }
--
-- if (digit == '0' && !goto_exten(chan, dialcontext, "o")) {
-+ if (digit == '0' && !goto_exten(chan, S_OR(dialcontext, "default"), "o")) {
- return 0;
- }
-
-- if (digit == '*' && !goto_exten(chan, dialcontext, "a")) {
-+ if (digit == '*' && !goto_exten(chan, S_OR(dialcontext, "default"), "a")) {
- return 0;
- }
-
-@@ -614,16 +688,16 @@
- if (option_debug) {
- ast_debug(2, "Listing matching entries:\n");
- for (ptr = sorted, i = 0; i < count; i++, ptr++) {
-- ast_log(LOG_DEBUG, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
-+ ast_debug(2, "%s: %s\n", ptr[0]->exten, ptr[0]->name);
- }
- }
-
- if (ast_test_flag(flags, OPT_SELECTFROMMENU)) {
- /* Offer multiple entries at the same time */
-- res = select_item_menu(chan, sorted, count, context, dialcontext, flags);
-+ res = select_item_menu(chan, sorted, count, dialcontext, flags);
- } else {
- /* Offer entries one by one */
-- res = select_item_seq(chan, sorted, count, context, dialcontext, flags);
-+ res = select_item_seq(chan, sorted, count, dialcontext, flags);
- }
-
- if (!res) {
-@@ -645,7 +719,7 @@
- int res = 0, digit = 3;
- struct ast_config *cfg, *ucfg;
- const char *dirintro;
-- char *parse, *opts[OPT_ARG_ARRAY_SIZE];
-+ char *parse, *opts[OPT_ARG_ARRAY_SIZE] = { 0, };
- struct ast_flags flags = { 0 };
- struct ast_flags config_flags = { 0 };
- enum { FIRST, LAST, BOTH } which = LAST;
-@@ -656,11 +730,6 @@
- AST_APP_ARG(options);
- );
-
-- if (ast_strlen_zero(data)) {
-- ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
-- return -1;
-- }
--
- parse = ast_strdupa(data);
-
- AST_STANDARD_APP_ARGS(args, parse);
-@@ -668,16 +737,15 @@
- if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
- return -1;
-
-- if (ast_strlen_zero(args.dialcontext))
-- args.dialcontext = args.vmcontext;
--
-- cfg = realtime_directory(args.vmcontext);
-- if (!cfg) {
-+ if (!(cfg = realtime_directory(args.vmcontext))) {
- ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
- return -1;
- }
-
-- 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");
-+ ucfg = NULL;
-+ }
-
- dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
- if (ast_strlen_zero(dirintro))
-@@ -772,7 +840,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, directory_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, directory_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");
-Index: apps/app_while.c
-===================================================================
---- a/apps/app_while.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_while.c (.../team/group/issue14292) (revision 178988)
-@@ -33,29 +33,72 @@
- #include "asterisk/module.h"
- #include "asterisk/channel.h"
-
-+/*** DOCUMENTATION
-+ <application name="While" language="en_US">
-+ <synopsis>
-+ Start a while loop.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="expr" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Start a While Loop. Execution will return to this point when
-+ <literal>EndWhile()</literal> is called until expr is no longer true.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">EndWhile</ref>
-+ <ref type="application">ExitWhile</ref>
-+ <ref type="application">ContinueWhile</ref>
-+ </see-also>
-+ </application>
-+ <application name="EndWhile" language="en_US">
-+ <synopsis>
-+ End a while loop.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Return to the previous called <literal>While()</literal>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">While</ref>
-+ <ref type="application">ExitWhile</ref>
-+ <ref type="application">ContinueWhile</ref>
-+ </see-also>
-+ </application>
-+ <application name="ExitWhile" language="en_US">
-+ <synopsis>
-+ End a While loop.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Exits a <literal>While()</literal> loop, whether or not the conditional has been satisfied.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">While</ref>
-+ <ref type="application">EndWhile</ref>
-+ <ref type="application">ContinueWhile</ref>
-+ </see-also>
-+ </application>
-+ <application name="ContinueWhile" language="en_US">
-+ <synopsis>
-+ Restart a While loop.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Returns to the top of the while loop and re-evaluates the conditional.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">While</ref>
-+ <ref type="application">EndWhile</ref>
-+ <ref type="application">ExitWhile</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- static char *start_app = "While";
--static char *start_desc =
--" While(<expr>): Start a While Loop. Execution will return to this\n"
--"point when EndWhile() is called until expr is no longer true.\n";
--
--static char *start_synopsis = "Start a while loop";
--
--
- static char *stop_app = "EndWhile";
--static char *stop_desc =
--" EndWhile(): Return to the previous called While()\n";
--
--static char *stop_synopsis = "End a while loop";
--
- static char *exit_app = "ExitWhile";
--static char *exit_desc =
--" ExitWhile(): Exits a While() loop, whether or not the conditional has been satisfied.\n";
--static char *exit_synopsis = "End a While loop";
--
- static char *continue_app = "ContinueWhile";
--static char *continue_desc =
--" ContinueWhile(): Returns to the top of the while loop and re-evaluates the conditional.\n";
--static char *continue_synopsis = "Restart a While loop";
-
- #define VAR_SIZE 64
-
-@@ -300,10 +343,10 @@
- {
- int res;
-
-- res = ast_register_application(start_app, while_start_exec, start_synopsis, start_desc);
-- res |= ast_register_application(stop_app, while_end_exec, stop_synopsis, stop_desc);
-- res |= ast_register_application(exit_app, while_exit_exec, exit_synopsis, exit_desc);
-- res |= ast_register_application(continue_app, while_continue_exec, continue_synopsis, continue_desc);
-+ res = ast_register_application_xml(start_app, while_start_exec);
-+ res |= ast_register_application_xml(stop_app, while_end_exec);
-+ res |= ast_register_application_xml(exit_app, while_exit_exec);
-+ res |= ast_register_application_xml(continue_app, while_continue_exec);
-
- return res;
- }
-Index: apps/app_dahdibarge.c
-===================================================================
---- a/apps/app_dahdibarge.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_dahdibarge.c (.../team/group/issue14292) (revision 178988)
-@@ -52,17 +52,26 @@
- #include "asterisk/say.h"
- #include "asterisk/utils.h"
-
-+/*** DOCUMENTATION
-+ <application name="DAHDIBarge" language="en_US">
-+ <synopsis>
-+ Barge in (monitor) DAHDI channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channel">
-+ <para>Channel to barge.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Barges in on a specified DAHDI <replaceable>channel</replaceable> or prompts
-+ if one is not specified. Returns <literal>-1</literal> when caller user hangs
-+ up and is independent of the state of the channel being monitored.
-+ </para>
-+ </description>
-+ </application>
-+ ***/
- static char *app = "DAHDIBarge";
-
--static char *synopsis = "Barge in (monitor) DAHDI channel";
--
--static char *descrip =
--" DAHDIBarge([channel]): Barges in on a specified DAHDI\n"
--"channel or prompts if one is not specified. Returns\n"
--"-1 when caller user hangs up and is independent of the\n"
--"state of the channel being monitored.";
--
--
- #define CONF_SIZE 160
-
- static int careful_write(int fd, unsigned char *data, int len)
-@@ -293,7 +302,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, "Barge in on DAHDI channel application");
-Index: apps/app_privacy.c
-===================================================================
---- a/apps/app_privacy.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_privacy.c (.../team/group/issue14292) (revision 178988)
-@@ -41,26 +41,45 @@
- #include "asterisk/app.h"
- #include "asterisk/config.h"
-
--static char *app = "PrivacyManager";
-+/*** DOCUMENTATION
-+ <application name="PrivacyManager" language="en_US">
-+ <synopsis>
-+ Require phone number to be entered, if no CallerID sent
-+ </synopsis>
-+ <syntax>
-+ <parameter name="maxretries">
-+ <para>Total tries caller is allowed to input a callerid. Defaults to <literal>3</literal>.</para>
-+ </parameter>
-+ <parameter name="minlength">
-+ <para>Minimum allowable digits in the input callerid number. Defaults to <literal>10</literal>.</para>
-+ </parameter>
-+ <parameter name="context">
-+ <para>Context to check the given callerid against patterns.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>If no Caller*ID is sent, PrivacyManager answers the channel and asks
-+ the caller to enter their phone number. The caller is given
-+ <replaceable>maxretries</replaceable> attempts to do so. The application does
-+ <emphasis>nothing</emphasis> if Caller*ID was received on the channel.</para>
-+ <para>The application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="PRIVACYMGRSTATUS">
-+ <para>The status of the privacy manager's attempt to collect a phone number from the user.</para>
-+ <value name="SUCCESS"/>
-+ <value name="FAILED"/>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">Zapateller</ref>
-+ </see-also>
-+ </application>
-+ ***/
-
--static char *synopsis = "Require phone number to be entered, if no CallerID sent";
-
--static char *descrip =
-- " PrivacyManager([maxretries][,minlength][,context]): If no Caller*ID \n"
-- "is sent, PrivacyManager answers the channel and asks the caller to\n"
-- "enter their phone number. The caller is given 'maxretries' attempts to do so.\n"
-- "The application does nothing if Caller*ID was received on the channel.\n"
-- " maxretries default 3 -maximum number of attempts the caller is allowed \n"
-- " to input a callerid.\n"
-- " minlength default 10 -minimum allowable digits in the input callerid number.\n"
-- " context context to check the given Caller*ID against patterns.\n"
-- "The application sets the following channel variable upon completion: \n"
-- "PRIVACYMGRSTATUS The status of the privacy manager's attempt to collect \n"
-- " a phone number from the user. A text string that is either:\n"
-- " SUCCESS | FAILED \n"
--;
-+static char *app = "PrivacyManager";
-
--
- static int privacy_exec (struct ast_channel *chan, void *data)
- {
- int res=0;
-@@ -178,7 +197,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, privacy_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, privacy_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");
-Index: apps/app_record.c
-===================================================================
---- a/apps/app_record.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_record.c (.../team/group/issue14292) (revision 178988)
-@@ -36,35 +36,78 @@
- #include "asterisk/channel.h"
- #include "asterisk/dsp.h" /* use dsp routines for silence detection */
-
-+/*** DOCUMENTATION
-+ <application name="Record" language="en_US">
-+ <synopsis>
-+ Record to a file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true" argsep=".">
-+ <argument name="filename" required="true" />
-+ <argument name="format" required="true">
-+ <para>Is the format of the file type to be recorded (wav, gsm, etc).</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="silence">
-+ <para>Is the number of seconds of silence to allow before returning.</para>
-+ </parameter>
-+ <parameter name="maxduration">
-+ <para>Is the maximum recording duration in seconds. If missing
-+ or 0 there is no maximum.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="a">
-+ <para>Append to existing recording rather than replacing.</para>
-+ </option>
-+ <option name="n">
-+ <para>Do not answer, but record anyway if line not yet answered.</para>
-+ </option>
-+ <option name="q">
-+ <para>quiet (do not play a beep tone).</para>
-+ </option>
-+ <option name="s">
-+ <para>skip recording if the line is not yet answered.</para>
-+ </option>
-+ <option name="t">
-+ <para>use alternate '*' terminator key (DTMF) instead of default '#'</para>
-+ </option>
-+ <option name="x">
-+ <para>Ignore all terminator keys (DTMF) and keep recording until hangup.</para>
-+ </option>
-+ <option name="k">
-+ <para>Keep recording if channel hangs up.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>If filename contains <literal>%d</literal>, these characters will be replaced with a number
-+ incremented by one each time the file is recorded.
-+ Use <astcli>core show file formats</astcli> to see the available formats on your system
-+ User can press <literal>#</literal> to terminate the recording and continue to the next priority.
-+ If the user hangs up during a recording, all data will be lost and the application will terminate.</para>
-+ <variablelist>
-+ <variable name="RECORDED_FILE">
-+ <para>Will be set to the final filename of the recording.</para>
-+ </variable>
-+ <variable name="RECORD_STATUS">
-+ <para>This is the final status of the command</para>
-+ <value name="DTMF">A terminating DTMF was received ('#' or '*', depending upon option 't')</value>
-+ <value name="SILENCE">The maximum silence occurred in the recording.</value>
-+ <value name="SKIP">The line was not yet answered and the 's' option was specified.</value>
-+ <value name="TIMEOUT">The maximum length was reached.</value>
-+ <value name="HANGUP">The channel was hung up.</value>
-+ <value name="ERROR">An unrecoverable error occurred, which resulted in a WARNING to the logs.</value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-
-+ ***/
-+
- static char *app = "Record";
-
--static char *synopsis = "Record to a file";
--
--static char *descrip =
--" Record(filename.format,silence[,maxduration][,options])\n\n"
--"Records from the channel into a given filename. If the file exists it will\n"
--"be overwritten.\n"
--"- 'format' is the format of the file type to be recorded (wav, gsm, etc).\n"
--"- 'silence' is the number of seconds of silence to allow before returning.\n"
--"- 'maxduration' is the maximum recording duration in seconds. If missing\n"
--"or 0 there is no maximum.\n"
--"- 'options' may contain any of the following letters:\n"
--" 'a' : append to existing recording rather than replacing\n"
--" 'n' : do not answer, but record anyway if line not yet answered\n"
--" 'q' : quiet (do not play a beep tone)\n"
--" 's' : skip recording if the line is not yet answered\n"
--" 't' : use alternate '*' terminator key (DTMF) instead of default '#'\n"
--" 'x' : ignore all terminator keys (DTMF) and keep recording until hangup\n"
--"\n"
--"If filename contains '%d', these characters will be replaced with a number\n"
--"incremented by one each time the file is recorded. A channel variable\n"
--"named RECORDED_FILE will also be set, which contains the final filemname.\n\n"
--"Use 'core show file formats' to see the available formats on your system\n\n"
--"User can press '#' to terminate the recording and continue to the next priority.\n\n"
--"If the user should hangup during a recording, all data will be lost and the\n"
--"application will teminate. \n";
--
- enum {
- OPTION_APPEND = (1 << 0),
- OPTION_NOANSWER = (1 << 1),
-@@ -72,11 +115,13 @@
- OPTION_SKIP = (1 << 3),
- OPTION_STAR_TERMINATE = (1 << 4),
- OPTION_IGNORE_TERMINATE = (1 << 5),
-- FLAG_HAS_PERCENT = (1 << 6),
-+ OPTION_KEEP = (1 << 6),
-+ FLAG_HAS_PERCENT = (1 << 7),
- };
-
- AST_APP_OPTIONS(app_opts,{
- AST_APP_OPTION('a', OPTION_APPEND),
-+ AST_APP_OPTION('k', OPTION_KEEP),
- AST_APP_OPTION('n', OPTION_NOANSWER),
- AST_APP_OPTION('q', OPTION_QUIET),
- AST_APP_OPTION('s', OPTION_SKIP),
-@@ -119,6 +164,7 @@
- /* The next few lines of code parse out the filename and header from the input string */
- if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
- ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- return -1;
- }
-
-@@ -140,6 +186,7 @@
- }
- if (!ext) {
- ast_log(LOG_WARNING, "No extension specified to filename!\n");
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- return -1;
- }
- if (args.silence) {
-@@ -206,6 +253,7 @@
- if (chan->_state != AST_STATE_UP) {
- if (ast_test_flag(&flags, OPTION_SKIP)) {
- /* At the user's option, skip if the line is not up */
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "SKIP");
- return 0;
- } else if (!ast_test_flag(&flags, OPTION_NOANSWER)) {
- /* Otherwise answer unless we're supposed to record while on-hook */
-@@ -215,6 +263,7 @@
-
- if (res) {
- ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- goto out;
- }
-
-@@ -236,11 +285,13 @@
- res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- return -1;
- }
- sildet = ast_dsp_new();
- if (!sildet) {
- ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- return -1;
- }
- ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
-@@ -257,6 +308,7 @@
-
- if (!s) {
- ast_log(LOG_WARNING, "Could not create file %s\n", args.filename);
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- goto out;
- }
-
-@@ -273,6 +325,7 @@
- if (maxduration > 0) {
- if (waitres == 0) {
- gottimeout = 1;
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT");
- break;
- }
- maxduration = waitres;
-@@ -289,6 +342,7 @@
- if (res) {
- ast_log(LOG_WARNING, "Problem writing frame\n");
- ast_frfree(f);
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- break;
- }
-
-@@ -304,6 +358,7 @@
- /* Ended happily with silence */
- ast_frfree(f);
- gotsilence = 1;
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "SILENCE");
- break;
- }
- }
-@@ -312,12 +367,14 @@
-
- if (res) {
- ast_log(LOG_WARNING, "Problem writing frame\n");
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
- ast_frfree(f);
- break;
- }
- } else if ((f->frametype == AST_FRAME_DTMF) &&
- (f->subclass == terminator)) {
- ast_frfree(f);
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF");
- break;
- }
- ast_frfree(f);
-@@ -325,7 +382,10 @@
- if (!f) {
- ast_debug(1, "Got hangup\n");
- res = -1;
-- ast_filedelete(args.filename, NULL);
-+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "HANGUP");
-+ if (!ast_test_flag(&flags, OPTION_KEEP)) {
-+ ast_filedelete(args.filename, NULL);
-+ }
- }
-
- if (gotsilence) {
-@@ -360,7 +420,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, record_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, record_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application");
-Index: apps/app_authenticate.c
-===================================================================
---- a/apps/app_authenticate.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_authenticate.c (.../team/group/issue14292) (revision 178988)
-@@ -54,30 +54,57 @@
-
-
- static char *app = "Authenticate";
-+/*** DOCUMENTATION
-+ <application name="Authenticate" language="en_US">
-+ <synopsis>
-+ Authenticate a user
-+ </synopsis>
-+ <syntax>
-+ <parameter name="password" required="true">
-+ <para>Password the user should know</para>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="a">
-+ <para>Set the channels' account code to the password that is entered</para>
-+ </option>
-+ <option name="d">
-+ <para>Interpret the given path as database key, not a literal file</para>
-+ </option>
-+ <option name="m">
-+ <para>Interpret the given path as a file which contains a list of account
-+ codes and password hashes delimited with <literal>:</literal>, listed one per line in
-+ the file. When one of the passwords is matched, the channel will have
-+ its account code set to the corresponding account code in the file.</para>
-+ </option>
-+ <option name="r">
-+ <para>Remove the database key upon successful entry (valid with <literal>d</literal> only)</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="maxdigits" required="false">
-+ <para>maximum acceptable number of digits. Stops reading after
-+ maxdigits have been entered (without requiring the user to press the <literal>#</literal> key).
-+ Defaults to 0 - no limit - wait for the user press the <literal>#</literal> key.</para>
-+ </parameter>
-+ <parameter name="prompt" required="false">
-+ <para>Override the agent-pass prompt file.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application asks the caller to enter a given password in order to continue dialplan execution.</para>
-+ <para>If the password begins with the <literal>/</literal> character,
-+ it is interpreted as a file which contains a list of valid passwords, listed 1 password per line in the file.</para>
-+ <para>When using a database key, the value associated with the key can be anything.</para>
-+ <para>Users have three attempts to authenticate before the channel is hung up.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">VMAuthenticate</ref>
-+ <ref type="application">DISA</ref>
-+ </see-also>
-+ </application>
-+ ***/
-
--static char *synopsis = "Authenticate a user";
--
--static char *descrip =
--" Authenticate(password[,options[,maxdigits]]): This application asks the caller\n"
--"to enter a given password in order to continue dialplan execution. If the password\n"
--"begins with the '/' character, it is interpreted as a file which contains a list of\n"
--"valid passwords, listed 1 password per line in the file.\n"
--" When using a database key, the value associated with the key can be anything.\n"
--"Users have three attempts to authenticate before the channel is hung up.\n"
--" Options:\n"
--" a - Set the channels' account code to the password that is entered\n"
--" d - Interpret the given path as database key, not a literal file\n"
--" m - Interpret the given path as a file which contains a list of account\n"
--" codes and password hashes delimited with ':', listed one per line in\n"
--" the file. When one of the passwords is matched, the channel will have\n"
--" its account code set to the corresponding account code in the file.\n"
--" r - Remove the database key upon successful entry (valid with 'd' only)\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"
--;
--
- static int auth_exec(struct ast_channel *chan, void *data)
- {
- int res = 0, retries, maxdigits;
-@@ -88,6 +115,7 @@
- AST_APP_ARG(password);
- AST_APP_ARG(options);
- AST_APP_ARG(maxdigits);
-+ AST_APP_ARG(prompt);
- );
-
- if (ast_strlen_zero(data)) {
-@@ -115,6 +143,12 @@
- maxdigits = sizeof(passwd) - 2;
- }
-
-+ if (!ast_strlen_zero(arglist.prompt)) {
-+ prompt = arglist.prompt;
-+ } else {
-+ prompt = "agent-pass";
-+ }
-+
- /* Start asking for password */
- for (retries = 0; retries < 3; retries++) {
- if ((res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0)) < 0)
-@@ -218,7 +252,7 @@
-
- static int load_module(void)
- {
-- if (ast_register_application(app, auth_exec, synopsis, descrip))
-+ if (ast_register_application_xml(app, auth_exec))
- return AST_MODULE_LOAD_FAILURE;
- return AST_MODULE_LOAD_SUCCESS;
- }
-Index: apps/app_fax.c
-===================================================================
---- a/apps/app_fax.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_fax.c (.../team/group/issue14292) (revision 178988)
-@@ -44,60 +44,105 @@
- #include "asterisk/module.h"
- #include "asterisk/manager.h"
-
-+/*** DOCUMENTATION
-+ <application name="SendFAX" language="en_US">
-+ <synopsis>
-+ Send a Fax
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true">
-+ <para>Filename of TIFF file to fax</para>
-+ </parameter>
-+ <parameter name="a" required="false">
-+ <para>Makes the application behave as the answering machine</para>
-+ <para>(Default behavior is as calling machine)</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Send a given TIFF file to the channel as a FAX.</para>
-+ <para>This application sets the following channel variables:</para>
-+ <variablelist>
-+ <variable name="LOCALSTATIONID">
-+ <para>To identify itself to the remote end</para>
-+ </variable>
-+ <variable name="LOCALHEADERINFO">
-+ <para>To generate a header line on each page</para>
-+ </variable>
-+ <variable name="FAXSTATUS">
-+ <value name="SUCCESS"/>
-+ <value name="FAILED"/>
-+ </variable>
-+ <variable name="FAXERROR">
-+ <para>Cause of failure</para>
-+ </variable>
-+ <variable name="REMOTESTATIONID">
-+ <para>The CSID of the remote side</para>
-+ </variable>
-+ <variable name="FAXPAGES">
-+ <para>Number of pages sent</para>
-+ </variable>
-+ <variable name="FAXBITRATE">
-+ <para>Transmission rate</para>
-+ </variable>
-+ <variable name="FAXRESOLUTION">
-+ <para>Resolution of sent fax</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="ReceiveFAX" language="en_US">
-+ <synopsis>
-+ Receive a Fax
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true">
-+ <para>Filename of TIFF file save incoming fax</para>
-+ </parameter>
-+ <parameter name="c" required="false">
-+ <para>Makes the application behave as the calling machine</para>
-+ <para>(Default behavior is as answering machine)</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Receives a FAX from the channel into the given filename
-+ overwriting the file if it already exists.</para>
-+ <para>File created will be in TIFF format.</para>
-+
-+ <para>This application sets the following channel variables:</para>
-+ <variablelist>
-+ <variable name="LOCALSTATIONID">
-+ <para>To identify itself to the remote end</para>
-+ </variable>
-+ <variable name="LOCALHEADERINFO">
-+ <para>To generate a header line on each page</para>
-+ </variable>
-+ <variable name="FAXSTATUS">
-+ <value name="SUCCESS"/>
-+ <value name="FAILED"/>
-+ </variable>
-+ <variable name="FAXERROR">
-+ <para>Cause of failure</para>
-+ </variable>
-+ <variable name="REMOTESTATIONID">
-+ <para>The CSID of the remote side</para>
-+ </variable>
-+ <variable name="FAXPAGES">
-+ <para>Number of pages sent</para>
-+ </variable>
-+ <variable name="FAXBITRATE">
-+ <para>Transmission rate</para>
-+ </variable>
-+ <variable name="FAXRESOLUTION">
-+ <para>Resolution of sent fax</para>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+
-+ ***/
-+
- static char *app_sndfax_name = "SendFAX";
--static char *app_sndfax_synopsis = "Send a FAX";
--static char *app_sndfax_desc =
--" SendFAX(filename[|options]):\n"
--"Send a given TIFF file to the channel as a FAX.\n"
--"The option string may contain zero or more of the following characters:\n"
--" 'a' - makes the application behave as an answering machine\n"
--" The default behaviour is to behave as a calling machine.\n"
--"\n"
--"This application uses following variables:\n"
--" LOCALSTATIONID to identify itself to the remote end.\n"
--" LOCALHEADERINFO to generate a header line on each page.\n"
--"\n"
--"This application sets the following channel variables upon completion:\n"
--" FAXSTATUS - status of operation:\n"
--" SUCCESS | FAILED\n"
--" FAXERROR - Error when FAILED\n"
--" FAXMODE - Mode used:\n"
--" audio | T38\n"
--" REMOTESTATIONID - CSID of the remote side.\n"
--" FAXPAGES - number of pages sent.\n"
--" FAXBITRATE - transmition rate.\n"
--" FAXRESOLUTION - resolution.\n"
--"\n"
--"Returns -1 in case of user hang up or any channel error.\n"
--"Returns 0 on success.\n";
--
- static char *app_rcvfax_name = "ReceiveFAX";
--static char *app_rcvfax_synopsis = "Receive a FAX";
--static char *app_rcvfax_desc =
--" ReceiveFAX(filename[|options]):\n"
--"Receives a fax from the channel into the given filename overwriting\n"
--"the file if it already exists. File created will have TIFF format.\n"
--"The option string may contain zero or more of the following characters:\n"
--" 'c' -- makes the application behave as a calling machine\n"
--" The default behaviour is to behave as an answering machine.\n"
--"\n"
--"This application uses following variables:\n"
--" LOCALSTATIONID to identify itself to the remote end.\n"
--" LOCALHEADERINFO to generate a header line on each page.\n"
--"\n"
--"This application sets the following channel variables upon completion:\n"
--" FAXSTATUS - status of operation:\n"
--" SUCCESS | FAILED\n"
--" FAXERROR - Error when FAILED\n"
--" FAXMODE - Mode used:\n"
--" audio | T38\n"
--" REMOTESTATIONID - CSID of the remote side.\n"
--" FAXPAGES - number of pages sent.\n"
--" FAXBITRATE - transmition rate.\n"
--" FAXRESOLUTION - resolution.\n"
--"\n"
--"Returns -1 in case of user hang up or any channel error.\n"
--"Returns 0 on success.\n";
-
- #define MAX_SAMPLES 240
-
-@@ -161,6 +206,7 @@
- char buf[20];
- fax_session *s = (fax_session *) user_data;
- t30_stats_t stat;
-+ int pages_transferred;
-
- ast_debug(1, "Fax phase E handler. result=%d\n", result);
-
-@@ -186,7 +232,12 @@
- pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
- pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
- pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
-- snprintf(buf, sizeof(buf), "%d", stat.pages_transferred);
-+#if SPANDSP_RELEASE_DATE >= 20090220
-+ pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
-+#else
-+ pages_transferred = stat.pages_transferred;
-+#endif
-+ snprintf(buf, sizeof(buf), "%d", pages_transferred);
- pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
- snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
- pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
-@@ -195,7 +246,7 @@
-
- ast_debug(1, "Fax transmitted successfully.\n");
- ast_debug(1, " Remote station ID: %s\n", far_ident);
-- ast_debug(1, " Pages transferred: %d\n", stat.pages_transferred);
-+ ast_debug(1, " Pages transferred: %d\n", pages_transferred);
- ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
- ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
-
-@@ -215,7 +266,7 @@
- S_OR(s->chan->cid.cid_num, ""),
- far_ident,
- local_ident,
-- stat.pages_transferred,
-+ pages_transferred,
- stat.y_resolution,
- stat.bit_rate,
- s->file_name);
-@@ -756,8 +807,8 @@
- {
- int res ;
-
-- res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
-- res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
-+ res = ast_register_application_xml(app_sndfax_name, sndfax_exec);
-+ res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec);
-
- /* The default SPAN message handler prints to stderr. It is something we do not want */
- span_set_message_handler(NULL);
-Index: apps/app_waituntil.c
-===================================================================
---- a/apps/app_waituntil.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_waituntil.c (.../team/group/issue14292) (revision 178988)
-@@ -34,15 +34,38 @@
- #include "asterisk/pbx.h"
- #include "asterisk/module.h"
-
-+/*** DOCUMENTATION
-+ <application name="WaitUntil" language="en_US">
-+ <synopsis>
-+ Wait (sleep) until the current time is the given epoch.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="epoch" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Waits until the given <replaceable>epoch</replaceable>.</para>
-+ <para>Sets <variable>WAITUNTILSTATUS</variable> to one of the following values:</para>
-+ <variablelist>
-+ <variable name="WAITUNTILSTATUS">
-+ <value name="OK">
-+ Wait succeeded.
-+ </value>
-+ <value name="FAILURE">
-+ Invalid argument.
-+ </value>
-+ <value name="HANGUP">
-+ Channel hungup before time elapsed.
-+ </value>
-+ <value name="PAST">
-+ Time specified had already past.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
-+
- static char *app = "WaitUntil";
--static char *synopsis = "Wait (sleep) until the current time is the given epoch";
--static char *descrip =
--" WaitUntil(<epoch>): Waits until the given time. Sets WAITUNTILSTATUS to\n"
--"one of the following values:\n"
--" OK Wait succeeded\n"
--" FAILURE Invalid argument\n"
--" HANGUP Channel hung up before time elapsed\n"
--" PAST The time specified was already past\n";
-
- static int waituntil_exec(struct ast_channel *chan, void *data)
- {
-@@ -89,7 +112,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, waituntil_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, waituntil_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Wait until specified time");
-Index: apps/app_originate.c
-===================================================================
---- a/apps/app_originate.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/apps/app_originate.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,217 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Roberto Casas.
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Roberto Casas <roberto.casas@diaple.com>
-+ * Russell Bryant <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*!
-+ * \file
-+ * \brief Originate application
-+ *
-+ * \author Roberto Casas <roberto.casas@diaple.com>
-+ * \author Russell Bryant <russell@digium.com>
-+ *
-+ * \ingroup applications
-+ *
-+ * \todo Make a way to be able to set variables (and functions) on the outbound
-+ * channel, similar to the Variable headers for the AMI Originate, and the
-+ * Set options for call files.
-+ */
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/file.h"
-+#include "asterisk/channel.h"
-+#include "asterisk/pbx.h"
-+#include "asterisk/module.h"
-+#include "asterisk/app.h"
-+
-+static const char app_originate[] = "Originate";
-+
-+/*** DOCUMENTATION
-+ <application name="Originate" language="en_US">
-+ <synopsis>
-+ Originate a call.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="tech_data" required="true">
-+ <para>Channel technology and data for creating the outbound channel.
-+ For example, SIP/1234.</para>
-+ </parameter>
-+ <parameter name="type" required="true">
-+ <para>This should be <literal>app</literal> or <literal>exten</literal>, depending on whether the outbound channel should be connected to an application or extension.</para>
-+ </parameter>
-+ <parameter name="arg1" required="true">
-+ <para>If the type is <literal>app</literal>, then this is the application name. If the type is <literal>exten</literal>, then this is the context that the channel will be sent to.</para>
-+ </parameter>
-+ <parameter name="arg2" required="false">
-+ <para>If the type is <literal>app</literal>, then this is the data passed as arguments to the application. If the type is <literal>exten</literal>, then this is the extension that the channel will be sent to.</para>
-+ </parameter>
-+ <parameter name="arg3" required="false">
-+ <para>If the type is <literal>exten</literal>, then this is the priority that the channel is sent to. If the type is <literal>app</literal>, then this parameter is ignored.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application originates an outbound call and connects it to a specified extension or application. This application will block until the outgoing call fails or gets answered. At that point, this application will exit with the status variable set and dialplan processing will continue.</para>
-+
-+ <para>This application sets the following channel variable before exiting:</para>
-+ <variablelist>
-+ <variable name="ORIGINATE_STATUS">
-+ <para>This indicates the result of the call origination.</para>
-+ <value name="FAILED"/>
-+ <value name="SUCCESS"/>
-+ <value name="BUSY"/>
-+ <value name="CONGESTION"/>
-+ <value name="HANGUP"/>
-+ <value name="RINGING"/>
-+ <value name="UNKNOWN">
-+ In practice, you should never see this value. Please report it to the issue tracker if you ever see it.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ ***/
-+
-+static int originate_exec(struct ast_channel *chan, void *data)
-+{
-+ AST_DECLARE_APP_ARGS(args,
-+ AST_APP_ARG(tech_data);
-+ AST_APP_ARG(type);
-+ AST_APP_ARG(arg1);
-+ AST_APP_ARG(arg2);
-+ AST_APP_ARG(arg3);
-+ );
-+ char *parse;
-+ char *chantech, *chandata;
-+ int res = -1;
-+ int outgoing_res = 0;
-+ int outgoing_status = 0;
-+ static const unsigned int timeout = 30;
-+ static const char default_exten[] = "s";
-+
-+ ast_autoservice_start(chan);
-+
-+ if (ast_strlen_zero(data)) {
-+ ast_log(LOG_ERROR, "Originate() requires arguments\n");
-+ goto return_cleanup;
-+ }
-+
-+ parse = ast_strdupa(data);
-+
-+ AST_STANDARD_APP_ARGS(args, parse);
-+
-+ if (args.argc < 3) {
-+ ast_log(LOG_ERROR, "Incorrect number of arguments\n");
-+ goto return_cleanup;
-+ }
-+
-+ chandata = ast_strdupa(args.tech_data);
-+ chantech = strsep(&chandata, "/");
-+
-+ if (ast_strlen_zero(chandata) || ast_strlen_zero(chantech)) {
-+ ast_log(LOG_ERROR, "Channel Tech/Data invalid: '%s'\n", args.tech_data);
-+ goto return_cleanup;
-+ }
-+
-+ if (!strcasecmp(args.type, "exten")) {
-+ int priority = 1; /* Initialized in case priority not specified */
-+ const char *exten = args.arg2;
-+
-+ if (args.argc == 5) {
-+ /* Context/Exten/Priority all specified */
-+ if (sscanf(args.arg3, "%d", &priority) != 1) {
-+ ast_log(LOG_ERROR, "Invalid priority: '%s'\n", args.arg3);
-+ goto return_cleanup;
-+ }
-+ } else if (args.argc == 3) {
-+ /* Exten not specified */
-+ exten = default_exten;
-+ }
-+
-+ ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
-+ chantech, chandata, args.arg1, exten, priority);
-+
-+ outgoing_res = ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata,
-+ timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
-+ NULL, NULL, NULL, NULL);
-+ } else if (!strcasecmp(args.type, "app")) {
-+ ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
-+ chantech, chandata, args.arg1, S_OR(args.arg2, ""));
-+
-+ outgoing_res = ast_pbx_outgoing_app(chantech, AST_FORMAT_SLINEAR, chandata,
-+ timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
-+ NULL, NULL, NULL, NULL);
-+ } else {
-+ ast_log(LOG_ERROR, "Incorrect type, it should be 'exten' or 'app': %s\n",
-+ args.type);
-+ goto return_cleanup;
-+ }
-+
-+ res = 0;
-+
-+return_cleanup:
-+ if (res) {
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "FAILED");
-+ } else {
-+ switch (outgoing_status) {
-+ case 0:
-+ case AST_CONTROL_ANSWER:
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "SUCCESS");
-+ break;
-+ case AST_CONTROL_BUSY:
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "BUSY");
-+ break;
-+ case AST_CONTROL_CONGESTION:
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "CONGESTION");
-+ break;
-+ case AST_CONTROL_HANGUP:
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "HANGUP");
-+ break;
-+ case AST_CONTROL_RINGING:
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "RINGING");
-+ break;
-+ default:
-+ ast_log(LOG_WARNING, "Unknown originate status result of '%d'\n",
-+ outgoing_status);
-+ pbx_builtin_setvar_helper(chan, "ORIGINATE_STATUS", "UNKNOWN");
-+ break;
-+ }
-+ }
-+
-+ ast_autoservice_stop(chan);
-+
-+ return res;
-+}
-+
-+static int unload_module(void)
-+{
-+ return ast_unregister_application(app_originate);
-+}
-+
-+static int load_module(void)
-+{
-+ int res;
-+
-+ res = ast_register_application_xml(app_originate, originate_exec);
-+
-+ return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
-+}
-+
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Originate call");
-
-Property changes on: apps/app_originate.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: apps/app_queue.c
-===================================================================
---- a/apps/app_queue.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_queue.c (.../team/group/issue14292) (revision 178988)
-@@ -94,6 +94,7 @@
- #include "asterisk/strings.h"
- #include "asterisk/global_datastores.h"
- #include "asterisk/taskprocessor.h"
-+#include "asterisk/callerid.h"
-
- /*!
- * \par Please read before modifying this file.
-@@ -109,6 +110,388 @@
- * to this order!
- */
-
-+/*** DOCUMENTATION
-+ <application name="Queue" language="en_US">
-+ <synopsis>
-+ Queue a call for a call queue.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="C">
-+ <para>Mark all calls as "answered elsewhere" when cancelled.</para>
-+ </option>
-+ <option name="c">
-+ <para>Continue in the dialplan if the callee hangs up.</para>
-+ </option>
-+ <option name="d">
-+ <para>data-quality (modem) call (minimum delay).</para>
-+ </option>
-+ <option name="h">
-+ <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
-+ </option>
-+ <option name="H">
-+ <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
-+ </option>
-+ <option name="n">
-+ <para>No retries on the timeout; will exit this application and
-+ go to the next step.</para>
-+ </option>
-+ <option name="i">
-+ <para>Ignore call forward requests from queue members and do nothing
-+ when they are requested.</para>
-+ </option>
-+ <option name="I">
-+ <para>Asterisk will ignore any connected line update requests or any redirecting party
-+ update requests it may receive on this dial attempt.</para>
-+ </option>
-+ <option name="r">
-+ <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
-+ </option>
-+ <option name="t">
-+ <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
-+ </option>
-+ <option name="T">
-+ <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
-+ </option>
-+ <option name="w">
-+ <para>Allow the <emphasis>called</emphasis> user to write the conversation to
-+ disk via Monitor.</para>
-+ </option>
-+ <option name="W">
-+ <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
-+ disk via Monitor.</para>
-+ </option>
-+ <option name="k">
-+ <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
-+ the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="K">
-+ <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
-+ the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
-+ </option>
-+ <option name="x">
-+ <para>Allow the <emphasis>called</emphasis> user to write the conversation
-+ to disk via MixMonitor.</para>
-+ </option>
-+ <option name="X">
-+ <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
-+ disk via MixMonitor.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="URL">
-+ <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
-+ </parameter>
-+ <parameter name="announceoverride" />
-+ <parameter name="timeout">
-+ <para>Will cause the queue to fail out after a specified number of
-+ seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
-+ <replaceable>retry</replaceable> cycle.</para>
-+ </parameter>
-+ <parameter name="AGI">
-+ <para>Will setup an AGI script to be executed on the calling party's channel once they are
-+ connected to a queue member.</para>
-+ </parameter>
-+ <parameter name="macro">
-+ <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para>
-+ </parameter>
-+ <parameter name="gosub">
-+ <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para>
-+ </parameter>
-+ <parameter name="rule">
-+ <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>In addition to transferring the call, a call may be parked and then picked
-+ up by another user.</para>
-+ <para>This application will return to the dialplan if the queue does not exist, or
-+ any of the join options cause the caller to not enter the queue.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="QUEUESTATUS">
-+ <para>The status of the call as a text string.</para>
-+ <value name="TIMEOUT" />
-+ <value name="FULL" />
-+ <value name="JOINEMPTY" />
-+ <value name="LEAVEEMPTY" />
-+ <value name="JOINUNAVAIL" />
-+ <value name="LEAVEUNAVAIL" />
-+ <value name="CONTINUE" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">AddQueueMember</ref>
-+ <ref type="application">RemoveQueueMember</ref>
-+ <ref type="application">PauseQueueMember</ref>
-+ <ref type="application">UnpauseQueueMember</ref>
-+ <ref type="application">AgentLogin</ref>
-+ <ref type="function">QUEUE_MEMBER_COUNT</ref>
-+ <ref type="function">QUEUE_MEMBER_LIST</ref>
-+ <ref type="function">QUEUE_WAITING_COUNT</ref>
-+ </see-also>
-+ </application>
-+ <application name="AddQueueMember" language="en_US">
-+ <synopsis>
-+ Dynamically adds queue members.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ <parameter name="interface" />
-+ <parameter name="penalty" />
-+ <parameter name="options" />
-+ <parameter name="membername" />
-+ <parameter name="stateinterface" />
-+ </syntax>
-+ <description>
-+ <para>Dynamically adds interface to an existing queue. If the interface is
-+ already in the queue it will return an error.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="AQMSTATUS">
-+ <para>The status of the attempt to add a queue member as a text string.</para>
-+ <value name="ADDED" />
-+ <value name="MEMBERALREADY" />
-+ <value name="NOSUCHQUEUE" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">RemoveQueueMember</ref>
-+ <ref type="application">PauseQueueMember</ref>
-+ <ref type="application">UnpauseQueueMember</ref>
-+ <ref type="application">AgentLogin</ref>
-+ </see-also>
-+ </application>
-+ <application name="RemoveQueueMember" language="en_US">
-+ <synopsis>
-+ Dynamically removes queue members.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ <parameter name="interface" />
-+ <parameter name="options" />
-+ </syntax>
-+ <description>
-+ <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="RQMSTATUS">
-+ <value name="REMOVED" />
-+ <value name="NOTINQUEUE" />
-+ <value name="NOSUCHQUEUE" />
-+ </variable>
-+ </variablelist>
-+ <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Queue</ref>
-+ <ref type="application">AddQueueMember</ref>
-+ <ref type="application">PauseQueueMember</ref>
-+ <ref type="application">UnpauseQueueMember</ref>
-+ </see-also>
-+ </application>
-+ <application name="PauseQueueMember" language="en_US">
-+ <synopsis>
-+ Pauses a queue member.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" />
-+ <parameter name="interface" required="true" />
-+ <parameter name="options" />
-+ <parameter name="reason">
-+ <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
-+ This prevents any calls from being sent from the queue to the interface until it is
-+ unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
-+ the interface is paused in every queue it is a member of. The application will fail if the
-+ interface is not found.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="PQMSTATUS">
-+ <para>The status of the attempt to pause a queue member as a text string.</para>
-+ <value name="PAUSED" />
-+ <value name="NOTFOUND" />
-+ </variable>
-+ </variablelist>
-+ <para>Example: PauseQueueMember(,SIP/3000)</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">UnpauseQueueMember</ref>
-+ </see-also>
-+ </application>
-+ <application name="UnpauseQueueMember" language="en_US">
-+ <synopsis>
-+ Unpauses a queue member.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" />
-+ <parameter name="interface" required="true" />
-+ <parameter name="options" />
-+ <parameter name="reason">
-+ <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
-+ and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="UPQMSTATUS">
-+ <para>The status of the attempt to unpause a queue member as a text string.</para>
-+ <value name="UNPAUSED" />
-+ <value name="NOTFOUND" />
-+ </variable>
-+ </variablelist>
-+ <para>Example: UnpauseQueueMember(,SIP/3000)</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">PauseQueueMember</ref>
-+ </see-also>
-+ </application>
-+ <application name="QueueLog" language="en_US">
-+ <synopsis>
-+ Writes to the queue_log file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ <parameter name="uniqueid" required="true" />
-+ <parameter name="agent" required="true" />
-+ <parameter name="event" required="true" />
-+ <parameter name="additionalinfo" />
-+ </syntax>
-+ <description>
-+ <para>Allows you to write your own events into the queue log.</para>
-+ <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Queue</ref>
-+ </see-also>
-+ </application>
-+ <function name="QUEUE_VARIABLES" language="en_US">
-+ <synopsis>
-+ Return Queue information in variables.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true">
-+ <enumlist>
-+ <enum name="QUEUEMAX">
-+ <para>Maxmimum number of calls allowed.</para>
-+ </enum>
-+ <enum name="QUEUESTRATEGY">
-+ <para>The strategy of the queue.</para>
-+ </enum>
-+ <enum name="QUEUECALLS">
-+ <para>Number of calls currently in the queue.</para>
-+ </enum>
-+ <enum name="QUEUEHOLDTIME">
-+ <para>Current average hold time.</para>
-+ </enum>
-+ <enum name="QUEUECOMPLETED">
-+ <para>Number of completed calls for the queue.</para>
-+ </enum>
-+ <enum name="QUEUEABANDONED">
-+ <para>Number of abandoned calls.</para>
-+ </enum>
-+ <enum name="QUEUESRVLEVEL">
-+ <para>Queue service level.</para>
-+ </enum>
-+ <enum name="QUEUESRVLEVELPERF">
-+ <para>Current service level performance.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Makes the following queue variables available.</para>
-+ <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
-+ </description>
-+ </function>
-+ <function name="QUEUE_MEMBER" language="en_US">
-+ <synopsis>
-+ Count number of members answering a queue.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ <parameter name="option" required="true">
-+ <enumlist>
-+ <enum name="logged">
-+ <para>Returns the number of logged-in members for the specified queue.</para>
-+ </enum>
-+ <enum name="free">
-+ <para>Returns the number of logged-in members for the specified queue available to take a call.</para>
-+ </enum>
-+ <enum name="count">
-+ <para>Returns the total number of members for the specified queue.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
-+ </description>
-+ </function>
-+ <function name="QUEUE_MEMBER_COUNT" language="en_US">
-+ <synopsis>
-+ Count number of members answering a queue.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
-+ <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
-+ </description>
-+ <see-also>
-+ <ref type="function">QUEUE_MEMBER_LIST</ref>
-+ </see-also>
-+ </function>
-+ <function name="QUEUE_WAITING_COUNT" language="en_US">
-+ <synopsis>
-+ Count number of calls currently waiting in a queue.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" />
-+ </syntax>
-+ <description>
-+ <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
-+ </description>
-+ </function>
-+ <function name="QUEUE_MEMBER_LIST" language="en_US">
-+ <synopsis>
-+ Returns a list of interfaces on a queue.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">QUEUE_MEMBER_COUNT</ref>
-+ </see-also>
-+ </function>
-+ <function name="QUEUE_MEMBER_PENALTY" language="en_US">
-+ <synopsis>
-+ Gets or sets queue members penalty.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="queuename" required="true" />
-+ <parameter name="interface" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Gets or sets queue members penalty.</para>
-+ </description>
-+ </function>
-+
-+ ***/
-+
- enum {
- QUEUE_STRATEGY_RINGALL = 0,
- QUEUE_STRATEGY_LEASTRECENT,
-@@ -119,6 +502,13 @@
- QUEUE_STRATEGY_WRANDOM
- };
-
-+enum queue_reload_mask {
-+ QUEUE_RELOAD_PARAMETERS = (1 << 0),
-+ QUEUE_RELOAD_MEMBER = (1 << 1),
-+ QUEUE_RELOAD_RULES = (1 << 2),
-+ QUEUE_RESET_STATS = (1 << 3),
-+};
-+
- static const struct strategy {
- int strategy;
- const char *name;
-@@ -151,128 +541,15 @@
-
- static char *app = "Queue";
-
--static char *synopsis = "Queue a call for a call queue";
--
--static char *descrip =
--" Queue(queuename[,options[,URL][,announceoverride][,timeout][,AGI][,macro][,gosub][,rule]):\n"
--"Queues an incoming call in a particular call queue as defined in queues.conf.\n"
--"This application will return to the dialplan if the queue does not exist, or\n"
--"any of the join options cause the caller to not enter the queue.\n"
--"The option string may contain zero or more of the following characters:\n"
--" 'c' -- continue in the dialplan if the callee hangs up.\n"
--" 'd' -- data-quality (modem) call (minimum delay).\n"
--" 'h' -- allow callee to hang up by hitting '*', or whatver disconnect sequence\n"
--" that is defined in the featuremap section in features.conf.\n"
--" 'H' -- allow caller to hang up by hitting '*', or whatever disconnect sequence\n"
--" that is defined in the featuremap section in features.conf.\n"
--" 'n' -- no retries on the timeout; will exit this application and \n"
--" go to the next step.\n"
--" 'i' -- ignore call forward requests from queue members and do nothing\n"
--" when they are requested.\n"
--" 'r' -- ring instead of playing MOH. Periodic Announcements are still made, if applicable.\n"
--" 't' -- allow the called user transfer the calling user by pressing '#' or\n"
--" whatever blindxfer sequence defined in the featuremap section in\n"
--" features.conf\n"
--" 'T' -- to allow the calling user to transfer the call by pressing '#' or\n"
--" whatever blindxfer sequence defined in the featuremap section in\n"
--" features.conf\n"
--" 'w' -- allow the called user to write the conversation to disk via Monitor\n"
--" by pressing the automon sequence defined in the featuremap section in\n"
--" features.conf\n"
--" 'W' -- allow the calling user to write the conversation to disk via Monitor\n"
--" by pressing the automon sequence defined in the featuremap section in\n"
--" features.conf\n"
--" 'k' -- Allow the called party to enable parking of the call by sending\n"
--" the DTMF sequence defined for call parking in 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 features.conf.\n"
--" 'x' -- allow the called user to write the conversation to disk via MixMonitor\n"
--" by pressing the automixmon sequence defined in the featuremap section in\n"
--" features.conf\n"
--" 'X' -- allow the calling user to write the conversation to disk via MixMonitor\n"
--" by pressing the automixmon sequence defined in the featuremap section in\n"
--" features.conf\n"
--" The optional URL will be sent to the called party if the channel supports\n"
--"it.\n"
--" The optional AGI parameter will setup an AGI script to be executed on the \n"
--"calling party's channel once they are connected to a queue member.\n"
--" The optional macro parameter will run a macro on the \n"
--"calling party's channel once they are connected to a queue member.\n"
--" The optional gosub parameter will run a gosub on the \n"
--"calling party's channel once they are connected to a queue member.\n"
--" The optional rule parameter will cause the queue's defaultrule to be\n"
--"overridden by the rule specified.\n"
--" The timeout will cause the queue to fail out after a specified number of\n"
--"seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
--" This application sets the following channel variable upon completion:\n"
--" QUEUESTATUS The status of the call as a text string, one of\n"
--" TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n";
--
- static char *app_aqm = "AddQueueMember" ;
--static char *app_aqm_synopsis = "Dynamically adds queue members" ;
--static char *app_aqm_descrip =
--" AddQueueMember(queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]]):\n"
--"Dynamically adds interface to an existing queue.\n"
--"If the interface is already in the queue it will return an error.\n"
--" This application sets the following channel variable upon completion:\n"
--" AQMSTATUS The status of the attempt to add a queue member as a \n"
--" text string, one of\n"
--" ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
--"Example: AddQueueMember(techsupport,SIP/3000)\n"
--"";
-
- static char *app_rqm = "RemoveQueueMember" ;
--static char *app_rqm_synopsis = "Dynamically removes queue members" ;
--static char *app_rqm_descrip =
--" RemoveQueueMember(queuename[,interface[,options]]):\n"
--"Dynamically removes interface to an existing queue\n"
--"If the interface is NOT in the queue it will return an error.\n"
--" This application sets the following channel variable upon completion:\n"
--" RQMSTATUS The status of the attempt to remove a queue member as a\n"
--" text string, one of\n"
--" REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
--"Example: RemoveQueueMember(techsupport,SIP/3000)\n"
--"";
-
- static char *app_pqm = "PauseQueueMember" ;
--static char *app_pqm_synopsis = "Pauses a queue member" ;
--static char *app_pqm_descrip =
--" PauseQueueMember([queuename],interface[,options[,reason]]):\n"
--"Pauses (blocks calls for) a queue member.\n"
--"The given interface will be paused in the given queue. This prevents\n"
--"any calls from being sent from the queue to the interface until it is\n"
--"unpaused with UnpauseQueueMember or the manager interface. If no\n"
--"queuename is given, the interface is paused in every queue it is a\n"
--"member of. The application will fail if the interface is not found.\n"
--"The reason string is entirely optional and is used to add extra information\n"
--"to the appropriate queue_log entries and manager events.\n"
--" This application sets the following channel variable upon completion:\n"
--" PQMSTATUS The status of the attempt to pause a queue member as a\n"
--" text string, one of\n"
--" PAUSED | NOTFOUND\n"
--"Example: PauseQueueMember(,SIP/3000)\n";
-
- static char *app_upqm = "UnpauseQueueMember" ;
--static char *app_upqm_synopsis = "Unpauses a queue member" ;
--static char *app_upqm_descrip =
--" UnpauseQueueMember([queuename],interface[,options[,reason]]):\n"
--"Unpauses (resumes calls to) a queue member.\n"
--"This is the counterpart to PauseQueueMember and operates exactly the\n"
--"same way, except it unpauses instead of pausing the given interface.\n"
--"The reason string is entirely optional and is used to add extra information\n"
--"to the appropriate queue_log entries and manager events.\n"
--" This application sets the following channel variable upon completion:\n"
--" UPQMSTATUS The status of the attempt to unpause a queue \n"
--" member as a text string, one of\n"
--" UNPAUSED | NOTFOUND\n"
--"Example: UnpauseQueueMember(,SIP/3000)\n";
-
- static char *app_ql = "QueueLog" ;
--static char *app_ql_synopsis = "Writes to the queue_log" ;
--static char *app_ql_descrip =
--" QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n"
--"Allows you to write your own events into the queue log\n"
--"Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n";
-
- /*! \brief Persistent Members astdb family */
- static const char *pm_family = "Queue/PersistentMembers";
-@@ -280,9 +557,6 @@
- #define PM_MAX_LEN 8192
-
- /*! \brief queues.conf [general] option */
--static int queue_keep_stats = 0;
--
--/*! \brief queues.conf [general] option */
- static int queue_persistent_members = 0;
-
- /*! \brief queues.conf per-queue weight option */
-@@ -356,6 +630,8 @@
- time_t lastcall;
- struct call_queue *lastqueue;
- struct member *member;
-+ int update_connectedline;
-+ struct ast_party_connected_line connected;
- };
-
-
-@@ -381,6 +657,7 @@
- int linwrapped; /*!< Is the linpos wrapped? */
- time_t start; /*!< When we started holding */
- time_t expire; /*!< When this entry should expire (time out of queue) */
-+ int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
- struct ast_channel *chan; /*!< Our channel */
- AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
- struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
-@@ -404,17 +681,18 @@
- char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
- };
-
--struct member_interface {
-- char interface[80];
-- AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
-+enum empty_conditions {
-+ QUEUE_EMPTY_PENALTY = (1 << 0),
-+ QUEUE_EMPTY_PAUSED = (1 << 1),
-+ QUEUE_EMPTY_INUSE = (1 << 2),
-+ QUEUE_EMPTY_RINGING = (1 << 3),
-+ QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
-+ QUEUE_EMPTY_INVALID = (1 << 5),
-+ QUEUE_EMPTY_UNKNOWN = (1 << 6),
-+ QUEUE_EMPTY_WRAPUP = (1 << 7),
- };
-
--static AST_LIST_HEAD_STATIC(interfaces, member_interface);
--
- /* values used in multi-bit flags in call_queue */
--#define QUEUE_EMPTY_NORMAL 1
--#define QUEUE_EMPTY_STRICT 2
--#define QUEUE_EMPTY_LOOSE 3
- #define ANNOUNCEHOLDTIME_ALWAYS 1
- #define ANNOUNCEHOLDTIME_ONCE 2
- #define QUEUE_EVENT_VARIABLES 3
-@@ -477,9 +755,7 @@
- /*! Sound files: Custom announce, no default */
- struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
- unsigned int dead:1;
-- unsigned int joinempty:2;
- unsigned int eventwhencalled:2;
-- unsigned int leavewhenempty:2;
- unsigned int ringinuse:1;
- unsigned int setinterfacevar:1;
- unsigned int setqueuevar:1;
-@@ -493,6 +769,8 @@
- unsigned int maskmemberstatus:1;
- unsigned int realtime:1;
- unsigned int found:1;
-+ enum empty_conditions joinempty;
-+ enum empty_conditions leavewhenempty;
- int announcepositionlimit; /*!< How many positions we announce? */
- int announcefrequency; /*!< How often to announce their position */
- int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
-@@ -501,6 +779,7 @@
- int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
- int roundingseconds; /*!< How many seconds do we round to? */
- int holdtime; /*!< Current avg holdtime, based on an exponential average */
-+ int talktime; /*!< Current avg talktime, based on the same exponential average */
- int callscompleted; /*!< Number of queue calls completed */
- int callsabandoned; /*!< Number of queue calls abandoned */
- int servicelevel; /*!< seconds setting for servicelevel*/
-@@ -544,8 +823,6 @@
-
- static struct ao2_container *queues;
-
--static void copy_rules(struct queue_ent *qe, const char *rulename);
--static void update_qe_rule(struct queue_ent *qe);
- static void update_realtime_members(struct call_queue *q);
- static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
-
-@@ -624,8 +901,8 @@
- sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
-
- snprintf(interfacevar, sizeof(interfacevar),
-- "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
-- q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
-+ "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
-+ q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
-
- pbx_builtin_setvar_multiple(chan, interfacevar);
- }
-@@ -651,53 +928,67 @@
- new->opos = *pos;
- }
-
--enum queue_member_status {
-- QUEUE_NO_MEMBERS,
-- QUEUE_NO_REACHABLE_MEMBERS,
-- QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
-- QUEUE_NORMAL
--};
--
- /*! \brief Check if members are available
- *
- * This function checks to see if members are available to be called. If any member
-- * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
-- * the appropriate reason why is returned
-+ * is available, the function immediately returns 0. If no members are available,
-+ * then -1 is returned.
- */
--static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty, int min_penalty)
-+static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
- {
- struct member *member;
- struct ao2_iterator mem_iter;
-- enum queue_member_status result = QUEUE_NO_MEMBERS;
-
- ao2_lock(q);
- mem_iter = ao2_iterator_init(q->members, 0);
- for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
-- if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty)))
-- continue;
-+ if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
-+ if (conditions & QUEUE_EMPTY_PENALTY) {
-+ ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
-+ continue;
-+ }
-+ }
-
- switch (member->status) {
- case AST_DEVICE_INVALID:
-- /* nothing to do */
-- break;
-+ if (conditions & QUEUE_EMPTY_INVALID) {
-+ ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
-+ break;
-+ }
- case AST_DEVICE_UNAVAILABLE:
-- if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
-- result = QUEUE_NO_REACHABLE_MEMBERS;
-- break;
-+ if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
-+ ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
-+ break;
-+ }
-+ case AST_DEVICE_INUSE:
-+ if (conditions & QUEUE_EMPTY_INUSE) {
-+ ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
-+ break;
-+ }
-+ case AST_DEVICE_UNKNOWN:
-+ if (conditions & QUEUE_EMPTY_UNKNOWN) {
-+ ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
-+ break;
-+ }
- default:
-- if (member->paused) {
-- result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
-+ if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
-+ ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
-+ break;
-+ } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
-+ ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
-+ break;
- } else {
- ao2_unlock(q);
- ao2_ref(member, -1);
-- return QUEUE_NORMAL;
-+ ast_debug(4, "%s is available.\n", member->membername);
-+ return 0;
- }
- break;
- }
- }
-
- ao2_unlock(q);
-- return result;
-+ return -1;
- }
-
- struct statechange {
-@@ -711,87 +1002,69 @@
- * Lock interface list find sc, iterate through each queues queue_member list for member to
- * update state inside queues
- */
--static int update_status(const char *interface, const int status)
-+static int update_status(struct call_queue *q, struct member *m, const int status)
- {
-- struct member *cur;
-- struct ao2_iterator mem_iter, queue_iter;
-- struct call_queue *q;
-+ m->status = status;
-
-- queue_iter = ao2_iterator_init(queues, 0);
-- while ((q = ao2_iterator_next(&queue_iter))) {
-- ao2_lock(q);
-- mem_iter = ao2_iterator_init(q->members, 0);
-- while ((cur = ao2_iterator_next(&mem_iter))) {
-- char *tmp_interface;
-- char *slash_pos;
-- tmp_interface = ast_strdupa(cur->state_interface);
-- if ((slash_pos = strchr(tmp_interface, '/')))
-- if (!strncasecmp(tmp_interface, "Local", 5) && (slash_pos = strchr(slash_pos + 1, '/')))
-- *slash_pos = '\0';
-+ if (q->maskmemberstatus)
-+ return 0;
-
-- if (strcasecmp(interface, tmp_interface)) {
-- ao2_ref(cur, -1);
-- continue;
-- }
-+ manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
-+ "Queue: %s\r\n"
-+ "Location: %s\r\n"
-+ "MemberName: %s\r\n"
-+ "Membership: %s\r\n"
-+ "Penalty: %d\r\n"
-+ "CallsTaken: %d\r\n"
-+ "LastCall: %d\r\n"
-+ "Status: %d\r\n"
-+ "Paused: %d\r\n",
-+ q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
-+ m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
-+ );
-
-- if (cur->status != status) {
-- cur->status = status;
-- if (q->maskmemberstatus) {
-- ao2_ref(cur, -1);
-- continue;
-- }
--
-- manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
-- "Queue: %s\r\n"
-- "Location: %s\r\n"
-- "MemberName: %s\r\n"
-- "Membership: %s\r\n"
-- "Penalty: %d\r\n"
-- "CallsTaken: %d\r\n"
-- "LastCall: %d\r\n"
-- "Status: %d\r\n"
-- "Paused: %d\r\n",
-- q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
-- cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
-- }
-- ao2_ref(cur, -1);
-- }
-- queue_unref(q);
-- ao2_unlock(q);
-- }
--
- return 0;
- }
-
- /*! \brief set a member's status based on device state of that member's interface*/
- static int handle_statechange(void *datap)
- {
-- struct member_interface *curint;
- struct statechange *sc = datap;
-+ struct ao2_iterator miter, qiter;
-+ struct member *m;
-+ struct call_queue *q;
-+ char interface[80], *slash_pos;
-+ int found = 0;
-
-- AST_LIST_LOCK(&interfaces);
-- AST_LIST_TRAVERSE(&interfaces, curint, list) {
-- char *interface;
-- char *slash_pos;
-- interface = ast_strdupa(curint->interface);
-- if ((slash_pos = strchr(interface, '/')))
-- if ((slash_pos = strchr(slash_pos + 1, '/')))
-- *slash_pos = '\0';
-+ qiter = ao2_iterator_init(queues, 0);
-
-- if (!strcasecmp(interface, sc->dev))
-- break;
-- }
-- AST_LIST_UNLOCK(&interfaces);
-+ while ((q = ao2_iterator_next(&qiter))) {
-+ ao2_lock(q);
-
-- if (!curint) {
-- ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, devstate2str(sc->state));
-- ast_free(sc);
-- return 0;
-+ miter = ao2_iterator_init(q->members, 0);
-+ for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
-+ ast_copy_string(interface, m->state_interface, sizeof(interface));
-+
-+ if ((slash_pos = strchr(interface, '/')))
-+ if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
-+ *slash_pos = '\0';
-+
-+ if (!strcasecmp(interface, sc->dev)) {
-+ found = 1;
-+ update_status(q, m, sc->state);
-+ ao2_ref(m, -1);
-+ break;
-+ }
-+ }
-+
-+ ao2_unlock(q);
- }
-
-- ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, devstate2str(sc->state));
-+ if (found)
-+ ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
-+ else
-+ ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
-
-- update_status(sc->dev, sc->state);
- ast_free(sc);
- return 0;
- }
-@@ -923,7 +1196,6 @@
- else
- q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
- }
-- q->membercount = 0;
- q->found = 1;
-
- ast_string_field_set(q, sound_next, "queue-youarenext");
-@@ -959,90 +1231,6 @@
- q->wrapuptime = 0;
- }
-
--static int add_to_interfaces(const char *interface)
--{
-- struct member_interface *curint;
--
-- AST_LIST_LOCK(&interfaces);
-- AST_LIST_TRAVERSE(&interfaces, curint, list) {
-- if (!strcasecmp(curint->interface, interface))
-- break;
-- }
--
-- if (curint) {
-- AST_LIST_UNLOCK(&interfaces);
-- return 0;
-- }
--
-- ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
--
-- if ((curint = ast_calloc(1, sizeof(*curint)))) {
-- ast_copy_string(curint->interface, interface, sizeof(curint->interface));
-- AST_LIST_INSERT_HEAD(&interfaces, curint, list);
-- }
-- AST_LIST_UNLOCK(&interfaces);
--
-- return 0;
--}
--
--static int interface_exists_global(const char *interface, int lock_queue_container)
--{
-- struct call_queue *q;
-- struct member *mem, tmpmem;
-- struct ao2_iterator queue_iter, mem_iter;
-- int ret = 0;
--
-- ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
-- queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : F_AO2I_DONTLOCK);
-- while ((q = ao2_iterator_next(&queue_iter))) {
-- ao2_lock(q);
-- mem_iter = ao2_iterator_init(q->members, 0);
-- while ((mem = ao2_iterator_next(&mem_iter))) {
-- if (!strcasecmp(mem->state_interface, interface)) {
-- ao2_ref(mem, -1);
-- ret = 1;
-- break;
-- }
-- }
-- ao2_unlock(q);
-- queue_unref(q);
-- }
--
-- return ret;
--}
--
--static int remove_from_interfaces(const char *interface, int lock_queue_container)
--{
-- struct member_interface *curint;
--
-- if (interface_exists_global(interface, lock_queue_container))
-- return 0;
--
-- AST_LIST_LOCK(&interfaces);
-- AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
-- if (!strcasecmp(curint->interface, interface)) {
-- ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
-- AST_LIST_REMOVE_CURRENT(list);
-- ast_free(curint);
-- break;
-- }
-- }
-- AST_LIST_TRAVERSE_SAFE_END;
-- AST_LIST_UNLOCK(&interfaces);
--
-- return 0;
--}
--
--static void clear_and_free_interfaces(void)
--{
-- struct member_interface *curint;
--
-- AST_LIST_LOCK(&interfaces);
-- while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
-- ast_free(curint);
-- AST_LIST_UNLOCK(&interfaces);
--}
--
- /*!
- * \brief Change queue penalty by adding rule.
- *
-@@ -1060,7 +1248,6 @@
- int penaltychangetime, inserted = 0;
-
- if (!(rule = ast_calloc(1, sizeof(*rule)))) {
-- ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
- return -1;
- }
-
-@@ -1123,6 +1310,39 @@
- return 0;
- }
-
-+static void parse_empty_options(const char *value, enum empty_conditions *empty)
-+{
-+ char *value_copy = ast_strdupa(value);
-+ char *option = NULL;
-+ while ((option = strsep(&value_copy, ","))) {
-+ if (!strcasecmp(option, "paused")) {
-+ *empty |= QUEUE_EMPTY_PAUSED;
-+ } else if (!strcasecmp(option, "penalty")) {
-+ *empty |= QUEUE_EMPTY_PENALTY;
-+ } else if (!strcasecmp(option, "inuse")) {
-+ *empty |= QUEUE_EMPTY_INUSE;
-+ } else if (!strcasecmp(option, "ringing")) {
-+ *empty |= QUEUE_EMPTY_RINGING;
-+ } else if (!strcasecmp(option, "invalid")) {
-+ *empty |= QUEUE_EMPTY_INVALID;
-+ } else if (!strcasecmp(option, "wrapup")) {
-+ *empty |= QUEUE_EMPTY_WRAPUP;
-+ } else if (!strcasecmp(option, "unavailable")) {
-+ *empty |= QUEUE_EMPTY_UNAVAILABLE;
-+ } else if (!strcasecmp(option, "unknown")) {
-+ *empty |= QUEUE_EMPTY_UNKNOWN;
-+ } else if (!strcasecmp(option, "loose")) {
-+ *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
-+ } else if (!strcasecmp(option, "strict")) {
-+ *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
-+ } else if (ast_false(option)) {
-+ *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
-+ } else if (ast_true(option)) {
-+ *empty = 0;
-+ }
-+ }
-+}
-+
- /*! \brief Configure a queue parameter.
- *
- * The failunknown flag is set for config files (and static realtime) to show
-@@ -1283,23 +1503,9 @@
- }
- q->strategy = strategy;
- } else if (!strcasecmp(param, "joinempty")) {
-- if (!strcasecmp(val, "loose"))
-- q->joinempty = QUEUE_EMPTY_LOOSE;
-- else if (!strcasecmp(val, "strict"))
-- q->joinempty = QUEUE_EMPTY_STRICT;
-- else if (ast_true(val))
-- q->joinempty = QUEUE_EMPTY_NORMAL;
-- else
-- q->joinempty = 0;
-+ parse_empty_options(val, &q->joinempty);
- } else if (!strcasecmp(param, "leavewhenempty")) {
-- if (!strcasecmp(val, "loose"))
-- q->leavewhenempty = QUEUE_EMPTY_LOOSE;
-- else if (!strcasecmp(val, "strict"))
-- q->leavewhenempty = QUEUE_EMPTY_STRICT;
-- else if (ast_true(val))
-- q->leavewhenempty = QUEUE_EMPTY_NORMAL;
-- else
-- q->leavewhenempty = 0;
-+ parse_empty_options(val, &q->leavewhenempty);
- } else if (!strcasecmp(param, "eventmemberstatus")) {
- q->maskmemberstatus = !ast_true(val);
- } else if (!strcasecmp(param, "eventwhencalled")) {
-@@ -1314,10 +1520,6 @@
- q->memberdelay = atoi(val);
- } else if (!strcasecmp(param, "weight")) {
- q->weight = atoi(val);
-- if (q->weight)
-- use_weight++;
-- /* With Realtime queues, if the last queue using weights is deleted in realtime,
-- we will not see any effect on use_weight until next reload. */
- } else if (!strcasecmp(param, "timeoutrestart")) {
- q->timeoutrestart = ast_true(val);
- } else if (!strcasecmp(param, "defaultrule")) {
-@@ -1373,9 +1575,7 @@
- if (paused_str)
- m->paused = paused;
- if (strcasecmp(state_interface, m->state_interface)) {
-- remove_from_interfaces(m->state_interface, 0);
- ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
-- add_to_interfaces(m->state_interface);
- }
- m->penalty = penalty;
- found = 1;
-@@ -1391,7 +1591,6 @@
- m->dead = 0;
- m->realtime = 1;
- ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
-- add_to_interfaces(m->state_interface);
- ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
- ao2_link(q->members, m);
- ao2_ref(m, -1);
-@@ -1411,7 +1610,6 @@
- while ((cur = ao2_iterator_next(&mem_iter))) {
- if (all || !cur->dynamic) {
- ao2_unlink(q->members, cur);
-- remove_from_interfaces(cur->state_interface, 1);
- q->membercount--;
- }
- ao2_ref(cur, -1);
-@@ -1515,6 +1713,7 @@
- ao2_lock(q);
- clear_queue(q);
- q->realtime = 1;
-+ q->membercount = 0;
- /*Before we initialize the queue, we need to set the strategy, so that linear strategy
- * will allocate the members properly
- */
-@@ -1579,7 +1778,6 @@
- if (m->dead) {
- ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
- ao2_unlink(q->members, m);
-- remove_from_interfaces(m->state_interface, 0);
- q->membercount--;
- }
- ao2_ref(m, -1);
-@@ -1597,6 +1795,7 @@
- struct call_queue *q = NULL, tmpq = {
- .name = queuename,
- };
-+ int prev_weight = 0;
-
- /* Find the queue in the in-core list first. */
- q = ao2_find(queues, &tmpq, OBJ_POINTER);
-@@ -1620,13 +1819,27 @@
- return NULL;
- }
- }
-+ if (q) {
-+ prev_weight = q->weight ? 1 : 0;
-+ }
-
- ao2_lock(queues);
-+
- q = find_queue_by_name_rt(queuename, queue_vars, member_config);
-- if (member_config)
-+ if (member_config) {
- ast_config_destroy(member_config);
-- if (queue_vars)
-+ }
-+ if (queue_vars) {
- ast_variables_destroy(queue_vars);
-+ }
-+ /* update the use_weight value if the queue's has gained or lost a weight */
-+ if (!q->weight && prev_weight) {
-+ ast_atomic_fetchadd_int(&use_weight, -1);
-+ }
-+ if (q->weight && !prev_weight) {
-+ ast_atomic_fetchadd_int(&use_weight, +1);
-+ }
-+ /* Other cases will end up with the proper value for use_weight */
- ao2_unlock(queues);
-
- } else {
-@@ -1688,7 +1901,6 @@
- if (m->dead) {
- ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
- ao2_unlink(q->members, m);
-- remove_from_interfaces(m->state_interface, 0);
- q->membercount--;
- }
- ao2_ref(m, -1);
-@@ -1698,15 +1910,13 @@
- ast_config_destroy(member_config);
- }
-
--static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, const char *overriding_rule)
-+static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
- {
- struct call_queue *q;
- struct queue_ent *cur, *prev = NULL;
- int res = -1;
- int pos = 0;
- int inserted = 0;
-- enum queue_member_status status;
-- int exit = 0;
-
- if (!(q = load_realtime_queue(queuename)))
- return res;
-@@ -1714,63 +1924,52 @@
- ao2_lock(queues);
- ao2_lock(q);
-
-- copy_rules(qe, S_OR(overriding_rule, q->defaultrule));
-- qe->pr = AST_LIST_FIRST(&qe->qe_rules);
--
- /* This is our one */
-- while (!exit) {
-- status = get_member_status(q, qe->max_penalty, qe->min_penalty);
-- if (!q->joinempty && (status == QUEUE_NO_MEMBERS))
-+ if (q->joinempty) {
-+ int status = 0;
-+ if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
- *reason = QUEUE_JOINEMPTY;
-- else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS))
-- *reason = QUEUE_JOINUNAVAIL;
-- else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS))
-- *reason = QUEUE_JOINUNAVAIL;
-- else if (q->maxlen && (q->count >= q->maxlen))
-- *reason = QUEUE_FULL;
-- else {
-- /* There's space for us, put us at the right position inside
-- * the queue.
-- * Take into account the priority of the calling user */
-- inserted = 0;
-- prev = NULL;
-- cur = q->head;
-- while (cur) {
-- /* We have higher priority than the current user, enter
-- * before him, after all the other users with priority
-- * higher or equal to our priority. */
-- if ((!inserted) && (qe->prio > cur->prio)) {
-- insert_entry(q, prev, qe, &pos);
-- inserted = 1;
-- }
-- cur->pos = ++pos;
-- prev = cur;
-- cur = cur->next;
-+ ao2_unlock(q);
-+ ao2_unlock(queues);
-+ return res;
-+ }
-+ }
-+ if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
-+ *reason = QUEUE_FULL;
-+ else if (*reason == QUEUE_UNKNOWN) {
-+ /* There's space for us, put us at the right position inside
-+ * the queue.
-+ * Take into account the priority of the calling user */
-+ inserted = 0;
-+ prev = NULL;
-+ cur = q->head;
-+ while (cur) {
-+ /* We have higher priority than the current user, enter
-+ * before him, after all the other users with priority
-+ * higher or equal to our priority. */
-+ if ((!inserted) && (qe->prio > cur->prio)) {
-+ insert_entry(q, prev, qe, &pos);
-+ inserted = 1;
- }
-- /* No luck, join at the end of the queue */
-- if (!inserted)
-- insert_entry(q, prev, qe, &pos);
-- ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
-- ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
-- ast_copy_string(qe->context, q->context, sizeof(qe->context));
-- q->count++;
-- res = 0;
-- manager_event(EVENT_FLAG_CALL, "Join",
-- "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
-- qe->chan->name,
-- S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
-- S_OR(qe->chan->cid.cid_name, "unknown"),
-- q->name, qe->pos, q->count, qe->chan->uniqueid );
-- ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
-+ cur->pos = ++pos;
-+ prev = cur;
-+ cur = cur->next;
- }
-- if (!exit && qe->pr && res) {
-- /* We failed to join the queue, but perhaps we can join if we move
-- * to the next defined penalty rule
-- */
-- update_qe_rule(qe);
-- } else {
-- exit = 1;
-- }
-+ /* No luck, join at the end of the queue */
-+ if (!inserted)
-+ insert_entry(q, prev, qe, &pos);
-+ ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
-+ ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
-+ ast_copy_string(qe->context, q->context, sizeof(qe->context));
-+ q->count++;
-+ res = 0;
-+ manager_event(EVENT_FLAG_CALL, "Join",
-+ "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
-+ qe->chan->name,
-+ S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
-+ S_OR(qe->chan->cid.cid_name, "unknown"),
-+ q->name, qe->pos, q->count, qe->chan->uniqueid );
-+ ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
- }
- ao2_unlock(q);
- ao2_unlock(queues);
-@@ -1834,6 +2033,7 @@
- static int say_position(struct queue_ent *qe, int ringing)
- {
- int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
-+ int say_thanks = 1;
- time_t now;
-
- /* Let minannouncefrequency seconds pass between the start of each position announcement */
-@@ -1942,15 +2142,16 @@
- if (res)
- goto playout;
- }
--
-+ } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
-+ say_thanks = 0;
- }
-
- posout:
-- if (announceposition == 1){
-- if (qe->parent->announceposition) {
-- ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
-- qe->chan->name, qe->parent->name, qe->pos);
-- }
-+ if (qe->parent->announceposition) {
-+ ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
-+ qe->chan->name, qe->parent->name, qe->pos);
-+ }
-+ if (say_thanks) {
- res = play_file(qe->chan, qe->parent->sound_thanks);
- }
- playout:
-@@ -2048,14 +2249,18 @@
- }
-
- /*! \brief Hang up a list of outgoing calls */
--static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
-+static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
- {
- struct callattempt *oo;
-
- while (outgoing) {
-+ /* If someone else answered the call we should indicate this in the CANCEL */
- /* Hangup any existing lines we have open */
-- if (outgoing->chan && (outgoing->chan != exception))
-+ if (outgoing->chan && (outgoing->chan != exception || cancel_answered_elsewhere)) {
-+ if (exception || cancel_answered_elsewhere)
-+ ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
- ast_hangup(outgoing->chan);
-+ }
- oo = outgoing;
- outgoing = outgoing->q_next;
- if (oo->member)
-@@ -2115,7 +2320,7 @@
- /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
- static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
- {
-- struct ast_str *buf = ast_str_alloca(len + 1);
-+ struct ast_str *buf = ast_str_thread_get(&global_app_buf, len + 1);
- char *tmp;
-
- if (pbx_builtin_serialize_variables(chan, &buf)) {
-@@ -2123,7 +2328,7 @@
-
- /* convert "\n" to "\nVariable: " */
- strcpy(vars, "Variable: ");
-- tmp = buf->str;
-+ tmp = ast_str_buffer(buf);
-
- for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
- vars[j] = tmp[i];
-@@ -2219,33 +2424,47 @@
- if (!tmp->chan) { /* If we can't, just go on to the next call */
- if (qe->chan->cdr)
- ast_cdr_busy(qe->chan->cdr);
-- tmp->stillgoing = 0;
-+ tmp->stillgoing = 0;
-
-- update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
--
- ao2_lock(qe->parent);
-+ update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
- qe->parent->rrpos++;
- qe->linpos++;
- ao2_unlock(qe->parent);
-
--
- (*busies)++;
- return 0;
- }
-
-+ if (qe->cancel_answered_elsewhere) {
-+ ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
-+ }
- tmp->chan->appl = "AppQueue";
- tmp->chan->data = "(Outgoing Line)";
- memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
-- if (tmp->chan->cid.cid_num)
-- ast_free(tmp->chan->cid.cid_num);
-- tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
-- if (tmp->chan->cid.cid_name)
-- ast_free(tmp->chan->cid.cid_name);
-- tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
-- if (tmp->chan->cid.cid_ani)
-- ast_free(tmp->chan->cid.cid_ani);
-- tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
-
-+ /* If the new channel has no callerid, try to guess what it should be */
-+ if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
-+ if (!ast_strlen_zero(qe->chan->connected.id.number)) {
-+ ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
-+ tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
-+ } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
-+ ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
-+ } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
-+ ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
-+ }
-+ tmp->update_connectedline = 0;
-+ }
-+
-+ if (tmp->chan->cid.cid_rdnis)
-+ ast_free(tmp->chan->cid.cid_rdnis);
-+ tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
-+ ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
-+
-+ tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
-+
-+ ast_copy_caller_to_connected(&tmp->chan->connected, &qe->chan->cid);
-+
- /* Inherit specially named variables from parent channel */
- ast_channel_inherit_variables(qe->chan, tmp->chan);
-
-@@ -2270,7 +2489,7 @@
- ast_verb(3, "Couldn't call %s\n", tmp->interface);
- do_hang(tmp);
- (*busies)++;
-- update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
-+ update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
- return 0;
- } else if (qe->parent->eventwhencalled) {
- char vars[2048];
-@@ -2296,7 +2515,7 @@
- ast_verb(3, "Called %s\n", tmp->interface);
- }
-
-- update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
-+ update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
- return 1;
- }
-
-@@ -2434,12 +2653,12 @@
- if (qe->parent->randomperiodicannounce) {
- qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
- } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
-- ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) {
-+ ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
- qe->last_periodic_announce_sound = 0;
- }
-
- /* play the announcement */
-- res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str);
-+ res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
-
- if ((res > 0 && !valid_exit(qe, res)) || res < 0)
- res = 0;
-@@ -2481,25 +2700,30 @@
- }
-
- /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
--static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
-+static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
- {
- ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
-- if (qe->parent->eventwhencalled)
-+ if (qe->parent->eventwhencalled) {
-+ char vars[2048];
-+
- manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
- "Queue: %s\r\n"
- "Uniqueid: %s\r\n"
- "Channel: %s\r\n"
- "Member: %s\r\n"
- "MemberName: %s\r\n"
-- "Ringtime: %d\r\n",
-+ "Ringtime: %d\r\n"
-+ "%s",
- qe->parent->name,
- qe->chan->uniqueid,
- qe->chan->name,
- interface,
- membername,
-- rnatime);
-+ rnatime,
-+ qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
-+ }
- ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
-- if (qe->parent->autopause) {
-+ if (qe->parent->autopause && pause) {
- if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
- ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
- } else {
-@@ -2520,7 +2744,7 @@
- * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
- * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
- */
--static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
-+static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
- {
- const char *queue = qe->parent->name;
- struct callattempt *o, *start = NULL, *prev = NULL;
-@@ -2540,6 +2764,7 @@
- #ifdef HAVE_EPOLL
- struct callattempt *epollo;
- #endif
-+ struct ast_party_connected_line connected_caller;
-
- starttime = (long) time(NULL);
- #ifdef HAVE_EPOLL
-@@ -2583,7 +2808,7 @@
- if (numlines == (numbusies + numnochan)) {
- ast_debug(1, "Everyone is busy at this time\n");
- } else {
-- ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
-+ ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
- }
- *to = 0;
- return NULL;
-@@ -2593,6 +2818,15 @@
- if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
- if (!peer) {
- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
-+ if (update_connectedline) {
-+ if (o->connected.id.number) {
-+ ast_connected_line_update(in, &o->connected);
-+ } else if (o->update_connectedline) {
-+ ast_party_connected_line_collect_caller(&connected_caller, &o->chan->cid);
-+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-+ ast_connected_line_update(in, &connected_caller);
-+ }
-+ }
- peer = o;
- }
- } else if (o->chan && (o->chan == winner)) {
-@@ -2607,6 +2841,9 @@
- winner = NULL;
- continue;
- } else if (!ast_strlen_zero(o->chan->call_forward)) {
-+ struct ast_party_redirecting *apr = &o->chan->redirecting;
-+ struct ast_party_connected_line *apc = &o->chan->connected;
-+ struct ast_channel *original = o->chan;
- char tmpchan[256];
- char *stuff;
- char *tech;
-@@ -2631,25 +2868,29 @@
- } else {
- ast_channel_inherit_variables(in, o->chan);
- ast_channel_datastore_inherit(in, o->chan);
-- if (o->chan->cid.cid_num)
-- ast_free(o->chan->cid.cid_num);
-- o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
-
-- if (o->chan->cid.cid_name)
-- ast_free(o->chan->cid.cid_name);
-- o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
--
- ast_string_field_set(o->chan, accountcode, in->accountcode);
- o->chan->cdrflags = in->cdrflags;
-
-- if (in->cid.cid_ani) {
-- if (o->chan->cid.cid_ani)
-- ast_free(o->chan->cid.cid_ani);
-- o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
-- }
-+ ast_set_redirecting(o->chan, apr);
-+
- if (o->chan->cid.cid_rdnis)
- ast_free(o->chan->cid.cid_rdnis);
-- o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
-+ o->chan->cid.cid_rdnis = ast_strdup(S_OR(original->cid.cid_rdnis,S_OR(in->macroexten, in->exten)));
-+
-+ o->chan->cid.cid_tns = in->cid.cid_tns;
-+
-+ ast_party_caller_copy(&o->chan->cid, &in->cid);
-+ ast_party_connected_line_copy(&o->chan->connected, apc);
-+
-+ ast_redirecting_update(in, apr);
-+ if (in->cid.cid_rdnis) {
-+ ast_free(in->cid.cid_rdnis);
-+ }
-+ in->cid.cid_rdnis = ast_strdup(o->chan->cid.cid_rdnis);
-+
-+ update_connectedline = 1;
-+
- if (ast_call(o->chan, tmpchan, 0)) {
- ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
- do_hang(o);
-@@ -2668,6 +2909,15 @@
- /* This is our guy if someone answered. */
- if (!peer) {
- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
-+ if (update_connectedline) {
-+ if (o->connected.id.number) {
-+ ast_connected_line_update(in, &o->connected);
-+ } else if (o->update_connectedline) {
-+ ast_party_connected_line_collect_caller(&connected_caller, &o->chan->cid);
-+ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-+ ast_connected_line_update(in, &connected_caller);
-+ }
-+ }
- peer = o;
- }
- break;
-@@ -2678,7 +2928,7 @@
- do_hang(o);
- endtime = (long) time(NULL);
- endtime -= starttime;
-- rna(endtime*1000, qe, on, membername);
-+ rna(endtime * 1000, qe, on, membername, 0);
- if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
- if (qe->parent->timeoutrestart)
- *to = orig;
-@@ -2692,7 +2942,7 @@
- ast_cdr_busy(in->cdr);
- endtime = (long) time(NULL);
- endtime -= starttime;
-- rna(endtime*1000, qe, on, membername);
-+ rna(endtime * 1000, qe, on, membername, 0);
- do_hang(o);
- if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
- if (qe->parent->timeoutrestart)
-@@ -2707,14 +2957,38 @@
- case AST_CONTROL_OFFHOOK:
- /* Ignore going off hook */
- break;
-+ case AST_CONTROL_CONNECTED_LINE:
-+ if (!update_connectedline) {
-+ ast_verb(3, "Connected line update to %s prevented.\n", in->name);
-+ } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
-+ struct ast_party_connected_line connected;
-+ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", o->chan->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", o->chan->name, in->name);
-+ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
-+ }
-+ break;
-+ case AST_CONTROL_REDIRECTING:
-+ if (!update_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", o->chan->name, in->name);
-+ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
-+ }
-+ break;
- default:
- ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
-+ break;
- }
- }
- ast_frfree(f);
- } else {
- endtime = (long) time(NULL) - starttime;
-- rna(endtime * 1000, qe, on, membername);
-+ rna(endtime * 1000, qe, on, membername, 1);
- do_hang(o);
- if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
- if (qe->parent->timeoutrestart)
-@@ -2754,7 +3028,7 @@
- }
- if (!*to) {
- for (o = start; o; o = o->call_next)
-- rna(orig, qe, o->interface, o->member->membername);
-+ rna(orig, qe, o->interface, o->member->membername, 1);
- }
- }
-
-@@ -2892,8 +3166,6 @@
-
- /* This is the holding pen for callers 2 through maxlen */
- for (;;) {
-- enum queue_member_status status = QUEUE_NORMAL;
-- int exit = 0;
-
- if (is_our_turn(qe))
- break;
-@@ -2904,48 +3176,17 @@
- break;
- }
-
-- /* If we are going to exit due to a leavewhenempty condition, we should
-- * actually attempt to keep the caller in the queue until we have
-- * exhausted all penalty rules.
-- */
-- for (; !exit || qe->pr; update_qe_rule(qe)) {
-- status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
--
-- if (!qe->pr || status == QUEUE_NORMAL) {
-+ if (qe->parent->leavewhenempty) {
-+ int status = 0;
-+
-+ if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
-+ *reason = QUEUE_LEAVEEMPTY;
-+ ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
-+ leave_queue(qe);
- break;
- }
--
-- /* leave the queue if no agents, if enabled */
-- if ((qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) ||
-- ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) ||
-- ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) {
-- continue;
-- } else {
-- exit = 1;
-- }
- }
-
-- if (qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) {
-- *reason = QUEUE_LEAVEEMPTY;
-- ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
-- leave_queue(qe);
-- break;
-- }
--
-- /* leave the queue if no reachable agents, if enabled */
-- if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
-- *reason = QUEUE_LEAVEUNAVAIL;
-- ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
-- leave_queue(qe);
-- break;
-- }
-- if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS)) {
-- *reason = QUEUE_LEAVEUNAVAIL;
-- ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
-- leave_queue(qe);
-- break;
-- }
--
- /* Make a position announcement, if enabled */
- if (qe->parent->announcefrequency &&
- (res = say_position(qe,ringing)))
-@@ -2995,8 +3236,10 @@
- * \brief update the queue status
- * \retval Always 0
- */
--static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
-+static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
- {
-+ int oldtalktime;
-+
- struct member *mem;
- struct call_queue *qtmp;
- struct ao2_iterator queue_iter;
-@@ -3025,6 +3268,9 @@
- q->callscompleted++;
- if (callcompletedinsl)
- q->callscompletedinsl++;
-+ /* Calculate talktime using the same exponential average as holdtime code*/
-+ oldtalktime = q->talktime;
-+ q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
- ao2_unlock(q);
- return 0;
- }
-@@ -3180,7 +3426,7 @@
- new_chan->exten, new_chan->context, (long) (callstart - qe->start),
- (long) (time(NULL) - callstart), qe->opos);
-
-- update_queue(qe->parent, member, callcompletedinsl);
-+ update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
-
- /* No need to lock the channels because they are already locked in ast_do_masquerade */
- if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
-@@ -3324,6 +3570,7 @@
- char *p;
- char vars[2048];
- int forwardsallowed = 1;
-+ int update_connectedline = 1;
- int callcompletedinsl;
- struct ao2_iterator memi;
- struct ast_datastore *datastore, *transfer_ds;
-@@ -3389,13 +3636,18 @@
- case 'i':
- forwardsallowed = 0;
- break;
-+ case 'I':
-+ update_connectedline = 0;
-+ break;
- case 'x':
- ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
- break;
- case 'X':
- ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
- break;
--
-+ case 'C':
-+ qe->cancel_answered_elsewhere = 1;
-+ break;
- }
-
- if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
-@@ -3411,6 +3663,13 @@
- queue_ref(qe->parent);
- }
-
-+ /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited.
-+ (this is mainly to support chan_local)
-+ */
-+ if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) {
-+ qe->cancel_answered_elsewhere = 1;
-+ }
-+
- /* Hold the lock while we setup the outgoing calls */
- if (use_weight)
- ao2_lock(queues);
-@@ -3471,6 +3730,17 @@
- }
- }
- AST_LIST_UNLOCK(dialed_interfaces);
-+
-+ ast_channel_lock(qe->chan);
-+ /* If any pre-existing connected line information exists on this
-+ * channel, like from the CONNECTED_LINE dialplan function, use this
-+ * to seed the connected line information. It may, of course, be updated
-+ * during the call
-+ */
-+ if (qe->chan->connected.id.number) {
-+ ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
-+ }
-+ ast_channel_unlock(qe->chan);
-
- if (di) {
- free(tmp);
-@@ -3502,6 +3772,7 @@
- tmp->oldstatus = cur->status;
- tmp->lastcall = cur->lastcall;
- tmp->lastqueue = cur->lastqueue;
-+ tmp->update_connectedline = 1;
- ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
- /* Special case: If we ring everyone, go ahead and ring them, otherwise
- just calculate their metric for the appropriate strategy */
-@@ -3542,7 +3813,7 @@
- ring_one(qe, outgoing, &numbusies);
- if (use_weight)
- ao2_unlock(queues);
-- lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
-+ lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
- /* The ast_channel_datastore_remove() function could fail here if the
- * datastore was moved to another channel during a masquerade. If this is
- * the case, don't free the datastore here because later, when the channel
-@@ -3591,7 +3862,7 @@
- member = lpeer->member;
- /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
- ao2_ref(member, 1);
-- hangupcalls(outgoing, peer);
-+ hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
- outgoing = NULL;
- if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
- int res2;
-@@ -3982,7 +4253,7 @@
- if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
- ast_channel_datastore_remove(qe->chan, tds);
- }
-- update_queue(qe->parent, member, callcompletedinsl);
-+ update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
- }
-
- if (transfer_ds) {
-@@ -3994,7 +4265,7 @@
- ao2_ref(member, -1);
- }
- out:
-- hangupcalls(outgoing, NULL);
-+ hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
-
- return res;
- }
-@@ -4108,7 +4379,6 @@
- "MemberName: %s\r\n",
- q->name, mem->interface, mem->membername);
- ao2_unlink(q->members, mem);
-- remove_from_interfaces(mem->state_interface, 0);
- ao2_ref(mem, -1);
-
- if (queue_persistent_members)
-@@ -4149,7 +4419,6 @@
- ao2_lock(q);
- if ((old_member = interface_exists(q, interface)) == NULL) {
- if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
-- add_to_interfaces(new_member->state_interface);
- new_member->dynamic = 1;
- ao2_link(q->members, new_member);
- q->membercount++;
-@@ -4538,6 +4807,8 @@
- *temppos = '\0';
- }
-
-+ ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
-+
- switch (remove_from_queue(args.queuename, args.interface)) {
- case RES_OKAY:
- ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
-@@ -4667,10 +4938,7 @@
- {
- struct penalty_rule *pr_iter;
- struct rule_list *rl_iter;
-- const char *tmp = rulename;
-- if (ast_strlen_zero(tmp)) {
-- return;
-- }
-+ const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
- AST_LIST_LOCK(&rule_lists);
- AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
- if (!strcasecmp(rl_iter->name, tmp))
-@@ -4816,13 +5084,15 @@
- qe.last_periodic_announce_time = time(NULL);
- qe.last_periodic_announce_sound = 0;
- qe.valid_digits = 0;
-- if (join_queue(args.queuename, &qe, &reason, args.rule)) {
-+ if (join_queue(args.queuename, &qe, &reason)) {
- ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
- set_queue_result(chan, reason);
- return 0;
- }
- ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
- S_OR(chan->cid.cid_num, ""));
-+ copy_rules(&qe, args.rule);
-+ qe.pr = AST_LIST_FIRST(&qe.qe_rules);
- check_turns:
- if (ringing) {
- ast_indicate(chan, AST_CONTROL_RINGING);
-@@ -4844,9 +5114,6 @@
- /* they may dial a digit from the queue context; */
- /* or, they may timeout. */
-
-- enum queue_member_status status = QUEUE_NORMAL;
-- int exit = 0;
--
- /* Leave if we have exceeded our queuetimeout */
- if (qe.expire && (time(NULL) >= qe.expire)) {
- record_abandoned(&qe);
-@@ -4890,6 +5157,17 @@
- goto stop;
- }
-
-+ if (qe.parent->leavewhenempty) {
-+ int status = 0;
-+ if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
-+ record_abandoned(&qe);
-+ reason = QUEUE_LEAVEEMPTY;
-+ ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
-+ res = 0;
-+ break;
-+ }
-+ }
-+
- /* exit after 'timeout' cycle if 'n' option enabled */
- if (noption && tries >= qe.parent->membercount) {
- ast_verb(3, "Exiting on time-out cycle\n");
-@@ -4900,46 +5178,7 @@
- break;
- }
-
-- for (; !exit || qe.pr; update_qe_rule(&qe)) {
-- status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty);
--
-- if (!qe.pr || status == QUEUE_NORMAL) {
-- break;
-- }
--
-- if ((qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) ||
-- ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) ||
-- ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) {
-- continue;
-- } else {
-- exit = 1;
-- }
-- }
--
-- /* leave the queue if no agents, if enabled */
-- if (qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) {
-- record_abandoned(&qe);
-- reason = QUEUE_LEAVEEMPTY;
-- ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
-- res = 0;
-- break;
-- }
--
-- /* leave the queue if no reachable agents, if enabled */
-- if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
-- record_abandoned(&qe);
-- reason = QUEUE_LEAVEUNAVAIL;
-- ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
-- res = 0;
-- break;
-- }
-- if ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS)) {
-- record_abandoned(&qe);
-- reason = QUEUE_LEAVEUNAVAIL;
-- res = 0;
-- break;
-- }
--
-+
- /* Leave if we have exceeded our queuetimeout */
- if (qe.expire && (time(NULL) >= qe.expire)) {
- record_abandoned(&qe);
-@@ -5036,8 +5275,8 @@
- }
-
- snprintf(interfacevar, sizeof(interfacevar),
-- "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
-- q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
-+ "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
-+ q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
-
- pbx_builtin_setvar_multiple(chan, interfacevar);
- }
-@@ -5304,73 +5543,41 @@
-
- static struct ast_custom_function queuevar_function = {
- .name = "QUEUE_VARIABLES",
-- .synopsis = "Return Queue information in variables",
-- .syntax = "QUEUE_VARIABLES(<queuename>)",
-- .desc =
--"Makes the following queue variables available.\n"
--"QUEUEMAX maxmimum number of calls allowed\n"
--"QUEUESTRATEGY the strategy of the queue\n"
--"QUEUECALLS number of calls currently in the queue\n"
--"QUEUEHOLDTIME current average hold time\n"
--"QUEUECOMPLETED number of completed calls for the queue\n"
--"QUEUEABANDONED number of abandoned calls\n"
--"QUEUESRVLEVEL queue service level\n"
--"QUEUESRVLEVELPERF current service level performance\n"
--"Returns 0 if queue is found and setqueuevar is defined, -1 otherwise",
- .read = queue_function_var,
- };
-
- static struct ast_custom_function queuemembercount_function = {
- .name = "QUEUE_MEMBER",
-- .synopsis = "Count number of members answering a queue",
-- .syntax = "QUEUE_MEMBER(<queuename>, <option>)",
-- .desc =
--"Returns the number of members currently associated with the specified queue.\n"
--"One of three options may be passed to determine the count returned:\n"
-- "\"logged\" - Returns the number of logged-in members for the specified queue\n"
-- "\"free\" - Returns the number of logged-in members for the specified queue available to take a call\n"
-- "\"count\" - Returns the total number of members for the specified queue\n",
- .read = queue_function_qac,
- };
-
- static struct ast_custom_function queuemembercount_dep = {
- .name = "QUEUE_MEMBER_COUNT",
-- .synopsis = "Count number of members answering a queue",
-- .syntax = "QUEUE_MEMBER_COUNT(<queuename>)",
-- .desc =
--"Returns the number of members currently associated with the specified queue.\n\n"
--"This function has been deprecated in favor of the QUEUE_MEMBER function\n",
- .read = queue_function_qac_dep,
- };
-
- static struct ast_custom_function queuewaitingcount_function = {
- .name = "QUEUE_WAITING_COUNT",
-- .synopsis = "Count number of calls currently waiting in a queue",
-- .syntax = "QUEUE_WAITING_COUNT(<queuename>)",
-- .desc =
--"Returns the number of callers currently waiting in the specified queue.\n",
- .read = queue_function_queuewaitingcount,
- };
-
- static struct ast_custom_function queuememberlist_function = {
- .name = "QUEUE_MEMBER_LIST",
-- .synopsis = "Returns a list of interfaces on a queue",
-- .syntax = "QUEUE_MEMBER_LIST(<queuename>)",
-- .desc =
--"Returns a comma-separated list of members associated with the specified queue.\n",
- .read = queue_function_queuememberlist,
- };
-
- static struct ast_custom_function queuememberpenalty_function = {
- .name = "QUEUE_MEMBER_PENALTY",
-- .synopsis = "Gets or sets queue members penalty.",
-- .syntax = "QUEUE_MEMBER_PENALTY(<queuename>,<interface>)",
-- .desc =
--"Gets or sets queue members penalty\n",
- .read = queue_function_memberpenalty_read,
- .write = queue_function_memberpenalty_write,
- };
-
-+/*! \brief Reload the rules defined in queuerules.conf
-+ *
-+ * \param reload If 1, then only process queuerules.conf if the file
-+ * has changed since the last time we inspected it.
-+ * \return Always returns AST_MODULE_LOAD_SUCCESS
-+ */
- static int reload_queue_rules(int reload)
- {
- struct ast_config *cfg;
-@@ -5382,57 +5589,80 @@
-
- if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
- ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
-+ return AST_MODULE_LOAD_SUCCESS;
- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
- ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
- return AST_MODULE_LOAD_SUCCESS;
-- } else {
-- AST_LIST_LOCK(&rule_lists);
-- while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
-- while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
-- ast_free(pr_iter);
-- ast_free(rl_iter);
-+ } else if (cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
-+ return AST_MODULE_LOAD_SUCCESS;
-+ }
-+
-+ AST_LIST_LOCK(&rule_lists);
-+ while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
-+ while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
-+ ast_free(pr_iter);
-+ ast_free(rl_iter);
-+ }
-+ while ((rulecat = ast_category_browse(cfg, rulecat))) {
-+ if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
-+ AST_LIST_UNLOCK(&rule_lists);
-+ return AST_MODULE_LOAD_FAILURE;
-+ } else {
-+ ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
-+ AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
-+ for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
-+ if(!strcasecmp(rulevar->name, "penaltychange"))
-+ insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
-+ else
-+ ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
- }
-- while ((rulecat = ast_category_browse(cfg, rulecat))) {
-- if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
-- ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n");
-- AST_LIST_UNLOCK(&rule_lists);
-- return AST_MODULE_LOAD_FAILURE;
-- } else {
-- ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
-- AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
-- for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
-- if(!strcasecmp(rulevar->name, "penaltychange")) {
-- insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
-- } else {
-- ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
-- }
-- }
-- }
-- AST_LIST_UNLOCK(&rule_lists);
- }
-+ AST_LIST_UNLOCK(&rule_lists);
-
- ast_config_destroy(cfg);
-
- return AST_MODULE_LOAD_SUCCESS;
- }
-
-+/*! Set the global queue parameters as defined in the "general" section of queues.conf */
-+static void queue_set_global_params(struct ast_config *cfg)
-+{
-+ const char *general_val = NULL;
-+ queue_persistent_members = 0;
-+ if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
-+ queue_persistent_members = ast_true(general_val);
-+ autofill_default = 0;
-+ if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
-+ autofill_default = ast_true(general_val);
-+ montype_default = 0;
-+ if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
-+ if (!strcasecmp(general_val, "mixmonitor"))
-+ montype_default = 1;
-+ }
-+ update_cdr = 0;
-+ if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
-+ update_cdr = ast_true(general_val);
-+ shared_lastcall = 0;
-+ if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
-+ shared_lastcall = ast_true(general_val);
-+}
-
--static int reload_queues(int reload)
-+/*! \brief reload information pertaining to a single member
-+ *
-+ * This function is called when a member = line is encountered in
-+ * queues.conf.
-+ *
-+ * \param memberdata The part after member = in the config file
-+ * \param q The queue to which this member belongs
-+ */
-+static void reload_single_member(const char *memberdata, struct call_queue *q)
- {
-- struct call_queue *q;
-- struct ast_config *cfg;
-- char *cat, *tmp;
-- struct ast_variable *var;
-+ char *membername, *interface, *state_interface, *tmp;
-+ char *parse;
- struct member *cur, *newm;
-- struct ao2_iterator mem_iter;
-- int new;
-- const char *general_val = NULL;
-- char parse[80];
-- char *interface, *state_interface;
-- char *membername = NULL;
-+ struct member tmpmem;
- int penalty;
-- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-- struct ao2_iterator queue_iter;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(interface);
- AST_APP_ARG(penalty);
-@@ -5440,200 +5670,325 @@
- AST_APP_ARG(state_interface);
- );
-
-- /*First things first. Let's load queuerules.conf*/
-- if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE)
-- return AST_MODULE_LOAD_FAILURE;
--
-- if (!(cfg = ast_config_load("queues.conf", config_flags))) {
-- ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
-- return 0;
-- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
-- ao2_lock(queues);
-- use_weight=0;
-- /* Mark all queues as dead for the moment */
-- queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
-- while ((q = ao2_iterator_next(&queue_iter))) {
-- if (!q->realtime) {
-- q->dead = 1;
-- q->found = 0;
-+ /* Add a new member */
-+ parse = ast_strdupa(memberdata);
-+
-+ AST_STANDARD_APP_ARGS(args, parse);
-+
-+ interface = args.interface;
-+ if (!ast_strlen_zero(args.penalty)) {
-+ tmp = args.penalty;
-+ ast_strip(tmp);
-+ penalty = atoi(tmp);
-+ if (penalty < 0) {
-+ penalty = 0;
- }
-- queue_unref(q);
-+ } else {
-+ penalty = 0;
- }
-
-- /* Chug through config file */
-- cat = NULL;
-- while ((cat = ast_category_browse(cfg, cat)) ) {
-- if (!strcasecmp(cat, "general")) {
-- /* Initialize global settings */
-- queue_keep_stats = 0;
-- if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats")))
-- queue_keep_stats = ast_true(general_val);
-- queue_persistent_members = 0;
-- if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
-- queue_persistent_members = ast_true(general_val);
-- autofill_default = 0;
-- if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
-- autofill_default = ast_true(general_val);
-- montype_default = 0;
-- if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
-- if (!strcasecmp(general_val, "mixmonitor"))
-- montype_default = 1;
-- }
-- update_cdr = 0;
-- if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
-- update_cdr = ast_true(general_val);
-- shared_lastcall = 0;
-- if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
-- shared_lastcall = ast_true(general_val);
-- } else { /* Define queue */
-- /* Look for an existing one */
-- struct call_queue tmpq = {
-- .name = cat,
-- };
-- if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
-- /* Make one then */
-- if (!(q = alloc_queue(cat))) {
-- /* TODO: Handle memory allocation failure */
-- }
-- new = 1;
-- } else
-- new = 0;
-- if (q) {
-- const char *tmpvar = NULL;
-- if (!new)
-- ao2_lock(q);
-- /* Check if a queue with this name already exists */
-- if (q->found) {
-- ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
-- if (!new) {
-- ao2_unlock(q);
-- queue_unref(q);
-- }
-- continue;
-- }
-- /* Due to the fact that the "linear" strategy will have a different allocation
-- * scheme for queue members, we must devise the queue's strategy before other initializations
-- */
-- if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
-- q->strategy = strat2int(tmpvar);
-- if (q->strategy < 0) {
-- ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
-- tmpvar, q->name);
-- q->strategy = QUEUE_STRATEGY_RINGALL;
-- }
-- } else
-- q->strategy = QUEUE_STRATEGY_RINGALL;
-- /* Re-initialize the queue, and clear statistics */
-- init_queue(q);
-- if (!queue_keep_stats)
-- clear_queue(q);
-- mem_iter = ao2_iterator_init(q->members, 0);
-- while ((cur = ao2_iterator_next(&mem_iter))) {
-- if (!cur->dynamic) {
-- cur->delme = 1;
-- }
-- ao2_ref(cur, -1);
-- }
-- for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
-- if (!strcasecmp(var->name, "member")) {
-- struct member tmpmem;
-- membername = NULL;
-+ if (!ast_strlen_zero(args.membername)) {
-+ membername = args.membername;
-+ ast_strip(membername);
-+ } else {
-+ membername = interface;
-+ }
-
-- /* Add a new member */
-- ast_copy_string(parse, var->value, sizeof(parse));
--
-- AST_STANDARD_APP_ARGS(args, parse);
-+ if (!ast_strlen_zero(args.state_interface)) {
-+ state_interface = args.state_interface;
-+ ast_strip(state_interface);
-+ } else {
-+ state_interface = interface;
-+ }
-
-- interface = args.interface;
-- if (!ast_strlen_zero(args.penalty)) {
-- tmp = args.penalty;
-- while (*tmp && *tmp < 33) tmp++;
-- penalty = atoi(tmp);
-- if (penalty < 0) {
-- penalty = 0;
-- }
-- } else
-- penalty = 0;
-+ /* Find the old position in the list */
-+ ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
-+ cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
-+ if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
-+ ao2_link(q->members, newm);
-+ ao2_ref(newm, -1);
-+ }
-+ newm = NULL;
-
-- if (!ast_strlen_zero(args.membername)) {
-- membername = args.membername;
-- while (*membername && *membername < 33) membername++;
-- }
-+ if (cur) {
-+ ao2_ref(cur, -1);
-+ } else {
-+ q->membercount++;
-+ }
-+}
-
-- if (!ast_strlen_zero(args.state_interface)) {
-- state_interface = args.state_interface;
-- while (*state_interface && *state_interface < 33) state_interface++;
-- } else
-- state_interface = interface;
-+static int mark_member_dead(void *obj, void *arg, int flags)
-+{
-+ struct member *member = obj;
-+ if (!member->dynamic) {
-+ member->delme = 1;
-+ }
-+ return 0;
-+}
-
-- /* Find the old position in the list */
-- ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
-- cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
-- /* Only attempt removing from interfaces list if the new state_interface is different than the old one */
-- if (cur && strcasecmp(cur->state_interface, state_interface)) {
-- remove_from_interfaces(cur->state_interface, 0);
-- }
-- newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
-- if (!cur || (cur && strcasecmp(cur->state_interface, state_interface)))
-- add_to_interfaces(state_interface);
-- ao2_link(q->members, newm);
-- ao2_ref(newm, -1);
-- newm = NULL;
-+static int kill_dead_members(void *obj, void *arg, int flags)
-+{
-+ struct member *member = obj;
-+ struct call_queue *q = arg;
-
-- if (cur)
-- ao2_ref(cur, -1);
-- else {
-- q->membercount++;
-- }
-- } else {
-- queue_set_param(q, var->name, var->value, var->lineno, 1);
-- }
-- }
-+ if (!member->delme) {
-+ if (member->dynamic) {
-+ /* dynamic members were not counted toward the member count
-+ * when reloading members from queues.conf, so we do that here
-+ */
-+ q->membercount++;
-+ }
-+ member->status = ast_device_state(member->state_interface);
-+ return 0;
-+ } else {
-+ q->membercount--;
-+ return CMP_MATCH;
-+ }
-+}
-
-- /* Free remaining members marked as delme */
-- mem_iter = ao2_iterator_init(q->members, 0);
-- while ((cur = ao2_iterator_next(&mem_iter))) {
-- if (! cur->delme) {
-- ao2_ref(cur, -1);
-- continue;
-- }
-- q->membercount--;
-- ao2_unlink(q->members, cur);
-- remove_from_interfaces(cur->interface, 0);
-- ao2_ref(cur, -1);
-- }
--
-- if (new) {
-- ao2_link(queues, q);
-- } else
-- ao2_unlock(q);
-- queue_unref(q);
-+/*! \brief Reload information pertaining to a particular queue
-+ *
-+ * Once we have isolated a queue within reload_queues, we call this. This will either
-+ * reload information for the queue or if we're just reloading member information, we'll just
-+ * reload that without touching other settings within the queue
-+ *
-+ * \param cfg The configuration which we are reading
-+ * \param mask Tells us what information we need to reload
-+ * \param queuename The name of the queue we are reloading information from
-+ * \retval void
-+ */
-+static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
-+{
-+ int new;
-+ struct call_queue *q = NULL;
-+ /*We're defining a queue*/
-+ struct call_queue tmpq = {
-+ .name = queuename,
-+ };
-+ const char *tmpvar;
-+ const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
-+ const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
-+ int prev_weight = 0;
-+ struct ast_variable *var;
-+ if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
-+ if (queue_reload) {
-+ /* Make one then */
-+ if (!(q = alloc_queue(queuename))) {
-+ return;
- }
-+ } else {
-+ /* Since we're not reloading queues, this means that we found a queue
-+ * in the configuration file which we don't know about yet. Just return.
-+ */
-+ return;
- }
-+ new = 1;
-+ } else {
-+ new = 0;
- }
-- ast_config_destroy(cfg);
-- queue_iter = ao2_iterator_init(queues, 0);
-- while ((q = ao2_iterator_next(&queue_iter))) {
-- if (q->dead) {
-- ao2_unlink(queues, q);
-- } else {
-- ao2_lock(q);
-- mem_iter = ao2_iterator_init(q->members, 0);
-- while ((cur = ao2_iterator_next(&mem_iter))) {
-- if (cur->dynamic)
-- q->membercount++;
-- cur->status = ast_device_state(cur->interface);
-- ao2_ref(cur, -1);
-- }
-+
-+ if (!new) {
-+ ao2_lock(q);
-+ prev_weight = q->weight ? 1 : 0;
-+ }
-+ /* Check if we already found a queue with this name in the config file */
-+ if (q->found) {
-+ ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
-+ if (!new) {
-+ /* It should be impossible to *not* hit this case*/
- ao2_unlock(q);
- }
- queue_unref(q);
-+ return;
- }
-+ /* Due to the fact that the "linear" strategy will have a different allocation
-+ * scheme for queue members, we must devise the queue's strategy before other initializations.
-+ * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
-+ * container used will have only a single bucket instead of the typical number.
-+ */
-+ if (queue_reload) {
-+ if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
-+ q->strategy = strat2int(tmpvar);
-+ if (q->strategy < 0) {
-+ ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
-+ tmpvar, q->name);
-+ q->strategy = QUEUE_STRATEGY_RINGALL;
-+ }
-+ } else {
-+ q->strategy = QUEUE_STRATEGY_RINGALL;
-+ }
-+ init_queue(q);
-+ }
-+ if (member_reload) {
-+ q->membercount = 0;
-+ ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
-+ }
-+ for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
-+ if (member_reload && !strcasecmp(var->name, "member")) {
-+ reload_single_member(var->value, q);
-+ } else if (queue_reload) {
-+ queue_set_param(q, var->name, var->value, var->lineno, 1);
-+ }
-+ }
-+ /* At this point, we've determined if the queue has a weight, so update use_weight
-+ * as appropriate
-+ */
-+ if (!q->weight && prev_weight) {
-+ ast_atomic_fetchadd_int(&use_weight, -1);
-+ }
-+ else if (q->weight && !prev_weight) {
-+ ast_atomic_fetchadd_int(&use_weight, +1);
-+ }
-+
-+ /* Free remaining members marked as delme */
-+ if (member_reload) {
-+ ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
-+ }
-+
-+ if (new) {
-+ ao2_link(queues, q);
-+ } else {
-+ ao2_unlock(q);
-+ }
-+ queue_unref(q);
-+}
-+
-+static int mark_dead_and_unfound(void *obj, void *arg, int flags)
-+{
-+ struct call_queue *q = obj;
-+ char *queuename = arg;
-+ if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
-+ q->dead = 1;
-+ q->found = 0;
-+ }
-+ return 0;
-+}
-+
-+static int kill_dead_queues(void *obj, void *arg, int flags)
-+{
-+ struct call_queue *q = obj;
-+ char *queuename = arg;
-+ if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
-+ return CMP_MATCH;
-+ } else {
-+ return 0;
-+ }
-+}
-+
-+/*! \brief reload the queues.conf file
-+ *
-+ * This function reloads the information in the general section of the queues.conf
-+ * file and potentially more, depending on the value of mask.
-+ *
-+ * \param reload 0 if we are calling this the first time, 1 every other time
-+ * \param mask Gives flags telling us what information to actually reload
-+ * \param queuename If set to a non-zero string, then only reload information from
-+ * that particular queue. Otherwise inspect all queues
-+ * \retval -1 Failure occurred
-+ * \retval 0 All clear!
-+ */
-+static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
-+{
-+ struct ast_config *cfg;
-+ char *cat;
-+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-+ const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
-+
-+ if (!(cfg = ast_config_load("queues.conf", config_flags))) {
-+ ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
-+ return -1;
-+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-+ return 0;
-+ } else if (cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
-+ return -1;
-+ }
-+
-+ /* We've made it here, so it looks like we're doing operations on all queues. */
-+ ao2_lock(queues);
-+
-+ /* Mark all queues as dead for the moment if we're reloading queues.
-+ * For clarity, we could just be reloading members, in which case we don't want to mess
-+ * with the other queue parameters at all*/
-+ if (queue_reload) {
-+ ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
-+ }
-+
-+ /* Chug through config file */
-+ cat = NULL;
-+ while ((cat = ast_category_browse(cfg, cat)) ) {
-+ if (!strcasecmp(cat, "general") && queue_reload) {
-+ queue_set_global_params(cfg);
-+ continue;
-+ }
-+ if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
-+ reload_single_queue(cfg, mask, cat);
-+ }
-+
-+ ast_config_destroy(cfg);
-+ /* Unref all the dead queues if we were reloading queues */
-+ if (queue_reload) {
-+ ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
-+ }
- ao2_unlock(queues);
-- return 1;
-+ return 0;
- }
-+
-+/*! \brief Facilitates resetting statistics for a queue
-+ *
-+ * This function actually does not reset any statistics, but
-+ * rather finds a call_queue struct which corresponds to the
-+ * passed-in queue name and passes that structure to the
-+ * clear_queue function. If no queuename is passed in, then
-+ * all queues will have their statistics reset.
-+ *
-+ * \param queuename The name of the queue to reset the statistics
-+ * for. If this is NULL or zero-length, then this means to reset
-+ * the statistics for all queues
-+ * \retval void
-+ */
-+static int clear_stats(const char *queuename)
-+{
-+ struct call_queue *q;
-+ struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
-+ while ((q = ao2_iterator_next(&queue_iter))) {
-+ ao2_lock(q);
-+ if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
-+ clear_queue(q);
-+ ao2_unlock(q);
-+ }
-+ return 0;
-+}
-
-+/*! \brief The command center for all reload operations
-+ *
-+ * Whenever any piece of queue information is to be reloaded, this function
-+ * is called. It interprets the flags set in the mask parameter and acts
-+ * based on how they are set.
-+ *
-+ * \param reload True if we are reloading information, false if we are loading
-+ * information for the first time.
-+ * \param mask A bitmask which tells the handler what actions to take
-+ * \param queuename The name of the queue on which we wish to take action
-+ * \retval 0 All reloads were successful
-+ * \retval non-zero There was a failure
-+ */
-+static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
-+{
-+ int res = 0;
-+
-+ if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
-+ res |= reload_queue_rules(reload);
-+ }
-+ if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
-+ res |= clear_stats(queuename);
-+ }
-+ if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
-+ res |= reload_queues(reload, mask, queuename);
-+ }
-+ return res;
-+}
-+
- /*! \brief direct ouput to manager or cli with proper terminator */
- static void do_print(struct mansession *s, int fd, const char *str)
- {
-@@ -5714,10 +6069,10 @@
- sl = 0;
- if (q->callscompleted > 0)
- sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
-- ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
-- int2strat(q->strategy), q->holdtime, q->weight,
-+ ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
-+ int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
- q->callscompleted, q->callsabandoned,sl,q->servicelevel);
-- do_print(s, fd, out->str);
-+ do_print(s, fd, ast_str_buffer(out));
- if (!ao2_container_count(q->members))
- do_print(s, fd, " No Members");
- else {
-@@ -5736,13 +6091,13 @@
- mem->dynamic ? " (dynamic)" : "",
- mem->realtime ? " (realtime)" : "",
- mem->paused ? " (paused)" : "",
-- devstate2str(mem->status));
-+ ast_devstate2str(mem->status));
- if (mem->calls)
- ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
- mem->calls, (long) (time(NULL) - mem->lastcall));
- else
- ast_str_append(&out, 0, " has taken no calls yet");
-- do_print(s, fd, out->str);
-+ do_print(s, fd, ast_str_buffer(out));
- ao2_ref(mem, -1);
- }
- }
-@@ -5757,7 +6112,7 @@
- ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
- pos++, qe->chan->name, (long) (now - qe->start) / 60,
- (long) (now - qe->start) % 60, qe->prio);
-- do_print(s, fd, out->str);
-+ do_print(s, fd, ast_str_buffer(out));
- }
- }
- do_print(s, fd, ""); /* blank line between entries */
-@@ -5770,7 +6125,7 @@
- ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
- else
- ast_str_set(&out, 0, "No queues.");
-- do_print(s, fd, out->str);
-+ do_print(s, fd, ast_str_buffer(out));
- }
- return CLI_SUCCESS;
- }
-@@ -5912,10 +6267,11 @@
- "Available: %d\r\n"
- "Callers: %d\r\n"
- "HoldTime: %d\r\n"
-+ "TalkTime: %d\r\n"
- "LongestHoldTime: %d\r\n"
- "%s"
- "\r\n",
-- q->name, qmemcount, qmemavail, qchancount, q->holdtime, qlongestholdtime, idText);
-+ q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
- }
- ao2_unlock(q);
- queue_unref(q);
-@@ -5962,6 +6318,7 @@
- "Strategy: %s\r\n"
- "Calls: %d\r\n"
- "Holdtime: %d\r\n"
-+ "TalkTime: %d\r\n"
- "Completed: %d\r\n"
- "Abandoned: %d\r\n"
- "ServiceLevel: %d\r\n"
-@@ -5969,7 +6326,7 @@
- "Weight: %d\r\n"
- "%s"
- "\r\n",
-- q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted,
-+ q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
- q->callsabandoned, q->servicelevel, sl, q->weight, idText);
- /* List Queue Members */
- mem_iter = ao2_iterator_init(q->members, 0);
-@@ -5999,12 +6356,13 @@
- "Queue: %s\r\n"
- "Position: %d\r\n"
- "Channel: %s\r\n"
-+ "Uniqueid: %s\r\n"
- "CallerIDNum: %s\r\n"
- "CallerIDName: %s\r\n"
- "Wait: %ld\r\n"
- "%s"
- "\r\n",
-- q->name, pos++, qe->chan->name,
-+ q->name, pos++, qe->chan->name, qe->chan->uniqueid,
- S_OR(qe->chan->cid.cid_num, "unknown"),
- S_OR(qe->chan->cid.cid_name, "unknown"),
- (long) (now - qe->start), idText);
-@@ -6152,6 +6510,53 @@
- return 0;
- }
-
-+static int manager_queue_reload(struct mansession *s, const struct message *m)
-+{
-+ struct ast_flags mask = {0,};
-+ const char *queuename = NULL;
-+ int header_found = 0;
-+
-+ queuename = astman_get_header(m, "Queue");
-+ if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
-+ ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
-+ header_found = 1;
-+ }
-+ if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
-+ ast_set_flag(&mask, QUEUE_RELOAD_RULES);
-+ header_found = 1;
-+ }
-+ if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
-+ ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
-+ header_found = 1;
-+ }
-+
-+ if (!header_found) {
-+ ast_set_flag(&mask, AST_FLAGS_ALL);
-+ }
-+
-+ if (!reload_handler(1, &mask, queuename)) {
-+ astman_send_ack(s, m, "Queue reloaded successfully");
-+ } else {
-+ astman_send_error(s, m, "Error encountered while reloading queue");
-+ }
-+ return 0;
-+}
-+
-+static int manager_queue_reset(struct mansession *s, const struct message *m)
-+{
-+ const char *queuename = NULL;
-+ struct ast_flags mask = {QUEUE_RESET_STATS,};
-+
-+ queuename = astman_get_header(m, "Queue");
-+
-+ if (!reload_handler(1, &mask, queuename)) {
-+ astman_send_ack(s, m, "Queue stats reset successfully");
-+ } else {
-+ astman_send_error(s, m, "Error encountered while resetting queue stats");
-+ }
-+ return 0;
-+}
-+
- static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
- {
- /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
-@@ -6361,6 +6766,9 @@
- case RES_OUTOFMEMORY:
- ast_cli(a->fd, "Out of memory\n");
- return CLI_FAILURE;
-+ case RES_NOT_DYNAMIC:
-+ ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
-+ return CLI_FAILURE;
- default:
- return CLI_FAILURE;
- }
-@@ -6528,9 +6936,9 @@
- struct penalty_rule *pr_iter;
- switch (cmd) {
- case CLI_INIT:
-- e->command = "queue rules show";
-+ e->command = "queue show rules";
- e->usage =
-- "Usage: queue rules show [rulename]\n"
-+ "Usage: queue show rules [rulename]\n"
- " Show the list of rules associated with rulename. If no\n"
- " rulename is specified, list all rules defined in queuerules.conf\n";
- return NULL;
-@@ -6555,19 +6963,100 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_queue_rule_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
-+ struct ast_flags mask = {QUEUE_RESET_STATS,};
-+ int i;
-+
- switch (cmd) {
- case CLI_INIT:
-- e->command = "queue rules reload";
-- e->usage =
-- "Usage: queue rules reload\n"
-- " Reloads rules defined in queuerules.conf\n";
-+ e->command = "queue reset stats";
-+ e->usage =
-+ "Usage: queue reset stats [<queuenames>]\n"
-+ "\n"
-+ "Issuing this command will reset statistics for\n"
-+ "<queuenames>, or for all queues if no queue is\n"
-+ "specified.\n";
- return NULL;
- case CLI_GENERATE:
-+ if (a->pos >= 3) {
-+ return complete_queue(a->line, a->word, a->pos, a->n);
-+ } else {
-+ return NULL;
-+ }
-+ }
-+
-+ if (a->argc < 3) {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ if (a->argc == 3) {
-+ reload_handler(1, &mask, NULL);
-+ return CLI_SUCCESS;
-+ }
-+
-+ for (i = 3; i < a->argc; ++i) {
-+ reload_handler(1, &mask, a->argv[i]);
-+ }
-+
-+ return CLI_SUCCESS;
-+}
-+
-+static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct ast_flags mask = {0,};
-+ int i;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "queue reload {parameters|members|rules|all}";
-+ e->usage =
-+ "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
-+ "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
-+ "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
-+ "specified in order to know what information to reload. Below is an explanation\n"
-+ "of each of these qualifiers.\n"
-+ "\n"
-+ "\t'members' - reload queue members from queues.conf\n"
-+ "\t'parameters' - reload all queue options except for queue members\n"
-+ "\t'rules' - reload the queuerules.conf file\n"
-+ "\t'all' - reload queue rules, parameters, and members\n"
-+ "\n"
-+ "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
-+ "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
-+ "one queue is specified when using this command, reloading queue rules may cause\n"
-+ "other queues to be affected\n";
- return NULL;
-+ case CLI_GENERATE:
-+ if (a->pos >= 3) {
-+ return complete_queue(a->line, a->word, a->pos, a->n);
-+ } else {
-+ return NULL;
-+ }
- }
-- reload_queue_rules(1);
-+
-+ if (a->argc < 3)
-+ return CLI_SHOWUSAGE;
-+
-+ if (!strcasecmp(a->argv[2], "rules")) {
-+ ast_set_flag(&mask, QUEUE_RELOAD_RULES);
-+ } else if (!strcasecmp(a->argv[2], "members")) {
-+ ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
-+ } else if (!strcasecmp(a->argv[2], "parameters")) {
-+ ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
-+ } else if (!strcasecmp(a->argv[2], "all")) {
-+ ast_set_flag(&mask, AST_FLAGS_ALL);
-+ }
-+
-+ if (a->argc == 3) {
-+ reload_handler(1, &mask, NULL);
-+ return CLI_SUCCESS;
-+ }
-+
-+ for (i = 3; i < a->argc; ++i) {
-+ reload_handler(1, &mask, a->argv[i]);
-+ }
-+
- return CLI_SUCCESS;
- }
-
-@@ -6587,7 +7076,8 @@
- AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
- AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
- AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
-- AST_CLI_DEFINE(handle_queue_rule_reload, "Reload the rules defined in queuerules.conf"),
-+ AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
-+ AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
- };
-
- static int unload_module(void)
-@@ -6597,7 +7087,7 @@
- struct ao2_iterator q_iter;
- struct call_queue *q = NULL;
-
-- ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
- res = ast_manager_unregister("QueueStatus");
- res |= ast_manager_unregister("Queues");
- res |= ast_manager_unregister("QueueRule");
-@@ -6628,8 +7118,6 @@
- ast_context_destroy(con, "app_queue"); /* leave no trace */
- }
-
-- clear_and_free_interfaces();
--
- q_iter = ao2_iterator_init(queues, 0);
- while ((q = ao2_iterator_next(&q_iter))) {
- ao2_unlink(queues, q);
-@@ -6645,10 +7133,13 @@
- {
- int res;
- struct ast_context *con;
-+ struct ast_flags mask = {AST_FLAGS_ALL, };
-
- queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
-
-- if (!reload_queues(0))
-+ use_weight = 0;
-+
-+ if (reload_handler(0, &mask, NULL))
- return AST_MODULE_LOAD_DECLINE;
-
- con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
-@@ -6660,13 +7151,13 @@
- if (queue_persistent_members)
- reload_queue_members();
-
-- ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
-- res = ast_register_application(app, queue_exec, synopsis, descrip);
-- res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
-- res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
-- res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
-- res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
-- res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
-+ ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
-+ res = ast_register_application_xml(app, queue_exec);
-+ res |= ast_register_application_xml(app_aqm, aqm_exec);
-+ res |= ast_register_application_xml(app_rqm, rqm_exec);
-+ res |= ast_register_application_xml(app_pqm, pqm_exec);
-+ res |= ast_register_application_xml(app_upqm, upqm_exec);
-+ res |= ast_register_application_xml(app_ql, ql_exec);
- res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
- res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
- res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary");
-@@ -6676,6 +7167,8 @@
- res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log");
- res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member");
- res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules");
-+ res |= ast_manager_register("QueueReload", 0, manager_queue_reload, "Reload a queue, queues, or any sub-section of a queue or queues");
-+ res |= ast_manager_register("QueueReset", 0, manager_queue_reset, "Reset queue statistics");
- res |= ast_custom_function_register(&queuevar_function);
- res |= ast_custom_function_register(&queuemembercount_function);
- res |= ast_custom_function_register(&queuemembercount_dep);
-@@ -6687,7 +7180,7 @@
- ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
- }
-
-- if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE, device_state_cb, NULL, AST_EVENT_IE_END))) {
-+ if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END))) {
- res = -1;
- }
-
-@@ -6698,8 +7191,9 @@
-
- static int reload(void)
- {
-+ struct ast_flags mask = {AST_FLAGS_ALL,};
- ast_unload_realtime("queue_members");
-- reload_queues(1);
-+ reload_handler(1, &mask, NULL);
- return 0;
- }
-
-Index: apps/app_followme.c
-===================================================================
---- a/apps/app_followme.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_followme.c (.../team/group/issue14292) (revision 178988)
-@@ -58,21 +58,42 @@
- #include "asterisk/dsp.h"
- #include "asterisk/app.h"
-
-+/*** DOCUMENTATION
-+ <application name="FollowMe" language="en_US">
-+ <synopsis>
-+ Find-Me/Follow-Me application.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="followmeid" required="true" />
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="s">
-+ <para>Playback the incoming status message prior to starting
-+ the follow-me step(s)</para>
-+ </option>
-+ <option name="a">
-+ <para>Record the caller's name so it can be announced to the
-+ callee on each step.</para>
-+ </option>
-+ <option name="n">
-+ <para>Playback the unreachable status message if we've run out
-+ of steps to reach the or the callee has elected not to be reachable.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application performs Find-Me/Follow-Me functionality for the caller
-+ as defined in the profile matching the <replaceable>followmeid</replaceable> parameter in
-+ <filename>followme.conf</filename>. If the specified <replaceable>followmeid</replaceable>
-+ profile doesn't exist in <filename>followme.conf</filename>, execution will be returned
-+ to the dialplan and call execution will continue at the next priority.</para>
-+ <para>Returns -1 on hangup.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- static char *app = "FollowMe";
--static char *synopsis = "Find-Me/Follow-Me application";
--static char *descrip =
--" FollowMe(followmeid[,options]):\n"
--"This application performs Find-Me/Follow-Me functionality for the caller\n"
--"as defined in the profile matching the <followmeid> parameter in\n"
--"followme.conf. If the specified <followmeid> profile doesn't exist in\n"
--"followme.conf, execution will be returned to the dialplan and call\n"
--"execution will continue at the next priority.\n\n"
--" Options:\n"
--" s - Playback the incoming status message prior to starting the follow-me step(s)\n"
--" a - Record the caller's name so it can be announced to the callee on each step\n"
--" n - Playback the unreachable status message if we've run out of steps to reach the\n"
--" or the callee has elected not to be reachable.\n"
--"Returns -1 on hangup\n";
-
- /*! \brief Number structure */
- struct number {
-@@ -89,6 +110,7 @@
- char moh[AST_MAX_CONTEXT]; /*!< Music On Hold Class to be used */
- char context[AST_MAX_CONTEXT]; /*!< Context to dial from */
- unsigned int active; /*!< Profile is active (1), or disabled (0). */
-+ int realtime; /*!< Cached from realtime */
- char takecall[20]; /*!< Digit mapping to take a call */
- char nextindp[20]; /*!< Digit mapping to decline a call */
- char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
-@@ -232,17 +254,17 @@
- ast_copy_string(f->takecall, val, sizeof(f->takecall));
- else if (!strcasecmp(param, "declinecall"))
- ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
-- else if (!strcasecmp(param, "call-from-prompt"))
-+ else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
- ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt));
-- else if (!strcasecmp(param, "followme-norecording-prompt"))
-+ else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
- ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt));
-- else if (!strcasecmp(param, "followme-options-prompt"))
-+ else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
- ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt));
-- else if (!strcasecmp(param, "followme-pls-hold-prompt"))
-+ else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
- ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt));
-- else if (!strcasecmp(param, "followme-status-prompt"))
-+ else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
- ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
-- else if (!strcasecmp(param, "followme-sorry-prompt"))
-+ else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
- ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
- else if (failunknown) {
- if (linenum >= 0)
-@@ -291,8 +313,12 @@
- if (!(cfg = ast_config_load("followme.conf", config_flags))) {
- ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
- 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 followme.conf is in an invalid format. Aborting.\n");
-+ return 0;
-+ }
-
- AST_RWLIST_WRLOCK(&followmes);
-
-@@ -311,37 +337,50 @@
- featuredigittimeout = 5000;
- }
-
-- takecallstr = ast_variable_retrieve(cfg, "general", "takecall");
-- if (!ast_strlen_zero(takecallstr))
-+ if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
- ast_copy_string(takecall, takecallstr, sizeof(takecall));
-+ }
-
-- declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall");
-- if (!ast_strlen_zero(declinecallstr))
-+ if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
- ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
-+ }
-
-- tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt");
-- if (!ast_strlen_zero(tmpstr))
-+ if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
- ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
-+ } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
-+ }
-
-- tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt");
-- if (!ast_strlen_zero(tmpstr))
-+ if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
- ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
-+ } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
-+ }
-
-- tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt");
-- if (!ast_strlen_zero(tmpstr))
-+
-+ if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
- ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ }
-
-- tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt");
-- if (!ast_strlen_zero(tmpstr))
-- ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
-+ if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ }
-
-- tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt");
-- if (!ast_strlen_zero(tmpstr))
-- ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
-+ if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ }
-
-- tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt");
-- if (!ast_strlen_zero(tmpstr))
-- ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
-+ if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
-+ ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
-+ }
-
- /* Chug through config file */
- while ((cat = ast_category_browse(cfg, cat))) {
-@@ -374,7 +413,7 @@
- init_profile(f);
- free_numbers(f);
- var = ast_variable_browse(cfg, cat);
-- while(var) {
-+ while (var) {
- if (!strcasecmp(var->name, "number")) {
- int idx = 0;
-
-@@ -871,6 +910,66 @@
- return;
- }
-
-+static struct call_followme *find_realtime(const char *name)
-+{
-+ struct ast_variable *var = ast_load_realtime("followme", "name", name, SENTINEL), *v;
-+ struct ast_config *cfg;
-+ const char *catg;
-+ struct call_followme *new;
-+ struct ast_str *str = ast_str_create(16);
-+
-+ if (!var) {
-+ return NULL;
-+ }
-+
-+ if (!(new = alloc_profile(name))) {
-+ return NULL;
-+ }
-+
-+ for (v = var; v; v = v->next) {
-+ if (!strcasecmp(v->name, "active")) {
-+ if (ast_false(v->value)) {
-+ ast_mutex_destroy(&new->lock);
-+ ast_free(new);
-+ return NULL;
-+ }
-+ } else {
-+ profile_set_param(new, v->name, v->value, 0, 0);
-+ }
-+ }
-+
-+ ast_variables_destroy(var);
-+ new->realtime = 1;
-+
-+ /* Load numbers */
-+ if (!(cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name", name, SENTINEL))) {
-+ ast_mutex_destroy(&new->lock);
-+ ast_free(new);
-+ return NULL;
-+ }
-+
-+ for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
-+ const char *numstr, *timeoutstr, *ordstr;
-+ int timeout;
-+ struct number *cur;
-+ if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
-+ continue;
-+ }
-+ if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout")) || sscanf(timeoutstr, "%d", &timeout) != 1 || timeout < 1) {
-+ timeout = 25;
-+ }
-+ /* This one has to exist; it was part of the query */
-+ ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
-+ ast_str_set(&str, 0, "%s", numstr);
-+ if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
-+ AST_LIST_INSERT_TAIL(&new->numbers, cur, entry);
-+ }
-+ }
-+ ast_config_destroy(cfg);
-+
-+ return new;
-+}
-+
- static void end_bridge_callback(void *data)
- {
- char buf[80];
-@@ -941,6 +1040,10 @@
- ast_debug(1, "New profile %s.\n", args.followmeid);
-
- if (!f) {
-+ f = find_realtime(args.followmeid);
-+ }
-+
-+ if (!f) {
- ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
- return 0;
- }
-@@ -1041,6 +1144,12 @@
-
- outrun:
-
-+ if (f->realtime) {
-+ /* Not in list */
-+ free_numbers(f);
-+ ast_free(f);
-+ }
-+
- return res;
- }
-
-@@ -1067,7 +1176,7 @@
- if(!reload_followme(0))
- return AST_MODULE_LOAD_DECLINE;
-
-- return ast_register_application(app, app_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, app_exec);
- }
-
- static int reload(void)
-Index: apps/app_waitforring.c
-===================================================================
---- a/apps/app_waitforring.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_waitforring.c (.../team/group/issue14292) (revision 178988)
-@@ -35,16 +35,24 @@
- #include "asterisk/module.h"
- #include "asterisk/lock.h"
-
--static char *synopsis = "Wait for Ring Application";
-+/*** DOCUMENTATION
-+ <application name="WaitForRing" language="en_US">
-+ <synopsis>
-+ Wait for Ring Application.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="timeout" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Returns <literal>0</literal> after waiting at least <replaceable>timeout</replaceable> seconds,
-+ and only after the next ring has completed. Returns <literal>0</literal> on success or
-+ <literal>-1</literal> on hangup.</para>
-+ </description>
-+ </application>
-+ ***/
-
--static char *desc = " WaitForRing(timeout):\n"
--"Returns 0 after waiting at least timeout seconds. and\n"
--"only after the next ring has completed. Returns 0 on\n"
--"success or -1 on hangup\n";
--
- static char *app = "WaitForRing";
-
--
- static int waitforring_exec(struct ast_channel *chan, void *data)
- {
- struct ast_frame *f;
-@@ -111,7 +119,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, waitforring_exec, synopsis, desc);
-+ return ast_register_application_xml(app, waitforring_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Waits until first ring after time");
-Index: apps/app_flash.c
-===================================================================
---- a/apps/app_flash.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/apps/app_flash.c (.../team/group/issue14292) (revision 178988)
-@@ -43,17 +43,25 @@
- #include "asterisk/translate.h"
- #include "asterisk/image.h"
-
-+/*** DOCUMENTATION
-+ <application name="Flash" language="en_US">
-+ <synopsis>
-+ Flashes a DAHDI Trunk.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Performs a flash on a DAHDI trunk. This can be used to access features
-+ provided on an incoming analogue circuit such as conference and call waiting.
-+ Use with SendDTMF() to perform external transfers.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">SendDTMF</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- static char *app = "Flash";
-
--static char *synopsis = "Flashes a DAHDI Trunk";
--
--static char *descrip =
--"Performs a flash on a DAHDI trunk. This can be used\n"
--"to access features provided on an incoming analogue circuit\n"
--"such as conference and call waiting. Use with SendDTMF() to\n"
--"perform external transfers\n";
--
--
- static inline int dahdi_wait_event(int fd)
- {
- /* Avoid the silly dahdi_waitevent which ignores a bunch of events */
-@@ -105,7 +113,7 @@
-
- static int load_module(void)
- {
-- return ast_register_application(app, flash_exec, synopsis, descrip);
-+ return ast_register_application_xml(app, flash_exec);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Flash channel application");
-Index: doc/CODING-GUIDELINES
-===================================================================
---- a/doc/CODING-GUIDELINES (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/CODING-GUIDELINES (.../team/group/issue14292) (revision 178988)
-@@ -11,7 +11,7 @@
- code is organized, and to know how to extend asterisk or contribute
- new code.
-
--We are looking forward to your contributions to Asterisk - the
-+We are looking forward to your contributions to Asterisk - the
- Open Source PBX! As Asterisk is a large and in some parts very
- time-sensitive application, the code base needs to conform to
- a common set of coding rules so that many developers can enhance
-@@ -56,7 +56,7 @@
-
- - Try to match the existing formatting of the file you are working on.
-
--- Use spaces instead of tabs when aligning in-line comments or #defines (this makes
-+- Use spaces instead of tabs when aligning in-line comments or #defines (this makes
- your comments aligned even if the code is viewed with another tabsize)
-
- * File structure and header inclusion
-@@ -73,7 +73,7 @@
- set of unix functions (data types, system calls, basic I/O
- libraries) and the basic Asterisk APIs.
- ASTERISK_FILE_VERSION() stores in the executable information
--about the file.
-+about the file.
-
- Next, you should #include extra headers according to the functionality
- that your file uses or implements. For each group of functions that
-@@ -146,7 +146,7 @@
- * Code formatting
- -----------------
-
--Roughly, Asterisk code formatting guidelines are generally equivalent to the
-+Roughly, Asterisk code formatting guidelines are generally equivalent to the
- following:
-
- # indent -i4 -ts4 -br -brs -cdw -lp -ce -nbfda -npcs -nprs -npsl -nbbo -saf -sai -saw -cs -l90 foo.c
-@@ -167,7 +167,7 @@
- -sai: space after if
- -saw: space after while
- -cs: space after cast
-- -ln90: line length 90 columns
-+ -l90: line length 90 columns
-
- Function calls and arguments should be spaced in a consistent way across
- the codebase.
-@@ -219,7 +219,7 @@
- - No nested statements without braces, e.g.:
-
- for (x = 0; x < 5; x++)
-- if (foo)
-+ if (foo)
- if (bar)
- baz();
-
-@@ -265,9 +265,9 @@
- function while still performing proper cleanup. This is not a bad thing!
- Use of goto in this situation is encouraged, since it removes the need
- for excess code indenting without requiring duplication of cleanup code.
--
-+
- - Never use an uninitialized variable
--Make sure you never use an uninitialized variable. The compiler will
-+Make sure you never use an uninitialized variable. The compiler will
- usually warn you if you do so. However, do not go too far the other way,
- and needlessly initialize variables that do not require it. If the first
- time you use a variable in a function is to store a value there, then
-@@ -292,7 +292,7 @@
-
- As an example, suppose you wanted to take a local function "find_feature", defined
- as static in a file, and used only in that file, and make it public, and use it
--in other files. You will have to remove the "static" declaration and define a
-+in other files. You will have to remove the "static" declaration and define a
- prototype in an appropriate header file (usually in include/asterisk). A more
- specific name should be given, such as "ast_find_call_feature".
-
-@@ -311,7 +311,7 @@
- - Global variables
- Name global variables (or local variables when you have a lot of them or
- are in a long function) something that will make sense to aliens who
--find your code in 100 years. All variable names should be in lower
-+find your code in 100 years. All variable names should be in lower
- case, except when following external APIs or specifications that normally
- use upper- or mixed-case variable names; in that situation, it is
- preferable to follow the external API/specification for ease of
-@@ -321,7 +321,7 @@
- options that they are in fact intended to be global.
- e.g.: static char global_something[80]
-
--- Don't use un-necessary typedef's
-+- Don't use unnecessary typedef's
- Don't use 'typedef' just to shorten the amount of typing; there is no substantial
- benefit in this:
- struct foo { int bar; }; typedef struct foo foo_t;
-@@ -368,7 +368,7 @@
- know at the time you are writing the code whether the buffer is large enough
- for the fixed string or not, and if it's not, your code won't work anyway!
- Use strcpy() for this operation, or directly set the first two characters
--of the buffer if you are just trying to store a one-character string in the
-+of the buffer if you are just trying to store a one character string in the
- buffer. If you are trying to 'empty' the buffer, just store a single
- NULL character ('\0') in the first byte of the buffer; nothing else is
- needed, and any other method is wasteful.
-@@ -382,14 +382,13 @@
- * Use of functions
- ------------------
-
--For the sake of uclibc, do not use index, bcopy or bzero; use
--strchr(), memset(), and memmove() instead. uclibc can be configured
--to supply these functions, but we can save these users
--time and consternation if we abstain from using these
-+For the sake of uclibc, do not use index, bcopy or bzero; use strchr(), memset(),
-+and memmove() instead. uclibc can be configured to supply these functions, but
-+we can save these users time and consternation if we abstain from using these
- functions.
-
--When making applications, always ast_strdupa(data) to a local pointer if
--you intend to parse the incoming data string.
-+When making applications, always ast_strdupa(data) to a local pointer if you
-+intend to parse the incoming data string.
-
- if (data)
- mydata = ast_strdupa(data);
-@@ -410,8 +409,8 @@
- function or macro.
-
- Make sure you are not duplicating any functionality already found in an
--API call somewhere. If you are duplicating functionality found in
--another static function, consider the value of creating a new API call
-+API call somewhere. If you are duplicating functionality found in
-+another static function, consider the value of creating a new API call
- which can be shared.
-
- * Handling of pointers and allocations
-@@ -419,12 +418,12 @@
-
- - Dereference or localize pointers
- Always dereference or localize pointers to things that are not yours like
--channel members in a channel that is not associated with the current
-+channel members in a channel that is not associated with the current
- thread and for which you do not have a lock.
- channame = ast_strdupa(otherchan->name);
-
- - Use const on pointer arguments if possible
--Use const on pointer arguments which your function will not be modifying, as this
-+Use const on pointer arguments which your function will not be modifying, as this
- allows the compiler to make certain optimizations. In general, use 'const'
- on any argument that you have no direct intention of modifying, as it can
- catch logic/typing errors in your code when you use the argument variable
-@@ -449,7 +448,7 @@
- of a function you are calling; this can cause very strange stack
- arrangements and produce unexpected behavior.
-
---Allocations for structures
-+- Allocations for structures
- When allocating/zeroing memory for a structure, use code like this:
-
- struct foo *tmp;
-@@ -459,12 +458,12 @@
- tmp = ast_calloc(1, sizeof(*tmp));
-
- Avoid the combination of ast_malloc() and memset(). Instead, always use
--ast_calloc(). This will allocate and zero the memory in a single operation.
-+ast_calloc(). This will allocate and zero the memory in a single operation.
- In the case that uninitialized memory is acceptable, there should be a comment
- in the code that states why this is the case.
-
--Using sizeof(*tmp) instead of sizeof(struct foo) eliminates duplication of the
--'struct foo' identifier, which makes the code easier to read and also ensures
-+Using sizeof(*tmp) instead of sizeof(struct foo) eliminates duplication of the
-+'struct foo' identifier, which makes the code easier to read and also ensures
- that if it is copy-and-pasted it won't require as much editing.
-
- The ast_* family of functions for memory allocation are functionally the same.
-@@ -472,7 +471,7 @@
- fails for some reason. This eliminates the need to generate custom messages
- throughout the code to log that this has occurred.
-
---String Duplications
-+- String Duplications
-
- The functions strdup and strndup can *not* accept a NULL argument. This results
- in having code like this:
-@@ -484,7 +483,7 @@
-
- However, the ast_strdup and ast_strdupa functions will happily accept a NULL
- argument without generating an error. The same code can be written as:
--
-+
- newstr = ast_strdup(str);
-
- Furthermore, it is unnecessary to have code that malloc/calloc's for the length
-@@ -591,28 +590,28 @@
- passes over the code to optimize it.
-
- - Read the patch
--Before submitting a patch, *read* the actual patch file to be sure that
--all the changes you expect to be there are, and that there are no
-+Before submitting a patch, *read* the actual patch file to be sure that
-+all the changes you expect to be there are, and that there are no
- surprising changes you did not expect. During your development, that
- part of Asterisk may have changed, so make sure you compare with the
--latest CVS.
-+latest SVN.
-
- - Listen to advice
- If you are asked to make changes to your patch, there is a good chance
- the changes will introduce bugs, check it even more at this stage.
--Also remember that the bug marshal or co-developer that adds comments
-+Also remember that the bug marshal or co-developer that adds comments
- is only human, they may be in error :-)
-
- - Optimize, optimize, optimize
- If you are going to reuse a computed value, save it in a variable
--instead of recomputing it over and over. This can prevent you from
-+instead of recomputing it over and over. This can prevent you from
- making a mistake in subsequent computations, making it easier to correct
--if the formula has an error and may or may not help optimization but
-+if the formula has an error and may or may not help optimization but
- will at least help readability.
-
- Just an example (so don't over analyze it, that'd be a shame):
-
--const char *prefix = "pre";
-+const char *prefix = "pre";
- const char *postfix = "post";
- char *newname;
- char *name = "data";
-@@ -895,7 +894,7 @@
- for each package detected.
- These are normally of the form FOO_INCLUDE=... FOO_LIB=...
- FOO_DIR=... indicating, for each package, the useful libraries
-- and header files.
-+ and header files.
-
- The next step is to run "make menuselect", to extract the dependencies existing
- between files and modules, and to store build options.
-@@ -921,10 +920,10 @@
-
- TO BE COMPLETED
-
--
-+
- -----------------------------------------------
- Welcome to the Asterisk development community!
--Meet you on the asterisk-dev mailing list.
-+Meet you on the asterisk-dev mailing list.
- Subscribe at http://lists.digium.com!
-
- -- The Asterisk.org Development Team
-Index: doc/asterisk.8
-===================================================================
---- a/doc/asterisk.8 (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/asterisk.8 (.../team/group/issue14292) (revision 178988)
-@@ -157,6 +157,10 @@
- \fB-V\fR
- Display version information and exit immediately.
- .TP
-+\fB-W\fR
-+Change the terminal colors to compensate for a light background,
-+rather than a dark background, as is the default.
-+.TP
- \fB-x \fIcommand\fB\fR
- Connect to a running Asterisk process and execute a command on
- a command line, passing any output through to standard out and
-Index: doc/api-1.6.2-changes.txt
-===================================================================
---- a/doc/api-1.6.2-changes.txt (.../tags/1.6.1-rc1) (revision 0)
-+++ b/doc/api-1.6.2-changes.txt (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,6 @@
-+PBX changes
-+-----------
-+ * If you use ast_build_timing() in your application, you should start calling
-+ ast_destroy_timing() upon destruction of the structure, to avoid a memory
-+ leak.
-+
-
-Property changes on: doc/api-1.6.2-changes.txt
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: doc/unistim.txt
-===================================================================
---- a/doc/unistim.txt (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/unistim.txt (.../team/group/issue14292) (revision 178988)
-@@ -64,7 +64,7 @@
- - This feature must only be used on a trusted network. It's very insecure : all unistim phones
- will be able to use your asterisk pbx.
- - You must add an entry called [template]. Each new phones will be based on this profile.
--- You must set a least line=>. This value will be incremented when a new phone is registred.
-+- You must set a least line=>. This value will be incremented when a new phone is registered.
- device= must not be specified. By default, the phone will asks for a number. It will be added into
- the dialplan. Add extension=line for using the generated line number instead.
- Example :
-Index: doc/janitor-projects.txt
-===================================================================
---- a/doc/janitor-projects.txt (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/janitor-projects.txt (.../team/group/issue14292) (revision 178988)
-@@ -32,11 +32,3 @@
- -- Audit all channel/res/app/etc. modules to ensure that they do not register any entrypoints with the Asterisk core until after they are ready to service requests; all config file reading/processing, structure allocation, etc. must be completed before Asterisk is made aware of any services the module offers.
-
- -- Ensure that Realtime-enabled modules do not depend on the order of columns returned by the database lookup (example: outboundproxy and host settings in chan_sip).
--
-- -- There are several places in the code where the length of arrays is calculated in-line with sizeof() and division. A common place to find this is in for loops, like this:
--
-- for (i = 0; i < sizeof(array)/sizeof(array[0]); i++)
--
-- There is a macro in utils.h called ARRAY_LEN which should be used instead for readability's sake.
--
-- for (i = 0; i < ARRAY_LEN(array); i++)
-Index: doc/appdocsxml.dtd
-===================================================================
---- a/doc/appdocsxml.dtd (.../tags/1.6.1-rc1) (revision 0)
-+++ b/doc/appdocsxml.dtd (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,71 @@
-+ <!ELEMENT docs (application|function|agi)* >
-+
-+ <!ELEMENT application (synopsis?,syntax?,description?,see-also?)>
-+ <!ATTLIST application name CDATA #REQUIRED>
-+ <!ATTLIST application language CDATA #REQUIRED>
-+
-+ <!ELEMENT function (synopsis?,syntax?,description?,see-also?)>
-+ <!ATTLIST function name CDATA #REQUIRED>
-+ <!ATTLIST function language CDATA #REQUIRED>
-+
-+ <!ELEMENT agi (synopsis?,syntax?,description?,see-also?)>
-+ <!ATTLIST agi name CDATA #REQUIRED>
-+ <!ATTLIST agi language CDATA #REQUIRED>
-+
-+ <!ELEMENT see-also (ref*)>
-+
-+ <!ELEMENT ref (#PCDATA)*>
-+ <!ATTLIST ref type (application|function|astcli|link|manpage|filename|agi) #REQUIRED>
-+
-+ <!ELEMENT synopsis (#PCDATA)>
-+
-+ <!ELEMENT syntax (parameter*)>
-+ <!ATTLIST syntax argsep CDATA ",">
-+
-+ <!ELEMENT description (para|note|warning|variablelist|enumlist)*>
-+
-+ <!ELEMENT parameter (optionlist|enumlist|argument|para|note|warning|parameter)*>
-+ <!ATTLIST parameter name CDATA "">
-+ <!ATTLIST parameter required (yes|no|true|false) "false">
-+ <!ATTLIST parameter multiple (yes|no|true|false) "false">
-+ <!ATTLIST parameter hasparams (yes|no|true|false|optional) "false">
-+ <!ATTLIST parameter literal (yes|no|true|false) "false">
-+ <!ATTLIST parameter default CDATA "">
-+ <!ATTLIST parameter argsep CDATA ",">
-+
-+ <!ELEMENT optionlist (option+)>
-+ <!ELEMENT option (argument|para|note|warning|variablelist|enumlist)*>
-+ <!ATTLIST option name CDATA #REQUIRED>
-+ <!ATTLIST option argsep CDATA ",">
-+ <!ATTLIST option implies CDATA "">
-+ <!ATTLIST option hasparams CDATA "">
-+
-+ <!ELEMENT enumlist (enum+)>
-+ <!ELEMENT enum (para|note|warning|parameter)*>
-+ <!ATTLIST enum name CDATA "">
-+
-+ <!ELEMENT argument (para|note|warning|variablelist|argument)*>
-+ <!ATTLIST argument name CDATA #REQUIRED>
-+ <!ATTLIST argument multiple (yes|no|true|false) "false">
-+ <!ATTLIST argument required (yes|no|true|false) "false">
-+ <!ATTLIST argument hasparams (yes|no|true|false|optional) "false">
-+ <!ATTLIST argument argsep CDATA ",">
-+
-+ <!ELEMENT para (#PCDATA|astcli|literal|emphasis|filename|directory|replaceable|variable)*>
-+ <!ELEMENT literal (#PCDATA)>
-+ <!ELEMENT emphasis (#PCDATA)>
-+ <!ELEMENT filename (#PCDATA)>
-+ <!ELEMENT replaceable (#PCDATA)>
-+ <!ELEMENT directory (#PCDATA)>
-+ <!ELEMENT astcli (#PCDATA)>
-+
-+ <!ELEMENT note (para+)>
-+ <!ELEMENT warning (para+)>
-+
-+ <!ELEMENT variablelist (variable+)>
-+ <!ELEMENT variable (#PCDATA|value|para)*>
-+ <!ATTLIST variable name CDATA "">
-+
-+ <!ELEMENT value (#PCDATA)>
-+ <!ATTLIST value name CDATA #REQUIRED>
-+ <!ATTLIST value default CDATA "">
-
-Property changes on: doc/appdocsxml.dtd
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: doc/manager_1_1.txt
-===================================================================
---- a/doc/manager_1_1.txt (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/manager_1_1.txt (.../team/group/issue14292) (revision 178988)
-@@ -1,6 +1,12 @@
- Changes to manager version 1.1:
- -------------------------------
-
-+- Action: IAXregistry
-+ Modules: chan_iax2
-+ Purpose:
-+ To list all IAX2 peers in the IAX registry with their registration status.
-+ Variables:
-+ ActionID: <id> Action ID for this transaction. Will be returned.
-
- * SYNTAX CLEANUPS
- -----------------
-@@ -119,6 +125,14 @@
- If you call out to a subshell in Originate with the Application parameter,
- you now also need the System privilege.
-
-+- Event QueueEntry now also returns the Uniqueid field like other events from app_queue.
-+
-+- Action IAXpeerlist
-+ Now includes if the IAX link is a trunk or not
-+
-+- Action IAXpeers
-+ Now includes if the IAX link is a trunk or not
-+
- * NEW ACTIONS
- -------------
- - Action: ModuleLoad
-@@ -194,6 +208,51 @@
- Variables:
- ActionId: <id> Action ID for this transaction. Will be returned.
-
-+- Action: QueueReload
-+ Modules: app_queue
-+ Purpose:
-+ To reload queue rules, a queue's members, a queue's parameters, or all of the aforementioned
-+ Variable:
-+ Queuename: <name> The name of the queue to take action on. If no queue name is specified, then all queues are affected
-+ Rules: <yes or no> Whether to reload queue_rules.conf
-+ Members: <yes or no> Whether to reload the queue's members
-+ Parameters: <yes or no> Whether to reload the other queue options
-+
-+- Action: QueueReset
-+ Modules: app_queue
-+ Purpose:
-+ Reset the statistics for a queue
-+ Variables:
-+ Queuename: <name> The name of the queue on which to reset statistics
-+
-+- Action: SKINNYdevices
-+ Modules: chan_skinny
-+ Purpose:
-+ To list all SKINNY devices configured.
-+ Variables:
-+ ActionId: <id> Action ID for this transaction. Will be returned.
-+
-+- Action: SKINNYlines
-+ Modules: chan_skinny
-+ Purpose:
-+ To list all SKINNY lines configured.
-+ Variables:
-+ ActionId: <id> Action ID for this transaction. Will be returned.
-+
-+- Action SKINNYshowdevice
-+ Modules: chan_skinny
-+ Purpose:
-+ To list the information about a specific SKINNY device.
-+ Variables:
-+ Device: <device> Device to show information about.
-+
-+- Action SKINNYshowline
-+ Modules: chan_skinny
-+ Purpose:
-+ To list the information about a specific SKINNY line.
-+ Variables:
-+ Line: <line> Line to show information about.
-+
- * NEW EVENTS
- ------------
-
-@@ -329,6 +388,21 @@
- If an actionID was specified for the SipShowRegistry action, it will be appended as the
- last line of the RegistrationsComplete event.
-
-+- Event: ChanSpyStart
-+ Modules: app_chanspy
-+ Purpose: Reports when an active channel starts to be monitored by someone.
-+ Example:
-+ Event: ChanSpyStart
-+ SpyerChannel: SIP/4321-13bba124
-+ SpyeeChannel: SIP/1234-56ecc098
-+
-+- Event: ChanSpyStop
-+ Modules: app_chanspy
-+ Purpose: Reports when an active channel stops to be monitored by someone.
-+ Example:
-+ Event: ChanSpyStop
-+ SpyeeChannel: SIP/1234-56ecc098
-+
- * TODO
- ------
-
-Index: doc/tex/channelvariables.tex
-===================================================================
---- a/doc/tex/channelvariables.tex (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/tex/channelvariables.tex (.../team/group/issue14292) (revision 178988)
-@@ -922,6 +922,7 @@
- \begin{verbatim}
- ${SIPCALLID} * SIP Call-ID: header verbatim (for logging or CDR matching)
- ${SIPDOMAIN} * SIP destination domain of an inbound call (if appropriate)
-+${SIPFROMDOMAIN} Set SIP domain on outbound calls
- ${SIPUSERAGENT} * SIP user agent (deprecated)
- ${SIPURI} * SIP uri
- ${SIP_CODEC} Set the SIP codec for a call
-Index: doc/tex/qos.tex
-===================================================================
---- a/doc/tex/qos.tex (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/tex/qos.tex (.../team/group/issue14292) (revision 178988)
-@@ -1,83 +1,91 @@
- \subsubsection{Introduction}
-
--Asterisk support different QoS settings on application level on various protocol
--on any of signaling and media. Type of Service (TOS) byte can be set on
--outgoing IP packets for various protocols. The TOS byte is used by the network
--to provide some level of Quality of Service (QoS) even if the network is
--congested with other traffic.
-+Asterisk supports different QoS settings at the application level for various
-+protocols on both signaling and media. The Type of Service (TOS) byte can be
-+set on outgoing IP packets for various protocols. The TOS byte is used by the
-+network to provide some level of Quality of Service (QoS) even if the network
-+is congested with other traffic.
-
--Also asterisk running on Linux can set 802.1p CoS marks in VLAN packets for all
--used VoIP protocols. It is useful when you are working in switched environment.
--In fact asterisk only set priority for Linux socket. For mapping this priority
-+Asterisk running on Linux can also set 802.1p CoS marks in VLAN packets for the
-+VoIP protocols it uses. This is useful when working in a switched environment.
-+In fact Asterisk only set priority for Linux socket. For mapping this priority
- and VLAN CoS mark you need to use this command:
-
- \begin{verbatim}
- vconfig set_egress_map [vlan-device] [skb-priority] [vlan-qos]
- \end{verbatim}
-
--In table behind shown all voice channels and other modules of asterisk, that
--support QoS settings for network traffic and type of traffic which can have
--QoS settings.
-+The table below shows all VoIP channel drivers and other Asterisk modules that
-+support QoS settings for network traffic. It also shows the type(s) of
-+traffic for which each module can support setting QoS settings.
-
--\begin{verbatim}
-- Channel Drivers
--+==============+===========+=====+=====+=====+
--| | Signaling |Audio|Video| Text|
--+==============+===========+=====+=====+=====+
--|chan_sip | + | + | + | + |
--|--------------+-----------+-----+-----+-----+
--|chan_skinny | + | + | + | |
--|--------------+-----------+-----+-----+-----+
--|chan_mgcp | + | + | | |
--|--------------+-----------+-----+-----+-----+
--|chan_unistim | + | + | | |
--|--------------+-----------+-----+-----+-----+
--|chan_h323 | | + | | |
--|--------------+-----------+-----+-----+-----+
--|chan_iax2 | + |
--+==============+=============================+
-- Other
--+==============+=============================+
--| dundi.conf | + (tos setting) |
--|--------------+-----------------------------+
--| iaxprov.conf | + (tos setting) |
--+==============+=============================+
--\end{verbatim}
-+\begin{table}[h!]
-+\begin{center}
-+\begin{tabular}{ | l || c | c | c | c | }
-+ \hline
-+ & Signaling & Audio & Video & Text \\ \hline \hline
-+ chan\_sip & + & + & + & + \\ \hline
-+ chan\_skinny & + & + & + & \\ \hline
-+ chan\_mgcp & + & + & & \\ \hline
-+ chan\_unistm & + & + & & \\ \hline
-+ chan\_h323 & & + & & \\ \hline
-+ chan\_iax2 & \multicolumn{4}{|c|}{+} \\
-+ \hline
-+\end{tabular}
-+\end{center}
-+\caption{Channel Driver QoS Settings}
-+\end{table}
-
-+\begin{table}[h!]
-+\begin{center}
-+\begin{tabular}{ | l || c | c | c | c | }
-+ \hline
-+ & Signaling & Audio & Video & Text \\ \hline \hline
-+ dundi.conf & \multicolumn{4}{ | c | }{+ (tos setting)} \\ \hline
-+ iaxprov.conf & \multicolumn{4}{ | c | }{+ (tos setting)} \\ \hline
-+ \hline
-+\end{tabular}
-+\end{center}
-+\caption{Other ToS Settings}
-+\end{table}
-
- \subsubsection{IP TOS values}
--
- The allowable values for any of the tos* parameters are:
- CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, AF11, AF12, AF13, AF21, AF22, AF23,
- AF31, AF32, AF33, AF41, AF42, AF43 and ef (expedited forwarding),
-
- The tos* parameters also take numeric values.
-
--Note, that on Linux system you can use ef value in case your asterisk is running
--from a user other then root only when you have compiled asterisk with libcap.
-+Note that on a Linux system, Asterisk must be compiled with libcap in order to
-+use the ef tos setting if Asterisk is not run as root.
-
--The lowdelay, throughput, reliability, mincost, and none values are removed
-+The lowdelay, throughput, reliability, mincost, and none values have been removed
- in current releases.
-
- \subsubsection{802.1p CoS values}
-
--As far as 802.1p uses 3 bites from VLAN header, there are parameter can take
--integer values from 0 to 7.
-+Because 802.1p uses 3 bits of the VLAN header, this parameter can take integer
-+values from 0 to 7.
-
- \subsubsection{Recommended values}
--Recommended values shown above and also included in sample configuration files:
--\begin{verbatim}
--+============+=========+======+
--| | tos | cos |
--+============+=========+======+
--|Signaling | cs3 | 3 |
--|Audio | ef | 5 |
--|Video | af41 | 4 |
--|Text | af41 | 3 |
--|Other | ef | |
--+============+=========+======+
--\end{verbatim}
-+The recommended values shown below are also included in sample configuration files:
-
-+\begin{table}[h!]
-+\begin{center}
-+\begin{tabular}{ | l || l | l | }
-+\hline
-+ & tos & cos \\ \hline \hline
-+Signaling & cs3 & 3 \\ \hline
-+Audio & ef & 5 \\ \hline
-+Video & af41 & 4 \\ \hline
-+Text & af41 & 3 \\ \hline
-+Other & ef & \\
-+\hline
-+\end{tabular}
-+\end{center}
-+\caption{Recommended QoS Settings}
-+\end{table}
-+
- \subsubsection{IAX2}
-
- In iax.conf, there is a "tos" parameter that sets the global default TOS
-@@ -93,20 +101,21 @@
-
- \subsubsection{SIP}
-
--In sip.conf, there are three parameters that control the TOS settings:
-+In sip.conf, there are four parameters that control the TOS settings:
- "tos\_sip", "tos\_audio", "tos\_video" and "tos\_text". tos\_sip controls
- what TOS SIP call signaling packets are set to. tos\_audio, tos\_video
--and tos\_text controls what TOS RTP audio, video or text accordingly
--packets are set to.
-+and tos\_text control what TOS values are used for RTP audio, video, and text
-+packets, respectively.
-
- There are four parameters to control 802.1p CoS: "cos\_sip", "cos\_audio",
--"cos\_video" and "cos\_text". It behavior the same as written above.
-+"cos\_video" and "cos\_text". The behavior of these parameters is the
-+same as for the SIP TOS settings described above.
-
- \subsubsection{Other RTP channels}
-
- chan\_mgcp, chan\_h323, chan\_skinny and chan\_unistim also support TOS and
--CoS via setting tos and cos parameters in correspond to module config
--files. Naming style and behavior same as for chan\_sip.
-+CoS via setting tos and cos parameters in their corresponding configuration
-+files. Naming style and behavior are the same as for chan\_sip.
-
- \subsubsection{Reference}
-
-Index: doc/tex/misdn.tex
-===================================================================
---- a/doc/tex/misdn.tex (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/tex/misdn.tex (.../team/group/issue14292) (revision 178988)
-@@ -1,28 +1,27 @@
- \subsection{Introduction}
-
- This package contains the mISDN Channel Driver for the Asterisk PBX. It
--supports every mISDN Hardware and provides an interface for asterisk.
-+supports every mISDN Hardware and provides an interface for Asterisk.
-
- \subsection{Features}
-
- \begin{itemize}
--\item NT and TE mode
--\item PP and PMP mode
--\item BRI and PRI (with BNE1 and BN2E1 Cards)
--\item Hardware Bridging
--\item DTMF Detection in HW+mISDNdsp
--\item Display Messages on Phones (on those that support display msg)
--\item app\_SendText
--\item HOLD/RETRIEVE/TRANSFER on ISDN Phones : )
--\item Screen/ Not Screen User Number
--\item EchoCancellation
--\item Volume Control
--\item Crypting with mISDNdsp (Blowfish)
--\item Data (HDLC) callthrough
--\item Data Calling (with app\_ptyfork +pppd)
--\item Echo cancellation
--\item CallDeflection
--\item Some other
-+\item NT and TE mode
-+\item PP and PMP mode
-+\item BRI and PRI (with BNE1 and BN2E1 Cards)
-+\item Hardware bridging
-+\item DTMF detection in HW+mISDNdsp
-+\item Display messages on phones (on those that support it)
-+\item app\_SendText
-+\item HOLD/RETRIEVE/TRANSFER on ISDN phones : )
-+\item Allow/restrict user number presentation
-+\item Volume control
-+\item Crypting with mISDNdsp (Blowfish)
-+\item Data (HDLC) callthrough
-+\item Data calling (with app\_ptyfork +pppd)
-+\item Echo cancellation
-+\item Call deflection
-+\item Some others
- \end{itemize}
-
- \subsection{Fast Installation Guide}
-@@ -31,7 +30,7 @@
- \begin{itemize}
- \item You can download latest stable releases from \url{http://www.misdn.org/downloads/}
-
-- \item Just fetch the newest head of the GIT (mISDN provect moved from CVS)
-+ \item Just fetch the newest head of the GIT (mISDN project moved from CVS)
- In details this process described here: \url{http://www.misdn.org/index.php/GIT}
- \end{itemize}
-
-@@ -50,7 +49,7 @@
- make && make install
- \end{verbatim}
- \end{astlisting}
--Now you can compile chan\_misdn, just by making asterisk:
-+Now you can compile chan\_misdn, just by making Asterisk:
- \begin{astlisting}
- \begin{verbatim}
- cd asterisk ;
-@@ -66,8 +65,7 @@
-
- To compile and install this driver, you'll need at least one mISDN Driver and
- the mISDNuser package. Chan\_misdn works with both, the current release version
--and the development (svn trunk) version of Asterisk. mISDNuser and mISDN must
--be fetched from cvs.isdn4linux.de.
-+and the development (svn trunk) version of Asterisk.
-
- You should use Kernels $>$= 2.6.9
-
-@@ -84,7 +82,7 @@
- \end{verbatim}
- \end{astlisting}
- Now you will want to configure the misdn.conf file which resides in the
--asterisk config directory (normally /etc/asterisk).
-+Asterisk config directory (normally /etc/asterisk).
-
- \subsubsection{misdn.conf: [general]}
- The misdn.conf file contains a "general" subsection, and user subsections which
-@@ -93,13 +91,13 @@
- In the general subsection you can set options that are not directly port
- related. There is for example the very important debug variable which you can
- set from the Asterisk cli (command line interface) or in this configuration
--file, bigger numbers will lead to more debug output. There's also a tracefile
-+file, bigger numbers will lead to more debug output. There's also a trace file
- option, which takes a path+filename where debug output is written to.
-
- \subsubsection{misdn.conf: [default] subsection}
-
- The default subsection is another special subsection which can contain all the
--options available in the user/port subsections. the user/port subsection inherit
-+options available in the user/port subsections. The user/port subsections inherit
- their parameters from the default subsection.
-
- \subsubsection{misdn.conf: user/port subsections}
-@@ -108,13 +106,13 @@
- contain the ports variable which mean the mISDN Ports. Here you can add
- multiple ports, comma separated.
-
--Espacially for TE-Mode Ports there is a msns option. This option tells the
-+Especially for TE-Mode Ports there is a msns option. This option tells the
- chan\_misdn driver to listen for incoming calls with the given msns, you can
--insert a '*' as single msn, which leads in getting every incoming call (if you
--want to share on PMP TE S0 with a asterisk and a phone or isdn card you should
--insert here the msns which you'll like to give the Asterisk). Finally a
--context variable resides in the user subsections, which tells chan\_misdn where to
--send incoming calls to in the Asterisk dial plan (extension.conf).
-+insert a '*' as single msn, which leads to getting every incoming call. If you
-+want to share on PMP TE S0 with Asterisk and a phone or ISDN card you should
-+insert here the msns which you assign to Asterisk. Finally a context variable
-+resides in the user subsections, which tells chan\_misdn where to send incoming
-+calls to in the Asterisk dial plan (extension.conf).
-
-
- \subsubsection{Dial and Options String}
-@@ -127,20 +125,32 @@
- mISDN/<port>[:bchannel]|g:<group>/<extension>[/<OPTIONSSTRING>]
-
- The Optionsstring looks Like:
--:<optchar1><OptParam1>:<optchar2><OptParam2>
-+:<optchar><optarg>:<optchar><optarg>...
-
- the ":" character is the delimiter.
-
--The available Optchars are:
-- d - Send display text on called phone, text is the optparam
-- n - don't detect dtmf tones on called channel
-- h - make digital outgoing call
-- c - make crypted outgoing call, param is keyindex
-- e - perform echo cancellation on this channel,
-- takes taps as arguments (32,64,128,256)
-- s - send Non Inband DTMF as inband
-- vr - rxgain control
-- vt - txgain control
-+The available options are:
-+ a - Have Asterisk detect DTMF tones on called channel
-+ c - Make crypted outgoing call, optarg is keyindex
-+ d - Send display text to called phone, text is the optarg
-+ e - Perform echo cancelation on this channel,
-+ takes taps as optarg (32,64,128,256)
-+ e! - Disable echo cancelation on this channel
-+ f - Enable fax detection
-+ h - Make digital outgoing call
-+ h1 - Make HDLC mode digital outgoing call
-+ i - Ignore detected DTMF tones, don't signal them to Asterisk,
-+ they will be transported inband.
-+ jb - Set jitter buffer length, optarg is length
-+ jt - Set jitter buffer upper threshold, optarg is threshold
-+ jn - Disable jitter buffer
-+ n - Disable mISDN DSP on channel.
-+ Disables: echo cancel, DTMF detection, and volume control.
-+ p - Caller ID presentation,
-+ optarg is either 'allowed' or 'restricted'
-+ s - Send Non-inband DTMF as inband
-+ vr - Rx gain control, optarg is gain
-+ vt - Tx gain control, optarg is gain
- \end{verbatim}
- \end{astlisting}
-
-@@ -161,7 +171,7 @@
- PSTN_TE --> * Box 2 --> Phone2
- \end{verbatim}
-
--The Encryption must be done on the PSTN sides, so the dialplan on the boxes
-+The encryption must be done on the PSTN sides, so the dialplan on the boxes
- are:
-
- \begin{verbatim}
-@@ -210,7 +220,7 @@
-
- You can only use "misdn send display" when an Asterisk channel is created and
- isdn is in the correct state. "correct state" means that you have established a
--call to another phone (mustn't be isdn though).
-+call to another phone (must not be isdn though).
-
- Then you use it like this:
-
-@@ -232,8 +242,8 @@
- \subsection{Debugging and sending bug reports}
-
- If you encounter problems, you should set up the debugging flag, usually
--debug=2 should be enough. the messages are divided in asterisk and misdn
--parts. Misdn Debug messages begin with an 'I', asterisk messages begin with
-+debug=2 should be enough. The messages are divided into Asterisk and mISDN
-+parts. mISDN Debug messages begin with an 'I', Asterisk messages begin with
- an '*', the rest is clear I think.
-
- Please take a trace of the problem and open a report in the Asterisk issue
-@@ -266,7 +276,7 @@
-
- \subsection{Known Problems}
-
--Q: I cannot hear any tone after a successful CONNECT to the other end
-+Q: I cannot hear any tone after a successful CONNECT to the other end.
-
- A: You forgot to load mISDNdsp, which is now needed by chan\_misdn for switching
--and dtmf tone detection
-+and DTMF tone detection.
-Index: doc/tex/cdrdriver.tex
-===================================================================
---- a/doc/tex/cdrdriver.tex (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/tex/cdrdriver.tex (.../team/group/issue14292) (revision 178988)
-@@ -260,19 +260,35 @@
- \item Asterisk PBX
- \end{itemize}
-
--\begin{verbatim}
-- +--------------------+
-- | Asterisk PBX |
-- | |
-- |********************|
-- | | +---------------+
-- | RADIUS client |------->| RADIUS server |
-- | |<-------| (FreeRADIUS) |
-- +--------------------+ +---------------+
--\end{verbatim}
-+\begin{figure}[h]
-+\begin{center}
-+\setlength{\unitlength}{4cm}
-+\begin{picture}(3,.75)
-+\put(0,0){\line(0,1){.75}}
-+\put(0,.75){\line(1,0){1.5}}
-+\put(1.5,0){\line(0,1){.75}}
-+\put(0,0){\line(1,0){1.5}}
-+\put(.1,.4){\makebox(1.3,.3){Asterisk PBX}}
-+\put(.1,.4){\line(1,0){1.3}}
-+\put(.1,.1){\line(1,0){1.3}}
-+\put(.1,.1){\line(0,1){.3}}
-+\put(1.4,.1){\line(0,1){.3}}
-+\put(.1,.1){\makebox(1.3,.3){RADIUS Client}}
-+\put(1.8,0){\line(0,1){.5}}
-+\put(1.8,.5){\line(1,0){1.1}}
-+\put(1.8,0){\line(1,0){1.1}}
-+\put(2.9,0){\line(0,1){.5}}
-+\put(1.8,.275){\makebox(1.1,.1){RADIUS Server}}
-+\put(1.8,.125){\makebox(1.1,.1){$(FreeRADIUS)$}}
-+\thicklines
-+\put(1.4,.3){\vector(1,0){.4}}
-+\put(1.8,.2){\vector(-1,0){.4}}
-+\thinlines
-+\end{picture}
-+\end{center}
-+\caption{Asterisk/RADIUS Integration}
-+\end{figure}
-
--
--
- \subsection{Steps to follow in order to have RADIUS support}
-
- \subsubsection{Installation of the Radiusclient library}
-Index: doc/tex/odbcstorage.tex
-===================================================================
---- a/doc/tex/odbcstorage.tex (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/tex/odbcstorage.tex (.../team/group/issue14292) (revision 178988)
-@@ -2,30 +2,32 @@
-
- ODBC Storage allows you to store voicemail messages within a database
- instead of using a file. This is \textbf{not} a full realtime engine and
--\textbf{only} supports ODBC. The table description for the "voicemessages"
-+\textbf{only} supports ODBC. The table description for the \texttt{voicemessages}
- table is as follows:
-
--\begin{verbatim}
--+----------------+-------------+------+-----+---------+-------+
--| Field | Type | Null | Key | Default | Extra |
--+----------------+-------------+------+-----+---------+-------+
--| msgnum | int(11) | YES | | NULL | |
--| dir | varchar(80) | YES | MUL | NULL | |
--| context | varchar(80) | YES | | NULL | |
--| macrocontext | varchar(80) | YES | | NULL | |
--| callerid | varchar(40) | YES | | NULL | |
--| origtime | varchar(40) | YES | | NULL | |
--| duration | varchar(20) | YES | | NULL | |
--| mailboxuser | varchar(80) | YES | | NULL | |
--| mailboxcontext | varchar(80) | YES | | NULL | |
--| recording | longblob | YES | | NULL | |
--+----------------+-------------+------+-----+---------+-------+
--\end{verbatim}
-+\begin{table}[h]
-+\begin{center}
-+\begin{tabular}{ | l | l | c | c | l | l | }
-+\hline
-+Field & Type & Null & Key & Default & Extra \\ \hline \hline
-+msgnum & int(11) & Yes & & NULL & \\ \hline
-+dir & varchar(80) & Yes & MUL & NULL & \\ \hline
-+context & varchar(80) & Yes & & NULL & \\ \hline
-+macrocontext & varchar(80) & Yes & & NULL & \\ \hline
-+callerid & varchar(40) & Yes & & NULL & \\ \hline
-+origtime & varchar(40) & Yes & & NULL & \\ \hline
-+duration & varchar(20) & Yes & & NULL & \\ \hline
-+mailboxuser & varchar(80) & Yes & & NULL & \\ \hline
-+mailboxcontext & varchar(80) & Yes & & NULL & \\ \hline
-+recording & longblob & Yes & & NULL & \\
-+\hline
-+\end{tabular}
-+\end{center}
-+\caption{\texttt{voicemessages} Table Schema}
-+\end{table}
-
--The database name (from \path{/etc/asterisk/res_odbc.conf}) is in the
--"odbcstorage" variable in the general section of voicemail.conf.
-+The database name (from \path{/etc/asterisk/res_odbc.conf}) is in the
-+\texttt{odbcstorage} variable in the general section of \path{voicemail.conf}.
-
--You may modify the voicemessages table name by using
--odbctable=??? in voicemail.conf.
--
--
-+You may modify the \texttt{voicemessages} table name by using
-+\texttt{odbctable=\textit{table\_name}} in \path{voicemail.conf}.
-Index: doc/tex/asterisk-conf.tex
-===================================================================
---- a/doc/tex/asterisk-conf.tex (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/doc/tex/asterisk-conf.tex (.../team/group/issue14292) (revision 178988)
-@@ -82,6 +82,9 @@
- ; Enable internal timing support (-I)
- internal_timing = yes | no
-
-+; Language Options
-+documentation_language = en | es | ru
-+
- ; These options have no command line equivalent
-
- ; Cache record() files in another directory until completion
-Index: doc/followme.txt
-===================================================================
---- a/doc/followme.txt (.../tags/1.6.1-rc1) (revision 0)
-+++ b/doc/followme.txt (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,32 @@
-+Followme is now realtime-enabled:
-+
-+To use, you must define two backend data structures, with the following fields:
-+
-+followme:
-+ name Name of this followme entry. Specified when invoking the FollowMe
-+ application in the dialplan. This field is the only one which is
-+ mandatory. All of the other fields will inherit the default from
-+ followme.conf, if not specified in this data resource.
-+ musicclass OR The musiconhold class used for the caller while waiting to be
-+ musiconhold OR connected.
-+ music
-+ context Dialplan context from which to dial numbers
-+ takecall DTMF used to accept the call and be connected. For obvious reasons,
-+ this needs to be a single digit, '*', or '#'.
-+ declinecall DTMF used to refuse the call, sending it onto the next step, if any.
-+ call_from_prompt Prompt to play to the callee, announcing the call.
-+ norecording_prompt The alternate prompt to play to the callee, when the caller
-+ refuses to leave a name (or the option isn't set to allow them).
-+ options_prompt Normally, "press 1 to accept, 2 to decline".
-+ hold_prompt Message played to the caller while dialing the followme steps.
-+ status_prompt Normally, "Party is not at their desk".
-+ sorry_prompt Normally, "Unable to locate party".
-+
-+followme_numbers:
-+ name Name of this followme entry. Must match the name above.
-+ ordinal An integer, specifying the order in which these numbers will be
-+ followed.
-+ phonenumber The telephone number(s) you would like to call, separated by '&'.
-+ timeout Timeout associated with this step. See the followme documentation
-+ for more information on how this value is handled.
-+
-
-Property changes on: doc/followme.txt
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: doc/database_transactions.txt
-===================================================================
---- a/doc/database_transactions.txt (.../tags/1.6.1-rc1) (revision 0)
-+++ b/doc/database_transactions.txt (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,29 @@
-+As of 1.6.2, Asterisk now supports doing database transactions from the
-+dialplan. A number of new applications and functions have been introduced
-+for this purpose and this document should hopefully familiarize you with
-+all of them.
-+
-+First, the ODBC() function has been added which is used to set up all new
-+database transactions. Simply write the name of the transaction to this
-+function, along with the arguments of "transaction" and the database name,
-+e.g. Set(ODBC(transaction,postgres-asterisk)=foo). In this example, the
-+name of the transaction is "foo". The name doesn't really matter, unless
-+you're manipulating multiple transactions within the same dialplan, at the
-+same time. Then, you use the transaction name to change which transaction
-+is active for the next dialplan function.
-+
-+The ODBC() function is also used to turn on a mode known as forcecommit.
-+For most cases, you won't need to use this, but it's there. It simply
-+causes a transaction to be committed, when the channel hangs up. The other
-+property which may be set is the isolation property. Please consult with
-+your database vendor as to which values are supported by their ODBC driver.
-+Asterisk supports setting all standard ODBC values, but many databases do
-+not support the entire complement.
-+
-+Finally, when you have run multiple statements on your transaction and you
-+wish to complete the transaction, use the ODBC_Commit and ODBC_Rollback
-+applications, along with the transaction ID (in the example above, "foo")
-+to commit or rollback the transaction. Please note that if you do not
-+explicitly commit the transaction or if forcecommit is not turned on, the
-+transaction will be automatically rolled back at channel destruction (after
-+hangup) and all related database resources released back to the pool.
-
-Property changes on: doc/database_transactions.txt
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-
-Property changes on: doc
-___________________________________________________________________
-Modified: svn:ignore
- - api
-
- + api
-core-en_US.xml
-
-
-Index: UPGRADE.txt
-===================================================================
---- a/UPGRADE.txt (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/UPGRADE.txt (.../team/group/issue14292) (revision 178988)
-@@ -18,6 +18,13 @@
- ===
- ===========================================================
-
-+From 1.6.1 to 1.6.2:
-+
-+* The res_indications module has been removed. Its functionality was important
-+ enough that most of it has been moved into the Asterisk core.
-+ Two applications previously provided by res_indications, PlayTones and
-+ StopPlayTones, have been moved into a new module, app_playtones.
-+
- From 1.6.0.1 to 1.6.1:
-
- * The ast_agi_register_multiple() and ast_agi_unregister_multiple()
-@@ -67,3 +74,36 @@
-
- * The "Join" event from app_queue now uses the CallerIDNum header instead of
- the CallerID header to indicate the CallerID number.
-+
-+From 1.6.1 to 1.6.2:
-+
-+* The default console now will use colors according to the default background
-+ color, instead of forcing the background color to black. If you are using a
-+ light colored background for your console, you may wish to use the option
-+ flag '-W' to present better color choices for the various messages. However,
-+ if you'd prefer the old method of forcing colors to white text on a black
-+ background, the compatibility option -B is provided for this purpose.
-+
-+* SendImage() no longer hangs up the channel on transmission error or on
-+ any other error; in those cases, a FAILURE status is stored in
-+ SENDIMAGESTATUS and dialplan execution continues. The possible
-+ return values stored in SENDIMAGESTATUS are: SUCCESS, FAILURE, and
-+ UNSUPPORTED. ('OK' has been replaced with 'SUCCESS', and 'NOSUPPORT'
-+ has been replaced with 'UNSUPPORTED'). This change makes the
-+ SendImage application more consistent with other applications.
-+
-+* skinny.conf now has separate sections for lines and devices.
-+ Please have a look at configs/skinny.conf.sample and update
-+ your skinny.conf.
-+
-+* Queue names previously were treated in a case-sensitive manner,
-+ meaning that queues with names like "sales" and "sALeS" would be
-+ seen as unique queues. The parsing logic has changed to use
-+ case-insensitive comparisons now when originally hashing based on
-+ queue names, meaning that now the two queues mentioned as examples
-+ earlier will be seen as having the same name.
-+
-+* The SPRINTF() dialplan function has been moved into its own module,
-+ func_sprintf, and is no longer included in func_strings. If you use this
-+ function and do not use 'autoload=yes' in modules.conf, you will need
-+ to explicitly load func_sprintf for it to be available.
-Index: CHANGES
-===================================================================
---- a/CHANGES (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/CHANGES (.../team/group/issue14292) (revision 178988)
-@@ -9,6 +9,219 @@
- ======================================================================
-
- ------------------------------------------------------------------------------
-+--- Functionality changes for COLP feature -----------------------------------
-+------------------------------------------------------------------------------
-+
-+Dialplan Functions
-+------------------
-+ * Added new dialplan functions CONNECTEDLINE and REDIRECTING which permits
-+ setting various connected line and redirecting party information.
-+
-+Queue changes
-+-------------
-+ * A new option, 'I' has been added to both app_queue and app_dial.
-+ By setting this option, Asterisk will not update the caller with
-+ connected line changes or redirecting party changes when they occur.
-+
-+mISDN channel driver (chan_misdn) changes
-+----------------------------------------
-+ * Added display_connected parameter to misdn.conf to put a display string
-+ in the CONNECT message containing the connected name and/or number if
-+ the presentation setting permits it.
-+ * Added display_setup parameter to misdn.conf to put a display string
-+ in the SETUP message containing the caller name and/or number if the
-+ presentation setting permits it.
-+ * Made misdn.conf parameters localdialplan and cpndialplan take a -1 to
-+ indicate the dialplan settings are to be obtained from the asterisk
-+ channel.
-+ * Made misdn.conf parameter callerid accept the "name" <number> format
-+ used by the rest of the system.
-+ * Made use the nationalprefix and internationalprefix misdn.conf
-+ parameters to prefix any received number from the ISDN link if that
-+ number has the corresponding Type-Of-Number.
-+ * Added the following new parameters: unknownprefix, netspecificprefix,
-+ subscriberprefix, and abbreviatedprefix in misdn.conf to prefix any
-+ received number from the ISDN link if that number has the corresponding
-+ Type-Of-Number.
-+
-+libpri channel driver (chan_dahdi) changes
-+-------------------------------------------
-+ * The channel variable PRIREDIRECTREASON is now just a status variable.
-+ Use the REDIRECTING(reason) dialplan function to alter the reason.
-+
-+SIP channel driver (chan_sip) changes
-+-------------------------------------------
-+ * The sendrpid parameter has been expanded to include the options
-+ 'rpid' and 'pai'. Setting sendrpid to 'rpid' will cause Remote-Party-ID
-+ header to be sent (equivalent to setting sendrpid=yes) and setting
-+ sendrpid to 'pai' will cause P-Asserted-Identity header to be sent.
-+
-+------------------------------------------------------------------------------
-+--- Functionality changes from Asterisk 1.6.1 to Asterisk 1.6.2 -------------
-+------------------------------------------------------------------------------
-+
-+SIP Changes
-+-----------
-+ * Added support for SUBSCRIBE/NOTIFY with dialog-info based call pickups.
-+ Snom phones use this for call pickup of extensions that the phone is
-+ subscribed to.
-+ * Added support for subscribing to a voice mailbox on a remote server and
-+ making the new/old message count available to local devices.
-+ * Added support for setting the domain in the URI for caller of an
-+ outbound call by using the SIPFROMDOMAIN channel variable.
-+ * Added a new configuration option "remotesecret" for authentication to
-+ remote services. For backwards compatibility, "secret" still has the
-+ same function as before, but now you can configure both a remote secret and a
-+ local secret for mutual authentication.
-+ * Added a new 'faxdetect=yes|no' configuration option to sip.conf. When this
-+ option is enabled, a SIP channel will go to the fax extension (if it exists)
-+ after T38 is negotiated. This option is disabled by default.
-+ * If the channel variable ATTENDED_TRANSFER_COMPLETE_SOUND is set,
-+ the sound will be played to the target of an attended transfer
-+ * Added two new configuration options, "qualifygap" and "qualifypeers", which allow
-+ finer control over how many peers Asterisk will qualify and the gap between them
-+ when all peers need to be qualified at the same time.
-+ * Added a new 'ignoresdpversion' option to sip.conf. When this is enabled
-+ (either globally or for a specific peer), chan_sip will treat any SDP data
-+ it receives as new data and update the media stream accordingly. By
-+ default, Asterisk will only modify the media stream if the SDP session
-+ version received is different from the current SDP session version. This
-+ option is required to interoperate with devices that have non-standard SDP
-+ session version implementations (observed with Microsoft OCS). This option
-+ is disabled by default.
-+ * The parsing of register => lines in sip.conf has been modified to allow a port
-+ to be present in the "user" portion. Please see the sip.conf.sample file for more
-+ information
-+ * Added support for subscribing to MWI on a remote server and making the status available
-+ as a mailbox. Please see the sip.conf.sample file for more information.
-+ * Added a function to remove SIP headers added in the dialplan before the
-+ first INVITE is generated - SIPRemoveHeader()
-+ * Channel variables set with setvar= in a device configuration is now
-+ set both for inbound and outbound calls.
-+ * Added support for ITU G.722.1 and G.722.1C (Siren7 and Siren14) media streams.
-+
-+IAX2 changes
-+------------
-+ * Added immediate option to iax.conf
-+ * Added forceencryption option to iax.conf
-+ * Added Encryption and Trunk status to manager command "iaxpeers"
-+
-+Skinny Changes
-+--------------
-+ * The configuration file now holds separate sections for devices and lines.
-+ Please have a look at configs/skinny.conf.sample and change your skinny.conf
-+ accordingly.
-+
-+DAHDI Changes
-+-------------
-+ * The UK option waitfordialtone has been added for use with BT analog
-+ lines.
-+ * Added a 'faxbuffers' configuration option to chan_dahdi.conf. This option
-+ is used in conjunction with the 'faxdetect' configuration option. When
-+ 'faxbuffers' is used and fax tones are detected, the channel will dynamically
-+ switch to the configured faxbuffers policy. For example, to use 6 buffers
-+ and a 'full' buffer policy for a fax transmission, add:
-+ faxbuffers=>6,full
-+ The faxbuffers configuration will be in affect until the call is torn down.
-+
-+Dialplan Functions
-+------------------
-+ * Added a new dialplan function, CURLOPT, which permits setting various
-+ options that may be useful with the CURL dialplan function, such as
-+ cookies, proxies, connection timeouts, passwords, etc.
-+ * Permit the syntax and synopsis fields of the corresponding dialplan
-+ functions to be individually set from func_odbc.conf.
-+ * Added debugging CLI functions to func_odbc, 'odbc read' and 'odbc write'.
-+ * func_odbc now may specify an insert query to execute, when the write query
-+ affects 0 rows (usually indicating that no such row exists).
-+ * Added a new dialplan function, LISTFILTER, which permits removing elements
-+ from a set list, by name. Uses the same general syntax as the existing CUT
-+ and FIELDQTY dialplan functions, which also manage lists.
-+ * Added REALTIME_FIELD and REALTIME_HASH, which should aid users in better
-+ obtaining realtime data from the dialplan.
-+ * Added LOCAL_PEEK, which I have no idea how to use, but Leif Madsen wanted it.
-+ Russell says it's, like, a scope resolution function for LOCAL variables.
-+ Totally. Hopefully, that means more to you than it does to me.
-+ * Added AUDIOHOOK_INHERIT. For information on its use, please see the output
-+ of "core show function AUDIOHOOK_INHERIT" from the CLI
-+ * Added AES_ENCRYPT. For information on its use, please see the output
-+ of "core show function AES_ENCRYPT" from the CLI
-+ * Added AES_DECRYPT. For information on its use, please see the output
-+ of "core show function AES_DECRYPT" from the CLI
-+ * func_odbc now supports database transactions across multiple queries.
-+
-+Applications
-+------------
-+ * DAHDISendCallreroutingFacility parameters are now comma-separated,
-+ instead of the old pipe.
-+ * Scheduled meetme conferences may now have their end times extended by
-+ using MeetMeAdmin.
-+ * app_authenticate now gives the ability to select a prompt other than
-+ the default.
-+ * app_directory now pays attention to the searchcontexts setting in
-+ voicemail.conf and will look through all contexts, if no context is
-+ specified in the initial argument.
-+ * A new application, Originate, has been introduced, that allows asynchronous
-+ call origination from the dialplan.
-+ * Voicemail now permits setting the emailsubject and emailbody per mailbox,
-+ in addition to the setting in the "general" context.
-+
-+Miscellaneous
-+-------------
-+ * The Asterisk CLI has a new command, "channel redirect", which is similar in
-+ operation to the AMI Redirect action.
-+ * res_jabber: autoprune has been disabled by default, to avoid misconfiguration
-+ that would end up being interpreted as a bug once Asterisk started removing
-+ the contacts from a user list.
-+ * extensions.conf now allows you to use keyword "same" to define an extension
-+ without actually specifying an extension. It uses exactly the same pattern
-+ as previously used on the last "exten" line. For example:
-+ exten => 123,1,NoOp(something)
-+ same => n,SomethingElse()
-+ * musiconhold.conf classes of type 'files' can now use relative directory paths,
-+ which are interpreted as relative to the astvarlibdir setting in asterisk.conf.
-+ * All deprecated CLI commands are removed from the sourcecode. They are now handled
-+ by the new clialiases module. See cli_aliases.conf.sample file.
-+ * Times within timespecs are now accurate down to the minute. This is a change
-+ from historical Asterisk, which only provided timespecs rounded to the nearest
-+ even (read: evenly divisible by 2) minute mark.
-+ * The realtime switch now supports an option flag, 'p', which disables searches for
-+ pattern matches.
-+ * In addition to a time range and date range, timespecs now accept a 5th optional
-+ argument, timezone. This allows you to perform time checks on alternate
-+ timezones, especially if those daylight savings time ranges vary from your
-+ machine's native timezone. See GotoIfTime, ExecIfTime, IFTIME(), and timed
-+ includes.
-+ * The contrib/scripts/ directory now has a script called sip_nat_settings that will
-+ give you the correct output for an asterisk box behind nat. It will give you the
-+ externhost and localnet settings.
-+ * The Asterisk core now supports ITU G.722.1 and G.722.1C media streams, and
-+ can connect calls in passthrough mode, as well as record and play back files.
-+ * Successful and unsuccessful call pickup can now be alerted through sounds, by
-+ using pickupsound and pickupfailsound in features.conf.
-+
-+Asterisk Manager Interface
-+--------------------------
-+ * When using the AMI over HTTP, you can now include a 'SuppressEvents' header (with
-+ a non-empty value) in your request. If you do this, any pending AMI events will
-+ *not* be included in the response to your request as they would normally, but
-+ will be left in the event queue for the next request you make to retrieve. For
-+ some applications, this will allow you to guarantee that you will only see
-+ events in responses to 'WaitEvent' actions, and can better know when to expect them.
-+ To know whether the Asterisk server supports this header or not, your client can
-+ inspect the first response back from the server to see if it includes this header:
-+
-+ Pragma: SuppressEvents
-+
-+ If this is included, the server supports event suppression.
-+
-+ * Added 4 new Actions to list skinny device(s) and line(s)
-+ SKINNYdevices
-+ SKINNYshowdevice
-+ SKINNYlines
-+ SKINNYshowline
-+
-+------------------------------------------------------------------------------
- --- Functionality changes from Asterisk 1.6.0 to Asterisk 1.6.1 -------------
- ------------------------------------------------------------------------------
-
-@@ -78,8 +291,6 @@
- wish to validate or invalidate the password given. Arguments are:
- "mailbox" "context" "oldpass" "newpass". See the sample voicemail.conf for
- more details
-- * The voicemail externnotify script now accepts an additional (last) parameter
-- containing the number of urgent messages in the INBOX.
- * Dial has a new option: F(context^extension^pri), which permits a callee to
- continue in the dialplan, at the specified label, if the caller hangs up.
- * ChanSpy and ExtenSpy have a new option, 's' which suppresses speaking the
-@@ -184,6 +395,7 @@
- --------------------------------
- * The Status command now takes an optional list of variables to display
- along with channel status.
-+ * The QueueEntry event now also includes the channel's uniqueid
-
- ODBC Changes
- ------------
-@@ -198,6 +410,9 @@
- * A new configuration option, "timeoutpriority" has been added. Please see the section labeled
- "QUEUE TIMING OPTIONS" in configs/queues.conf.sample for a detailed explanation of the option
- as well as an explanation about timeout options in general
-+ * Added a new option - C - for forcing the "answered elsewhere" flag on
-+ cancellation of calls in to members of the queue. This is to avoid the
-+ call to a member of a queue having the call listed as a "missed call".
-
- Realtime changes
- ----------------
-@@ -220,6 +435,11 @@
- operator. This is most helpful when working with long SQL queries in
- func_odbc.conf, as the queries no longer need to be specified on a single
- line.
-+ * CDR config file, cdr.conf, has an added option, "initiatedseconds",
-+ which will add a second to the billsec when the ending
-+ time is set, if the number in the microseconds field of the end time is
-+ greater than the number of microseconds in the answer time. This allows
-+ users to count the 'initiated' seconds in their billing records.
-
- ------------------------------------------------------------------------------
- --- Functionality changes from Asterisk 1.4.X to Asterisk 1.6.0 -------------
-@@ -277,6 +497,8 @@
- * Originate now accepts codec settings with "Codecs: alaw, ulaw, h264"
- * New command: Atxfer. See doc/manager_1_1.txt for more details or
- manager show command Atxfer from the CLI
-+ * New command: IAXregistry. See doc/manager_1_1.txt for more details or
-+ manager show command IAXregistry from the CLI
-
- Dialplan functions
- ------------------
-@@ -311,6 +533,12 @@
-
- CLI Changes
- -----------
-+ * Added CLI permissions, config file: cli_permissions.conf
-+ default is to allow all commands for every local user/group.
-+ Also this new feature added three new CLI commands:
-+ - cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]
-+ - cli reload permissions
-+ - cli show permissions
- * New CLI command "core show hint" (usage: core show hint <exten>)
- * New CLI command "core show settings"
- * Added 'core show channels count' CLI command.
-@@ -330,6 +558,9 @@
- sorted into the different possible callbacks, with the number of entries
- currently scheduled for each. Gives you a feel for how busy the sip channel
- driver is.
-+ * Added 'skinny show lines verbose' CLI command. This will show the subs for every channel.
-+ * Cleanup another bunch of CLI commands. Now all modules follow the same schema.
-+ (Done by lmadsen, junky and mvanbaak during the devcon 2008)
-
- SIP changes
- -----------
-@@ -440,8 +671,8 @@
- ----------------------
- * The ackcall and endcall options are now supplemented with options acceptdtmf
- and enddtmf. These allow for the DTMF keypress to be configurable. The options
-- default to their old hard-coded values ('#' and '*' respectively) so this should
-- not break any existing agent installations.
-+ default to their old hard-coded values ('#' and '*' respectively) so this should
-+ not break any existing agent installations.
-
- DAHDI channel driver (chan_dahdi) Changes
- ----------------------------------------
-@@ -570,6 +801,9 @@
- * Added a new parameter for member definition, called state_interface. This may be
- used so that a member may be called via one interface but have a different interface's
- device state reported.
-+ * Added new CLI and Manager commands relating to reloading queues. From the CLI, see
-+ "queue reload", "queue reset stats". Also see "manager show command QueueReload" and
-+ "manager show command QueueReset."
- * New configuration option: randomperiodicannounce. If a list of periodic announcements is
- specified by the periodic-announce option, then one will be chosen randomly when it is time
- to play a periodic announcment
-@@ -584,6 +818,14 @@
- when a realtime queue member is removed. Since there is no calling channel associated
- with these events, the string "REALTIME" is placed where the channel's unique id
- is typically placed.
-+ * The configuration method for the "joinempty" and "leavewhenempty" options has
-+ changed to a comma-separated list of methods of determining member availability
-+ instead of vague terms such as "yes," "loose," "no," and "strict." These old four
-+ values are still accepted for backwards-compatibility, though.
-+ * The average talktime is now calculated on queues. This information is reported via the
-+ CLI commands "queue show" and "queues show"; through the AMI events AgentComplete, QueueSummary,
-+ and QueueParams; and through the channelvariable QUEUETALKTIME if setinterfacevar=yes is set for
-+ the queue.
-
- MeetMe Changes
- --------------
-@@ -628,6 +870,7 @@
- WaitForRing() now takes floating pt timeout arg.
- SpeechBackground() -- clarified in the docstrings that the timeout is an integer seconds.
- * Added 's' option to Page application.
-+ * Added an optional timeout argument to the Page application.
- * Added 'E', 'V', and 'P' commands to ExternalIVR.
- * Added 'o' and 'X' options to Chanspy.
- * Added a new dialplan application, Bridge, which allows you to bridge the
-@@ -700,6 +943,13 @@
- Call Features (res_features) Changes
- ------------------------------------
- * Added the parkedcalltransfers option to features.conf
-+ * Added parkedcallparking option to control one touch parking w/ parking
-+ pickup
-+ * Added parkedcallhangup option to control disconnect feature w/ parking
-+ pickup
-+ * Added parkedcallrecording option to control one-touch record w/ parking
-+ pickup
-+ * Added BRIDGE_FEATURES variable to set available features for a channel
- * The built-in method for doing attended transfers has been updated to
- include some new options that allow you to have the transferee sent
- back to the person that did the transfer if the transfer is not successful.
-@@ -714,6 +964,7 @@
- the first one available.
- * Added cli command 'features reload' to reload call features from features.conf
- * Moved into core asterisk binary.
-+ * Changed the default setting for featuredigittimeout to 2000 ms from 500 ms.
-
- Language Support Changes
- ------------------------
-@@ -859,7 +1110,15 @@
- allocation of additional extensions which will reach the specified user.
- * A new option for the configure script, --enable-internal-poll, has been added
- for use with systems which may have a buggy implementation of the poll system
-- call. If you notice odd behavior such as the CLI being unresponsive on remote
-- consoles, you may want to try using this option. This option is enabled by default
-- on Darwin systems since it is known that the Darwin poll() implementation has
-- odd issues.
-+ call. If you notice odd behavior such as the CLI being unresponsive on remote
-+ consoles, you may want to try using this option. This option is enabled by default
-+ on Darwin systems since it is known that the Darwin poll() implementation has
-+ odd issues.
-+
-+Timer Changes
-+--------------------
-+* In addition to timing from DAHDI, there is a new timing module called
-+ res_timing_timerfd. In order to use this, you must be running Linux with
-+ a kernel version 2.6.25 or newer as well as glibc 2.8 or newer. The configure
-+ script will be able to tell if you have the requirements. From menuselect, select
-+ res_timing_timerfd from the Resource Modules menu.
-Index: sounds/sounds.xml
-===================================================================
---- a/sounds/sounds.xml (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/sounds/sounds.xml (.../team/group/issue14292) (revision 178988)
-@@ -14,6 +14,10 @@
- </member>
- <member name="CORE-SOUNDS-EN-SLN16" displayname="English, Signed-linear 16kHz format">
- </member>
-+ <member name="CORE-SOUNDS-EN-SIREN7" displayname="English, G.722.1 (Siren7) format">
-+ </member>
-+ <member name="CORE-SOUNDS-EN-SIREN14" displayname="English, G.722.1C (Siren14) format">
-+ </member>
- <member name="CORE-SOUNDS-ES-WAV" displayname="Spanish, WAV format">
- </member>
- <member name="CORE-SOUNDS-ES-ULAW" displayname="Spanish, mu-Law format">
-@@ -28,6 +32,10 @@
- </member>
- <member name="CORE-SOUNDS-ES-SLN16" displayname="Spanish, Signed-linear 16kHz format">
- </member>
-+ <member name="CORE-SOUNDS-ES-SIREN7" displayname="Spanish, G.722.1 (Siren7) format">
-+ </member>
-+ <member name="CORE-SOUNDS-ES-SIREN14" displayname="Spanish, G.722.1C (Siren14) format">
-+ </member>
- <member name="CORE-SOUNDS-FR-WAV" displayname="French, WAV format">
- </member>
- <member name="CORE-SOUNDS-FR-ULAW" displayname="French, mu-Law format">
-@@ -42,6 +50,10 @@
- </member>
- <member name="CORE-SOUNDS-FR-SLN16" displayname="French, Signed-linear 16kHz format">
- </member>
-+ <member name="CORE-SOUNDS-FR-SIREN7" displayname="French, G.722.1 (Siren7) format">
-+ </member>
-+ <member name="CORE-SOUNDS-FR-SIREN14" displayname="French, G.722.1C (Siren14) format">
-+ </member>
- </category>
- <category name="MENUSELECT_MOH" displayname="Music On Hold File Packages" positive_output="yes">
- <member name="MOH-FREEPLAY-WAV" displayname="FreePlay Music On Hold Files, WAV format" >
-@@ -59,6 +71,10 @@
- </member>
- <member name="MOH-FREEPLAY-SLN16" displayname="FreePlay Music On Hold Files, Signed-linear 16kHz format" >
- </member>
-+ <member name="MOH-FREEPLAY-SIREN7" displayname="FreePlay Music On Hold Files, G.722.1 (Siren7) format" >
-+ </member>
-+ <member name="MOH-FREEPLAY-SIREN14" displayname="FreePlay Music On Hold Files, G.722.1C (Siren14) format" >
-+ </member>
- </category>
- <category name="MENUSELECT_EXTRA_SOUNDS" displayname="Extras Sound Packages" positive_output="yes">
- <member name="EXTRA-SOUNDS-EN-WAV" displayname="English, WAV format">
-@@ -73,4 +89,10 @@
- </member>
- <member name="EXTRA-SOUNDS-EN-G722" displayname="English, G.722 format">
- </member>
-+ <member name="EXTRA-SOUNDS-EN-SLN16" displayname="English, Signed-linear 16kHz format">
-+ </member>
-+ <member name="EXTRA-SOUNDS-EN-SIREN7" displayname="English, G.722.1 (Siren7) format">
-+ </member>
-+ <member name="EXTRA-SOUNDS-EN-SIREN14" displayname="English, G.722.1C (Siren14) format">
-+ </member>
- </category>
-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 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@
-+ @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@
-+ @echo "<docs>" >> $@
-+ @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 "</docs>" >> $@
-+
-+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
-+ <function name="RAND" language="en_US">
-+ <synopsis>
-+ Choose a random number in a range.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="min" />
-+ <parameter name="max" />
-+ </syntax>
-+ <description>
-+ <para>Choose a random number between <replaceable>min</replaceable> and <replaceable>max</replaceable>.
-+ <replaceable>min</replaceable> defaults to <literal>0</literal>, if not specified, while <replaceable>max</replaceable> defaults
-+ to <literal>RAND_MAX</literal> (2147483647 on many systems).</para>
-+ <para>Example: Set(junky=${RAND(1,8)});
-+ Sets junky to a random number between 1 and 8, inclusive.</para>
-+ </description>
-+ </function>
-+ ***/
- 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
-+ <function name="BASE64_ENCODE" language="en_US">
-+ <synopsis>
-+ Encode a string in base64.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true">
-+ <para>Input string</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the base64 string.</para>
-+ </description>
-+ </function>
-+ <function name="BASE64_DECODE" language="en_US">
-+ <synopsis>
-+ Decode a base64 string.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true">
-+ <para>Input string.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the plain text string.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<string>)",
- .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(<base64_string>)",
- .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
-+ <function name="AGC" language="en_US">
-+ <synopsis>
-+ Apply automatic gain control to audio on a channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channeldirection" required="true">
-+ <para>This can be either <literal>rx</literal> or <literal>tx</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>The AGC function will apply automatic gain control to the audio on the
-+ channel that it is executed on. Using <literal>rx</literal> for audio received
-+ and <literal>tx</literal> 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 <literal>1-32768</literal>. The larger the number
-+ the louder (more gain) the channel will receive.</para>
-+ <para>Examples:</para>
-+ <para>exten => 1,1,Set(AGC(rx)=8000)</para>
-+ <para>exten => 1,2,Set(AGC(tx)=off)</para>
-+ </description>
-+ </function>
-+ <function name="DENOISE" language="en_US">
-+ <synopsis>
-+ Apply noise reduction to audio on a channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channeldirection" required="true">
-+ <para>This can be either <literal>rx</literal> or <literal>tx</literal>
-+ the values that can be set to this are either <literal>on</literal> and
-+ <literal>off</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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 <literal>rx</literal> for audio received from the channel
-+ and <literal>tx</literal> to apply the filter to the audio being sent to the channel.</para>
-+ <para>Examples:</para>
-+ <para>exten => 1,1,Set(DENOISE(rx)=on)</para>
-+ <para>exten => 1,2,Set(DENOISE(tx)=off)</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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
-+ <function name="IFMODULE" language="en_US">
-+ <synopsis>
-+ Checks if an Asterisk module is loaded in memory.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="modulename.so" required="true">
-+ <para>Module name complete with <literal>.so</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Checks if a module is loaded. Use the full module name
-+ as shown by the list in <literal>module list</literal>.
-+ Returns <literal>1</literal> if module exists in memory, otherwise <literal>0</literal></para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<modulename.so>)",
- .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
-+ <function name="MD5" language="en_US">
-+ <synopsis>
-+ Computes an MD5 digest.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="data" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Computes an MD5 digest.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<data>)",
- .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
-+ <function name="DIALGROUP" language="en_US">
-+ <synopsis>
-+ Manages a group of users for dialing.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="group" required="true" />
-+ <parameter name="op">
-+ <para>The operation name, possible values are:</para>
-+ <para><literal>add</literal> - add a channel name or interface (write-only)</para>
-+ <para><literal>del</literal> - remove a channel name or interface (write-only)</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>When DIALGROUP is read from, the argument is interpreted as the particular
-+ <replaceable>group</replaceable> for which a dial should be attempted. When DIALGROUP is written to
-+ with no arguments, the entire list is replaced with the argument specified.</para>
-+ <para>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.</para>
-+ <para>Example:</para>
-+ <para>exten => 1,1,Set(DIALGROUP(mygroup,add)=SIP/10)</para>
-+ <para>exten => 1,n,Set(DIALGROUP(mygroup,add)=SIP/20)</para>
-+ <para>exten => 1,n,Dial(${DIALGROUP(mygroup)})</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<group>[,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
-+ <function name="ENV" language="en_US">
-+ <synopsis>
-+ Gets or sets the environment variable specified.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true">
-+ <para>Environment variable name</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ </description>
-+ </function>
-+ <function name="STAT" language="en_US">
-+ <synopsis>
-+ Does a check on the specified file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="flag" required="true">
-+ <para>Flag may be one of the following:</para>
-+ <para>d - Checks if the file is a directory.</para>
-+ <para>e - Checks if the file exists.</para>
-+ <para>f - Checks if the file is a regular file.</para>
-+ <para>m - Returns the file mode (in octal)</para>
-+ <para>s - Returns the size (in bytes) of the file</para>
-+ <para>A - Returns the epoch at which the file was last accessed.</para>
-+ <para>C - Returns the epoch at which the inode was last changed.</para>
-+ <para>M - Returns the epoch at which the file was last modified.</para>
-+ </parameter>
-+ <parameter name="filename" required="true" />
-+ </syntax>
-+ <description>
-+ </description>
-+ </function>
-+ <function name="FILE" language="en_US">
-+ <synopsis>
-+ Obtains the contents of a file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true" />
-+ <parameter name="offset" required="true">
-+ <para>Maybe specified as any number. if negative <replaceable>offset</replaceable> specifies the number
-+ of bytes back from the end of the file.</para>
-+ </parameter>
-+ <parameter name="length" required="true">
-+ <para>If specified, will limit the length of the data read to that size.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<envname>)",
- .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(<flag>,<filename>)",
-- .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(<filename>,<offset>,<length>)",
-- .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 =
--"<offset> may be specified as any number. If negative, <offset> specifies\n"
--" the number of bytes back from the end of the file.\n"
--"<length>, 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
-+ <function name="FIELDQTY" language="en_US">
-+ <synopsis>
-+ Count the fields with an arbitrary delimiter
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true" />
-+ <parameter name="delim" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Example: ${FIELDQTY(ex-amp-le,-)} returns 3</para>
-+ </description>
-+ </function>
-+ <function name="LISTFILTER" language="en_US">
-+ <synopsis>Remove an item from a list, by name.</synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true" />
-+ <parameter name="delim" required="true" default="," />
-+ <parameter name="value" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Remove <replaceable>value</replaceable> from the list contained in the <replaceable>varname</replaceable>
-+ variable, where the list delimiter is specified by the <replaceable>delim</replaceable> parameter. This is
-+ very useful for removing a single channel name from a list of channels, for example.</para>
-+ </description>
-+ </function>
-+ <function name="FILTER" language="en_US">
-+ <synopsis>
-+ Filter the string to include only the allowed characters
-+ </synopsis>
-+ <syntax>
-+ <parameter name="allowed-chars" required="true" />
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Permits all characters listed in <replaceable>allowed-chars</replaceable>,
-+ filtering all others outs. In addition to literally listing the characters,
-+ you may also use ranges of characters (delimited by a <literal>-</literal></para>
-+ <para>Hexadecimal characters started with a <literal>\x</literal>(i.e. \x20)</para>
-+ <para>Octal characters started with a <literal>\0</literal> (i.e. \040)</para>
-+ <para>Also <literal>\t</literal>,<literal>\n</literal> and <literal>\r</literal> are recognized.</para>
-+ <note><para>If you want the <literal>-</literal> character it needs to be prefixed with a
-+ <literal>\</literal></para></note>
-+ </description>
-+ </function>
-+ <function name="REGEX" language="en_US">
-+ <synopsis>
-+ Check string against a regular expression.
-+ </synopsis>
-+ <syntax argsep=" ">
-+ <parameter name="&quot;regular expression&quot;" required="true" />
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Return <literal>1</literal> on regular expression match or <literal>0</literal> otherwise</para>
-+ <para>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.</para>
-+ </description>
-+ </function>
-+ <application name="ClearHash" language="en_US">
-+ <synopsis>
-+ Clear the keys from a specified hashname.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="hashname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Clears all keys out of the specified <replaceable>hashname</replaceable>.</para>
-+ </description>
-+ </application>
-+ <function name="HASH" language="en_US">
-+ <synopsis>
-+ Implementation of a dialplan associative array
-+ </synopsis>
-+ <syntax>
-+ <parameter name="hashname" required="true" />
-+ <parameter name="hashkey" />
-+ </syntax>
-+ <description>
-+ <para>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</para>
-+ </description>
-+ </function>
-+ <function name="HASHKEYS" language="en_US">
-+ <synopsis>
-+ Retrieve the keys of the HASH() function.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="hashname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ </function>
-+ <function name="KEYPADHASH" language="en_US">
-+ <synopsis>
-+ Hash the letters in string into equivalent keypad numbers.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Example: ${KEYPADHASH(Les)} returns "537"</para>
-+ </description>
-+ </function>
-+ <function name="ARRAY" language="en_US">
-+ <synopsis>
-+ Allows setting multiple variables at once.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="var1" required="true" />
-+ <parameter name="var2" required="false" multiple="true" />
-+ <parameter name="varN" required="false" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2</para>
-+ </description>
-+ </function>
-+ <function name="STRPTIME" language="en_US">
-+ <synopsis>
-+ Returns the epoch of the arbitrary date/time string structured as described by the format.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="datetime" required="true" />
-+ <parameter name="timezone" required="true" />
-+ <parameter name="format" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This is useful for converting a date into <literal>EPOCH</literal> time,
-+ possibly to pass to an application like SayUnixTime or to calculate the difference
-+ between the two date strings</para>
-+ <para>Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835</para>
-+ </description>
-+ </function>
-+ <function name="STRFTIME" language="en_US">
-+ <synopsis>
-+ Returns the current date/time in the specified format.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="epoch" />
-+ <parameter name="timezone" />
-+ <parameter name="format" />
-+ </syntax>
-+ <description>
-+ <para>STRFTIME supports all of the same formats as the underlying C function
-+ <emphasis>strftime(3)</emphasis>.
-+ It also supports the following format: <literal>%[n]q</literal> - fractions of a second,
-+ with leading zeros.</para>
-+ <para>Example: <literal>%3q</literal> will give milliseconds and <literal>%1q</literal>
-+ 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 <literal>%S.%3q</literal>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="manpage">strftime(3)</ref>
-+ </see-also>
-+ </function>
-+ <function name="EVAL" language="en_US">
-+ <synopsis>
-+ Evaluate stored variables
-+ </synopsis>
-+ <syntax>
-+ <parameter name="variable" required="true" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ <para>Example: If the <variable>MYVAR</variable> contains
-+ <variable>OTHERVAR</variable>, then the result of ${EVAL(
-+ <variable>MYVAR</variable>)} in the dialplan will be the
-+ contents of <variable>OTHERVAR</variable>. Normally just
-+ putting <variable>MYVAR</variable> in the dialplan the result
-+ would be <variable>OTHERVAR</variable>.</para>
-+ </description>
-+ </function>
-+ <function name="TOUPPER" language="en_US">
-+ <synopsis>
-+ Convert string to all uppercase letters.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Example: ${TOUPPER(Example)} returns "EXAMPLE"</para>
-+ </description>
-+ </function>
-+ <function name="TOLOWER" language="en_US">
-+ <synopsis>
-+ Convert string to all lowercase letters.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Example: ${TOLOWER(Example)} returns "example"</para>
-+ </description>
-+ </function>
-+ <function name="LEN" language="en_US">
-+ <synopsis>
-+ Return the length of the string given.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Example: ${LEN(example)} returns 7</para>
-+ </description>
-+ </function>
-+ <function name="QUOTE" language="en_US">
-+ <synopsis>
-+ Quotes a given string, escaping embedded quotes as necessary
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Example: ${QUOTE(ab"c"de)} will return "abcde"</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<varname>,<delim>)",
- .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(<listname>,<delimiter>,<fieldvalue>)\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(<allowed-chars>,<string>)",
- .read = filter,
-- .desc =
--"Permits all characters listed in <allowed-chars>, 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(\"<regular expression>\" <data>)",
- .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(<hashname>)\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(<hashname>)",
- .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(<format>,<arg1>[,...<argN>])",
-- .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(<string>)",
- .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(<string>)",
- .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([<epoch>][,[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(<datetime>,<timezone>,<format>)",
-- .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(<variable>)",
-- .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(<string>)",
- .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(<string>)",
- .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(<string>)",
- .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(&regex_function);
- res |= ast_custom_function_unregister(&array_function);
- res |= ast_custom_function_unregister(&quote_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(&regex_function);
- res |= ast_custom_function_register(&array_function);
- res |= ast_custom_function_register(&quote_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
-+ <function name="VMCOUNT" language="en_US">
-+ <synopsis>
-+ Count the voicemails in a specified mailbox.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="vmbox" required="true" argsep="@">
-+ <argument name="vmbox" required="true" />
-+ <argument name="context" required="false">
-+ <para>If not specified, defaults to <literal>default</literal>.</para>
-+ </argument>
-+ </parameter>
-+ <parameter name="folder" required="false">
-+ <para>If not specified, defaults to <literal>INBOX</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Count the number of voicemails in a specified mailbox, you could also specify
-+ the <replaceable>context</replaceable> and the mailbox <replaceable>folder</replaceable>.</para>
-+ <para>Example: <literal>exten => s,1,Set(foo=${VMCOUNT(125)})</literal></para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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
-+ <function name="SHA1" language="en_US">
-+ <synopsis>
-+ Computes a SHA1 digest.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="data" required="true">
-+ <para>Input string</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Generate a SHA1 digest via the SHA1 algorythm.</para>
-+ <para>Example: Set(sha1hash=${SHA1(junky)})</para>
-+ <para>Sets the asterisk variable sha1hash to the string <literal>60fa5675b9303eb62f99a9cd47f9f5837d18f9a0</literal>
-+ which is known as his hash</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<data>)",
- .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
-+ <function name="ISNULL" language="en_US">
-+ <synopsis>
-+ Check if a value is NULL.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="data" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Returns <literal>1</literal> if NULL or <literal>0</literal> otherwise.</para>
-+ </description>
-+ </function>
-+ <function name="SET" language="en_US">
-+ <synopsis>
-+ SET assigns a value to a channel variable.
-+ </synopsis>
-+ <syntax argsep="=">
-+ <parameter name="varname" required="true" />
-+ <parameter name="value" />
-+ </syntax>
-+ <description>
-+ </description>
-+ </function>
-+ <function name="EXISTS" language="en_US">
-+ <synopsis>
-+ Test the existence of a value.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="data" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Returns <literal>1</literal> if exists, <literal>0</literal> otherwise.</para>
-+ </description>
-+ </function>
-+ <function name="IF" language="en_US">
-+ <synopsis>
-+ Check for an expresion.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="expresion" required="true" />
-+ <parameter name="retvalue" argsep=":" required="true">
-+ <argument name="true" />
-+ <argument name="false" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
-+ </description>
-+ </function>
-+ <function name="IFTIME" language="en_US">
-+ <synopsis>
-+ Temporal Conditional.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="timespec" required="true" />
-+ <parameter name="retvalue" required="true" argsep=":">
-+ <argument name="true" />
-+ <argument name="false" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the data following <literal>?</literal> if true, else the data following <literal>:</literal></para>
-+ </description>
-+ </function>
-+ <function name="IMPORT" language="en_US">
-+ <synopsis>
-+ Retrieve the value of a variable from another channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channel" required="true" />
-+ <parameter name="variable" required="true" />
-+ </syntax>
-+ <description>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<data>)",
- .read = isnull,
- };
-
- static struct ast_custom_function set_function = {
- .name = "SET",
-- .synopsis = "SET assigns a value to a channel variable",
-- .syntax = "SET(<varname>=[<value>])",
- .read = set,
- };
-
- static struct ast_custom_function exists_function = {
- .name = "EXISTS",
-- .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise",
-- .syntax = "EXISTS(<data>)",
- .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(<expr>?[<true>][:<false>])",
- .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(<timespec>?[<true>][:<false>])",
- .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
-+ <function name="URIENCODE" language="en_US">
-+ <synopsis>
-+ Encodes a string to URI-safe encoding according to RFC 2396.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="data" required="true">
-+ <para>Input string to be encoded.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the encoded string defined in <replaceable>data</replaceable>.</para>
-+ </description>
-+ </function>
-+ <function name="URIDECODE" language="en_US">
-+ <synopsis>
-+ Decodes a URI-encoded string according to RFC 2396.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="data" required="true">
-+ <para>Input string to be decoded.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the decoded URI-encoded <replaceable>data</replaceable> string.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- /*! \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(<data>)",
- .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(<data>)",
- .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
-+ <function name="ENUMQUERY" language="en_US">
-+ <synopsis>
-+ Initiate an ENUM query.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="number" required="true" />
-+ <parameter name="method-type">
-+ <para>If no <replaceable>method-type</replaceable> is given, the default will be
-+ <literal>sip</literal>.</para>
-+ </parameter>
-+ <parameter name="zone-suffix">
-+ <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
-+ <literal>e164.arpa</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This will do a ENUM lookup of the given phone number.</para>
-+ </description>
-+ </function>
-+ <function name="ENUMRESULT" language="en_US">
-+ <synopsis>
-+ Retrieve results from a ENUMQUERY.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="id" required="true">
-+ <para>The identifier returned by the ENUMQUERY function.</para>
-+ </parameter>
-+ <parameter name="resultnum" required="true">
-+ <para>The number of the result that you want to retrieve.</para>
-+ <para>Results start at <literal>1</literal>. If this argument is specified
-+ as <literal>getnum</literal>, then it will return the total number of results
-+ that are available.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This function will retrieve results from a previous use
-+ of the ENUMQUERY function.</para>
-+ </description>
-+ </function>
-+ <function name="ENUMLOOKUP" language="en_US">
-+ <synopsis>
-+ General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="number" required="true" />
-+ <parameter name="method-type">
-+ <para>If no <replaceable>method-type</replaceable> is given, the default will be
-+ <literal>sip</literal>.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="c">
-+ <para>Returns an integer count of the number of NAPTRs of a certain RR type.</para>
-+ <para>Combination of <literal>c</literal> and Method-type of <literal>ALL</literal> will
-+ return a count of all NAPTRs for the record.</para>
-+ </option>
-+ <option name="u">
-+ <para>Returns the full URI and does not strip off the URI-scheme.</para>
-+ </option>
-+ <option name="s">
-+ <para>Triggers ISN specific rewriting.</para>
-+ </option>
-+ <option name="i">
-+ <para>Looks for branches into an Infrastructure ENUM tree.</para>
-+ </option>
-+ <option name="d">
-+ <para>for a direct DNS lookup without any flipping of digits.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="record#">
-+ <para>If no <replaceable>record#</replaceable> is given,
-+ defaults to <literal>1</literal>.</para>
-+ </parameter>
-+ <parameter name="zone-suffix">
-+ <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
-+ <literal>e164.arpa</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>For more information see <filename>doc/asterisk.pdf</filename>.</para>
-+ </description>
-+ </function>
-+ <function name="TXTCIDNAME" language="en_US">
-+ <synopsis>
-+ TXTCIDNAME looks up a caller name via DNS.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="number" required="true" />
-+ <parameter name="zone-suffix">
-+ <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
-+ <literal>e164.arpa</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<number>[,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
-+ <function name = "AUDIOHOOK_INHERIT" language="en_US">
-+ <synopsis>
-+ Set whether an audiohook may be inherited to another channel
-+ </synopsis>
-+ <syntax>
-+ <parameter name="source" required="true">
-+ <para>The built-in sources in Asterisk are</para>
-+ <enumlist>
-+ <enum name="MixMonitor" />
-+ <enum name="Chanspy" />
-+ <enum name="Volume" />
-+ <enum name="Speex" />
-+ <enum name="JACK_HOOK" />
-+ </enumlist>
-+ <para>Note that the names are not case-sensitive</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+
-+ <para>Example scenario:</para>
-+ <para>exten => 2000,1,MixMonitor(blah.wav)</para>
-+ <para>exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)</para>
-+ <para>exten => 2000,n,Dial(SIP/2000)</para>
-+ <para>
-+ </para>
-+ <para>exten => 4000,1,Dial(SIP/4000)</para>
-+ <para>
-+ </para>
-+ <para>exten => 5000,1,MixMonitor(blah2.wav)</para>
-+ <para>exten => 5000,n,Dial(SIP/5000)</para>
-+ <para>
-+ </para>
-+ <para>In this basic dialplan scenario, let's consider the following sample calls</para>
-+ <para>Call 1: Caller dials 2000. The person who answers then executes an attended</para>
-+ <para> transfer to 4000.</para>
-+ <para>Result: Since extension 2000 set MixMonitor to be inheritable, after the</para>
-+ <para> transfer to 4000 has completed, the call will continue to be recorded
-+ to blah.wav</para>
-+ <para>
-+ </para>
-+ <para>Call 2: Caller dials 5000. The person who answers then executes an attended</para>
-+ <para> transfer to 4000.</para>
-+ <para>Result: Since extension 5000 did not set MixMonitor to be inheritable, the</para>
-+ <para> recording will stop once the call has been transferred to 4000.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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
-+ <function name="AST_CONFIG" language="en_US">
-+ <synopsis>
-+ Retrieve a variable from a configuration file.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="config_file" required="true" />
-+ <parameter name="category" required="true" />
-+ <parameter name="variable_name" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function reads a variable from an Asterisk configuration file.</para>
-+ </description>
-+ </function>
-+
-+***/
-+
- 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
-+ <function name="GROUP_COUNT" language="en_US">
-+ <synopsis>
-+ Counts the number of channels in the specified group.
-+ </synopsis>
-+ <syntax argsep="@">
-+ <parameter name="groupname">
-+ <para>Group name.</para>
-+ </parameter>
-+ <parameter name="category">
-+ <para>Category name</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Calculates the group count for the specified group, or uses the
-+ channel's current group if not specifed (and non-empty).</para>
-+ </description>
-+ </function>
-+ <function name="GROUP_MATCH_COUNT" language="en_US">
-+ <synopsis>
-+ Counts the number of channels in the groups matching the specified pattern.
-+ </synopsis>
-+ <syntax argsep="@">
-+ <parameter name="groupmatch" required="true">
-+ <para>A standard regular expression used to match a group name.</para>
-+ </parameter>
-+ <parameter name="category">
-+ <para>Category name.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Calculates the group count for all groups that match the specified pattern.
-+ Uses standard regular expression matching (see regex(7)).</para>
-+ </description>
-+ </function>
-+ <function name="GROUP" language="en_US">
-+ <synopsis>
-+ Gets or sets the channel group.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="category">
-+ <para>Category name.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para><replaceable>category</replaceable> can be employed for more fine grained group management. Each channel
-+ can only be member of exactly one group per <replaceable>category</replaceable>.</para>
-+ </description>
-+ </function>
-+ <function name="GROUP_LIST" language="en_US">
-+ <synopsis>
-+ Gets a list of the groups set on a channel.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Gets a list of the groups set on a channel.</para>
-+ </description>
-+ </function>
-+
-+ ***/
-+
- 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 <func_odbc__200508@the-tilghman.com>
- *
-@@ -27,8 +28,6 @@
- */
-
- /*** MODULEINFO
-- <depend>unixodbc</depend>
-- <depend>ltdl</depend>
- <depend>res_odbc</depend>
- ***/
-
-@@ -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
-+ <function name="ODBC_FETCH" language="en_US">
-+ <synopsis>
-+ Fetch a row from a multirow query.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="result-id" required="true" />
-+ </syntax>
-+ <description>
-+ <para>For queries which are marked as mode=multirow, the original
-+ query returns a <replaceable>result-id</replaceable> from which results
-+ may be fetched. This function implements the actual fetch of the results.</para>
-+ <para>This also sets <variable>ODBC_FETCH_STATUS</variable>.</para>
-+ <variablelist>
-+ <variable name="ODBC_FETCH_STATUS">
-+ <value name="SUCESS">
-+ If rows are available.
-+ </value>
-+ <value name="FAILURE">
-+ If no rows are available.
-+ </value>
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </function>
-+ <application name="ODBCFinish" language="en_US">
-+ <synopsis>
-+ Clear the resultset of a sucessful multirow query.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="result-id" required="true" />
-+ </syntax>
-+ <description>
-+ <para>For queries which are marked as mode=multirow, this will clear
-+ any remaining rows of the specified resultset.</para>
-+ </description>
-+ </application>
-+ <function name="SQL_ESC" language="en_US">
-+ <synopsis>
-+ Escapes single ticks for use in SQL statements.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Used in SQL templates to escape data which may contain single ticks
-+ <literal>'</literal> which are otherwise used to delimit data.</para>
-+ <para>Example: SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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(<string>)",
-- .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(<result-id>)",
-- .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(<result-id>)\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(<arg1>[...[,<argN>]])", (*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(<arg1>[...[,<argN>]])", (*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 <name> <args> [exec]\n"
-+ " Evaluates the SQL provided in the ODBC function <name>, 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 <name> <args> <value> [exec]\n"
-+ " Evaluates the SQL provided in the ODBC function <name>, 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
-+ <function name="SHELL" language="en_US">
-+ <synopsis>
-+ Executes a command as if you were at a shell.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="command" required="true">
-+ <para>This is the argument to the function, the command you want to pass to the shell.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the value from a system command</para>
-+ <para>Example: <literal>Set(foo=${SHELL(echo \bar\)})</literal></para>
-+ <note><para>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.</para></note>
-+ </description>
-+
-+ </function>
-+ ***/
- static struct ast_custom_function shell_function = {
- .name = "SHELL",
-- .synopsis = "Executes a command as if you were at a shell.",
-- .syntax = "SHELL(<command>)",
- .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
-+ <function name="VOLUME" language="en_US">
-+ <synopsis>
-+ Set the TX or RX volume of a channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="direction" required="true">
-+ <para>Must be <literal>TX</literal> or <literal>RX</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>The VOLUME function can be used to increase or decrease the <literal>tx</literal> or
-+ <literal>rx</literal> gain of any channel.</para>
-+ <para>For example:</para>
-+ <para>Set(VOLUME(TX)=3)</para>
-+ <para>Set(VOLUME(RX)=2)</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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 <dvossel@digium.com>
-+ * \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
-+ <function name="AES_ENCRYPT" language="en_US">
-+ <synopsis>
-+ Encrypt a string with AES given a 16 character key.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="key" required="true">
-+ <para>AES Key</para>
-+ </parameter>
-+ <parameter name="string" required="true">
-+ <para>Input string</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns an AES encrypted string encoded in base64.</para>
-+ </description>
-+ </function>
-+ <function name="AES_DECRYPT" language="en_US">
-+ <synopsis>
-+ Decrypt a string encoded in base64 with AES given a 16 character key.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="key" required="true">
-+ <para>AES Key</para>
-+ </parameter>
-+ <parameter name="string" required="true">
-+ <para>Input string.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Returns the plain text string.</para>
-+ </description>
-+ </function>
-+ ***/
-+
-+
-+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(<key>,<data>) - 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(<key>,<data>) - <key> 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(<keys>,<data>) - <data> 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
-+ <function name="DIALPLAN_EXISTS" language="en_US">
-+ <synopsis>
-+ Checks the existence of a dialplan target.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="context" required="true" />
-+ <parameter name="extension" />
-+ <parameter name="priority" />
-+ </syntax>
-+ <description>
-+ <para>This function returns <literal>1</literal> if the target exits. Otherwise, it returns <literal>0</literal>.</para>
-+ </description>
-+ </function>
-+
-+ ***/
-+
- 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
-+ <function name="DB" language="en_US">
-+ <synopsis>
-+ Read from or write to the Asterisk database.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">DBdel</ref>
-+ <ref type="function">DB_DELETE</ref>
-+ <ref type="application">DBdeltree</ref>
-+ <ref type="function">DB_EXISTS</ref>
-+ </see-also>
-+ </function>
-+ <function name="DB_EXISTS" language="en_US">
-+ <synopsis>
-+ Check to see if a key exists in the Asterisk database.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function will check to see if a key exists in the Asterisk
-+ database. If it exists, the function will return <literal>1</literal>. If not,
-+ it will return <literal>0</literal>. Checking for existence of a database key will
-+ also set the variable DB_RESULT to the key's value if it exists.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">DB</ref>
-+ </see-also>
-+ </function>
-+ <function name="DB_DELETE" language="en_US">
-+ <synopsis>
-+ Return a value from the database and delete it.
-+ </synopsis>
-+ <syntax argsep="/">
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function will retrieve a value from the Asterisk database
-+ and then remove that key from the database. <variable>DB_RESULT</variable>
-+ will be set to the key's value if it exists.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">DBdel</ref>
-+ <ref type="function">DB</ref>
-+ <ref type="application">DBdeltree</ref>
-+ </see-also>
-+ </function>
-+ ***/
-+
- 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(<family>/<key>)",
-- .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(<family>/<key>)",
-- .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(<family>/<key>)",
-- .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 <ctype.h>
-+
-+#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
-+ <function name="SPRINTF" language="en_US">
-+ <synopsis>
-+ Format a variable according to a format string.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="format" required="true" />
-+ <parameter name="arg1" required="true" />
-+ <parameter name="arg2" multiple="true" />
-+ <parameter name="argN" />
-+ </syntax>
-+ <description>
-+ <para>Parses the format string specified and returns a string matching
-+ that format. Supports most options found in <emphasis>sprintf(3)</emphasis>.
-+ Returns a shortened string if a format specifier is not recognized.</para>
-+ </description>
-+ <see-also>
-+ <ref type="manpage">sprintf(3)</ref>
-+ </see-also>
-+ </function>
-+ ***/
-+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
-+ <function name="VERSION" language="en_US">
-+ <synopsis>
-+ Return the Version info for this Asterisk.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="info">
-+ <para>The possible values are:</para>
-+ <enumlist>
-+ <enum name="ASTERISK_VERSION_NUM">
-+ <para>A string of digits is returned (right now fixed at 999999).</para>
-+ </enum>
-+ <enum name="BUILD_USER">
-+ <para>The string representing the user's name whose account
-+ was used to configure Asterisk, is returned.</para>
-+ </enum>
-+ <enum name="BUILD_HOSTNAME">
-+ <para>The string representing the name of the host on which Asterisk was configured, is returned.</para>
-+ </enum>
-+ <enum name="BUILD_MACHINE">
-+ <para>The string representing the type of machine on which Asterisk was configured, is returned.</para>
-+ </enum>
-+ <enum name="BUILD_OS">
-+ <para>The string representing the OS of the machine on which Asterisk was configured, is returned.</para>
-+ </enum>
-+ <enum name="BUILD_DATE">
-+ <para>The string representing the date on which Asterisk was configured, is returned.</para>
-+ </enum>
-+ <enum name="BUILD_KERNEL">
-+ <para>The string representing the kernel version of the machine on which Asterisk
-+ was configured, is returned.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>If there are no arguments, return the version of Asterisk in this format: SVN-branch-1.4-r44830M</para>
-+ <para>Example: Set(junky=${VERSION()};</para>
-+ <para>Sets junky to the string <literal>SVN-branch-1.6-r74830M</literal>, or possibly, <literal>SVN-trunk-r45126M</literal>.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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
-+ <function name="TIMEOUT" language="en_US">
-+ <synopsis>
-+ Gets or sets timeouts on the channel. Timeout values are in seconds.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="timeouttype" required="true">
-+ <para>The timeout that will be manipulated. The possible timeout types
-+ are: <literal>absolute</literal>, <literal>digit</literal> or
-+ <literal>response</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>The timeouts that can be manipulated are:</para>
-+ <para><literal>absolute</literal>: The absolute maximum amount of time permitted for a call.
-+ Setting of 0 disables the timeout.</para>
-+ <para><literal>digit</literal>: 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 <literal>i</literal>
-+ extension, or if it doesn't exist the call would be
-+ terminated). The default timeout is 5 seconds.</para>
-+ <para><literal>response</literal>: 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
-+ <literal>t</literal> extension if it exists, and if not the call would be
-+ terminated. The default timeout is 10 seconds.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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
-+ <function name="LOCK" language="en_US">
-+ <synopsis>
-+ Attempt to obtain a named mutex.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="lockname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>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 <literal>1</literal> if the lock was obtained or <literal>0</literal> on error.</para>
-+ <note><para>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.</para></note>
-+ </description>
-+ </function>
-+ <function name="TRYLOCK" language="en_US">
-+ <synopsis>
-+ Attempt to obtain a named mutex.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="lockname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Attempts to grab a named lock exclusively, and prevents other channels
-+ from obtaining the same lock. Returns <literal>1</literal> if the lock was
-+ available or <literal>0</literal> otherwise.</para>
-+ </description>
-+ </function>
-+ <function name="UNLOCK" language="en_US">
-+ <synopsis>
-+ Unlocks a named mutex.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="lockname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Unlocks a previously locked mutex. Returns <literal>1</literal> if the channel
-+ had a lock or <literal>0</literal> otherwise.</para>
-+ <note><para>It is generally unnecessary to unlock in a hangup routine, as any locks
-+ held are automatically freed when the channel is destroyed.</para></note>
-+ </description>
-+ </function>
-+ ***/
-+
-+
-+
- 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(<lockname>)",
- .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(<lockname>)",
- .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(<lockname>)",
- .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
-+ <function name="MATH" language="en_US">
-+ <synopsis>
-+ Performs Mathematical Functions.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="expression" required="true">
-+ <para>Is of the form:
-+ <replaceable>number1</replaceable><replaceable>op</replaceable><replaceable>number2</replaceable>
-+ where the possible values for <replaceable>op</replaceable>
-+ are:</para>
-+ <para>+,-,/,*,%,&lt;&lt;,&gt;&gt;,^,AND,OR,XOR,&lt;,%gt;,&gt;=,&lt;=,== (and behave as their C equivalents)</para>
-+ </parameter>
-+ <parameter name="type">
-+ <para>Wanted type of result:</para>
-+ <para>f, float - float(default)</para>
-+ <para>i, int - integer</para>
-+ <para>h, hex - hex</para>
-+ <para>c, char - char</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Performs mathematical functions based on two parameters and an operator. The returned
-+ value type is <replaceable>type</replaceable></para>
-+ <para>Example: Set(i=${MATH(123%16,int)}) - sets var i=11</para>
-+ </description>
-+ </function>
-+ ***/
-+
- enum TypeOfFunctions {
- ADDFUNCTION,
- DIVIDEFUNCTION,
-@@ -306,17 +335,6 @@
-
- static struct ast_custom_function math_function = {
- .name = "MATH",
-- .synopsis = "Performs Mathematical Functions",
-- .syntax = "MATH(<number1><op><number2>[,<type_of_result>])",
-- .desc = "Perform calculation on number1 to number2. Valid ops are: \n"
-- " +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,>,>=,<=,==\n"
-- "and behave as their C equivalents.\n"
-- "<type_of_result> - 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
-+ <function name="SORT" language="en_US">
-+ <synopsis>
-+ Sorts a list of key/vals into a list of keys, based upon the vals.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="keyval" required="true" argsep=":">
-+ <argument name="key1" required="true" />
-+ <argument name="val1" required="true" />
-+ </parameter>
-+ <parameter name="keyvaln" multiple="true" argsep=":">
-+ <argument name="key2" required="true" />
-+ <argument name="val2" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ </function>
-+ <function name="CUT" language="en_US">
-+ <synopsis>
-+ Slices and dices strings, based upon a named delimiter.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true">
-+ <para>Variable you want cut</para>
-+ </parameter>
-+ <parameter name="char-delim" required="true">
-+ <para>Delimiter, defaults to <literal>-</literal></para>
-+ </parameter>
-+ <parameter name="range-spec" required="true">
-+ <para>Number of the field you want (1-based offset), may also be specified as a range (with <literal>-</literal>)
-+ or group of ranges and fields (with <literal>&amp;</literal>)</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Cut out information from a string (<replaceable>varname</replaceable>), based upon a named delimiter.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- /* 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(<varname>,<char-delim>,<range-spec>)",
-- .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 <rmudgett@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*!
-+ * \file
-+ * \brief Redirecting data dialplan function
-+ * \ingroup functions
-+ *
-+ * \author Richard Mudgett <rmudgett@digium.com>
-+ *
-+ * See Also:
-+ * \arg \ref AstCREDITS
-+ */
-+
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+/* ------------------------------------------------------------------- */
-+
-+
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/types.h>
-+
-+#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
-+ <function name="GLOBAL" language="en_US">
-+ <synopsis>
-+ Gets or sets the global variable specified.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true">
-+ <para>Global variable name</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Set or get the value of a global variable specified in <replaceable>varname</replaceable></para>
-+ </description>
-+ </function>
-+ <function name="SHARED" language="en_US">
-+ <synopsis>
-+ Gets or sets the shared variable specified.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="varname" required="true">
-+ <para>Variable name</para>
-+ </parameter>
-+ <parameter name="channel">
-+ <para>If not specified will default to current channel. It is the complete
-+ channel name: <literal>SIP/12-abcd1234</literal> or the prefix only <literal>SIP/12</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Implements a shared variable area, in which you may share variables between
-+ channels.</para>
-+ <para>The variables used in this space are separate from the general namespace of
-+ the channel and thus <variable>SHARED(foo)</variable> and <variable>foo</variable>
-+ represent two completely different variables, despite sharing the same name.</para>
-+ <para>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).</para>
-+ </description>
-+ </function>
-+
-+ ***/
-+
- 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(<varname>)",
- .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(<varname>[,<channel>])",
-- .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
-+ <function name="EXTENSION_STATE" language="en_US">
-+ <synopsis>
-+ Get an extension's state.
-+ </synopsis>
-+ <syntax argsep="@">
-+ <parameter name="extension" required="true" />
-+ <parameter name="context">
-+ <para>If it is not specified defaults to <literal>default</literal>.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>The EXTENSION_STATE function can be used to retrieve the state from any
-+ hinted extension. For example:</para>
-+ <para>NoOp(1234@default has state ${EXTENSION_STATE(1234)})</para>
-+ <para>NoOp(4567@home has state ${EXTENSION_STATE(4567@home)})</para>
-+ <para>The possible values returned by this function are:</para>
-+ <para>UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING |
-+ RINGINUSE | HOLDINUSE | ONHOLD</para>
-+ </description>
-+ </function>
-+ ***/
-+
- 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
-+ <function name="REALTIME" language="en_US">
-+ <synopsis>
-+ RealTime Read/Write Functions.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="fieldmatch" required="true" />
-+ <parameter name="value" />
-+ <parameter name="delim1|field">
-+ <para>Use <replaceable>delim1</replaceable> with <replaceable>delim2</replaceable> on
-+ read and <replaceable>field</replaceable> without <replaceable>delim2</replaceable> on
-+ write</para>
-+ <para>If we are reading and <replaceable>delim1</replaceable> is not specified, defaults
-+ to <literal>,</literal></para>
-+ </parameter>
-+ <parameter name="delim2">
-+ <para>Parameter only used when reading, if not specified defaults to <literal>=</literal></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>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 <replaceable>delim1</replaceable>, 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.</para>
-+ </description>
-+ </function>
-+ <function name="REALTIME_STORE" language="en_US">
-+ <synopsis>
-+ RealTime Store Function.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="field1" required="true" />
-+ <parameter name="fieldN" required="true" multiple="true" />
-+ <parameter name="field30" required="true" />
-+ </syntax>
-+ <description>
-+ <para>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.</para>
-+ </description>
-+ </function>
-+ <function name="REALTIME_DESTROY" language="en_US">
-+ <synopsis>
-+ RealTime Destroy Function.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="fieldmatch" required="true" />
-+ <parameter name="value" />
-+ <parameter name="delim1" />
-+ <parameter name="delim2" />
-+ </syntax>
-+ <description>
-+ <para>This function acts in the same way as REALTIME(....) does, except that
-+ it destroys the matched record in the RT engine.</para>
-+ </description>
-+ </function>
-+ <function name="REALTIME_FIELD" language="en_US">
-+ <synopsis>
-+ RealTime query function.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="fieldmatch" required="true" />
-+ <parameter name="value" required="true" />
-+ <parameter name="fieldname" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function retrieves a single item, <replaceable>fieldname</replaceable>
-+ from the RT engine, where <replaceable>fieldmatch</replaceable> contains the value
-+ <replaceable>value</replaceable>. When written to, the REALTIME_FIELD() function
-+ performs identically to the REALTIME() function.</para>
-+ </description>
-+ </function>
-+ <function name="REALTIME_HASH" language="en_US">
-+ <synopsis>
-+ RealTime query function.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="fieldmatch" required="true" />
-+ <parameter name="value" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function retrieves a single record from the RT engine, where
-+ <replaceable>fieldmatch</replaceable> contains the value
-+ <replaceable>value</replaceable> 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.</para>
-+ </description>
-+ </function>
-+ ***/
-+
-+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(<option>)",
-+ .desc =
-+" cookie - Send cookie with request\n"
-+" conntimeout - Number of seconds to wait for connection\n"
-+" dnstimeout - Number of seconds to wait for DNS response\n"
-+" ftptext - For FTP, force a text transfer (boolean)\n"
-+" ftptimeout - For FTP, the server response timeout\n"
-+" header - Retrieve header information (boolean)\n"
-+" httptimeout - Number of seconds to wait for HTTP response\n"
-+" maxredirs - Maximum number of redirects to follow\n"
-+" proxy - Hostname or IP to use as a proxy\n"
-+" proxytype - http, socks4, or socks5\n"
-+" proxyport - port number of the proxy\n"
-+" proxyuserpwd - A <user>:<pass> to use for authentication\n"
-+" referer - Referer URL to use for the request\n"
-+" useragent - UserAgent string to use\n"
-+" userpwd - A <user>:<pass> to use for authentication\n"
-+" hashcompat - Result data will be compatible for use with HASH()\n"
-+"",
-+ .read = acf_curlopt_read,
-+ .write = acf_curlopt_write,
-+};
-+
- static int unload_module(void)
- {
- int res;
-
- res = ast_custom_function_unregister(&acf_curl);
-+ res |= ast_custom_function_unregister(&acf_curlopt);
-
- return res;
- }
-@@ -188,6 +557,7 @@
- }
-
- res = ast_custom_function_register(&acf_curl);
-+ res |= ast_custom_function_register(&acf_curlopt);
-
- return res;
- }
-Index: funcs/func_blacklist.c
-===================================================================
---- a/funcs/func_blacklist.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/funcs/func_blacklist.c (.../team/group/issue14292) (revision 178988)
-@@ -35,6 +35,23 @@
- #include "asterisk/channel.h"
- #include "asterisk/astdb.h"
-
-+/*** DOCUMENTATION
-+ <function name="BLACKLIST" language="en_US">
-+ <synopsis>
-+ Check if the callerid is on the blacklist.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Uses astdb to check if the Caller*ID is in family <literal>blacklist</literal>.
-+ Returns <literal>1</literal> or <literal>0</literal>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">DB</ref>
-+ </see-also>
-+ </function>
-+
-+***/
-+
- static int blacklist_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
- {
- char blacklist[1];
-@@ -55,9 +72,6 @@
-
- static struct ast_custom_function blacklist_function = {
- .name = "BLACKLIST",
-- .synopsis = "Check if the callerid is on the blacklist",
-- .desc = "Uses astdb to check if the Caller*ID is in family 'blacklist'. Returns 1 or 0.\n",
-- .syntax = "BLACKLIST()",
- .read = blacklist_read,
- };
-
-Index: funcs/func_cdr.c
-===================================================================
---- a/funcs/func_cdr.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/funcs/func_cdr.c (.../team/group/issue14292) (revision 178988)
-@@ -36,6 +36,133 @@
- #include "asterisk/app.h"
- #include "asterisk/cdr.h"
-
-+/*** DOCUMENTATION
-+ <function name="CDR" language="en_US">
-+ <synopsis>
-+ Gets or sets a CDR variable.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="name" required="true">
-+ <para>CDR field name:</para>
-+ <enumlist>
-+ <enum name="clid">
-+ <para>Caller ID.</para>
-+ </enum>
-+ <enum name="lastdata">
-+ <para>Last application arguments.</para>
-+ </enum>
-+ <enum name="disposition">
-+ <para>ANSWERED, NO ANSWER, BUSY.</para>
-+ </enum>
-+ <enum name="src">
-+ <para>Source.</para>
-+ </enum>
-+ <enum name="start">
-+ <para>Time the call started.</para>
-+ </enum>
-+ <enum name="amaflags">
-+ <para>DOCUMENTATION, BILL, IGNORE, etc.</para>
-+ </enum>
-+ <enum name="dst">
-+ <para>Destination.</para>
-+ </enum>
-+ <enum name="answer">
-+ <para>Time the call was answered.</para>
-+ </enum>
-+ <enum name="accountcode">
-+ <para>The channel's account code.</para>
-+ </enum>
-+ <enum name="dcontext">
-+ <para>Destination context.</para>
-+ </enum>
-+ <enum name="end">
-+ <para>Time the call ended.</para>
-+ </enum>
-+ <enum name="uniqueid">
-+ <para>The channel's unique id.</para>
-+ </enum>
-+ <enum name="dstchannel">
-+ <para>Destination channel.</para>
-+ </enum>
-+ <enum name="duration">
-+ <para>Duration of the call.</para>
-+ </enum>
-+ <enum name="userfield">
-+ <para>The channel's user specified field.</para>
-+ </enum>
-+ <enum name="lastapp">
-+ <para>Last application.</para>
-+ </enum>
-+ <enum name="billsec">
-+ <para>Duration of the call once it was answered.</para>
-+ </enum>
-+ <enum name="channel">
-+ <para>Channel name.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ <parameter name="options" required="false">
-+ <optionlist>
-+ <option name="l">
-+ <para>Uses the most recent CDR on a channel with multiple records</para>
-+ </option>
-+ <option name="r">
-+ <para>Searches the entire stack of CDRs on the channel.</para>
-+ </option>
-+ <option name="s">
-+ <para>Skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.
-+ (on setting/writing CDR vars only)</para>
-+ </option>
-+ <option name="u">
-+ <para>Retrieves the raw, unprocessed value.</para>
-+ <para>For example, 'start', 'answer', and 'end' will be retrieved as epoch
-+ values, when the <literal>u</literal> option is passed, but formatted as YYYY-MM-DD HH:MM:SS
-+ otherwise. Similarly, disposition and amaflags will return their raw
-+ integral values.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>All of the CDR field names are read-only, except for <literal>accountcode</literal>,
-+ <literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
-+ a name not on the above list, and create your own variable, whose value can be changed
-+ with this function, and this variable will be stored on the cdr.</para>
-+ <note><para>For setting CDR values, the <literal>l</literal> flag does not apply to
-+ setting the <literal>accountcode</literal>, <literal>userfield</literal>, or
-+ <literal>amaflags</literal>.</para></note>
-+ <para>Raw values for <literal>disposition</literal>:</para>
-+ <enumlist>
-+ <enum name="1">
-+ <para>NO ANSWER</para>
-+ </enum>
-+ <enum name="2">
-+ <para>BUSY</para>
-+ </enum>
-+ <enum name="3">
-+ <para>FAILED</para>
-+ </enum>
-+ <enum name="4">
-+ <para>ANSWERED</para>
-+ </enum>
-+ </enumlist>
-+ <para>Raw values for <literal>amaflags</literal>:</para>
-+ <enumlist>
-+ <enum name="1">
-+ <para>OMIT</para>
-+ </enum>
-+ <enum name="2">
-+ <para>BILLING</para>
-+ </enum>
-+ <enum name="3">
-+ <para>DOCUMENTATION</para>
-+ </enum>
-+ </enumlist>
-+ <para>Example: exten => 1,1,Set(CDR(userfield)=test)</para>
-+ </description>
-+ </function>
-+ ***/
-+
- enum {
- OPT_RECURSIVE = (1 << 0),
- OPT_UNPARSED = (1 << 1),
-@@ -128,44 +255,8 @@
-
- static struct ast_custom_function cdr_function = {
- .name = "CDR",
-- .synopsis = "Gets or sets a CDR variable",
-- .syntax = "CDR(<name>[,options])",
- .read = cdr_read,
- .write = cdr_write,
-- .desc =
--"Options:\n"
--" 'l' uses the most recent CDR on a channel with multiple records\n"
--" 'r' searches the entire stack of CDRs on the channel\n"
--" 's' skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.\n"
--" (on setting/writing CDR vars only)\n"
--" 'u' retrieves the raw, unprocessed value\n"
--" For example, 'start', 'answer', and 'end' will be retrieved as epoch\n"
--" values, when the 'u' option is passed, but formatted as YYYY-MM-DD HH:MM:SS\n"
--" otherwise. Similarly, disposition and amaflags will return their raw\n"
--" integral values.\n"
--" Here is a list of all the available cdr field names:\n"
--" clid lastdata disposition\n"
--" src start amaflags\n"
--" dst answer accountcode\n"
--" dcontext end uniqueid\n"
--" dstchannel duration userfield\n"
--" lastapp billsec channel\n"
--" All of the above variables are read-only, except for accountcode,\n"
--" userfield, and amaflags. You may, however, supply\n"
--" a name not on the above list, and create your own\n"
--" variable, whose value can be changed with this function,\n"
--" and this variable will be stored on the cdr.\n"
--" For setting CDR values, the 'l' flag does not apply to\n"
--" setting the accountcode, userfield, or amaflags.\n"
--" raw values for disposition:\n"
--" 1 = NO ANSWER\n"
--" 2 = BUSY\n"
--" 3 = FAILED\n"
--" 4 = ANSWERED\n"
--" raw values for amaflags:\n"
--" 1 = OMIT\n"
--" 2 = BILLING\n"
--" 3 = DOCUMENTATION\n",
- };
-
- static int unload_module(void)
-Index: funcs/func_channel.c
-===================================================================
---- a/funcs/func_channel.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/funcs/func_channel.c (.../team/group/issue14292) (revision 178988)
-@@ -38,6 +38,168 @@
- #include "asterisk/indications.h"
- #include "asterisk/stringfields.h"
-
-+/*** DOCUMENTATION
-+ <function name="CHANNELS" language="en_US">
-+ <synopsis>
-+ Gets the list of channels, optionally filtering by a regular expression.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="regular_expression" />
-+ </syntax>
-+ <description>
-+ <para>Gets the list of channels, optionally filtering by a <replaceable>regular_expression</replaceable>. If
-+ no argument is provided, all known channels are returned. The
-+ <replaceable>regular_expression</replaceable> must correspond to
-+ the POSIX.2 specification, as shown in <emphasis>regex(7)</emphasis>. The list returned
-+ will be space-delimited.</para>
-+ </description>
-+ </function>
-+ <function name="CHANNEL" language="en_US">
-+ <synopsis>
-+ Gets/sets various pieces of information about the channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="item" required="true">
-+ <para>Standard items (provided by all channel technologies) are:</para>
-+ <enumlist>
-+ <enum name="audioreadformat">
-+ <para>R/O format currently being read.</para>
-+ </enum>
-+ <enum name="audionativeformat">
-+ <para>R/O format used natively for audio.</para>
-+ </enum>
-+ <enum name="audiowriteformat">
-+ <para>R/O format currently being written.</para>
-+ </enum>
-+ <enum name="callgroup">
-+ <para>R/W call groups for call pickup.</para>
-+ </enum>
-+ <enum name="channeltype">
-+ <para>R/O technology used for channel.</para>
-+ </enum>
-+ <enum name="language">
-+ <para>R/W language for sounds played.</para>
-+ </enum>
-+ <enum name="musicclass">
-+ <para>R/W class (from musiconhold.conf) for hold music.</para>
-+ </enum>
-+ <enum name="parkinglot">
-+ <para>R/W parkinglot for parking.</para>
-+ </enum>
-+ <enum name="rxgain">
-+ <para>R/W set rxgain level on channel drivers that support it.</para>
-+ </enum>
-+ <enum name="state">
-+ <para>R/O state for channel</para>
-+ </enum>
-+ <enum name="tonezone">
-+ <para>R/W zone for indications played</para>
-+ </enum>
-+ <enum name="txgain">
-+ <para>R/W set txgain level on channel drivers that support it.</para>
-+ </enum>
-+ <enum name="videonativeformat">
-+ <para>R/O format used natively for video</para>
-+ </enum>
-+ <enum name="trace">
-+ <para>R/W whether or not context tracing is enabled, only available
-+ <emphasis>if CHANNEL_TRACE is defined</emphasis>.</para>
-+ </enum>
-+ </enumlist>
-+ <para><emphasis>chan_sip</emphasis> provides the following additional options:</para>
-+ <enumlist>
-+ <enum name="peerip">
-+ <para>R/O Get the IP address of the peer.</para>
-+ </enum>
-+ <enum name="recvip">
-+ <para>R/O Get the source IP address of the peer.</para>
-+ </enum>
-+ <enum name="from">
-+ <para>R/O Get the URI from the From: header.</para>
-+ </enum>
-+ <enum name="uri">
-+ <para>R/O Get the URI from the Contact: header.</para>
-+ </enum>
-+ <enum name="useragent">
-+ <para>R/O Get the useragent.</para>
-+ </enum>
-+ <enum name="peername">
-+ <para>R/O Get the name of the peer.</para>
-+ </enum>
-+ <enum name="t38passthrough">
-+ <para>R/O <literal>1</literal> if T38 is offered or enabled in this channel,
-+ otherwise <literal>0</literal></para>
-+ </enum>
-+ <enum name="rtpqos">
-+ <para>R/O Get QOS information about the RTP stream</para>
-+ <para> This option takes two additional arguments:</para>
-+ <para> Argument 1:</para>
-+ <para> <literal>audio</literal> Get data about the audio stream</para>
-+ <para> <literal>video</literal> Get data about the video stream</para>
-+ <para> <literal>text</literal> Get data about the text stream</para>
-+ <para> Argument 2:</para>
-+ <para> <literal>local_ssrc</literal> Local SSRC (stream ID)</para>
-+ <para> <literal>local_lostpackets</literal> Local lost packets</para>
-+ <para> <literal>local_jitter</literal> Local calculated jitter</para>
-+ <para> <literal>local_maxjitter</literal> Local calculated jitter (maximum)</para>
-+ <para> <literal>local_minjitter</literal> Local calculated jitter (minimum)</para>
-+ <para> <literal>local_normdevjitter</literal>Local calculated jitter (normal deviation)</para>
-+ <para> <literal>local_stdevjitter</literal> Local calculated jitter (standard deviation)</para>
-+ <para> <literal>local_count</literal> Number of received packets</para>
-+ <para> <literal>remote_ssrc</literal> Remote SSRC (stream ID)</para>
-+ <para> <literal>remote_lostpackets</literal>Remote lost packets</para>
-+ <para> <literal>remote_jitter</literal> Remote reported jitter</para>
-+ <para> <literal>remote_maxjitter</literal> Remote calculated jitter (maximum)</para>
-+ <para> <literal>remote_minjitter</literal> Remote calculated jitter (minimum)</para>
-+ <para> <literal>remote_normdevjitter</literal>Remote calculated jitter (normal deviation)</para>
-+ <para> <literal>remote_stdevjitter</literal>Remote calculated jitter (standard deviation)</para>
-+ <para> <literal>remote_count</literal> Number of transmitted packets</para>
-+ <para> <literal>remote_ssrc</literal> Remote SSRC (stream ID)</para>
-+ <para> <literal>remote_lostpackets</literal>Remote lost packets</para>
-+ <para> <literal>remote_jitter</literal> Remote reported jitter</para>
-+ <para> <literal>remote_maxjitter</literal> Remote calculated jitter (maximum)</para>
-+ <para> <literal>remote_minjitter</literal> Remote calculated jitter (minimum)</para>
-+ <para> <literal>remote_normdevjitter</literal>Remote calculated jitter (normal deviation)</para>
-+ <para> <literal>remote_stdevjitter</literal>Remote calculated jitter (standard deviation)</para>
-+ <para> <literal>remote_count</literal> Number of transmitted packets</para>
-+ <para> <literal>rtt</literal> Round trip time</para>
-+ <para> <literal>maxrtt</literal> Round trip time (maximum)</para>
-+ <para> <literal>minrtt</literal> Round trip time (minimum)</para>
-+ <para> <literal>normdevrtt</literal> Round trip time (normal deviation)</para>
-+ <para> <literal>stdevrtt</literal> Round trip time (standard deviation)</para>
-+ <para> <literal>all</literal> All statistics (in a form suited to logging,
-+ but not for parsing)</para>
-+ </enum>
-+ <enum name="rtpdest">
-+ <para>R/O Get remote RTP destination information.</para>
-+ <para> This option takes one additional argument:</para>
-+ <para> Argument 1:</para>
-+ <para> <literal>audio</literal> Get audio destination</para>
-+ <para> <literal>video</literal> Get video destination</para>
-+ </enum>
-+ </enumlist>
-+ <para><emphasis>chan_iax2</emphasis> provides the following additional options:</para>
-+ <enumlist>
-+ <enum name="osptoken">
-+ <para>R/W Get or set the OSP token information for a call.</para>
-+ </enum>
-+ <enum name="peerip">
-+ <para>R/O Get the peer's ip address.</para>
-+ </enum>
-+ <enum name="peername">
-+ <para>R/O Get the peer's username.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Gets/sets various pieces of information about the channel, additional <replaceable>item</replaceable> may
-+ be available from the channel driver; see its documentation for details. Any <replaceable>item</replaceable>
-+ requested that is not available on the current channel will return an empty string.</para>
-+ </description>
-+ </function>
-+ ***/
-+
- #define locked_copy_string(chan, dest, source, len) \
- do { \
- ast_channel_lock(chan); \
-@@ -134,12 +296,19 @@
- }
- #endif
- else if (!strcasecmp(data, "tonezone")) {
-- struct tone_zone *new_zone;
-+ struct ast_tone_zone *new_zone;
- if (!(new_zone = ast_get_indication_zone(value))) {
- ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
- ret = -1;
-- } else
-- chan->zone = new_zone;
-+ } else {
-+ ast_channel_lock(chan);
-+ if (chan->zone) {
-+ chan->zone = ast_tone_zone_unref(chan->zone);
-+ }
-+ chan->zone = ast_tone_zone_ref(new_zone);
-+ ast_channel_unlock(chan);
-+ new_zone = ast_tone_zone_unref(new_zone);
-+ }
- } else if (!strcasecmp(data, "callgroup"))
- chan->callgroup = ast_get_group(value);
- else if (!strcasecmp(data, "txgain")) {
-@@ -168,80 +337,6 @@
-
- static struct ast_custom_function channel_function = {
- .name = "CHANNEL",
-- .synopsis = "Gets/sets various pieces of information about the channel.",
-- .syntax = "CHANNEL(item)",
-- .desc = "Gets/set various pieces of information about the channel.\n"
-- "Standard items (provided by all channel technologies) are:\n"
-- "R/O audioreadformat format currently being read\n"
-- "R/O audionativeformat format used natively for audio\n"
-- "R/O audiowriteformat format currently being written\n"
-- "R/W callgroup call groups for call pickup\n"
-- "R/O channeltype technology used for channel\n"
-- "R/W language language for sounds played\n"
-- "R/W musicclass class (from musiconhold.conf) for hold music\n"
-- "R/W parkinglot parkinglot for parking\n"
-- "R/W rxgain set rxgain level on channel drivers that support it\n"
-- "R/O state state for channel\n"
-- "R/W tonezone zone for indications played\n"
-- "R/W txgain set txgain level on channel drivers that support it\n"
-- "R/O videonativeformat format used natively for video\n"
--#ifdef CHANNEL_TRACE
-- "R/W trace whether or not context tracing is enabled\n"
--#endif
-- "\n"
-- "chan_sip provides the following additional options:\n"
-- "R/O peerip Get the IP address of the peer\n"
-- "R/O recvip Get the source IP address of the peer\n"
-- "R/O from Get the URI from the From: header\n"
-- "R/O uri Get the URI from the Contact: header\n"
-- "R/O useragent Get the useragent\n"
-- "R/O peername Get the name of the peer\n"
-- "R/O t38passthrough 1 if T38 is offered or enabled in this channel, otherwise 0\n"
-- "R/O rtpqos Get QOS information about the RTP stream\n"
-- " This option takes two additional arguments:\n"
-- " Argument 1:\n"
-- " audio Get data about the audio stream\n"
-- " video Get data about the video stream\n"
-- " text Get data about the text stream\n"
-- " Argument 2:\n"
-- " local_ssrc Local SSRC (stream ID)\n"
-- " local_lostpackets Local lost packets\n"
-- " local_jitter Local calculated jitter\n"
-- " local_maxjitter Local calculated jitter (maximum)\n"
-- " local_minjitter Local calculated jitter (minimum)\n"
-- " local_normdevjitter Local calculated jitter (normal deviation)\n"
-- " local_stdevjitter Local calculated jitter (standard deviation)\n"
-- " local_count Number of received packets\n"
-- " remote_ssrc Remote SSRC (stream ID)\n"
-- " remote_lostpackets Remote lost packets\n"
-- " remote_jitter Remote reported jitter\n"
-- " remote_maxjitter Remote calculated jitter (maximum)\n"
-- " remote_minjitter Remote calculated jitter (minimum)\n"
-- " remote_normdevjitter Remote calculated jitter (normal deviation)\n"
-- " remote_stdevjitter Remote calculated jitter (standard deviation)\n"
-- " remote_count Number of transmitted packets\n"
-- " rtt Round trip time\n"
-- " maxrtt Round trip time (maximum)\n"
-- " minrtt Round trip time (minimum)\n"
-- " normdevrtt Round trip time (normal deviation)\n"
-- " stdevrtt Round trip time (standard deviation)\n"
-- " all All statistics (in a form suited to logging, but not for parsing)\n"
-- "R/O rtpdest Get remote RTP destination information\n"
-- " This option takes one additional argument:\n"
-- " Argument 1:\n"
-- " audio Get audio destination\n"
-- " video Get video destination\n"
-- "\n"
-- "chan_iax2 provides the following additional options:\n"
-- "R/W osptoken Get or set the OSP token information for a call\n"
-- "R/O peerip Get the peer's ip address\n"
-- "R/O peername Get the peer's username\n"
-- "\n"
-- "Additional items may be available from the channel driver providing\n"
-- "the channel; see its documentation for details.\n"
-- "\n"
-- "Any item requested that is not available on the current channel will\n"
-- "return an empty string.\n",
- .read = func_channel_read,
- .write = func_channel_write,
- };
-@@ -288,13 +383,6 @@
-
- static struct ast_custom_function channels_function = {
- .name = "CHANNELS",
-- .synopsis = "Gets the list of channels, optionally filtering by a regular expression.",
-- .syntax = "CHANNEL([regular expression])",
-- .desc =
--"Gets the list of channels, optionally filtering by a regular expression. If\n"
--"no argument is provided, all known channels are returned. The regular\n"
--"expression must correspond to the POSIX.2 specification, as shown in\n"
--"regex(7). The list returned will be space-delimited.\n",
- .read = func_channels_read,
- };
-
-Index: funcs/func_connectedline.c
-===================================================================
---- a/funcs/func_connectedline.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/funcs/func_connectedline.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,216 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2007, Gareth Palmer
-+ *
-+ * Gareth Palmer <gareth@acsdata.co.nz>
-+ *
-+ * 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 Connected Line dialplan function
-+ *
-+ * \ingroup functions
-+ */
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/types.h>
-+
-+#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"
-+
-+static int connectedline_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("all", data, 3)) {
-+ snprintf(buf, len, "\"%s\" <%s>",
-+ S_OR(chan->connected.id.name, ""),
-+ S_OR(chan->connected.id.number, ""));
-+ } else if (!strncasecmp("name", data, 4)) {
-+ if (chan->connected.id.name) {
-+ ast_copy_string(buf, chan->connected.id.name, len);
-+ }
-+ } else if (!strncasecmp("num", data, 3)) {
-+ if (chan->connected.id.number) {
-+ ast_copy_string(buf, chan->connected.id.number, len);
-+ }
-+ } else if (!strncasecmp("ton", data, 3)) {
-+ snprintf(buf, len, "%d", chan->connected.id.number_type);
-+ } else if (!strncasecmp("pres", data, 4)) {
-+ ast_copy_string(buf, ast_named_caller_presentation(chan->connected.id.number_presentation), len);
-+ } else if (!strncasecmp("source", data, 6)) {
-+ ast_copy_string(buf, ast_connected_line_source_name(chan->connected.source), len);
-+ } else {
-+ ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
-+ }
-+
-+ ast_channel_unlock(chan);
-+
-+ return 0;
-+}
-+
-+static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data,
-+ const char *value)
-+{
-+ struct ast_party_connected_line connected;
-+ char *val;
-+ char *option;
-+ void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected);
-+
-+ 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_connected_line;
-+ break;
-+
-+ default:
-+ ast_log(LOG_ERROR, "Unknown connectedline option '%s'.\n", option);
-+ return 0;
-+ } /* end switch */
-+ }
-+ else {
-+ set_it = ast_connected_line_update;
-+ }
-+
-+ ast_channel_lock(chan);
-+ ast_party_connected_line_set_init(&connected, &chan->connected);
-+ ast_channel_unlock(chan);
-+
-+ value = ast_skip_blanks(value);
-+
-+ if (!strncasecmp("all", data, 3)) {
-+ char name[256];
-+ char num[256];
-+
-+ ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
-+ connected.id.name = name;
-+ connected.id.number = num;
-+ set_it(chan, &connected);
-+ } else if (!strncasecmp("name", data, 4)) {
-+ connected.id.name = ast_strdupa(value);
-+ ast_trim_blanks(connected.id.name);
-+ set_it(chan, &connected);
-+ } else if (!strncasecmp("num", data, 3)) {
-+ connected.id.number = ast_strdupa(value);
-+ ast_trim_blanks(connected.id.number);
-+ set_it(chan, &connected);
-+ } else if (!strncasecmp("ton", data, 3)) {
-+ val = ast_strdupa(value);
-+ ast_trim_blanks(val);
-+
-+ if (('0' <= val[0]) && (val[0] <= '9')) {
-+ connected.id.number_type = atoi(val);
-+ set_it(chan, &connected);
-+ } else {
-+ ast_log(LOG_ERROR, "Unknown connectedline type of number '%s', value unchanged\n", val);
-+ }
-+ } 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 connectedline number presentation '%s', value unchanged\n", val);
-+ } else {
-+ connected.id.number_presentation = pres;
-+ set_it(chan, &connected);
-+ }
-+ } else if (!strncasecmp("source", data, 6)) {
-+ int source;
-+
-+ val = ast_strdupa(value);
-+ ast_trim_blanks(val);
-+
-+ if (('0' <= val[0]) && (val[0] <= '9')) {
-+ source = atoi(val);
-+ } else {
-+ source = ast_connected_line_source_parse(val);
-+ }
-+
-+ if (source < 0) {
-+ ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
-+ } else {
-+ connected.source = source;
-+ set_it(chan, &connected);
-+ }
-+ } else {
-+ ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
-+ }
-+
-+ return 0;
-+}
-+
-+static struct ast_custom_function connectedline_function = {
-+ .name = "CONNECTEDLINE",
-+ .synopsis = "Gets or sets Connected Line data on the channel.",
-+ .syntax = "CONNECTEDLINE(datatype[,i])",
-+ .desc =
-+ "Gets or sets Connected Line 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"
-+ "\"all\", \"name\", \"num\", \"ton\", \"pres\", and \"source\"\n"
-+ "The source datatype can be set to the following:\n"
-+ "answer - Normal Call Answering\n"
-+ "transfer_alerting - Call Transfer(Alerting)\n"
-+ "transfer_active - Call Transfer(Active)\n",
-+ .read = connectedline_read,
-+ .write = connectedline_write,
-+};
-+
-+static int unload_module(void)
-+{
-+ return ast_custom_function_unregister(&connectedline_function);
-+}
-+
-+static int load_module(void)
-+{
-+ return ast_custom_function_register(&connectedline_function);
-+}
-+
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Connected Line dialplan function");
-
-Property changes on: funcs/func_connectedline.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: funcs/func_iconv.c
-===================================================================
---- a/funcs/func_iconv.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/funcs/func_iconv.c (.../team/group/issue14292) (revision 178988)
-@@ -41,6 +41,32 @@
- #include "asterisk/utils.h"
- #include "asterisk/app.h"
-
-+/*** DOCUMENTATION
-+ <function name="ICONV" language="en_US">
-+ <synopsis>
-+ Converts charsets of strings.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="in-charset" required="true">
-+ <para>Input charset</para>
-+ </parameter>
-+ <parameter name="out-charset" required="true">
-+ <para>Output charset</para>
-+ </parameter>
-+ <parameter name="string" required="true">
-+ <para>String to convert, from <replaceable>in-charset</replaceable> to <replaceable>out-charset</replaceable></para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Converts string from <replaceable>in-charset</replaceable> into <replaceable>out-charset</replaceable>.
-+ For available charsets, use <literal>iconv -l</literal> on your shell command line.</para>
-+ <note><para>Due to limitations within the API, ICONV will not currently work with
-+ charsets with embedded NULLs. If found, the string will terminate.</para></note>
-+ </description>
-+ </function>
-+ ***/
-+
-+
- /*!
- * Some systems define the second arg to iconv() as (const char *),
- * while others define it as (char *). Cast it to a (void *) to
-@@ -101,14 +127,7 @@
-
- static struct ast_custom_function iconv_function = {
- .name = "ICONV",
-- .synopsis = "Converts charsets of strings.",
-- .desc =
--"Converts string from in-charset into out-charset. For available charsets,\n"
--"use 'iconv -l' on your shell command line.\n"
--"Note: due to limitations within the API, ICONV will not currently work with\n"
--"charsets with embedded NULLs. If found, the string will terminate.\n",
-- .syntax = "ICONV(in-charset,out-charset,string)",
-- .read = iconv_read,
-+ .read = iconv_read
- };
-
- static int unload_module(void)
-Index: funcs/func_callerid.c
-===================================================================
---- a/funcs/func_callerid.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/funcs/func_callerid.c (.../team/group/issue14292) (revision 178988)
-@@ -32,6 +32,74 @@
- #include "asterisk/app.h"
- #include "asterisk/callerid.h"
-
-+/*** DOCUMENTATION
-+ <function name="CALLERID" language="en_US">
-+ <synopsis>
-+ Gets or sets Caller*ID data on the channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="datatype" required="true">
-+ <para>The allowable datatypes are:</para>
-+ <enumlist>
-+ <enum name="all" />
-+ <enum name="num" />
-+ <enum name="ANI" />
-+ <enum name="DNID" />
-+ <enum name="RDNIS" />
-+ <enum name="pres" />
-+ <enum name="ton" />
-+ </enumlist>
-+ </parameter>
-+ <parameter name="CID">
-+ <para>Optional Caller*ID</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Gets or sets Caller*ID data on the channel. Uses channel callerid by default or optional
-+ callerid, if specified.</para>
-+ </description>
-+ </function>
-+ <function name="CALLERPRES" language="en_US">
-+ <synopsis>
-+ Gets or sets Caller*ID presentation on the channel.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Gets or sets Caller*ID presentation on the channel. The following values
-+ are valid:</para>
-+ <enumlist>
-+ <enum name="allowed_not_screened">
-+ <para>Presentation Allowed, Not Screened.</para>
-+ </enum>
-+ <enum name="allowed_passed_screen">
-+ <para>Presentation Allowed, Passed Screen.</para>
-+ </enum>
-+ <enum name="allowed_failed_screen">
-+ <para>Presentation Allowed, Failed Screen.</para>
-+ </enum>
-+ <enum name="allowed">
-+ <para>Presentation Allowed, Network Number.</para>
-+ </enum>
-+ <enum name="prohib_not_screened">
-+ <para>Presentation Prohibited, Not Screened.</para>
-+ </enum>
-+ <enum name="prohib_passed_screen">
-+ <para>Presentation Prohibited, Passed Screen.</para>
-+ </enum>
-+ <enum name="prohib_failed_screen">
-+ <para>Presentation Prohibited, Failed Screen.</para>
-+ </enum>
-+ <enum name="prohib">
-+ <para>Presentation Prohibited, Network Number.</para>
-+ </enum>
-+ <enum name="unavailable">
-+ <para>Number Unavailable.</para>
-+ </enum>
-+ </enumlist>
-+ </description>
-+ </function>
-+ ***/
-+
- static int callerpres_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
- {
- ast_copy_string(buf, ast_named_caller_presentation(chan->cid.cid_pres), len);
-@@ -205,33 +273,12 @@
-
- static struct ast_custom_function callerid_function = {
- .name = "CALLERID",
-- .synopsis = "Gets or sets Caller*ID data on the channel.",
-- .syntax = "CALLERID(datatype[,<optional-CID>])",
-- .desc =
-- "Gets or sets Caller*ID data on the channel. The allowable datatypes\n"
-- "are \"all\", \"name\", \"num\", \"ANI\", \"DNID\", \"RDNIS\", \"pres\",\n"
-- "and \"ton\".\n"
-- "Uses channel callerid by default or optional callerid, if specified.\n",
- .read = callerid_read,
- .write = callerid_write,
- };
-
- static struct ast_custom_function callerpres_function = {
- .name = "CALLERPRES",
-- .synopsis = "Gets or sets Caller*ID presentation on the channel.",
-- .syntax = "CALLERPRES()",
-- .desc =
--"Gets or sets Caller*ID presentation on the channel. The following values\n"
--"are valid:\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",
- .read = callerpres_read,
- .write = callerpres_write,
- };
-Index: funcs/func_devstate.c
-===================================================================
---- a/funcs/func_devstate.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/funcs/func_devstate.c (.../team/group/issue14292) (revision 178988)
-@@ -44,6 +44,57 @@
- #include "asterisk/astdb.h"
- #include "asterisk/app.h"
-
-+/*** DOCUMENTATION
-+ <function name="DEVICE_STATE" language="en_US">
-+ <synopsis>
-+ Get or Set a device state.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="device" required="true" />
-+ </syntax>
-+ <description>
-+ <para>The DEVICE_STATE function can be used to retrieve the device state from any
-+ device state provider. For example:</para>
-+ <para>NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})</para>
-+ <para>NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})</para>
-+ <para>The DEVICE_STATE function can also be used to set custom device state from
-+ the dialplan. The <literal>Custom:</literal> prefix must be used. For example:</para>
-+ <para>Set(DEVICE_STATE(Custom:lamp1)=BUSY)</para>
-+ <para>Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)</para>
-+ <para>You can subscribe to the status of a custom device state using a hint in
-+ the dialplan:</para>
-+ <para>exten => 1234,hint,Custom:lamp1</para>
-+ <para>The possible values for both uses of this function are:</para>
-+ <para>UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING |
-+ RINGINUSE | ONHOLD</para>
-+ </description>
-+ </function>
-+ <function name="HINT" language="en_US">
-+ <synopsis>
-+ Get the devices set for a dialplan hint.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="extension" required="true" argsep="@">
-+ <argument name="extension" required="true" />
-+ <argument name="context" />
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="n">
-+ <para>Retrieve name on the hint instead of list of devices.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>The HINT function can be used to retrieve the list of devices that are
-+ mapped to a dialplan hint. For example:</para>
-+ <para>NoOp(Hint for Extension 1234 is ${HINT(1234)})</para>
-+ </description>
-+ </function>
-+ ***/
-+
-+
- static const char astdb_family[] = "CustomDevstate";
-
- static int devstate_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-@@ -137,50 +188,6 @@
- return ast_devstate_val(buf);
- }
-
--static char *handle_cli_funcdevstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- struct ast_db_entry *db_entry, *db_tree;
--
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "funcdevstate list";
-- e->usage =
-- "Usage: funcdevstate list\n"
-- " List all custom device states that have been set by using\n"
-- " the DEVICE_STATE dialplan function.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc != e->args)
-- return CLI_SHOWUSAGE;
--
-- ast_cli(a->fd, "\n"
-- "---------------------------------------------------------------------\n"
-- "--- Custom Device States --------------------------------------------\n"
-- "---------------------------------------------------------------------\n"
-- "---\n");
--
-- db_entry = db_tree = ast_db_gettree(astdb_family, NULL);
-- for (; db_entry; db_entry = db_entry->next) {
-- const char *dev_name = strrchr(db_entry->key, '/') + 1;
-- if (dev_name <= (const char *) 1)
-- continue;
-- ast_cli(a->fd, "--- Name: 'Custom:%s' State: '%s'\n"
-- "---\n", dev_name, db_entry->data);
-- }
-- ast_db_freetree(db_tree);
-- db_tree = NULL;
--
-- ast_cli(a->fd,
-- "---------------------------------------------------------------------\n"
-- "---------------------------------------------------------------------\n"
-- "\n");
--
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_devstate_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct ast_db_entry *db_entry, *db_tree;
-@@ -288,48 +295,19 @@
- return CLI_SUCCESS;
- }
-
--static struct ast_cli_entry cli_funcdevstate_list_deprecated = AST_CLI_DEFINE(handle_cli_funcdevstate_list, "List currently known custom device states");
- static struct ast_cli_entry cli_funcdevstate[] = {
-- AST_CLI_DEFINE(handle_cli_devstate_list, "List currently known custom device states", .deprecate_cmd = &cli_funcdevstate_list_deprecated),
-+ AST_CLI_DEFINE(handle_cli_devstate_list, "List currently known custom device states"),
- AST_CLI_DEFINE(handle_cli_devstate_change, "Change a custom device state"),
- };
-
- static struct ast_custom_function devstate_function = {
- .name = "DEVICE_STATE",
-- .synopsis = "Get or Set a device state",
-- .syntax = "DEVICE_STATE(device)",
-- .desc =
-- " The DEVICE_STATE function can be used to retrieve the device state from any\n"
-- "device state provider. For example:\n"
-- " NoOp(SIP/mypeer has state ${DEVICE_STATE(SIP/mypeer)})\n"
-- " NoOp(Conference number 1234 has state ${DEVICE_STATE(MeetMe:1234)})\n"
-- "\n"
-- " The DEVICE_STATE function can also be used to set custom device state from\n"
-- "the dialplan. The \"Custom:\" prefix must be used. For example:\n"
-- " Set(DEVICE_STATE(Custom:lamp1)=BUSY)\n"
-- " Set(DEVICE_STATE(Custom:lamp2)=NOT_INUSE)\n"
-- "You can subscribe to the status of a custom device state using a hint in\n"
-- "the dialplan:\n"
-- " exten => 1234,hint,Custom:lamp1\n"
-- "\n"
-- " The possible values for both uses of this function are:\n"
-- "UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING\n"
-- "RINGINUSE | ONHOLD\n",
- .read = devstate_read,
- .write = devstate_write,
- };
-
- static struct ast_custom_function hint_function = {
- .name = "HINT",
-- .synopsis = "Get the devices set for a dialplan hint",
-- .syntax = "HINT(extension[@context][|options])",
-- .desc =
-- " The HINT function can be used to retrieve the list of devices that are\n"
-- "mapped to a dialplan hint. For example:\n"
-- " NoOp(Hint for Extension 1234 is ${HINT(1234)})\n"
-- "Options:\n"
-- " 'n' - Retrieve name on the hint instead of list of devices\n"
-- "",
- .read = hint_read,
- };
-
-Index: autoconf/ast_check_pwlib.m4
-===================================================================
---- a/autoconf/ast_check_pwlib.m4 (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/autoconf/ast_check_pwlib.m4 (.../team/group/issue14292) (revision 178988)
-@@ -103,13 +103,13 @@
- else
- AC_CHECK_HEADER(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
- if test "${HAS_PWLIB:-unset}" != "unset" ; then
-- AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
-- if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
-- AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
-- fi
-+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin$PATH_SEPARATOR/usr/local/share/pwlib/make)
- 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
-@@ -121,10 +121,13 @@
- else
- AC_CHECK_HEADER(/usr/include/ptlib.h, HAS_PWLIB=1, )
- if test "${HAS_PWLIB:-unset}" != "unset" ; then
-- AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
-+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/bin$PATH_SEPARATOR/usr/share/pwlib/make)
- 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
-@@ -188,8 +191,14 @@
- ])
-
- AC_DEFUN([AST_CHECK_PWLIB_VERSION], [
-+ if test "x$7" != "x"; then
-+ VNAME="$7"
-+ else
-+ VNAME="$2_VERSION"
-+ fi
-+
- if test "${HAS_$2:-unset}" != "unset"; then
-- $2_VERSION=`grep "$2_VERSION" ${$2_INCDIR}/$3 | sed -e 's/[[[:space:]]]\{1,\}/ /g' | cut -f3 -d ' ' | sed -e 's/"//g'`
-+ $2_VERSION=`grep "$VNAME" ${$2_INCDIR}/$3 | sed -e 's/[[[:space:]]]\{1,\}/ /g' | cut -f3 -d ' ' | sed -e 's/"//g'`
- $2_MAJOR_VERSION=`echo ${$2_VERSION} | cut -f1 -d.`
- $2_MINOR_VERSION=`echo ${$2_VERSION} | cut -f2 -d.`
- $2_BUILD_NUMBER=`echo ${$2_VERSION} | cut -f3 -d.`
-Index: autoconf/ast_func_fork.m4
-===================================================================
---- a/autoconf/ast_func_fork.m4 (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/autoconf/ast_func_fork.m4 (.../team/group/issue14292) (revision 178988)
-@@ -39,6 +39,8 @@
- fi
- if test "x$ac_cv_func_fork_works" = xyes; then
- AC_DEFINE(HAVE_WORKING_FORK, 1, [Define to 1 if `fork' works.])
-+ PBX_WORKING_FORK=1
-+ AC_SUBST(PBX_WORKING_FORK)
- fi
- ])# AST_FUNC_FORK
-
-Index: autoconf/ast_gcc_attribute.m4
-===================================================================
---- a/autoconf/ast_gcc_attribute.m4 (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/autoconf/ast_gcc_attribute.m4 (.../team/group/issue14292) (revision 178988)
-@@ -1,17 +1,31 @@
- # Helper function to check for gcc attributes.
--# AST_GCC_ATTRIBUTE([attribute name])
-+# AST_GCC_ATTRIBUTE([attribute name], [attribute syntax])
-
- AC_DEFUN([AST_GCC_ATTRIBUTE],
- [
- AC_MSG_CHECKING(for compiler 'attribute $1' support)
- saved_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -Werror"
-+
-+if test "x$2" = "x"
-+then
- AC_COMPILE_IFELSE(
- AC_LANG_PROGRAM([void __attribute__(($1)) *test(void *muffin, ...) {}],
- []),
- AC_MSG_RESULT(yes)
- AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
-- AC_MSG_RESULT(no))
-+ AC_MSG_RESULT(no)
-+)
-+else
-+AC_COMPILE_IFELSE(
-+ AC_LANG_PROGRAM([void __attribute__(($2)) *test(void *muffin, ...) {}],
-+ []),
-+ AC_MSG_RESULT(yes)
-+ AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
-+ AC_MSG_RESULT(no)
-+)
-+fi
-+
-+CFLAGS="$saved_CFLAGS"
- ]
--CFLAGS="$saved_CFLAGS"
- )
-Index: autoconf/ast_prog_sed.m4
-===================================================================
---- a/autoconf/ast_prog_sed.m4 (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/autoconf/ast_prog_sed.m4 (.../team/group/issue14292) (revision 178988)
-@@ -12,7 +12,8 @@
- done
- echo "$ac_script" | sed 99q >conftest.sed
- $as_unset ac_script || ac_script=
-- _AC_PATH_PROG_FEATURE_CHECK(SED, [sed gsed],
-+ ifdef([_AC_PATH_PROGS_FEATURE_CHECK],[],[define([_AC_PATH_PROGS_FEATURE_CHECK],defn([_AC_PATH_PROG_FEATURE_CHECK]))])
-+ _AC_PATH_PROGS_FEATURE_CHECK(SED, [sed gsed],
- [_AC_FEATURE_CHECK_LENGTH([ac_path_SED], [ac_cv_path_SED],
- ["$ac_path_SED" -f conftest.sed])])])
- SED="$ac_cv_path_SED"
-Index: autoconf/ast_ext_lib.m4
-===================================================================
---- a/autoconf/ast_ext_lib.m4 (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/autoconf/ast_ext_lib.m4 (.../team/group/issue14292) (revision 178988)
-@@ -10,11 +10,15 @@
- [
- $1_DESCRIP="$2"
- $1_OPTION="$3"
-+ PBX_$1=0
- AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH $4]),
- [
- case ${withval} in
- n|no)
- USE_$1=no
-+ # -1 is a magic value used by menuselect to know that the package
-+ # was disabled, other than 'not found'
-+ PBX_$1=-1
- ;;
- y|ye|yes)
- ac_mandatory_list="${ac_mandatory_list} $1"
-@@ -25,7 +29,6 @@
- ;;
- esac
- ])
-- PBX_$1=0
- AC_SUBST([$1_LIB])
- AC_SUBST([$1_INCLUDE])
- AC_SUBST([$1_DIR])
-Index: include/asterisk/global_datastores.h
-===================================================================
---- a/include/asterisk/global_datastores.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/global_datastores.h (.../team/group/issue14292) (revision 178988)
-@@ -26,22 +26,11 @@
-
- #include "asterisk/channel.h"
-
--#define MAX_DIAL_FEATURE_OPTIONS 30
--
- extern const struct ast_datastore_info dialed_interface_info;
-
--extern const struct ast_datastore_info dial_features_info;
--
- struct ast_dialed_interface {
- AST_LIST_ENTRY(ast_dialed_interface) list;
- char interface[1];
- };
-
--struct ast_dial_features {
-- struct ast_flags features_caller;
-- struct ast_flags features_callee;
-- char options[MAX_DIAL_FEATURE_OPTIONS];
-- int is_caller;
--};
--
- #endif
-Index: include/asterisk/options.h
-===================================================================
---- a/include/asterisk/options.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/options.h (.../team/group/issue14292) (revision 178988)
-@@ -82,6 +82,14 @@
- AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
- /*! There is a per-file verbose setting */
- AST_OPT_FLAG_VERBOSE_FILE = (1 << 24),
-+ /*! Terminal colors should be adjusted for a light-colored background */
-+ AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),
-+ /*! Count Initiated seconds in CDR's */
-+ AST_OPT_FLAG_INITIATED_SECONDS = (1 << 26),
-+ /*! Force black background */
-+ AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27),
-+ /*! Hide remote console connect messages on console */
-+ AST_OPT_FLAG_HIDE_CONSOLE_CONNECT = (1 << 28),
- };
-
- /*! These are the options that set by default when Asterisk starts */
-@@ -111,6 +119,9 @@
- #define ast_opt_mute ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
- #define ast_opt_dbg_file ast_test_flag(&ast_options, AST_OPT_FLAG_DEBUG_FILE)
- #define ast_opt_verb_file ast_test_flag(&ast_options, AST_OPT_FLAG_VERBOSE_FILE)
-+#define ast_opt_light_background ast_test_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND)
-+#define ast_opt_force_black_background ast_test_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND)
-+#define ast_opt_hide_connect ast_test_flag(&ast_options, AST_OPT_FLAG_HIDE_CONSOLE_CONNECT)
-
- extern struct ast_flags ast_options;
-
-Index: include/asterisk/xml.h
-===================================================================
---- a/include/asterisk/xml.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/include/asterisk/xml.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,122 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+#ifndef _ASTERISK_XML_H
-+#define _ASTERISK_XML_H
-+
-+/*! \file
-+ * \brief Asterisk XML abstraction layer
-+ */
-+
-+struct ast_xml_node;
-+struct ast_xml_doc;
-+
-+/*! \brief Initialize the XML library implementation.
-+ * This function is used to setup everything needed
-+ * to start working with the xml implementation.
-+ * \retval 0 On success.
-+ * \retval 1 On error.
-+ */
-+int ast_xml_init(void);
-+
-+/*! \brief Cleanup library allocated global data.
-+ * \retval 0 On success.
-+ * \retval 1 On error.
-+ */
-+int ast_xml_finish(void);
-+
-+/*! \brief Open an XML document.
-+ * \param filename Document path.
-+ * \retval NULL on error.
-+ * \retval The ast_xml_doc reference to the open document.
-+ */
-+struct ast_xml_doc *ast_xml_open(char *filename);
-+
-+/*! \brief Close an already open document and free the used
-+ * structure.
-+ * \retval doc The document reference.
-+ */
-+void ast_xml_close(struct ast_xml_doc *doc);
-+
-+/*! \brief Get the document root node.
-+ * \param doc Document reference
-+ * \retval NULL on error
-+ * \retval The root node on success.
-+ */
-+struct ast_xml_node *ast_xml_get_root(struct ast_xml_doc *doc);
-+
-+/*! \brief Free node
-+ * \param node Node to be released.
-+ */
-+void ast_xml_free_node(struct ast_xml_node *node);
-+
-+/*! \brief Free an attribute returned by ast_xml_get_attribute()
-+ * \param data pointer to be freed.
-+ */
-+void ast_xml_free_attr(const char *attribute);
-+
-+/*! \brief Free a content element that was returned by ast_xml_get_text()
-+ * \param text text to be freed.
-+ */
-+void ast_xml_free_text(const char *text);
-+
-+/*! \brief Get a node attribute by name
-+ * \param node Node where to search the attribute.
-+ * \param attrname Attribute name.
-+ * \retval NULL on error
-+ * \retval The attribute value on success.
-+ */
-+const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname);
-+
-+/*! \brief Find a node element by name.
-+ * \param node This is the node starting point.
-+ * \param name Node name to find.
-+ * \param attrname attribute name to match (if NULL it won't be matched).
-+ * \param attrvalue attribute value to match (if NULL it won't be matched).
-+ * \retval NULL if not found
-+ * \retval The node on success.
-+ */
-+struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue);
-+
-+/*! \brief Get an element content string.
-+ * \param node Node from where to get the string.
-+ * \retval NULL on error.
-+ * \retval The text content of node.
-+ */
-+const char *ast_xml_get_text(struct ast_xml_node *node);
-+
-+/*! \brief Get the name of a node. */
-+const char *ast_xml_node_get_name(struct ast_xml_node *node);
-+
-+/*! \brief Get the node's children. */
-+struct ast_xml_node *ast_xml_node_get_children(struct ast_xml_node *node);
-+
-+/*! \brief Get the next node in the same level. */
-+struct ast_xml_node *ast_xml_node_get_next(struct ast_xml_node *node);
-+
-+/*! \brief Get the previous node in the same leve. */
-+struct ast_xml_node *ast_xml_node_get_prev(struct ast_xml_node *node);
-+
-+/*! \brief Get the parent of a specified node. */
-+struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node);
-+
-+/* Features using ast_xml_ */
-+#ifdef HAVE_LIBXML2
-+#define AST_XML_DOCS
-+#endif
-+
-+#endif /* _ASTERISK_XML_H */
-+
-
-Property changes on: include/asterisk/xml.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: include/asterisk/config.h
-===================================================================
---- a/include/asterisk/config.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/config.h (.../team/group/issue14292) (revision 178988)
-@@ -45,7 +45,9 @@
- CONFIG_FLAG_NOCACHE = (1 << 2),
- };
-
-+#define CONFIG_STATUS_FILEMISSING (void *)0
- #define CONFIG_STATUS_FILEUNCHANGED (void *)-1
-+#define CONFIG_STATUS_FILEINVALID (void *)-2
-
- /*!
- * \brief Types used in ast_realtime_require_field
-@@ -89,6 +91,7 @@
- typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
- typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
- typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
-+typedef int realtime_update2(const char *database, const char *table, va_list ap);
- typedef int realtime_store(const char *database, const char *table, va_list ap);
- typedef int realtime_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
- typedef int realtime_require(const char *database, const char *table, va_list ap);
-@@ -101,6 +104,7 @@
- realtime_var_get *realtime_func;
- realtime_multi_get *realtime_multi_func;
- realtime_update *update_func;
-+ realtime_update2 *update2_func;
- realtime_store *store_func;
- realtime_destroy *destroy_func;
- realtime_require *require_func;
-@@ -117,7 +121,7 @@
- * CONFIG_FLAG_FILEUNCHANGED - check the file mtime and return CONFIG_STATUS_FILEUNCHANGED if the mtime is the same; or
- * CONFIG_FLAG_NOCACHE - don't cache file mtime (main purpose of this option is to save memory on temporary files).
- *
-- * \retval an ast_config data structure on success
-+ * \return an ast_config data structure on success
- * \retval NULL on error
- */
- struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags);
-@@ -206,6 +210,12 @@
- * entity in realtime and return a variable list of its parameters. Note
- * that unlike the variables in ast_config, the resulting list of variables
- * MUST be freed with ast_variables_destroy() as there is no container.
-+ *
-+ * The difference between these two calls is that ast_load_realtime excludes
-+ * fields whose values are NULL, while ast_load_realtime_all loads all columns.
-+ *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
- */
- struct ast_variable *ast_load_realtime(const char *family, ...) attribute_sentinel;
- struct ast_variable *ast_load_realtime_all(const char *family, ...) attribute_sentinel;
-@@ -215,6 +225,8 @@
- * \param family which family/config to destroy
- * Various backends may cache attributes about a realtime data storage
- * facility; on reload, a front end resource may request to purge that cache.
-+ * \retval 0 If any cache was purged
-+ * \retval -1 If no cache was found
- */
- int ast_unload_realtime(const char *family);
-
-@@ -241,17 +253,27 @@
- * a timeout value may reasonably be specified as an INTEGER2, with size 5.
- * Even though values above 32767 seconds are possible, they are unlikely
- * to be useful, and we should not complain about that size).
-+ *
-+ * \retval 0 Required fields met specified standards
-+ * \retval -1 One or more fields was missing or insufficient
-+ *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
- */
- int ast_realtime_require_field(const char *family, ...) attribute_sentinel;
-
- /*!
- * \brief Retrieve realtime configuration
- * \param family which family/config to lookup
-+ *
- * This will use builtin configuration backends to look up a particular
- * entity in realtime and return a variable list of its parameters. Unlike
- * the ast_load_realtime, this function can return more than one entry and
-- * is thus stored inside a taditional ast_config structure rather than
-+ * is thus stored inside a traditional ast_config structure rather than
- * just returning a linked list of variables.
-+ *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
- */
- struct ast_config *ast_load_realtime_multientry(const char *family, ...) attribute_sentinel;
-
-@@ -261,15 +283,38 @@
- * \param keyfield which field to use as the key
- * \param lookup which value to look for in the key field to match the entry.
- * This function is used to update a parameter in realtime configuration space.
-+ * \return Number of rows affected, or -1 on error.
- *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
- */
- int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...) attribute_sentinel;
-
- /*!
-+ * \brief Update realtime configuration
-+ * \param family which family/config to be updated
-+ * This function is used to update a parameter in realtime configuration space.
-+ * It includes the ability to lookup a row based upon multiple key criteria.
-+ * As a result, this function includes two sentinel values, one to terminate
-+ * lookup values and the other to terminate the listing of fields to update.
-+ * \return Number of rows affected, or -1 on error.
-+ *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
-+ */
-+int ast_update2_realtime(const char *family, ...) attribute_sentinel;
-+
-+/*!
- * \brief Create realtime configuration
- * \param family which family/config to be created
- * This function is used to create a parameter in realtime configuration space.
-+ * \return Number of rows affected, or -1 on error.
-+ * On the MySQL engine only, for reasons of backwards compatibility, the return
-+ * value is the insert ID. This value is nonportable and may be changed in a
-+ * future version to match the other engines.
- *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
- */
- int ast_store_realtime(const char *family, ...) attribute_sentinel;
-
-@@ -280,7 +325,10 @@
- * \param lookup which value to look for in the key field to match the entry.
- * This function is used to destroy an entry in realtime configuration space.
- * Additional params are used as keys.
-+ * \return Number of rows affected, or -1 on error.
- *
-+ * Note that you should use the constant SENTINEL to terminate arguments, in
-+ * order to preserve cross-platform compatibility.
- */
- int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...) attribute_sentinel;
-
-@@ -300,20 +348,50 @@
- */
- void ast_variables_destroy(struct ast_variable *var);
-
--/*! \brief Register config engine */
-+/*! \brief Register config engine
-+ * \retval 1 Always
-+ */
- int ast_config_engine_register(struct ast_config_engine *newconfig);
-
--/*! \brief Deegister config engine */
-+/*! \brief Deregister config engine
-+ * \retval 0 Always
-+ */
- int ast_config_engine_deregister(struct ast_config_engine *del);
-
-+/*!\brief Exposed initialization method for core process
-+ * This method is intended for use only with the core initialization and is
-+ * not designed to be called from any user applications.
-+ */
- int register_config_cli(void);
-+
-+/*!\brief Exposed re-initialization method for core process
-+ * This method is intended for use only with the core re-initialization and is
-+ * not designed to be called from any user applications.
-+ */
- int read_config_maps(void);
-
-+/*!\brief Create a new base configuration structure */
- struct ast_config *ast_config_new(void);
-+
-+/*!\brief Retrieve the current category name being built.
-+ * API for backend configuration engines while building a configuration set.
-+ */
- struct ast_category *ast_config_get_current_category(const struct ast_config *cfg);
-+
-+/*!\brief Set the category within the configuration as being current.
-+ * API for backend configuration engines while building a configuration set.
-+ */
- void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
-+
-+/*!\brief Retrieve a configuration variable within the configuration set.
-+ * Retrieves the named variable \p var within category \p cat of configuration
-+ * set \p cfg. If not found, attempts to retrieve the named variable \p var
-+ * from within category \em general.
-+ * \return Value of \p var, or NULL if not found.
-+ */
- const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var);
-
-+/*!\brief Create a category structure */
- struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
- void ast_category_append(struct ast_config *config, struct ast_category *cat);
-
-@@ -327,6 +405,11 @@
- */
- void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match);
- int ast_category_delete(struct ast_config *cfg, const char *category);
-+
-+/*!\brief Removes and destroys all variables within a category
-+ * \retval 0 if the category was found and emptied
-+ * \retval -1 if the category was not found
-+ */
- int ast_category_empty(struct ast_config *cfg, const char *category);
- void ast_category_destroy(struct ast_category *cat);
- struct ast_variable *ast_category_detach_variables(struct ast_category *cat);
-@@ -356,7 +439,8 @@
- int ast_variable_update(struct ast_category *category, const char *variable,
- const char *value, const char *match, unsigned int object);
-
--int config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator);
-+int ast_config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator);
-+int config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator) __attribute__((deprecated));
-
- struct ast_config *ast_config_internal_load(const char *configfile, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl_file, const char *who_asked);
-
-@@ -487,6 +571,7 @@
- #define CV_DSTR(__x, __dst) CV_F(__x, if (__dst) ast_free(__dst); __dst = ast_strdup(__val))
- #define CV_STRFIELD(__x, __obj, __field) CV_F(__x, ast_string_field_set(__obj, __field, __val))
-
-+/*!\brief Check if require type is an integer type */
- AST_INLINE_API(
- int ast_rq_is_int(require_type type),
- {
-Index: include/asterisk/term.h
-===================================================================
---- a/include/asterisk/term.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/term.h (.../team/group/issue14292) (revision 178988)
-@@ -62,8 +62,34 @@
- #define COLOR_BRWHITE (37 | 128)
- /*@} */
-
-+/*! \brief Maximum number of characters needed for a color escape sequence,
-+ * plus a null char */
-+#define AST_TERM_MAX_ESCAPE_CHARS 23
-+
- char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout);
-
-+/*!
-+ * \brief Append a color sequence to an ast_str
-+ *
-+ * \param str The string to append to
-+ * \param fgcolor foreground color
-+ * \param bgcolor background color
-+ *
-+ * \retval 0 success
-+ * \retval -1 failure
-+ */
-+int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor);
-+
-+/*!
-+ * \brief Write a color sequence to a string
-+ *
-+ * \param outbuf the location to write to
-+ * \param fgcolor foreground color
-+ * \param bgcolor background color
-+ * \param maxout maximum number of characters to write
-+ *
-+ * \return outbuf
-+ */
- char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout);
-
- char *term_strip(char *outbuf, char *inbuf, int maxout);
-Index: include/asterisk/cdr.h
-===================================================================
---- a/include/asterisk/cdr.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/cdr.h (.../team/group/issue14292) (revision 178988)
-@@ -282,7 +282,7 @@
- * Changes the value of the last executed app
- * Returns nothing
- */
--void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data);
-+void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data);
-
- /*!
- * \brief Convert a string to a detail record AMA flag
-Index: include/asterisk/channel.h
-===================================================================
---- a/include/asterisk/channel.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/channel.h (.../team/group/issue14292) (revision 178988)
-@@ -28,7 +28,7 @@
- A phone call through Asterisk consists of an incoming
- connection and an outbound connection. Each call comes
- in through a channel driver that supports one technology,
-- like SIP, DAHDI, IAX2 etc.
-+ like SIP, DAHDI, IAX2 etc.
- \par
- Each channel driver, technology, has it's own private
- channel or dialog structure, that is technology-dependent.
-@@ -38,13 +38,13 @@
- \par Call scenario
- This happens when an incoming call arrives to Asterisk
- -# Call arrives on a channel driver interface
-- -# Channel driver creates a PBX channel and starts a
-+ -# Channel driver creates a PBX channel and starts a
- pbx thread on the channel
- -# The dial plan is executed
- -# At this point at least two things can happen:
-- -# The call is answered by Asterisk and
-+ -# The call is answered by Asterisk and
- Asterisk plays a media stream or reads media
-- -# The dial plan forces Asterisk to create an outbound
-+ -# The dial plan forces Asterisk to create an outbound
- call somewhere with the dial (see \ref app_dial.c)
- application
- .
-@@ -67,14 +67,14 @@
- Asterisk in order to be able to provide a proper CDR record
- for the call.
-
--
-+
- \par Masquerading channels
- In some cases, a channel can masquerade itself into another
-- channel. This happens frequently in call transfers, where
-+ channel. This happens frequently in call transfers, where
- a new channel takes over a channel that is already involved
- in a call. The new channel sneaks in and takes over the bridge
- and the old channel, now a zombie, is hung up.
--
-+
- \par Reference
- \arg channel.c - generic functions
- \arg channel.h - declarations of functions, flags and structures
-@@ -86,11 +86,11 @@
- */
- /*! \page Def_Bridge Asterisk Channel Bridges
-
-- In Asterisk, there's several media bridges.
-+ In Asterisk, there's several media bridges.
-
- The Core bridge handles two channels (a "phone call") and bridge
- them together.
--
-+
- The conference bridge (meetme) handles several channels simultaneously
- with the support of an external timer (DAHDI timer). This is used
- not only by the Conference application (meetme) but also by the
-@@ -102,7 +102,7 @@
- can create a native bridge without sending media through the
- core.
-
-- Native briding can be disabled by a number of reasons,
-+ Native bridging can be disabled by a number of reasons,
- like DTMF being needed by the core or codecs being incompatible
- so a transcoding module is needed.
-
-@@ -111,11 +111,11 @@
- \li \see ast_channel_bridge()
- \li \see app_meetme.c
- \li \ref AstRTPbridge
-- \li \see ast_rtp_bridge()
-+ \li \see ast_rtp_bridge()
- \li \ref Def_Channel
- */
-
--/*! \page AstFileDesc File descriptors
-+/*! \page AstFileDesc File descriptors
- Asterisk File descriptors are connected to each channel (see \ref Def_Channel)
- in the \ref ast_channel structure.
- */
-@@ -173,7 +173,7 @@
-
- typedef unsigned long long ast_group_t;
-
--/*! \todo Add an explanation of an Asterisk generator
-+/*! \todo Add an explanation of an Asterisk generator
- */
- struct ast_generator {
- void *(*alloc)(struct ast_channel *chan, void *params);
-@@ -191,41 +191,162 @@
- * \note All string fields here are malloc'ed, so they need to be
- * freed when the structure is deleted.
- * Also, NULL and "" must be considered equivalent.
-- *
-- * SIP and IAX2 has utf8 encoded Unicode caller ID names.
-+ *
-+ * \note SIP and IAX2 has utf8 encoded Unicode caller ID names.
- * In some cases, we also have an alternative (RPID) E.164 number that can be used
-- * as caller ID on numeric E.164 phone networks (DAHDI or SIP/IAX2 to pstn gateway).
-+ * as caller ID on numeric E.164 phone networks (DAHDI or SIP/IAX2 to PSTN gateway).
- *
- * \todo Implement settings for transliteration between UTF8 caller ID names in
- * to Ascii Caller ID's (DAHDI). Östen Åsklund might be transliterated into
-- * Osten Asklund or Oesten Aasklund depending upon language and person...
-- * We need automatic routines for incoming calls and static settings for
-- * our own accounts.
-+ * Osten Asklund or Oesten Aasklund depending upon language and person...
-+ * We need automatic routines for incoming calls and static settings for
-+ * our own accounts.
- */
- struct ast_callerid {
-- char *cid_dnid; /*!< Malloc'd Dialed Number Identifier */
-- char *cid_num; /*!< Malloc'd Caller Number */
-- char *cid_name; /*!< Malloc'd Caller Name (ASCII) */
-- char *cid_ani; /*!< Malloc'd ANI */
-- char *cid_rdnis; /*!< Malloc'd RDNIS */
-- int cid_pres; /*!< Callerid presentation/screening */
-- int cid_ani2; /*!< Callerid ANI 2 (Info digits) */
-- int cid_ton; /*!< Callerid Type of Number */
-- int cid_tns; /*!< Callerid Transit Network Select */
-+ /*!
-+ * \brief Malloc'd Dialed Number Identifier
-+ * (Field will eventually move to struct ast_channel.dialed.number)
-+ */
-+ char *cid_dnid;
-+
-+ /*!
-+ * \brief Malloc'd Caller Number
-+ * (Field will eventually move to struct ast_channel.caller.id.number)
-+ */
-+ char *cid_num;
-+
-+ /*!
-+ * \brief Malloc'd Caller Name (ASCII)
-+ * (Field will eventually move to struct ast_channel.caller.id.name)
-+ */
-+ char *cid_name;
-+
-+ /*!
-+ * \brief Malloc'd Automatic Number Identification (ANI)
-+ * (Field will eventually move to struct ast_channel.caller.ani)
-+ */
-+ char *cid_ani;
-+
-+ /*!
-+ * \brief Malloc'd Redirecting Directory Number Information Service (RDNIS)
-+ * (Field will eventually move to struct ast_channel.redirecting.from.number)
-+ */
-+ char *cid_rdnis;
-+
-+ /*!
-+ * \brief Callerid Q.931 encoded number presentation/screening fields
-+ * (Field will eventually move to struct ast_channel.caller.id.number_presentation)
-+ */
-+ int cid_pres;
-+
-+ /*!
-+ * \brief Callerid ANI 2 (Info digits)
-+ * (Field will eventually move to struct ast_channel.caller.ani2)
-+ */
-+ int cid_ani2;
-+
-+ /*!
-+ * \brief Callerid Q.931 encoded type-of-number/numbering-plan fields
-+ * \note Currently this value is mostly just passed around the system.
-+ * The H.323 interfaces set the value from received messages and uses the value for sent messages.
-+ * The DAHDI PRI interfaces set the value from received messages but does not use it for sent messages.
-+ * You can read it and set it but only H.323 uses it.
-+ * (Field will eventually move to struct ast_channel.caller.id.number_type)
-+ */
-+ int cid_ton;
-+
-+ /*!
-+ * \brief Callerid Transit Network Select
-+ * \note Currently this value is just passed around the system.
-+ * You can read it and set it but it is never used for anything.
-+ * (Field will eventually move to struct ast_channel.dialed.transit_network_select)
-+ */
-+ int cid_tns;
- };
-
--/*! \brief
-- Structure to describe a channel "technology", ie a channel driver
-- See for examples:
-- \arg chan_iax2.c - The Inter-Asterisk exchange protocol
-- \arg chan_sip.c - The SIP channel driver
-- \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
-+/*!
-+ * \brief Information needed to identify an endpoint in a call.
-+ * \note All string fields here are malloc'ed, so they need to be
-+ * freed when the structure is deleted.
-+ * \note NULL and "" must be considered equivalent.
-+ */
-+struct ast_party_id {
-+ /*! \brief Subscriber phone number (Malloced) */
-+ char *number;
-
-- If you develop your own channel driver, this is where you
-- tell the PBX at registration of your driver what properties
-- this driver supports and where different callbacks are
-- implemented.
--*/
-+ /*! \brief Subscriber name (Malloced) */
-+ char *name;
-+
-+ /*! \brief Q.931 encoded type-of-number/numbering-plan fields */
-+ int number_type;
-+
-+ /*! \brief Q.931 encoded number presentation/screening fields */
-+ int number_presentation;
-+};
-+
-+/*! \brief Connected Line/Party information.
-+ * \note All string fields here are malloc'ed, so they need to be
-+ * freed when the structure is deleted.
-+ * \note NULL and "" must be considered equivalent.
-+ */
-+struct ast_party_connected_line {
-+ struct ast_party_id id; /*! \brief Connected party ID */
-+
-+ /*!
-+ * \brief Automatic Number Identification (ANI) (Malloced)
-+ * \note Not really part of connected line data but needed to
-+ * save the corresponding caller id value.
-+ */
-+ char *ani;
-+
-+ /*!
-+ * \brief Automatic Number Identification 2 (Info Digits)
-+ * \note Not really part of connected line data but needed to
-+ * save the corresponding caller id value.
-+ */
-+ int ani2;
-+
-+ /*! \brief Information about the source of an update (Q.SIG/ISDN requirement).
-+ * \note enum AST_CONNECTED_LINE_UPDATE_SOURCE values
-+ * for Normal-Answer, Call-transfer, Call-diversion
-+ */
-+ int source;
-+};
-+
-+/*! \brief Redirecting Line information.
-+ * RDNIS (Redirecting Directory Number Information Service)
-+ * Where a call diversion or transfer was invoked.
-+ * \note All string fields here are malloc'ed, so they need to be
-+ * freed when the structure is deleted.
-+ * \note NULL and "" must be considered equivalent.
-+ */
-+struct ast_party_redirecting {
-+ /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */
-+ struct ast_party_id from;
-+
-+ /*! \brief Call is redirecting to a new party (Sent to the caller) */
-+ struct ast_party_id to;
-+
-+ /*! \brief Number of times the call was redirected */
-+ int count;
-+
-+ /*! \brief enum AST_REDIRECTING_REASON value for redirection */
-+ int reason;
-+};
-+
-+/*! \brief
-+ * Structure to describe a channel "technology", ie a channel driver
-+ * See for examples:
-+ * \arg chan_iax2.c - The Inter-Asterisk exchange protocol
-+ * \arg chan_sip.c - The SIP channel driver
-+ * \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
-+ *
-+ * \details
-+ * If you develop your own channel driver, this is where you
-+ * tell the PBX at registration of your driver what properties
-+ * this driver supports and where different callbacks are
-+ * implemented.
-+ */
- struct ast_channel_tech {
- const char * const type;
- const char * const description;
-@@ -239,22 +360,22 @@
-
- int (* const devicestate)(void *data); /*!< Devicestate call back */
-
-- /*!
-- * \brief Start sending a literal DTMF digit
-+ /*!
-+ * \brief Start sending a literal DTMF digit
- *
-- * \note The channel is not locked when this function gets called.
-+ * \note The channel is not locked when this function gets called.
- */
- int (* const send_digit_begin)(struct ast_channel *chan, char digit);
-
-- /*!
-- * \brief Stop sending a literal DTMF digit
-+ /*!
-+ * \brief Stop sending a literal DTMF digit
- *
-- * \note The channel is not locked when this function gets called.
-+ * \note The channel is not locked when this function gets called.
- */
- int (* const send_digit_end)(struct ast_channel *chan, char digit, unsigned int duration);
-
- /*! \brief Call a given phone number (address, etc), but don't
-- take longer than timeout seconds to do so. */
-+ * take longer than timeout seconds to do so. */
- int (* const call)(struct ast_channel *chan, char *addr, int timeout);
-
- /*! \brief Hangup (and possibly destroy) the channel */
-@@ -320,7 +441,7 @@
-
- /*! \brief Retrieve base channel (agent and local) */
- struct ast_channel* (* get_base_channel)(struct ast_channel *chan);
--
-+
- /*! \brief Set base channel (agent and local) */
- int (* set_base_channel)(struct ast_channel *chan, struct ast_channel *base);
-
-@@ -353,7 +474,7 @@
- AST_ADSI_OFFHOOKONLY,
- };
-
--/*!
-+/*!
- * \brief ast_channel states
- *
- * \note Bits 0-15 of state are reserved for the state (up/down) of the line
-@@ -385,7 +506,8 @@
- T38_STATE_NEGOTIATED, /*!< T38 established */
- };
-
--/*! \brief Main Channel structure associated with a channel.
-+/*!
-+ * \brief Main Channel structure associated with a channel.
- * This is the side of it mostly used by the pbx and call management.
- *
- * \note XXX It is important to remember to increment .cleancount each time
-@@ -399,7 +521,6 @@
- * and 8-byte fields causes 4 bytes of padding to be added before many
- * 8-byte fields.
- */
--
- struct ast_channel {
- const struct ast_channel_tech *tech; /*!< Technology (point to channel driver) */
- void *tech_pvt; /*!< Private data used by the technology driver */
-@@ -407,8 +528,8 @@
- void *generatordata; /*!< Current generator data if there is any */
- struct ast_generator *generator; /*!< Current active data generator */
- struct ast_channel *_bridge; /*!< Who are we bridged to, if we're bridged.
-- Who is proxying for us, if we are proxied (i.e. chan_agent).
-- Do not access directly, use ast_bridged_channel(chan) */
-+ * Who is proxying for us, if we are proxied (i.e. chan_agent).
-+ * Do not access directly, use ast_bridged_channel(chan) */
- struct ast_channel *masq; /*!< Channel that will masquerade as us */
- struct ast_channel *masqr; /*!< Who we are masquerading as */
- const char *blockproc; /*!< Procedure causing blocking */
-@@ -424,8 +545,8 @@
- struct ast_trans_pvt *readtrans; /*!< Read translation path */
- struct ast_audiohook_list *audiohooks;
- struct ast_cdr *cdr; /*!< Call Detail Record */
-- struct tone_zone *zone; /*!< Tone zone as set in indications.conf or
-- in the CHANNEL dialplan function */
-+ struct ast_tone_zone *zone; /*!< Tone zone as set in indications.conf or
-+ * in the CHANNEL dialplan function */
- struct ast_channel_monitor *monitor; /*!< Channel monitoring */
- #ifdef HAVE_EPOLL
- struct ast_epoll_data *epfd_data[AST_MAX_FDS];
-@@ -441,11 +562,33 @@
- AST_STRING_FIELD(parkinglot); /*! Default parking lot, if empty, default parking lot */
- AST_STRING_FIELD(dialcontext); /*!< Dial: Extension context that we were called from */
- );
--
-+
- struct timeval whentohangup; /*!< Non-zero, set to actual time when channel is to be hung up */
- pthread_t blocker; /*!< If anyone is blocking, this is them */
- ast_mutex_t lock_dont_use; /*!< Lock a channel for some operations. See ast_channel_lock() */
-- struct ast_callerid cid; /*!< Caller ID, name, presentation etc */
-+
-+ /*!
-+ * \brief Channel Caller ID information.
-+ * \note The caller id information is the caller id of this
-+ * channel when it is used to initiate a call.
-+ */
-+ struct ast_callerid cid;
-+
-+ /*!
-+ * \brief Channel Connected Line ID information.
-+ * \note The connected line information identifies the channel
-+ * connected/bridged to this channel.
-+ */
-+ struct ast_party_connected_line connected;
-+
-+ /*!
-+ * \brief Redirecting/Diversion information
-+ * \note Until struct ast_channel.cid.cid_rdnis is replaced
-+ * with ast_channel.redirecting.from.number, the
-+ * ast_channel.redirecting.from.number field is not used.
-+ */
-+ struct ast_party_redirecting redirecting;
-+
- struct ast_frame dtmff; /*!< DTMF frame */
- struct varshead varshead; /*!< A linked list for channel variables. See \ref AstChanVar */
- ast_group_t callgroup; /*!< Call group for call pickups */
-@@ -460,11 +603,11 @@
- unsigned long outsmpl; /*!< Track the read/written samples for monitor use */
-
- int fds[AST_MAX_FDS]; /*!< File descriptors for channel -- Drivers will poll on
-- these file descriptors, so at least one must be non -1.
-- See \arg \ref AstFileDesc */
-+ * these file descriptors, so at least one must be non -1.
-+ * See \arg \ref AstFileDesc */
- int cdrflags; /*!< Call Detail Record Flags */
- int _softhangup; /*!< Whether or not we have been hung up... Do not set this value
-- directly, use ast_softhangup() */
-+ * directly, use ast_softhangup() */
- int fdno; /*!< Which fd had an event detected on */
- int streamid; /*!< For streaming playback, the schedule ID */
- int vstreamid; /*!< For streaming video playback, the schedule ID */
-@@ -477,9 +620,9 @@
- int amaflags; /*!< Set BEFORE PBX is started to determine AMA flags */
- enum ast_channel_adsicpe adsicpe; /*!< Whether or not ADSI is detected on CPE */
- unsigned int fin; /*!< Frames in counters. The high bit is a debug mask, so
-- the counter is only in the remaining bits */
-+ * the counter is only in the remaining bits */
- unsigned int fout; /*!< Frames out counters. The high bit is a debug mask, so
-- the counter is only in the remaining bits */
-+ * the counter is only in the remaining bits */
- int hangupcause; /*!< Why is the channel hanged up. See causes.h */
- unsigned int flags; /*!< channel flags of AST_FLAG_ type */
- int alertpipe[2];
-@@ -494,7 +637,7 @@
- #endif
- int visible_indication; /*!< Indication currently playing on the channel */
-
-- unsigned short transfercapability; /*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
-+ unsigned short transfercapability; /*!< ISDN Transfer Capability - AST_FLAG_DIGITAL is not enough */
-
- char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */
- char context[AST_MAX_CONTEXT]; /*!< Dialplan: Current extension context */
-@@ -506,17 +649,17 @@
-
- /*! \brief ast_channel_tech Properties */
- enum {
-- /*! \brief Channels have this property if they can accept input with jitter;
-+ /*! \brief Channels have this property if they can accept input with jitter;
- * i.e. most VoIP channels */
- AST_CHAN_TP_WANTSJITTER = (1 << 0),
-- /*! \brief Channels have this property if they can create jitter;
-+ /*! \brief Channels have this property if they can create jitter;
- * i.e. most VoIP channels */
- AST_CHAN_TP_CREATESJITTER = (1 << 1),
- };
-
- /*! \brief ast_channel flags */
- enum {
-- /*! Queue incoming dtmf, to be released when this flag is turned off */
-+ /*! Queue incoming DTMF, to be released when this flag is turned off */
- AST_FLAG_DEFER_DTMF = (1 << 1),
- /*! write should be interrupt generator */
- AST_FLAG_WRITE_INT = (1 << 2),
-@@ -540,14 +683,14 @@
- AST_FLAG_OUTGOING = (1 << 10),
- /*! A DTMF_BEGIN frame has been read from this channel, but not yet an END */
- AST_FLAG_IN_DTMF = (1 << 12),
-- /*! A DTMF_END was received when not IN_DTMF, so the length of the digit is
-+ /*! A DTMF_END was received when not IN_DTMF, so the length of the digit is
- * currently being emulated */
- AST_FLAG_EMULATE_DTMF = (1 << 13),
- /*! This is set to tell the channel not to generate DTMF begin frames, and
- * to instead only generate END frames. */
- AST_FLAG_END_DTMF_ONLY = (1 << 14),
- /*! Flag to show channels that this call is hangup due to the fact that the call
-- was indeed anwered, but in another channel */
-+ was indeed answered, but in another channel */
- AST_FLAG_ANSWERED_ELSEWHERE = (1 << 15),
- /*! This flag indicates that on a masquerade, an active stream should not
- * be carried over */
-@@ -559,7 +702,7 @@
- /*! This flag indicates that the hangup exten should NOT be run when the
- * bridge terminates, this will allow the hangup in the pbx loop to be run instead.
- * */
-- AST_FLAG_BRIDGE_HANGUP_DONT = (1 << 17),
-+ AST_FLAG_BRIDGE_HANGUP_DONT = (1 << 18),
- };
-
- /*! \brief ast_bridge_config flags */
-@@ -572,6 +715,7 @@
- AST_FEATURE_PARKCALL = (1 << 5),
- AST_FEATURE_AUTOMIXMON = (1 << 6),
- AST_FEATURE_NO_H_EXTEN = (1 << 7),
-+ AST_FEATURE_WARNING_ACTIVE = (1 << 8),
- };
-
- /*! \brief bridge configuration */
-@@ -579,6 +723,7 @@
- struct ast_flags features_caller;
- struct ast_flags features_callee;
- struct timeval start_time;
-+ struct timeval nexteventts;
- long feature_timer;
- long timelimit;
- long play_warning;
-@@ -637,13 +782,13 @@
- CHANNEL_MANAGER_RELOAD,
- };
-
--/*!
-+/*!
- * \note None of the datastore API calls lock the ast_channel they are using.
- * So, the channel should be locked before calling the functions that
- * take a channel argument.
- */
-
--/*!
-+/*!
- * \brief Create a channel data store object
- * \deprecated You should use the ast_datastore_alloc() generic function instead.
- */
-@@ -660,19 +805,18 @@
- /*! \brief Inherit datastores from a parent to a child. */
- int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to);
-
--/*!
-- * \brief Add a datastore to a channel
-+/*!
-+ * \brief Add a datastore to a channel
- *
- * \note The channel should be locked before calling this function.
- *
- * \retval 0 success
- * \retval non-zero failure
- */
--
- int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore);
-
--/*!
-- * \brief Remove a datastore from a channel
-+/*!
-+ * \brief Remove a datastore from a channel
- *
- * \note The channel should be locked before calling this function.
- *
-@@ -681,8 +825,8 @@
- */
- int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore);
-
--/*!
-- * \brief Find a datastore on a channel
-+/*!
-+ * \brief Find a datastore on a channel
- *
- * \note The channel should be locked before calling this function.
- *
-@@ -697,8 +841,8 @@
- /*! \brief Change the state of a channel */
- int ast_setstate(struct ast_channel *chan, enum ast_channel_state);
-
--/*!
-- * \brief Create a channel structure
-+/*!
-+ * \brief Create a channel structure
- *
- * \retval NULL failure
- * \retval non-NULL successfully allocated channel
-@@ -708,8 +852,8 @@
- */
- struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const int amaflag, const char *name_fmt, ...) __attribute__((format(printf, 9, 10)));
-
--/*!
-- * \brief Queue an outgoing frame
-+/*!
-+ * \brief Queue an outgoing frame
- *
- * \note The channel does not need to be locked before calling this function.
- */
-@@ -729,14 +873,14 @@
- */
- int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *f);
-
--/*!
-- * \brief Queue a hangup frame
-+/*!
-+ * \brief Queue a hangup frame
- *
- * \note The channel does not need to be locked before calling this function.
- */
- int ast_queue_hangup(struct ast_channel *chan);
-
--/*!
-+/*!
- * \brief Queue a hangup frame with hangupcause set
- *
- * \note The channel does not need to be locked before calling this function.
-@@ -769,6 +913,7 @@
- * \retval 0 success
- * \retval non-zero failure
- *
-+ * \details
- * The supplied payload data is copied into the frame, so the caller's copy
- * is not modified nor freed, and the resulting frame will retain a copy of
- * the data even if the caller frees their local copy.
-@@ -785,8 +930,8 @@
- int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control,
- const void *data, size_t datalen);
-
--/*!
-- * \brief Change channel name
-+/*!
-+ * \brief Change channel name
- *
- * \note The channel must be locked before calling this function.
- */
-@@ -795,15 +940,16 @@
- /*! \brief Free a channel structure */
- void ast_channel_free(struct ast_channel *);
-
--/*!
-- * \brief Requests a channel
-+/*!
-+ * \brief Requests a channel
- *
- * \param type type of channel to request
- * \param format requested channel format (codec)
- * \param data data to pass to the channel requester
- * \param status status
- *
-- * Request a channel of a given type, with data as optional information used
-+ * \details
-+ * Request a channel of a given type, with data as optional information used
- * by the low level module
- *
- * \retval NULL failure
-@@ -812,7 +958,7 @@
- struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
-
- /*!
-- * \brief Request a channel of a given type, with data as optional information used
-+ * \brief Request a channel of a given type, with data as optional information used
- * by the low level module and attempt to place a call on it
- *
- * \param type type of channel to request
-@@ -830,7 +976,7 @@
- int timeout, int *reason, const char *cid_num, const char *cid_name);
-
- /*!
-- * \brief Request a channel of a given type, with data as optional information used
-+ * \brief Request a channel of a given type, with data as optional information used
- * by the low level module and attempt to place a call on it
- * \param type type of channel to request
- * \param format requested channel format
-@@ -846,14 +992,14 @@
- struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data,
- int timeout, int *reason, const char *cid_num, const char *cid_name, struct outgoing_helper *oh);
-
--/*!\brief Register a channel technology (a new channel driver)
-+/*! \brief Register a channel technology (a new channel driver)
- * Called by a channel module to register the kind of channels it supports.
- * \param tech Structure defining channel technology or "type"
- * \return Returns 0 on success, -1 on failure.
- */
- int ast_channel_register(const struct ast_channel_tech *tech);
-
--/*! \brief Unregister a channel technology
-+/*! \brief Unregister a channel technology
- * \param tech Structure defining channel technology or "type" that was previously registered
- * \return No return value.
- */
-@@ -893,7 +1039,7 @@
- int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out);
- #endif
-
--/*! \brief Hang up a channel
-+/*! \brief Hang up a channel
- * \note This function performs a hard hangup on a channel. Unlike the soft-hangup, this function
- * performs all stream stopping, etc, on the channel that needs to end.
- * chan is no longer valid after this call.
-@@ -902,13 +1048,14 @@
- */
- int ast_hangup(struct ast_channel *chan);
-
--/*!
-- * \brief Softly hangup up a channel
-+/*!
-+ * \brief Softly hangup up a channel
- *
- * \param chan channel to be soft-hung-up
- * \param cause Ast hangupcause for hangup
- *
-- * Call the protocol layer, but don't destroy the channel structure
-+ * \details
-+ * Call the protocol layer, but don't destroy the channel structure
- * (use this if you are trying to
- * safely hangup a channel managed by another thread.
- *
-@@ -918,23 +1065,24 @@
- */
- int ast_softhangup(struct ast_channel *chan, int cause);
-
--/*! \brief Softly hangup up a channel (no channel lock)
-+/*! \brief Softly hangup up a channel (no channel lock)
- * \param chan channel to be soft-hung-up
- * \param cause Ast hangupcause for hangup (see cause.h) */
- int ast_softhangup_nolock(struct ast_channel *chan, int cause);
-
--/*! \brief Check to see if a channel is needing hang up
-+/*! \brief Check to see if a channel is needing hang up
- * \param chan channel on which to check for hang up
- * This function determines if the channel is being requested to be hung up.
- * \return Returns 0 if not, or 1 if hang up is requested (including time-out).
- */
- int ast_check_hangup(struct ast_channel *chan);
-
--/*! \brief Compare a offset with the settings of when to hang a channel up
-+/*! \brief Compare a offset with the settings of when to hang a channel up
- * \param chan channel on which to check for hang up
- * \param offset offset in seconds and useconds from current time
- * \return 1, 0, or -1
-- * This function compares a offset from current time with the absolute time
-+ * \details
-+ * This function compares a offset from current time with the absolute time
- * out on a channel (when to hang up). If the absolute time out on a channel
- * is earlier than current time plus the offset, it returns 1, if the two
- * time values are equal, it return 0, otherwise, it return -1.
-@@ -942,11 +1090,12 @@
- int ast_channel_cmpwhentohangup(struct ast_channel *chan, time_t offset) __attribute__((deprecated));
- int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offset);
-
--/*! \brief Set when to hang a channel up
-+/*! \brief Set when to hang a channel up
- *
- * \param chan channel on which to check for hang up
- * \param offset offset in seconds and useconds relative to the current time of when to hang up
- *
-+ * \details
- * This function sets the absolute time out on a channel (when to hang up).
- *
- * \note This function does not require that the channel is locked before
-@@ -957,11 +1106,12 @@
- void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) __attribute__((deprecated));
- void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset);
-
--/*!
-+/*!
- * \brief Answer a channel
-- *
-+ *
- * \param chan channel to answer
- *
-+ * \details
- * This function answers a channel and handles all necessary call
- * setup functions.
- *
-@@ -971,20 +1121,21 @@
- * \retval non-zero on failure
- */
- int ast_answer(struct ast_channel *chan);
--int __ast_answer(struct ast_channel *chan, unsigned int delay);
-+int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer);
-
--/*! \brief Make a call
-+/*! \brief Make a call
- * \param chan which channel to make the call on
- * \param addr destination of the call
- * \param timeout time to wait on for connect
-- * Place a call, take no longer than timeout ms.
-- \return Returns -1 on failure, 0 on not enough time
-- (does not automatically stop ringing), and
-- the number of seconds the connect took otherwise.
-- */
-+ * \details
-+ * Place a call, take no longer than timeout ms.
-+ * \return -1 on failure, 0 on not enough time
-+ * (does not automatically stop ringing), and
-+ * the number of seconds the connect took otherwise.
-+ */
- int ast_call(struct ast_channel *chan, char *addr, int timeout);
-
--/*! \brief Indicates condition of channel
-+/*! \brief Indicates condition of channel
- * \note Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
- * \param chan channel to change the indication
- * \param condition which condition to indicate on the channel
-@@ -1004,33 +1155,37 @@
-
- /* Misc stuff ------------------------------------------------ */
-
--/*! \brief Wait for input on a channel
-+/*! \brief Wait for input on a channel
- * \param chan channel to wait on
- * \param ms length of time to wait on the channel
-- * Wait for input on a channel for a given # of milliseconds (<0 for indefinite).
-- \return Returns < 0 on failure, 0 if nothing ever arrived, and the # of ms remaining otherwise */
-+ * \details
-+ * Wait for input on a channel for a given # of milliseconds (<0 for indefinite).
-+ * \return Returns < 0 on failure, 0 if nothing ever arrived, and the # of ms remaining otherwise
-+ */
- int ast_waitfor(struct ast_channel *chan, int ms);
-
--/*! \brief Wait for a specified amount of time, looking for hangups
-+/*! \brief Wait for a specified amount of time, looking for hangups
- * \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
-+ * \details
- * Waits for a specified amount of time, servicing the channel as required.
- * \return returns -1 on hangup, otherwise 0.
- */
- int ast_safe_sleep(struct ast_channel *chan, int ms);
-
--/*! \brief Wait for a specified amount of time, looking for hangups and a condition argument
-+/*! \brief Wait for a specified amount of time, looking for hangups and a condition argument
- * \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
- * \param cond a function pointer for testing continue condition
- * \param data argument to be passed to the condition test function
- * \return returns -1 on hangup, otherwise 0.
-+ * \details
- * Waits for a specified amount of time, servicing the channel as required. If cond
- * returns 0, this function returns.
- */
- int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data );
-
--/*! \brief Waits for activity on a group of channels
-+/*! \brief Waits for activity on a group of channels
- * \param chan an array of pointers to channels
- * \param n number of channels that are to be waited upon
- * \param fds an array of fds to wait upon
-@@ -1038,44 +1193,50 @@
- * \param exception exception flag
- * \param outfd fd that had activity on it
- * \param ms how long the wait was
-+ * \details
- * Big momma function here. Wait for activity on any of the n channels, or any of the nfds
-- file descriptors.
-- \return Returns the channel with activity, or NULL on error or if an FD
-- came first. If the FD came first, it will be returned in outfd, otherwise, outfd
-- will be -1 */
-+ * file descriptors.
-+ * \return Returns the channel with activity, or NULL on error or if an FD
-+ * came first. If the FD came first, it will be returned in outfd, otherwise, outfd
-+ * will be -1
-+ */
- struct ast_channel *ast_waitfor_nandfds(struct ast_channel **chan, int n,
- int *fds, int nfds, int *exception, int *outfd, int *ms);
-
- /*! \brief Waits for input on a group of channels
-- Wait for input on an array of channels for a given # of milliseconds.
-- \return Return channel with activity, or NULL if none has activity.
-- \param chan an array of pointers to channels
-- \param n number of channels that are to be waited upon
-- \param ms time "ms" is modified in-place, if applicable */
-+ * Wait for input on an array of channels for a given # of milliseconds.
-+ * \return Return channel with activity, or NULL if none has activity.
-+ * \param chan an array of pointers to channels
-+ * \param n number of channels that are to be waited upon
-+ * \param ms time "ms" is modified in-place, if applicable
-+ */
- struct ast_channel *ast_waitfor_n(struct ast_channel **chan, int n, int *ms);
-
- /*! \brief Waits for input on an fd
-- This version works on fd's only. Be careful with it. */
-+ * This version works on fd's only. Be careful with it.
-+ */
- int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception);
-
-
- /*! \brief Reads a frame
- * \param chan channel to read a frame from
- * \return Returns a frame, or NULL on error. If it returns NULL, you
-- best just stop reading frames and assume the channel has been
-- disconnected. */
-+ * best just stop reading frames and assume the channel has been
-+ * disconnected.
-+ */
- struct ast_frame *ast_read(struct ast_channel *chan);
-
--/*! \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
-- \param chan channel to read a frame from
-- \return Returns a frame, or NULL on error. If it returns NULL, you
-- best just stop reading frames and assume the channel has been
-- disconnected.
-- \note Audio is replaced with AST_FRAME_NULL to avoid
-- transcode when the resulting audio is not necessary. */
-+/*! \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
-+ * \param chan channel to read a frame from
-+ * \return Returns a frame, or NULL on error. If it returns NULL, you
-+ * best just stop reading frames and assume the channel has been
-+ * disconnected.
-+ * \note Audio is replaced with AST_FRAME_NULL to avoid
-+ * transcode when the resulting audio is not necessary.
-+ */
- struct ast_frame *ast_read_noaudio(struct ast_channel *chan);
-
--/*! \brief Write a frame to a channel
-+/*! \brief Write a frame to a channel
- * This function writes the given frame to the indicated channel.
- * \param chan destination channel of the frame
- * \param frame frame that will be written
-@@ -1083,7 +1244,7 @@
- */
- int ast_write(struct ast_channel *chan, struct ast_frame *frame);
-
--/*! \brief Write video frame to a channel
-+/*! \brief Write video frame to a channel
- * This function writes the given frame to the indicated channel.
- * \param chan destination channel of the frame
- * \param frame frame that will be written
-@@ -1091,7 +1252,7 @@
- */
- int ast_write_video(struct ast_channel *chan, struct ast_frame *frame);
-
--/*! \brief Write text frame to a channel
-+/*! \brief Write text frame to a channel
- * This function writes the given frame to the indicated channel.
- * \param chan destination channel of the frame
- * \param frame frame that will be written
-@@ -1103,7 +1264,7 @@
- int ast_prod(struct ast_channel *chan);
-
- /*! \brief Sets read format on channel chan
-- * Set read format for channel to whichever component of "format" is best.
-+ * Set read format for channel to whichever component of "format" is best.
- * \param chan channel to change
- * \param format format to change to
- * \return Returns 0 on success, -1 on failure
-@@ -1111,24 +1272,25 @@
- int ast_set_read_format(struct ast_channel *chan, int format);
-
- /*! \brief Sets write format on channel chan
-- * Set write format for channel to whichever component of "format" is best.
-+ * Set write format for channel to whichever component of "format" is best.
- * \param chan channel to change
- * \param format new format for writing
- * \return Returns 0 on success, -1 on failure
- */
- int ast_set_write_format(struct ast_channel *chan, int format);
-
--/*!
-- * \brief Sends text to a channel
-+/*!
-+ * \brief Sends text to a channel
- *
- * \param chan channel to act upon
- * \param text string of text to send on the channel
- *
-+ * \details
- * Write text to a display on a channel
- *
- * \note The channel does not need to be locked before calling this function.
- *
-- * \retval 0 on success
-+ * \retval 0 on success
- * \retval -1 on failure
- */
- int ast_sendtext(struct ast_channel *chan, const char *text);
-@@ -1136,31 +1298,28 @@
- /*! \brief Receives a text character from a channel
- * \param chan channel to act upon
- * \param timeout timeout in milliseconds (0 for infinite wait)
-+ * \details
- * Read a char of text from a channel
-- * Returns 0 on success, -1 on failure
-+ * \return 0 on success, -1 on failure
- */
- int ast_recvchar(struct ast_channel *chan, int timeout);
-
--/*! \brief Send a DTMF digit to a channel
-- * Send a DTMF digit to a channel.
-+/*! \brief Send a DTMF digit to a channel.
- * \param chan channel to act upon
- * \param digit the DTMF digit to send, encoded in ASCII
- * \param duration the duration of the digit ending in ms
-- * \return Returns 0 on success, -1 on failure
-+ * \return 0 on success, -1 on failure
- */
- int ast_senddigit(struct ast_channel *chan, char digit, unsigned int duration);
-
--/*! \brief Send a DTMF digit to a channel
-- * Send a DTMF digit to a channel.
-+/*! \brief Send a DTMF digit to a channel.
- * \param chan channel to act upon
- * \param digit the DTMF digit to send, encoded in ASCII
-- * \return Returns 0 on success, -1 on failure
-+ * \return 0 on success, -1 on failure
- */
- int ast_senddigit_begin(struct ast_channel *chan, char digit);
-
--/*! \brief Send a DTMF digit to a channel
--
-- * Send a DTMF digit to a channel.
-+/*! \brief Send a DTMF digit to a channel.
- * \param chan channel to act upon
- * \param digit the DTMF digit to send, encoded in ASCII
- * \param duration the duration of the digit ending in ms
-@@ -1177,10 +1336,10 @@
- char *ast_recvtext(struct ast_channel *chan, int timeout);
-
- /*! \brief Browse channels in use
-- * Browse the channels currently in use
-+ * Browse the channels currently in use
- * \param prev where you want to start in the channel list
- * \return Returns the next channel in the list, NULL on end.
-- * If it returns a channel, that channel *has been locked*!
-+ * If it returns a channel, that channel *has been locked*!
- */
- struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev);
-
-@@ -1200,14 +1359,26 @@
- struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
- const char *context);
-
--/*! ! \brief Waits for a digit
-+/*! \brief Search for a channel based on the passed channel matching callback
-+ * Search for a channel based on the specified is_match callback, and return the
-+ * first channel that we match. When returned, the channel will be locked. Note
-+ * that the is_match callback is called with the passed channel locked, and should
-+ * return 0 if there is no match, and non-zero if there is.
-+ * \param is_match callback executed on each channel until non-zero is returned, or we
-+ * run out of channels to search.
-+ * \param data data passed to the is_match callback during each invocation.
-+ * \return Returns the matched channel, or NULL if no channel was matched.
-+ */
-+struct ast_channel *ast_channel_search_locked(int (*is_match)(struct ast_channel *, void *), void *data);
-+
-+/*! \brief Waits for a digit
- * \param c channel to wait for a digit on
- * \param ms how many milliseconds to wait
- * \return Returns <0 on error, 0 on no entry, and the digit on success. */
- int ast_waitfordigit(struct ast_channel *c, int ms);
-
- /*! \brief Wait for a digit
-- Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
-+ * Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
- * \param c channel to wait for a digit on
- * \param ms how many milliseconds to wait
- * \param audiofd audio file descriptor to write to if audio frames are received
-@@ -1215,105 +1386,109 @@
- * \return Returns 1 if ctrlfd becomes available */
- int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
-
--/*! Reads multiple digits
-+/*! \brief Reads multiple digits
- * \param c channel to read from
- * \param s string to read in to. Must be at least the size of your length
- * \param len how many digits to read (maximum)
- * \param timeout how long to timeout between digits
- * \param rtimeout timeout to wait on the first digit
- * \param enders digits to end the string
-- * Read in a digit string "s", max length "len", maximum timeout between
-- digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
-- for the first digit. Returns 0 on normal return, or 1 on a timeout. In the case of
-- a timeout, any digits that were read before the timeout will still be available in s.
-- RETURNS 2 in full version when ctrlfd is available, NOT 1*/
-+ * \details
-+ * Read in a digit string "s", max length "len", maximum timeout between
-+ * digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
-+ * for the first digit.
-+ * \return Returns 0 on normal return, or 1 on a timeout. In the case of
-+ * a timeout, any digits that were read before the timeout will still be available in s.
-+ * RETURNS 2 in full version when ctrlfd is available, NOT 1
-+ */
- int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
- int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd);
-
- /*! \brief Report DTMF on channel 0 */
--#define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0)
-+#define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0)
- /*! \brief Report DTMF on channel 1 */
--#define AST_BRIDGE_DTMF_CHANNEL_1 (1 << 1)
-+#define AST_BRIDGE_DTMF_CHANNEL_1 (1 << 1)
- /*! \brief Return all voice frames on channel 0 */
--#define AST_BRIDGE_REC_CHANNEL_0 (1 << 2)
-+#define AST_BRIDGE_REC_CHANNEL_0 (1 << 2)
- /*! \brief Return all voice frames on channel 1 */
--#define AST_BRIDGE_REC_CHANNEL_1 (1 << 3)
-+#define AST_BRIDGE_REC_CHANNEL_1 (1 << 3)
- /*! \brief Ignore all signal frames except NULL */
--#define AST_BRIDGE_IGNORE_SIGS (1 << 4)
-+#define AST_BRIDGE_IGNORE_SIGS (1 << 4)
-
-
--/*! \brief Makes two channel formats compatible
-+/*! \brief Makes two channel formats compatible
- * \param c0 first channel to make compatible
- * \param c1 other channel to make compatible
-- * Set two channels to compatible formats -- call before ast_channel_bridge in general .
-+ * \details
-+ * Set two channels to compatible formats -- call before ast_channel_bridge in general .
- * \return Returns 0 on success and -1 if it could not be done */
- int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
-
--/*! Bridge two channels together (early)
-+/*! \brief Bridge two channels together (early)
- * \param c0 first channel to bridge
- * \param c1 second channel to bridge
-+ * \details
- * Bridge two channels (c0 and c1) together early. This implies either side may not be answered yet.
- * \return Returns 0 on success and -1 if it could not be done */
- int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
-
--/*! Bridge two channels together
-+/*! \brief Bridge two channels together
- * \param c0 first channel to bridge
- * \param c1 second channel to bridge
- * \param config config for the channels
- * \param fo destination frame(?)
- * \param rc destination channel(?)
-+ * \details
- * Bridge two channels (c0 and c1) together. If an important frame occurs, we return that frame in
-- *rf (remember, it could be NULL) and which channel (0 or 1) in rc */
-+ * *rf (remember, it could be NULL) and which channel (0 or 1) in rc
-+ */
- /* int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); */
- int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,
- struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc);
-
--/*!
-+/*!
- * \brief Weird function made for call transfers
- *
- * \param original channel to make a copy of
- * \param clone copy of the original channel
- *
-+ * \details
- * This is a very strange and freaky function used primarily for transfer. Suppose that
- * "original" and "clone" are two channels in random situations. This function takes
- * the guts out of "clone" and puts them into the "original" channel, then alerts the
- * channel driver of the change, asking it to fixup any private information (like the
- * p->owner pointer) that is affected by the change. The physical layer of the original
-- * channel is hung up.
-+ * channel is hung up.
- *
- * \note Neither channel passed here needs to be locked before calling this function.
- */
- int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
-
--/*! Gives the string form of a given cause code */
--/*!
-+/*! \brief Gives the string form of a given cause code.
-+ *
- * \param state cause to get the description of
-- * Give a name to a cause code
-- * Returns the text form of the binary cause code given
-+ * \return the text form of the binary cause code given
- */
- const char *ast_cause2str(int state) attribute_pure;
-
--/*! Convert the string form of a cause code to a number */
--/*!
-+/*! \brief Convert the string form of a cause code to a number
-+ *
- * \param name string form of the cause
-- * Returns the cause code
-+ * \return the cause code
- */
- int ast_str2cause(const char *name) attribute_pure;
-
--/*! Gives the string form of a given channel state */
--/*!
-+/*! \brief Gives the string form of a given channel state
-+ *
- * \param ast_channel_state state to get the name of
-- * Give a name to a state
-- * Returns the text form of the binary state given
-+ * \return the text form of the binary state given
- */
- const char *ast_state2str(enum ast_channel_state);
-
--/*! Gives the string form of a given transfer capability */
--/*!
-- * \param transfercapability transfercapabilty to get the name of
-- * Give a name to a transfercapbility
-- * See above
-- * Returns the text form of the binary transfer capability
-+/*! \brief Gives the string form of a given transfer capability
-+ *
-+ * \param transfercapability transfer capability to get the name of
-+ * \return the text form of the binary transfer capability
- */
- char *ast_transfercapability2str(int transfercapability) attribute_const;
-
-@@ -1322,63 +1497,66 @@
- none or a subset of those features, and you should not count on this if you want your
- asterisk application to be portable. They're mainly useful for tweaking performance */
-
--/*! Sets an option on a channel */
--/*!
-+/*! \brief Sets an option on a channel
-+ *
- * \param channel channel to set options on
- * \param option option to change
- * \param data data specific to option
- * \param datalen length of the data
- * \param block blocking or not
-- * Set an option on a channel (see frame.h), optionally blocking awaiting the reply
-- * Returns 0 on success and -1 on failure
-+ * \details
-+ * Set an option on a channel (see frame.h), optionally blocking awaiting the reply
-+ * \return 0 on success and -1 on failure
- */
- int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block);
-
--/*! Pick the best codec */
--/* Choose the best codec... Uhhh... Yah. */
-+/*! Pick the best codec
-+ * Choose the best codec... Uhhh... Yah. */
- int ast_best_codec(int fmts);
-
-
--/*! Checks the value of an option */
--/*!
-+/*! \brief Checks the value of an option
-+ *
- * Query the value of an option
- * Works similarly to setoption except only reads the options.
- */
- int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
-
--/*! Checks for HTML support on a channel */
--/*! Returns 0 if channel does not support HTML or non-zero if it does */
-+/*! \brief Checks for HTML support on a channel
-+ * \return 0 if channel does not support HTML or non-zero if it does */
- int ast_channel_supports_html(struct ast_channel *channel);
-
--/*! Sends HTML on given channel */
--/*! Send HTML or URL on link. Returns 0 on success or -1 on failure */
-+/*! \brief Sends HTML on given channel
-+ * Send HTML or URL on link.
-+ * \return 0 on success or -1 on failure */
- int ast_channel_sendhtml(struct ast_channel *channel, int subclass, const char *data, int datalen);
-
--/*! Sends a URL on a given link */
--/*! Send URL on link. Returns 0 on success or -1 on failure */
-+/*! \brief Sends a URL on a given link
-+ * Send URL on link.
-+ * \return 0 on success or -1 on failure */
- int ast_channel_sendurl(struct ast_channel *channel, const char *url);
-
--/*! Defers DTMF */
--/*! Defer DTMF so that you only read things like hangups and audio. Returns
-- non-zero if channel was already DTMF-deferred or 0 if channel is just now
-- being DTMF-deferred */
-+/*! \brief Defers DTMF so that you only read things like hangups and audio.
-+ * \return non-zero if channel was already DTMF-deferred or
-+ * 0 if channel is just now being DTMF-deferred
-+ */
- int ast_channel_defer_dtmf(struct ast_channel *chan);
-
--/*! Undo defer. ast_read will return any dtmf characters that were queued */
-+/*! Undo defer. ast_read will return any DTMF characters that were queued */
- void ast_channel_undefer_dtmf(struct ast_channel *chan);
-
- /*! Initiate system shutdown -- prevents new channels from being allocated.
-- If "hangup" is non-zero, all existing channels will receive soft
-- hangups */
-+ * \param hangup If "hangup" is non-zero, all existing channels will receive soft
-+ * hangups */
- void ast_begin_shutdown(int hangup);
-
- /*! Cancels an existing shutdown and returns to normal operation */
- void ast_cancel_shutdown(void);
-
--/*! Returns number of active/allocated channels */
-+/*! \return number of active/allocated channels */
- int ast_active_channels(void);
-
--/*! Returns non-zero if Asterisk is being shut down */
-+/*! \return non-zero if Asterisk is being shut down */
- int ast_shutting_down(void);
-
- /*! Activate a given generator */
-@@ -1411,15 +1589,15 @@
- int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, int vol);
-
- /*!
-- * \brief Automatically service a channel for us...
-+ * \brief Automatically service a channel for us...
- *
- * \retval 0 success
- * \retval -1 failure, or the channel is already being autoserviced
- */
- int ast_autoservice_start(struct ast_channel *chan);
-
--/*!
-- * \brief Stop servicing a channel for us...
-+/*!
-+ * \brief Stop servicing a channel for us...
- *
- * \note if chan is locked prior to calling ast_autoservice_stop, it
- * is likely that there will be a deadlock between the thread that calls
-@@ -1427,7 +1605,7 @@
- * that chan is not locked prior to this call
- *
- * \retval 0 success
-- * \retval -1 error, or the channel has been hungup
-+ * \retval -1 error, or the channel has been hungup
- */
- int ast_autoservice_stop(struct ast_channel *chan);
-
-@@ -1436,97 +1614,107 @@
- *
- * \arg rate number of timer ticks per second
- *
-+ * \details
- * If timers are supported, force a scheduled expiration on the
-- * timer fd, at which point we call the callback function / data
-+ * timer fd, at which point we call the callback function / data
- *
-- * Call this function with a rate of 0 to turn off the timer ticks
-+ * \note Call this function with a rate of 0 to turn off the timer ticks
- */
- int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data);
-
--/*! \brief Transfer a channel (if supported). Returns -1 on error, 0 if not supported
-- and 1 if supported and requested
-- \param chan current channel
-- \param dest destination extension for transfer
--*/
-+/*! \brief Transfer a channel (if supported).
-+ * \retval -1 on error
-+ * \retval 0 if not supported
-+ * \retval 1 if supported and requested
-+ * \param chan current channel
-+ * \param dest destination extension for transfer
-+ */
- int ast_transfer(struct ast_channel *chan, char *dest);
-
--/*! \brief Start masquerading a channel
-- XXX This is a seriously whacked out operation. We're essentially putting the guts of
-- the clone channel into the original channel. Start by killing off the original
-- channel's backend. I'm not sure we're going to keep this function, because
-- while the features are nice, the cost is very high in terms of pure nastiness. XXX
-- \param chan Channel to masquerade
--*/
-+/*! \brief Start masquerading a channel
-+ * \details
-+ * XXX This is a seriously whacked out operation. We're essentially putting the guts of
-+ * the clone channel into the original channel. Start by killing off the original
-+ * channel's backend. I'm not sure we're going to keep this function, because
-+ * while the features are nice, the cost is very high in terms of pure nastiness. XXX
-+ * \param chan Channel to masquerade
-+ */
- int ast_do_masquerade(struct ast_channel *chan);
-
--/*! \brief Find bridged channel
-- \param chan Current channel
--*/
-+/*! \brief Find bridged channel
-+ * \param chan Current channel
-+ */
- struct ast_channel *ast_bridged_channel(struct ast_channel *chan);
-
- /*!
-- \brief Inherits channel variable from parent to child channel
-- \param parent Parent channel
-- \param child Child channel
--
-- Scans all channel variables in the parent channel, looking for those
-- that should be copied into the child channel.
-- Variables whose names begin with a single '_' are copied into the
-- child channel with the prefix removed.
-- Variables whose names begin with '__' are copied into the child
-- channel with their names unchanged.
--*/
-+ * \brief Inherits channel variable from parent to child channel
-+ * \param parent Parent channel
-+ * \param child Child channel
-+ *
-+ * \details
-+ * Scans all channel variables in the parent channel, looking for those
-+ * that should be copied into the child channel.
-+ * Variables whose names begin with a single '_' are copied into the
-+ * child channel with the prefix removed.
-+ * Variables whose names begin with '__' are copied into the child
-+ * channel with their names unchanged.
-+ */
- void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child);
-
- /*!
-- \brief adds a list of channel variables to a channel
-- \param chan the channel
-- \param vars a linked list of variables
--
-- Variable names can be for a regular channel variable or a dialplan function
-- that has the ability to be written to.
--*/
-+ * \brief adds a list of channel variables to a channel
-+ * \param chan the channel
-+ * \param vars a linked list of variables
-+ *
-+ * \details
-+ * Variable names can be for a regular channel variable or a dialplan function
-+ * that has the ability to be written to.
-+ */
- void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars);
-
- /*!
-- \brief An opaque 'object' structure use by silence generators on channels.
-+ * \brief An opaque 'object' structure use by silence generators on channels.
- */
- struct ast_silence_generator;
-
- /*!
-- \brief Starts a silence generator on the given channel.
-- \param chan The channel to generate silence on
-- \return An ast_silence_generator pointer, or NULL if an error occurs
--
-- This function will cause SLINEAR silence to be generated on the supplied
-- channel until it is disabled; if the channel cannot be put into SLINEAR
-- mode then the function will fail.
--
-- The pointer returned by this function must be preserved and passed to
-- ast_channel_stop_silence_generator when you wish to stop the silence
-- generation.
-+ * \brief Starts a silence generator on the given channel.
-+ * \param chan The channel to generate silence on
-+ * \return An ast_silence_generator pointer, or NULL if an error occurs
-+ *
-+ * \details
-+ * This function will cause SLINEAR silence to be generated on the supplied
-+ * channel until it is disabled; if the channel cannot be put into SLINEAR
-+ * mode then the function will fail.
-+ *
-+ * \note
-+ * The pointer returned by this function must be preserved and passed to
-+ * ast_channel_stop_silence_generator when you wish to stop the silence
-+ * generation.
- */
- struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan);
-
- /*!
-- \brief Stops a previously-started silence generator on the given channel.
-- \param chan The channel to operate on
-- \param state The ast_silence_generator pointer return by a previous call to
-- ast_channel_start_silence_generator.
-- \return nothing
--
-- This function will stop the operating silence generator and return the channel
-- to its previous write format.
-+ * \brief Stops a previously-started silence generator on the given channel.
-+ * \param chan The channel to operate on
-+ * \param state The ast_silence_generator pointer return by a previous call to
-+ * ast_channel_start_silence_generator.
-+ * \return nothing
-+ *
-+ * \details
-+ * This function will stop the operating silence generator and return the channel
-+ * to its previous write format.
- */
- void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state);
-
- /*!
-- \brief Check if the channel can run in internal timing mode.
-- \param chan The channel to check
-- \return boolean
--
-- This function will return 1 if internal timing is enabled and the timing
-- device is available.
-+ * \brief Check if the channel can run in internal timing mode.
-+ * \param chan The channel to check
-+ * \return boolean
-+ *
-+ * \details
-+ * This function will return 1 if internal timing is enabled and the timing
-+ * device is available.
- */
- int ast_internal_timing_enabled(struct ast_channel *chan);
-
-@@ -1575,12 +1763,13 @@
- }
- #endif
-
--/*! \brief Waits for activity on a group of channels
-+/*! \brief Waits for activity on a group of channels
- * \param nfds the maximum number of file descriptors in the sets
- * \param rfds file descriptors to check for read availability
- * \param wfds file descriptors to check for write availability
- * \param efds file descriptors to check for exceptions (OOB data)
- * \param tvp timeout while waiting for events
-+ * \details
- * This is the same as a standard select(), except it guarantees the
- * behaviour where the passed struct timeval is updated with how much
- * time was not slept while waiting for the specified events
-@@ -1638,7 +1827,7 @@
- char *ast_print_group(char *buf, int buflen, ast_group_t group);
-
- /*! \brief Convert enum channelreloadreason to text string for manager event
-- \param reason Enum channelreloadreason - reason for reload (manager, cli, start etc)
-+ * \param reason The reason for reload (manager, cli, start etc)
- */
- const char *channelreloadreason2txt(enum channelreloadreason reason);
-
-@@ -1646,9 +1835,9 @@
- struct ast_variable *ast_channeltype_list(void);
-
- /*!
-- \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
-- \param reason The integer argument, usually taken from AST_CONTROL_ macros
-- \return char pointer explaining the code
-+ * \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
-+ * \param reason The integer argument, usually taken from AST_CONTROL_ macros
-+ * \return char pointer explaining the code
- */
- const char *ast_channel_reason2str(int reason);
-
-@@ -1658,10 +1847,70 @@
- struct ast_channel *chan;
- char *category;
- char *group;
-- AST_LIST_ENTRY(ast_group_info) list;
-+ AST_LIST_ENTRY(ast_group_info) list;
- };
-
-
-+void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src);
-+
-+void ast_party_connected_line_init(struct ast_party_connected_line *init);
-+void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src);
-+void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide);
-+void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src);
-+void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid);
-+void ast_party_connected_line_free(struct ast_party_connected_line *doomed);
-+
-+void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src);
-+void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide);
-+void ast_party_redirecting_free(struct ast_party_redirecting *doomed);
-+
-+void ast_copy_caller_to_connected(struct ast_party_connected_line *dest, const struct ast_callerid *src);
-+void ast_copy_connected_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src);
-+
-+/*!
-+ * \brief Set the connected line id information in the Asterisk channel
-+ *
-+ * \note The channel does not need to be locked before calling this function.
-+ */
-+void ast_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected);
-+
-+/*!
-+ * \brief Parse connected line indication frame data
-+ */
-+int ast_parse_connected_line_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected);
-+
-+/*!
-+ * \brief Indicate that the connected line has changed
-+ */
-+void ast_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected);
-+
-+/*!
-+ * \brief Queue a connected line update frame on a channel
-+ */
-+void ast_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected);
-+
-+/*!
-+ * \brief Set the redirecting id information in the Asterisk channel
-+ *
-+ * \note The channel does not need to be locked before calling this function.
-+ */
-+void ast_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
-+
-+/*!
-+ * \brief Parse redirecting indication frame data
-+ */
-+int ast_parse_redirecting_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting);
-+
-+/*!
-+ * \brief Indicate that the redirecting has changed
-+ */
-+void ast_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
-+
-+/*!
-+ * \brief Queue a redirecting update frame on a channel
-+ */
-+void ast_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
-+
- #if defined(__cplusplus) || defined(c_plusplus)
- }
- #endif
-Index: include/asterisk/_private.h
-===================================================================
---- a/include/asterisk/_private.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/_private.h (.../team/group/issue14292) (revision 178988)
-@@ -24,6 +24,7 @@
- int astdb_init(void); /*!< Provided by db.c */
- void ast_channels_init(void); /*!< Provided by channel.c */
- void ast_builtins_init(void); /*!< Provided by cli.c */
-+int ast_cli_perms_init(int reload); /*!< Provided by cli.c */
- int dnsmgr_init(void); /*!< Provided by dnsmgr.c */
- void dnsmgr_start_refresh(void); /*!< Provided by dnsmgr.c */
- int dnsmgr_reload(void); /*!< Provided by dnsmgr.c */
-@@ -38,6 +39,8 @@
- int ast_http_reload(void); /*!< Provided by http.c */
- int ast_tps_init(void); /*!< Provided by taskprocessor.c */
- int ast_timing_init(void); /*!< Provided by timing.c */
-+int ast_indications_init(void); /*!< Provided by indications.c */
-+int ast_indications_reload(void);/*!< Provided by indications.c */
-
- /*!
- * \brief Reload asterisk modules.
-@@ -56,4 +59,10 @@
- */
- int ast_module_reload(const char *name);
-
-+/*! \brief Load XML documentation. Provided by xmldoc.c
-+ * \retval 1 on error.
-+ * \retval 0 on success.
-+ */
-+int ast_xmldoc_load_documentation(void);
-+
- #endif /* _ASTERISK__PRIVATE_H */
-Index: include/asterisk/manager.h
-===================================================================
---- a/include/asterisk/manager.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/manager.h (.../team/group/issue14292) (revision 178988)
-@@ -147,8 +147,8 @@
- const char *synopsis,
- const char *description);
-
--/*! \brief Unregister a registred manager command
-- \param action Name of registred Action:
-+/*! \brief Unregister a registered manager command
-+ \param action Name of registered Action:
- */
- int ast_manager_unregister( char *action );
-
-Index: include/asterisk/features.h
-===================================================================
---- a/include/asterisk/features.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/features.h (.../team/group/issue14292) (revision 178988)
-@@ -67,6 +67,7 @@
- #define AST_FEATURE_RETURN_STOREDIGITS 22
- #define AST_FEATURE_RETURN_SUCCESS 23
- #define AST_FEATURE_RETURN_KEEPTRYING 24
-+#define AST_FEATURE_RETURN_PARKFAILED 25
-
- /*!
- * \brief Park a call and read back parked location
-Index: include/asterisk/app.h
-===================================================================
---- a/include/asterisk/app.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/app.h (.../team/group/issue14292) (revision 178988)
-@@ -23,12 +23,17 @@
- #ifndef _ASTERISK_APP_H
- #define _ASTERISK_APP_H
-
-+#include "asterisk/strings.h"
-+#include "asterisk/threadstorage.h"
-+
- struct ast_flags64;
-
- #if defined(__cplusplus) || defined(c_plusplus)
- extern "C" {
- #endif
-
-+AST_THREADSTORAGE_EXTERNAL(global_app_buf);
-+
- /* IVR stuff */
-
- /*! \brief Callback function for IVR
-@@ -485,12 +490,17 @@
- /*! \brief Allow to record message and have a review option */
- int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path);
-
--/*! \brief Decode an encoded control or extended ASCII character */
-+/*! \brief Decode an encoded control or extended ASCII character
-+ \return Returns a pointer to the result string
-+*/
- int ast_get_encoded_char(const char *stream, char *result, size_t *consumed);
-
--/*! \brief Decode a string which may contain multiple encoded control or extended ASCII characters */
--int ast_get_encoded_str(const char *stream, char *result, size_t result_size);
-+/*! \brief Decode a stream of encoded control or extended ASCII characters */
-+char *ast_get_encoded_str(const char *stream, char *result, size_t result_len);
-
-+/*! \brief Decode a stream of encoded control or extended ASCII characters */
-+int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream);
-+
- /*! \brief Common routine for child processes, to close all fds prior to exec(2) */
- void ast_close_fds_above_n(int n);
-
-Index: include/asterisk/res_odbc.h
-===================================================================
---- a/include/asterisk/res_odbc.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/res_odbc.h (.../team/group/issue14292) (revision 178988)
-@@ -31,28 +31,34 @@
- #include <sqlext.h>
- #include <sqltypes.h>
- #include "asterisk/linkedlists.h"
-+#include "asterisk/strings.h"
-
- typedef enum { ODBC_SUCCESS=0, ODBC_FAIL=-1} odbc_status;
-
-+/*! \brief Flags for use with ast_odbc_request_obj2 */
-+enum {
-+ RES_ODBC_SANITY_CHECK = (1 << 0),
-+ RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1),
-+};
-+
- /*! \brief ODBC container */
- struct odbc_obj {
- ast_mutex_t lock;
-- SQLHDBC con; /* ODBC Connection Handle */
-- struct odbc_class *parent; /* Information about the connection is protected */
-- struct timeval last_used;
-+ SQLHDBC con; /*!< ODBC Connection Handle */
-+ struct odbc_class *parent; /*!< Information about the connection is protected */
-+ struct timeval last_used; /*!< Used by idlecheck to determine if the connection should be renegotiated */
- #ifdef DEBUG_THREADS
- char file[80];
- char function[80];
- int lineno;
- #endif
-- unsigned int used:1;
-+ unsigned int used:1; /*!< Is this connection currently in use? */
- unsigned int up:1;
-+ unsigned int tx:1; /*!< Should this connection be unshared, regardless of the class setting? */
-+ struct odbc_txn_frame *txf; /*!< Reference back to the transaction frame, if applicable */
- AST_LIST_ENTRY(odbc_obj) list;
- };
-
--/*!\brief These aren't used in any API calls, but they are kept in a common
-- * location, simply for convenience and to avoid duplication.
-- */
- struct odbc_cache_columns {
- char *name;
- SQLSMALLINT type;
-@@ -106,12 +112,31 @@
- * when the thread is done by calling odbc_release_obj(), below.
- */
- #ifdef DEBUG_THREADS
-+struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno);
-+#define ast_odbc_request_obj2(a, b) _ast_odbc_request_obj2(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__)
-+#else
-+struct odbc_obj *ast_odbc_request_obj2(const char *name, struct ast_flags flags);
-+#endif
-+
-+#ifdef DEBUG_THREADS
- struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno);
- #define ast_odbc_request_obj(a, b) _ast_odbc_request_obj(a, b, __FILE__, __PRETTY_FUNCTION__, __LINE__)
- #else
- struct odbc_obj *ast_odbc_request_obj(const char *name, int check);
- #endif
-
-+/*!
-+ * \brief Retrieve a stored ODBC object, if a transaction has been started.
-+ * \param chan Channel associated with the transaction.
-+ * \param objname Name of the database handle. This name corresponds to the name passed
-+ * to ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the
-+ * existence of this parameter name explicitly allows for multiple transactions to be open
-+ * at once, albeit to different databases.
-+ * \retval A stored ODBC object, if a transaction was already started.
-+ * \retval NULL, if no transaction yet exists.
-+ */
-+struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname);
-+
- /*!
- * \brief Releases an ODBC object previously allocated by odbc_request_obj()
- * \param obj The ODBC object
-@@ -183,4 +208,14 @@
- */
- #define ast_odbc_release_table(ptr) if (ptr) { AST_RWLIST_UNLOCK(&(ptr)->columns); }
-
-+/*!\brief Wrapper for SQLGetData to use with dynamic strings
-+ * \param buf Address of the pointer to the ast_str structure.
-+ * \param maxlen The maximum size of the resulting string, or 0 for no limit.
-+ * \param StatementHandle The statement handle from which to retrieve data.
-+ * \param ColumnNumber Column number (1-based offset) for which to retrieve data.
-+ * \param TargetType The SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR)
-+ * \param StrLen_or_Ind A pointer to a length indicator, specifying the total length of data.
-+ */
-+SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind);
-+
- #endif /* _ASTERISK_RES_ODBC_H */
-Index: include/asterisk/slinfactory.h
-===================================================================
---- a/include/asterisk/slinfactory.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/slinfactory.h (.../team/group/issue14292) (revision 178988)
-@@ -38,10 +38,11 @@
- size_t holdlen; /*!< Number of samples currently in the hold */
- unsigned int size; /*!< Number of samples currently in the factory */
- unsigned int format; /*!< Current format the translation path is converting from */
-+ unsigned int output_format; /*!< The output format desired */
- };
-
- /*!
-- * \brief Initialize an slinfactory
-+ * \brief Initialize a slinfactory
- *
- * \param sf The slinfactory to initialize
- *
-@@ -50,6 +51,16 @@
- void ast_slinfactory_init(struct ast_slinfactory *sf);
-
- /*!
-+ * \brief Initialize a slinfactory
-+ *
-+ * \param sf The slinfactory to initialize
-+ * \param sample_rate The output sample rate desired
-+ *
-+ * \return 0 on success, non-zero on failure
-+ */
-+int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_rate);
-+
-+/*!
- * \brief Destroy the contents of a slinfactory
- *
- * \param sf The slinfactory that is no longer needed
-@@ -63,7 +74,7 @@
- void ast_slinfactory_destroy(struct ast_slinfactory *sf);
-
- /*!
-- * \brief Feed audio into an slinfactory
-+ * \brief Feed audio into a slinfactory
- *
- * \param sf The slinfactory to feed into
- * \param f Frame containing audio to feed in
-@@ -73,7 +84,7 @@
- int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f);
-
- /*!
-- * \brief Read samples from an slinfactory
-+ * \brief Read samples from a slinfactory
- *
- * \param sf The slinfactory to read from
- * \param buf Buffer to put samples into
-@@ -84,7 +95,7 @@
- int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples);
-
- /*!
-- * \brief Retrieve number of samples currently in an slinfactory
-+ * \brief Retrieve number of samples currently in a slinfactory
- *
- * \param sf The slinfactory to peek into
- *
-@@ -93,7 +104,7 @@
- unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf);
-
- /*!
-- * \brief Flush the contents of an slinfactory
-+ * \brief Flush the contents of a slinfactory
- *
- * \param sf The slinfactory to flush
- *
-Index: include/asterisk/rtp.h
-===================================================================
---- a/include/asterisk/rtp.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/rtp.h (.../team/group/issue14292) (revision 178988)
-@@ -84,6 +84,12 @@
- /*! T.140 Redundancy structure*/
- struct rtp_red;
-
-+/*! \brief The value of each payload format mapping: */
-+struct rtpPayloadType {
-+ int isAstFormat; /*!< whether the following code is an AST_FORMAT */
-+ int code;
-+};
-+
- /*! \brief This is the structure that binds a channel (SIP/Jingle/H.323) to the RTP subsystem
- */
- struct ast_rtp_protocol {
-@@ -136,7 +142,7 @@
- * \param io
- * \param rtcpenable
- * \param callbackmode
-- * \returns A representation (structure) of an RTP session.
-+ * \return A representation (structure) of an RTP session.
- */
- struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode);
-
-@@ -150,7 +156,7 @@
- * \param rtcpenable
- * \param callbackmode
- * \param in
-- * \returns A representation (structure) of an RTP session.
-+ * \return A representation (structure) of an RTP session.
- */
- struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode, struct in_addr in);
-
-@@ -209,22 +215,66 @@
- /*! \brief clear payload type */
- void ast_rtp_unset_m_type(struct ast_rtp* rtp, int pt);
-
--/*! \brief Initiate payload type to a known MIME media type for a codec */
-+/*! \brief Set payload type to a known MIME media type for a codec
-+ *
-+ * \param rtp RTP structure to modify
-+ * \param pt Payload type entry to modify
-+ * \param mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
-+ * \param mimeSubtype MIME subtype of media stream (typically a codec name)
-+ * \param options Zero or more flags from the ast_rtp_options enum
-+ *
-+ * This function 'fills in' an entry in the list of possible formats for
-+ * a media stream associated with an RTP structure.
-+ *
-+ * \retval 0 on success
-+ * \retval -1 if the payload type is out of range
-+ * \retval -2 if the mimeType/mimeSubtype combination was not found
-+ */
- int ast_rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
- char *mimeType, char *mimeSubtype,
- enum ast_rtp_options options);
-
-+/*! \brief Set payload type to a known MIME media type for a codec with a specific sample rate
-+ *
-+ * \param rtp RTP structure to modify
-+ * \param pt Payload type entry to modify
-+ * \param mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
-+ * \param mimeSubtype MIME subtype of media stream (typically a codec name)
-+ * \param options Zero or more flags from the ast_rtp_options enum
-+ * \param sample_rate The sample rate of the media stream
-+ *
-+ * This function 'fills in' an entry in the list of possible formats for
-+ * a media stream associated with an RTP structure.
-+ *
-+ * \retval 0 on success
-+ * \retval -1 if the payload type is out of range
-+ * \retval -2 if the mimeType/mimeSubtype combination was not found
-+ */
-+int ast_rtp_set_rtpmap_type_rate(struct ast_rtp* rtp, int pt,
-+ char *mimeType, char *mimeSubtype,
-+ enum ast_rtp_options options,
-+ unsigned int sample_rate);
-+
- /*! \brief Mapping between RTP payload format codes and Asterisk codes: */
- struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt);
- int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code);
-
- void ast_rtp_get_current_formats(struct ast_rtp* rtp,
-- int* astFormats, int* nonAstFormats);
-+ int* astFormats, int* nonAstFormats);
-
- /*! \brief Mapping an Asterisk code into a MIME subtype (string): */
- const char *ast_rtp_lookup_mime_subtype(int isAstFormat, int code,
- enum ast_rtp_options options);
-
-+/*! \brief Get the sample rate associated with known RTP payload types
-+ *
-+ * \param isAstFormat True if the value in the 'code' parameter is an AST_FORMAT value
-+ * \param code Format code, either from AST_FORMAT list or from AST_RTP list
-+ *
-+ * \return the sample rate if the format was found, zero if it was not found
-+ */
-+unsigned int ast_rtp_lookup_sample_rate(int isAstFormat, int code);
-+
- /*! \brief Build a string of MIME subtype names from a capability list */
- char *ast_rtp_lookup_mime_multiple(char *buf, size_t size, const int capability,
- const int isAstFormat, enum ast_rtp_options options);
-Index: include/asterisk/hashtab.h
-===================================================================
---- a/include/asterisk/hashtab.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/hashtab.h (.../team/group/issue14292) (revision 178988)
-@@ -81,12 +81,12 @@
- {
- struct ast_hashtab_bucket **array;
- struct ast_hashtab_bucket *tlist; /*!< the head of a DLList of all the hashbuckets in the table (for traversal). */
--
-- int (*compare) (const void *a, const void *b); /*!< a ptr to func that returns int, and take two void* ptrs, compares them,
-+
-+ int (*compare) (const void *a, const void *b); /*!< a ptr to func that returns int, and take two void* ptrs, compares them,
- rets -1 if a < b; rets 0 if a==b; rets 1 if a>b */
- int (*newsize) (struct ast_hashtab *tab); /*!< a ptr to func that returns int, a new size for hash tab, based on curr_size */
- int (*resize) (struct ast_hashtab *tab); /*!< a function to decide whether this hashtable should be resized now */
-- unsigned int (*hash) (const void *obj); /*!< a hash func ptr for this table. Given a raw ptr to an obj,
-+ unsigned int (*hash) (const void *obj); /*!< a hash func ptr for this table. Given a raw ptr to an obj,
- it calcs a hash.*/
- int hash_tab_size; /*!< the size of the bucket array */
- int hash_tab_elements; /*!< the number of objects currently stored in the table */
-@@ -108,47 +108,87 @@
-
- /* some standard, default routines for general use */
-
--/*! \brief For sizing the hash table, tells if num is prime or not */
-+/*!
-+ * \brief Determines if the specified number is prime.
-+ *
-+ * \param num the number to test
-+ * \retval 0 if the number is not prime
-+ * \retval 1 if the number is prime
-+ */
- int ast_is_prime(int num);
-
--/*!
-- * \brief assumes a and b are char *
-- * \return 0 if they match
--*/
-+/*!
-+ * \brief Compares two strings for equality.
-+ *
-+ * \param a a character string
-+ * \param b a character string
-+ * \retval 0 if the strings match
-+ * \retval <0 if string a is less than string b
-+ * \retval >0 if string a is greather than string b
-+ */
- int ast_hashtab_compare_strings(const void *a, const void *b);
-
- /*!
-- * \brief assumes a & b are strings
-- * \return 0 if they match (strcasecmp)
--*/
-+ * \brief Compares two strings for equality, ignoring case.
-+ *
-+ * \param a a character string
-+ * \param b a character string
-+ * \retval 0 if the strings match
-+ * \retval <0 if string a is less than string b
-+ * \retval >0 if string a is greather than string b
-+ */
- int ast_hashtab_compare_strings_nocase(const void *a, const void *b);
-
- /*!
-- * \brief assumes a & b are int *
-- * \retval 0 if match
-- * \retval 1 a > b
-- * \retval -1 a < b
--*/
-+ * \brief Compares two integers for equality.
-+ *
-+ * \param a an integer pointer (int *)
-+ * \param b an integer pointer (int *)
-+ * \retval 0 if the integers pointed to are equal
-+ * \retval 1 if a is greater than b
-+ * \retval -1 if a is less than b
-+ */
- int ast_hashtab_compare_ints(const void *a, const void *b);
-
- /*!
-- * \brief assumes a & b are short *
-- * \retval 0 if match
-- * \retval 1 a > b
-- * \retval -1 a < b
--*/
-+ * \brief Compares two shorts for equality.
-+ *
-+ * \param a a short pointer (short *)
-+ * \param b a short pointer (short *)
-+ * \retval 0 if the shorts pointed to are equal
-+ * \retval 1 if a is greater than b
-+ * \retval -1 if a is less than b
-+ */
- int ast_hashtab_compare_shorts(const void *a, const void *b);
-
- /*!
-- * \brief determine if resize should occur
-- * \returns 1 if the table is 75% full or more
--*/
-+ * \brief Determines if a table resize should occur using the Java algorithm
-+ * (if the table load factor is 75% or higher).
-+ *
-+ * \param tab the hash table to operate on
-+ * \retval 0 if the table load factor is less than or equal to 75%
-+ * \retval 1 if the table load factor is greater than 75%
-+ */
- int ast_hashtab_resize_java(struct ast_hashtab *tab);
-
--/*! \brief no resizing; always return 0 */
-+/*! \brief Causes a resize whenever the number of elements stored in the table
-+ * exceeds the number of buckets in the table.
-+ *
-+ * \param tab the hash table to operate on
-+ * \retval 0 if the number of elements in the table is less than or equal to
-+ * the number of buckets
-+ * \retval 1 if the number of elements in the table exceeds the number of
-+ * buckets
-+ */
- int ast_hashtab_resize_tight(struct ast_hashtab *tab);
-
--/*! \brief no resizing; always return 0 */
-+/*!
-+ * \brief Effectively disables resizing by always returning 0, regardless of
-+ * of load factor.
-+ *
-+ * \param tab the hash table to operate on
-+ * \return 0 is always returned
-+ */
- int ast_hashtab_resize_none(struct ast_hashtab *tab);
-
- /*! \brief Create a prime number roughly 2x the current table size */
-@@ -160,20 +200,39 @@
- /*! \brief always return current size -- no resizing */
- int ast_hashtab_newsize_none(struct ast_hashtab *tab);
-
--/*!
-+/*!
- * \brief Hashes a string to a number
-- * \param obj
-- * \note A modulus is applied so it in the range 0 to mod-1
--*/
-+ *
-+ * \param obj the string to hash
-+ * \return Integer hash of the specified string
-+ * \sa ast_hashtable_hash_string_nocase
-+ * \sa ast_hashtab_hash_string_sax
-+ * \note A modulus will be applied to the return value of this function
-+ */
- unsigned int ast_hashtab_hash_string(const void *obj);
-
--/*! \brief Upperases each char before using them for a hash */
-+/*!
-+ * \brief Hashes a string to a number ignoring case
-+ *
-+ * \param obj the string to hash
-+ * \return Integer hash of the specified string
-+ * \sa ast_hashtable_hash_string
-+ * \sa ast_hashtab_hash_string_sax
-+ * \note A modulus will be applied to the return value of this function
-+ */
- unsigned int ast_hashtab_hash_string_nocase(const void *obj);
-
-+/*!
-+ * \brief Hashes a string to a number using a modified Shift-And-XOR algorithm
-+ *
-+ * \param obj the string to hash
-+ * \return Integer has of the specified string
-+ * \sa ast_hastable_hash_string
-+ * \sa ast_hastable_hash_string_nocase
-+ */
-+unsigned int ast_hashtab_hash_string_sax(const void *obj);
-
--unsigned int ast_hashtab_hash_string_sax(const void *obj); /* from Josh */
-
--
- unsigned int ast_hashtab_hash_int(const int num); /* right now, both these funcs are just result = num%modulus; */
-
-
-@@ -183,7 +242,7 @@
- /*!
- * \brief Create the hashtable list
- * \param initial_buckets starting number of buckets
-- * \param compare a func ptr to compare two elements in the hash -- cannot be null
-+ * \param compare a func ptr to compare two elements in the hash -- cannot be null
- * \param resize a func ptr to decide if the table needs to be resized, a NULL ptr here will cause a default to be used
- * \param newsize a func ptr that returns a new size of the array. A NULL will cause a default to be used
- * \param hash a func ptr to do the hashing
-@@ -191,23 +250,23 @@
- */
- #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
- struct ast_hashtab * _ast_hashtab_create(int initial_buckets,
-- int (*compare)(const void *a, const void *b),
-- int (*resize)(struct ast_hashtab *),
-+ int (*compare)(const void *a, const void *b),
-+ int (*resize)(struct ast_hashtab *),
- int (*newsize)(struct ast_hashtab *tab),
-- unsigned int (*hash)(const void *obj),
-+ unsigned int (*hash)(const void *obj),
- int do_locking, const char *file, int lineno, const char *function);
- #define ast_hashtab_create(a,b,c,d,e,f) _ast_hashtab_create(a,b,c,d,e,f,__FILE__,__LINE__,__PRETTY_FUNCTION__)
- #else
- struct ast_hashtab * ast_hashtab_create(int initial_buckets,
-- int (*compare)(const void *a, const void *b),
-- int (*resize)(struct ast_hashtab *),
-+ int (*compare)(const void *a, const void *b),
-+ int (*resize)(struct ast_hashtab *),
- int (*newsize)(struct ast_hashtab *tab),
-- unsigned int (*hash)(const void *obj),
-+ unsigned int (*hash)(const void *obj),
- int do_locking );
- #endif
-
- /*!
-- * \brief This func will free the hash table and all its memory.
-+ * \brief This func will free the hash table and all its memory.
- * \note It doesn't touch the objects stored in it, unless you
- * specify a destroy func; it will call that func for each
- * object in the hashtab, remove all the objects, and then
-@@ -220,14 +279,14 @@
-
-
- /*!
-- * \brief Insert without checking
-+ * \brief Insert without checking
- * \param tab
- * \param obj
- *
- * Normally, you'd insert "safely" by checking to see if the element is
- * already there; in this case, you must already have checked. If an element
- * is already in the hashtable, that matches this one, most likely this one
-- * will be found first.
-+ * will be found first.
- * \note will force a resize if the resize func returns 1
- * \retval 1 on success
- * \retval 0 if there's a problem
-@@ -239,7 +298,7 @@
- * \param tab
- * \param obj
- * \param h hashed index value
-- *
-+ *
- * \note Will force a resize if the resize func returns 1
- * \retval 1 on success
- * \retval 0 if there's a problem
-@@ -250,14 +309,14 @@
- * \brief Check and insert new object only if it is not there.
- * \note Will force a resize if the resize func returns 1
- * \retval 1 on success
-- * \retval 0 if there's a problem, or it's already there.
-+ * \retval 0 if there's a problem, or it's already there.
- */
- int ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj);
-
- /*!
-- * \brief Lookup this object in the hash table.
-- * \param tab
-- * \param obj
-+ * \brief Lookup this object in the hash table.
-+ * \param tab
-+ * \param obj
- * \retval a ptr if found
- * \retval NULL if not found
- */
-@@ -324,15 +383,15 @@
- following locking routines yourself to lock the table between threads. */
-
- /*! \brief Call this after you create the table to init the lock */
--void ast_hashtab_initlock(struct ast_hashtab *tab);
-+void ast_hashtab_initlock(struct ast_hashtab *tab);
- /*! \brief Request a write-lock on the table. */
--void ast_hashtab_wrlock(struct ast_hashtab *tab);
-+void ast_hashtab_wrlock(struct ast_hashtab *tab);
- /*! \brief Request a read-lock on the table -- don't change anything! */
--void ast_hashtab_rdlock(struct ast_hashtab *tab);
-+void ast_hashtab_rdlock(struct ast_hashtab *tab);
- /*! \brief release a read- or write- lock. */
--void ast_hashtab_unlock(struct ast_hashtab *tab);
-+void ast_hashtab_unlock(struct ast_hashtab *tab);
- /*! \brief Call this before you destroy the table. */
--void ast_hashtab_destroylock(struct ast_hashtab *tab);
-+void ast_hashtab_destroylock(struct ast_hashtab *tab);
-
-
- #endif
-Index: include/asterisk/compat.h
-===================================================================
---- a/include/asterisk/compat.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/compat.h (.../team/group/issue14292) (revision 178988)
-@@ -182,4 +182,15 @@
- typedef unsigned long long uint64_t;
- #endif
-
-+/* glob compat stuff */
-+#if defined(__Darwin__) || defined(__CYGWIN__)
-+#define GLOB_ABORTED GLOB_ABEND
- #endif
-+#include <glob.h>
-+#ifdef SOLARIS
-+#define MY_GLOB_FLAGS GLOB_NOCHECK
-+#else
-+#define MY_GLOB_FLAGS (GLOB_NOMAGIC|GLOB_BRACE)
-+#endif
-+
-+#endif
-Index: include/asterisk/module.h
-===================================================================
---- a/include/asterisk/module.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/module.h (.../team/group/issue14292) (revision 178988)
-@@ -380,6 +380,23 @@
- */
- #define ast_register_application(app, execute, synopsis, description) ast_register_application2(app, execute, synopsis, description, ast_module_info->self)
-
-+/*!
-+ * \brief Register an application using XML documentation.
-+ *
-+ * \param app Short name of the application
-+ * \param execute a function callback to execute the application. It should return
-+ * non-zero if the channel needs to be hung up.
-+ *
-+ * This registers an application with Asterisk's internal application list.
-+ * \note The individual applications themselves are responsible for registering and unregistering
-+ * and unregistering their own CLI commands.
-+ *
-+ * \retval 0 success
-+ * \retval -1 failure.
-+ */
-+#define ast_register_application_xml(app, execute) ast_register_application(app, execute, NULL, NULL)
-+
-+
- /*!
- * \brief Register an application.
- *
-Index: include/asterisk/dsp.h
-===================================================================
---- a/include/asterisk/dsp.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/dsp.h (.../team/group/issue14292) (revision 178988)
-@@ -41,6 +41,7 @@
- #define DSP_PROGRESS_BUSY (1 << 18) /*!< Enable busy tone detection */
- #define DSP_PROGRESS_CONGESTION (1 << 19) /*!< Enable congestion tone detection */
- #define DSP_FEATURE_CALL_PROGRESS (DSP_PROGRESS_TALK | DSP_PROGRESS_RINGING | DSP_PROGRESS_BUSY | DSP_PROGRESS_CONGESTION)
-+#define DSP_FEATURE_WAITDIALTONE (1 << 20) /*!< Enable dial tone detection */
-
- #define DSP_FAXMODE_DETECT_CNG (1 << 0)
- #define DSP_FAXMODE_DETECT_CED (1 << 1)
-Index: include/asterisk/timing.h
-===================================================================
---- a/include/asterisk/timing.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/timing.h (.../team/group/issue14292) (revision 178988)
-@@ -1,9 +1,10 @@
- /*
- * Asterisk -- An open source telephony toolkit.
- *
-- * Copyright (C) 2008, Digium, Inc.
-+ * Copyright (C) 2008 - 2009, Digium, Inc.
- *
- * Kevin P. Fleming <kpfleming@digium.com>
-+ * Russell Bryant <russell@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
-@@ -20,6 +21,7 @@
- \file timing.h
- \brief Timing source management
- \author Kevin P. Fleming <kpfleming@digium.com>
-+ \author Russell Bryant <russell@digium.com>
-
- Portions of Asterisk require a timing source, a periodic trigger
- for media handling activities. The functions in this file allow
-@@ -43,6 +45,9 @@
- 4) Multiple 'event types', so that the code using the timer can
- know whether the wakeup it received was due to a periodic trigger
- or a continuous trigger.
-+
-+ \todo Create an implementation of this API for Linux based on the
-+ following API: http://www.kernel.org/doc/man-pages/online/pages/man2/timerfd_create.2.html
- */
-
- #ifndef _ASTERISK_TIMING_H
-@@ -52,7 +57,7 @@
- extern "C" {
- #endif
-
--enum ast_timing_event {
-+enum ast_timer_event {
- AST_TIMING_EVENT_EXPIRED = 1,
- AST_TIMING_EVENT_CONTINUOUS = 2,
- };
-@@ -64,37 +69,44 @@
- * So, the behavior of these calls should match the documentation of the
- * public API calls.
- */
--struct ast_timing_functions {
-+struct ast_timing_interface {
-+ const char *name;
-+ /*! This handles the case where multiple timing modules are loaded.
-+ * The highest priority timing interface available will be used. */
-+ unsigned int priority;
- int (*timer_open)(void);
- void (*timer_close)(int handle);
- int (*timer_set_rate)(int handle, unsigned int rate);
- void (*timer_ack)(int handle, unsigned int quantity);
- int (*timer_enable_continuous)(int handle);
- int (*timer_disable_continuous)(int handle);
-- enum ast_timing_event (*timer_get_event)(int handle);
-+ enum ast_timer_event (*timer_get_event)(int handle);
- unsigned int (*timer_get_max_rate)(int handle);
- };
-
- /*!
-- * \brief Install a set of timing functions.
-+ * \brief Register a set of timing functions.
- *
-- * \param funcs An instance of the \c ast_timing_functions structure with pointers
-+ * \param funcs An instance of the \c ast_timing_interfaces structure with pointers
- * to the functions provided by the timing implementation.
- *
- * \retval NULL failure
-- * \retval non-Null handle to be passed to ast_uninstall_timing_functions() on success
-+ * \retval non-Null handle to be passed to ast_unregister_timing_interface() on success
- */
--void *ast_install_timing_functions(struct ast_timing_functions *funcs);
-+#define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self)
-+void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
-+ struct ast_module *mod);
-
- /*!
-- * \brief Uninstall a previously-installed set of timing functions.
-+ * \brief Unregister a previously registered timing interface.
- *
- * \param handle The handle returned from a prior successful call to
-- * ast_install_timing_functions().
-+ * ast_register_timing_interface().
- *
-- * \return nothing
-+ * \retval 0 success
-+ * \retval non-zero failure
- */
--void ast_uninstall_timing_functions(void *handle);
-+int ast_unregister_timing_interface(void *handle);
-
- /*!
- * \brief Open a timing fd
-@@ -174,7 +186,7 @@
- *
- * \return which event triggered the timing fd
- */
--enum ast_timing_event ast_timer_get_event(int handle);
-+enum ast_timer_event ast_timer_get_event(int handle);
-
- /*!
- * \brief Get maximum rate supported for a timing handle
-Index: include/asterisk/frame.h
-===================================================================
---- a/include/asterisk/frame.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/frame.h (.../team/group/issue14292) (revision 178988)
-@@ -39,54 +39,56 @@
- char framing[32];
- };
-
--/*! \page Def_Frame AST Multimedia and signalling frames
-- \section Def_AstFrame What is an ast_frame ?
-- A frame of data read used to communicate between
-- between channels and applications.
-- Frames are divided into frame types and subclasses.
-+/*!
-+ * \page Def_Frame AST Multimedia and signalling frames
-+ * \section Def_AstFrame What is an ast_frame ?
-+ * A frame of data read used to communicate between
-+ * between channels and applications.
-+ * Frames are divided into frame types and subclasses.
-+ *
-+ * \par Frame types
-+ * \arg \b VOICE: Voice data, subclass is codec (AST_FORMAT_*)
-+ * \arg \b VIDEO: Video data, subclass is codec (AST_FORMAT_*)
-+ * \arg \b DTMF: A DTMF digit, subclass is the digit
-+ * \arg \b IMAGE: Image transport, mostly used in IAX
-+ * \arg \b TEXT: Text messages and character by character (real time text)
-+ * \arg \b HTML: URL's and web pages
-+ * \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
-+ * \arg \b IAX: Private frame type for the IAX protocol
-+ * \arg \b CNG: Comfort noice frames
-+ * \arg \b CONTROL:A control frame, subclass defined as AST_CONTROL_
-+ * \arg \b NULL: Empty, useless frame
-+ *
-+ * \par Files
-+ * \arg frame.h Definitions
-+ * \arg frame.c Function library
-+ * \arg \ref Def_Channel Asterisk channels
-+ * \section Def_ControlFrame Control Frames
-+ * Control frames send signalling information between channels
-+ * and devices. They are prefixed with AST_CONTROL_, like AST_CONTROL_FRAME_HANGUP
-+ * \arg \b HANGUP The other end has hungup
-+ * \arg \b RING Local ring
-+ * \arg \b RINGING The other end is ringing
-+ * \arg \b ANSWER The other end has answered
-+ * \arg \b BUSY Remote end is busy
-+ * \arg \b TAKEOFFHOOK Make it go off hook (what's "it" ? )
-+ * \arg \b OFFHOOK Line is off hook
-+ * \arg \b CONGESTION Congestion (circuit is busy, not available)
-+ * \arg \b FLASH Other end sends flash hook
-+ * \arg \b WINK Other end sends wink
-+ * \arg \b OPTION Send low-level option
-+ * \arg \b RADIO_KEY Key radio (see app_rpt.c)
-+ * \arg \b RADIO_UNKEY Un-key radio (see app_rpt.c)
-+ * \arg \b PROGRESS Other end indicates call progress
-+ * \arg \b PROCEEDING Indicates proceeding
-+ * \arg \b HOLD Call is placed on hold
-+ * \arg \b UNHOLD Call is back from hold
-+ * \arg \b VIDUPDATE Video update requested
-+ * \arg \b SRCUPDATE The source of media has changed
-+ * \arg \b CONNECTED_LINE Connected line has changed
-+ * \arg \b REDIRECTING Call redirecting information has changed.
-+ */
-
-- \par Frame types
-- \arg \b VOICE: Voice data, subclass is codec (AST_FORMAT_*)
-- \arg \b VIDEO: Video data, subclass is codec (AST_FORMAT_*)
-- \arg \b DTMF: A DTMF digit, subclass is the digit
-- \arg \b IMAGE: Image transport, mostly used in IAX
-- \arg \b TEXT: Text messages and character by character (real time text)
-- \arg \b HTML: URL's and web pages
-- \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
-- \arg \b IAX: Private frame type for the IAX protocol
-- \arg \b CNG: Comfort noice frames
-- \arg \b CONTROL: A control frame, subclass defined as AST_CONTROL_
-- \arg \b NULL: Empty, useless frame
--
-- \par Files
-- \arg frame.h Definitions
-- \arg frame.c Function library
-- \arg \ref Def_Channel Asterisk channels
-- \section Def_ControlFrame Control Frames
-- Control frames send signalling information between channels
-- and devices. They are prefixed with AST_CONTROL_, like AST_CONTROL_FRAME_HANGUP
-- \arg \b HANGUP The other end has hungup
-- \arg \b RING Local ring
-- \arg \b RINGING The other end is ringing
-- \arg \b ANSWER The other end has answered
-- \arg \b BUSY Remote end is busy
-- \arg \b TAKEOFFHOOK Make it go off hook (what's "it" ? )
-- \arg \b OFFHOOK Line is off hook
-- \arg \b CONGESTION Congestion (circuit is busy, not available)
-- \arg \b FLASH Other end sends flash hook
-- \arg \b WINK Other end sends wink
-- \arg \b OPTION Send low-level option
-- \arg \b RADIO_KEY Key radio (see app_rpt.c)
-- \arg \b RADIO_UNKEY Un-key radio (see app_rpt.c)
-- \arg \b PROGRESS Other end indicates call progress
-- \arg \b PROCEEDING Indicates proceeding
-- \arg \b HOLD Call is placed on hold
-- \arg \b UNHOLD Call is back from hold
-- \arg \b VIDUPDATE Video update requested
-- \arg \b SRCUPDATE The source of media has changed
--
--*/
--
- /*!
- * \brief Frame types
- *
-@@ -194,9 +196,17 @@
- for this purpose instead of having to declare one on the stack */
- extern struct ast_frame ast_null_frame;
-
--#define AST_FRIENDLY_OFFSET 64 /*! It's polite for a a new frame to
-- have this number of bytes for additional
-- headers. */
-+/*! \brief Offset into a frame's data buffer.
-+ *
-+ * By providing some "empty" space prior to the actual data of an ast_frame,
-+ * this gives any consumer of the frame ample space to prepend other necessary
-+ * information without having to create a new buffer.
-+ *
-+ * As an example, RTP can use the data from an ast_frame and simply prepend the
-+ * RTP header information into the space provided by AST_FRIENDLY_OFFSET instead
-+ * of having to create a new buffer with the necessary space allocated.
-+ */
-+#define AST_FRIENDLY_OFFSET 64
- #define AST_MIN_OFFSET 32 /*! Make sure we keep at least this much handy */
-
- /*! Need the header be free'd? */
-@@ -259,6 +269,10 @@
- #define AST_FORMAT_G726 (1 << 11)
- /*! G.722 */
- #define AST_FORMAT_G722 (1 << 12)
-+/*! G.722.1 (also known as Siren7, 32kbps assumed) */
-+#define AST_FORMAT_SIREN7 (1 << 13)
-+/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
-+#define AST_FORMAT_SIREN14 (1 << 14)
- /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
- #define AST_FORMAT_SLINEAR16 (1 << 15)
- /*! Maximum audio mask */
-@@ -307,6 +321,8 @@
- AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */
- AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */
- AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */
-+ AST_CONTROL_CONNECTED_LINE = 21, /*!< Indicate connected line has changed */
-+ AST_CONTROL_REDIRECTING = 22 /*!< Indicate redirecting id has changed */
- };
-
- enum ast_control_t38 {
-@@ -523,8 +539,8 @@
- #endif
- /*@} Doxygen marker */
-
--struct ast_format_list *ast_get_format_list_index(int index);
--struct ast_format_list *ast_get_format_list(size_t *size);
-+const struct ast_format_list *ast_get_format_list_index(int index);
-+const struct ast_format_list *ast_get_format_list(size_t *size);
- void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix);
-
- /*! \page AudioCodecPref Audio Codec Preferences
-@@ -630,10 +646,16 @@
- */
- static force_inline int ast_format_rate(int format)
- {
-- if (format == AST_FORMAT_G722 || format == AST_FORMAT_SLINEAR16)
-+ switch (format) {
-+ case AST_FORMAT_G722:
-+ case AST_FORMAT_SLINEAR16:
-+ case AST_FORMAT_SIREN7:
- return 16000;
--
-- return 8000;
-+ case AST_FORMAT_SIREN14:
-+ return 32000;
-+ default:
-+ return 8000;
-+ }
- }
-
- #if defined(__cplusplus) || defined(c_plusplus)
-Index: include/asterisk/say.h
-===================================================================
---- a/include/asterisk/say.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/say.h (.../team/group/issue14292) (revision 178988)
-@@ -66,13 +66,14 @@
- #define SAY_EXTERN extern
- #endif
-
--/*
-+/*!
- * \brief says a number
- * \param chan channel to say them number on
- * \param num number to say on the channel
- * \param ints which dtmf to interrupt on
- * \param lang language to speak the number
- * \param options set to 'f' for female, 'm' for male, 'c' for commune, 'n' for neuter, 'p' for plural
-+ * \details
- * Vocally says a number on a given channel
- * \retval 0 on success
- * \retval DTMF digit on interrupt
-@@ -84,15 +85,16 @@
- /* Same as above with audiofd for received audio and returns 1 on ctrlfd being readable */
- SAY_EXTERN int (* ast_say_number_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_number_full);
-
--/*
-+/*!
- * \brief says an enumeration
- * \param chan channel to say them enumeration on
- * \param num number to say on the channel
- * \param ints which dtmf to interrupt on
- * \param lang language to speak the enumeration
- * \param options set to 'f' for female, 'm' for male, 'c' for commune, 'n' for neuter, 'p' for plural
-- * Vocally says a enumeration on a given channel (first, sencond, third, forth, thirtyfirst, hundredth, ....)
-- * especially useful for dates and messages. says 'last' if num equals to INT_MAX
-+ * \details
-+ * Vocally says an enumeration on a given channel (first, sencond, third, forth, thirtyfirst, hundredth, ....)
-+ * Especially useful for dates and messages. Says 'last' if num equals to INT_MAX
- * \retval 0 on success
- * \retval DTMF digit on interrupt
- * \retval -1 on failure
-@@ -102,12 +104,13 @@
-
- SAY_EXTERN int (* ast_say_enumeration_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_enumeration_full);
-
--/*
-+/*!
- * \brief says digits
- * \param chan channel to act upon
- * \param num number to speak
- * \param ints which dtmf to interrupt on
- * \param lang language to speak
-+ * \details
- * Vocally says digits of a given number
- * \retval 0 on success
- * \retval DTMF if interrupted
-@@ -119,12 +122,13 @@
- int ast_say_digits_full(struct ast_channel *chan, int num,
- const char *ints, const char *lang, int audiofd, int ctrlfd);
-
--/*
-+/*!
- * \brief says digits of a string
- * \param chan channel to act upon
- * \param num string to speak
- * \param ints which dtmf to interrupt on
- * \param lang language to speak in
-+ * \details
- * Vocally says the digits of a given string
- * \retval 0 on succes
- * \retval DTMF if interrupted
-Index: include/asterisk/threadstorage.h
-===================================================================
---- a/include/asterisk/threadstorage.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/threadstorage.h (.../team/group/issue14292) (revision 178988)
-@@ -60,12 +60,6 @@
- int (*custom_init)(void *); /*!< Custom initialization function specific to the object */
- };
-
--#ifdef SOLARIS
--#define THREADSTORAGE_ONCE_INIT {PTHREAD_ONCE_INIT}
--#else
--#define THREADSTORAGE_ONCE_INIT PTHREAD_ONCE_INIT
--#endif
--
- #if defined(DEBUG_THREADLOCALS)
- void __ast_threadstorage_object_add(void *key, size_t len, const char *file, const char *function, unsigned int line);
- void __ast_threadstorage_object_remove(void *key);
-@@ -85,7 +79,11 @@
- * \endcode
- */
- #define AST_THREADSTORAGE(name) \
-- AST_THREADSTORAGE_CUSTOM(name, NULL, ast_free_ptr)
-+ AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr, static)
-+#define AST_THREADSTORAGE_PUBLIC(name) \
-+ AST_THREADSTORAGE_CUSTOM_SCOPE(name, NULL, ast_free_ptr,)
-+#define AST_THREADSTORAGE_EXTERNAL(name) \
-+ extern struct ast_threadstorage name
-
- /*!
- * \brief Define a thread storage variable, with custom initialization and cleanup
-@@ -103,34 +101,36 @@
- * AST_THREADSTORAGE_CUSTOM(my_buf, my_init, my_cleanup);
- * \endcode
- */
-+#define AST_THREADSTORAGE_CUSTOM(a,b,c) AST_THREADSTORAGE_CUSTOM_SCOPE(a,b,c,static)
-+
- #if !defined(DEBUG_THREADLOCALS)
--#define AST_THREADSTORAGE_CUSTOM(name, c_init, c_cleanup) \
--static void __init_##name(void); \
--static struct ast_threadstorage name = { \
-- .once = THREADSTORAGE_ONCE_INIT, \
-- .key_init = __init_##name, \
-- .custom_init = c_init, \
--}; \
--static void __init_##name(void) \
--{ \
-- pthread_key_create(&(name).key, c_cleanup); \
-+#define AST_THREADSTORAGE_CUSTOM_SCOPE(name, c_init, c_cleanup, scope) \
-+static void __init_##name(void); \
-+scope struct ast_threadstorage name = { \
-+ .once = PTHREAD_ONCE_INIT, \
-+ .key_init = __init_##name, \
-+ .custom_init = c_init, \
-+}; \
-+static void __init_##name(void) \
-+{ \
-+ pthread_key_create(&(name).key, c_cleanup); \
- }
- #else /* defined(DEBUG_THREADLOCALS) */
--#define AST_THREADSTORAGE_CUSTOM(name, c_init, c_cleanup) \
--static void __init_##name(void); \
--static struct ast_threadstorage name = { \
-- .once = THREADSTORAGE_ONCE_INIT, \
-- .key_init = __init_##name, \
-- .custom_init = c_init, \
--}; \
--static void __cleanup_##name(void *data) \
--{ \
-- __ast_threadstorage_object_remove(data); \
-- c_cleanup(data); \
--} \
--static void __init_##name(void) \
--{ \
-- pthread_key_create(&(name).key, __cleanup_##name); \
-+#define AST_THREADSTORAGE_CUSTOM_SCOPE(name, c_init, c_cleanup, scope) \
-+static void __init_##name(void); \
-+scope struct ast_threadstorage name = { \
-+ .once = PTHREAD_ONCE_INIT, \
-+ .key_init = __init_##name, \
-+ .custom_init = c_init, \
-+}; \
-+static void __cleanup_##name(void *data) \
-+{ \
-+ __ast_threadstorage_object_remove(data); \
-+ c_cleanup(data); \
-+} \
-+static void __init_##name(void) \
-+{ \
-+ pthread_key_create(&(name).key, __cleanup_##name); \
- }
- #endif /* defined(DEBUG_THREADLOCALS) */
-
-Index: include/asterisk/devicestate.h
-===================================================================
---- a/include/asterisk/devicestate.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/devicestate.h (.../team/group/issue14292) (revision 178988)
-@@ -73,14 +73,15 @@
- *
- * \param devstate Current device state
- */
--const char *devstate2str(enum ast_device_state devstate);
-+const char *devstate2str(enum ast_device_state devstate) attribute_pure __attribute__((deprecated));
-+const char *ast_devstate2str(enum ast_device_state devstate) attribute_pure;
-
- /*!
- * \brief Convert device state to text string that is easier to parse
- *
- * \param devstate Current device state
- */
--const char *ast_devstate_str(enum ast_device_state devstate);
-+const char *ast_devstate_str(enum ast_device_state devstate) attribute_pure;
-
- /*!
- * \brief Convert device state from text to integer value
-Index: include/asterisk/indications.h
-===================================================================
---- a/include/asterisk/indications.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/indications.h (.../team/group/issue14292) (revision 178988)
-@@ -1,89 +1,240 @@
- /*
- * Asterisk -- An open source telephony toolkit.
- *
-+ * Copyright (C) 2002, Pauline Middelink
-+ * 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 BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU Lesser General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU Lesser General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, write to the Free Software
-- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+/*!
-+ * \file
-+ * \brief Tone Indication Support
- *
-- * Primary Author: Pauline Middelink <middelink@polyware.nl>
-- *
-+ * \author Pauline Middelink <middelink@polyware.nl>
-+ * \author Russell Bryant <russell@digium.com>
- */
-
- #ifndef _ASTERISK_INDICATIONS_H
- #define _ASTERISK_INDICATIONS_H
-
--#include "asterisk/lock.h"
-+#include "asterisk/astobj2.h"
-
--/*! \brief Description is a series of tones of the format:
-- [!]freq1[+freq2][/duration] separated by commas. There
-- are no spaces. The sequence is repeated back to the
-- first tone description not preceeded by !. Duration is
-- specified in milliseconds */
--struct tone_zone_sound {
-- struct tone_zone_sound *next; /*!< next element */
-- const char *name; /*!< Identifing name */
-- const char *data; /*!< Actual zone description */
-+/*!
-+ * \brief Description of a tone
-+ */
-+struct ast_tone_zone_sound {
-+ /*! \brief Name of the tone. For example, "busy". */
-+ const char *name;
-+ /*!
-+ * \brief Description of a tone
-+ *
-+ * The format is a comma separated list of tone parts in the following format:
-+ *
-+ * Format: [!][M]freq[<+|*>freq2][/duration]
-+ * - '!' - means that the element is NOT repeated
-+ * - 'M' - interpret the frequencies as midi notes instead of frequencies
-+ * - freq - The first frequency
-+ * - freq2 - The second frequency (optional)
-+ * - '*' - modulate freq by freq2 at a fixed depth of 90%
-+ * - '+' - combine the frequencies
-+ * - duration - the length of the tone part (optional, forever if not specified)
-+ */
-+ const char *data;
-+ /*! \brief Linked list fields for including in the list on an ast_tone_zone */
-+ AST_LIST_ENTRY(ast_tone_zone_sound) entry;
-+ /*! \brief Flags only used internally */
-+ union {
-+ uint32_t __padding;
-+ struct {
-+ unsigned int killme:1;
-+ };
-+ };
- };
-
--struct tone_zone {
-- AST_RWLIST_ENTRY(tone_zone) list;
-- char country[5]; /*!< Country code */
-- char alias[5]; /*!< is this an alias? */
-- char description[40]; /*!< Description */
-- int nrringcadence; /*!< # registered ringcadence elements */
-- int *ringcadence; /*!< Ring cadence */
-- struct tone_zone_sound *tones; /*!< The known tones for this zone */
-+/*!
-+ * \brief A set of tones for a given locale
-+ *
-+ * \note If a reference to this tone zone is held, then the country
-+ * is guaranteed not to change. It is safe to read it without
-+ * locking the tone zone. This is not the case for any other
-+ * field.
-+ */
-+struct ast_tone_zone {
-+ /*! \brief Country code that this set of tones is for */
-+ char country[5];
-+ /*!
-+ * \brief Text description of the given country.
-+ *
-+ * This is for nothing more than friendly display to a human.
-+ */
-+ char description[40];
-+ /*! \brief Number of ring cadence elements in the ringcadence array */
-+ unsigned int nrringcadence;
-+ /*!
-+ * \brief Array of ring cadence parts
-+ *
-+ * Each element is an amount of time in milliseconds. The first element
-+ * is for time on, and from there it alternates between on and off.
-+ */
-+ int *ringcadence;
-+ /*! \brief A list of tones for this locale */
-+ AST_LIST_HEAD_NOLOCK(, ast_tone_zone_sound) tones;
-+ /*! \brief Flags only used internally */
-+ union {
-+ uint32_t __padding;
-+ struct {
-+ unsigned int killme:1;
-+ };
-+ };
- };
-
--/*! \brief set the default tone country */
--int ast_set_indication_country(const char *country);
-+/*!
-+ * \brief A description of a part of a tone
-+ *
-+ * The elements in this structure map to the format described for the data
-+ * part of the ast_tone_zone_sound struct.
-+ */
-+struct ast_tone_zone_part {
-+ unsigned int freq1;
-+ unsigned int freq2;
-+ unsigned int time;
-+ unsigned int modulate:1;
-+ unsigned int midinote:1;
-+};
-
--/*! \brief locate tone_zone, given the country. if country == NULL, use the default country */
--struct tone_zone *ast_get_indication_zone(const char *country);
--/*! \brief locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
--struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication);
-+/*!
-+ * \brief Parse a tone part
-+ *
-+ * \param s The part of a tone to parse. This should be in the form described for
-+ * the data part of ast_tone_zone_sound. '!' should be removed if present.
-+ * \param tone_data An output parameter that contains the result of the parsing.
-+ *
-+ * \retval 0 success
-+ * \retval -1 failure, and the contents of tone_data are undefined
-+ */
-+int ast_tone_zone_part_parse(const char *s, struct ast_tone_zone_part *tone_data);
-
--/*! \brief add a new country, if country exists, it will be replaced. */
--int ast_register_indication_country(struct tone_zone *country);
--/*! \brief remove an existing country and all its indications, country must exist */
--int ast_unregister_indication_country(const char *country);
--/*! \brief add a new indication to a tone_zone. tone_zone must exist. if the indication already
-- * exists, it will be replaced. */
--int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist);
--/*! \brief remove an existing tone_zone's indication. tone_zone must exist */
--int ast_unregister_indication(struct tone_zone *zone, const char *indication);
-+/*!
-+ * \brief locate ast_tone_zone
-+ *
-+ * \param country country to find. If NULL is provided, get the default.
-+ *
-+ * \return a reference to the specified country if found or NULL if not found
-+ */
-+struct ast_tone_zone *ast_get_indication_zone(const char *country);
-
--/*! \brief Start a tone-list going */
--int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
--/*! \brief Stop the tones from playing */
-+/*!
-+ * \brief Locate a tone zone sound
-+ *
-+ * \param zone Zone to look in for a sound, if NULL, the default will be used
-+ * \param indication Sound to look for, such as "busy"
-+ *
-+ * \return a reference to the specified sound if it exists, NULL if not
-+ */
-+struct ast_tone_zone_sound *ast_get_indication_tone(const struct ast_tone_zone *zone, const char *indication);
-+
-+/*!
-+ * \brief Start playing a list of tones on a channel
-+ *
-+ * \param chan the channel to play tones on
-+ * \param vol volume
-+ * \param tonelist the list of tones to play, comma separated
-+ * \param interruptible whether or not this tone can be interrupted
-+ *
-+ * \retval 0 success
-+ * \retval non-zero failure
-+ */
-+int ast_playtones_start(struct ast_channel *chan, int vol, const char *tonelist, int interruptible);
-+
-+/*!
-+ * \brief Stop playing tones on a channel
-+ *
-+ * \param chan the channel to stop tones on
-+ */
- void ast_playtones_stop(struct ast_channel *chan);
-
--/*! \brief support for walking through a list of indications */
--struct tone_zone *ast_walk_indications(const struct tone_zone *cur);
-+/*!
-+ * \brief Get the number of registered tone zones
-+ *
-+ * \return the total number of registered tone zones
-+ */
-+int ast_tone_zone_count(void);
-
--#if 0
--extern struct tone_zone *tone_zones;
--extern ast_mutex_t tzlock;
--#endif
-+/*!
-+ * \brief Get an iterator for the available tone zones
-+ *
-+ * Use ao2_iterator_next() to iterate the tone zones.
-+ *
-+ * \return an initialized iterator
-+ */
-+struct ao2_iterator ast_tone_zone_iterator_init(void);
-
-+/*!
-+ * \brief Lock an ast_tone_zone
-+ */
-+#define ast_tone_zone_lock(tz) ao2_lock(tz)
-+
-+/*!
-+ * \brief Unlock an ast_tone_zone
-+ */
-+#define ast_tone_zone_unlock(tz) ao2_unlock(tz)
-+
-+/*!
-+ * \brief Trylock an ast_tone_zone
-+ */
-+#define ast_tone_zone_trylock(tz) ao2_trylock(tz)
-+
-+/*!
-+ * \brief Release a reference to an ast_tone_zone
-+ *
-+ * \return NULL
-+ */
-+static inline struct ast_tone_zone *ast_tone_zone_unref(struct ast_tone_zone *tz)
-+{
-+ ao2_ref(tz, -1);
-+ return NULL;
-+}
-+
-+/*!
-+ * \brief Increase the reference count on an ast_tone_zone
-+ *
-+ * \return The tone zone provided as an argument
-+ */
-+static inline struct ast_tone_zone *ast_tone_zone_ref(struct ast_tone_zone *tz)
-+{
-+ ao2_ref(tz, +1);
-+ return tz;
-+}
-+
-+/*!
-+ * \brief Release a reference to an ast_tone_zone_sound
-+ *
-+ * \return NULL
-+ */
-+static inline struct ast_tone_zone_sound *ast_tone_zone_sound_unref(struct ast_tone_zone_sound *ts)
-+{
-+ ao2_ref(ts, -1);
-+ return NULL;
-+}
-+
-+/*!
-+ * \brief Increase the reference count on an ast_tone_zone_sound
-+ *
-+ * \return The tone zone sound provided as an argument
-+ */
-+static inline struct ast_tone_zone_sound *ast_tone_zone_sound_ref(struct ast_tone_zone_sound *ts)
-+{
-+ ao2_ref(ts, +1);
-+ return ts;
-+}
-+
- #endif /* _ASTERISK_INDICATIONS_H */
-Index: include/asterisk/astobj2.h
-===================================================================
---- a/include/asterisk/astobj2.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/astobj2.h (.../team/group/issue14292) (revision 178988)
-@@ -478,7 +478,12 @@
- * \param a A pointer to the object we want to lock.
- * \return 0 on success, other values on error.
- */
-+#ifndef DEBUG_THREADS
- int ao2_trylock(void *a);
-+#else
-+#define ao2_trylock(a) _ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
-+int _ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
-+#endif
-
- /*! \brief
- * Return the lock address of an object
-@@ -506,7 +511,7 @@
-
- Operations on container include:
-
-- - c = \b ao2_container_alloc(size, cmp_fn, hash_fn)
-+ - c = \b ao2_container_alloc(size, hash_fn, cmp_fn)
- allocate a container with desired size and default compare
- and hash function
- -The compare function returns an int, which
-@@ -597,10 +602,22 @@
- * \param flags flags from ao2_callback()
- *
- * The return values are a combination of enum _cb_results.
-- * Callback functions are used to search or manipulate objects in a container,
-+ * Callback functions are used to search or manipulate objects in a container.
- */
- typedef int (ao2_callback_fn)(void *obj, void *arg, int flags);
-
-+/*! \brief
-+ * Type of a generic callback function
-+ * \param obj pointer to the (user-defined part) of an object.
-+ * \param arg callback argument from ao2_callback()
-+ * \param data arbitrary data from ao2_callback()
-+ * \param flags flags from ao2_callback()
-+ *
-+ * The return values are a combination of enum _cb_results.
-+ * Callback functions are used to search or manipulate objects in a container.
-+ */
-+typedef int (ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags);
-+
- /*! \brief a very common callback is one that matches by address. */
- ao2_callback_fn ao2_match_by_addr;
-
-@@ -832,25 +849,54 @@
- * be used to free the additional reference possibly created by this function.
- */
- #ifdef REF_DEBUG
--#define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), (arg5), __FILE__, __LINE__, __PRETTY_FUNCTION__)
--#define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-+#define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), (arg5), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-+#define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
- #else
- #define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback((arg1), (arg2), (arg3), (arg4))
- #define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback((arg1), (arg2), (arg3), (arg4))
- #endif
- void *_ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
-- ao2_callback_fn *cb_fn, void *arg, char *tag,
-- char *file, int line, const char *funcname);
-+ ao2_callback_fn *cb_fn, void *arg, char *tag,
-+ char *file, int line, const char *funcname);
- void *_ao2_callback(struct ao2_container *c,
-- enum search_flags flags,
-- ao2_callback_fn *cb_fn, void *arg);
-+ enum search_flags flags,
-+ ao2_callback_fn *cb_fn, void *arg);
-
-+/*! \brief
-+ * ao2_callback_data() is a generic function that applies cb_fn() to all objects
-+ * in a container. It is functionally identical to ao2_callback() except that
-+ * instead of taking an ao2_callback_fn *, it takes an ao2_callback_data_fn *, and
-+ * allows the caller to pass in arbitrary data.
-+ *
-+ * This call would be used instead of ao2_callback() when the caller needs to pass
-+ * OBJ_POINTER as part of the flags argument (which in turn requires passing in a
-+ * prototype ao2 object for 'arg') and also needs access to other non-global data
-+ * to complete it's comparison or task.
-+ *
-+ * See the documentation for ao2_callback() for argument descriptions.
-+ *
-+ * \see ao2_callback()
-+ */
-+#ifdef REF_DEBUG
-+#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) _ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), (arg6), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-+#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) _ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-+#else
-+#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) _ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
-+#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) _ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
-+#endif
-+void *_ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
-+ ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag,
-+ char *file, int line, const char *funcname);
-+void *_ao2_callback_data(struct ao2_container *c,
-+ enum search_flags flags,
-+ ao2_callback_data_fn *cb_fn, void *arg, void *data);
-+
- /*! ao2_find() is a short hand for ao2_callback(c, flags, c->cmp_fn, arg)
- * XXX possibly change order of arguments ?
- */
- #ifdef REF_DEBUG
--#define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
--#define ao2_find(arg1,arg2,arg3) _ao2_find_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-+#define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-+#define ao2_find(arg1,arg2,arg3) _ao2_find_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
- #else
- #define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find((arg1), (arg2), (arg3))
- #define ao2_find(arg1,arg2,arg3) _ao2_find((arg1), (arg2), (arg3))
-Index: include/asterisk/slin.h
-===================================================================
---- a/include/asterisk/slin.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/include/asterisk/slin.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,115 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2007, Digium, Inc.
-+ *
-+ * Russell Bryant <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+static uint8_t ex_slin8[] = {
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+};
-+
-+static uint8_t ex_slin16[] = {
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+};
-+
-+static inline struct ast_frame *slin8_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_SLINEAR,
-+ .datalen = sizeof(ex_slin8),
-+ .samples = ARRAY_LEN(ex_slin8) / 2,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_slin8,
-+ };
-+
-+ return &f;
-+}
-+
-+static inline struct ast_frame *slin16_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_SLINEAR16,
-+ .datalen = sizeof(ex_slin16),
-+ .samples = ARRAY_LEN(ex_slin16) / 2,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_slin16,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: include/asterisk/slin.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: include/asterisk/cli.h
-===================================================================
---- a/include/asterisk/cli.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/cli.h (.../team/group/issue14292) (revision 178988)
-@@ -32,6 +32,10 @@
- void ast_cli(int fd, const char *fmt, ...)
- __attribute__((format(printf, 2, 3)));
-
-+/* dont check permissions while passing this option as a 'uid'
-+ * to the cli_has_permissions() function. */
-+#define CLI_NO_PERMS -1
-+
- #define RESULT_SUCCESS 0
- #define RESULT_SHOWUSAGE 1
- #define RESULT_FAILURE 2
-@@ -154,21 +158,15 @@
- const char *summary; /*!< Summary of the command (< 60 characters) */
- const char *usage; /*!< Detailed usage information */
-
-- struct ast_cli_entry *deprecate_cmd;
--
- int inuse; /*!< For keeping track of usage */
- struct module *module; /*!< module this belongs to */
- char *_full_cmd; /*!< built at load time from cmda[] */
- int cmdlen; /*!< len up to the first invalid char [<{% */
- /*! \brief This gets set in ast_cli_register()
-- It then gets set to something different when the deprecated command
-- is run for the first time (ie; after we warn the user that it's deprecated)
- */
- int args; /*!< number of non-null entries in cmda */
- char *command; /*!< command, non-null for new-style entries */
-- int deprecated;
- cli_fn handler;
-- char *_deprecated_by; /*!< copied from the "parent" _full_cmd, on deprecated commands */
- /*! For linking */
- AST_LIST_ENTRY(ast_cli_entry) list;
- };
-@@ -197,24 +195,36 @@
-
- /*!
- * \brief Interprets a command
-- * Interpret a command s, sending output to fd
-+ * Interpret a command s, sending output to fd if uid:gid has permissions
-+ * to run this command. uid = CLI_NO_PERMS to avoid checking user permissions
-+ * gid = CLI_NO_PERMS to avoid checking group permissions.
-+ * \param uid User ID that is trying to run the command.
-+ * \param gid Group ID that is trying to run the command.
- * \param fd pipe
- * \param s incoming string
- * \retval 0 on success
- * \retval -1 on failure
- */
--int ast_cli_command(int fd, const char *s);
-+int ast_cli_command_full(int uid, int gid, int fd, const char *s);
-
-+#define ast_cli_command(fd,s) ast_cli_command_full(CLI_NO_PERMS, CLI_NO_PERMS, fd, s)
-+
- /*!
- * \brief Executes multiple CLI commands
- * Interpret strings separated by NULL and execute each one, sending output to fd
-+ * if uid has permissions, uid = CLI_NO_PERMS to avoid checking users permissions.
-+ * gid = CLI_NO_PERMS to avoid checking group permissions.
-+ * \param uid User ID that is trying to run the command.
-+ * \param gid Group ID that is trying to run the command.
- * \param fd pipe
- * \param size is the total size of the string
- * \param s incoming string
- * \retval number of commands executed
- */
--int ast_cli_command_multiple(int fd, size_t size, const char *s);
-+int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s);
-
-+#define ast_cli_command_multiple(fd,size,s) ast_cli_command_multiple_full(CLI_NO_PERMS, CLI_NO_PERMS, fd, size, s)
-+
- /*! \brief Registers a command or an array of commands
- * \param e which cli entry to register.
- * Register your own command
-Index: include/asterisk/buildinfo.h
-===================================================================
---- a/include/asterisk/buildinfo.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/include/asterisk/buildinfo.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,29 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 1999 - 2006, Digium, Inc.
-+ *
-+ * Mark Spencer <markster@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+#ifndef _ASTERISK_BUILDINFO_H
-+#define _ASTERISK_BUILDINFO_H
-+
-+extern const char *ast_build_hostname;
-+extern const char *ast_build_kernel;
-+extern const char *ast_build_machine;
-+extern const char *ast_build_os;
-+extern const char *ast_build_date;
-+extern const char *ast_build_user;
-+
-+#endif
-
-Property changes on: include/asterisk/buildinfo.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: include/asterisk/heap.h
-===================================================================
---- a/include/asterisk/heap.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/include/asterisk/heap.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,240 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2009, Digium, Inc.
-+ *
-+ * Russell Bryant <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*!
-+ * \file
-+ * \brief Max Heap data structure
-+ * \author Russell Bryant <russell@digium.com>
-+ */
-+
-+#ifndef __AST_HEAP_H__
-+#define __AST_HEAP_H__
-+
-+/*!
-+ * \brief A max heap.
-+ *
-+ * \note Thread-safety is left to the user of the API. The heap API provides
-+ * no locking of its own. If the heap will be accessed by multiple threads,
-+ * then a lock must be used to ensure that only a single operation is
-+ * done on the heap at a time. For the sake of convenience, a lock is
-+ * provided for the user of the API to use if another lock is not already
-+ * available to protect the heap.
-+ */
-+struct ast_heap;
-+
-+/*!
-+ * \brief Function type for comparing nodes in a heap
-+ *
-+ * \param elm1 the first element
-+ * \param elm2 the second element
-+ *
-+ * \retval negative if elm1 < elm2
-+ * \retval 0 if elm1 == elm2
-+ * \retval positive if elm1 > elm2
-+ *
-+ * \note This implementation is of a max heap. However, if a min heap is
-+ * desired, simply swap the return values of this function.
-+ */
-+typedef int (*ast_heap_cmp_fn)(void *elm1, void *elm2);
-+
-+/*!
-+ * \brief Create a max heap
-+ *
-+ * \param init_height The initial height of the heap to allocate space for.
-+ * To start out, there will be room for (2 ^ init_height) - 1 entries.
-+ * However, the heap will grow as needed.
-+ * \param cmp_fn The function that should be used to compare elements in the heap.
-+ * \param index_offset This parameter is optional, but must be provided to be able
-+ * to use ast_heap_remove(). This is the number of bytes into the element
-+ * where an ssize_t has been made available for the heap's internal
-+ * use. The heap will use this field to keep track of the element's current
-+ * position in the heap. The offsetof() macro is useful for providing a
-+ * proper value for this argument. If ast_heap_remove() will not be used,
-+ * then a negative value can be provided to indicate that no field for an
-+ * offset has been allocated.
-+ *
-+ * Example Usage:
-+ *
-+ * \code
-+ *
-+ * struct myobj {
-+ * int foo;
-+ * int bar;
-+ * char stuff[8];
-+ * char things[8];
-+ * ssize_t __heap_index;
-+ * };
-+ *
-+ * ...
-+ *
-+ * static int myobj_cmp(void *obj1, void *obj2);
-+ *
-+ * ...
-+ *
-+ * struct ast_heap *h;
-+ *
-+ * h = ast_heap_create(8, myobj_cmp, offsetof(struct myobj, __heap_index));
-+ *
-+ * \endcode
-+ *
-+ * \return An instance of a max heap
-+ */
-+struct ast_heap *ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_fn,
-+ ssize_t index_offset);
-+
-+/*!
-+ * \brief Destroy a max heap
-+ *
-+ * \param h the heap to destroy
-+ *
-+ * \return NULL for convenience
-+ */
-+struct ast_heap *ast_heap_destroy(struct ast_heap *h);
-+
-+/*!
-+ * \brief Push an element on to a heap
-+ *
-+ * \param h the heap being added to
-+ * \param elm the element being put on the heap
-+ *
-+ * \retval 0 success
-+ * \retval non-zero failure
-+ */
-+int ast_heap_push(struct ast_heap *h, void *elm);
-+
-+/*!
-+ * \brief Pop the max element off of the heap
-+ *
-+ * \param h the heap
-+ *
-+ * \return this will return the element on the top of the heap, which has the
-+ * largest value according to the element comparison function that was
-+ * provided when the heap was created. The element will be removed before
-+ * being returned.
-+ */
-+void *ast_heap_pop(struct ast_heap *h);
-+
-+/*!
-+ * \brief Remove a specific element from a heap
-+ *
-+ * \param h the heap to remove from
-+ * \param elm the element to remove
-+ *
-+ * \return elm, if the removal was successful, or NULL if it failed
-+ *
-+ * \note the index_offset parameter to ast_heap_create() is required to be able
-+ * to use this function.
-+ */
-+void *ast_heap_remove(struct ast_heap *h, void *elm);
-+
-+/*!
-+ * \brief Peek at an element on a heap
-+ *
-+ * \param h the heap
-+ * \param index index of the element to return. The first element is at index 1,
-+ * and the last element is at the index == the size of the heap.
-+ *
-+ * \return an element at the specified index on the heap. This element will \b not
-+ * be removed before being returned.
-+ *
-+ * \note If this function is being used in combination with ast_heap_size() for
-+ * purposes of traversing the heap, the heap must be locked for the entire
-+ * duration of the traversal.
-+ *
-+ * Example code for a traversal:
-+ * \code
-+ *
-+ * struct ast_heap *h;
-+ *
-+ * ...
-+ *
-+ * size_t size, i;
-+ * void *cur_obj;
-+ *
-+ * ast_heap_rdlock(h);
-+ *
-+ * size = ast_heap_size(h);
-+ *
-+ * for (i = 1; i <= size && (cur_obj = ast_heap_peek(h, i)); i++) {
-+ * ... Do stuff with cur_obj ...
-+ * }
-+ *
-+ * ast_heap_unlock(h);
-+ *
-+ * \endcode
-+ */
-+void *ast_heap_peek(struct ast_heap *h, unsigned int index);
-+
-+/*!
-+ * \brief Get the current size of a heap
-+ *
-+ * \param h the heap
-+ *
-+ * \return the number of elements currently in the heap
-+ */
-+size_t ast_heap_size(struct ast_heap *h);
-+
-+/*!
-+ * \brief Write-Lock a heap
-+ *
-+ * \arg h the heap
-+ *
-+ * A lock is provided for convenience. It can be assumed that none of the
-+ * ast_heap API calls are thread safe. This lock does not have to be used
-+ * if another one is already available to protect the heap.
-+ *
-+ * \return see the documentation for pthread_rwlock_wrlock()
-+ */
-+int ast_heap_wrlock(struct ast_heap *h);
-+
-+/*!
-+ * \brief Read-Lock a heap
-+ *
-+ * \arg h the heap
-+ *
-+ * A lock is provided for convenience. It can be assumed that none of the
-+ * ast_heap API calls are thread safe. This lock does not have to be used
-+ * if another one is already available to protect the heap.
-+ *
-+ * \return see the documentation for pthread_rwlock_rdlock()
-+ */
-+int ast_heap_rdlock(struct ast_heap *h);
-+
-+/*!
-+ * \brief Unlock a heap
-+ *
-+ * \arg h the heap
-+ *
-+ * \return see the documentation for pthread_rwlock_unlock()
-+ */
-+int ast_heap_unlock(struct ast_heap *h);
-+
-+/*!
-+ * \brief Verify that a heap has been properly constructed
-+ *
-+ * \param h a heap
-+ *
-+ * \retval 0 success
-+ * \retval non-zero failure
-+ *
-+ * \note This function is mostly for debugging purposes. It traverses an existing
-+ * heap and verifies that every node is properly placed relative to its children.
-+ */
-+int ast_heap_verify(struct ast_heap *h);
-+
-+#endif /* __AST_HEAP_H__ */
-
-Property changes on: include/asterisk/heap.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: include/asterisk/optional_api.h
-===================================================================
---- a/include/asterisk/optional_api.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/include/asterisk/optional_api.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,126 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Kevin P. Fleming <kpfleming@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+#ifndef __ASTERISK_OPTIONAL_API_H
-+#define __ASTERISK_OPTIONAL_API_H
-+
-+/*!
-+ * \file
-+ * \brief Optional API function macros
-+ *
-+ * Some Asterisk API functions are provided by loadable modules, thus,
-+ * they may or may not be available at run time depending on whether the
-+ * providing module has been loaded or not. In addition, there are some
-+ * modules that are consumers of these APIs that *optionally* use them; they
-+ * have only a part of their functionality dependent on the APIs, and can
-+ * provide the remainder even if the APIs are not available.
-+ *
-+ * To accomodate this situation, the AST_OPTIONAL_API macro allows an API
-+ * function to be declared in a special way, if Asterisk being built on a
-+ * platform that supports the GCC 'weak' and 'alias' attributes. If so,
-+ * the API function is actually a weak symbol, which means if the provider
-+ * of the API is not loaded, the symbol can still be referenced (unlike a
-+ * strong symbol, which would cause an immediate fault if not defined when
-+ * referenced), but it will return NULL signifying the linker/loader was
-+ * not able to resolve the symbol. In addition, the macro defines a hidden
-+ * 'stub' version of the API call, using a provided function body, and uses
-+ * the alias attribute to make the API function symbol actually resolve to
-+ * that hidden stub, but only when the *real* provider of the symbol has
-+ * not been found.
-+ *
-+ * An example can be found in agi.h:
-+ *
-+ * \code
-+ * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd),
-+ * { return AST_OPTIONAL_API_UNAVAILABLE; });
-+ * \endcode
-+ *
-+ * This defines the 'ast_agi_register' function as an optional API; if a
-+ * consumer of this API is loaded when there is no provider of it, then
-+ * calling this function will actually call the hidden stub, and return
-+ * the value AST_OPTIONAL_API_UNAVAILABLE. This allows the consumer to
-+ * safely know that the API is not available, and to avoid using any
-+ * other APIs from the not-present provider.
-+ *
-+ * In the module providing the API, the AST_OPTIONAL_API macro must
-+ * be informed that it should not build the hidden stub function or
-+ * apply special aliases to the function prototype; this can be done
-+ * by defining AST_API_MODULE just before including the header file
-+ * containing the AST_OPTIONAL_API macro calls.
-+ *
-+ * \note If the GCC 'weak' and 'alias' attributes are not available,
-+ * then the AST_OPTIONAL_API macro will result in a non-optional function
-+ * definition; this means that any consumers of the API functions so
-+ * defined will require that the provider of the API functions be
-+ * loaded before they can reference the symbols.
-+ */
-+
-+#define __stringify_1(x) #x
-+#define __stringify(x) __stringify_1(x)
-+
-+/*!
-+ * \brief A common value for optional API stub functions to return
-+ *
-+ * This value is defined as INT_MIN, the minimum value for an integer
-+ * (maximum negative value), which can be used by any optional API
-+ * functions that return a signed integer value and would not be
-+ * able to return such a value under normal circumstances.
-+ */
-+#define AST_OPTIONAL_API_UNAVAILABLE INT_MIN
-+
-+#if defined(HAVE_ATTRIBUTE_weak_import) && !defined(AST_API_MODULE)
-+#define AST_OPTIONAL_API(result, name, proto, stub) result name proto __attribute__((weak_import));
-+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result name proto __attribute__((weak_import,attr));
-+#elif defined(HAVE_ATTRIBUTE_weak) && defined(HAVE_ATTRIBUTE_alias) && !defined(AST_API_MODULE) && !defined(HAVE_ATTRIBUTE_weak_import)
-+#define AST_OPTIONAL_API(result, name, proto, stub) \
-+ static result __##name proto stub; \
-+ result __attribute__((weak, alias("__" __stringify(name)))) name proto;
-+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
-+ static result __attribute__((attr)) __##name proto stub; \
-+ result __attribute__((weak, alias("__" __stringify(name)), attr)) name proto;
-+#else
-+/*!
-+ * \brief Define an optional API function
-+ *
-+ * \param result The type of result the function returns
-+ * \param name The name of the function
-+ * \param proto The prototype (arguments) of the function
-+ * \param stub The code block that will be used by the hidden stub when needed
-+ *
-+ * Example usage:
-+ * \code
-+ * AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd),
-+ * { return AST_OPTIONAL_API_UNAVAILABLE; });
-+ * \endcode
-+ */
-+#define AST_OPTIONAL_API(result, name, proto, stub) result name proto;
-+/*!
-+ * \brief Define an optional API function with compiler attributes
-+ *
-+ * \param result The type of result the function returns
-+ * \param attr Any compiler attributes to be applied to the function (without the __attribute__ wrapper)
-+ * \param name The name of the function
-+ * \param proto The prototype (arguments) of the function
-+ * \param stub The code block that will be used by the hidden stub when needed
-+ */
-+#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) name proto;
-+#endif
-+
-+#undef AST_API_MODULE
-+
-+#endif /* __ASTERISK_OPTIONAL_API_H */
-
-Property changes on: include/asterisk/optional_api.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: include/asterisk/sched.h
-===================================================================
---- a/include/asterisk/sched.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/sched.h (.../team/group/issue14292) (revision 178988)
-@@ -49,15 +49,17 @@
- * and not a copy of the value of the id.
- */
- #define AST_SCHED_DEL(sched, id) \
-- do { \
-+ ({ \
- int _count = 0; \
-- while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
-+ int _sched_res = -1; \
-+ while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) \
- usleep(1); \
-+ if (_count == 10 && option_debug > 2) { \
-+ ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \
- } \
-- if (_count == 10) \
-- ast_debug(3, "Unable to cancel schedule ID %d.\n", id); \
- id = -1; \
-- } while (0);
-+ (_sched_res); \
-+ })
-
- #define AST_SCHED_DEL_UNREF(sched, id, refcall) \
- do { \
-@@ -145,13 +147,12 @@
- typedef int (*ast_sched_cb)(const void *data);
- #define AST_SCHED_CB(a) ((ast_sched_cb)(a))
-
--struct ast_cb_names
--{
-+struct ast_cb_names {
- int numassocs;
- char *list[10];
- ast_sched_cb cblist[10];
- };
--char *ast_sched_report(struct sched_context *con, char *buf, int bufsiz, struct ast_cb_names *cbnames);
-+void ast_sched_report(struct sched_context *con, struct ast_str **buf, struct ast_cb_names *cbnames);
-
- /*! \brief Adds a scheduled event
- * Schedule an event to take place at some point in the future. callback
-@@ -256,7 +257,7 @@
- * Debugging: Dump the contents of the scheduler to stderr
- * \param con Context to dump
- */
--void ast_sched_dump(const struct sched_context *con);
-+void ast_sched_dump(struct sched_context *con);
-
- /*! \brief Returns the number of seconds before an event takes place
- * \param con Context to use
-@@ -282,6 +283,114 @@
- } \
- } while(0)
-
-+/*!
-+ * \brief An opaque type representing a scheduler thread
-+ *
-+ * The purpose of the ast_sched_thread API is to provide a common implementation
-+ * of the case where a module wants to have a dedicated thread for handling the
-+ * scheduler.
-+ */
-+struct ast_sched_thread;
-+
-+/*!
-+ * \brief Create a scheduler with a dedicated thread
-+ *
-+ * This function should be used to allocate a scheduler context and a dedicated
-+ * thread for processing scheduler entries. The thread is started immediately.
-+ *
-+ * \retval NULL error
-+ * \retval non-NULL a handle to the scheduler and its dedicated thread.
-+ */
-+struct ast_sched_thread *ast_sched_thread_create(void);
-+
-+/*!
-+ * \brief Destroy a scheduler and its thread
-+ *
-+ * This function is used to destroy a scheduler context and the dedicated thread
-+ * that was created for handling scheduler entries. Any entries in the scheduler
-+ * that have not yet been processed will be thrown away. Once this function is
-+ * called, the handle must not be used again.
-+ *
-+ * \param st the handle to the scheduler and thread
-+ *
-+ * \return NULL for convenience
-+ */
-+struct ast_sched_thread *ast_sched_thread_destroy(struct ast_sched_thread *st);
-+
-+/*!
-+ * \brief Add a scheduler entry
-+ *
-+ * \param st the handle to the scheduler and thread
-+ * \param when the number of ms in the future to run the task. A value <= 0
-+ * is treated as "run now".
-+ * \param cb the function to call when the scheduled time arrives
-+ * \param data the parameter to pass to the scheduler callback
-+ *
-+ * \retval 0 success
-+ * \retval non-zero failure
-+ */
-+int ast_sched_thread_add(struct ast_sched_thread *st, int when, ast_sched_cb cb,
-+ const void *data);
-+
-+/*!
-+ * \brief Add a variable reschedule time scheduler entry
-+ *
-+ * \param st the handle to the scheduler and thread
-+ * \param when the number of ms in the future to run the task. A value <= 0
-+ * is treated as "run now".
-+ * \param cb the function to call when the scheduled time arrives
-+ * \param data the parameter to pass to the scheduler callback
-+ * \param variable If this value is non-zero, then the scheduler will use the return
-+ * value of the scheduler as the amount of time in the future to run the
-+ * task again. Normally, a return value of 0 means do not re-schedule, and
-+ * non-zero means re-schedule using the time provided when the scheduler
-+ * entry was first created.
-+ *
-+ * \retval 0 success
-+ * \retval non-zero failure
-+ */
-+int ast_sched_thread_add_variable(struct ast_sched_thread *st, int when, ast_sched_cb cb,
-+ const void *data, int variable);
-+
-+/*!
-+ * \brief Get the scheduler context for a given ast_sched_thread
-+ *
-+ * This function should be used only when direct access to the scheduler context
-+ * is required. Its use is discouraged unless necessary. The cases where
-+ * this is currently required is when you want to take advantage of one of the
-+ * AST_SCHED macros.
-+ *
-+ * \param st the handle to the scheduler and thread
-+ *
-+ * \return the sched_context associated with an ast_sched_thread
-+ */
-+struct sched_context *ast_sched_thread_get_context(struct ast_sched_thread *st);
-+
-+/*!
-+ * \brief Delete a scheduler entry
-+ *
-+ * This uses the AST_SCHED_DEL macro internally.
-+ *
-+ * \param st the handle to the scheduler and thread
-+ * \param id scheduler entry id to delete
-+ *
-+ * \retval 0 success
-+ * \retval non-zero failure
-+ */
-+#define ast_sched_thread_del(st, id) ({ \
-+ struct sched_context *__tmp_context = ast_sched_thread_get_context(st); \
-+ AST_SCHED_DEL(__tmp_context, id); \
-+})
-+
-+/*!
-+ * \brief Force re-processing of the scheduler context
-+ *
-+ * \param st the handle to the scheduler and thread
-+ *
-+ * \return nothing
-+ */
-+void ast_sched_thread_poke(struct ast_sched_thread *st);
-+
- #if defined(__cplusplus) || defined(c_plusplus)
- }
- #endif
-Index: include/asterisk/pbx.h
-===================================================================
---- a/include/asterisk/pbx.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/pbx.h (.../team/group/issue14292) (revision 178988)
-@@ -26,6 +26,7 @@
- #include "asterisk/sched.h"
- #include "asterisk/chanvars.h"
- #include "asterisk/hashtab.h"
-+#include "asterisk/stringfields.h"
-
- #if defined(__cplusplus) || defined(c_plusplus)
- extern "C" {
-@@ -70,12 +71,23 @@
- /*! \brief Typedef for devicestate and hint callbacks */
- typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data);
-
-+/*! \brief From where the documentation come from */
-+enum ast_doc_src {
-+ AST_XML_DOC, /*!< From XML documentation */
-+ AST_STATIC_DOC /*!< From application/function registration */
-+};
-+
- /*! \brief Data structure associated with a custom dialplan function */
- struct ast_custom_function {
-- const char *name; /*!< Name */
-- const char *synopsis; /*!< Short description for "show functions" */
-- const char *desc; /*!< Help text that explains it all */
-- const char *syntax; /*!< Syntax description */
-+ const char *name; /*!< Name */
-+ AST_DECLARE_STRING_FIELDS(
-+ AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show functions' */
-+ AST_STRING_FIELD(desc); /*!< Description (help text) for 'show functions &lt;name&gt;' */
-+ AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show functions' */
-+ AST_STRING_FIELD(arguments); /*!< Arguments description */
-+ AST_STRING_FIELD(seealso); /*!< See also */
-+ );
-+ enum ast_doc_src docsrc; /*!< Where the documentation come from */
- int (*read)(struct ast_channel *, const char *, char *, char *, size_t); /*!< Read function, if read is supported */
- int (*write)(struct ast_channel *, const char *, char *, const char *); /*!< Write function, if write is supported */
- struct ast_module *mod; /*!< Module this custom function belongs to */
-@@ -99,16 +111,33 @@
- };
-
- struct ast_timing {
-- int hastime; /*!< If time construct exists */
-- unsigned int monthmask; /*!< Mask for month */
-- unsigned int daymask; /*!< Mask for date */
-- unsigned int dowmask; /*!< Mask for day of week (mon-sun) */
-- unsigned int minmask[24]; /*!< Mask for minute */
-+ int hastime; /*!< If time construct exists */
-+ unsigned int monthmask; /*!< Mask for month */
-+ unsigned int daymask; /*!< Mask for date */
-+ unsigned int dowmask; /*!< Mask for day of week (sun-sat) */
-+ unsigned int minmask[48]; /*!< Mask for minute */
-+ char *timezone; /*!< NULL, or zoneinfo style timezone */
- };
-
-+/*!\brief Construct a timing bitmap, for use in time-based conditionals.
-+ * \param i Pointer to an ast_timing structure.
-+ * \param info Standard string containing a timerange, weekday range, monthday range, and month range, as well as an optional timezone.
-+ * \retval Returns 1 on success or 0 on failure.
-+ */
- int ast_build_timing(struct ast_timing *i, const char *info);
-+
-+/*!\brief Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified.
-+ * \param i Pointer to an ast_timing structure.
-+ * \retval Returns 1, if the time matches or 0, if the current time falls outside of the specified range.
-+ */
- int ast_check_timing(const struct ast_timing *i);
-
-+/*!\brief Deallocates memory structures associated with a timing bitmap.
-+ * \param i Pointer to an ast_timing structure.
-+ * \retval Returns 0 on success or a number suitable for passing into strerror, otherwise.
-+ */
-+int ast_destroy_timing(struct ast_timing *i);
-+
- struct ast_pbx {
- int dtimeoutms; /*!< Timeout between digits (milliseconds) */
- int rtimeoutms; /*!< Timeout for response (milliseconds) */
-@@ -906,6 +935,8 @@
-
- void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
- void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count);
-+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
-+void ast_str_substitute_variables(struct ast_str **buf, size_t maxlen, struct ast_channel *chan, const char *templ);
-
- int ast_extension_patmatch(const char *pattern, const char *data);
-
-Index: include/asterisk/strings.h
-===================================================================
---- a/include/asterisk/strings.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/strings.h (.../team/group/issue14292) (revision 178988)
-@@ -23,14 +23,29 @@
- #ifndef _ASTERISK_STRINGS_H
- #define _ASTERISK_STRINGS_H
-
-+/* #define DEBUG_OPAQUE */
-+
- #include <ctype.h>
-
--#include "asterisk/inline_api.h"
- #include "asterisk/utils.h"
- #include "asterisk/threadstorage.h"
-
-+#if defined(DEBUG_OPAQUE)
-+#define __AST_STR_USED used2
-+#define __AST_STR_LEN len2
-+#define __AST_STR_STR str2
-+#define __AST_STR_TS ts2
-+#else
-+#define __AST_STR_USED used
-+#define __AST_STR_LEN len
-+#define __AST_STR_STR str
-+#define __AST_STR_TS ts
-+#endif
-+
- /* You may see casts in this header that may seem useless but they ensure this file is C++ clean */
-
-+#define AS_OR(a,b) (a && ast_str_strlen(a)) ? ast_str_buffer(a) : (b)
-+
- #ifdef AST_DEVMODE
- #define ast_strlen_zero(foo) _ast_strlen_zero(foo, __FILE__, __PRETTY_FUNCTION__, __LINE__)
- static force_inline int _ast_strlen_zero(const char *s, const char *file, const char *function, int line)
-@@ -45,7 +60,7 @@
- }
-
- #else
--static force_inline int ast_strlen_zero(const char *s)
-+static force_inline int attribute_pure ast_strlen_zero(const char *s)
- {
- return (!s || (*s == '\0'));
- }
-@@ -54,13 +69,13 @@
- /*! \brief returns the equivalent of logic or for strings:
- * first one if not empty, otherwise second one.
- */
--#define S_OR(a, b) (!ast_strlen_zero(a) ? (a) : (b))
-+#define S_OR(a, b) ({typeof(&((a)[0])) __x = (a); ast_strlen_zero(__x) ? (b) : __x;})
-
- /*! \brief returns the equivalent of logic or for strings, with an additional boolean check:
- * second one if not empty and first one is true, otherwise third one.
- * example: S_COR(usewidget, widget, "<no widget>")
- */
--#define S_COR(a, b, c) ((a && !ast_strlen_zero(b)) ? (b) : (c))
-+#define S_COR(a, b, c) ({typeof(&((b)[0])) __x = (b); (a) && !ast_strlen_zero(__x) ? (__x) : (c);})
-
- /*!
- \brief Gets a pointer to the first non-whitespace character in a string.
-@@ -68,11 +83,11 @@
- \return a pointer to the first non-whitespace character
- */
- AST_INLINE_API(
--char *ast_skip_blanks(const char *str),
-+char * attribute_pure ast_skip_blanks(const char *str),
- {
- while (*str && ((unsigned char) *str) < 33)
- str++;
-- return (char *)str;
-+ return (char *) str;
- }
- )
-
-@@ -107,11 +122,11 @@
- \return a pointer to the first whitespace character
- */
- AST_INLINE_API(
--char *ast_skip_nonblanks(char *str),
-+char * attribute_pure ast_skip_nonblanks(const char *str),
- {
- while (*str && ((unsigned char) *str) > 32)
- str++;
-- return str;
-+ return (char *) str;
- }
- )
-
-@@ -127,9 +142,9 @@
- AST_INLINE_API(
- char *ast_strip(char *s),
- {
-- s = ast_skip_blanks(s);
-- if (s)
-+ if ((s = ast_skip_blanks(s))) {
- ast_trim_blanks(s);
-+ }
- return s;
- }
- )
-@@ -202,7 +217,6 @@
- }
- )
-
--
- /*!
- \brief Build a string in a buffer, designed to be called repeatedly
-
-@@ -243,7 +257,7 @@
- * \retval -1 if "true".
- * \retval 0 otherwise.
- */
--int ast_true(const char *val);
-+int attribute_pure ast_true(const char *val);
-
- /*!
- * \brief Make sure something is false.
-@@ -255,7 +269,7 @@
- * \retval -1 if "true".
- * \retval 0 otherwise.
- */
--int ast_false(const char *val);
-+int attribute_pure ast_false(const char *val);
-
- /*
- * \brief Join an array of strings into a single string.
-@@ -338,13 +352,13 @@
- * struct ast_threadstorage pointer.
- */
- struct ast_str {
-- size_t len; /*!< The current maximum length of the string */
-- size_t used; /*!< Amount of space used */
-- struct ast_threadstorage *ts; /*!< What kind of storage is this ? */
-+ size_t __AST_STR_LEN; /*!< The current maximum length of the string */
-+ size_t __AST_STR_USED; /*!< Amount of space used */
-+ struct ast_threadstorage *__AST_STR_TS; /*!< What kind of storage is this ? */
- #define DS_MALLOC ((struct ast_threadstorage *)1)
- #define DS_ALLOCA ((struct ast_threadstorage *)2)
- #define DS_STATIC ((struct ast_threadstorage *)3) /* not supported yet */
-- char str[0]; /*!< The string buffer */
-+ char __AST_STR_STR[0]; /*!< The string buffer */
- };
-
- /*!
-@@ -366,11 +380,11 @@
- buf = (struct ast_str *)ast_calloc(1, sizeof(*buf) + init_len);
- if (buf == NULL)
- return NULL;
--
-- buf->len = init_len;
-- buf->used = 0;
-- buf->ts = DS_MALLOC;
-
-+ buf->__AST_STR_LEN = init_len;
-+ buf->__AST_STR_USED = 0;
-+ buf->__AST_STR_TS = DS_MALLOC;
-+
- return buf;
- }
- )
-@@ -382,13 +396,82 @@
- void ast_str_reset(struct ast_str *buf),
- {
- if (buf) {
-- buf->used = 0;
-- if (buf->len)
-- buf->str[0] = '\0';
-+ buf->__AST_STR_USED = 0;
-+ if (buf->__AST_STR_LEN) {
-+ buf->__AST_STR_STR[0] = '\0';
-+ }
- }
- }
- )
-
-+/*! \brief Update the length of the buffer, after using ast_str merely as a buffer.
-+ * \param buf A pointer to the ast_str string.
-+ */
-+AST_INLINE_API(
-+void ast_str_update(struct ast_str *buf),
-+{
-+ buf->__AST_STR_USED = strlen(buf->__AST_STR_STR);
-+}
-+)
-+
-+/*! \brief Trims trailing whitespace characters from an ast_str string.
-+ * \param buf A pointer to the ast_str string.
-+ */
-+AST_INLINE_API(
-+void ast_str_trim_blanks(struct ast_str *buf),
-+{
-+ if (!buf) {
-+ return;
-+ }
-+ while (buf->__AST_STR_USED && buf->__AST_STR_STR[buf->__AST_STR_USED - 1] < 33) {
-+ buf->__AST_STR_STR[--(buf->__AST_STR_USED)] = '\0';
-+ }
-+}
-+)
-+
-+/*!\brief Returns the current length of the string stored within buf.
-+ * \param A pointer to the ast_str string.
-+ */
-+AST_INLINE_API(
-+size_t attribute_pure ast_str_strlen(struct ast_str *buf),
-+{
-+ return buf->__AST_STR_USED;
-+}
-+)
-+
-+/*!\brief Returns the current maximum length (without reallocation) of the current buffer.
-+ * \param A pointer to the ast_str string.
-+ */
-+AST_INLINE_API(
-+size_t attribute_pure ast_str_size(struct ast_str *buf),
-+{
-+ return buf->__AST_STR_LEN;
-+}
-+)
-+
-+/*!\brief Returns the string buffer within the ast_str buf.
-+ * \param A pointer to the ast_str string.
-+ */
-+AST_INLINE_API(
-+char * attribute_pure ast_str_buffer(struct ast_str *buf),
-+{
-+ return buf->__AST_STR_STR;
-+}
-+)
-+
-+AST_INLINE_API(
-+char *ast_str_truncate(struct ast_str *buf, ssize_t len),
-+{
-+ if (len < 0) {
-+ buf->__AST_STR_USED += ((ssize_t) abs(len)) > (ssize_t) buf->__AST_STR_USED ? -buf->__AST_STR_USED : len;
-+ } else {
-+ buf->__AST_STR_USED = len;
-+ }
-+ buf->__AST_STR_STR[buf->__AST_STR_USED] = '\0';
-+ return buf->__AST_STR_STR;
-+}
-+)
-+
- /*
- * AST_INLINE_API() is a macro that takes a block of code as an argument.
- * Using preprocessor #directives in the argument is not supported by all
-@@ -412,21 +495,21 @@
- {
- struct ast_str *old_buf = *buf;
-
-- if (new_len <= (*buf)->len)
-+ if (new_len <= (*buf)->__AST_STR_LEN)
- return 0; /* success */
-- if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC)
-+ if ((*buf)->__AST_STR_TS == DS_ALLOCA || (*buf)->__AST_STR_TS == DS_STATIC)
- return -1; /* cannot extend */
- *buf = (struct ast_str *)__ast_realloc(*buf, new_len + sizeof(struct ast_str), file, lineno, function);
- if (*buf == NULL) {
- *buf = old_buf;
- return -1;
- }
-- if ((*buf)->ts != DS_MALLOC) {
-- pthread_setspecific((*buf)->ts->key, *buf);
-+ if ((*buf)->__AST_STR_TS != DS_MALLOC) {
-+ pthread_setspecific((*buf)->__AST_STR_TS->key, *buf);
- _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));)
- }
-
-- (*buf)->len = new_len;
-+ (*buf)->__AST_STR_LEN = new_len;
- return 0;
- }
- )
-@@ -437,22 +520,22 @@
- {
- struct ast_str *old_buf = *buf;
-
-- if (new_len <= (*buf)->len)
-+ if (new_len <= (*buf)->__AST_STR_LEN)
- return 0; /* success */
-- if ((*buf)->ts == DS_ALLOCA || (*buf)->ts == DS_STATIC)
-+ if ((*buf)->__AST_STR_TS == DS_ALLOCA || (*buf)->__AST_STR_TS == DS_STATIC)
- return -1; /* cannot extend */
- *buf = (struct ast_str *)ast_realloc(*buf, new_len + sizeof(struct ast_str));
- if (*buf == NULL) {
- *buf = old_buf;
- return -1;
- }
-- if ((*buf)->ts != DS_MALLOC) {
-- pthread_setspecific((*buf)->ts->key, *buf);
-+ if ((*buf)->__AST_STR_TS != DS_MALLOC) {
-+ pthread_setspecific((*buf)->__AST_STR_TS->key, *buf);
- _DB1(__ast_threadstorage_object_replace(old_buf, *buf, new_len + sizeof(struct ast_str));)
- }
-
-- (*buf)->len = new_len;
-- return 0;
-+ (*buf)->__AST_STR_LEN = new_len;
-+ return 0;
- }
- )
- #endif
-@@ -461,10 +544,10 @@
- ({ \
- struct ast_str *__ast_str_buf; \
- __ast_str_buf = alloca(sizeof(*__ast_str_buf) + init_len); \
-- __ast_str_buf->len = init_len; \
-- __ast_str_buf->used = 0; \
-- __ast_str_buf->ts = DS_ALLOCA; \
-- __ast_str_buf->str[0] = '\0'; \
-+ __ast_str_buf->__AST_STR_LEN = init_len; \
-+ __ast_str_buf->__AST_STR_USED = 0; \
-+ __ast_str_buf->__AST_STR_TS = DS_ALLOCA; \
-+ __ast_str_buf->__AST_STR_STR[0] = '\0'; \
- (__ast_str_buf); \
- })
-
-@@ -509,11 +592,11 @@
- buf = (struct ast_str *)ast_threadstorage_get(ts, sizeof(*buf) + init_len);
- if (buf == NULL)
- return NULL;
--
-- if (!buf->len) {
-- buf->len = init_len;
-- buf->used = 0;
-- buf->ts = ts;
-+
-+ if (!buf->__AST_STR_LEN) {
-+ buf->__AST_STR_LEN = init_len;
-+ buf->__AST_STR_USED = 0;
-+ buf->__AST_STR_TS = ts;
- }
-
- return buf;
-@@ -529,11 +612,11 @@
- buf = (struct ast_str *)__ast_threadstorage_get(ts, sizeof(*buf) + init_len, file, function, line);
- if (buf == NULL)
- return NULL;
--
-- if (!buf->len) {
-- buf->len = init_len;
-- buf->used = 0;
-- buf->ts = ts;
-+
-+ if (!buf->__AST_STR_LEN) {
-+ buf->__AST_STR_LEN = init_len;
-+ buf->__AST_STR_USED = 0;
-+ buf->__AST_STR_TS = ts;
- }
-
- return buf;
-@@ -584,6 +667,8 @@
- */
- int __attribute__((format(printf, 4, 0))) __ast_str_helper(struct ast_str **buf, size_t max_len,
- int append, const char *fmt, va_list ap);
-+char *__ast_str_helper2(struct ast_str **buf, size_t max_len,
-+ const char *src, size_t maxsrc, int append, int escapecommas);
-
- /*!
- * \brief Set a dynamic string from a va_list
-@@ -640,6 +725,34 @@
- }
- )
-
-+/*!\brief Set a dynamic string to a non-NULL terminated substring. */
-+AST_INLINE_API(char *ast_str_set_substr(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
-+{
-+ return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 0);
-+}
-+)
-+
-+/*!\brief Append a non-NULL terminated substring to the end of a dynamic string. */
-+AST_INLINE_API(char *ast_str_append_substr(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
-+{
-+ return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 0);
-+}
-+)
-+
-+/*!\brief Set a dynamic string to a non-NULL terminated substring, with escaping of commas. */
-+AST_INLINE_API(char *ast_str_set_escapecommas(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
-+{
-+ return __ast_str_helper2(buf, maxlen, src, maxsrc, 0, 1);
-+}
-+)
-+
-+/*!\brief Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas. */
-+AST_INLINE_API(char *ast_str_append_escapecommas(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc),
-+{
-+ return __ast_str_helper2(buf, maxlen, src, maxsrc, 1, 1);
-+}
-+)
-+
- /*!
- * \brief Set a dynamic string using variable arguments
- *
-@@ -701,7 +814,7 @@
- *
- * http://www.cse.yorku.ca/~oz/hash.html
- */
--static force_inline int ast_str_hash(const char *str)
-+static force_inline int attribute_pure ast_str_hash(const char *str)
- {
- int hash = 5381;
-
-@@ -718,7 +831,7 @@
- * all characters to lowercase prior to computing a hash. This
- * allows for easy case-insensitive lookups in a hash table.
- */
--static force_inline int ast_str_case_hash(const char *str)
-+static force_inline int attribute_pure ast_str_case_hash(const char *str)
- {
- int hash = 5381;
-
-@@ -728,4 +841,5 @@
-
- return abs(hash);
- }
-+
- #endif /* _ASTERISK_STRINGS_H */
-Index: include/asterisk/stringfields.h
-===================================================================
---- a/include/asterisk/stringfields.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/stringfields.h (.../team/group/issue14292) (revision 178988)
-@@ -183,7 +183,7 @@
- */
- void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head,
-- const ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5)));
-+ ast_string_field *ptr, const char *format, ...) __attribute__((format(printf, 4, 5)));
-
- /*!
- \internal
-@@ -198,7 +198,7 @@
- */
- void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head,
-- const ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0)));
-+ ast_string_field *ptr, const char *format, va_list a1, va_list a2) __attribute__((format(printf, 4, 0)));
-
- /*!
- \brief Declare a string field
-@@ -287,7 +287,7 @@
- \return nothing
- */
- #define ast_string_field_ptr_build(x, ptr, fmt, args...) \
-- __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args)
-+ __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args)
-
- /*!
- \brief Set a field to a complex (built) value
-@@ -298,7 +298,7 @@
- \return nothing
- */
- #define ast_string_field_build(x, field, fmt, args...) \
-- __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args)
-+ __ast_string_field_ptr_build(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args)
-
- /*!
- \brief Set a field to a complex (built) value with prebuilt va_lists.
-@@ -310,7 +310,7 @@
- \return nothing
- */
- #define ast_string_field_ptr_build_va(x, ptr, fmt, args1, args2) \
-- __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, ptr, fmt, args1, args2)
-+ __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) ptr, fmt, args1, args2)
-
- /*!
- \brief Set a field to a complex (built) value
-@@ -322,6 +322,6 @@
- \return nothing
- */
- #define ast_string_field_build_va(x, field, fmt, args1, args2) \
-- __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, &(x)->field, fmt, args1, args2)
-+ __ast_string_field_ptr_build_va(&(x)->__field_mgr, &(x)->__field_mgr_pool, (ast_string_field *) &(x)->field, fmt, args1, args2)
-
- #endif /* _ASTERISK_STRINGFIELDS_H */
-Index: include/asterisk/agi.h
-===================================================================
---- a/include/asterisk/agi.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/agi.h (.../team/group/issue14292) (revision 178988)
-@@ -28,6 +28,7 @@
- #endif
-
- #include "asterisk/cli.h"
-+#include "asterisk/optional_api.h"
-
- typedef struct agi_state {
- int fd; /*!< FD for general output */
-@@ -38,43 +39,53 @@
- } AGI;
-
- typedef struct agi_command {
-- /* Null terminated list of the words of the command */
-- char *cmda[AST_MAX_CMD_LEN];
-- /* Handler for the command (channel, AGI state, # of arguments, argument list).
-+ char *cmda[AST_MAX_CMD_LEN]; /*!< Null terminated list of the words of the command */
-+ /*! Handler for the command (channel, AGI state, # of arguments, argument list).
- Returns RESULT_SHOWUSAGE for improper arguments */
- int (*handler)(struct ast_channel *chan, AGI *agi, int argc, char *argv[]);
-- /* Summary of the command (< 60 characters) */
-+ /*! Summary of the command (< 60 characters) */
- char *summary;
-- /* Detailed usage information */
-+ /*! Detailed usage information */
- char *usage;
-- /* Does this application run dead */
-+ /*! Does this application run dead */
- int dead;
-- /* Pointer to module that registered the agi command */
-+ /*! AGI command syntax description */
-+ char *syntax;
-+ /*! See also content */
-+ char *seealso;
-+ /*! Where the documentation come from. */
-+ enum ast_doc_src docsrc;
-+ /*! Pointer to module that registered the agi command */
- struct ast_module *mod;
-- /* Linked list pointer */
-+ /*! Linked list pointer */
- AST_LIST_ENTRY(agi_command) list;
- } agi_command;
-
--#if defined(ASTERISK_AGI_OPTIONAL)
--#define AGI_WEAK attribute_weak
--#else
--#define AGI_WEAK
--#endif
-+/*!
-+ * \brief
-+ *
-+ * Registers an AGI command.
-+ *
-+ * \param mod Pointer to the module_info structure for the module that is registering the command
-+ * \param cmd Pointer to the descriptor for the command
-+ * \return 1 on success, 0 if the command is already registered
-+ *
-+ */
-+AST_OPTIONAL_API(int, ast_agi_register, (struct ast_module *mod, agi_command *cmd),
-+ { return AST_OPTIONAL_API_UNAVAILABLE; });
-
- /*!
- * \brief
- *
-- * Sends a string of text to an application connected via AGI.
-+ * Unregisters an AGI command.
- *
-- * \param fd The file descriptor for the AGI session (from struct agi_state)
-- * \param chan Pointer to an associated Asterisk channel, if any
-- * \param fmt printf-style format string
-- * \return 0 for success, -1 for failure
-+ * \param mod Pointer to the module_info structure for the module that is unregistering the command
-+ * \param cmd Pointer to the descriptor for the command
-+ * \return 1 on success, 0 if the command was not already registered
- *
- */
--int AGI_WEAK ast_agi_send(int fd, struct ast_channel *chan, char *fmt, ...) __attribute__((format(printf, 3, 4)));
--int AGI_WEAK ast_agi_register(struct ast_module *mod, agi_command *cmd);
--int AGI_WEAK ast_agi_unregister(struct ast_module *mod, agi_command *cmd);
-+AST_OPTIONAL_API(int, ast_agi_unregister, (struct ast_module *mod, agi_command *cmd),
-+ { return AST_OPTIONAL_API_UNAVAILABLE; });
-
- /*!
- * \brief
-@@ -83,15 +94,16 @@
- * entries.
- *
- * \param mod Pointer to the module_info structure for the module that is registering the commands
-- * \param cmd Pointer to the first entry in the array of commands
-+ * \param cmd Pointer to the first entry in the array of command descriptors
- * \param len Length of the array (use the ARRAY_LEN macro to determine this easily)
-- * \return 0 on success, -1 on failure
-+ * \return 0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
- *
- * \note If any command fails to register, all commands previously registered during the operation
- * will be unregistered. In other words, this function registers all the provided commands, or none
- * of them.
- */
--int AGI_WEAK ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len);
-+AST_OPTIONAL_API(int, ast_agi_register_multiple, (struct ast_module *mod, struct agi_command *cmd, unsigned int len),
-+ { return AST_OPTIONAL_API_UNAVAILABLE; });
-
- /*!
- * \brief
-@@ -100,15 +112,30 @@
- * entries.
- *
- * \param mod Pointer to the module_info structure for the module that is unregistering the commands
-- * \param cmd Pointer to the first entry in the array of commands
-+ * \param cmd Pointer to the first entry in the array of command descriptors
- * \param len Length of the array (use the ARRAY_LEN macro to determine this easily)
-- * \return 0 on success, -1 on failure
-+ * \return 0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
- *
- * \note If any command fails to unregister, this function will continue to unregister the
- * remaining commands in the array; it will not reregister the already-unregistered commands.
- */
--int AGI_WEAK ast_agi_unregister_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len);
-+AST_OPTIONAL_API(int, ast_agi_unregister_multiple, (struct ast_module *mod, struct agi_command *cmd, unsigned int len),
-+ { return AST_OPTIONAL_API_UNAVAILABLE; });
-
-+/*!
-+ * \brief
-+ *
-+ * Sends a string of text to an application connected via AGI.
-+ *
-+ * \param fd The file descriptor for the AGI session (from struct agi_state)
-+ * \param chan Pointer to an associated Asterisk channel, if any
-+ * \param fmt printf-style format string
-+ * \return 0 for success, -1 for failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
-+ *
-+ */
-+AST_OPTIONAL_API_ATTR(int, format(printf, 3, 4), ast_agi_send, (int fd, struct ast_channel *chan, char *fmt, ...),
-+ { return AST_OPTIONAL_API_UNAVAILABLE; });
-+
- #if defined(__cplusplus) || defined(c_plusplus)
- }
- #endif
-Index: include/asterisk/autoconfig.h.in
-===================================================================
---- a/include/asterisk/autoconfig.h.in (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/autoconfig.h.in (.../team/group/issue14292) (revision 178988)
-@@ -91,6 +91,9 @@
- /* Define to 1 if you have the `atexit' function. */
- #undef HAVE_ATEXIT
-
-+/* Define to 1 if your GCC C compiler supports the 'alias' attribute. */
-+#undef HAVE_ATTRIBUTE_alias
-+
- /* Define to 1 if your GCC C compiler supports the 'always_inline' attribute.
- */
- #undef HAVE_ATTRIBUTE_always_inline
-@@ -120,6 +123,9 @@
- /* Define to 1 if your GCC C compiler supports the 'weak' attribute. */
- #undef HAVE_ATTRIBUTE_weak
-
-+/* Define to 1 if your GCC C compiler supports the 'weak_import' attribute. */
-+#undef HAVE_ATTRIBUTE_weak_import
-+
- /* Define this to indicate the ${BKTR_DESCRIP} library */
- #undef HAVE_BKTR
-
-@@ -150,6 +156,9 @@
- /* Define to 1 if your system has a working `chown' function. */
- #undef HAVE_CHOWN
-
-+/* Define to 1 if you have the `closefrom' function. */
-+#undef HAVE_CLOSEFROM
-+
- /* Define this to indicate the ${COS_DESCRIP} library */
- #undef HAVE_COS
-
-@@ -180,6 +189,18 @@
- /* Define if your system has the DAHDI headers. */
- #undef HAVE_DAHDI
-
-+/* Define if your system has the DAHDI_HALF_FULL headers. */
-+#undef HAVE_DAHDI_HALF_FULL
-+
-+/* Define DAHDI_HALF_FULL headers version */
-+#undef HAVE_DAHDI_HALF_FULL_VERSION
-+
-+/* Define if your system has the DAHDI_LINEREVERSE_VMWI headers. */
-+#undef HAVE_DAHDI_LINEREVERSE_VMWI
-+
-+/* Define DAHDI_LINEREVERSE_VMWI headers version */
-+#undef HAVE_DAHDI_LINEREVERSE_VMWI_VERSION
-+
- /* Define DAHDI headers version */
- #undef HAVE_DAHDI_VERSION
-
-@@ -319,6 +340,9 @@
- /* Define to 1 if you have the `getpagesize' function. */
- #undef HAVE_GETPAGESIZE
-
-+/* Define to 1 if you have the `getpeereid' function. */
-+#undef HAVE_GETPEEREID
-+
- /* Define to 1 if you have the `gettimeofday' function. */
- #undef HAVE_GETTIMEOFDAY
-
-@@ -374,9 +398,21 @@
- /* Define to 1 if you have the `inet_ntoa' function. */
- #undef HAVE_INET_NTOA
-
-+/* Define this to indicate the ${INOTIFY_DESCRIP} library */
-+#undef HAVE_INOTIFY
-+
-+/* Define to indicate the ${INOTIFY_DESCRIP} library version */
-+#undef HAVE_INOTIFY_VERSION
-+
- /* Define to 1 if you have the <inttypes.h> header file. */
- #undef HAVE_INTTYPES_H
-
-+/* Define this to indicate the ${IODBC_DESCRIP} library */
-+#undef HAVE_IODBC
-+
-+/* Define to indicate the ${IODBC_DESCRIP} library version */
-+#undef HAVE_IODBC_VERSION
-+
- /* Define to 1 if you have the `ioperm' function. */
- #undef HAVE_IOPERM
-
-@@ -410,6 +446,9 @@
- /* Define to 1 if you have the <libintl.h> header file. */
- #undef HAVE_LIBINTL_H
-
-+/* Define if your system has the LIBXML2 libraries. */
-+#undef HAVE_LIBXML2
-+
- /* Define to 1 if you have the <limits.h> header file. */
- #undef HAVE_LIMITS_H
-
-@@ -617,6 +656,12 @@
- /* Define to indicate the ${PRI_INBANDDISCONNECT_DESCRIP} library version */
- #undef HAVE_PRI_INBANDDISCONNECT_VERSION
-
-+/* Define this to indicate the ${PRI_PROG_W_CAUSE_DESCRIP} library */
-+#undef HAVE_PRI_PROG_W_CAUSE
-+
-+/* Define to indicate the ${PRI_PROG_W_CAUSE_DESCRIP} library version */
-+#undef HAVE_PRI_PROG_W_CAUSE_VERSION
-+
- /* Define to indicate the ${PRI_DESCRIP} library version */
- #undef HAVE_PRI_VERSION
-
-@@ -913,6 +958,12 @@
- /* Define to indicate the ${SUPPSERV_DESCRIP} library version */
- #undef HAVE_SUPPSERV_VERSION
-
-+/* Define to 1 if you have the `swapctl' function. */
-+#undef HAVE_SWAPCTL
-+
-+/* Define to 1 if you have the `sysctl' function. */
-+#undef HAVE_SYSCTL
-+
- /* Define to 1 if your system has sysinfo support */
- #undef HAVE_SYSINFO
-
-@@ -988,6 +1039,12 @@
- /* Define to 1 if you have the <termios.h> header file. */
- #undef HAVE_TERMIOS_H
-
-+/* Define if your system has the TIMERFD headers. */
-+#undef HAVE_TIMERFD
-+
-+/* Define TIMERFD headers version */
-+#undef HAVE_TIMERFD_VERSION
-+
- /* Define to 1 if your system defines timersub. */
- #undef HAVE_TIMERSUB
-
-Index: include/asterisk/extconf.h
-===================================================================
---- a/include/asterisk/extconf.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/extconf.h (.../team/group/issue14292) (revision 178988)
-@@ -76,8 +76,14 @@
- /*! \brief A registered application */
- struct ast_app {
- int (*execute)(struct ast_channel *chan, void *data);
-- const char *synopsis; /*!< Synopsis text for 'show applications' */
-- const char *description; /*!< Description (help text) for 'show application &lt;name&gt;' */
-+ AST_DECLARE_STRING_FIELDS(
-+ AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show applications' */
-+ AST_STRING_FIELD(description); /*!< Description (help text) for 'show application &lt;name&gt;' */
-+ AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show applications' */
-+ AST_STRING_FIELD(arguments); /*!< Arguments description */
-+ AST_STRING_FIELD(seealso); /*!< See also */
-+ );
-+ enum ast_xmldoc_src docsrc; /*!< Where the documentation come from. */
- AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
- void *module; /*!< Module this app belongs to */
- char name[0]; /*!< Name of the application */
-Index: include/asterisk/localtime.h
-===================================================================
---- a/include/asterisk/localtime.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/localtime.h (.../team/group/issue14292) (revision 178988)
-@@ -40,9 +40,42 @@
- int tm_usec; /*!< microseconds */
- };
-
-+/*!\brief Timezone-independent version of localtime_r(3).
-+ * \param timep Current time, including microseconds
-+ * \param p_tm Pointer to memory where the broken-out time will be stored
-+ * \param zone Text string of a standard system zoneinfo file. If NULL, the system localtime will be used.
-+ * \retval p_tm is returned for convenience
-+ */
- struct ast_tm *ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone);
-+
- void ast_get_dst_info(const time_t * const timep, int *dst_enabled, time_t *dst_start, time_t *dst_end, int *gmt_off, const char * const zone);
-+
-+/*!\brief Timezone-independent version of mktime(3).
-+ * \param tmp Current broken-out time, including microseconds
-+ * \param zone Text string of a standard system zoneinfo file. If NULL, the system localtime will be used.
-+ * \retval A structure containing both seconds and fractional thereof since January 1st, 1970 UTC
-+ */
- struct timeval ast_mktime(struct ast_tm * const tmp, const char *zone);
-+
-+/*!\brief Special version of strftime(3) that handles fractions of a second.
-+ * Takes the same arguments as strftime(3), with the addition of %q, which
-+ * specifies microseconds.
-+ * \param buf Address in memory where the resulting string will be stored.
-+ * \param len Size of the chunk of memory buf.
-+ * \param format A string specifying the format of time to be placed into buf.
-+ * \param tm Pointer to the broken out time to be used for the format.
-+ * \retval An integer value specifying the number of bytes placed into buf or -1 on error.
-+ */
- int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm);
-
-+/*!\brief Special version of strptime(3) which places the answer in the common
-+ * structure ast_tm. Also, unlike strptime(3), ast_strptime() initializes its
-+ * memory prior to use.
-+ * \param s A string specifying some portion of a date and time.
-+ * \param format The format in which the string, s, is expected.
-+ * \param tm The broken-out time structure into which the parsed data is expected.
-+ * \retval A pointer to the first character within s not used to parse the date and time.
-+ */
-+char *ast_strptime(const char *s, const char *format, struct ast_tm *tm);
-+
- #endif /* _ASTERISK_LOCALTIME_H */
-Index: include/asterisk/tcptls.h
-===================================================================
---- a/include/asterisk/tcptls.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/tcptls.h (.../team/group/issue14292) (revision 178988)
-@@ -157,6 +157,6 @@
- int ast_ssl_setup(struct ast_tls_config *cfg);
-
- HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *ser, void *buf, size_t count);
--HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, void *buf, size_t count);
-+HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, const void *buf, size_t count);
-
- #endif /* _ASTERISK_TCPTLS_H */
-Index: include/asterisk/compiler.h
-===================================================================
---- a/include/asterisk/compiler.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/compiler.h (.../team/group/issue14292) (revision 178988)
-@@ -74,4 +74,10 @@
- #define attribute_weak
- #endif
-
-+#ifdef HAVE_ATTRIBUTE_weak_import
-+#define attribute_weak_import __attribute__((weak_import))
-+#else
-+#define attribute_weak_import
-+#endif
-+
- #endif /* _ASTERISK_COMPILER_H */
-Index: include/asterisk/callerid.h
-===================================================================
---- a/include/asterisk/callerid.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/callerid.h (.../team/group/issue14292) (revision 178988)
-@@ -66,9 +66,9 @@
-
- /* defines dealing with message waiting indication generation */
- /*! MWI SDMF format */
--#define CID_MWI_TYPE_SDMF 0x00
-+#define CID_MWI_TYPE_SDMF 0x00
- /*! MWI MDMF format -- generate only MWI field */
--#define CID_MWI_TYPE_MDMF 0x01
-+#define CID_MWI_TYPE_MDMF 0x01
- /*! MWI MDMF format -- generate name, callerid, date and MWI fields */
- #define CID_MWI_TYPE_MDMF_FULL 0x02
-
-@@ -86,21 +86,24 @@
- void callerid_init(void);
-
- /*! \brief Generates a CallerID FSK stream in ulaw format suitable for transmission.
-- * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own. "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
-+ * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own.
-+ * "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
- * \param number Use NULL for no number or "P" for "private"
- * \param name name to be used
- * \param flags passed flags
- * \param callwaiting callwaiting flag
- * \param codec -- either AST_FORMAT_ULAW or AST_FORMAT_ALAW
-+ * \details
- * This function creates a stream of callerid (a callerid spill) data in ulaw format.
- * \return It returns the size
- * (in bytes) of the data (if it returns a size of 0, there is probably an error)
--*/
-+ */
- int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, int codec);
-
- /*! \brief Create a callerID state machine
- * \param cid_signalling Type of signalling in use
- *
-+ * \details
- * This function returns a malloc'd instance of the callerid_state data structure.
- * \return Returns a pointer to a malloc'd callerid_state structure, or NULL on error.
- */
-@@ -112,9 +115,11 @@
- * \param samples number of samples contained within the buffer.
- * \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
- *
-+ * \details
- * Send received audio to the Caller*ID demodulator.
-- * \return Returns -1 on error, 0 for "needs more samples",
-- * and 1 if the CallerID spill reception is complete.
-+ * \retval -1 on error
-+ * \retval 0 for "needs more samples"
-+ * \retval 1 if the CallerID spill reception is complete.
- */
- int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
-
-@@ -124,9 +129,11 @@
- * \param samples number of samples contained within the buffer.
- * \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
- *
-+ * \details
- * Send received audio to the Caller*ID demodulator (for japanese style lines).
-- * \return Returns -1 on error, 0 for "needs more samples",
-- * and 1 if the CallerID spill reception is complete.
-+ * \retval -1 on error
-+ * \retval 0 for "needs more samples"
-+ * \retval 1 if the CallerID spill reception is complete.
- */
- int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
-
-@@ -136,6 +143,7 @@
- * \param name Pass the address of a pointer-to-char (will contain the name)
- * \param flags Pass the address of an int variable(will contain the various callerid flags)
- *
-+ * \details
- * This function extracts a callerid string out of a callerid_state state machine.
- * If no number is found, *number will be set to NULL. Likewise for the name.
- * Flags can contain any of the following:
-@@ -144,18 +152,16 @@
- */
- void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags);
-
--/*! Get and parse DTMF-based callerid */
- /*!
-+ * \brief Get and parse DTMF-based callerid
- * \param cidstring The actual transmitted string.
- * \param number The cid number is returned here.
- * \param flags The cid flags are returned here.
-- * This function parses DTMF callerid.
- */
- void callerid_get_dtmf(char *cidstring, char *number, int *flags);
-
--/*! \brief Free a callerID state
-+/*! \brief This function frees callerid_state cid.
- * \param cid This is the callerid_state state machine to free
-- * This function frees callerid_state cid.
- */
- void callerid_free(struct callerid_state *cid);
-
-@@ -165,25 +171,27 @@
- * \param number Caller-ID Number
- * \param codec Asterisk codec (either AST_FORMAT_ALAW or AST_FORMAT_ULAW)
- *
-+ * \details
- * Acts like callerid_generate except uses an asterisk format callerid string.
- */
- int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int codec);
-
--/*! \brief Generate message waiting indicator
-+/*! \brief Generate message waiting indicator
- * \param active The message indicator state
- * -- either 0 no messages in mailbox or 1 messages in mailbox
- * \param type Format of message (any of CID_MWI_TYPE_*)
-- * \see callerid_generate() for more info as it use the same encoding
-+ * \see callerid_generate() for more info as it uses the same encoding
- */
- int vmwi_generate(unsigned char *buf, int active, int type, int codec, const char *name,
- const char *number, int flags);
-
- /*! \brief Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
-- * See ast_callerid_generate() for other details
-+ * \see ast_callerid_generate() for other details
- */
- int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, int codec);
-
- /*! \brief Destructively parse inbuf into name and location (or number)
-+ * \details
- * Parses callerid stream from inbuf and changes into useable form, outputed in name and location.
- * \param instr buffer of callerid stream (in audio form) to be parsed. Warning, data in buffer is changed.
- * \param name address of a pointer-to-char for the name value of the stream.
-@@ -192,8 +200,8 @@
- */
- int ast_callerid_parse(char *instr, char **name, char **location);
-
--/*! Generate a CAS (CPE Alert Signal) tone for 'n' samples */
- /*!
-+ * \brief Generate a CAS (CPE Alert Signal) tone for 'n' samples
- * \param outbuf Allocated buffer for data. Must be at least 2400 bytes unless no SAS is desired
- * \param sas Non-zero if CAS should be preceeded by SAS
- * \param len How many samples to generate.
-@@ -202,23 +210,26 @@
- */
- int ast_gen_cas(unsigned char *outbuf, int sas, int len, int codec);
-
--/*! \brief Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s... */
- /*!
-+ * \brief Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s...
- * \param n The number to be stripped/shrunk
- * \return Returns nothing important
- */
- void ast_shrink_phone_number(char *n);
-
--/*! \brief Check if a string consists only of digits and + \#
-- \param n number to be checked.
-- \return Returns 0 if n is a number, 1 if it's not.
-+/*!
-+ * \brief Check if a string consists only of digits and + \#
-+ * \param n number to be checked.
-+ * \return Returns 0 if n is a number, 1 if it's not.
- */
- int ast_isphonenumber(const char *n);
-
--/*! \brief Check if a string consists only of digits and and + \# ( ) - .
-- (meaning it can be cleaned with ast_shrink_phone_number)
-- \param exten The extension (or URI) to be checked.
-- \return Returns 0 if n is a number, 1 if it's not.
-+/*!
-+ * \brief Check if a string consists only of digits and and + \# ( ) - .
-+ * (meaning it can be cleaned with ast_shrink_phone_number)
-+ * \param exten The extension (or URI) to be checked.
-+ * \retval 1 if string is valid AST shrinkable phone number
-+ * \retval 0 if not
- */
- int ast_is_shrinkable_phonenumber(const char *exten);
-
-@@ -288,71 +299,111 @@
-
- /* Various defines and bits for handling PRI- and SS7-type restriction */
-
--#define AST_PRES_NUMBER_TYPE 0x03
-+#define AST_PRES_NUMBER_TYPE 0x03
- #define AST_PRES_USER_NUMBER_UNSCREENED 0x00
- #define AST_PRES_USER_NUMBER_PASSED_SCREEN 0x01
- #define AST_PRES_USER_NUMBER_FAILED_SCREEN 0x02
--#define AST_PRES_NETWORK_NUMBER 0x03
-+#define AST_PRES_NETWORK_NUMBER 0x03
-
--#define AST_PRES_RESTRICTION 0x60
--#define AST_PRES_ALLOWED 0x00
--#define AST_PRES_RESTRICTED 0x20
--#define AST_PRES_UNAVAILABLE 0x40
--#define AST_PRES_RESERVED 0x60
-+#define AST_PRES_RESTRICTION 0x60
-+#define AST_PRES_ALLOWED 0x00
-+#define AST_PRES_RESTRICTED 0x20
-+#define AST_PRES_UNAVAILABLE 0x40
-+#define AST_PRES_RESERVED 0x60
-
- #define AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \
-- AST_PRES_USER_NUMBER_UNSCREENED + AST_PRES_ALLOWED
-+ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED)
-
- #define AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \
-- AST_PRES_USER_NUMBER_PASSED_SCREEN + AST_PRES_ALLOWED
-+ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN)
-
- #define AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \
-- AST_PRES_USER_NUMBER_FAILED_SCREEN + AST_PRES_ALLOWED
-+ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN)
-
- #define AST_PRES_ALLOWED_NETWORK_NUMBER \
-- AST_PRES_NETWORK_NUMBER + AST_PRES_ALLOWED
-+ (AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER)
-
- #define AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED \
-- AST_PRES_USER_NUMBER_UNSCREENED + AST_PRES_RESTRICTED
-+ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED)
-
- #define AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \
-- AST_PRES_USER_NUMBER_PASSED_SCREEN + AST_PRES_RESTRICTED
-+ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN)
-
- #define AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \
-- AST_PRES_USER_NUMBER_FAILED_SCREEN + AST_PRES_RESTRICTED
-+ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN)
-
- #define AST_PRES_PROHIB_NETWORK_NUMBER \
-- AST_PRES_NETWORK_NUMBER + AST_PRES_RESTRICTED
-+ (AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER)
-
- #define AST_PRES_NUMBER_NOT_AVAILABLE \
-- AST_PRES_NETWORK_NUMBER + AST_PRES_UNAVAILABLE
-+ (AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER)
-
- int ast_parse_caller_presentation(const char *data);
- const char *ast_describe_caller_presentation(int data);
- const char *ast_named_caller_presentation(int data);
-
--/*! \page Def_CallerPres Caller ID Presentation
-+/*!
-+ * \page Def_CallerPres Caller ID Presentation
-+ *
-+ * Caller ID presentation values are used to set properties to a
-+ * caller ID in PSTN networks, and as RPID value in SIP transactions.
-+ *
-+ * The following values are available to use:
-+ * \arg \b Defined value, text string in config file, explanation
-+ *
-+ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", Presentation Allowed, Not Screened,
-+ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", Presentation Allowed, Passed Screen,
-+ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", Presentation Allowed, Failed Screen,
-+ * \arg \b AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", Presentation Allowed, Network Number,
-+ * \arg \b AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", Presentation Prohibited, Not Screened,
-+ * \arg \b AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", Presentation Prohibited, Passed Screen,
-+ * \arg \b AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", Presentation Prohibited, Failed Screen,
-+ * \arg \b AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", Presentation Prohibited, Network Number,
-+ *
-+ * \par References
-+ * \arg \ref callerid.h Definitions
-+ * \arg \ref callerid.c Functions
-+ * \arg \ref CID Caller ID names and numbers
-+ */
-
-- Caller ID presentation values are used to set properties to a
-- caller ID in PSTN networks, and as RPID value in SIP transactions.
-+/*! \brief redirecting reason codes.
-+ *
-+ * This list attempts to encompass redirecting reasons
-+ * as defined by several channel technologies.
-+ */
-+enum AST_REDIRECTING_REASON {
-+ AST_REDIRECTING_REASON_UNKNOWN,
-+ AST_REDIRECTING_REASON_USER_BUSY,
-+ AST_REDIRECTING_REASON_NO_ANSWER,
-+ AST_REDIRECTING_REASON_UNAVAILABLE,
-+ AST_REDIRECTING_REASON_UNCONDITIONAL,
-+ AST_REDIRECTING_REASON_TIME_OF_DAY,
-+ AST_REDIRECTING_REASON_DO_NOT_DISTURB,
-+ AST_REDIRECTING_REASON_DEFLECTION,
-+ AST_REDIRECTING_REASON_FOLLOW_ME,
-+ AST_REDIRECTING_REASON_OUT_OF_ORDER,
-+ AST_REDIRECTING_REASON_AWAY,
-+ AST_REDIRECTING_REASON_CALL_FWD_DTE, /* This is something defined in Q.931, and no I don't know what it means */
-+};
-
-- The following values are available to use:
-- \arg \b Defined value, text string in config file, explanation
-+int ast_redirecting_reason_parse(const char *data);
-+const char *ast_redirecting_reason_describe(int data);
-+const char *ast_redirecting_reason_name(int data);
-
-- \arg \b AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", Presentation Allowed, Not Screened,
-- \arg \b AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", Presentation Allowed, Passed Screen,
-- \arg \b AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", Presentation Allowed, Failed Screen,
-- \arg \b AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", Presentation Allowed, Network Number,
-- \arg \b AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", Presentation Prohibited, Not Screened,
-- \arg \b AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", Presentation Prohibited, Passed Screen,
-- \arg \b AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", Presentation Prohibited, Failed Screen,
-- \arg \b AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", Presentation Prohibited, Network Number,
-+/*!
-+ * \brief Connected line update source code
-+ */
-+enum AST_CONNECTED_LINE_UPDATE_SOURCE {
-+ AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, /* Update for unknown reason (May be interpreted to mean from answer) */
-+ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, /* Update from normal call answering */
-+ AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION, /* Update from call diversion (Deprecated, use REDIRECTING updates instead.) */
-+ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, /* Update from call transfer(active) (Party has already answered) */
-+ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING /* Update from call transfer(alerting) (Party has not answered yet) */
-+};
-
-- \par References
-- \arg \ref callerid.h Definitions
-- \arg \ref callerid.c Functions
-- \arg \ref CID Caller ID names and numbers
--*/
-+int ast_connected_line_source_parse(const char *data);
-+const char *ast_connected_line_source_describe(int data);
-+const char *ast_connected_line_source_name(int data);
-
-
- #endif /* _ASTERISK_CALLERID_H */
-Index: include/asterisk/doxyref.h
-===================================================================
---- a/include/asterisk/doxyref.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/doxyref.h (.../team/group/issue14292) (revision 178988)
-@@ -1,10 +1,8 @@
- /*
- * Asterisk -- An open source telephony toolkit.
- *
-- * Copyright (C) 1999 - 2005, Digium, Inc.
-+ * Copyright (C) 1999 - 2008, Digium, Inc.
- *
-- * Mark Spencer <markster@digium.com>
-- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
-@@ -16,110 +14,491 @@
- * at the top of the source tree.
- */
-
--/*! \file
-+/*!
-+ * \file
- * \brief This file generates Doxygen pages from files in the /doc
-- directory of the Asterisk source code tree
-+ * directory of the Asterisk source code tree
- */
-
--/* The following is for Doxygen Developer's documentation generated
-+/*
-+ * The following is for Doxygen Developer's documentation generated
- * by running "make progdocs" with doxygen installed on your
- * system.
- */
--/*! \page DevDoc Asterisk Developer's Documentation - appendices
-- * \arg \ref CodeGuide : The must-read document for all developer's
-- * \arg \ref AstAPI
-- * \arg \ref Def_Channel : What's a channel, anyway?
-- * \arg \ref channel_drivers : Existing channel drivers
-- * \arg \ref AstDebug : Hints on debugging
-- * \arg \ref AstAMI : The Call management socket API
-- * \arg \ref AstARA : A generic data storage and retrieval API for Asterisk
-- * \arg \ref AstDUNDi : A way to find phone services dynamically by using the DUNDi protocol
-- * \arg \ref AJI_intro : The Asterisk Jabber Interface
-- * \arg \ref AstCDR
-- * \arg \ref AstREADME
-- * \arg \ref AstVar
-- * \arg \ref AstVideo
-- * \arg \ref AstENUM : The IETF way to redirect from phone numbers to VoIP calls
-- * \arg \ref AstHTTP
-- * \arg \ref AstSpeech
-- * \arg \ref ConfigFiles
-- * \arg \ref SoundFiles included in the Asterisk distribution
-- * \arg \ref AstCREDITS : A Thank You to contributors
-- * \arg \ref extref
-- \n\n
-+
-+/*!
-+ * \page DevDoc Asterisk Developer's Documentation - Appendices
-+ *
-+ * \section devpolicy Development and Release Policies
-+ * \arg \ref CodeGuide : The must-read document for all developers
-+ * \arg \ref CommitMessages : Information on formatting and special tags for commit messages
-+ * \arg \ref ReleaseStatus : The current support level for various Asterisk releases
-+ * \arg \ref ReleasePolicies : Asterisk Release and Commit Policies
-+ * \arg \ref AstCREDITS : A Thank You to contributors (unfortunately out of date)
-+ *
-+ * \section apisandinterfaces Asterisk APIs and Interfaces
-+ * \arg \ref AstAPI
-+ * \arg \ref Def_Channel : What's a channel, anyway?
-+ * \arg \ref channel_drivers : Existing channel drivers
-+ * \arg \ref AstAMI : The Call management socket API
-+ * \arg \ref AstARA : A generic data storage and retrieval API for Asterisk
-+ * \arg \ref AstDUNDi : A way to find phone services dynamically by using the DUNDi protocol
-+ * \arg \ref AJI_intro : The Asterisk Jabber Interface
-+ * \arg \ref AstCDR
-+ * \arg \ref AstVar
-+ * \arg \ref AstVideo
-+ * \arg \ref AstENUM : The IETF way to redirect from phone numbers to VoIP calls
-+ * \arg \ref AstHTTP
-+ * \arg \ref AstSpeech
-+ *
-+ * \section debugconfig Debugging and Configuration References
-+ * \arg \ref AstREADME : General Administrator README file
-+ * \arg \ref AstDebug : Hints on debugging
-+ * \arg \ref extref
-+ * \arg \ref ConfigFiles
-+ * \arg \ref SoundFiles included in the Asterisk distribution
-+ *
- * \section weblinks Web sites
- * \arg \b Main: Asterisk Developer's website http://www.asterisk.org/developers/
-- * \arg \b Bugs: The Issue tracker http://bugs.digium.com
-- * \arg \b Lists: List server http://lists.digium.com
-+ * \arg \b Bugs: The Issue Tracker http://bugs.digium.com
-+ * \arg \b Lists: List Server http://lists.digium.com
- * \arg \b Wiki: The Asterisk Wiki http://www.voip-info.org
- * \arg \b Docs: The Asterisk Documentation Project http://www.asteriskdocs.org
-- * \arg \b Digium: The Asterisk company http://www.digium.com
-- *
-+ * \arg \b Digium: The Asterisk Company http://www.digium.com
- */
-
--/*! \page CodeGuide Coding Guidelines
-- * \section Coding Guidelines
-- * This file is in the /doc directory in your Asterisk source tree.
-- * Make sure to stay up to date with the latest guidelines.
-- * \verbinclude CODING-GUIDELINES
-+/*!
-+ * \page ReleaseStatus Asterisk Release Status
-+ *
-+ * @AsteriskTrunkWarning
-+ *
-+ * \section warranty Warranty
-+ * The following warranty applies to all open source releases of Asterisk:
-+ *
-+ * NO WARRANTY
-+ *
-+ * BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-+ * FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-+ * OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-+ * PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-+ * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-+ * TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-+ * PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-+ * REPAIR OR CORRECTION.
-+
-+ * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-+ * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-+ * REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-+ * INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-+ * OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-+ * TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-+ * YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-+ * PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-+ * POSSIBILITY OF SUCH DAMAGES.
-+ *
-+ * \section releasestatustypes Release Status Types
-+ *
-+ * Release management is a essentially an agreement between the development
-+ * community and the %user community on what kind of updates can be expected
-+ * for Asterisk releases, and what types of changes these updates will contain.
-+ * Once these policies are established, the development community works very
-+ * hard to adhere to them. However, the development community does reserve
-+ * the right to make exceptions to these rules for special cases as the need
-+ * arises.
-+ *
-+ * Asterisk releases are in various states of maintenance. The states are
-+ * defined here:
-+ *
-+ * \arg <b>None</b> - This release series is receiving no updates whatsoever.
-+ * \arg <b>Security-Only</b> - This release series is receiving updates, but
-+ * only to address security issues. Security issues found and fixed in
-+ * this release series will be accompanied by a published security advisory
-+ * from the Asterisk project.
-+ * \arg <b>Full-Support</b> - This release series is receiving updates for all
-+ * types of bugs.
-+ * \arg <b>Full-Development</b> - Changes in this part of Asterisk include bug
-+ * fixes, as well as new %features and architectural improvements.
-+ *
-+ * \section AsteriskReleases Asterisk Maintenance Levels
-+ *
-+ * \htmlonly
-+ * <table border="1">
-+ * <tr>
-+ * <td><b>Name</b></td>
-+ * <td><b>SVN Branch</b></td>
-+ * <td><b>Status</b></td>
-+ * <td><b>Notes</b></td>
-+ * </tr>
-+ * <tr>
-+ * <td>Asterisk 1.0</td>
-+ * <td>/branches/1.0</td>
-+ * <td>None</td>
-+ * </tr>
-+ * <tr>
-+ * <td>Asterisk 1.2</td>
-+ * <td>/branches/1.2</td>
-+ * <td>Security-Only</td>
-+ * </tr>
-+ * <tr>
-+ * <td>Asterisk 1.4</td>
-+ * <td>/branches/1.4</td>
-+ * <td>Full-Support</td>
-+ * </tr>
-+ * <tr>
-+ * <td>Asterisk 1.6.0</td>
-+ * <td>/branches/1.6.0</td>
-+ * <td>Full-Support</td>
-+ * </tr>
-+ * <tr>
-+ * <td>Asterisk 1.6.1</td>
-+ * <td>/branches/1.6.1</td>
-+ * <td>Full-Support</td>
-+ * <td>Still in beta</td>
-+ * </tr>
-+ * <tr>
-+ * <td>Asterisk trunk</td>
-+ * <td>/trunk</td>
-+ * <td>Full-Development</td>
-+ * <td>No releases are made directly from trunk.</td>
-+ * </tr>
-+ * </table>
-+ * \endhtmlonly
-+ *
-+ * For more information on how and when Asterisk releases are made, see the
-+ * release policies page:
-+ * \arg \ref ReleasePolicies
- */
-
--/*! \page AstAPI Asterisk API
-- * \section Asteriskapi Asterisk API
-- * Some generic documents on the Asterisk architecture
-+/*!
-+ * \page ReleasePolicies Asterisk Release and Commit Policies
- *
-- * \arg \ref AstThreadStorage
-- * \arg \ref DataStores
-- * \arg \ref AstExtState
-+ * \AsteriskTrunkWarning
- *
-- * \subsection model_txt Generic Model
-- * \verbinclude model.txt
-- * \subsection channel_txt Channels
-- * \arg See \ref Def_Channel
-+ * \section releasestatus Asterisk Release Status
-+ *
-+ * For more information on the current status of each Asterisk release series,
-+ * please see the Asterisk Release Status page:
-+ *
-+ * \arg \ref ReleaseStatus
-+ *
-+ * <hr/>
-+ *
-+ * \section commitmonitoring Commit Monitoring
-+ *
-+ * To monitor commits to Asterisk and related projects, visit
-+ * <a href="http://lists.digium.com/">http://lists.digium.com</a>. The Digium
-+ * mailing list server hosts a %number of mailing lists for commits.
-+ *
-+ * <hr/>
-+ *
-+ * \section ast10policy Asterisk 1.0
-+ *
-+ * \subsection svnbranch SVN Branch
-+ *
-+ * \arg /branches/1.0
-+ *
-+ * \subsection ast10releases Release and Commit Policy
-+ * No more releases of Asterisk 1.0 will be made for any reason.
-+ *
-+ * No commits should be made to the Asterisk 1.0 branch.
-+ *
-+ * <hr/>
-+ *
-+ * \section ast12policy Asterisk 1.2
-+ *
-+ * \subsection svnbranch SVN Branch
-+ *
-+ * \arg /branches/1.2
-+ *
-+ * \subsection ast12releases Release and Commit Policy
-+ *
-+ * There will be no more scheduled releases of Asterisk 1.2.
-+ *
-+ * Commits to the Asterisk 1.2 branch should only address security issues or
-+ * regressions introduced by previous security fixes. For a security issue, the
-+ * commit should be accompanied by an
-+ * <a href="http://downloads.digium.com/pub/security/">Asterisk Security Advisory</a>
-+ * and an immediate release. When a commit goes in to fix a regression, the previous
-+ * security advisory that is related to the change that introduced the bug should get
-+ * updated to indicate that there is an updated version of the fix. A release should
-+ * be made immediately for these regression fixes, as well.
-+ *
-+ * <hr/>
-+ *
-+ * \section ast14policy Asterisk 1.4
-+ *
-+ * \subsection svnbranch SVN Branch
-+ *
-+ * \arg /branches/1.4
-+ *
-+ * \subsection ast14releases Release and Commit Policy
-+ *
-+ * Asterisk 1.4 is receiving regular bug fix release updates. An attempt is made to
-+ * make releases of every four to six weeks. Since this release series is receiving
-+ * changes for all types of bugs, the number of changes in a single release can be
-+ * significant. 1.4.X releases go through a release candidate testing cycle to help
-+ * catch any regressions that may have been introduced.
-+ *
-+ * Commits to Asterisk 1.4 must be to address bugs only. No new %features should be
-+ * introduced into Asterisk 1.4 to reduce the %number of changes to this established
-+ * release series. The only exceptions to this %rule are for cases where something
-+ * that may be considered a feature is needed to address a bug or security issue.
-+ *
-+ * <hr/>
-+ *
-+ * \section ast16policy Asterisk 1.6
-+ *
-+ * \subsection svnbranch SVN Branch
-+ *
-+ * \arg /branches/1.6.*
-+ *
-+ * \subsection ast16releases Release and Commit Policy
-+ *
-+ * Asterisk 1.6 is managed in a different way than previous Asterisk release series.
-+ * From a high level, it was inspired by the release model used for Linux 2.6.
-+ * The intended time frame for 1.6.X releases is every 2 or 3 months. Each 1.6.X
-+ * release gets its own branch. The 1.6.X branches are branches off of trunk.
-+ * Once the branch is created, it only receives bug fixes. Each 1.6.X release goes
-+ * through a beta and release candidate testing cycle.
-+ *
-+ * After a 1.6.X release is published, it will be maintained until 1.6.[X + 3] is
-+ * released. While a 1.6.X release branch is still maintained, it will receive only
-+ * bug fixes. Periodic maintenance releases will be made and labeled as 1.6.X.Y.
-+ * 1.6.X.Y releases should go through a release candidate test cycle before being
-+ * published.
-+ *
-+ * For now, all previous 1.6 release will be maintained for security issues. Once
-+ * we have more 1.6 releases to deal with, this part of the policy will likely change.
-+ *
-+ * For some history on the motivations for Asterisk 1.6 release management, see the
-+ * first two sections of this
-+ * <a href="http://lists.digium.com/pipermail/asterisk-dev/2007-October/030083.html">mailing list post</a>.
-+ *
-+ * <hr/>
-+ *
-+ * \section asttrunk Asterisk Trunk
-+ *
-+ * \subsection svnbranch SVN Branch
-+ *
-+ * \arg /trunk
-+ *
-+ * \subsection asttrunkpolicy Release and Commit Policy
-+ *
-+ * No releases are ever made directly from Asterisk trunk.
-+ *
-+ * Asterisk trunk is used as the main development area for upcoming Asterisk 1.6
-+ * releases. Commits to Asterisk trunk are not limited. They can be bug fixes,
-+ * new %features, and architectural improvements. However, for larger sets
-+ * of changes, developers should work with the Asterisk project leaders to
-+ * schedule them for inclusion. Care is taken not to include too many invasive
-+ * sets of changes for each new Asterisk 1.6 release.
-+ *
-+ * No changes should go into Asterisk trunk that are not ready to go into a
-+ * release. While the upcoming release will go through a beta and release
-+ * candidate test cycle, code should not be in trunk until the code has been
-+ * tested and reviewed such that there is reasonable belief that the code
-+ * is ready to go.
-+ *
-+ * <hr/>
-+ *
-+ * \section astteam Asterisk Team Branches
-+ *
-+ * \subsection svnbranch SVN Branch
-+ *
-+ * \arg /team/&lt;developername&gt;
-+ *
-+ * \subsection astteampolicy Release and Commit Policy
-+ *
-+ * The Asterisk subversion repository has a special directory called "team"
-+ * where developers can make their own personal development branches. This is
-+ * where new %features, bug fixes, and architectural improvements are developed
-+ * while they are in %progress.
-+ *
-+ * Just about anything goes as far as commits to this area goes. However,
-+ * developers should keep in mind that anything committed here, as well as
-+ * anywhere else on Digium's SVN server, falls under the contributor license
-+ * agreement.
-+ *
-+ * In addition to each developer having their own space for working on projects,
-+ * there is also a team/group folder where %group development efforts take place.
-+ *
-+ * Finally, in each developer folder, there is a folder called "private". This
-+ * is where developers can create branches for working on things that they are
-+ * not ready for the whole world to see.
- */
-
--/*! \page AstDebug Debugging
-- * \section debug Debugging
-- * \verbinclude backtrace.txt
-+/*!
-+ * \page CodeGuide Coding Guidelines
-+ * \AsteriskTrunkWarning
-+ * \section Coding Guidelines
-+ * This file is in the /doc directory in your Asterisk source tree.
-+ * Make sure to stay up to date with the latest guidelines.
-+ * \verbinclude CODING-GUIDELINES
- */
-
--/*! \page AstSpeech The Generic Speech Recognition API
-- * \section debug The Generic Speech Recognition API
-- * \verbinclude speechrec.txt
-+/*!
-+ * \page CommitMessages Guidelines for Commit Messages
-+ *
-+ * \AsteriskTrunkWarning
-+ *
-+ * <hr/>
-+ *
-+ * \section CommitMsgFormatting Commit Message Formatting
-+ *
-+ * The following illustrates the basic outline for commit messages:
-+ *
-+ \verbatim
-+ <One-liner summary of changes>
-+
-+ <Verbose description of the changes>
-+
-+ <Special Tags>
-+ \endverbatim
-+ *
-+ * Some commit history viewers treat the first line of commit messages as the
-+ * summary for the commit. So, an effort should be made to format our commit
-+ * messages in that fashion. The verbose description may contain multiple
-+ * paragraphs, itemized lists, etc.
-+ *
-+ * Commit messages should be wrapped at 80 %columns.
-+ *
-+ * \note For trivial commits, such as "fix the build", or "fix spelling mistake",
-+ * the verbose description may not be necessary.
-+ *
-+ * <hr/>
-+ *
-+ * \section CommitMsgTags Special Tags for Commit Messages
-+ *
-+ * \subsection MantisTags Mantis (http://bugs.digium.com/)
-+ *
-+ * To have a commit noted in an issue, use a tag of the form:
-+ * \arg (issue #1234)
-+ *
-+ * To have a commit automatically close an issue, use a tag of the form:
-+ * \arg (closes issue #1234)
-+ *
-+ * When making a commit for a mantis issue, it is easiest to use the
-+ * provided commit %message template functionality. It will format the
-+ * special tags appropriately, and will also include information about who
-+ * reported the issue, which patches are being applied, and who did testing.
-+ *
-+ * Assuming that you have bug marshal access (and if you have commit access,
-+ * it is pretty safe to assume that you do), you will find the commit %message
-+ * template section directly below the issue details section and above the
-+ * issue relationships section. You will have to click the '+' next to
-+ * "Commit message template" to make the contents of the section visible.
-+ *
-+ * Here is an example of what the template will generate for you:
-+ *
-+ \verbatim
-+ (closes issue #1234)
-+ Reported by: SomeGuy
-+ Patches:
-+ fix_bug_1234.diff uploaded by SomeDeveloper (license 5678)
-+ \endverbatim
-+ *
-+ * If the patch being committed was written by the person doing the commit,
-+ * and is not available to reference as an upload to the issue, there is no
-+ * need to include something like "fixed by me", as that will be the default
-+ * assumption when a specific patch is not referenced.
-+ *
-+ * \subsection ReviewBoardTags Review Board (http://reviewboard.digium.com/)
-+ *
-+ * To have a commit set a review request as submitted, include the full URL
-+ * to the review request. For example:
-+ * \arg Review: %http://reviewboard.digium.com/r/95/
-+ *
-+ * \note The trailing slash in the review URL is required.
-+ *
-+ * <hr/>
-+ *
-+ * \section CommitMsgSvnmerge Commit Messages with svnmerge
-+ *
-+ * When using the svnmerge tool for merging changes between branches, use the
-+ * commit %message generated by svnmerge. The '-f' option to svnmerge allows
-+ * you to specify a file for svnmerge to write out a commit %message to. The
-+ * '-F' option to svn commit allows you to specify a file that contains the
-+ * commit %message.
-+ *
-+ * If you are using the expect script wrappers for svnmerge from repotools,
-+ * a commit %message is automatically placed in the file '../merge.msg'.
-+ *
-+ * For more detailed information about working with branches and merging,
-+ * see the following page on %asterisk.org:
-+ * \arg http://www.asterisk.org/developers/svn-branching-merging
- */
-
--/*! \page DataStores Channel Data Stores
-- * \section debug Channel Data Stores
-- * \verbinclude datastores.txt
-+/*!
-+ * \page AstAPI Asterisk API
-+ * \section Asteriskapi Asterisk API
-+ * Some generic documents on the Asterisk architecture
-+ *
-+ * \arg \ref AstThreadStorage
-+ * \arg \ref DataStores
-+ * \arg \ref AstExtState
-+ *
-+ * \subsection model_txt Generic Model
-+ * \verbinclude model.txt
-+ * \subsection channel_txt Channels
-+ * \arg See \ref Def_Channel
- */
-
--/*! \page AstAMI AMI - The Manager Interface
-- * \section ami AMI - The manager Interface
-- * \arg \link Config_ami Configuration file \endlink
-- * \arg \ref manager.c
-- * \verbinclude manager.txt
-+/*!
-+ * \page AstDebug Debugging
-+ * \section debug Debugging
-+ * \verbinclude backtrace.txt
- */
-
--/*! \page AstARA ARA - The Asterisk Realtime Interface
-- * \section realtime ARA - a generic API to storage and retrieval
-- * Implemented in \ref config.c
-- * Implemented in \ref pbx_realtime.c
-- * \verbinclude realtime.txt
-- * \verbinclude extconfig.txt
-+/*!
-+ * \page AstSpeech The Generic Speech Recognition API
-+ * \section debug The Generic Speech Recognition API
-+ * \verbinclude speechrec.txt
- */
-
--/*! \page AstDUNDi DUNDi
--DUNDi is a peer-to-peer system for locating Internet gateways to telephony services. Unlike traditional centralized services (such as the remarkably simple and concise ENUM standard), DUNDi is fully-distributed with no centralized authority whatsoever.
-+/*!
-+ * \page DataStores Channel Data Stores
-+ * \section debug Channel Data Stores
-+ * \verbinclude datastores.txt
-+ */
-
--DUNDi is not itself a Voice-over IP signaling or media protocol. Instead, it publishes routes which are in turn accessed via industry standard protocols such as IAX, SIP and H.323.
-+/*!
-+ * \page AstAMI AMI - The Manager Interface
-+ * \section ami AMI - The manager Interface
-+ * \arg \link Config_ami Configuration file \endlink
-+ * \arg \ref manager.c
-+ * \verbinclude manager.txt
-+ */
-
-- \par References
-- \arg DUNDi is documented at http://www.dundi.com
-- \arg Implemented in \ref pbx_dundi.c and \ref dundi-parser.c
-- \arg Configuration in \link Config_dun dundi.conf \endlink
-+/*!
-+ * \page AstARA ARA - The Asterisk Realtime Interface
-+ * \section realtime ARA - a generic API to storage and retrieval
-+ * Implemented in \ref config.c
-+ * Implemented in \ref pbx_realtime.c
-+ * \verbinclude realtime.txt
-+ * \verbinclude extconfig.txt
- */
-
--/*! \page AstCDR CDR - Call Data Records and billing
-+/*!
-+ * \page AstDUNDi DUNDi
-+ *
-+ * DUNDi is a peer-to-peer system for locating Internet gateways to telephony
-+ * services. Unlike traditional centralized services (such as the remarkably
-+ * simple and concise ENUM standard), DUNDi is fully-distributed with no
-+ * centralized authority whatsoever.
-+ *
-+ * DUNDi is not itself a Voice-over IP signaling or media protocol. Instead,
-+ * it publishes routes which are in turn accessed via industry standard
-+ * protocols such as IAX, SIP and H.323.
-+ *
-+ * \par References
-+ * \arg DUNDi is documented at http://www.dundi.com
-+ * \arg Implemented in \ref pbx_dundi.c and \ref dundi-parser.c
-+ * \arg Configuration in \link Config_dun dundi.conf \endlink
-+ */
-+
-+/*!
-+ * \page AstCDR CDR - Call Data Records and billing
- * \section cdr Call Data Records
- * \par See also
- * \arg \ref cdr.c
-@@ -129,20 +508,24 @@
- * \verbinclude cdrdriver.txt
- */
-
--/*! \page AstREADME README - the general administrator introduction
-- * \verbinclude README
-+/*!
-+ * \page AstREADME README
-+ * \verbinclude README
- */
-
--/*! \page AstCREDITS CREDITS
-- * \verbinclude CREDITS
-+/*!
-+ * \page AstCREDITS CREDITS
-+ * \verbinclude CREDITS
- */
-
--/*! \page AstVideo Video support in Asterisk
-+/*!
-+ * \page AstVideo Video support in Asterisk
- * \section sectAstVideo Video support in Asterisk
-- * \verbinclude video.txt
-+ * \verbinclude video.txt
- */
-
--/*! \page AstVar Globally predefined channel variables
-+/*!
-+ * \page AstVar Globally predefined channel variables
- * \section globchan Globally predefined channel variables
- *
- * More and more of these variables are being replaced by dialplan functions.
-@@ -154,10 +537,10 @@
- * - \ref AstChanVar
- *
- * \verbinclude channelvariables.tex
--
- */
-
--/*! \page AstChanVar Asterisk Dialplan Variables
-+/*!
-+ * \page AstChanVar Asterisk Dialplan Variables
- * Asterisk Dialplan variables are divided into three groups:
- * - Predefined global variables, handled by the PBX core
- * - Global variables, that exist for the duration of the pbx execution
-@@ -201,11 +584,10 @@
- *
- * The variables is a linked list stored in the channel data structure
- * with the list starting at varshead in struct ast_channel
-- *
-- *
- */
-
--/*! \page AstENUM ENUM
-+/*!
-+ * \page AstENUM ENUM
- * \section enumreadme ENUM
- * \arg Configuration: \ref Config_enum
- * \arg \ref enum.c
-@@ -214,7 +596,8 @@
- * \verbinclude enum.txt
- */
-
--/*! \page ConfigFiles Configuration files
-+/*!
-+ * \page ConfigFiles Configuration files
- * \section config Main configuration files
- * \arg \link Config_ast asterisk.conf - the main configuration file \endlink
- * \arg \link Config_ext extensions.conf - The Dial Plan \endlink
-@@ -256,10 +639,13 @@
- * \arg \link res_config_sqlite SQLite Resource driver configuration \endlink
- */
-
--/*! \page Config_ast Asterisk.conf
-+/*!
-+ * \page Config_ast Asterisk.conf
- * \verbinclude asterisk-conf.txt
- */
--/*! \page Config_mod Modules configuration
-+
-+/*!
-+ * \page Config_mod Modules configuration
- * All res_ resource modules are loaded with globals on, which means
- * that non-static functions are callable from other modules.
- *
-@@ -268,25 +654,29 @@
- * \verbinclude modules.conf.sample
- */
-
--/*! \page Config_fea Call features configuration
-+/*!
-+ * \page Config_fea Call features configuration
- * \par See also
- * \arg \ref res_features.c : Call feature implementation
- * \section featconf features.conf
- * \verbinclude features.conf.sample
- */
-
--/*! \page Config_followme Followme: An application for simple follow-me calls
-+/*!
-+ * \page Config_followme Followme: An application for simple follow-me calls
- * \section followmeconf Followme.conf
- * - See app_followme.c
- * \verbinclude followme.conf.sample
- */
-
--/*! \page Config_ext Extensions.conf - the Dial Plan
-+/*!
-+ * \page Config_ext Extensions.conf - the Dial Plan
- * \section dialplan Extensions.conf
- * \verbinclude extensions.conf.sample
- */
-
--/*! \page Config_iax IAX2 configuration
-+/*!
-+ * \page Config_iax IAX2 configuration
- * IAX2 is implemented in \ref chan_iax2.c
- * \arg \link Config_iax iax.conf Configuration file example \endlink
- * \section iaxreadme IAX readme file
-@@ -297,13 +687,15 @@
- * \verbinclude jitterbuffer.txt
- */
-
--/*! \page Config_iax IAX configuration
-+/*!
-+ * \page Config_iax IAX configuration
- * \arg Implemented in \ref chan_iax2.c
- * \section iaxconf iax.conf
- * \verbinclude iax.conf.sample
- */
-
--/*! \page Config_sip SIP configuration
-+/*!
-+ * \page Config_sip SIP configuration
- * Also see \ref Config_rtp RTP configuration
- * \arg Implemented in \ref chan_sip.c
- * \section sipconf sip.conf
-@@ -312,20 +704,23 @@
- * \arg \b Back \ref chanconf
- */
-
--/*! \page Config_mgcp MGCP configuration
-+/*!
-+ * \page Config_mgcp MGCP configuration
- * Also see \ref Config_rtp RTP configuration
- * \arg Implemented in \ref chan_mgcp.c
- * \section mgcpconf mgcp.conf
- * \verbinclude mgcp.conf.sample
- */
-
--/*! \page README_misdn MISDN documentation
-+/*!
-+ * \page README_misdn MISDN documentation
- * \arg See \ref Config_misdn
- * \section mISDN configuration
- * \verbinclude misdn.txt
- */
-
--/*! \page Config_misdn MISDN configuration
-+/*!
-+ * \page Config_misdn MISDN configuration
- * \arg Implemented in \ref chan_misdn.c
- * \arg \ref README_misdn
- * \arg See the mISDN home page: http://www.isdn4linux.de/mISDN/
-@@ -333,19 +728,22 @@
- * \verbinclude misdn.conf.sample
- */
-
--/*! \page Config_vm VoiceMail configuration
-+/*!
-+ * \page Config_vm VoiceMail configuration
- * \section vmconf voicemail.conf
- * \arg Implemented in \ref app_voicemail.c
- * \verbinclude voicemail.conf.sample
- */
-
--/*! \page Config_dahdi DAHDI configuration
-+/*!
-+ * \page Config_dahdi DAHDI configuration
- * \section dahdiconf dahdi.conf
- * \arg Implemented in \ref chan_dahdi.c
- * \verbinclude dahdi.conf.sample
- */
-
--/*! \page Config_h323 H.323 channel driver information
-+/*!
-+ * \page Config_h323 H.323 channel driver information
- * This is the configuration of the H.323 channel driver within the Asterisk
- * distribution. There's another one, called OH323, in asterisk-addons
- * \arg Implemented in \ref chan_h323.c
-@@ -353,53 +751,61 @@
- * \ref chan_h323.c
- */
-
--/*! \page Config_oss OSS configuration
-+/*!
-+ * \page Config_oss OSS configuration
- * \section ossconf oss.conf
- * \arg Implemented in \ref chan_oss.c
- * \verbinclude oss.conf.sample
- */
-
--/*! \page Config_alsa ALSA configuration
-+/*!
-+ * \page Config_alsa ALSA configuration
- * \section alsaconf alsa.conf
- * \arg Implemented in \ref chan_alsa.c
- * \verbinclude alsa.conf.sample
- */
-
--/*! \page Config_agent Agent configuration
-+/*!
-+ * \page Config_agent Agent configuration
- * \section agentconf agents.conf
- * The agent channel is a proxy channel for queues
- * \arg Implemented in \ref chan_agent.c
- * \verbinclude agents.conf.sample
- */
-
--/*! \page Config_rtp RTP configuration
-+/*!
-+ * \page Config_rtp RTP configuration
- * \arg Implemented in \ref rtp.c
- * Used in \ref chan_sip.c and \ref chan_mgcp.c (and various H.323 channels)
- * \section rtpconf rtp.conf
- * \verbinclude rtp.conf.sample
- */
-
--/*! \page Config_dun DUNDi Configuration
-+/*!
-+ * \page Config_dun DUNDi Configuration
- * \arg See also \ref AstDUNDi
- * \section dundiconf dundi.conf
- * \verbinclude dundi.conf.sample
- */
-
--/*! \page Config_enum ENUM Configuration
-+/*!
-+ * \page Config_enum ENUM Configuration
- * \section enumconf enum.conf
- * \arg See also \ref enumreadme
- * \arg Implemented in \ref func_enum.c and \ref enum.c
- * \verbinclude enum.conf.sample
- */
-
--/*! \page cdr_custom Custom CDR Configuration
-+/*!
-+ * \page cdr_custom Custom CDR Configuration
- * \par See also
- * \arg \ref cdrconf
- * \arg \ref cdr_custom.c
- * \verbinclude cdr_custom.conf.sample
- */
-
--/*! \page cdr_ami Manager CDR driver configuration
-+/*!
-+ * \page cdr_ami Manager CDR driver configuration
- * \par See also
- * \arg \ref cdrconf
- * \arg \ref AstAMI
-@@ -407,7 +813,8 @@
- * \verbinclude cdr_manager.conf.sample
- */
-
--/*! \page cdr_odbc ODBC CDR driver configuration
-+/*!
-+ * \page cdr_odbc ODBC CDR driver configuration
- * \arg See also \ref cdrconf
- * \arg \ref cdr_odbc.c
- * \verbinclude cdr_odbc.conf.sample
-@@ -415,7 +822,8 @@
- * \arg http://www.unixodbc.org
- */
-
--/*! \page cdr_pgsql PostgreSQL CDR driver configuration
-+/*!
-+ * \page cdr_pgsql PostgreSQL CDR driver configuration
- * \arg See also \ref cdrconf
- * \arg \ref cdr_pgsql.c
- * See also:
-@@ -423,21 +831,24 @@
- * \verbinclude cdr_pgsql.conf.sample
- */
-
--/*! \page cdr_sqlite SQLite CDR driver configuration
-+/*!
-+ * \page cdr_sqlite SQLite CDR driver configuration
- * \arg See also \ref cdrconf
- * \arg \ref cdr_sqlite.c
- * See also:
- * \arg http://www.sqlite.org
- */
-
--/*! \page cdr_tds FreeTDS CDR driver configuration
-+/*!
-+ * \page cdr_tds FreeTDS CDR driver configuration
- * \arg See also \ref cdrconf
- * See also:
- * \arg http://www.freetds.org
- * \verbinclude cdr_tds.conf.sample
- */
-
--/*! \page Config_cdr CDR configuration
-+/*!
-+ * \page Config_cdr CDR configuration
- * \par See also
- * \arg \ref cdr_drivers
- * \arg \link Config_cdr CDR configuration \endlink
-@@ -450,109 +861,126 @@
- * \verbinclude cdr.conf.sample
- */
-
--/*! \page Config_moh Music on Hold Configuration
-+/*!
-+ * \page Config_moh Music on Hold Configuration
- * \arg Implemented in \ref res_musiconhold.c
- * \section mohconf musiconhold.conf
- * \verbinclude musiconhold.conf.sample
- */
-
--/*! \page Config_adsi ADSI Configuration
-+/*!
-+ * \page Config_adsi ADSI Configuration
- * \section adsiconf adsi.conf
- * \verbinclude adsi.conf.sample
- */
-
--/*! \page Config_codec CODEC Configuration
-+/*!
-+ * \page Config_codec CODEC Configuration
- * \section codecsconf codecs.conf
- * \verbinclude codecs.conf.sample
- */
-
--/*! \page Config_ara REALTIME Configuration
-+/*!
-+ * \page Config_ara REALTIME Configuration
- * \arg See also: \arg \link AstARA \endlink
- * \section extconf extconfig.conf
- * \verbinclude extconfig.conf.sample
- */
-
--/*! \page Config_ami AMI configuration
-+/*!
-+ * \page Config_ami AMI configuration
- * \arg See also: \arg \link AstAMI \endlink
- * \section amiconf manager.conf
- * \verbinclude manager.conf.sample
- */
-
--/*! \page Config_qu ACD - Queue system configuration
-+/*!
-+ * \page Config_qu ACD - Queue system configuration
- * \arg Implemented in \ref app_queue.c
- * \section quconf queues.conf
- * \verbinclude queues.conf.sample
- */
-
--/*! \page Config_mm Meetme - The conference bridge configuration
-+/*!
-+ * \page Config_mm Meetme - The conference bridge configuration
- * \arg Implemented in \ref app_meetme.c
- * \section mmconf meetme.conf
- * \verbinclude meetme.conf.sample
- */
-
--/*! \page SoundFiles Sound files
-- * \section SecSound Asterisk Sound files
-- * Asterisk includes a large number of sound files. Many of these
-- * are used by applications and demo scripts within asterisk.
-+/*!
-+ * \page SoundFiles Sound files
-+ * \section SecSound Asterisk Sound files
-+ * Asterisk includes a large number of sound files. Many of these
-+ * are used by applications and demo scripts within asterisk.
- *
-- * Additional sound files are available in the asterisk-addons
-- * repository on svn.digium.com
-+ * Additional sound files are available in the asterisk-addons
-+ * repository on svn.digium.com
- */
-
--/*! \addtogroup cdr_drivers Module: CDR Drivers
-- * \section CDR_generic Asterisk CDR Drivers
-- * \brief CDR drivers are loaded dynamically, each loaded CDR driver produce a billing record for each call.
-- * \arg \ref Config_mod "Modules Configuration"
-- * \arg \ref Config_cdr "CDR Configuration"
-+/*!
-+ * \addtogroup cdr_drivers Module: CDR Drivers
-+ * \section CDR_generic Asterisk CDR Drivers
-+ * \brief CDR drivers are loaded dynamically, each loaded CDR driver produce
-+ * a billing record for each call.
-+ * \arg \ref Config_mod "Modules Configuration"
-+ * \arg \ref Config_cdr "CDR Configuration"
- */
-
-
--/*! \addtogroup channel_drivers Module: Asterisk Channel Drivers
-- * \section channel_generic Asterisk Channel Drivers
-- * \brief Channel drivers are loaded dynamically.
-- * \arg \ref Config_mod "Modules Configuration"
-+/*!
-+ * \addtogroup channel_drivers Module: Asterisk Channel Drivers
-+ * \section channel_generic Asterisk Channel Drivers
-+ * \brief Channel drivers are loaded dynamically.
-+ * \arg \ref Config_mod "Modules Configuration"
- */
-
--/*! \addtogroup applications Module: Dial plan applications
-- * \section app_generic Asterisk Dial Plan Applications
-- * \brief Applications support the dialplan. They register dynamically with \see ast_register_application() and unregister with \see ast_unregister_application()
-+/*!
-+ * \addtogroup applications Module: Dial plan applications
-+ * \section app_generic Asterisk Dial Plan Applications
-+ * \brief Applications support the dialplan. They register dynamically with
-+ * \see ast_register_application() and unregister with
-+ * \see ast_unregister_application()
- * \par See also
- * \arg \ref functions
-- *
- */
-
--/*! \addtogroup functions Module: Dial plan functions
-- * \section func_generic Asterisk Dial Plan Functions
-- * \brief Functions support the dialplan. They do not change any property of a channel
-- * or touch a channel in any way.
-+/*!
-+ * \addtogroup functions Module: Dial plan functions
-+ * \section func_generic Asterisk Dial Plan Functions
-+ * \brief Functions support the dialplan. They do not change any property of a channel
-+ * or touch a channel in any way.
- * \par See also
- * \arg \ref applications
- *
- */
-
--/*! \addtogroup codecs Module: Codecs
-- * \section codec_generic Asterisk Codec Modules
-- * Codecs are referenced in configuration files by name
-- * \par See also
-- * \arg \ref formats
-- *
-+/*!
-+ * \addtogroup codecs Module: Codecs
-+ * \section codec_generic Asterisk Codec Modules
-+ * Codecs are referenced in configuration files by name
-+ * \par See also
-+ * \arg \ref formats
- */
-
--/*! \addtogroup formats Module: Media File Formats
-- * \section codec_generic Asterisk Format drivers
-- * Formats are modules that read or write media files to disk.
-- * \par See also
-- * \arg \ref codecs
-+/*!
-+ * \addtogroup formats Module: Media File Formats
-+ * \section codec_generic Asterisk Format drivers
-+ * Formats are modules that read or write media files to disk.
-+ * \par See also
-+ * \arg \ref codecs
- */
-
--/*! \page AstHTTP AMI over HTTP support
-+/*!
-+ * \page AstHTTP AMI over HTTP support
- * The http.c file includes support for manager transactions over
- * http.
-- * \section ami AMI - The manager Interface
-- * \arg \link Config_ami Configuration file \endlink
-+ * \section ami AMI - The manager Interface
-+ * \arg \link Config_ami Configuration file \endlink
- */
-
--/*! \page res_config_sqlite SQLite Resource driver configuration
-+/*!
-+ * \page res_config_sqlite SQLite Resource driver configuration
- * \arg Implemented in \ref res_config_sqlite.c
- * \arg Configuration file:
- * \verbinclude res_config_sqlite.conf
-Index: include/asterisk/causes.h
-===================================================================
---- a/include/asterisk/causes.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk/causes.h (.../team/group/issue14292) (revision 178988)
-@@ -81,6 +81,10 @@
- - AST_CAUSE_PROTOCOL_ERROR 111
- - AST_CAUSE_INTERWORKING 127
-
-+The range 128-255 is private cause codes. Our private causes are:
-+
-+ - AST_CAUSE_ANSWERED_ELSEWHERE 200
-+
- For more information:
- - \ref app_dial.c
- */
-@@ -136,6 +140,9 @@
- #define AST_CAUSE_PROTOCOL_ERROR 111
- #define AST_CAUSE_INTERWORKING 127
-
-+/* Private Cause codes for Asterisk */
-+#define AST_CAUSE_ANSWERED_ELSEWHERE 200
-+
- /* Special Asterisk aliases */
- #define AST_CAUSE_BUSY AST_CAUSE_USER_BUSY
- #define AST_CAUSE_FAILURE AST_CAUSE_NETWORK_OUT_OF_ORDER
-Index: include/asterisk/xmldoc.h
-===================================================================
---- a/include/asterisk/xmldoc.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/include/asterisk/xmldoc.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,85 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+#ifndef _ASTERISK_XMLDOC_H
-+#define _ASTERISK_XMLDOC_H
-+
-+/*! \file
-+ * \brief Asterisk XML Documentation API
-+ */
-+
-+#include "asterisk/xml.h"
-+
-+#ifdef AST_XML_DOCS
-+
-+/*!
-+ * \brief Get the syntax for a specified application or function.
-+ * \param type Application, Function or AGI ?
-+ * \param name Name of the application or function.
-+ * \retval NULL on error.
-+ * \retval The generated syntax in a ast_malloc'ed string.
-+ */
-+char *ast_xmldoc_build_syntax(const char *type, const char *name);
-+
-+/*!
-+ * \brief Parse the <see-also> node content.
-+ * \param type 'application', 'function' or 'agi'.
-+ * \param name Application or functions name.
-+ * \retval NULL on error.
-+ * \retval Content of the see-also node.
-+ */
-+char *ast_xmldoc_build_seealso(const char *type, const char *name);
-+
-+/*!
-+ * \brief Generate the [arguments] tag based on type of node ('application',
-+ * 'function' or 'agi') and name.
-+ * \param type 'application', 'function' or 'agi' ?
-+ * \param name Name of the application or function to build the 'arguments' tag.
-+ * \retval NULL on error.
-+ * \retval Output buffer with the [arguments] tag content.
-+ */
-+char *ast_xmldoc_build_arguments(const char *type, const char *name);
-+
-+/*!
-+ * \brief Colorize and put delimiters (instead of tags) to the xmldoc output.
-+ * \param bwinput Not colorized input with tags.
-+ * \param withcolors Result output with colors.
-+ * \retval NULL on error.
-+ * \retval New malloced buffer colorized and with delimiters.
-+ */
-+char *ast_xmldoc_printable(const char *bwinput, int withcolors);
-+
-+/*!
-+ * \brief Generate synopsis documentation from XML.
-+ * \param type The source of documentation (application, function, etc).
-+ * \param name The name of the application, function, etc.
-+ * \retval NULL on error.
-+ * \retval A malloc'ed string with the synopsis.
-+ */
-+char *ast_xmldoc_build_synopsis(const char *type, const char *name);
-+
-+/*!
-+ * \brief Generate description documentation from XML.
-+ * \param type The source of documentation (application, function, etc).
-+ * \param name The name of the application, function, etc.
-+ * \retval NULL on error.
-+ * \retval A malloc'ed string with the formatted description.
-+ */
-+char *ast_xmldoc_build_description(const char *type, const char *name);
-+
-+#endif /* AST_XML_DOCS */
-+
-+#endif /* _ASTERISK_XMLDOC_H */
-
-Property changes on: include/asterisk/xmldoc.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: include/asterisk.h
-===================================================================
---- a/include/asterisk.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/include/asterisk.h (.../team/group/issue14292) (revision 178988)
-@@ -2,7 +2,7 @@
- * Asterisk -- A telephony toolkit for Linux.
- *
- * General Definitions for Asterisk top level program
-- *
-+ *
- * Copyright (C) 1999-2006, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
-@@ -54,9 +54,9 @@
- */
- int ast_register_atexit(void (*func)(void));
-
--/*!
-+/*!
- * \brief Unregister a function registered with ast_register_atexit().
-- * \param func The callback function to unregister.
-+ * \param func The callback function to unregister.
- */
- void ast_unregister_atexit(void (*func)(void));
-
-@@ -64,7 +64,7 @@
- /*!
- * \brief Register the version of a source code file with the core.
- * \param file the source file name
-- * \param version the version string (typically a CVS revision keyword string)
-+ * \param version the version string (typically a SVN revision keyword string)
- * \return nothing
- *
- * This function should not be called directly, but instead the
-@@ -89,11 +89,12 @@
- */
- const char *ast_file_version_find(const char *file);
-
-+char *ast_complete_source_filename(const char *partial, int n);
-
- /*!
- * \brief Register/unregister a source code file with the core.
- * \param file the source file name
-- * \param version the version string (typically a CVS revision keyword string)
-+ * \param version the version string (typically a SVN revision keyword string)
- *
- * This macro will place a file-scope constructor and destructor into the
- * source of the module using it; this will cause the version of this file
-@@ -107,8 +108,8 @@
- * \endcode
- *
- * \note The dollar signs above have been protected with backslashes to keep
-- * CVS from modifying them in this file; under normal circumstances they would
-- * not be present and CVS would expand the Revision keyword into the file's
-+ * SVN from modifying them in this file; under normal circumstances they would
-+ * not be present and SVN would expand the Revision keyword into the file's
- * revision number.
- */
- #ifdef MTX_PROFILE
-Index: main/utils.c
-===================================================================
---- a/main/utils.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/utils.c (.../team/group/issue14292) (revision 178988)
-@@ -826,7 +826,7 @@
- it's acquired... */
- if (lock_info->locks[i].lock_addr == this_lock_addr) {
- append_lock_information(&str, lock_info, i);
-- ast_log(LOG_NOTICE, "%s", str->str);
-+ ast_log(LOG_NOTICE, "%s", ast_str_buffer(str));
- break;
- }
- }
-@@ -899,7 +899,7 @@
- if (!str)
- return CLI_FAILURE;
-
-- ast_cli(a->fd, "%s", str->str);
-+ ast_cli(a->fd, "%s", ast_str_buffer(str));
-
- ast_free(str);
-
-@@ -1587,38 +1587,58 @@
-
- void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head,
-- const ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
-+ ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
- {
- size_t needed;
-- char *dst = (*pool_head)->base + mgr->used;
-- const char **p = (const char **) ptr;
-+ size_t available;
- size_t space = mgr->size - mgr->used;
-+ char *target;
-
-- /* try to write using available space */
-- needed = vsnprintf(dst, space, format, ap1) + 1;
-+ /* if the field already has space allocated, try to reuse it;
-+ otherwise, use the empty space at the end of the current
-+ pool
-+ */
-+ if ((*ptr)[0] != '\0') {
-+ target = (char *) *ptr;
-+ available = strlen(target) + 1;
-+ } else {
-+ target = (*pool_head)->base + mgr->used;
-+ available = space;
-+ }
-
-+ needed = vsnprintf(target, available, format, ap1) + 1;
-+
- va_end(ap1);
-
-- if (needed > space) { /* if it fails, reallocate */
-- size_t new_size = mgr->size * 2;
-+ if (needed > available) {
-+ /* if the space needed can be satisfied by using the current
-+ pool (which could only occur if we tried to use the field's
-+ allocated space and failed), then use that space; otherwise
-+ allocate a new pool
-+ */
-+ if (needed > space) {
-+ size_t new_size = mgr->size * 2;
-
-- while (new_size < needed)
-- new_size *= 2;
-+ while (new_size < needed)
-+ new_size *= 2;
-+
-+ if (add_string_pool(mgr, pool_head, new_size))
-+ return;
-+ }
-
-- if (add_string_pool(mgr, pool_head, new_size))
-- return;
--
-- dst = (*pool_head)->base + mgr->used;
-- vsprintf(dst, format, ap2);
-+ target = (*pool_head)->base + mgr->used;
-+ vsprintf(target, format, ap2);
- }
-
-- mgr->last_alloc = *p = dst;
-- mgr->used += needed;
-+ if (*ptr != target) {
-+ mgr->last_alloc = *ptr = target;
-+ mgr->used += needed;
-+ }
- }
-
- void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
- struct ast_string_field_pool **pool_head,
-- const ast_string_field *ptr, const char *format, ...)
-+ ast_string_field *ptr, const char *format, ...)
- {
- va_list ap1, ap2;
-
-@@ -1697,66 +1717,6 @@
- return -1;
- }
-
--/*!
-- * core handler for dynamic strings.
-- * This is not meant to be called directly, but rather through the
-- * various wrapper macros
-- * ast_str_set(...)
-- * ast_str_append(...)
-- * ast_str_set_va(...)
-- * ast_str_append_va(...)
-- */
--
--int __ast_str_helper(struct ast_str **buf, size_t max_len,
-- int append, const char *fmt, va_list ap)
--{
-- int res, need;
-- int offset = (append && (*buf)->len) ? (*buf)->used : 0;
-- va_list aq;
--
-- do {
-- if (max_len < 0) {
-- max_len = (*buf)->len; /* don't exceed the allocated space */
-- }
-- /*
-- * Ask vsnprintf how much space we need. Remember that vsnprintf
-- * does not count the final '\0' so we must add 1.
-- */
-- va_copy(aq, ap);
-- res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, aq);
--
-- need = res + offset + 1;
-- /*
-- * If there is not enough space and we are below the max length,
-- * reallocate the buffer and return a message telling to retry.
-- */
-- if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
-- if (max_len && max_len < need) { /* truncate as needed */
-- need = max_len;
-- } else if (max_len == 0) { /* if unbounded, give more room for next time */
-- need += 16 + need / 4;
-- }
-- if (0) { /* debugging */
-- ast_verbose("extend from %d to %d\n", (int)(*buf)->len, need);
-- }
-- if (ast_str_make_space(buf, need)) {
-- ast_verbose("failed to extend from %d to %d\n", (int)(*buf)->len, need);
-- return AST_DYNSTR_BUILD_FAILED;
-- }
-- (*buf)->str[offset] = '\0'; /* Truncate the partial write. */
--
-- /* Restart va_copy before calling vsnprintf() again. */
-- va_end(aq);
-- continue;
-- }
-- break;
-- } while (1);
-- /* update space used, keep in mind the truncation */
-- (*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset;
--
-- return res;
--}
--
- void ast_enable_packet_fragmentation(int sock)
- {
- #if defined(HAVE_IP_MTU_DISCOVER)
-Index: main/xml.c
-===================================================================
---- a/main/xml.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/main/xml.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,196 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief XML abstraction layer
-+ *
-+ * \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
-+ */
-+
-+#include "asterisk.h"
-+#include "asterisk/xml.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#if defined(HAVE_LIBXML2)
-+#define _POSIX_C_SOURCE 200112L
-+#include <libxml/parser.h>
-+#include <libxml/tree.h>
-+/* libxml2 ast_xml implementation. */
-+
-+
-+int ast_xml_init(void)
-+{
-+ LIBXML_TEST_VERSION
-+
-+ return 0;
-+}
-+
-+int ast_xml_finish(void)
-+{
-+ xmlCleanupParser();
-+
-+ return 0;
-+}
-+
-+struct ast_xml_doc *ast_xml_open(char *filename)
-+{
-+ xmlDoc *doc;
-+
-+ if (!filename) {
-+ return NULL;
-+ }
-+
-+ doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
-+
-+ return (struct ast_xml_doc *) doc;
-+}
-+
-+
-+void ast_xml_close(struct ast_xml_doc *doc)
-+{
-+ if (!doc) {
-+ return;
-+ }
-+
-+ xmlFreeDoc((xmlDoc *) doc);
-+ doc = NULL;
-+}
-+
-+
-+struct ast_xml_node *ast_xml_get_root(struct ast_xml_doc *doc)
-+{
-+ xmlNode *root_node;
-+
-+ if (!doc) {
-+ return NULL;
-+ }
-+
-+ root_node = xmlDocGetRootElement((xmlDoc *) doc);
-+
-+ return (struct ast_xml_node *) root_node;
-+}
-+
-+void ast_xml_free_node(struct ast_xml_node *node)
-+{
-+ if (!node) {
-+ return;
-+ }
-+
-+ xmlFreeNode((xmlNode *) node);
-+ node = NULL;
-+}
-+
-+void ast_xml_free_attr(const char *attribute)
-+{
-+ if (attribute) {
-+ xmlFree((char *) attribute);
-+ }
-+}
-+
-+void ast_xml_free_text(const char *text)
-+{
-+ if (text) {
-+ xmlFree((char *) text);
-+ }
-+}
-+
-+const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname)
-+{
-+ xmlChar *attrvalue;
-+
-+ if (!node) {
-+ return NULL;
-+ }
-+
-+ if (!attrname) {
-+ return NULL;
-+ }
-+
-+ attrvalue = xmlGetProp((xmlNode *) node, (xmlChar *) attrname);
-+
-+ return (const char *) attrvalue;
-+}
-+
-+struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue)
-+{
-+ struct ast_xml_node *cur;
-+ const char *attr;
-+
-+ if (!root_node) {
-+ return NULL;
-+ }
-+
-+ for (cur = root_node; cur; cur = ast_xml_node_get_next(cur)) {
-+ /* Check if the name matchs */
-+ if (strcmp(ast_xml_node_get_name(cur), name)) {
-+ continue;
-+ }
-+ /* We need to check for a specific attribute name? */
-+ if (!attrname || !attrvalue) {
-+ return cur;
-+ }
-+ /* Get the attribute, we need to compare it. */
-+ if ((attr = ast_xml_get_attribute(cur, attrname))) {
-+ /* does attribute name/value matches? */
-+ if (!strcmp(attr, attrvalue)) {
-+ ast_xml_free_attr(attr);
-+ return cur;
-+ }
-+ ast_xml_free_attr(attr);
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+const char *ast_xml_get_text(struct ast_xml_node *node)
-+{
-+ if (!node) {
-+ return NULL;
-+ }
-+
-+ return (const char *) xmlNodeGetContent((xmlNode *) node);
-+}
-+
-+const char *ast_xml_node_get_name(struct ast_xml_node *node)
-+{
-+ return (const char *) ((xmlNode *) node)->name;
-+}
-+
-+struct ast_xml_node *ast_xml_node_get_children(struct ast_xml_node *node)
-+{
-+ return (struct ast_xml_node *) ((xmlNode *) node)->children;
-+}
-+
-+struct ast_xml_node *ast_xml_node_get_next(struct ast_xml_node *node)
-+{
-+ return (struct ast_xml_node *) ((xmlNode *) node)->next;
-+}
-+
-+struct ast_xml_node *ast_xml_node_get_prev(struct ast_xml_node *node)
-+{
-+ return (struct ast_xml_node *) ((xmlNode *) node)->prev;
-+}
-+
-+struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node)
-+{
-+ return (struct ast_xml_node *) ((xmlNode *) node)->parent;
-+}
-+
-+#endif /* defined(HAVE_LIBXML2) */
-+
-
-Property changes on: main/xml.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: main/config.c
-===================================================================
---- a/main/config.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/config.c (.../team/group/issue14292) (revision 178988)
-@@ -39,24 +39,6 @@
-
- #define AST_INCLUDE_GLOB 1
-
--#ifdef AST_INCLUDE_GLOB
--/* glob compat stuff - eventually this should go in compat.h or some
-- * header in include/asterisk/
-- */
--#if defined(__Darwin__) || defined(__CYGWIN__)
--#define GLOB_ABORTED GLOB_ABEND
--#endif
--
--#include <glob.h>
--
--#ifdef SOLARIS
--#define MY_GLOB_FLAGS GLOB_NOCHECK
--#else
--#define MY_GLOB_FLAGS (GLOB_NOMAGIC|GLOB_BRACE)
--#endif
--
--#endif
--
- #include "asterisk/config.h"
- #include "asterisk/cli.h"
- #include "asterisk/lock.h"
-@@ -124,19 +106,23 @@
-
- static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
- {
-- if (cb)
-- cb->used = 0;
-- if (llb)
-- llb->used = 0;
-+ if (cb) {
-+ ast_str_reset(cb);
-+ }
-+ if (llb) {
-+ ast_str_reset(llb);
-+ }
- }
-
--static struct ast_comment *ALLOC_COMMENT(const struct ast_str *buffer)
-+static struct ast_comment *ALLOC_COMMENT(struct ast_str *buffer)
- {
- struct ast_comment *x = NULL;
-- if (buffer && buffer->used)
-- x = ast_calloc(1, sizeof(*x) + buffer->used + 1);
-- if (x)
-- strcpy(x->cmt, buffer->str);
-+ if (!buffer || !ast_str_strlen(buffer)) {
-+ return NULL;
-+ }
-+ if ((x = ast_calloc(1, sizeof(*x) + ast_str_strlen(buffer) + 1))) {
-+ strcpy(x->cmt, ast_str_buffer(buffer)); /* SAFE */
-+ }
- return x;
- }
-
-@@ -150,20 +136,21 @@
-
- static int hash_string(const void *obj, const int flags)
- {
-- char *str = ((struct inclfile*)obj)->fname;
-+ char *str = ((struct inclfile *) obj)->fname;
- int total;
-
-- for (total=0; *str; str++) {
-+ for (total = 0; *str; str++) {
- unsigned int tmp = total;
- total <<= 1; /* multiply by 2 */
- total += tmp; /* multiply by 3 */
- total <<= 2; /* multiply by 12 */
- total += tmp; /* multiply by 13 */
-
-- total += ((unsigned int)(*str));
-+ total += ((unsigned int) (*str));
- }
-- if (total < 0)
-+ if (total < 0) {
- total = -total;
-+ }
- return total;
- }
-
-@@ -377,16 +364,18 @@
- int lineno;
- int insertline;
-
-- if (!variable || sscanf(line, "%d", &insertline) != 1)
-+ if (!variable || sscanf(line, "%d", &insertline) != 1) {
- return;
-+ }
- if (!insertline) {
- variable->next = category->root;
- category->root = variable;
- } else {
- for (lineno = 1; lineno < insertline; lineno++) {
- cur = cur->next;
-- if (!cur->next)
-+ if (!cur->next) {
- break;
-+ }
- }
- variable->next = cur->next;
- cur->next = variable;
-@@ -408,10 +397,11 @@
- {
- struct ast_category *cat = NULL;
-
-- if (category && config->last_browse && (config->last_browse->name == category))
-+ if (category && config->last_browse && (config->last_browse->name == category)) {
- cat = config->last_browse;
-- else
-+ } else {
- cat = ast_category_get(config, category);
-+ }
-
- return (cat) ? cat->root : NULL;
- }
-@@ -420,8 +410,9 @@
- {
- const char *tmp;
- tmp = ast_variable_retrieve(cfg, cat, var);
-- if (!tmp)
-+ if (!tmp) {
- tmp = ast_variable_retrieve(cfg, "general", var);
-+ }
- return tmp;
- }
-
-@@ -432,16 +423,20 @@
-
- if (category) {
- for (v = ast_variable_browse(config, category); v; v = v->next) {
-- if (!strcasecmp(variable, v->name))
-+ if (!strcasecmp(variable, v->name)) {
- return v->value;
-+ }
- }
- } else {
- struct ast_category *cat;
-
-- for (cat = config->root; cat; cat = cat->next)
-- for (v = cat->root; v; v = v->next)
-- if (!strcasecmp(variable, v->name))
-+ for (cat = config->root; cat; cat = cat->next) {
-+ for (v = cat->root; v; v = v->next) {
-+ if (!strcasecmp(variable, v->name)) {
- return v->value;
-+ }
-+ }
-+ }
- }
-
- return NULL;
-@@ -1025,13 +1020,17 @@
-
- cur++;
- c = cur;
-- while (*c && (*c > 32)) c++;
-+ while (*c && (*c > 32)) {
-+ c++;
-+ }
-+
- if (*c) {
- *c = '\0';
- /* Find real argument */
- c = ast_skip_blanks(c + 1);
-- if (!(*c))
-+ if (!(*c)) {
- c = NULL;
-+ }
- } else
- c = NULL;
- if (!strcasecmp(cur, "include")) {
-@@ -1131,7 +1130,8 @@
-
- ast_str_set(str, 0, "%s", replace->value);
- ast_str_append(str, 0, "%s", c);
-- ast_variable_update(*cat, replace->name, ast_strip((*str)->str), replace->value, object);
-+ ast_str_trim_blanks(*str);
-+ ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
- } else if (c) {
- *c = 0;
- c++;
-@@ -1326,9 +1326,9 @@
- while (!feof(f)) {
- lineno++;
- if (fgets(buf, sizeof(buf), f)) {
-- if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && lline_buffer->used) {
-- CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
-- lline_buffer->used = 0; /* erase the lline buffer */
-+ if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
-+ CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
-+ ast_str_reset(lline_buffer); /* erase the lline buffer */
- }
-
- new_buf = buf;
-@@ -1337,14 +1337,14 @@
- else
- process_buf = buf;
-
-- if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
-+ if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer) && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
- /* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
- CB_ADD(&comment_buffer, "\n"); /* add a newline to the comment buffer */
- continue; /* go get a new line, then */
- }
-
- while ((comment_p = strchr(new_buf, COMMENT_META))) {
-- if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
-+ if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
- /* Escaped semicolons aren't comments. */
- new_buf = comment_p + 1;
- } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
-@@ -1400,7 +1400,7 @@
- char *buffer = ast_strip(process_buf);
- if (!ast_strlen_zero(buffer)) {
- if (process_text_line(cfg, &cat, buffer, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
-- cfg = NULL;
-+ cfg = CONFIG_STATUS_FILEINVALID;
- break;
- }
- }
-@@ -1409,44 +1409,45 @@
- }
- /* end of file-- anything in a comment buffer? */
- if (last_cat) {
-- if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
-- if (lline_buffer && lline_buffer->used) {
-- CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
-- lline_buffer->used = 0; /* erase the lline buffer */
-+ if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
-+ if (lline_buffer && ast_str_strlen(lline_buffer)) {
-+ CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
-+ ast_str_reset(lline_buffer); /* erase the lline buffer */
- }
- last_cat->trailing = ALLOC_COMMENT(comment_buffer);
- }
- } else if (last_var) {
-- if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
-- if (lline_buffer && lline_buffer->used) {
-- CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
-- lline_buffer->used = 0; /* erase the lline buffer */
-+ if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
-+ if (lline_buffer && ast_str_strlen(lline_buffer)) {
-+ CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
-+ ast_str_reset(lline_buffer); /* erase the lline buffer */
- }
- last_var->trailing = ALLOC_COMMENT(comment_buffer);
- }
- } else {
-- if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used) {
-- ast_debug(1, "Nothing to attach comments to, discarded: %s\n", comment_buffer->str);
-+ if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
-+ ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
- }
- }
- if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
- CB_RESET(comment_buffer, lline_buffer);
-
-- fclose(f);
-+ fclose(f);
- } while (0);
- if (comment) {
- ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
- }
- #ifdef AST_INCLUDE_GLOB
-- if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
-+ if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- break;
-+ }
- }
- globfree(&globbuf);
- }
- }
- #endif
-
-- if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
-+ if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
- if (comment_buffer)
- ast_free(comment_buffer);
- if (lline_buffer)
-@@ -1578,6 +1579,11 @@
-
- int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
- {
-+ return ast_config_text_file_save(configfile, cfg, generator);
-+}
-+
-+int ast_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
-+{
- FILE *f;
- char fn[256];
- struct ast_variable *var;
-@@ -2048,9 +2054,9 @@
-
- result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
-
-- if (result && result != CONFIG_STATUS_FILEUNCHANGED)
-+ if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED)
- result->include_level--;
-- else
-+ else if (result != CONFIG_STATUS_FILEINVALID)
- cfg->include_level--;
-
- return result;
-@@ -2066,7 +2072,7 @@
- return NULL;
-
- result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
-- if (!result || result == CONFIG_STATUS_FILEUNCHANGED)
-+ if (!result || result == CONFIG_STATUS_FILEUNCHANGED || result == CONFIG_STATUS_FILEINVALID)
- ast_config_destroy(cfg);
-
- return result;
-@@ -2075,8 +2081,8 @@
- static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
- {
- struct ast_config_engine *eng;
-- char db[256]="";
-- char table[256]="";
-+ char db[256];
-+ char table[256];
- struct ast_variable *res=NULL;
-
- eng = find_engine(family, db, sizeof(db), table, sizeof(table));
-@@ -2131,6 +2137,9 @@
- int ast_check_realtime(const char *family)
- {
- struct ast_config_engine *eng;
-+ if (!ast_realtime_enabled()) {
-+ return 0; /* There are no engines at all so fail early */
-+ }
-
- eng = find_engine(family, NULL, 0, NULL, 0);
- if (eng)
-@@ -2147,8 +2156,8 @@
- int ast_realtime_require_field(const char *family, ...)
- {
- struct ast_config_engine *eng;
-- char db[256] = "";
-- char table[256] = "";
-+ char db[256];
-+ char table[256];
- va_list ap;
- int res = -1;
-
-@@ -2165,8 +2174,8 @@
- int ast_unload_realtime(const char *family)
- {
- struct ast_config_engine *eng;
-- char db[256] = "";
-- char table[256] = "";
-+ char db[256];
-+ char table[256];
- int res = -1;
-
- eng = find_engine(family, db, sizeof(db), table, sizeof(table));
-@@ -2179,9 +2188,9 @@
- struct ast_config *ast_load_realtime_multientry(const char *family, ...)
- {
- struct ast_config_engine *eng;
-- char db[256]="";
-- char table[256]="";
-- struct ast_config *res=NULL;
-+ char db[256];
-+ char table[256];
-+ struct ast_config *res = NULL;
- va_list ap;
-
- va_start(ap, family);
-@@ -2197,8 +2206,8 @@
- {
- struct ast_config_engine *eng;
- int res = -1;
-- char db[256]="";
-- char table[256]="";
-+ char db[256];
-+ char table[256];
- va_list ap;
-
- va_start(ap, lookup);
-@@ -2210,12 +2219,29 @@
- return res;
- }
-
-+int ast_update2_realtime(const char *family, ...)
-+{
-+ struct ast_config_engine *eng;
-+ int res = -1;
-+ char db[256];
-+ char table[256];
-+ va_list ap;
-+
-+ va_start(ap, family);
-+ eng = find_engine(family, db, sizeof(db), table, sizeof(table));
-+ if (eng && eng->update2_func)
-+ res = eng->update2_func(db, table, ap);
-+ va_end(ap);
-+
-+ return res;
-+}
-+
- int ast_store_realtime(const char *family, ...)
- {
- struct ast_config_engine *eng;
- int res = -1;
-- char db[256]="";
-- char table[256]="";
-+ char db[256];
-+ char table[256];
- va_list ap;
-
- va_start(ap, family);
-@@ -2231,8 +2257,8 @@
- {
- struct ast_config_engine *eng;
- int res = -1;
-- char db[256]="";
-- char table[256]="";
-+ char db[256];
-+ char table[256];
- va_list ap;
-
- va_start(ap, lookup);
-@@ -2521,6 +2547,6 @@
-
- int register_config_cli()
- {
-- ast_cli_register_multiple(cli_config, sizeof(cli_config) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_config, ARRAY_LEN(cli_config));
- return 0;
- }
-Index: main/loader.c
-===================================================================
---- a/main/loader.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/loader.c (.../team/group/issue14292) (revision 178988)
-@@ -249,6 +249,7 @@
- { "features", ast_features_reload },
- { "dsp", ast_dsp_reload},
- { "udptl", ast_udptl_reload },
-+ { "indications", ast_indications_reload },
- { NULL, NULL }
- };
-
-@@ -787,7 +788,8 @@
- embedded_module_list.first = NULL;
- }
-
-- if (!(cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags))) {
-+ cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
- goto done;
- }
-Index: main/term.c
-===================================================================
---- a/main/term.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/term.c (.../team/group/issue14292) (revision 178988)
-@@ -50,6 +50,20 @@
- NULL
- };
-
-+static int opposite(int color)
-+{
-+ int lookup[] = {
-+ /* BLACK */ COLOR_BLACK,
-+ /* RED */ COLOR_MAGENTA,
-+ /* GREEN */ COLOR_GREEN,
-+ /* BROWN */ COLOR_BROWN,
-+ /* BLUE */ COLOR_CYAN,
-+ /* MAGENTA */ COLOR_RED,
-+ /* CYAN */ COLOR_BLUE,
-+ /* WHITE */ COLOR_BLACK };
-+ return color ? lookup[color - 30] : 0;
-+}
-+
- /* Ripped off from Ross Ridge, but it's public domain code (libmytinfo) */
- static short convshort(char *s)
- {
-@@ -134,9 +148,19 @@
-
- if (vt100compat) {
- /* Make commands show up in nice colors */
-- snprintf(prepdata, sizeof(prepdata), "%c[%d;%d;%dm", ESC, ATTR_BRIGHT, COLOR_BROWN, COLOR_BLACK + 10);
-- snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10);
-- snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC);
-+ if (ast_opt_light_background) {
-+ snprintf(prepdata, sizeof(prepdata), "%c[%dm", ESC, COLOR_BROWN);
-+ snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, COLOR_BLACK);
-+ snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC);
-+ } else if (ast_opt_force_black_background) {
-+ snprintf(prepdata, sizeof(prepdata), "%c[%d;%d;%dm", ESC, ATTR_BRIGHT, COLOR_BROWN, COLOR_BLACK + 10);
-+ snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10);
-+ snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC);
-+ } else {
-+ snprintf(prepdata, sizeof(prepdata), "%c[%d;%dm", ESC, ATTR_BRIGHT, COLOR_BROWN);
-+ snprintf(enddata, sizeof(enddata), "%c[%d;%dm", ESC, ATTR_RESET, COLOR_WHITE);
-+ snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC);
-+ }
- }
- return 0;
- }
-@@ -144,82 +168,103 @@
- char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
- {
- int attr = 0;
-- char tmp[40];
-+
- if (!vt100compat) {
- ast_copy_string(outbuf, inbuf, maxout);
- return outbuf;
- }
-- if (!fgcolor && !bgcolor) {
-+ if (!fgcolor) {
- ast_copy_string(outbuf, inbuf, maxout);
- return outbuf;
- }
-- if ((fgcolor & 128) && (bgcolor & 128)) {
-- /* Can't both be highlighted */
-- ast_copy_string(outbuf, inbuf, maxout);
-- return outbuf;
-+
-+ if (fgcolor & 128) {
-+ attr = ast_opt_light_background ? 0 : ATTR_BRIGHT;
-+ fgcolor &= ~128;
- }
-- if (!bgcolor)
-- bgcolor = COLOR_BLACK;
-
- if (bgcolor) {
- bgcolor &= ~128;
-- bgcolor += 10;
- }
-- if (fgcolor & 128) {
-- attr = ATTR_BRIGHT;
-- fgcolor &= ~128;
-+
-+ if (ast_opt_light_background) {
-+ fgcolor = opposite(fgcolor);
- }
-- if (fgcolor && bgcolor) {
-- snprintf(tmp, sizeof(tmp), "%d;%d", fgcolor, bgcolor);
-- } else if (bgcolor) {
-- snprintf(tmp, sizeof(tmp), "%d", bgcolor);
-- } else if (fgcolor) {
-- snprintf(tmp, sizeof(tmp), "%d", fgcolor);
-- }
-- if (attr) {
-- snprintf(outbuf, maxout, "%c[%d;%sm%s%c[0;%d;%dm", ESC, attr, tmp, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10);
-+
-+ if (ast_opt_force_black_background) {
-+ snprintf(outbuf, maxout, "%c[%d;%d;%dm%s%c[%d;%dm", ESC, attr, fgcolor, bgcolor + 10, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10);
- } else {
-- snprintf(outbuf, maxout, "%c[%sm%s%c[0;%d;%dm", ESC, tmp, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10);
-+ snprintf(outbuf, maxout, "%c[%d;%dm%s%c[0m", ESC, attr, fgcolor, inbuf, ESC);
- }
- return outbuf;
- }
-
--char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
-+static void check_fgcolor(int *fgcolor, int *attr)
- {
-- int attr=0;
-- char tmp[40];
-- if ((!vt100compat) || (!fgcolor && !bgcolor)) {
-- *outbuf = '\0';
-- return outbuf;
-+ if (*fgcolor & 128) {
-+ *attr = ast_opt_light_background ? 0 : ATTR_BRIGHT;
-+ *fgcolor &= ~128;
- }
-- if ((fgcolor & 128) && (bgcolor & 128)) {
-- /* Can't both be highlighted */
-- *outbuf = '\0';
-- return outbuf;
-+
-+ if (ast_opt_light_background) {
-+ *fgcolor = opposite(*fgcolor);
- }
-- if (!bgcolor)
-- bgcolor = COLOR_BLACK;
-+}
-
-- if (bgcolor) {
-- bgcolor &= ~128;
-- bgcolor += 10;
-+static void check_bgcolor(int *bgcolor)
-+{
-+ if (*bgcolor) {
-+ *bgcolor &= ~128;
- }
-- if (fgcolor & 128) {
-- attr = ATTR_BRIGHT;
-- fgcolor &= ~128;
-+}
-+
-+static int check_colors_allowed(int fgcolor)
-+{
-+ return (!vt100compat || !fgcolor) ? 0 : 1;
-+}
-+
-+int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
-+{
-+ int attr = 0;
-+
-+ if (!check_colors_allowed(fgcolor)) {
-+ return -1;
- }
-- if (fgcolor && bgcolor) {
-- snprintf(tmp, sizeof(tmp), "%d;%d", fgcolor, bgcolor);
-+
-+ check_fgcolor(&fgcolor, &attr);
-+ check_bgcolor(&bgcolor);
-+
-+ if (ast_opt_force_black_background) {
-+ ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
- } else if (bgcolor) {
-- snprintf(tmp, sizeof(tmp), "%d", bgcolor);
-- } else if (fgcolor) {
-- snprintf(tmp, sizeof(tmp), "%d", fgcolor);
-+ ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
-+ } else {
-+ ast_str_append(str, 0, "%c[%d;%dm", ESC, attr, fgcolor);
- }
-- if (attr) {
-- snprintf(outbuf, maxout, "%c[%d;%sm", ESC, attr, tmp);
-+
-+ return 0;
-+}
-+
-+char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
-+{
-+ int attr = 0;
-+
-+ if (!check_colors_allowed(fgcolor)) {
-+ *outbuf = '\0';
-+ return outbuf;
-+ }
-+
-+ check_fgcolor(&fgcolor, &attr);
-+ check_bgcolor(&bgcolor);
-+
-+ if (ast_opt_force_black_background) {
-+ snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
-+ } else if (bgcolor) {
-+ snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
- } else {
-- snprintf(outbuf, maxout, "%c[%sm", ESC, tmp);
-+ snprintf(outbuf, maxout, "%c[%d;%dm", ESC, attr, fgcolor);
- }
-+
- return outbuf;
- }
-
-@@ -250,11 +295,25 @@
- ast_copy_string(outbuf, inbuf, maxout);
- return outbuf;
- }
-- snprintf(outbuf, maxout, "%c[%d;%d;%dm%c%c[%d;%d;%dm%s",
-- ESC, ATTR_BRIGHT, COLOR_BLUE, COLOR_BLACK + 10,
-- inbuf[0],
-- ESC, 0, COLOR_WHITE, COLOR_BLACK + 10,
-- inbuf + 1);
-+ if (ast_opt_force_black_background) {
-+ snprintf(outbuf, maxout, "%c[%d;%dm%c%c[%d;%dm%s",
-+ ESC, COLOR_BLUE, COLOR_BLACK + 10,
-+ inbuf[0],
-+ ESC, COLOR_WHITE, COLOR_BLACK + 10,
-+ inbuf + 1);
-+ } else if (ast_opt_light_background) {
-+ snprintf(outbuf, maxout, "%c[%d;0m%c%c[%d;0m%s",
-+ ESC, COLOR_BLUE,
-+ inbuf[0],
-+ ESC, COLOR_BLACK,
-+ inbuf + 1);
-+ } else {
-+ snprintf(outbuf, maxout, "%c[%d;%d;0m%c%c[%d;%d;0m%s",
-+ ESC, ATTR_BRIGHT, COLOR_BLUE,
-+ inbuf[0],
-+ ESC, 0, COLOR_WHITE,
-+ inbuf + 1);
-+ }
- return outbuf;
- }
-
-Index: main/cdr.c
-===================================================================
---- a/main/cdr.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/cdr.c (.../team/group/issue14292) (revision 178988)
-@@ -367,8 +367,7 @@
- char workspace[256];
- int total = 0, x = 0, i;
-
-- (*buf)->used = 0;
-- (*buf)->str[0] = '\0';
-+ ast_str_reset(*buf);
-
- for (; cdr; cdr = recur ? cdr->next : NULL) {
- if (++x > 1)
-@@ -776,7 +775,7 @@
- }
- }
-
--void ast_cdr_setapp(struct ast_cdr *cdr, char *app, char *data)
-+void ast_cdr_setapp(struct ast_cdr *cdr, const char *app, const char *data)
- {
-
- for (; cdr; cdr = cdr->next) {
-@@ -870,8 +869,11 @@
- ast_log(LOG_WARNING, "CDR on channel '%s' has no answer time but is 'ANSWERED'\n", S_OR(cdr->channel, "<unknown>"));
- cdr->disposition = AST_CDR_FAILED;
- }
-- } else
-+ } else {
- cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec;
-+ if (ast_test_flag(&ast_options, AST_OPT_FLAG_INITIATED_SECONDS))
-+ cdr->billsec += cdr->end.tv_usec > cdr->answer.tv_usec ? 1 : 0;
-+ }
- }
- }
-
-@@ -1334,14 +1336,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_cli_status_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_cli_status(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "cdr status";
-- return res;
--}
--
- static char *handle_cli_submit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1364,8 +1358,7 @@
- }
-
- static struct ast_cli_entry cli_submit = AST_CLI_DEFINE(handle_cli_submit, "Posts all pending batched CDR data");
--static struct ast_cli_entry cli_status_deprecated = AST_CLI_DEFINE(handle_cli_status_deprecated, "Display the CDR status");
--static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status", .deprecate_cmd = &cli_status_deprecated);
-+static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CDR status");
-
- static int do_reload(int reload)
- {
-@@ -1378,6 +1371,7 @@
- const char *size_value;
- const char *time_value;
- const char *end_before_h_value;
-+ const char *initiatedseconds_value;
- int cfg_size;
- int cfg_time;
- int was_enabled;
-@@ -1387,6 +1381,9 @@
-
- if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
- return 0;
-+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
-+ return 0;
-+ }
-
- ast_mutex_lock(&cdr_batch_lock);
-
-@@ -1436,6 +1433,8 @@
- }
- if ((end_before_h_value = ast_variable_retrieve(config, "general", "endbeforehexten")))
- ast_set2_flag(&ast_options, ast_true(end_before_h_value), AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN);
-+ if ((initiatedseconds_value = ast_variable_retrieve(config, "general", "initiatedseconds")))
-+ ast_set2_flag(&ast_options, ast_true(initiatedseconds_value), AST_OPT_FLAG_INITIATED_SECONDS);
- }
-
- if (enabled && !batchmode) {
-Index: main/channel.c
-===================================================================
---- a/main/channel.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/channel.c (.../team/group/issue14292) (revision 178988)
-@@ -131,7 +131,7 @@
- *
- * \ref causes.h
- */
--const struct ast_cause {
-+static const struct {
- int cause;
- const char *name;
- const char *desc;
-@@ -363,8 +363,7 @@
- return total;
- }
- traced = store->data;
-- (*buf)->used = 0;
-- (*buf)->str[0] = '\0';
-+ ast_str_reset(*buf);
- AST_LIST_TRAVERSE(&traced->trace, trace, entry) {
- if (ast_str_append(buf, 0, "[%d] => %s, %s, %d\n", total, trace->context, trace->exten, trace->priority) < 0) {
- ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
-@@ -940,6 +939,8 @@
- "CallerIDNum: %s\r\n"
- "CallerIDName: %s\r\n"
- "AccountCode: %s\r\n"
-+ "Exten: %s\r\n"
-+ "Context: %s\r\n"
- "Uniqueid: %s\r\n",
- tmp->name,
- state,
-@@ -947,6 +948,8 @@
- S_OR(cid_num, ""),
- S_OR(cid_name, ""),
- tmp->accountcode,
-+ S_OR(exten, ""),
-+ S_OR(context, ""),
- tmp->uniqueid);
- }
-
-@@ -1244,6 +1247,24 @@
- return channel_find_locked(chan, NULL, 0, context, exten);
- }
-
-+/*! \brief Search for a channel based on the passed channel matching callback (first match) and return it, locked */
-+struct ast_channel *ast_channel_search_locked(int (*is_match)(struct ast_channel *, void *), void *data)
-+{
-+ struct ast_channel *c = NULL;
-+
-+ AST_RWLIST_RDLOCK(&channels);
-+ AST_RWLIST_TRAVERSE(&channels, c, chan_list) {
-+ ast_channel_lock(c);
-+ if (is_match(c, data)) {
-+ break;
-+ }
-+ ast_channel_unlock(c);
-+ }
-+ AST_RWLIST_UNLOCK(&channels);
-+
-+ return c;
-+}
-+
- /*! \brief Wait, look for hangups and condition arg */
- int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data)
- {
-@@ -1286,6 +1307,435 @@
- cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = cid->cid_rdnis = NULL;
- }
-
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Initialize the given party id structure.
-+ *
-+ * \param init Party id structure to initialize.
-+ *
-+ * \return Nothing
-+ */
-+static void ast_party_id_init(struct ast_party_id *init)
-+{
-+ init->number = NULL;
-+ init->name = NULL;
-+ init->number_type = 0; /* Unknown */
-+ init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-+} /* end ast_party_id_init() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Copy the source party id information to the destination party id.
-+ *
-+ * \param dest Destination party id
-+ * \param src Source party id
-+ *
-+ * \return Nothing
-+ */
-+static void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
-+{
-+ if (dest == src) {
-+ /* Don't copy to self */
-+ return;
-+ }
-+
-+ if (dest->number) {
-+ ast_free(dest->number);
-+ }
-+ dest->number = ast_strdup(src->number);
-+
-+ if (dest->name) {
-+ ast_free(dest->name);
-+ }
-+ dest->name = ast_strdup(src->name);
-+
-+ dest->number_type = src->number_type;
-+ dest->number_presentation = src->number_presentation;
-+} /* end ast_party_id_copy() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Initialize the given party id structure using the given guide
-+ * for a set update operation.
-+ *
-+ * \details
-+ * The initialization is needed to allow a set operation to know if a
-+ * value needs to be updated. Simple integers need the guide's original
-+ * value in case the set operation is not trying to set a new value.
-+ * String values are simply set to NULL pointers if they are not going
-+ * to be updated.
-+ *
-+ * \param init Party id structure to initialize.
-+ * \param guide Source party id to use as a guide in initializing.
-+ *
-+ * \return Nothing
-+ */
-+static void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide)
-+{
-+ init->number = NULL;
-+ init->name = NULL;
-+ init->number_type = guide->number_type;
-+ init->number_presentation = guide->number_presentation;
-+} /* end ast_party_id_set_init() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Set the source party id information into the destination party id.
-+ *
-+ * \param dest Destination party id
-+ * \param src Source party id
-+ *
-+ * \return Nothing
-+ */
-+static void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src)
-+{
-+ if (dest == src) {
-+ /* Don't set to self */
-+ return;
-+ }
-+
-+ if (src->name && src->name != dest->name) {
-+ if (dest->name) {
-+ ast_free(dest->name);
-+ }
-+ dest->name = ast_strdup(src->name);
-+ }
-+
-+ if (src->number && src->number != dest->number) {
-+ if (dest->number) {
-+ ast_free(dest->number);
-+ }
-+ dest->number = ast_strdup(src->number);
-+ }
-+
-+ dest->number_type = src->number_type;
-+ dest->number_presentation = src->number_presentation;
-+} /* end ast_party_id_set() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Destroy the party id contents
-+ *
-+ * \param doomed The party id to destroy.
-+ *
-+ * \return Nothing
-+ */
-+static void ast_party_id_free(struct ast_party_id *doomed)
-+{
-+ if (doomed->number) {
-+ ast_free(doomed->number);
-+ doomed->number = NULL;
-+ }
-+
-+ if (doomed->name) {
-+ ast_free(doomed->name);
-+ doomed->name = NULL;
-+ }
-+} /* end ast_party_id_free() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Copy the source caller information to the destination caller.
-+ *
-+ * \param dest Destination caller
-+ * \param src Source caller
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src)
-+{
-+ if (dest == src) {
-+ /* Don't copy to self */
-+ return;
-+ }
-+
-+#if 1
-+ /* Copy caller-id specific information ONLY from struct ast_callerid */
-+ if (dest->cid_num)
-+ {
-+ ast_free(dest->cid_num);
-+ }
-+ dest->cid_num = ast_strdup(src->cid_num);
-+
-+ if (dest->cid_name)
-+ {
-+ ast_free(dest->cid_name);
-+ }
-+ dest->cid_name = ast_strdup(src->cid_name);
-+
-+ dest->cid_ton = src->cid_ton;
-+ dest->cid_pres = src->cid_pres;
-+
-+
-+ if (dest->cid_ani)
-+ {
-+ ast_free(dest->cid_ani);
-+ }
-+ dest->cid_ani = ast_strdup(src->cid_ani);
-+
-+ dest->cid_ani2 = src->cid_ani2;
-+
-+#else
-+
-+ /* The src and dest parameter types will become struct ast_party_caller ptrs. */
-+
-+ ast_party_id_copy(&dest->id, &src->id);
-+
-+ if (dest->ani) {
-+ ast_free(dest->ani);
-+ }
-+ dest->ani = ast_strdup(src->ani);
-+
-+ dest->ani2 = src->ani2;
-+#endif
-+} /* end ast_party_caller_copy() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Initialize the given connected line structure.
-+ *
-+ * \param init Connected line structure to initialize.
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_connected_line_init(struct ast_party_connected_line *init)
-+{
-+ ast_party_id_init(&init->id);
-+ init->ani = NULL;
-+ init->ani2 = 0;
-+ init->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
-+} /* end ast_party_connected_line_init() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Copy the source connected line information to the destination connected line.
-+ *
-+ * \param dest Destination connected line
-+ * \param src Source connected line
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
-+{
-+ if (dest == src) {
-+ /* Don't copy to self */
-+ return;
-+ }
-+
-+ ast_party_id_copy(&dest->id, &src->id);
-+
-+ if (dest->ani) {
-+ ast_free(dest->ani);
-+ }
-+ dest->ani = ast_strdup(src->ani);
-+
-+ dest->ani2 = src->ani2;
-+ dest->source = src->source;
-+} /* end ast_party_connected_line_copy() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Initialize the given connected line structure using the given
-+ * guide for a set update operation.
-+ *
-+ * \details
-+ * The initialization is needed to allow a set operation to know if a
-+ * value needs to be updated. Simple integers need the guide's original
-+ * value in case the set operation is not trying to set a new value.
-+ * String values are simply set to NULL pointers if they are not going
-+ * to be updated.
-+ *
-+ * \param init Connected line structure to initialize.
-+ * \param guide Source connected line to use as a guide in initializing.
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
-+{
-+ ast_party_id_set_init(&init->id, &guide->id);
-+ init->ani = NULL;
-+ init->ani2 = guide->ani2;
-+ init->source = guide->source;
-+} /* end ast_party_connected_line_set_init() */
-+
-+/*! \brief Set the connected line information based on another connected line source
-+ *
-+ * This is similar to ast_party_connected_line_copy, except that NULL values for
-+ * strings in the src parameter indicate not to update the corresponding dest values.
-+ *
-+ * \param src The source connected line to use as a guide to set the dest
-+ * \param dest The connected line one wishes to update
-+ *
-+ * \return Nada
-+ */
-+void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
-+{
-+ ast_party_id_set(&dest->id, &src->id);
-+
-+ if (src->ani && src->ani != dest->ani) {
-+ if (dest->ani) {
-+ ast_free(dest->ani);
-+ }
-+ dest->ani = ast_strdup(src->ani);
-+ }
-+
-+ dest->ani2 = src->ani2;
-+ dest->source = src->source;
-+}
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Collect the caller party information into a connected line structure.
-+ *
-+ * \param connected Collected caller information for the connected line
-+ * \param cid Caller information.
-+ *
-+ * \return Nothing
-+ *
-+ * \warning This is a shallow copy.
-+ * \warning DO NOT call ast_party_connected_line_free() on the filled in
-+ * connected line structure!
-+ */
-+void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid)
-+{
-+ connected->id.number = cid->cid_num;
-+ connected->id.name = cid->cid_name;
-+ connected->id.number_type = cid->cid_ton;
-+ connected->id.number_presentation = cid->cid_pres;
-+
-+ connected->ani = cid->cid_ani;
-+ connected->ani2 = cid->cid_ani2;
-+ connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
-+} /* end ast_party_connected_line_collect_caller() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Destroy the connected line information contents
-+ *
-+ * \param doomed The connected line information to destroy.
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
-+{
-+ ast_party_id_free(&doomed->id);
-+
-+ if (doomed->ani) {
-+ ast_free(doomed->ani);
-+ doomed->ani = NULL;
-+ }
-+} /* end ast_party_connected_line_free() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Copy the source redirecting information to the destination redirecting.
-+ *
-+ * \param dest Destination redirecting
-+ * \param src Source redirecting
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
-+{
-+ if (dest == src) {
-+ /* Don't copy to self */
-+ return;
-+ }
-+
-+ ast_party_id_copy(&dest->from, &src->from);
-+ ast_party_id_copy(&dest->to, &src->to);
-+ dest->count = src->count;
-+ dest->reason = src->reason;
-+} /* end ast_party_redirecting_copy() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Initialize the given redirecting id structure using the given guide
-+ * for a set update operation.
-+ *
-+ * \details
-+ * The initialization is needed to allow a set operation to know if a
-+ * value needs to be updated. Simple integers need the guide's original
-+ * value in case the set operation is not trying to set a new value.
-+ * String values are simply set to NULL pointers if they are not going
-+ * to be updated.
-+ *
-+ * \param init Redirecting id structure to initialize.
-+ * \param guide Source redirecting id to use as a guide in initializing.
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
-+{
-+ ast_party_id_set_init(&init->from, &guide->from);
-+ ast_party_id_set_init(&init->to, &guide->to);
-+ init->count = guide->count;
-+ init->reason = guide->reason;
-+} /* end ast_party_redirecting_set_init() */
-+
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Destroy the redirecting information contents
-+ *
-+ * \param doomed The redirecting information to destroy.
-+ *
-+ * \return Nothing
-+ */
-+void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
-+{
-+ ast_party_id_free(&doomed->from);
-+ ast_party_id_free(&doomed->to);
-+} /* end ast_party_redirecting_free() */
-+
-+
-+
-+
- /*! \brief Free a channel structure */
- void ast_channel_free(struct ast_channel *chan)
- {
-@@ -1349,7 +1799,11 @@
- ast_translator_free_path(chan->writetrans);
- if (chan->pbx)
- ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
-+
- free_cid(&chan->cid);
-+ ast_party_connected_line_free(&chan->connected);
-+ ast_party_redirecting_free(&chan->redirecting);
-+
- /* Close pipes if appropriate */
- if ((fd = chan->alertpipe[0]) > -1)
- close(fd);
-@@ -1382,14 +1836,21 @@
- ast_cdr_discard(chan->cdr);
- chan->cdr = NULL;
- }
--
-+
-+ if (chan->zone) {
-+ chan->zone = ast_tone_zone_unref(chan->zone);
-+ }
-+
- ast_mutex_destroy(&chan->lock_dont_use);
-
- ast_string_field_free_memory(chan);
- ast_free(chan);
- AST_RWLIST_UNLOCK(&channels);
-
-- ast_devstate_changed_literal(AST_DEVICE_NOT_INUSE, name);
-+ /* Queue an unknown state, because, while we know that this particular
-+ * instance is dead, we don't know the state of all other possible
-+ * instances. */
-+ ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name);
- }
-
- struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
-@@ -1673,7 +2134,7 @@
- }
-
- #define ANSWER_WAIT_MS 500
--int __ast_answer(struct ast_channel *chan, unsigned int delay)
-+int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer)
- {
- int res = 0;
-
-@@ -1701,7 +2162,9 @@
- res = chan->tech->answer(chan);
- }
- ast_setstate(chan, AST_STATE_UP);
-- ast_cdr_answer(chan->cdr);
-+ if (cdr_answer) {
-+ ast_cdr_answer(chan->cdr);
-+ }
- ast_channel_unlock(chan);
- if (delay) {
- ast_safe_sleep(chan, delay);
-@@ -1737,6 +2200,12 @@
- }
- break;
- case AST_STATE_UP:
-+ /* Calling ast_cdr_answer when it it has previously been called
-+ * is essentially a no-op, so it is safe.
-+ */
-+ if (cdr_answer) {
-+ ast_cdr_answer(chan->cdr);
-+ }
- break;
- default:
- break;
-@@ -1750,7 +2219,7 @@
-
- int ast_answer(struct ast_channel *chan)
- {
-- return __ast_answer(chan, 0);
-+ return __ast_answer(chan, 0, 1);
- }
-
- void ast_deactivate_generator(struct ast_channel *chan)
-@@ -2282,6 +2751,8 @@
- case AST_CONTROL_RINGING:
- case AST_CONTROL_ANSWER:
- case AST_CONTROL_SRCUPDATE:
-+ case AST_CONTROL_CONNECTED_LINE:
-+ case AST_CONTROL_REDIRECTING:
- /* Unimportant */
- break;
- default:
-@@ -2463,7 +2934,7 @@
- }
-
- if (chan->timingfd > -1 && chan->fdno == AST_TIMING_FD) {
-- enum ast_timing_event res;
-+ enum ast_timer_event res;
-
- ast_clear_flag(chan, AST_FLAG_EXCEPTION);
-
-@@ -2858,7 +3329,9 @@
- case AST_CONTROL_ANSWER:
- case AST_CONTROL_HANGUP:
- case AST_CONTROL_T38:
-- return 0;
-+ case AST_CONTROL_CONNECTED_LINE:
-+ case AST_CONTROL_REDIRECTING:
-+ break;
-
- case AST_CONTROL_CONGESTION:
- case AST_CONTROL_BUSY:
-@@ -2878,8 +3351,8 @@
- /* By using an enum, we'll get compiler warnings for values not handled
- * in switch statements. */
- enum ast_control_frame_type condition = _condition;
-- const struct tone_zone_sound *ts = NULL;
-- int res = -1;
-+ struct ast_tone_zone_sound *ts = NULL;
-+ int res;
-
- ast_channel_lock(chan);
-
-@@ -2888,10 +3361,41 @@
- ast_channel_unlock(chan);
- return -1;
- }
-+ switch (condition) {
-+ case AST_CONTROL_CONNECTED_LINE:
-+ {
-+ struct ast_party_connected_line connected;
-
-+ ast_party_connected_line_set_init(&connected, &chan->connected);
-+ res = ast_parse_connected_line_data(data, datalen, &connected);
-+ if (!res) {
-+ ast_set_connected_line(chan, &connected);
-+ }
-+ ast_party_connected_line_free(&connected);
-+ }
-+ break;
-+
-+ case AST_CONTROL_REDIRECTING:
-+ {
-+ struct ast_party_redirecting redirecting;
-+
-+ ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
-+ res = ast_parse_redirecting_data(data, datalen, &redirecting);
-+ if (!res) {
-+ ast_set_redirecting(chan, &redirecting);
-+ }
-+ ast_party_redirecting_free(&redirecting);
-+ }
-+ break;
-+
-+ default:
-+ break;
-+ } /* end switch */
- if (chan->tech->indicate) {
- /* See if the channel driver can handle this condition. */
- res = chan->tech->indicate(chan, condition, data, datalen);
-+ } else {
-+ res = -1;
- }
-
- ast_channel_unlock(chan);
-@@ -2944,15 +3448,18 @@
- case AST_CONTROL_HOLD:
- case AST_CONTROL_UNHOLD:
- case AST_CONTROL_T38:
-+ case AST_CONTROL_CONNECTED_LINE:
-+ case AST_CONTROL_REDIRECTING:
- /* Nothing left to do for these. */
- res = 0;
- break;
- }
-
-- if (ts && ts->data[0]) {
-+ if (ts) {
- /* We have a tone to play, yay. */
- ast_debug(1, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
- ast_playtones_start(chan, 0, ts->data, 1);
-+ ts = ast_tone_zone_sound_unref(ts);
- res = 0;
- chan->visible_indication = condition;
- }
-@@ -3405,6 +3912,7 @@
- struct ast_channel *chan;
- int res = 0;
- int last_subclass = 0;
-+ struct ast_party_connected_line connected;
-
- if (outstate)
- *outstate = 0;
-@@ -3435,7 +3943,13 @@
- if (oh->account)
- ast_cdr_setaccount(chan, oh->account);
- }
-+
- ast_set_callerid(chan, cid_num, cid_name, cid_num);
-+ ast_party_connected_line_set_init(&connected, &chan->connected);
-+ connected.id.number = (char *) cid_num;
-+ connected.id.name = (char *) cid_name;
-+ connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-+ ast_set_connected_line(chan, &connected);
-
- if (ast_call(chan, data, 0)) { /* ast_call failed... */
- ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
-@@ -3474,6 +3988,8 @@
- case AST_CONTROL_UNHOLD:
- case AST_CONTROL_VIDUPDATE:
- case AST_CONTROL_SRCUPDATE:
-+ case AST_CONTROL_CONNECTED_LINE:
-+ case AST_CONTROL_REDIRECTING:
- case -1: /* Ignore -- just stopping indications */
- break;
-
-@@ -3913,7 +4429,11 @@
- struct ast_frame *current;
- const struct ast_channel_tech *t;
- void *t_pvt;
-- struct ast_callerid tmpcid;
-+ union {
-+ struct ast_callerid cid;
-+ struct ast_party_connected_line connected;
-+ struct ast_party_redirecting redirecting;
-+ } exchange;
- struct ast_channel *clonechan = original->masq;
- struct ast_cdr *cdr;
- int rformat = original->readformat;
-@@ -4094,11 +4614,19 @@
- /* Stream stuff stays the same */
- /* Keep the original state. The fixup code will need to work with it most likely */
-
-- /* Just swap the whole structures, nevermind the allocations, they'll work themselves
-- out. */
-- tmpcid = original->cid;
-+ /*
-+ * Just swap the whole structures, nevermind the allocations,
-+ * they'll work themselves out.
-+ */
-+ exchange.cid = original->cid;
- original->cid = clonechan->cid;
-- clonechan->cid = tmpcid;
-+ clonechan->cid = exchange.cid;
-+ exchange.connected = original->connected;
-+ original->connected = clonechan->connected;
-+ clonechan->connected = exchange.connected;
-+ exchange.redirecting = original->redirecting;
-+ original->redirecting = clonechan->redirecting;
-+ clonechan->redirecting = exchange.redirecting;
-
- /* Restore original timing file descriptor */
- ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd);
-@@ -4341,10 +4869,13 @@
- if (bridge_end.tv_sec) {
- to = ast_tvdiff_ms(bridge_end, ast_tvnow());
- if (to <= 0) {
-- if (config->timelimit)
-+ if (config->timelimit) {
- res = AST_BRIDGE_RETRY;
-- else
-+ /* generic bridge ending to play warning */
-+ ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
-+ } else {
- res = AST_BRIDGE_COMPLETE;
-+ }
- break;
- }
- } else
-@@ -4389,6 +4920,8 @@
- case AST_CONTROL_UNHOLD:
- case AST_CONTROL_VIDUPDATE:
- case AST_CONTROL_SRCUPDATE:
-+ case AST_CONTROL_CONNECTED_LINE:
-+ case AST_CONTROL_REDIRECTING:
- ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
- if (jb_in_use) {
- ast_jb_empty_and_reset(c0, c1);
-@@ -4423,6 +4956,7 @@
- ast_debug(1, "Got DTMF %s on channel (%s)\n",
- f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
- who->name);
-+
- break;
- }
- /* Write immediately frames, not passed through jb */
-@@ -4494,7 +5028,6 @@
- int o0nativeformats;
- int o1nativeformats;
- long time_left_ms=0;
-- struct timeval nexteventts = { 0, };
- char caller_warning = 0;
- char callee_warning = 0;
-
-@@ -4541,11 +5074,11 @@
- o1nativeformats = c1->nativeformats;
-
- if (config->feature_timer) {
-- nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
-- } else if (config->timelimit) {
-- nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
-+ config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
-+ } else if (config->timelimit && firstpass) {
-+ config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
- if (caller_warning || callee_warning)
-- nexteventts = ast_tvsub(nexteventts, ast_samp2tv(config->play_warning, 1000));
-+ config->nexteventts = ast_tvsub(config->nexteventts, ast_samp2tv(config->play_warning, 1000));
- }
-
- if (!c0->tech->send_digit_begin)
-@@ -4565,9 +5098,9 @@
-
- to = -1;
-
-- if (!ast_tvzero(nexteventts)) {
-+ if (!ast_tvzero(config->nexteventts)) {
- now = ast_tvnow();
-- to = ast_tvdiff_ms(nexteventts, now);
-+ to = ast_tvdiff_ms(config->nexteventts, now);
- if (to <= 0) {
- if (!config->timelimit) {
- res = AST_BRIDGE_COMPLETE;
-@@ -4595,7 +5128,7 @@
- }
-
- if (!to) {
-- if (time_left_ms >= 5000 && config->warning_sound && config->play_warning) {
-+ if (time_left_ms >= 5000 && config->warning_sound && config->play_warning && ast_test_flag(config, AST_FEATURE_WARNING_ACTIVE)) {
- int t = (time_left_ms + 500) / 1000; /* round to nearest second */
- if (caller_warning)
- bridge_playfile(c0, c1, config->warning_sound, t);
-@@ -4603,10 +5136,11 @@
- bridge_playfile(c1, c0, config->warning_sound, t);
- }
- if (config->warning_freq && (time_left_ms > (config->warning_freq + 5000)))
-- nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
-+ config->nexteventts = ast_tvadd(config->nexteventts, ast_samp2tv(config->warning_freq, 1000));
- else
-- nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
-+ config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
- }
-+ ast_clear_flag(config, AST_FEATURE_WARNING_ACTIVE);
- }
-
- if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) {
-@@ -4719,9 +5253,13 @@
- if (!ast_strlen_zero(pbx_builtin_getvar_helper(c1, "BRIDGEPEER")))
- pbx_builtin_setvar_helper(c1, "BRIDGEPEER", c0->name);
-
-- res = ast_generic_bridge(c0, c1, config, fo, rc, nexteventts);
-- if (res != AST_BRIDGE_RETRY)
-+ res = ast_generic_bridge(c0, c1, config, fo, rc, config->nexteventts);
-+ if (res != AST_BRIDGE_RETRY) {
- break;
-+ } else if (config->feature_timer) {
-+ /* feature timer expired but has not been updated, sending to ast_bridge_call to do so */
-+ break;
-+ }
- }
-
- ast_clear_flag(c0, AST_FLAG_END_DTMF_ONLY);
-@@ -5302,3 +5840,753 @@
-
- return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd);
- }
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Copy the caller information to the connected line information.
-+ *
-+ * \param dest Destination connected line information
-+ * \param src Source caller information
-+ *
-+ * \return Nothing
-+ *
-+ * \note Assumes locks are already acquired
-+ */
-+void ast_copy_caller_to_connected(struct ast_party_connected_line *dest, const struct ast_callerid *src)
-+{
-+#if 1
-+ /* Must manually fill in struct ast_party_id until struct ast_callerid goes away */
-+ if (dest->id.number) {
-+ ast_free(dest->id.number);
-+ }
-+ dest->id.number = ast_strdup(src->cid_num);
-+
-+ if (dest->id.name) {
-+ ast_free(dest->id.name);
-+ }
-+ dest->id.name = ast_strdup(src->cid_name);
-+
-+ dest->id.number_type = src->cid_ton;
-+ dest->id.number_presentation = src->cid_pres;
-+
-+
-+ if (dest->ani) {
-+ ast_free(dest->ani);
-+ }
-+ dest->ani = ast_strdup(src->cid_ani);
-+
-+ dest->ani2 = src->cid_ani2;
-+
-+#else
-+
-+ /* The src parameter type will become a struct ast_party_caller ptr. */
-+
-+ ast_party_id_copy(&dest->id, &src->id);
-+
-+ if (dest->ani) {
-+ ast_free(dest->ani);
-+ }
-+ dest->ani = ast_strdup(src->ani);
-+
-+ dest->ani2 = src->ani2;
-+#endif
-+} /* end ast_copy_caller_to_connected() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Copy the connected line information to the caller information.
-+ *
-+ * \param dest Destination caller information
-+ * \param src Source connected line information
-+ *
-+ * \return Nothing
-+ *
-+ * \note Assumes locks are already acquired
-+ */
-+void ast_copy_connected_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src)
-+{
-+#if 1
-+ /* Must manually extract from struct ast_party_id until struct ast_callerid goes away */
-+ if (dest->cid_num) {
-+ ast_free(dest->cid_num);
-+ }
-+ dest->cid_num = ast_strdup(src->id.number);
-+
-+ if (dest->cid_name) {
-+ ast_free(dest->cid_name);
-+ }
-+ dest->cid_name = ast_strdup(src->id.name);
-+
-+ dest->cid_ton = src->id.number_type;
-+ dest->cid_pres = src->id.number_presentation;
-+
-+
-+ if (dest->cid_ani) {
-+ ast_free(dest->cid_ani);
-+ }
-+ dest->cid_ani = ast_strdup(src->ani);
-+
-+ dest->cid_ani2 = src->ani2;
-+
-+#else
-+
-+ /* The dest parameter type will become a struct ast_party_caller ptr. */
-+
-+ ast_party_id_copy(&dest->id, &src->id);
-+
-+ if (dest->ani) {
-+ ast_free(dest->ani);
-+ }
-+ dest->ani = ast_strdup(src->ani);
-+
-+ dest->ani2 = src->ani2;
-+#endif
-+} /* end ast_copy_connected_to_caller() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Set the connected line information in the Asterisk channel
-+ *
-+ * \param chan Asterisk channel to set connected line information
-+ * \param connected Connected line information
-+ *
-+ * \return Nothing
-+ *
-+ * \note The channel does not need to be locked before calling this function.
-+ */
-+void ast_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
-+{
-+ if (&chan->connected == connected) {
-+ /* Don't set to self */
-+ return;
-+ }
-+
-+ ast_channel_lock(chan);
-+ ast_party_connected_line_set(&chan->connected, connected);
-+ ast_channel_unlock(chan);
-+} /* end ast_set_connected_line() */
-+
-+
-+
-+
-+/*!
-+ * \brief Element identifiers for connected line indication frame data
-+ * \note Only add to the end of this enum.
-+ */
-+enum {
-+ AST_CONNECTED_LINE_NUMBER,
-+ AST_CONNECTED_LINE_NAME,
-+ AST_CONNECTED_LINE_NUMBER_TYPE,
-+ AST_CONNECTED_LINE_NUMBER_PRESENTATION,
-+ AST_CONNECTED_LINE_SOURCE
-+};
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Build the connected line information data frame.
-+ *
-+ * \param data Buffer to fill with the frame data
-+ * \param datalen Size of the buffer to fill
-+ * \param connected Connected line information
-+ *
-+ * \retval -1 if error
-+ * \retval Amount of data buffer used
-+ */
-+static int build_connected_line_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected)
-+{
-+ int32_t value;
-+ size_t length;
-+ size_t pos = 0;
-+
-+ /*
-+ * The size of integer values must be fixed in case the frame is
-+ * shipped to another machine.
-+ */
-+
-+ /* *************** Connected line party id *************** */
-+ if (connected->id.number) {
-+ length = strlen(connected->id.number);
-+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
-+ ast_log(LOG_WARNING, "No space left for connected line number\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_CONNECTED_LINE_NUMBER;
-+ data[pos++] = length;
-+ memcpy(data + pos, connected->id.number, length);
-+ pos += length;
-+ }
-+
-+ if (connected->id.name) {
-+ length = strlen(connected->id.name);
-+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
-+ ast_log(LOG_WARNING, "No space left for connected line name\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_CONNECTED_LINE_NAME;
-+ data[pos++] = length;
-+ memcpy(data + pos, connected->id.name, length);
-+ pos += length;
-+ }
-+
-+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
-+ ast_log(LOG_WARNING, "No space left for connected line type of number\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_CONNECTED_LINE_NUMBER_TYPE;
-+ data[pos++] = 1;
-+ data[pos++] = connected->id.number_type;
-+
-+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
-+ ast_log(LOG_WARNING, "No space left for connected line presentation\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_CONNECTED_LINE_NUMBER_PRESENTATION;
-+ data[pos++] = 1;
-+ data[pos++] = connected->id.number_presentation;
-+
-+ /* Connected line source */
-+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
-+ ast_log(LOG_WARNING, "No space left for connected line source\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_CONNECTED_LINE_SOURCE;
-+ data[pos++] = sizeof(value);
-+ value = htonl(connected->source);
-+ memcpy(data + pos, &value, sizeof(value));
-+ pos += sizeof(value);
-+
-+ return pos;
-+} /* end build_connected_line_data() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Parse connected line indication frame data
-+ *
-+ * \param data Buffer with the frame data to parse
-+ * \param datalen Size of the buffer
-+ * \param connected Extracted connected line information
-+ *
-+ * \retval 0 on success.
-+ * \retval -1 on error.
-+ *
-+ * \note The filled in connected line structure needs to be initialized by
-+ * ast_party_connected_line_set_init() before calling. If defaults are not
-+ * required use ast_party_connected_line_init().
-+ * \note The filled in connected line structure needs to be destroyed by
-+ * ast_party_connected_line_free() when it is no longer needed.
-+ */
-+int ast_parse_connected_line_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
-+{
-+ size_t pos;
-+ unsigned char ie_len;
-+ unsigned char ie_id;
-+ int32_t value;
-+
-+ for (pos = 0; pos < datalen; pos += ie_len) {
-+ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
-+ ast_log(LOG_WARNING, "Invalid connected line update\n");
-+ return -1;
-+ }
-+ ie_id = data[pos++];
-+ ie_len = data[pos++];
-+ if (datalen < pos + ie_len) {
-+ ast_log(LOG_WARNING, "Invalid connected line update\n");
-+ return -1;
-+ }
-+
-+ switch (ie_id) {
-+ case AST_CONNECTED_LINE_NUMBER:
-+ if (connected->id.number) {
-+ ast_free(connected->id.number);
-+ }
-+ connected->id.number = ast_malloc(ie_len + 1);
-+ if (connected->id.number) {
-+ memcpy(connected->id.number, data + pos, ie_len);
-+ connected->id.number[ie_len] = 0;
-+ }
-+ break;
-+ case AST_CONNECTED_LINE_NAME:
-+ if (connected->id.name) {
-+ ast_free(connected->id.name);
-+ }
-+ connected->id.name = ast_malloc(ie_len + 1);
-+ if (connected->id.name) {
-+ memcpy(connected->id.name, data + pos, ie_len);
-+ connected->id.name[ie_len] = 0;
-+ }
-+ break;
-+ case AST_CONNECTED_LINE_NUMBER_TYPE:
-+ if (ie_len != 1) {
-+ ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ connected->id.number_type = data[pos];
-+ break;
-+ case AST_CONNECTED_LINE_NUMBER_PRESENTATION:
-+ if (ie_len != 1) {
-+ ast_log(LOG_WARNING, "Invalid connected line presentation (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ connected->id.number_presentation = data[pos];
-+ break;
-+ case AST_CONNECTED_LINE_SOURCE:
-+ if (ie_len != sizeof(value)) {
-+ ast_log(LOG_WARNING, "Invalid connected line source (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ memcpy(&value, data + pos, sizeof(value));
-+ connected->source = ntohl(value);
-+ break;
-+ default:
-+ ast_log(LOG_DEBUG, "Unknown connected line element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
-+ break;
-+ } /* end switch */
-+ } /* end for */
-+
-+ return 0;
-+} /* end ast_parse_connected_line_data() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Indicate that the connected line information has changed
-+ *
-+ * \param chan Asterisk channel to indicate connected line information
-+ * \param connected Connected line information
-+ *
-+ * \return Nothing
-+ */
-+void ast_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected)
-+{
-+ unsigned char data[1024]; /* This should be large enough */
-+ size_t datalen;
-+
-+ datalen = build_connected_line_data(data, sizeof(data), connected);
-+ if (datalen == (size_t) -1) {
-+ return;
-+ }
-+
-+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
-+} /* end ast_connected_line_update() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Queue a connected line update frame on a channel
-+ *
-+ * \param chan Asterisk channel to indicate connected line information
-+ * \param connected Connected line information
-+ *
-+ * \return Nothing
-+ */
-+void ast_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected)
-+{
-+ unsigned char data[1024]; /* This should be large enough */
-+ size_t datalen;
-+
-+ datalen = build_connected_line_data(data, sizeof(data), connected);
-+ if (datalen == (size_t) -1) {
-+ return;
-+ }
-+
-+ ast_queue_control_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
-+} /* end ast_queue_connected_line_update() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Set the redirecting id information in the Asterisk channel
-+ *
-+ * \param chan Asterisk channel to set redirecting id information
-+ * \param redirecting Redirecting id information
-+ *
-+ * \return Nothing
-+ *
-+ * \note The channel does not need to be locked before calling this function.
-+ */
-+void ast_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
-+{
-+ if (&chan->redirecting == redirecting) {
-+ /* Don't set to self */
-+ return;
-+ }
-+
-+ ast_channel_lock(chan);
-+
-+ ast_party_id_set(&chan->redirecting.from, &redirecting->from);
-+ if (redirecting->from.number
-+ && redirecting->from.number != chan->redirecting.from.number) {
-+ /*
-+ * Must move string to ast_channel.cid.cid_rdnis until it goes away.
-+ */
-+ if (chan->cid.cid_rdnis) {
-+ ast_free(chan->cid.cid_rdnis);
-+ }
-+ chan->cid.cid_rdnis = chan->redirecting.from.number;
-+ chan->redirecting.from.number = NULL;
-+ }
-+
-+ ast_party_id_set(&chan->redirecting.to, &redirecting->to);
-+ chan->redirecting.reason = redirecting->reason;
-+ chan->redirecting.count = redirecting->count;
-+
-+ ast_channel_unlock(chan);
-+} /* end ast_set_redirecting() */
-+
-+
-+
-+
-+/*!
-+ * \brief Element identifiers for redirecting indication frame data
-+ * \note Only add to the end of this enum.
-+ */
-+enum {
-+ AST_REDIRECTING_FROM_NUMBER,
-+ AST_REDIRECTING_FROM_NAME,
-+ AST_REDIRECTING_FROM_NUMBER_TYPE,
-+ AST_REDIRECTING_FROM_NUMBER_PRESENTATION,
-+ AST_REDIRECTING_TO_NUMBER,
-+ AST_REDIRECTING_TO_NAME,
-+ AST_REDIRECTING_TO_NUMBER_TYPE,
-+ AST_REDIRECTING_TO_NUMBER_PRESENTATION,
-+ AST_REDIRECTING_REASON,
-+ AST_REDIRECTING_COUNT
-+};
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \internal
-+ * \brief Build the redirecting id data frame.
-+ *
-+ * \param data Buffer to fill with the frame data
-+ * \param datalen Size of the buffer to fill
-+ * \param redirecting Redirecting id information
-+ *
-+ * \retval -1 if error
-+ * \retval Amount of data buffer used
-+ */
-+static int build_redirecting_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting)
-+{
-+ int32_t value;
-+ size_t length;
-+ size_t pos = 0;
-+
-+ /*
-+ * The size of integer values must be fixed in case the frame is
-+ * shipped to another machine.
-+ */
-+
-+ /* *************** Redirecting from party id *************** */
-+ if (redirecting->from.number) {
-+ length = strlen(redirecting->from.number);
-+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
-+ ast_log(LOG_WARNING, "No space left for redirecting from number\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_FROM_NUMBER;
-+ data[pos++] = length;
-+ memcpy(data + pos, redirecting->from.number, length);
-+ pos += length;
-+ }
-+
-+ if (redirecting->from.name) {
-+ length = strlen(redirecting->from.name);
-+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
-+ ast_log(LOG_WARNING, "No space left for redirecting from name\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_FROM_NAME;
-+ data[pos++] = length;
-+ memcpy(data + pos, redirecting->from.name, length);
-+ pos += length;
-+ }
-+
-+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
-+ ast_log(LOG_WARNING, "No space left for redirecting from type of number\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_FROM_NUMBER_TYPE;
-+ data[pos++] = 1;
-+ data[pos++] = redirecting->from.number_type;
-+
-+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
-+ ast_log(LOG_WARNING, "No space left for redirecting from presentation\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_FROM_NUMBER_PRESENTATION;
-+ data[pos++] = 1;
-+ data[pos++] = redirecting->from.number_presentation;
-+
-+ /* *************** Redirecting to party id *************** */
-+ if (redirecting->to.number) {
-+ length = strlen(redirecting->to.number);
-+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
-+ ast_log(LOG_WARNING, "No space left for redirecting to number\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_TO_NUMBER;
-+ data[pos++] = length;
-+ memcpy(data + pos, redirecting->to.number, length);
-+ pos += length;
-+ }
-+
-+ if (redirecting->to.name) {
-+ length = strlen(redirecting->to.name);
-+ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
-+ ast_log(LOG_WARNING, "No space left for redirecting to name\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_TO_NAME;
-+ data[pos++] = length;
-+ memcpy(data + pos, redirecting->to.name, length);
-+ pos += length;
-+ }
-+
-+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
-+ ast_log(LOG_WARNING, "No space left for redirecting to type of number\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_TO_NUMBER_TYPE;
-+ data[pos++] = 1;
-+ data[pos++] = redirecting->to.number_type;
-+
-+ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
-+ ast_log(LOG_WARNING, "No space left for redirecting to presentation\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_TO_NUMBER_PRESENTATION;
-+ data[pos++] = 1;
-+ data[pos++] = redirecting->to.number_presentation;
-+
-+ /* Redirecting reason */
-+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
-+ ast_log(LOG_WARNING, "No space left for redirecting reason\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_REASON;
-+ data[pos++] = sizeof(value);
-+ value = htonl(redirecting->reason);
-+ memcpy(data + pos, &value, sizeof(value));
-+ pos += sizeof(value);
-+
-+ /* Redirecting count */
-+ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
-+ ast_log(LOG_WARNING, "No space left for redirecting count\n");
-+ return -1;
-+ }
-+ data[pos++] = AST_REDIRECTING_COUNT;
-+ data[pos++] = sizeof(value);
-+ value = htonl(redirecting->count);
-+ memcpy(data + pos, &value, sizeof(value));
-+ pos += sizeof(value);
-+
-+ return pos;
-+} /* end build_redirecting_data() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Parse redirecting indication frame data
-+ *
-+ * \param data Buffer with the frame data to parse
-+ * \param datalen Size of the buffer
-+ * \param redirecting Extracted redirecting id information
-+ *
-+ * \retval 0 on success.
-+ * \retval -1 on error.
-+ *
-+ * \note The filled in id structure needs to be initialized by
-+ * ast_party_redirecting_set_init() before calling.
-+ * \note The filled in id structure needs to be destroyed by
-+ * ast_party_redirecting_free() when it is no longer needed.
-+ */
-+int ast_parse_redirecting_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting)
-+{
-+ size_t pos;
-+ unsigned char ie_len;
-+ unsigned char ie_id;
-+ int32_t value;
-+
-+ for (pos = 0; pos < datalen; pos += ie_len) {
-+ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
-+ ast_log(LOG_WARNING, "Invalid redirecting update\n");
-+ return -1;
-+ }
-+ ie_id = data[pos++];
-+ ie_len = data[pos++];
-+ if (datalen < pos + ie_len) {
-+ ast_log(LOG_WARNING, "Invalid redirecting update\n");
-+ return -1;
-+ }
-+
-+ switch (ie_id) {
-+ case AST_REDIRECTING_FROM_NUMBER:
-+ if (redirecting->from.number) {
-+ ast_free(redirecting->from.number);
-+ }
-+ redirecting->from.number = ast_malloc(ie_len + 1);
-+ if (redirecting->from.number) {
-+ memcpy(redirecting->from.number, data + pos, ie_len);
-+ redirecting->from.number[ie_len] = 0;
-+ }
-+ break;
-+ case AST_REDIRECTING_FROM_NAME:
-+ if (redirecting->from.name) {
-+ ast_free(redirecting->from.name);
-+ }
-+ redirecting->from.name = ast_malloc(ie_len + 1);
-+ if (redirecting->from.name) {
-+ memcpy(redirecting->from.name, data + pos, ie_len);
-+ redirecting->from.name[ie_len] = 0;
-+ }
-+ break;
-+ case AST_REDIRECTING_FROM_NUMBER_TYPE:
-+ if (ie_len != 1) {
-+ ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ redirecting->from.number_type = data[pos];
-+ break;
-+ case AST_REDIRECTING_FROM_NUMBER_PRESENTATION:
-+ if (ie_len != 1) {
-+ ast_log(LOG_WARNING, "Invalid redirecting from presentation (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ redirecting->from.number_presentation = data[pos];
-+ break;
-+ case AST_REDIRECTING_TO_NUMBER:
-+ if (redirecting->to.number) {
-+ ast_free(redirecting->to.number);
-+ }
-+ redirecting->to.number = ast_malloc(ie_len + 1);
-+ if (redirecting->to.number) {
-+ memcpy(redirecting->to.number, data + pos, ie_len);
-+ redirecting->to.number[ie_len] = 0;
-+ }
-+ break;
-+ case AST_REDIRECTING_TO_NAME:
-+ if (redirecting->to.name) {
-+ ast_free(redirecting->to.name);
-+ }
-+ redirecting->to.name = ast_malloc(ie_len + 1);
-+ if (redirecting->to.name) {
-+ memcpy(redirecting->to.name, data + pos, ie_len);
-+ redirecting->to.name[ie_len] = 0;
-+ }
-+ break;
-+ case AST_REDIRECTING_TO_NUMBER_TYPE:
-+ if (ie_len != 1) {
-+ ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ redirecting->to.number_type = data[pos];
-+ break;
-+ case AST_REDIRECTING_TO_NUMBER_PRESENTATION:
-+ if (ie_len != 1) {
-+ ast_log(LOG_WARNING, "Invalid redirecting to presentation (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ redirecting->to.number_presentation = data[pos];
-+ break;
-+ case AST_REDIRECTING_REASON:
-+ if (ie_len != sizeof(value)) {
-+ ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ memcpy(&value, data + pos, sizeof(value));
-+ redirecting->reason = ntohl(value);
-+ break;
-+ case AST_REDIRECTING_COUNT:
-+ if (ie_len != sizeof(value)) {
-+ ast_log(LOG_WARNING, "Invalid redirecting count (%u)\n", (unsigned) ie_len);
-+ break;
-+ }
-+ memcpy(&value, data + pos, sizeof(value));
-+ redirecting->count = ntohl(value);
-+ break;
-+ default:
-+ ast_log(LOG_DEBUG, "Unknown redirecting element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
-+ break;
-+ } /* end switch */
-+ } /* end for */
-+
-+ return 0;
-+} /* end ast_parse_redirecting_data() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Indicate that the redirecting id has changed
-+ *
-+ * \param chan Asterisk channel to indicate redirecting id information
-+ * \param redirecting Redirecting id information
-+ *
-+ * \return Nothing
-+ */
-+void ast_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
-+{
-+ unsigned char data[1024]; /* This should be large enough */
-+ size_t datalen;
-+
-+ datalen = build_redirecting_data(data, sizeof(data), redirecting);
-+ if (datalen == (size_t) -1) {
-+ return;
-+ }
-+
-+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
-+} /* end ast_redirecting_update() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Queue a redirecting update frame on a channel
-+ *
-+ * \param chan Asterisk channel to indicate redirecting id information
-+ * \param redirecting Redirecting id information
-+ *
-+ * \return Nothing
-+ */
-+void ast_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
-+{
-+ unsigned char data[1024]; /* This should be large enough */
-+ size_t datalen;
-+
-+ datalen = build_redirecting_data(data, sizeof(data), redirecting);
-+ if (datalen == (size_t) -1) {
-+ return;
-+ }
-+
-+ ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
-+} /* end ast_queue_redirecting_update() */
-+
-Index: main/manager.c
-===================================================================
---- a/main/manager.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/manager.c (.../team/group/issue14292) (revision 178988)
-@@ -149,7 +149,39 @@
- {{ "restart", "gracefully", NULL }},
- };
-
--struct mansession {
-+/* In order to understand what the heck is going on with the
-+ * mansession_session and mansession structs, we need to have a bit of a history
-+ * lesson.
-+ *
-+ * In the beginning, there was the mansession. The mansession contained data that was
-+ * intrinsic to a manager session, such as the time that it started, the name of the logged-in
-+ * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
-+ * sessions, these were used to represent the TCP socket over which the AMI session was taking
-+ * place. It makes perfect sense for these fields to be a part of the session-specific data since
-+ * the session actually defines this information.
-+ *
-+ * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
-+ * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
-+ * but rather to the action that is being executed. Because a single session may execute many commands
-+ * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
-+ * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
-+ * has had a chance to properly close its handles.
-+ *
-+ * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
-+ * from being run at the same time in a single session. Some manager actions may block for a long time, thus
-+ * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
-+ * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
-+ * part of the action instead.
-+ *
-+ * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
-+ * contain the action-specific information, such as which file to write to. In order to maintain expectations
-+ * of action handlers and not have to change the public API of the manager code, we would need to name this
-+ * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
-+ * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
-+ * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
-+ * data.
-+ */
-+struct mansession_session {
- pthread_t ms_t; /*!< Execution thread, basically useless */
- ast_mutex_t __lock; /*!< Thread lock -- don't use in action callbacks, it's already taken care of */
- /* XXX need to document which fields it is protecting */
-@@ -175,13 +207,24 @@
- int writetimeout; /*!< Timeout for ast_carefulwrite() */
- int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
- AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
-- AST_LIST_ENTRY(mansession) list;
-+ AST_LIST_ENTRY(mansession_session) list;
- };
-
--#define NEW_EVENT(m) (AST_LIST_NEXT(m->last_ev, eq_next))
-+/* In case you didn't read that giant block of text above the mansession_session struct, the
-+ * 'mansession' struct is named this solely to keep the API the same in Asterisk. This structure really
-+ * represents data that is different from Manager action to Manager action. The mansession_session pointer
-+ * contained within points to session-specific data.
-+ */
-+struct mansession {
-+ struct mansession_session *session;
-+ FILE *f;
-+ int fd;
-+};
-
--static AST_LIST_HEAD_STATIC(sessions, mansession);
-+#define NEW_EVENT(m) (AST_LIST_NEXT(m->session->last_ev, eq_next))
-
-+static AST_LIST_HEAD_STATIC(sessions, mansession_session);
-+
- /*! \brief user descriptor, as read from the config file.
- *
- * \note It is still missing some fields -- e.g. we can have multiple permit and deny
-@@ -348,7 +391,7 @@
- int i;
- char *sep = "";
-
-- (*res)->used = 0;
-+ ast_str_reset(*res);
- for (i = 0; i < ARRAY_LEN(perms) - 1; i++) {
- if (authority & perms[i].num) {
- ast_str_append(res, 0, "%s%s", sep, perms[i].label);
-@@ -356,10 +399,10 @@
- }
- }
-
-- if ((*res)->used == 0) /* replace empty string with something sensible */
-+ if (ast_str_strlen(*res) == 0) /* replace empty string with something sensible */
- ast_str_append(res, 0, "<none>");
-
-- return (*res)->str;
-+ return ast_str_buffer(*res);
- }
-
- /*! Tells you if smallstr exists inside bigstr
-@@ -428,7 +471,7 @@
-
- static int check_manager_session_inuse(const char *name)
- {
-- struct mansession *session = NULL;
-+ struct mansession_session *session = NULL;
-
- AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE(&sessions, session, list) {
-@@ -459,13 +502,13 @@
- * \param s manager session to get parameter from.
- * \return displayconnects config option value.
- */
--static int manager_displayconnects (struct mansession *s)
-+static int manager_displayconnects (struct mansession_session *session)
- {
- struct ast_manager_user *user = NULL;
- int ret = 0;
-
- AST_RWLIST_RDLOCK(&users);
-- if ((user = get_manager_by_name_locked (s->username)))
-+ if ((user = get_manager_by_name_locked (session->username)))
- ret = user->displayconnects;
- AST_RWLIST_UNLOCK(&users);
-
-@@ -522,18 +565,18 @@
- {
- switch (cmd) {
- case CLI_INIT:
-- e->command = "manager debug [on|off]";
-- e->usage = "Usage: manager debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
-+ e->command = "manager set debug [on|off]";
-+ e->usage = "Usage: manager set debug [on|off]\n Show, enable, disable debugging of the manager code.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-- if (a->argc == 2)
-+ if (a->argc == 3)
- ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
-- else if (a->argc == 3) {
-- if (!strcasecmp(a->argv[2], "on"))
-+ else if (a->argc == 4) {
-+ if (!strcasecmp(a->argv[3], "on"))
- manager_debug = 1;
-- else if (!strcasecmp(a->argv[2], "off"))
-+ else if (!strcasecmp(a->argv[3], "off"))
- manager_debug = 0;
- else
- return CLI_SHOWUSAGE;
-@@ -678,7 +721,7 @@
- /*! \brief CLI command manager list connected */
- static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
-- struct mansession *s;
-+ struct mansession_session *session;
- time_t now = time(NULL);
- #define HSMCONN_FORMAT1 " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
- #define HSMCONN_FORMAT2 " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
-@@ -698,8 +741,8 @@
- ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
-
- AST_LIST_LOCK(&sessions);
-- AST_LIST_TRAVERSE(&sessions, s, list) {
-- ast_cli(a->fd, HSMCONN_FORMAT2, s->username, ast_inet_ntoa(s->sin.sin_addr), (int)(s->sessionstart), (int)(now - s->sessionstart), s->fd, s->inuse, s->readperm, s->writeperm);
-+ AST_LIST_TRAVERSE(&sessions, session, list) {
-+ ast_cli(a->fd, HSMCONN_FORMAT2, session->username, ast_inet_ntoa(session->sin.sin_addr), (int)(session->sessionstart), (int)(now - session->sessionstart), session->fd, session->inuse, session->readperm, session->writeperm);
- count++;
- }
- AST_LIST_UNLOCK(&sessions);
-@@ -787,30 +830,30 @@
- /*
- * destroy a session, leaving the usecount
- */
--static void free_session(struct mansession *s)
-+static void free_session(struct mansession_session *session)
- {
-- struct eventqent *eqe = s->last_ev;
-+ struct eventqent *eqe = session->last_ev;
- struct ast_datastore *datastore;
-
- /* Get rid of each of the data stores on the session */
-- while ((datastore = AST_LIST_REMOVE_HEAD(&s->datastores, entry))) {
-+ while ((datastore = AST_LIST_REMOVE_HEAD(&session->datastores, entry))) {
- /* Free the data store */
- ast_datastore_free(datastore);
- }
-
-- if (s->f != NULL)
-- fclose(s->f);
-- ast_mutex_destroy(&s->__lock);
-- ast_free(s);
-+ if (session->f != NULL)
-+ fclose(session->f);
-+ ast_mutex_destroy(&session->__lock);
-+ ast_free(session);
- unref_event(eqe);
- }
-
--static void destroy_session(struct mansession *s)
-+static void destroy_session(struct mansession_session *session)
- {
- AST_LIST_LOCK(&sessions);
-- AST_LIST_REMOVE(&sessions, s, list);
-+ AST_LIST_REMOVE(&sessions, session, list);
- ast_atomic_fetchadd_int(&num_sessions, -1);
-- free_session(s);
-+ free_session(session);
- AST_LIST_UNLOCK(&sessions);
- }
-
-@@ -899,7 +942,11 @@
- */
- static int send_string(struct mansession *s, char *string)
- {
-- return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->writetimeout);
-+ if (s->f) {
-+ return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->session->writetimeout);
-+ } else {
-+ return ast_careful_fwrite(s->session->f, s->session->fd, string, strlen(string), s->session->writetimeout);
-+ }
- }
-
- /*!
-@@ -930,15 +977,16 @@
- ast_str_set_va(&buf, 0, fmt, ap);
- va_end(ap);
-
-- if (s->f != NULL)
-- send_string(s, buf->str);
-- else
-+ if (s->f != NULL || s->session->f != NULL) {
-+ send_string(s, ast_str_buffer(buf));
-+ } else {
- ast_verbose("fd == -1 in astman_append, should not happen\n");
-+ }
- }
-
- /*! \note NOTE: XXX this comment is unclear and possibly wrong.
- Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
-- hold the session lock _or_ be running in an action callback (in which case s->busy will
-+ hold the session lock _or_ be running in an action callback (in which case s->session->busy will
- be non-zero). In either of these cases, there is no need to lock-protect the session's
- fd, since no other output will be sent (events will be queued), and no input will
- be read until either the current action finishes or get_input() obtains the session
-@@ -1004,10 +1052,10 @@
- {
- int maskint = strings_to_mask(eventmask);
-
-- ast_mutex_lock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
- if (maskint >= 0)
-- s->send_events = maskint;
-- ast_mutex_unlock(&s->__lock);
-+ s->session->send_events = maskint;
-+ ast_mutex_unlock(&s->session->__lock);
-
- return maskint;
- }
-@@ -1033,12 +1081,12 @@
- AST_RWLIST_WRLOCK(&users);
-
- if (!(user = get_manager_by_name_locked(username))) {
-- ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
-- } else if (user->ha && !ast_apply_ha(user->ha, &(s->sin))) {
-- ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
-+ ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
-+ } else if (user->ha && !ast_apply_ha(user->ha, &(s->session->sin))) {
-+ ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
- } else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
- const char *key = astman_get_header(m, "Key");
-- if (!ast_strlen_zero(key) && !ast_strlen_zero(s->challenge) && user->secret) {
-+ if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
- int x;
- int len = 0;
- char md5key[256] = "";
-@@ -1046,7 +1094,7 @@
- unsigned char digest[16];
-
- MD5Init(&md5);
-- MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
-+ MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
- MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
- MD5Final(digest, &md5);
- for (x = 0; x < 16; x++)
-@@ -1055,24 +1103,24 @@
- error = 0;
- } else {
- ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
-- S_OR(s->challenge, ""));
-+ S_OR(s->session->challenge, ""));
- }
- } else if (password && user->secret && !strcmp(password, user->secret))
- error = 0;
-
- if (error) {
-- ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
-+ ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
- AST_RWLIST_UNLOCK(&users);
- return -1;
- }
-
- /* auth complete */
-
-- ast_copy_string(s->username, username, sizeof(s->username));
-- s->readperm = user->readperm;
-- s->writeperm = user->writeperm;
-- s->writetimeout = user->writetimeout;
-- s->sessionstart = time(NULL);
-+ ast_copy_string(s->session->username, username, sizeof(s->session->username));
-+ s->session->readperm = user->readperm;
-+ s->session->writeperm = user->writeperm;
-+ s->session->writetimeout = user->writetimeout;
-+ s->session->sessionstart = time(NULL);
- set_eventmask(s, astman_get_header(m, "Events"));
-
- AST_RWLIST_UNLOCK(&users);
-@@ -1087,9 +1135,13 @@
-
- static int action_ping(struct mansession *s, const struct message *m)
- {
-- astman_append(s, "Response: Success\r\n"
-- "Ping: Pong\r\n"
-- "\r\n");
-+ const char *actionid = astman_get_header(m, "ActionID");
-+
-+ astman_append(s, "Response: Success\r\n");
-+ if (!ast_strlen_zero(actionid)){
-+ astman_append(s, "ActionID: %s\r\n", actionid);
-+ }
-+ astman_append(s, "Ping: Pong\r\n\r\n");
- return 0;
- }
-
-@@ -1115,7 +1167,8 @@
- astman_send_error(s, m, "Filename not specified");
- return 0;
- }
-- if (!(cfg = ast_config_load2(fn, "manager", config_flags))) {
-+ cfg = ast_config_load2(fn, "manager", config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- astman_send_error(s, m, "Config file not found");
- return 0;
- }
-@@ -1274,7 +1327,7 @@
- snprintf(hdr, sizeof(hdr), "Action-%06d", x);
- action = astman_get_header(m, hdr);
- if (ast_strlen_zero(action)) /* breaks the for loop if no action header */
-- break; /* this could cause problems if actions come in misnumbered */
-+ break; /* this could cause problems if actions come in misnumbered */
-
- snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
- cat = astman_get_header(m, hdr);
-@@ -1436,7 +1489,7 @@
- result = handle_updates(s, m, cfg, dfn);
- if (!result) {
- ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
-- res = config_text_file_save(dfn, cfg, "Manager");
-+ res = ast_config_text_file_save(dfn, cfg, "Manager");
- ast_config_destroy(cfg);
- if (res) {
- astman_send_error(s, m, "Save of config failed");
-@@ -1504,11 +1557,12 @@
- ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
- ast_str_append(&filepath, 0, "%s", fn);
-
-- if ((fd = open(filepath->str, O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
-+ if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
- close(fd);
- astman_send_ack(s, m, "New configuration file created successfully");
-- } else
-+ } else {
- astman_send_error(s, m, strerror(errno));
-+ }
-
- return 0;
- }
-@@ -1542,76 +1596,76 @@
- /* XXX maybe put an upper bound, or prevent the use of 0 ? */
- }
-
-- ast_mutex_lock(&s->__lock);
-- if (s->waiting_thread != AST_PTHREADT_NULL)
-- pthread_kill(s->waiting_thread, SIGURG);
-+ ast_mutex_lock(&s->session->__lock);
-+ if (s->session->waiting_thread != AST_PTHREADT_NULL)
-+ pthread_kill(s->session->waiting_thread, SIGURG);
-
-- if (s->managerid) { /* AMI-over-HTTP session */
-+ if (s->session->managerid) { /* AMI-over-HTTP session */
- /*
- * Make sure the timeout is within the expire time of the session,
- * as the client will likely abort the request if it does not see
- * data coming after some amount of time.
- */
- time_t now = time(NULL);
-- int max = s->sessiontimeout - now - 10;
-+ int max = s->session->sessiontimeout - now - 10;
-
- if (max < 0) /* We are already late. Strange but possible. */
- max = 0;
- if (timeout < 0 || timeout > max)
- timeout = max;
-- if (!s->send_events) /* make sure we record events */
-- s->send_events = -1;
-+ if (!s->session->send_events) /* make sure we record events */
-+ s->session->send_events = -1;
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
-
- /* XXX should this go inside the lock ? */
-- s->waiting_thread = pthread_self(); /* let new events wake up this thread */
-+ s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
- ast_debug(1, "Starting waiting for an event!\n");
-
- for (x = 0; x < timeout || timeout < 0; x++) {
-- ast_mutex_lock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
- if (NEW_EVENT(s))
- needexit = 1;
- /* We can have multiple HTTP session point to the same mansession entry.
- * The way we deal with it is not very nice: newcomers kick out the previous
- * HTTP session. XXX this needs to be improved.
- */
-- if (s->waiting_thread != pthread_self())
-+ if (s->session->waiting_thread != pthread_self())
- needexit = 1;
-- if (s->needdestroy)
-+ if (s->session->needdestroy)
- needexit = 1;
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- if (needexit)
- break;
-- if (s->managerid == 0) { /* AMI session */
-- if (ast_wait_for_input(s->fd, 1000))
-+ if (s->session->managerid == 0) { /* AMI session */
-+ if (ast_wait_for_input(s->session->fd, 1000))
- break;
- } else { /* HTTP session */
- sleep(1);
- }
- }
- ast_debug(1, "Finished waiting for an event!\n");
-- ast_mutex_lock(&s->__lock);
-- if (s->waiting_thread == pthread_self()) {
-+ ast_mutex_lock(&s->session->__lock);
-+ if (s->session->waiting_thread == pthread_self()) {
- struct eventqent *eqe;
- astman_send_response(s, m, "Success", "Waiting for Event completed.");
- while ( (eqe = NEW_EVENT(s)) ) {
- ref_event(eqe);
-- if (((s->readperm & eqe->category) == eqe->category) &&
-- ((s->send_events & eqe->category) == eqe->category)) {
-+ if (((s->session->readperm & eqe->category) == eqe->category) &&
-+ ((s->session->send_events & eqe->category) == eqe->category)) {
- astman_append(s, "%s", eqe->eventdata);
- }
-- s->last_ev = unref_event(s->last_ev);
-+ s->session->last_ev = unref_event(s->session->last_ev);
- }
- astman_append(s,
- "Event: WaitEventComplete\r\n"
- "%s"
- "\r\n", idText);
-- s->waiting_thread = AST_PTHREADT_NULL;
-+ s->session->waiting_thread = AST_PTHREADT_NULL;
- } else {
- ast_debug(1, "Abandoning event request!\n");
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- return 0;
- }
-
-@@ -1628,7 +1682,7 @@
-
- astman_start_ack(s, m);
- AST_RWLIST_TRAVERSE(&actions, cur, list) {
-- if (s->writeperm & cur->authority || cur->authority == 0)
-+ if (s->session->writeperm & cur->authority || cur->authority == 0)
- astman_append(s, "%s: %s (Priv: %s)\r\n",
- cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
- }
-@@ -1677,10 +1731,10 @@
- astman_send_error(s, m, "Authentication failed");
- return -1;
- }
-- s->authenticated = 1;
-- if (manager_displayconnects(s))
-- ast_verb(2, "%sManager '%s' logged on from %s\n", (s->managerid ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
-- ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->managerid ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
-+ s->session->authenticated = 1;
-+ if (manager_displayconnects(s->session))
-+ ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
-+ ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
- astman_send_ack(s, m, "Authentication accepted");
- return 0;
- }
-@@ -1690,12 +1744,12 @@
- const char *authtype = astman_get_header(m, "AuthType");
-
- if (!strcasecmp(authtype, "MD5")) {
-- if (ast_strlen_zero(s->challenge))
-- snprintf(s->challenge, sizeof(s->challenge), "%ld", ast_random());
-- ast_mutex_lock(&s->__lock);
-+ if (ast_strlen_zero(s->session->challenge))
-+ snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
-+ ast_mutex_lock(&s->session->__lock);
- astman_start_ack(s, m);
-- astman_append(s, "Challenge: %s\r\n\r\n", s->challenge);
-- ast_mutex_unlock(&s->__lock);
-+ astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
-+ ast_mutex_unlock(&s->session->__lock);
- } else {
- astman_send_error(s, m, "Must specify AuthType");
- }
-@@ -1855,6 +1909,7 @@
- c = ast_get_channel_by_name_locked(name);
- if (!c) {
- astman_send_error(s, m, "No such channel");
-+ ast_free(str);
- return 0;
- }
- }
-@@ -1918,7 +1973,7 @@
- c->accountcode,
- c->_state,
- ast_state2str(c->_state), c->context,
-- c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, str->str, idText);
-+ c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
- } else {
- astman_append(s,
- "Event: Status\r\n"
-@@ -1937,7 +1992,7 @@
- S_OR(c->cid.cid_num, "<unknown>"),
- S_OR(c->cid.cid_name, "<unknown>"),
- c->accountcode,
-- ast_state2str(c->_state), bridge, c->uniqueid, str->str, idText);
-+ ast_state2str(c->_state), bridge, c->uniqueid, ast_str_buffer(str), idText);
- }
- ast_channel_unlock(c);
- if (!all)
-@@ -2404,7 +2459,7 @@
- }
- } else if (!ast_strlen_zero(app)) {
- /* To run the System application (or anything else that goes to shell), you must have the additional System privilege */
-- if (!(s->writeperm & EVENT_FLAG_SYSTEM)
-+ if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
- && (
- strcasestr(app, "system") == 0 || /* System(rm -rf /)
- TrySystem(rm -rf /) */
-@@ -2576,22 +2631,22 @@
- {
- int ret = 0;
-
-- ast_mutex_lock(&s->__lock);
-- if (s->f != NULL) {
-+ ast_mutex_lock(&s->session->__lock);
-+ if (s->session->f != NULL) {
- struct eventqent *eqe;
-
- while ( (eqe = NEW_EVENT(s)) ) {
- ref_event(eqe);
-- if (!ret && s->authenticated &&
-- (s->readperm & eqe->category) == eqe->category &&
-- (s->send_events & eqe->category) == eqe->category) {
-+ if (!ret && s->session->authenticated &&
-+ (s->session->readperm & eqe->category) == eqe->category &&
-+ (s->session->send_events & eqe->category) == eqe->category) {
- if (send_string(s, eqe->eventdata) < 0)
- ret = -1; /* don't send more */
- }
-- s->last_ev = unref_event(s->last_ev);
-+ s->session->last_ev = unref_event(s->session->last_ev);
- }
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- return ret;
- }
-
-@@ -2613,7 +2668,7 @@
- }
- }
-
-- manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body->str);
-+ manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, ast_str_buffer(body));
- return 0;
- }
-
-@@ -2916,26 +2971,26 @@
- ast_debug(1, "Manager received command '%s'\n", action);
-
- if (ast_strlen_zero(action)) {
-- ast_mutex_lock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
- astman_send_error(s, m, "Missing action in request");
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- return 0;
- }
-
-- if (!s->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
-- ast_mutex_lock(&s->__lock);
-+ if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
-+ ast_mutex_lock(&s->session->__lock);
- astman_send_error(s, m, "Permission denied");
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- return 0;
- }
-
-- if (!allowmultiplelogin && !s->authenticated && user &&
-+ if (!allowmultiplelogin && !s->session->authenticated && user &&
- (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
- if (check_manager_session_inuse(user)) {
- sleep(1);
-- ast_mutex_lock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
- astman_send_error(s, m, "Login Already In Use");
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- return -1;
- }
- }
-@@ -2944,7 +2999,7 @@
- AST_RWLIST_TRAVERSE(&actions, tmp, list) {
- if (strcasecmp(action, tmp->action))
- continue;
-- if (s->writeperm & tmp->authority || tmp->authority == 0)
-+ if (s->session->writeperm & tmp->authority || tmp->authority == 0)
- ret = tmp->func(s, m);
- else
- astman_send_error(s, m, "Permission denied");
-@@ -2955,14 +3010,20 @@
- if (!tmp) {
- char buf[512];
- snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
-- ast_mutex_lock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
- astman_send_error(s, m, buf);
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- }
- if (ret)
- return ret;
-- /* Once done with our message, deliver any pending events */
-- return process_events(s);
-+ /* Once done with our message, deliver any pending events unless the
-+ requester doesn't want them as part of this response.
-+ */
-+ if (ast_strlen_zero(astman_get_header(m, "SuppressEvents"))) {
-+ return process_events(s);
-+ } else {
-+ return ret;
-+ }
- }
-
- /*!
-@@ -2977,16 +3038,16 @@
- static int get_input(struct mansession *s, char *output)
- {
- int res, x;
-- int maxlen = sizeof(s->inbuf) - 1;
-- char *src = s->inbuf;
-+ int maxlen = sizeof(s->session->inbuf) - 1;
-+ char *src = s->session->inbuf;
-
- /*
- * Look for \r\n within the buffer. If found, copy to the output
- * buffer and return, trimming the \r\n (not used afterwards).
- */
-- for (x = 0; x < s->inlen; x++) {
-+ for (x = 0; x < s->session->inlen; x++) {
- int cr; /* set if we have \r */
-- if (src[x] == '\r' && x+1 < s->inlen && src[x+1] == '\n')
-+ if (src[x] == '\r' && x+1 < s->session->inlen && src[x+1] == '\n')
- cr = 2; /* Found. Update length to include \r\n */
- else if (src[x] == '\n')
- cr = 1; /* also accept \n only */
-@@ -2995,32 +3056,32 @@
- memmove(output, src, x); /*... but trim \r\n */
- output[x] = '\0'; /* terminate the string */
- x += cr; /* number of bytes used */
-- s->inlen -= x; /* remaining size */
-- memmove(src, src + x, s->inlen); /* remove used bytes */
-+ s->session->inlen -= x; /* remaining size */
-+ memmove(src, src + x, s->session->inlen); /* remove used bytes */
- return 1;
- }
-- if (s->inlen >= maxlen) {
-+ if (s->session->inlen >= maxlen) {
- /* no crlf found, and buffer full - sorry, too long for us */
-- ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), src);
-- s->inlen = 0;
-+ ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->session->sin.sin_addr), src);
-+ s->session->inlen = 0;
- }
- res = 0;
- while (res == 0) {
- /* XXX do we really need this locking ? */
-- ast_mutex_lock(&s->__lock);
-- if (s->pending_event) {
-- s->pending_event = 0;
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
-+ if (s->session->pending_event) {
-+ s->session->pending_event = 0;
-+ ast_mutex_unlock(&s->session->__lock);
- return 0;
- }
-- s->waiting_thread = pthread_self();
-- ast_mutex_unlock(&s->__lock);
-+ s->session->waiting_thread = pthread_self();
-+ ast_mutex_unlock(&s->session->__lock);
-
-- res = ast_wait_for_input(s->fd, -1); /* return 0 on timeout ? */
-+ res = ast_wait_for_input(s->session->fd, -1); /* return 0 on timeout ? */
-
-- ast_mutex_lock(&s->__lock);
-- s->waiting_thread = AST_PTHREADT_NULL;
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_lock(&s->session->__lock);
-+ s->session->waiting_thread = AST_PTHREADT_NULL;
-+ ast_mutex_unlock(&s->session->__lock);
- }
- if (res < 0) {
- /* If we get a signal from some other thread (typically because
-@@ -3031,23 +3092,23 @@
- ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
- return -1;
- }
-- ast_mutex_lock(&s->__lock);
-- res = fread(src + s->inlen, 1, maxlen - s->inlen, s->f);
-+ ast_mutex_lock(&s->session->__lock);
-+ res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
- if (res < 1)
- res = -1; /* error return */
- else {
-- s->inlen += res;
-- src[s->inlen] = '\0';
-+ s->session->inlen += res;
-+ src[s->session->inlen] = '\0';
- res = 0;
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&s->session->__lock);
- return res;
- }
-
- static int do_message(struct mansession *s)
- {
- struct message m = { 0 };
-- char header_buf[sizeof(s->inbuf)] = { '\0' };
-+ char header_buf[sizeof(s->session->inbuf)] = { '\0' };
- int res;
-
- for (;;) {
-@@ -3079,15 +3140,16 @@
- static void *session_do(void *data)
- {
- struct ast_tcptls_session_instance *ser = data;
-- struct mansession *s = ast_calloc(1, sizeof(*s));
-+ struct mansession_session *session = ast_calloc(1, sizeof(*session));
-+ struct mansession s = {.session = NULL, };
- int flags;
- int res;
-
-- if (s == NULL)
-+ if (session == NULL)
- goto done;
-
-- s->writetimeout = 100;
-- s->waiting_thread = AST_PTHREADT_NULL;
-+ session->writetimeout = 100;
-+ session->waiting_thread = AST_PTHREADT_NULL;
-
- flags = fcntl(ser->fd, F_GETFL);
- if (!block_sockets) /* make sure socket is non-blocking */
-@@ -3096,37 +3158,38 @@
- flags &= ~O_NONBLOCK;
- fcntl(ser->fd, F_SETFL, flags);
-
-- ast_mutex_init(&s->__lock);
-- s->send_events = -1;
-+ ast_mutex_init(&session->__lock);
-+ session->send_events = -1;
- /* Hook to the tail of the event queue */
-- s->last_ev = grab_last();
-+ session->last_ev = grab_last();
-
- /* these fields duplicate those in the 'ser' structure */
-- s->fd = ser->fd;
-- s->f = ser->f;
-- s->sin = ser->remote_address;
-+ session->fd = ser->fd;
-+ session->f = ser->f;
-+ session->sin = ser->remote_address;
-+ s.session = session;
-
-- AST_LIST_HEAD_INIT_NOLOCK(&s->datastores);
-+ AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
-
- AST_LIST_LOCK(&sessions);
-- AST_LIST_INSERT_HEAD(&sessions, s, list);
-+ AST_LIST_INSERT_HEAD(&sessions, session, list);
- ast_atomic_fetchadd_int(&num_sessions, 1);
- AST_LIST_UNLOCK(&sessions);
-
-- astman_append(s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
-+ astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
- for (;;) {
-- if ((res = do_message(s)) < 0)
-+ if ((res = do_message(&s)) < 0)
- break;
- }
- /* session is over, explain why and terminate */
-- if (s->authenticated) {
-- if (manager_displayconnects(s))
-- ast_verb(2, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
-- ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
-+ if (session->authenticated) {
-+ if (manager_displayconnects(session))
-+ ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
-+ ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
- } else {
- if (displayconnects)
-- ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
-- ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
-+ ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
-+ ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
- }
-
- /* It is possible under certain circumstances for this session thread
-@@ -3142,7 +3205,7 @@
- */
- usleep(1);
-
-- destroy_session(s);
-+ destroy_session(session);
-
- done:
- ao2_ref(ser, -1);
-@@ -3153,19 +3216,19 @@
- /*! \brief remove at most n_max stale session from the list. */
- static void purge_sessions(int n_max)
- {
-- struct mansession *s;
-+ struct mansession_session *session;
- time_t now = time(NULL);
-
- AST_LIST_LOCK(&sessions);
-- AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
-- if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, session, list) {
-+ if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
- AST_LIST_REMOVE_CURRENT(list);
- ast_atomic_fetchadd_int(&num_sessions, -1);
-- if (s->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(s)) {
-+ if (session->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(session)) {
- ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
-- s->username, ast_inet_ntoa(s->sin.sin_addr));
-+ session->username, ast_inet_ntoa(session->sin.sin_addr));
- }
-- free_session(s); /* XXX outside ? */
-+ free_session(session); /* XXX outside ? */
- if (--n_max <= 0)
- break;
- }
-@@ -3208,7 +3271,7 @@
- int __manager_event(int category, const char *event,
- const char *file, int line, const char *func, const char *fmt, ...)
- {
-- struct mansession *s;
-+ struct mansession_session *session;
- struct manager_custom_hook *hook;
- struct ast_str *auth = ast_str_alloca(80);
- const char *cat_str;
-@@ -3249,28 +3312,28 @@
-
- ast_str_append(&buf, 0, "\r\n");
-
-- append_event(buf->str, category);
-+ append_event(ast_str_buffer(buf), category);
-
- /* Wake up any sleeping sessions */
- AST_LIST_LOCK(&sessions);
-- AST_LIST_TRAVERSE(&sessions, s, list) {
-- ast_mutex_lock(&s->__lock);
-- if (s->waiting_thread != AST_PTHREADT_NULL)
-- pthread_kill(s->waiting_thread, SIGURG);
-+ AST_LIST_TRAVERSE(&sessions, session, list) {
-+ ast_mutex_lock(&session->__lock);
-+ if (session->waiting_thread != AST_PTHREADT_NULL)
-+ pthread_kill(session->waiting_thread, SIGURG);
- else
- /* We have an event to process, but the mansession is
- * not waiting for it. We still need to indicate that there
- * is an event waiting so that get_input processes the pending
- * event instead of polling.
- */
-- s->pending_event = 1;
-- ast_mutex_unlock(&s->__lock);
-+ session->pending_event = 1;
-+ ast_mutex_unlock(&session->__lock);
- }
- AST_LIST_UNLOCK(&sessions);
-
- AST_RWLIST_RDLOCK(&manager_hooks);
- AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
-- hook->helper(category, event, buf->str);
-+ hook->helper(category, event, ast_str_buffer(buf));
- }
- AST_RWLIST_UNLOCK(&manager_hooks);
-
-@@ -3390,38 +3453,38 @@
- * the value of the mansession_id cookie (0 is not valid and means
- * a session on the AMI socket).
- */
--static struct mansession *find_session(uint32_t ident, int incinuse)
-+static struct mansession_session *find_session(uint32_t ident, int incinuse)
- {
-- struct mansession *s;
-+ struct mansession_session *session;
-
- if (ident == 0)
- return NULL;
-
- AST_LIST_LOCK(&sessions);
-- AST_LIST_TRAVERSE(&sessions, s, list) {
-- ast_mutex_lock(&s->__lock);
-- if (s->managerid == ident && !s->needdestroy) {
-- ast_atomic_fetchadd_int(&s->inuse, incinuse ? 1 : 0);
-+ AST_LIST_TRAVERSE(&sessions, session, list) {
-+ ast_mutex_lock(&session->__lock);
-+ if (session->managerid == ident && !session->needdestroy) {
-+ ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
- break;
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&session->__lock);
- }
- AST_LIST_UNLOCK(&sessions);
-
-- return s;
-+ return session;
- }
-
- int astman_is_authed(uint32_t ident)
- {
- int authed;
-- struct mansession *s;
-+ struct mansession_session *session;
-
-- if (!(s = find_session(ident, 0)))
-+ if (!(session = find_session(ident, 0)))
- return 0;
-
-- authed = (s->authenticated != 0);
-+ authed = (session->authenticated != 0);
-
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&session->__lock);
-
- return authed;
- }
-@@ -3429,17 +3492,17 @@
- int astman_verify_session_readpermissions(uint32_t ident, int perm)
- {
- int result = 0;
-- struct mansession *s;
-+ struct mansession_session *session;
-
- AST_LIST_LOCK(&sessions);
-- AST_LIST_TRAVERSE(&sessions, s, list) {
-- ast_mutex_lock(&s->__lock);
-- if ((s->managerid == ident) && (s->readperm & perm)) {
-+ AST_LIST_TRAVERSE(&sessions, session, list) {
-+ ast_mutex_lock(&session->__lock);
-+ if ((session->managerid == ident) && (session->readperm & perm)) {
- result = 1;
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&session->__lock);
- break;
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&session->__lock);
- }
- AST_LIST_UNLOCK(&sessions);
- return result;
-@@ -3448,17 +3511,17 @@
- int astman_verify_session_writepermissions(uint32_t ident, int perm)
- {
- int result = 0;
-- struct mansession *s;
-+ struct mansession_session *session;
-
- AST_LIST_LOCK(&sessions);
-- AST_LIST_TRAVERSE(&sessions, s, list) {
-- ast_mutex_lock(&s->__lock);
-- if ((s->managerid == ident) && (s->writeperm & perm)) {
-+ AST_LIST_TRAVERSE(&sessions, session, list) {
-+ ast_mutex_lock(&session->__lock);
-+ if ((session->managerid == ident) && (session->writeperm & perm)) {
- result = 1;
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&session->__lock);
- break;
- }
-- ast_mutex_unlock(&s->__lock);
-+ ast_mutex_unlock(&session->__lock);
- }
- AST_LIST_UNLOCK(&sessions);
- return result;
-@@ -3699,7 +3762,8 @@
- struct ast_variable *params, int *status,
- char **title, int *contentlength)
- {
-- struct mansession *s = NULL;
-+ struct mansession s = {.session = NULL, };
-+ struct mansession_session *session = NULL;
- uint32_t ident = 0;
- int blastaway = 0;
- struct ast_variable *v;
-@@ -3716,45 +3780,47 @@
- }
- }
-
-- if (!(s = find_session(ident, 1))) {
-+ if (!(session = find_session(ident, 1))) {
- /* Create new session.
- * While it is not in the list we don't need any locking
- */
-- if (!(s = ast_calloc(1, sizeof(*s)))) {
-+ if (!(session = ast_calloc(1, sizeof(*session)))) {
- *status = 500;
- goto generic_callback_out;
- }
-- s->sin = *remote_address;
-- s->fd = -1;
-- s->waiting_thread = AST_PTHREADT_NULL;
-- s->send_events = 0;
-- ast_mutex_init(&s->__lock);
-- ast_mutex_lock(&s->__lock);
-- s->inuse = 1;
-+ session->sin = *remote_address;
-+ session->fd = -1;
-+ session->waiting_thread = AST_PTHREADT_NULL;
-+ session->send_events = 0;
-+ ast_mutex_init(&session->__lock);
-+ ast_mutex_lock(&session->__lock);
-+ session->inuse = 1;
- /*!\note There is approximately a 1 in 1.8E19 chance that the following
- * calculation will produce 0, which is an invalid ID, but due to the
- * properties of the rand() function (and the constantcy of s), that
- * won't happen twice in a row.
- */
-- while ((s->managerid = rand() ^ (unsigned long) s) == 0);
-- s->last_ev = grab_last();
-- AST_LIST_HEAD_INIT_NOLOCK(&s->datastores);
-+ while ((session->managerid = rand() ^ (unsigned long) session) == 0);
-+ session->last_ev = grab_last();
-+ AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
- AST_LIST_LOCK(&sessions);
-- AST_LIST_INSERT_HEAD(&sessions, s, list);
-+ AST_LIST_INSERT_HEAD(&sessions, session, list);
- ast_atomic_fetchadd_int(&num_sessions, 1);
- AST_LIST_UNLOCK(&sessions);
- }
-
-- ast_mutex_unlock(&s->__lock);
-+ s.session = session;
-
-+ ast_mutex_unlock(&session->__lock);
-+
- if (!(out = ast_str_create(1024))) {
- *status = 500;
- goto generic_callback_out;
- }
-
-- s->fd = mkstemp(template); /* create a temporary file for command output */
-+ s.fd = mkstemp(template); /* create a temporary file for command output */
- unlink(template);
-- s->f = fdopen(s->fd, "w+");
-+ s.f = fdopen(s.fd, "w+");
-
- for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
- hdrlen = strlen(v->name) + strlen(v->value) + 3;
-@@ -3764,28 +3830,29 @@
- m.hdrcount = x + 1;
- }
-
-- if (process_message(s, &m)) {
-- if (s->authenticated) {
-- if (manager_displayconnects(s)) {
-- ast_verb(2, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
-+ if (process_message(&s, &m)) {
-+ if (session->authenticated) {
-+ if (manager_displayconnects(session)) {
-+ ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
- }
-- ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
-+ ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
- } else {
- if (displayconnects) {
-- ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
-+ ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
- }
-- ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
-+ ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
- }
-- s->needdestroy = 1;
-+ session->needdestroy = 1;
- }
-
- ast_str_append(&out, 0,
- "Content-type: text/%s\r\n"
- "Cache-Control: no-cache;\r\n"
- "Set-Cookie: mansession_id=\"%08x\"; Version=\"1\"; Max-Age=%d\r\n"
-+ "Pragma: SuppressEvents\r\n"
- "\r\n",
- contenttype[format],
-- s->managerid, httptimeout);
-+ session->managerid, httptimeout);
-
- if (format == FORMAT_XML) {
- ast_str_append(&out, 0, "<ajax-response>\n");
-@@ -3817,12 +3884,12 @@
- ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
- }
-
-- if (s->f != NULL) { /* have temporary output */
-+ if (s.f != NULL) { /* have temporary output */
- char *buf;
-- size_t l = ftell(s->f);
-+ size_t l = ftell(s.f);
-
- if (l) {
-- if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, 0))) {
-+ if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) {
- if (format == FORMAT_XML || format == FORMAT_HTML)
- xml_translate(&out, buf, params, format);
- else
-@@ -3832,9 +3899,9 @@
- } else if (format == FORMAT_XML || format == FORMAT_HTML) {
- xml_translate(&out, "", params, format);
- }
-- fclose(s->f);
-- s->f = NULL;
-- s->fd = -1;
-+ fclose(s.f);
-+ s.f = NULL;
-+ s.fd = -1;
- }
-
- if (format == FORMAT_XML) {
-@@ -3842,26 +3909,26 @@
- } else if (format == FORMAT_HTML)
- ast_str_append(&out, 0, "</table></body>\r\n");
-
-- ast_mutex_lock(&s->__lock);
-+ ast_mutex_lock(&session->__lock);
- /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
-- s->sessiontimeout = time(NULL) + ((s->authenticated || httptimeout < 5) ? httptimeout : 5);
-+ session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
-
-- if (s->needdestroy) {
-- if (s->inuse == 1) {
-+ if (session->needdestroy) {
-+ if (session->inuse == 1) {
- ast_debug(1, "Need destroy, doing it now!\n");
- blastaway = 1;
- } else {
- ast_debug(1, "Need destroy, but can't do it yet!\n");
-- if (s->waiting_thread != AST_PTHREADT_NULL)
-- pthread_kill(s->waiting_thread, SIGURG);
-- s->inuse--;
-+ if (session->waiting_thread != AST_PTHREADT_NULL)
-+ pthread_kill(session->waiting_thread, SIGURG);
-+ session->inuse--;
- }
- } else
-- s->inuse--;
-- ast_mutex_unlock(&s->__lock);
-+ session->inuse--;
-+ ast_mutex_unlock(&session->__lock);
-
- if (blastaway)
-- destroy_session(s);
-+ destroy_session(session);
- generic_callback_out:
- if (*status != 200)
- return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
-@@ -3994,7 +4061,7 @@
- ast_manager_register2("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload, "Module management", mandescr_moduleload);
- ast_manager_register2("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck, "Check if module is loaded", mandescr_modulecheck);
-
-- ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
- ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
- registered = 1;
- /* Append placeholder event so master_eventq never runs dry */
-@@ -4271,14 +4338,14 @@
-
- int astman_datastore_add(struct mansession *s, struct ast_datastore *datastore)
- {
-- AST_LIST_INSERT_HEAD(&s->datastores, datastore, entry);
-+ AST_LIST_INSERT_HEAD(&s->session->datastores, datastore, entry);
-
- return 0;
- }
-
- int astman_datastore_remove(struct mansession *s, struct ast_datastore *datastore)
- {
-- return AST_LIST_REMOVE(&s->datastores, datastore, entry) ? 0 : -1;
-+ return AST_LIST_REMOVE(&s->session->datastores, datastore, entry) ? 0 : -1;
- }
-
- struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
-@@ -4288,7 +4355,7 @@
- if (info == NULL)
- return NULL;
-
-- AST_LIST_TRAVERSE_SAFE_BEGIN(&s->datastores, datastore, entry) {
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&s->session->datastores, datastore, entry) {
- if (datastore->info != info) {
- continue;
- }
-Index: main/ast_expr2f.c
-===================================================================
---- a/main/ast_expr2f.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/ast_expr2f.c (.../team/group/issue14292) (revision 178988)
-@@ -336,1906 +336,7 @@
- typedef int yy_state_type;
-
- #define yytext_ptr yytext_r
--static yyconst flex_int16_t yy_nxt[][256] =
-- {
-- {
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
--
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0
-- },
--
-- {
-- 7, 8, 8, 8, 8, 8, 8, 8, 8, 9,
-- 10, 8, 8, 9, 8, 8, 8, 8, 8, 8,
-- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-- 8, 8, 9, 11, 12, 13, 14, 15, 16, 13,
--
-- 17, 18, 19, 20, 21, 22, 13, 23, 24, 24,
-- 24, 24, 24, 24, 24, 24, 24, 24, 25, 13,
-- 26, 27, 28, 29, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 8, 13, 8, 13, 13, 8, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 8, 30, 8, 31, 8, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
--
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
--
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13
-- },
--
-- {
-- 7, 8, 8, 8, 8, 8, 8, 8, 8, 9,
-- 10, 8, 8, 9, 8, 8, 8, 8, 8, 8,
-- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-- 8, 8, 9, 11, 12, 13, 14, 15, 16, 13,
-- 17, 18, 19, 20, 21, 22, 13, 23, 24, 24,
-- 24, 24, 24, 24, 24, 24, 24, 24, 25, 13,
-- 26, 27, 28, 29, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
--
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 8, 13, 8, 13, 13, 8, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 8, 30, 8, 31, 8, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
--
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
-- 13, 13, 13, 13, 13, 13
-- },
--
-- {
-- 7, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
--
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
--
-- 32, 32, 32, 33, 32, 34, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
--
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32
-- },
--
-- {
-- 7, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
--
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 33, 32, 34, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
--
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-- 32, 32, 32, 32, 32, 32
--
-- },
--
-- {
-- 7, 35, 35, 35, 35, 35, 35, 35, 35, 36,
-- 36, 35, 35, 36, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 36, 36, 35, 35, 37, 36, 36, 35,
-- 36, 36, 36, 36, 35, 36, 35, 36, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 36, 35,
-- 36, 36, 36, 36, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
--
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 36, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
--
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35
-- },
--
-- {
-- 7, 35, 35, 35, 35, 35, 35, 35, 35, 36,
-- 36, 35, 35, 36, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 36, 36, 35, 35, 37, 36, 36, 35,
--
-- 36, 36, 36, 36, 35, 36, 35, 36, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 36, 35,
-- 36, 36, 36, 36, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 36, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
--
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
--
-- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
-- 35, 35, 35, 35, 35, 35
-- },
--
-- {
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
--
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
--
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7, -7, -7, -7, -7,
-- -7, -7, -7, -7, -7, -7
-- },
--
-- {
-- 7, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
--
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
--
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
--
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
-- -8, -8, -8, -8, -8, -8
-- },
--
-- {
-- 7, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
--
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
--
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
-- -9, -9, -9, -9, -9, -9
--
-- },
--
-- {
-- 7, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
--
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
--
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
-- -10, -10, -10, -10, -10, -10
-- },
--
-- {
-- 7, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
--
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, 38, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
--
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
--
-- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
-- -11, -11, -11, -11, -11, -11
-- },
--
-- {
-- 7, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 40, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
--
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
--
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39
-- },
--
-- {
-- 7, -13, -13, -13, -13, -13, -13, -13, -13, -13,
-- -13, -13, -13, -13, -13, -13, -13, -13, -13, -13,
--
-- -13, -13, -13, -13, -13, -13, -13, -13, -13, -13,
-- -13, -13, -13, -13, -13, 41, 42, -13, -13, 41,
-- -13, -13, -13, -13, -13, -13, 41, -13, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, -13, 41,
-- -13, -13, -13, -13, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, -13, 41, -13, 41, 41, -13, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, -13, -13, -13, -13, -13, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
-- },
--
-- {
-- 7, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 43, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
--
-- },
--
-- {
-- 7, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
--
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
--
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
-- -15, -15, -15, -15, -15, -15
-- },
--
-- {
-- 7, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, 44, -16,
--
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
--
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
--
-- -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
-- -16, -16, -16, -16, -16, -16
-- },
--
-- {
-- 7, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
--
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
--
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
-- -17, -17, -17, -17, -17, -17
-- },
--
-- {
-- 7, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
--
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
--
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
--
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
-- -18, -18, -18, -18, -18, -18
-- },
--
-- {
-- 7, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
--
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
--
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
-- -19, -19, -19, -19, -19, -19
--
-- },
--
-- {
-- 7, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
--
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
--
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
-- -20, -20, -20, -20, -20, -20
-- },
--
-- {
-- 7, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
--
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
--
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
--
-- -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
-- -21, -21, -21, -21, -21, -21
-- },
--
-- {
-- 7, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
--
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
--
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
-- -22, -22, -22, -22, -22, -22
-- },
--
-- {
-- 7, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
--
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
--
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
--
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
-- -23, -23, -23, -23, -23, -23
-- },
--
-- {
-- 7, -24, -24, -24, -24, -24, -24, -24, -24, -24,
-- -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
-- -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
-- -24, -24, -24, -24, -24, 41, 42, -24, -24, 41,
-- -24, -24, -24, -24, -24, -24, 45, -24, 46, 46,
-- 46, 46, 46, 46, 46, 46, 46, 46, -24, 41,
--
-- -24, -24, -24, -24, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, -24, 41, -24, 41, 41, -24, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, -24, -24, -24, -24, -24, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
--
-- },
--
-- {
-- 7, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, 47, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
--
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
--
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-- -25, -25, -25, -25, -25, -25
-- },
--
-- {
-- 7, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
--
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, 48, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
--
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
--
-- -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
-- -26, -26, -26, -26, -26, -26
-- },
--
-- {
-- 7, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, 49, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
--
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, 50, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
--
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
-- -27, -27, -27, -27, -27, -27
-- },
--
-- {
-- 7, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
--
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, 51, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
--
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
--
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
-- -28, -28, -28, -28, -28, -28
-- },
--
-- {
-- 7, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
--
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
--
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
-- -29, -29, -29, -29, -29, -29
--
-- },
--
-- {
-- 7, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
--
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, 52, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
--
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
-- -30, -30, -30, -30, -30, -30
-- },
--
-- {
-- 7, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
--
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, 53, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
--
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
--
-- -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
-- -31, -31, -31, -31, -31, -31
-- },
--
-- {
-- 7, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
--
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 55, 54, 56, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
--
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54
-- },
--
-- {
-- 7, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
--
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
--
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
--
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33, -33, -33, -33, -33,
-- -33, -33, -33, -33, -33, -33
-- },
--
-- {
-- 7, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
--
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
--
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
-- -34, -34, -34, -34, -34, -34
--
-- },
--
-- {
-- 7, 57, 57, 57, 57, 57, 57, 57, 57, -35,
-- -35, 57, 57, -35, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, -35, -35, 57, 57, -35, -35, -35, 57,
-- -35, -35, -35, -35, 57, -35, 57, -35, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, -35, 57,
-- -35, -35, -35, -35, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
--
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, -35, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
--
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57
-- },
--
-- {
-- 7, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
--
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
--
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
--
-- -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
-- -36, -36, -36, -36, -36, -36
-- },
--
-- {
-- 7, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
--
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, 58, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
--
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
-- -37, -37, -37, -37, -37, -37
-- },
--
-- {
-- 7, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
--
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
--
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
--
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
-- -38, -38, -38, -38, -38, -38
-- },
--
-- {
-- 7, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 40, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
--
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
--
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
-- 39, 39, 39, 39, 39, 39
--
-- },
--
-- {
-- 7, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
--
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
--
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
-- -40, -40, -40, -40, -40, -40
-- },
--
-- {
-- 7, -41, -41, -41, -41, -41, -41, -41, -41, -41,
-- -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
-- -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
-- -41, -41, -41, -41, -41, 41, 42, -41, -41, 41,
--
-- -41, -41, -41, -41, -41, -41, 41, -41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, -41, 41,
-- -41, -41, -41, -41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, -41, 41, -41, 41, 41, -41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, -41, -41, -41, -41, -41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
-- },
--
-- {
-- 7, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, -42, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
-- },
--
-- {
-- 7, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
--
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
--
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
--
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43, -43, -43, -43, -43,
-- -43, -43, -43, -43, -43, -43
-- },
--
-- {
-- 7, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
--
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
--
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
-- -44, -44, -44, -44, -44, -44
--
-- },
--
-- {
-- 7, -45, -45, -45, -45, -45, -45, -45, -45, -45,
-- -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
-- -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
-- -45, -45, -45, -45, -45, 41, 42, -45, -45, 41,
-- -45, -45, -45, -45, -45, -45, 41, -45, 59, 59,
-- 59, 59, 59, 59, 59, 59, 59, 59, -45, 41,
-- -45, -45, -45, -45, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, -45, 41, -45, 41, 41, -45, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, -45, -45, -45, -45, -45, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
-- },
--
-- {
-- 7, -46, -46, -46, -46, -46, -46, -46, -46, -46,
-- -46, -46, -46, -46, -46, -46, -46, -46, -46, -46,
-- -46, -46, -46, -46, -46, -46, -46, -46, -46, -46,
-- -46, -46, -46, -46, -46, 41, 42, -46, -46, 41,
--
-- -46, -46, -46, -46, -46, -46, 45, -46, 46, 46,
-- 46, 46, 46, 46, 46, 46, 46, 46, -46, 41,
-- -46, -46, -46, -46, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, -46, 41, -46, 41, 41, -46, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, -46, -46, -46, -46, -46, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
-- },
--
-- {
-- 7, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
--
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
--
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47, -47, -47, -47, -47,
-- -47, -47, -47, -47, -47, -47
-- },
--
-- {
-- 7, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
--
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
--
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
--
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
-- -48, -48, -48, -48, -48, -48
-- },
--
-- {
-- 7, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
--
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
--
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
-- -49, -49, -49, -49, -49, -49
--
-- },
--
-- {
-- 7, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
--
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
--
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
-- -50, -50, -50, -50, -50, -50
-- },
--
-- {
-- 7, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
--
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
--
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
--
-- -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
-- -51, -51, -51, -51, -51, -51
-- },
--
-- {
-- 7, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
--
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
--
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
-- -52, -52, -52, -52, -52, -52
-- },
--
-- {
-- 7, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
--
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
--
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
--
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
-- -53, -53, -53, -53, -53, -53
-- },
--
-- {
-- 7, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
--
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 55, 54, 56, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
--
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
-- 54, 54, 54, 54, 54, 54
--
-- },
--
-- {
-- 7, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
--
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
--
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
-- -55, -55, -55, -55, -55, -55
-- },
--
-- {
-- 7, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
--
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
--
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
--
-- -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
-- -56, -56, -56, -56, -56, -56
-- },
--
-- {
-- 7, 57, 57, 57, 57, 57, 57, 57, 57, -57,
-- -57, 57, 57, -57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, -57, -57, 57, 57, -57, -57, -57, 57,
-- -57, -57, -57, -57, 57, -57, 57, -57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, -57, 57,
-- -57, -57, -57, -57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
--
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, -57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
--
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
-- 57, 57, 57, 57, 57, 57
-- },
--
-- {
-- 7, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
--
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
--
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
--
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
-- -58, -58, -58, -58, -58, -58
-- },
--
-- {
-- 7, -59, -59, -59, -59, -59, -59, -59, -59, -59,
-- -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
-- -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
-- -59, -59, -59, -59, -59, 41, 42, -59, -59, 41,
-- -59, -59, -59, -59, -59, -59, 41, -59, 59, 59,
-- 59, 59, 59, 59, 59, 59, 59, 59, -59, 41,
--
-- -59, -59, -59, -59, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, -59, 41, -59, 41, 41, -59, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, -59, -59, -59, -59, -59, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
--
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
-- 41, 41, 41, 41, 41, 41
--
-- },
--
-- } ;
--
- static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
- static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
- static int yy_get_next_buffer (yyscan_t yyscanner );
-@@ -2261,26 +362,121 @@
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
--static yyconst flex_int16_t yy_accept[60] =
-+static yyconst flex_int16_t yy_accept[61] =
- { 0,
- 0, 0, 0, 0, 34, 34, 38, 37, 27, 29,
- 21, 37, 31, 37, 19, 2, 24, 25, 17, 14,
- 15, 16, 18, 30, 22, 10, 3, 9, 20, 1,
- 37, 37, 33, 32, 34, 35, 35, 13, 0, 28,
- 31, 0, 26, 5, 31, 30, 23, 12, 6, 7,
-- 11, 4, 8, 0, 33, 32, 34, 36, 30
-+ 11, 4, 8, 0, 33, 32, 34, 36, 30, 0
- } ;
-
--static yyconst yy_state_type yy_NUL_trans[60] =
-+static yyconst flex_int32_t yy_ec[256] =
- { 0,
-- 8, 8, 32, 32, 35, 35, 0, 0, 0, 0,
-- 0, 39, 0, 41, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 54, 0, 0, 57, 0, 0, 0, 39, 0,
-- 0, 41, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 0, 54, 0, 0, 57, 0, 0
-+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
-+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 2, 4, 5, 6, 7, 8, 9, 6, 10,
-+ 11, 12, 13, 14, 15, 16, 17, 18, 18, 18,
-+ 18, 18, 18, 18, 18, 18, 18, 19, 6, 20,
-+ 21, 22, 23, 6, 6, 6, 6, 6, 6, 6,
-+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-+ 1, 6, 1, 6, 6, 1, 6, 6, 6, 6,
-+
-+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-+ 6, 6, 24, 25, 26, 27, 1, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
-+ 28, 28, 28, 28, 28
- } ;
-
-+static yyconst flex_int32_t yy_meta[29] =
-+ { 0,
-+ 1, 2, 2, 2, 1, 3, 4, 2, 2, 2,
-+ 2, 2, 2, 1, 2, 3, 2, 3, 2, 2,
-+ 2, 2, 2, 1, 2, 1, 1, 3
-+ } ;
-+
-+static yyconst flex_int16_t yy_base[68] =
-+ { 0,
-+ 0, 0, 5, 6, 32, 60, 69, 137, 137, 137,
-+ 47, 59, 56, 38, 137, 48, 137, 137, 137, 137,
-+ 137, 137, 137, 83, 36, 33, 13, 32, 137, 27,
-+ 24, 17, 137, 137, 0, 137, 25, 137, 42, 137,
-+ 38, 12, 137, 137, 17, 0, 137, 137, 137, 137,
-+ 137, 137, 137, 18, 137, 137, 0, 137, 0, 137,
-+ 111, 115, 119, 121, 125, 129, 133
-+ } ;
-+
-+static yyconst flex_int16_t yy_def[68] =
-+ { 0,
-+ 60, 1, 61, 61, 62, 62, 60, 60, 60, 60,
-+ 60, 63, 64, 65, 60, 60, 60, 60, 60, 60,
-+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-+ 60, 66, 60, 60, 67, 60, 60, 60, 63, 60,
-+ 64, 65, 60, 60, 41, 24, 60, 60, 60, 60,
-+ 60, 60, 60, 66, 60, 60, 67, 60, 45, 0,
-+ 60, 60, 60, 60, 60, 60, 60
-+ } ;
-+
-+static yyconst flex_int16_t yy_nxt[166] =
-+ { 0,
-+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
-+ 18, 19, 20, 21, 22, 13, 23, 24, 25, 26,
-+ 27, 28, 29, 8, 30, 8, 31, 13, 33, 33,
-+ 34, 34, 35, 49, 59, 60, 35, 35, 37, 50,
-+ 55, 55, 56, 56, 42, 35, 40, 35, 58, 35,
-+ 53, 52, 51, 48, 47, 35, 44, 35, 35, 35,
-+ 35, 43, 42, 40, 35, 35, 37, 38, 60, 60,
-+ 60, 60, 60, 35, 60, 35, 60, 35, 60, 60,
-+ 60, 60, 60, 35, 60, 35, 35, 35, 41, 42,
-+ 60, 60, 60, 60, 60, 60, 60, 60, 45, 60,
-+
-+ 46, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-+ 41, 32, 32, 32, 32, 36, 36, 36, 36, 39,
-+ 39, 39, 39, 41, 41, 41, 41, 41, 41, 54,
-+ 54, 54, 54, 57, 60, 57, 7, 60, 60, 60,
-+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-+ 60, 60, 60, 60, 60
-+ } ;
-+
-+static yyconst flex_int16_t yy_chk[166] =
-+ { 0,
-+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 4,
-+ 3, 4, 5, 27, 45, 42, 5, 5, 5, 27,
-+ 32, 54, 32, 54, 41, 5, 39, 5, 37, 5,
-+ 31, 30, 28, 26, 25, 5, 16, 5, 5, 5,
-+ 6, 14, 13, 12, 6, 6, 6, 11, 7, 0,
-+ 0, 0, 0, 6, 0, 6, 0, 6, 0, 0,
-+ 0, 0, 0, 6, 0, 6, 6, 6, 24, 24,
-+ 0, 0, 0, 0, 0, 0, 0, 0, 24, 0,
-+
-+ 24, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 24, 61, 61, 61, 61, 62, 62, 62, 62, 63,
-+ 63, 63, 63, 64, 64, 65, 65, 65, 65, 66,
-+ 66, 66, 66, 67, 0, 67, 60, 60, 60, 60,
-+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
-+ 60, 60, 60, 60, 60
-+ } ;
-+
- /* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-@@ -2401,7 +597,7 @@
- static int curlycount = 0;
- static char *expr2_token_subst(const char *mess);
-
--#line 2403 "ast_expr2f.c"
-+#line 599 "ast_expr2f.c"
-
- #define INITIAL 0
- #define var 1
-@@ -2556,17 +752,33 @@
- */
- #ifndef YY_INPUT
- #define YY_INPUT(buf,result,max_size) \
-- errno=0; \
-- while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
-- { \
-- if( errno != EINTR) \
-+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
- { \
-+ int c = '*'; \
-+ size_t n; \
-+ for ( n = 0; n < max_size && \
-+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-+ buf[n] = (char) c; \
-+ if ( c == '\n' ) \
-+ buf[n++] = (char) c; \
-+ if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
-- break; \
-+ result = n; \
- } \
-+ else \
-+ { \
- errno=0; \
-- clearerr(yyin); \
-- }\
-+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
-+ { \
-+ if( errno != EINTR) \
-+ { \
-+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
-+ break; \
-+ } \
-+ errno=0; \
-+ clearerr(yyin); \
-+ } \
-+ }\
- \
-
- #endif
-@@ -2631,7 +843,7 @@
- #line 125 "ast_expr2.fl"
-
-
--#line 2633 "ast_expr2f.c"
-+#line 845 "ast_expr2f.c"
-
- yylval = yylval_param;
-
-@@ -2683,19 +895,27 @@
-
- yy_current_state = yyg->yy_start;
- yy_match:
-- while ( (yy_current_state = yy_nxt[yy_current_state][ YY_SC_TO_UI(*yy_cp) ]) > 0 )
-+ do
- {
-+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- yyg->yy_last_accepting_state = yy_current_state;
- yyg->yy_last_accepting_cpos = yy_cp;
- }
--
-+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-+ {
-+ yy_current_state = (int) yy_def[yy_current_state];
-+ if ( yy_current_state >= 61 )
-+ yy_c = yy_meta[(unsigned int) yy_c];
-+ }
-+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- ++yy_cp;
- }
-+ while ( yy_current_state != 60 );
-+ yy_cp = yyg->yy_last_accepting_cpos;
-+ yy_current_state = yyg->yy_last_accepting_state;
-
-- yy_current_state = -yy_current_state;
--
- yy_find_action:
- yy_act = yy_accept[yy_current_state];
-
-@@ -2708,7 +928,7 @@
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = yyg->yy_hold_char;
-- yy_cp = yyg->yy_last_accepting_cpos + 1;
-+ yy_cp = yyg->yy_last_accepting_cpos;
- yy_current_state = yyg->yy_last_accepting_state;
- goto yy_find_action;
-
-@@ -2959,7 +1179,7 @@
- #line 228 "ast_expr2.fl"
- ECHO;
- YY_BREAK
--#line 2961 "ast_expr2f.c"
-+#line 1181 "ast_expr2f.c"
- case YY_STATE_EOF(INITIAL):
- case YY_STATE_EOF(var):
- yyterminate();
-@@ -3027,7 +1247,8 @@
-
- else
- {
-- yy_cp = yyg->yy_c_buf_p;
-+ yy_cp = yyg->yy_last_accepting_cpos;
-+ yy_current_state = yyg->yy_last_accepting_state;
- goto yy_find_action;
- }
- }
-@@ -3245,17 +1466,19 @@
-
- for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
- {
-- if ( *yy_cp )
-- {
-- yy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)];
-- }
-- else
-- yy_current_state = yy_NUL_trans[yy_current_state];
-+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- yyg->yy_last_accepting_state = yy_current_state;
- yyg->yy_last_accepting_cpos = yy_cp;
- }
-+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-+ {
-+ yy_current_state = (int) yy_def[yy_current_state];
-+ if ( yy_current_state >= 61 )
-+ yy_c = yy_meta[(unsigned int) yy_c];
-+ }
-+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- }
-
- return yy_current_state;
-@@ -3272,17 +1495,20 @@
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
- register char *yy_cp = yyg->yy_c_buf_p;
-
-- yy_current_state = yy_NUL_trans[yy_current_state];
-- yy_is_jam = (yy_current_state == 0);
--
-- if ( ! yy_is_jam )
-+ register YY_CHAR yy_c = 1;
-+ if ( yy_accept[yy_current_state] )
- {
-- if ( yy_accept[yy_current_state] )
-- {
-- yyg->yy_last_accepting_state = yy_current_state;
-- yyg->yy_last_accepting_cpos = yy_cp;
-- }
-+ yyg->yy_last_accepting_state = yy_current_state;
-+ yyg->yy_last_accepting_cpos = yy_cp;
- }
-+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-+ {
-+ yy_current_state = (int) yy_def[yy_current_state];
-+ if ( yy_current_state >= 61 )
-+ yy_c = yy_meta[(unsigned int) yy_c];
-+ }
-+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-+ yy_is_jam = (yy_current_state == 60);
-
- return yy_is_jam ? 0 : yy_current_state;
- }
-Index: main/features.c
-===================================================================
---- a/main/features.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/features.c (.../team/group/issue14292) (revision 178988)
-@@ -56,9 +56,109 @@
- #include "asterisk/global_datastores.h"
- #include "asterisk/astobj2.h"
-
-+/*** DOCUMENTATION
-+ <application name="Bridge" language="en_US">
-+ <synopsis>
-+ Bridge two channels.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channel" required="true">
-+ <para>The current channel is bridged to the specified <replaceable>channel</replaceable>.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="p">
-+ <para>Play a courtesy tone to <replaceable>channel</replaceable>.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Allows the ability to bridge two channels via the dialplan.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="BRIDGERESULT">
-+ <para>The result of the bridge attempt as a text string.</para>
-+ <value name="SUCCESS" />
-+ <value name="FAILURE" />
-+ <value name="LOOP" />
-+ <value name="NONEXISTENT" />
-+ <value name="INCOMPATIBLE" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ </application>
-+ <application name="ParkedCall" language="en_US">
-+ <synopsis>
-+ Answer a parked call.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="exten" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Used to connect to a parked call. This application is always
-+ registered internally and does not need to be explicitly added
-+ into the dialplan, although you should include the <literal>parkedcalls</literal>
-+ context. If no extension is provided, then the first available
-+ parked call will be acquired.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Park</ref>
-+ <ref type="application">ParkAndAnnounce</ref>
-+ </see-also>
-+ </application>
-+ <application name="Park" language="en_US">
-+ <synopsis>
-+ Park yourself.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="timeout">
-+ <para>A custom parking timeout for this parked call.</para>
-+ </parameter>
-+ <parameter name="return_context">
-+ <para>The context to return the call to after it times out.</para>
-+ </parameter>
-+ <parameter name="return_exten">
-+ <para>The extension to return the call to after it times out.</para>
-+ </parameter>
-+ <parameter name="return_priority">
-+ <para>The priority to return the call to after it times out.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <para>A list of options for this parked call.</para>
-+ <optionlist>
-+ <option name="r">
-+ <para>Send ringing instead of MOH to the parked call.</para>
-+ </option>
-+ <option name="R">
-+ <para>Randomize the selection of a parking space.</para>
-+ </option>
-+ <option name="s">
-+ <para>Silence announcement of the parking space number.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Used to park yourself (typically in combination with a supervised
-+ transfer to know the parking space). This application is always
-+ registered internally and does not need to be explicitly added
-+ into the dialplan, although you should include the <literal>parkedcalls</literal>
-+ context (or the context specified in <filename>features.conf</filename>).</para>
-+ <para>If you set the <variable>PARKINGEXTEN</variable> variable to an extension in your
-+ parking context, Park() will park the call on that extension, unless
-+ it already exists. In that case, execution will continue at next priority.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">ParkAndAnnounce</ref>
-+ <ref type="application">ParkedCall</ref>
-+ </see-also>
-+ </application>
-+ ***/
-+
- #define DEFAULT_PARK_TIME 45000
- #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
--#define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
-+#define DEFAULT_FEATURE_DIGIT_TIMEOUT 2000
- #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
- #define DEFAULT_PARKINGLOT "default" /*!< Default parking lot */
- #define DEFAULT_ATXFER_DROP_CALL 0
-@@ -66,6 +166,7 @@
- #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
-
- #define AST_MAX_WATCHERS 256
-+#define MAX_DIAL_FEATURE_OPTIONS 30
-
- struct feature_group_exten {
- AST_LIST_ENTRY(feature_group_exten) entry;
-@@ -122,6 +223,8 @@
- int parkaddhints; /*!< Add parking hints automatically */
- int parkedcalltransfers; /*!< Enable DTMF based transfers on bridge when picking up parked calls */
- int parkedcallreparking; /*!< Enable DTMF based parking on bridge when picking up parked calls */
-+ int parkedcallhangup; /*!< Enable DTMF based hangup on a bridge when pickup up parked calls */
-+ int parkedcallrecording; /*!< Enable DTMF based recording on a bridge when picking up parked calls */
- AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings; /*!< List of active parkings in this parkinglot */
- };
-
-@@ -135,6 +238,8 @@
- static int parkedplay = 0; /*!< Who to play the courtesy tone to */
- static char xfersound[256]; /*!< Call transfer sound */
- static char xferfailsound[256]; /*!< Call transfer failure sound */
-+static char pickupsound[256]; /*!< Pickup sound */
-+static char pickupfailsound[256]; /*!< Pickup failure sound */
-
- static int adsipark;
-
-@@ -150,41 +255,8 @@
- static char *registrar = "features"; /*!< Registrar for operations */
-
- /* module and CLI command definitions */
--static char *synopsis = "Answer a parked call";
--
--static char *descrip = "ParkedCall(exten): "
--"Used to connect to a parked call. This application is always\n"
--"registered internally and does not need to be explicitly added\n"
--"into the dialplan, although you should include the 'parkedcalls'\n"
--"context. If no extension is provided, then the first available\n"
--"parked call will be acquired.\n";
--
- static char *parkcall = PARK_APP_NAME;
-
--static char *synopsis2 = "Park yourself";
--
--static char *descrip2 =
--" Park([timeout,[return_context,[return_exten,[return_priority,[options]]]]]):"
--"Used to park yourself (typically in combination with a supervised\n"
--"transfer to know the parking space). This application is always\n"
--"registered internally and does not need to be explicitly added\n"
--"into the dialplan, although you should include the 'parkedcalls'\n"
--"context (or the context specified in features.conf).\n\n"
--"If you set the PARKINGEXTEN variable to an extension in your\n"
--"parking context, Park() will park the call on that extension, unless\n"
--"it already exists. In that case, execution will continue at next\n"
--"priority.\n"
--" This application can accept arguments as well.\n"
--" timeout - A custom parking timeout for this parked call.\n"
--" return_context - The context to return the call to after it times out.\n"
--" return_exten - The extension to return the call to after it times out.\n"
--" return_priority - The priority to return the call to after it times out.\n"
--" options - A list of options for this parked call. Valid options are:\n"
--" 'r' - Send ringing instead of MOH to the parked call.\n"
--" 'R' - Randomize the selection of a parking space.\n"
--" 's' - Silence announcement of the parking space number.\n"
--"";
--
- static struct ast_app *monitor_app = NULL;
- static int monitor_ok = 1;
-
-@@ -195,7 +267,39 @@
- static int stopmixmonitor_ok = 1;
-
- static pthread_t parking_thread;
-+struct ast_dial_features {
-+ struct ast_flags features_caller;
-+ struct ast_flags features_callee;
-+ int is_caller;
-+};
-
-+static void *dial_features_duplicate(void *data)
-+{
-+ struct ast_dial_features *df = data, *df_copy;
-+
-+ if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
-+ return NULL;
-+ }
-+
-+ memcpy(df_copy, df, sizeof(*df));
-+
-+ return df_copy;
-+ }
-+
-+ static void dial_features_destroy(void *data)
-+ {
-+ struct ast_dial_features *df = data;
-+ if (df) {
-+ ast_free(df);
-+ }
-+ }
-+
-+ const struct ast_datastore_info dial_features_info = {
-+ .type = "dial-features",
-+ .destroy = dial_features_destroy,
-+ .duplicate = dial_features_duplicate,
-+ };
-+
- /* Forward declarations */
- static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
- static void parkinglot_unref(struct ast_parkinglot *parkinglot);
-@@ -301,7 +405,7 @@
- * bridge call, check if we're going back to dialplan
- * if not hangup both legs of the call
- */
--static void *ast_bridge_call_thread(void *data)
-+static void *ast_bridge_call_thread(void *data)
- {
- struct ast_bridge_thread_obj *tobj = data;
- int res;
-@@ -402,7 +506,7 @@
- static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
- {
- ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
-- exten, context, devstate2str(state));
-+ exten, context, ast_devstate2str(state));
-
- ast_devstate_changed(state, "park:%s@%s", exten, context);
- }
-@@ -451,15 +555,15 @@
- const char *return_ext;
- int return_pri;
- uint32_t flags;
-+ /*! Parked user that has already obtained a parking space */
-+ struct parkeduser *pu;
- };
-
--/* Park a call */
--static int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer,
-- struct ast_park_call_args *args)
-+static struct parkeduser *park_space_reserve(struct ast_channel *chan,
-+ struct ast_channel *peer, struct ast_park_call_args *args)
- {
- struct parkeduser *pu;
-- int i, x = -1, parking_range, parkingnum_copy;
-- struct ast_context *con;
-+ int i, parking_space = -1, parking_range;
- const char *parkinglotname = NULL;
- const char *parkingexten;
- struct ast_parkinglot *parkinglot = NULL;
-@@ -482,7 +586,7 @@
- /* Allocate memory for parking data */
- if (!(pu = ast_calloc(1, sizeof(*pu)))) {
- parkinglot_unref(parkinglot);
-- return -1;
-+ return NULL;
- }
-
- /* Lock parking list */
-@@ -496,21 +600,21 @@
- * limitation here. If extout was not numeric, we could permit
- * arbitrary non-numeric extensions.
- */
-- if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
-+ if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
- AST_LIST_UNLOCK(&parkinglot->parkings);
- parkinglot_unref(parkinglot);
- free(pu);
- ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
-- return 1; /* Continue execution if possible */
-+ return NULL;
- }
-- snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
-+ snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
-
- if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
- AST_LIST_UNLOCK(&parkinglot->parkings);
- parkinglot_unref(parkinglot);
- ast_free(pu);
- ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
-- return 1; /* Continue execution if possible */
-+ return NULL;
- }
- } else {
- int start;
-@@ -538,7 +642,7 @@
- }
-
- if (!cur || i == start - 1) {
-- x = i;
-+ parking_space = i;
- break;
- }
- }
-@@ -548,13 +652,37 @@
- ast_free(pu);
- AST_LIST_UNLOCK(&parkinglot->parkings);
- parkinglot_unref(parkinglot);
-- return -1;
-+ return NULL;
- }
- /* Set pointer for next parking */
- if (parkinglot->parkfindnext)
-- parkinglot->parking_offset = x - parkinglot->parking_start + 1;
-- snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
-+ parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
-+ snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
- }
-+
-+ pu->notquiteyet = 1;
-+ pu->parkingnum = parking_space;
-+ pu->parkinglot = parkinglot;
-+ AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
-+ parkinglot_unref(parkinglot);
-+
-+ return pu;
-+}
-+
-+/* Park a call */
-+static int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
-+{
-+ struct ast_context *con;
-+ int parkingnum_copy;
-+ struct parkeduser *pu = args->pu;
-+ const char *event_from;
-+
-+ if (pu == NULL)
-+ pu = park_space_reserve(chan, peer, args);
-+ if (pu == NULL)
-+ return 1; /* Continue execution if possible */
-+
-+ snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
-
- chan->appl = "Parked Call";
- chan->data = NULL;
-@@ -567,18 +695,16 @@
- ast_indicate(pu->chan, AST_CONTROL_RINGING);
- } else {
- ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
-- S_OR(parkinglot->mohclass, NULL),
-- !ast_strlen_zero(parkinglot->mohclass) ? strlen(parkinglot->mohclass) + 1 : 0);
-+ S_OR(pu->parkinglot->mohclass, NULL),
-+ !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
- }
- }
-
- pu->start = ast_tvnow();
-- pu->parkingnum = x;
-- pu->parkinglot = parkinglot;
-- pu->parkingtime = (args->timeout > 0) ? args->timeout : parkinglot->parkingtime;
-+ pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
- parkingnum_copy = pu->parkingnum;
- if (args->extout)
-- *(args->extout) = x;
-+ *(args->extout) = pu->parkingnum;
-
- if (peer) {
- /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
-@@ -616,16 +742,21 @@
- pu->priority = pu->priority ? pu->priority :
- (chan->macropriority ? chan->macropriority : chan->priority);
-
-- AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
-+ /* If parking a channel directly, don't quiet yet get parking running on it.
-+ * All parking lot entries are put into the parking lot with notquiteyet on. */
-+ if (peer != chan)
-+ pu->notquiteyet = 0;
-
-- /* If parking a channel directly, don't quiet yet get parking running on it */
-- if (peer == chan)
-- pu->notquiteyet = 1;
--
- /* Wake up the (presumably select()ing) thread */
- pthread_kill(parking_thread, SIGURG);
-- ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
-+ ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
-
-+ if (peer) {
-+ event_from = peer->name;
-+ } else {
-+ event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
-+ }
-+
- manager_event(EVENT_FLAG_CALL, "ParkedCall",
- "Exten: %s\r\n"
- "Channel: %s\r\n"
-@@ -635,7 +766,7 @@
- "CallerIDNum: %s\r\n"
- "CallerIDName: %s\r\n"
- "Uniqueid: %s\r\n",
-- pu->parkingexten, pu->chan->name, pu->parkinglot->name, peer ? peer->name : "",
-+ pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
- (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
- S_OR(pu->chan->cid.cid_num, "<unknown>"),
- S_OR(pu->chan->cid.cid_name, "<unknown>"),
-@@ -647,15 +778,15 @@
- ast_adsi_unload_session(peer);
- }
-
-- con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar);
-+ con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
- if (!con) /* Still no context? Bad */
-- ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
-+ ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
- if (con) {
- if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
-- notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_INUSE);
-+ notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
- }
-
-- AST_LIST_UNLOCK(&parkinglot->parkings);
-+ AST_LIST_UNLOCK(&pu->parkinglot->parkings);
-
- /* Only say number if it's a number and the channel hasn't been masqueraded away */
- if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
-@@ -668,8 +799,8 @@
- if (peer == chan) { /* pu->notquiteyet = 1 */
- /* Wake up parking thread if we're really done */
- ast_indicate_data(pu->chan, AST_CONTROL_HOLD,
-- S_OR(parkinglot->mohclass, NULL),
-- !ast_strlen_zero(parkinglot->mohclass) ? strlen(parkinglot->mohclass) + 1 : 0);
-+ S_OR(pu->parkinglot->mohclass, NULL),
-+ !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
- pu->notquiteyet = 0;
- pthread_kill(parking_thread, SIGURG);
- }
-@@ -691,10 +822,21 @@
- {
- struct ast_channel *chan;
- struct ast_frame *f;
-- char *orig_chan_name = NULL;
- int park_status;
- struct ast_park_call_args park_args = {0,};
-
-+ if (!args) {
-+ args = &park_args;
-+ args->timeout = timeout;
-+ args->extout = extout;
-+ }
-+
-+ if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
-+ if (peer)
-+ ast_stream_and_wait(peer, "beeperr", "");
-+ return AST_FEATURE_RETURN_PARKFAILED;
-+ }
-+
- /* Make a new, fake channel that we'll use to masquerade in the real one */
- if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
- ast_log(LOG_WARNING, "Unable to create parked channel\n");
-@@ -713,20 +855,13 @@
- if ((f = ast_read(chan)))
- ast_frfree(f);
-
-- if (!play_announcement) {
-- orig_chan_name = ast_strdupa(chan->name);
-- }
--
- if (peer == rchan) {
- peer = chan;
- }
-
-- if (!args) {
-- args = &park_args;
-- args->timeout = timeout,
-- args->extout = extout,
-- args->orig_chan_name = orig_chan_name;
-- }
-+ if (!play_announcement && args == &park_args) {
-+ args->orig_chan_name = ast_strdupa(chan->name);
-+ }
-
- park_status = ast_park_call_full(chan, peer, args);
- if (park_status == 1) {
-@@ -808,12 +943,11 @@
- res = ast_safe_sleep(chan, 1000);
-
- if (!res) { /* one direction used to call park_call.... */
-- masq_park_call_announce(parkee, parker, 0, NULL);
-- res = 0; /* PBX should hangup zombie channel */
-+ res = masq_park_call_announce(parkee, parker, 0, NULL);
-+ /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
- }
-
- return res;
--
- }
-
- /*! \brief Play message to both caller and callee in bridged call, plays synchronously, autoservicing the
-@@ -1117,7 +1251,7 @@
- struct ast_channel *transferee;
- const char *transferer_real_context;
- char xferto[256];
-- int res;
-+ int res, parkstatus = 0;
-
- set_peers(&transferer, &transferee, peer, chan, sense);
- transferer_real_context = real_ctx(transferer, transferee);
-@@ -1126,7 +1260,7 @@
- ast_indicate(transferee, AST_CONTROL_HOLD);
-
- memset(xferto, 0, sizeof(xferto));
--
-+
- /* Transfer */
- res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
- if (res < 0) {
-@@ -1146,14 +1280,14 @@
- res = finishup(transferee);
- if (res)
- res = -1;
-- else if (!masq_park_call_announce(transferee, transferer, 0, NULL)) { /* success */
-+ else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) { /* success */
- /* We return non-zero, but tell the PBX not to hang the channel when
- the thread dies -- We have to be careful now though. We are responsible for
- hanging up the channel, else it will never be hung up! */
-
- return 0;
- } else {
-- ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
-+ ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
- }
- /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
- } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
-@@ -1196,7 +1330,7 @@
- } else {
- ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
- }
-- if (ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
-+ if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
- finishup(transferee);
- return -1;
- }
-@@ -1256,6 +1390,9 @@
- struct ast_bridge_config bconfig;
- struct ast_frame *f;
- int l;
-+ struct ast_party_connected_line connected_line = {{0,},};
-+ struct ast_datastore *features_datastore;
-+ struct ast_dial_features *dialfeatures = NULL;
-
- ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
- set_peers(&transferer, &transferee, peer, chan, sense);
-@@ -1296,6 +1433,13 @@
- return AST_FEATURE_RETURN_SUCCESS;
- }
-
-+ /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
-+ * the different variables for handling this properly with a builtin_atxfer */
-+ if (!strcmp(xferto, ast_parking_ext())) {
-+ finishup(transferee);
-+ return builtin_parkcall(chan, peer, config, code, sense, data);
-+ }
-+
- l = strlen(xferto);
- snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
-
-@@ -1338,6 +1482,15 @@
- memset(&bconfig,0,sizeof(struct ast_bridge_config));
- ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
- ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
-+ /* We need to get the transferer's connected line information copied
-+ * at this point because he is likely to hang up during the bridge with
-+ * newchan. This info will be used down below before bridging the
-+ * transferee and newchan
-+ *
-+ * As a result, we need to be sure to free this data before returning
-+ * or overwriting it.
-+ */
-+ ast_party_connected_line_copy(&connected_line, &transferer->connected);
- res = ast_bridge_call(transferer, newchan, &bconfig);
- if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
- ast_hangup(newchan);
-@@ -1345,10 +1498,12 @@
- ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
- finishup(transferee);
- transferer->_softhangup = 0;
-+ ast_party_connected_line_free(&connected_line);
- return AST_FEATURE_RETURN_SUCCESS;
- }
- if (check_compat(transferee, newchan)) {
- finishup(transferee);
-+ ast_party_connected_line_free(&connected_line);
- return -1;
- }
- ast_indicate(transferee, AST_CONTROL_UNHOLD);
-@@ -1359,11 +1514,13 @@
- || ast_check_hangup(transferee)
- || ast_check_hangup(newchan)) {
- ast_hangup(newchan);
-+ ast_party_connected_line_free(&connected_line);
- return -1;
- }
- xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
- if (!xferchan) {
- ast_hangup(newchan);
-+ ast_party_connected_line_free(&connected_line);
- return -1;
- }
- /* Make formats okay */
-@@ -1383,8 +1540,33 @@
- if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
- ast_hangup(xferchan);
- ast_hangup(newchan);
-+ ast_party_connected_line_free(&connected_line);
- return -1;
- }
-+
-+ ast_channel_lock(newchan);
-+ if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
-+ dialfeatures = features_datastore->data;
-+ }
-+ ast_channel_unlock(newchan);
-+
-+ if (dialfeatures) {
-+ /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
-+ I don't currently understand, the abilities of newchan seem to be stored on the caller side */
-+ ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
-+ dialfeatures = NULL;
-+ }
-+
-+ ast_channel_lock(xferchan);
-+ if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
-+ dialfeatures = features_datastore->data;
-+ }
-+ ast_channel_unlock(xferchan);
-+
-+ if (dialfeatures) {
-+ ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
-+ }
-+
- tobj->chan = newchan;
- tobj->peer = xferchan;
- tobj->bconfig = *config;
-@@ -1393,6 +1575,19 @@
- tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
- }
-
-+ /* Due to a limitation regarding when callerID is set on a Local channel,
-+ * we use the transferer's connected line information here.
-+ */
-+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-+ ast_connected_line_update(xferchan, &connected_line);
-+ /* We need to free the allocated information in connected_line before overwriting
-+ * the info with the callerid of xferchan. Otherwise, there would be a memory leak
-+ */
-+ ast_party_connected_line_free(&connected_line);
-+ ast_party_connected_line_collect_caller(&connected_line, &xferchan->cid);
-+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-+ ast_connected_line_update(newchan, &connected_line);
-+
- if (ast_stream_and_wait(newchan, xfersound, ""))
- ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
- ast_bridge_call_thread_launch(tobj);
-@@ -1489,11 +1684,18 @@
- tobj->chan = newchan;
- tobj->peer = xferchan;
- tobj->bconfig = *config;
--
-+
- if (tobj->bconfig.end_bridge_callback_data_fixup) {
- tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
- }
-
-+ ast_party_connected_line_collect_caller(&connected_line, &newchan->cid);
-+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-+ ast_connected_line_update(xferchan, &connected_line);
-+ ast_party_connected_line_collect_caller(&connected_line, &xferchan->cid);
-+ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-+ ast_connected_line_update(newchan, &connected_line);
-+
- if (ast_stream_and_wait(newchan, xfersound, ""))
- ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
- ast_bridge_call_thread_launch(tobj);
-@@ -1837,6 +2039,7 @@
- !ast_strlen_zero(builtin_features[x].exten)) {
- /* Feature is up for consideration */
- if (!strcmp(builtin_features[x].exten, code)) {
-+ ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
- res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
- feature_detected = 1;
- break;
-@@ -1963,148 +2166,154 @@
- struct ast_channel *monitor_chans[2];
- struct ast_channel *active_channel;
- int res = 0, ready = 0;
-+ struct timeval started;
-+ int x, len = 0;
-+ char *disconnect_code = NULL, *dialed_code = NULL;
-
-- if ((chan = ast_request(type, format, data, &cause))) {
-- ast_set_callerid(chan, cid_num, cid_name, cid_num);
-- ast_string_field_set(chan, language, language);
-- ast_channel_inherit_variables(caller, chan);
-- pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
--
-- if (!ast_call(chan, data, timeout)) {
-- struct timeval started;
-- int x, len = 0;
-- char *disconnect_code = NULL, *dialed_code = NULL;
-+ if (!(chan = ast_request(type, format, data, &cause))) {
-+ ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
-+ switch(cause) {
-+ case AST_CAUSE_BUSY:
-+ state = AST_CONTROL_BUSY;
-+ break;
-+ case AST_CAUSE_CONGESTION:
-+ state = AST_CONTROL_CONGESTION;
-+ break;
-+ }
-+ goto done;
-+ }
-
-- ast_indicate(caller, AST_CONTROL_RINGING);
-- /* support dialing of the featuremap disconnect code while performing an attended tranfer */
-- ast_rwlock_rdlock(&features_lock);
-- for (x = 0; x < FEATURES_COUNT; x++) {
-- if (strcasecmp(builtin_features[x].sname, "disconnect"))
-- continue;
-+ ast_set_callerid(chan, cid_num, cid_name, cid_num);
-+ ast_string_field_set(chan, language, language);
-+ ast_channel_inherit_variables(caller, chan);
-+ pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
-+
-+ ast_copy_caller_to_connected(&chan->connected, &caller->cid);
-+
-+ if (ast_call(chan, data, timeout)) {
-+ ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
-+ goto done;
-+ }
-+
-+ ast_indicate(caller, AST_CONTROL_RINGING);
-+ /* support dialing of the featuremap disconnect code while performing an attended tranfer */
-+ ast_rwlock_rdlock(&features_lock);
-+ for (x = 0; x < FEATURES_COUNT; x++) {
-+ if (strcasecmp(builtin_features[x].sname, "disconnect"))
-+ continue;
-
-- disconnect_code = builtin_features[x].exten;
-- len = strlen(disconnect_code) + 1;
-- dialed_code = alloca(len);
-- memset(dialed_code, 0, len);
-- break;
-- }
-- ast_rwlock_unlock(&features_lock);
-- x = 0;
-- started = ast_tvnow();
-- to = timeout;
-+ disconnect_code = builtin_features[x].exten;
-+ len = strlen(disconnect_code) + 1;
-+ dialed_code = alloca(len);
-+ memset(dialed_code, 0, len);
-+ break;
-+ }
-+ ast_rwlock_unlock(&features_lock);
-+ x = 0;
-+ started = ast_tvnow();
-+ to = timeout;
-
-- ast_poll_channel_add(caller, chan);
-+ ast_poll_channel_add(caller, chan);
-
-- while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
-- struct ast_frame *f = NULL;
-+ while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
-+ struct ast_frame *f = NULL;
-
-- monitor_chans[0] = caller;
-- monitor_chans[1] = chan;
-- active_channel = ast_waitfor_n(monitor_chans, 2, &to);
-+ monitor_chans[0] = caller;
-+ monitor_chans[1] = chan;
-+ active_channel = ast_waitfor_n(monitor_chans, 2, &to);
-
-- /* see if the timeout has been violated */
-- if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
-- state = AST_CONTROL_UNHOLD;
-- ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
-- break; /*doh! timeout*/
-+ /* see if the timeout has been violated */
-+ if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
-+ state = AST_CONTROL_UNHOLD;
-+ ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
-+ break; /*doh! timeout*/
-+ }
-+
-+ if (!active_channel)
-+ continue;
-+
-+ if (chan && (chan == active_channel)){
-+ f = ast_read(chan);
-+ if (f == NULL) { /*doh! where'd he go?*/
-+ state = AST_CONTROL_HANGUP;
-+ res = 0;
-+ break;
-+ }
-+
-+ if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
-+ if (f->subclass == AST_CONTROL_RINGING) {
-+ state = f->subclass;
-+ ast_verb(3, "%s is ringing\n", chan->name);
-+ ast_indicate(caller, AST_CONTROL_RINGING);
-+ } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
-+ state = f->subclass;
-+ ast_verb(3, "%s is busy\n", chan->name);
-+ ast_indicate(caller, AST_CONTROL_BUSY);
-+ ast_frfree(f);
-+ f = NULL;
-+ break;
-+ } else if (f->subclass == AST_CONTROL_ANSWER) {
-+ /* This is what we are hoping for */
-+ state = f->subclass;
-+ ast_frfree(f);
-+ f = NULL;
-+ ready=1;
-+ break;
-+ } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
-+ ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
-+ } else if (f->subclass != -1) {
-+ ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
- }
-+ /* else who cares */
-+ }
-
-- if (!active_channel)
-- continue;
--
-- if (chan && (chan == active_channel)){
-- f = ast_read(chan);
-- if (f == NULL) { /*doh! where'd he go?*/
-- state = AST_CONTROL_HANGUP;
-- res = 0;
-+ } else if (caller && (active_channel == caller)) {
-+ f = ast_read(caller);
-+ if (f == NULL) { /*doh! where'd he go?*/
-+ if (!igncallerstate) {
-+ if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
-+ /* make this a blind transfer */
-+ ready = 1;
- break;
- }
--
-- if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
-- if (f->subclass == AST_CONTROL_RINGING) {
-- state = f->subclass;
-- ast_verb(3, "%s is ringing\n", chan->name);
-- ast_indicate(caller, AST_CONTROL_RINGING);
-- } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
-- state = f->subclass;
-- ast_verb(3, "%s is busy\n", chan->name);
-- ast_indicate(caller, AST_CONTROL_BUSY);
-- ast_frfree(f);
-- f = NULL;
-- break;
-- } else if (f->subclass == AST_CONTROL_ANSWER) {
-- /* This is what we are hoping for */
-- state = f->subclass;
-- ast_frfree(f);
-- f = NULL;
-- ready=1;
-- break;
-- } else if (f->subclass != -1) {
-- ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
-- }
-- /* else who cares */
-+ state = AST_CONTROL_HANGUP;
-+ res = 0;
-+ break;
-+ }
-+ } else {
-+
-+ if (f->frametype == AST_FRAME_DTMF) {
-+ dialed_code[x++] = f->subclass;
-+ dialed_code[x] = '\0';
-+ if (strlen(dialed_code) == len) {
-+ x = 0;
-+ } else if (x && strncmp(dialed_code, disconnect_code, x)) {
-+ x = 0;
-+ dialed_code[x] = '\0';
- }
--
-- } else if (caller && (active_channel == caller)) {
-- f = ast_read(caller);
-- if (f == NULL) { /*doh! where'd he go?*/
-- if (!igncallerstate) {
-- if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
-- /* make this a blind transfer */
-- ready = 1;
-- break;
-- }
-- state = AST_CONTROL_HANGUP;
-- res = 0;
-- break;
-- }
-- } else {
--
-- if (f->frametype == AST_FRAME_DTMF) {
-- dialed_code[x++] = f->subclass;
-- dialed_code[x] = '\0';
-- if (strlen(dialed_code) == len) {
-- x = 0;
-- } else if (x && strncmp(dialed_code, disconnect_code, x)) {
-- x = 0;
-- dialed_code[x] = '\0';
-- }
-- if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
-- /* Caller Canceled the call */
-- state = AST_CONTROL_UNHOLD;
-- ast_frfree(f);
-- f = NULL;
-- break;
-- }
-- }
-+ if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
-+ /* Caller Canceled the call */
-+ state = AST_CONTROL_UNHOLD;
-+ ast_frfree(f);
-+ f = NULL;
-+ break;
- }
- }
-- if (f)
-- ast_frfree(f);
-- } /* end while */
-+ }
-+ }
-+ if (f)
-+ ast_frfree(f);
-+ } /* end while */
-
-- ast_poll_channel_del(caller, chan);
--
-- } else
-- ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
-- } else {
-- ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
-- switch(cause) {
-- case AST_CAUSE_BUSY:
-- state = AST_CONTROL_BUSY;
-- break;
-- case AST_CAUSE_CONGESTION:
-- state = AST_CONTROL_CONGESTION;
-- break;
-- }
-- }
--
-+ ast_poll_channel_del(caller, chan);
-+
-+done:
- ast_indicate(caller, -1);
- if (chan && ready) {
- if (chan->_state == AST_STATE_UP)
- state = AST_CONTROL_ANSWER;
- res = 0;
-- } else if(chan) {
-+ } else if (chan) {
- res = -1;
- ast_hangup(chan);
- chan = NULL;
-@@ -2132,6 +2341,96 @@
- return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
- }
-
-+static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
-+{
-+ const char *feature;
-+
-+ if (ast_strlen_zero(features)) {
-+ return;
-+ }
-+
-+ for (feature = features; *feature; feature++) {
-+ switch (*feature) {
-+ case 'T' :
-+ case 't' :
-+ ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
-+ break;
-+ case 'K' :
-+ case 'k' :
-+ ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
-+ break;
-+ case 'H' :
-+ case 'h' :
-+ ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
-+ break;
-+ case 'W' :
-+ case 'w' :
-+ ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
-+ break;
-+ default :
-+ ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
-+ }
-+ }
-+}
-+
-+static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
-+{
-+ struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
-+ struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
-+
-+ ast_channel_lock(caller);
-+ ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
-+ ast_channel_unlock(caller);
-+ if (!ds_caller_features) {
-+ if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
-+ ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
-+ return;
-+ }
-+ if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
-+ ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
-+ ast_datastore_free(ds_caller_features);
-+ return;
-+ }
-+ ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
-+ caller_features->is_caller = 1;
-+ ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
-+ ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
-+ ds_caller_features->data = caller_features;
-+ ast_channel_lock(caller);
-+ ast_channel_datastore_add(caller, ds_caller_features);
-+ ast_channel_unlock(caller);
-+ } else {
-+ /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
-+ * flags over from the atxfer to the caller */
-+ return;
-+ }
-+
-+ ast_channel_lock(callee);
-+ ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
-+ ast_channel_unlock(callee);
-+ if (!ds_callee_features) {
-+ if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
-+ ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
-+ return;
-+ }
-+ if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
-+ ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
-+ ast_datastore_free(ds_callee_features);
-+ return;
-+ }
-+ ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
-+ callee_features->is_caller = 0;
-+ ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
-+ ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
-+ ds_callee_features->data = callee_features;
-+ ast_channel_lock(callee);
-+ ast_channel_datastore_add(callee, ds_callee_features);
-+ ast_channel_unlock(callee);
-+ }
-+
-+ return;
-+}
-+
- /*!
- * \brief bridge the call and set CDR
- * \param chan,peer,config
-@@ -2176,6 +2475,9 @@
- pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
- }
-
-+ set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
-+ add_features_datastores(chan, peer, config);
-+
- /* This is an interesting case. One example is if a ringing channel gets redirected to
- * an extension that picks up a parked call. This will make sure that the call taken
- * out of parking gets told that the channel it just got bridged to is still ringing. */
-@@ -2199,7 +2501,7 @@
- pbx_exec(src, monitor_app, tmp);
- }
- }
--
-+
- set_config_flags(chan, peer, config);
- config->firstpass = 1;
-
-@@ -2266,13 +2568,28 @@
- }
- for (;;) {
- struct ast_channel *other; /* used later */
-+
-+ res = ast_channel_bridge(chan, peer, config, &f, &who);
-
-- res = ast_channel_bridge(chan, peer, config, &f, &who);
--
-- if (config->feature_timer) {
-+ /* When frame is not set, we are probably involved in a situation
-+ where we've timed out.
-+ When frame is set, we'll come this code twice; once for DTMF_BEGIN
-+ and also for DTMF_END. If we flow into the following 'if' for both, then
-+ our wait times are cut in half, as both will subtract from the
-+ feature_timer. Not good!
-+ */
-+ if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
- /* Update time limit for next pass */
- diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
-- config->feature_timer -= diff;
-+ if (res == AST_BRIDGE_RETRY) {
-+ /* The feature fully timed out but has not been updated. Skip
-+ * the potential round error from the diff calculation and
-+ * explicitly set to expired. */
-+ config->feature_timer = -1;
-+ } else {
-+ config->feature_timer -= diff;
-+ }
-+
- if (hasfeatures) {
- /* Running on backup config, meaning a feature might be being
- activated, but that's no excuse to keep things going
-@@ -2608,6 +2925,50 @@
- );
- }
-
-+static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
-+{
-+ int i = 0;
-+ enum {
-+ OPT_CALLEE_REDIRECT = 't',
-+ OPT_CALLER_REDIRECT = 'T',
-+ OPT_CALLEE_AUTOMON = 'w',
-+ OPT_CALLER_AUTOMON = 'W',
-+ OPT_CALLEE_DISCONNECT = 'h',
-+ OPT_CALLER_DISCONNECT = 'H',
-+ OPT_CALLEE_PARKCALL = 'k',
-+ OPT_CALLER_PARKCALL = 'K',
-+ };
-+
-+ memset(options, 0, len);
-+ if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
-+ options[i++] = OPT_CALLER_REDIRECT;
-+ }
-+ if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
-+ options[i++] = OPT_CALLER_AUTOMON;
-+ }
-+ if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
-+ options[i++] = OPT_CALLER_DISCONNECT;
-+ }
-+ if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
-+ options[i++] = OPT_CALLER_PARKCALL;
-+ }
-+
-+ if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
-+ options[i++] = OPT_CALLEE_REDIRECT;
-+ }
-+ if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
-+ options[i++] = OPT_CALLEE_AUTOMON;
-+ }
-+ if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
-+ options[i++] = OPT_CALLEE_DISCONNECT;
-+ }
-+ if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
-+ options[i++] = OPT_CALLEE_PARKCALL;
-+ }
-+
-+ return options;
-+}
-+
- /*! \brief Run management on parkinglots, called once per parkinglot */
- int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
- {
-@@ -2665,10 +3026,13 @@
- peername += 7;
- }
-
-- if (dialfeatures)
-- snprintf(returnexten, sizeof(returnexten), "%s,,%s", peername, dialfeatures->options);
-- else /* Existing default */
-- snprintf(returnexten, sizeof(returnexten), "%s,,t", peername);
-+ if (dialfeatures) {
-+ char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
-+ snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
-+ } else { /* Existing default */
-+ ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
-+ snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
-+ }
-
- ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
- }
-@@ -2703,6 +3067,7 @@
- } else
- ast_log(LOG_WARNING, "Whoa, no parking context?\n");
- AST_LIST_REMOVE_CURRENT(list);
-+ free(pu);
- } else { /* still within parking time, process descriptors */
- for (x = 0; x < AST_MAX_FDS; x++) {
- struct ast_frame *f;
-@@ -2737,6 +3102,7 @@
- } else
- ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
- AST_LIST_REMOVE_CURRENT(list);
-+ free(pu);
- break;
- } else {
- /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
-@@ -2988,8 +3354,11 @@
- //ASTOBJ_UNLOCK(parkinglot);
-
- if (peer) {
-+ struct ast_datastore *features_datastore;
-+ struct ast_dial_features *dialfeatures = NULL;
-+
- /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
--
-+
- if (!ast_strlen_zero(courtesytone)) {
- int error = 0;
- ast_indicate(peer, AST_CONTROL_UNHOLD);
-@@ -3014,7 +3383,7 @@
- return -1;
- }
- } else
-- ast_indicate(peer, AST_CONTROL_UNHOLD);
-+ ast_indicate(peer, AST_CONTROL_UNHOLD);
-
- res = ast_channel_make_compatible(chan, peer);
- if (res < 0) {
-@@ -3029,14 +3398,43 @@
- pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
- ast_cdr_setdestchan(chan->cdr, peer->name);
- memset(&config, 0, sizeof(struct ast_bridge_config));
-- if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
-+
-+ /* Get datastore for peer and apply it's features to the callee side of the bridge config */
-+ ast_channel_lock(peer);
-+ if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
-+ dialfeatures = features_datastore->data;
-+ }
-+ ast_channel_unlock(peer);
-+
-+ if (dialfeatures) {
-+ ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL);
-+ }
-+
-+ if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
-- if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH))
-+ }
-+ if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
-- if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
-+ }
-+ if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
-- if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH))
-+ }
-+ if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
-+ }
-+ if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
-+ ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
-+ }
-+ if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
-+ ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
-+ }
-+ if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
-+ ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
-+ }
-+ if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
-+ ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
-+ }
-+
- res = ast_bridge_call(chan, peer, &config);
-
- pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
-@@ -3277,12 +3675,16 @@
- courtesytone[0] = '\0';
- strcpy(xfersound, "beep");
- strcpy(xferfailsound, "pbx-invalid");
-+ pickupsound[0] = '\0';
-+ pickupfailsound[0] = '\0';
- adsipark = 0;
- comebacktoorigin = 1;
-
- default_parkinglot->parkaddhints = 0;
- default_parkinglot->parkedcalltransfers = 0;
- default_parkinglot->parkedcallreparking = 0;
-+ default_parkinglot->parkedcallrecording = 0;
-+ default_parkinglot->parkedcallhangup = 0;
-
- transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
- featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
-@@ -3292,7 +3694,7 @@
- atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
-
- cfg = ast_config_load2("features.conf", "features", config_flags);
-- if (!cfg) {
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING,"Could not load features.conf\n");
- return 0;
- }
-@@ -3334,6 +3736,20 @@
- default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
- else if (!strcasecmp(var->value, "callee"))
- default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
-+ } else if (!strcasecmp(var->name, "parkedcallhangup")) {
-+ if (!strcasecmp(var->value, "both"))
-+ default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
-+ else if (!strcasecmp(var->value, "caller"))
-+ default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
-+ else if (!strcasecmp(var->value, "callee"))
-+ default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
-+ } else if (!strcasecmp(var->name, "parkedcallrecording")) {
-+ if (!strcasecmp(var->value, "both"))
-+ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
-+ else if (!strcasecmp(var->value, "caller"))
-+ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
-+ else if (!strcasecmp(var->value, "callee"))
-+ default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
- } else if (!strcasecmp(var->name, "adsipark")) {
- adsipark = ast_true(var->value);
- } else if (!strcasecmp(var->name, "transferdigittimeout")) {
-@@ -3381,6 +3797,10 @@
- ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
- } else if (!strcasecmp(var->name, "pickupexten")) {
- ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
-+ } else if (!strcasecmp(var->name, "pickupsound")) {
-+ ast_copy_string(pickupsound, var->value, sizeof(pickupsound));
-+ } else if (!strcasecmp(var->name, "pickupfailsound")) {
-+ ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound));
- } else if (!strcasecmp(var->name, "comebacktoorigin")) {
- comebacktoorigin = ast_true(var->value);
- } else if (!strcasecmp(var->name, "parkedmusicclass")) {
-@@ -3697,55 +4117,69 @@
- struct ast_bridge_thread_obj *tobj = NULL;
-
- /* make sure valid channels were specified */
-- if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
-- chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
-- chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
-- if (chana)
-- ast_channel_unlock(chana);
-- if (chanb)
-- ast_channel_unlock(chanb);
--
-- /* send errors if any of the channels could not be found/locked */
-- if (!chana) {
-- char buf[256];
-- snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
-- astman_send_error(s, m, buf);
-- return 0;
-- }
-- if (!chanb) {
-- char buf[256];
-- snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
-- astman_send_error(s, m, buf);
-- return 0;
-- }
-- } else {
-+ if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
- astman_send_error(s, m, "Missing channel parameter in request");
- return 0;
- }
-
-+ /* The same code must be executed for chana and chanb. To avoid a
-+ * theoretical deadlock, this code is separated so both chana and chanb will
-+ * not hold locks at the same time. */
-+
-+ /* Start with chana */
-+ chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
-+
-+ /* send errors if any of the channels could not be found/locked */
-+ if (!chana) {
-+ char buf[256];
-+ snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
-+ astman_send_error(s, m, buf);
-+ return 0;
-+ }
-+
- /* Answer the channels if needed */
- if (chana->_state != AST_STATE_UP)
- ast_answer(chana);
-- if (chanb->_state != AST_STATE_UP)
-- ast_answer(chanb);
-
- /* create the placeholder channels and grab the other channels */
- if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
- NULL, NULL, 0, "Bridge/%s", chana->name))) {
- astman_send_error(s, m, "Unable to create temporary channel!");
-+ ast_channel_unlock(chana);
- return 1;
- }
-
-+ do_bridge_masquerade(chana, tmpchana);
-+ ast_channel_unlock(chana);
-+ chana = NULL;
-+
-+ /* now do chanb */
-+ chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
-+ /* send errors if any of the channels could not be found/locked */
-+ if (!chanb) {
-+ char buf[256];
-+ snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
-+ ast_hangup(tmpchana);
-+ astman_send_error(s, m, buf);
-+ return 0;
-+ }
-+
-+ /* Answer the channels if needed */
-+ if (chanb->_state != AST_STATE_UP)
-+ ast_answer(chanb);
-+
-+ /* create the placeholder channels and grab the other channels */
- if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
- NULL, NULL, 0, "Bridge/%s", chanb->name))) {
- astman_send_error(s, m, "Unable to create temporary channels!");
-- ast_channel_free(tmpchana);
-+ ast_hangup(tmpchana);
-+ ast_channel_unlock(chanb);
- return 1;
- }
-+ do_bridge_masquerade(chanb, tmpchanb);
-+ ast_channel_unlock(chanb);
-+ chanb = NULL;
-
-- do_bridge_masquerade(chana, tmpchana);
-- do_bridge_masquerade(chanb, tmpchanb);
--
- /* make the channels compatible, send error if we fail doing so */
- if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
- ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
-@@ -3767,7 +4201,7 @@
- tobj->chan = tmpchana;
- tobj->peer = tmpchanb;
- tobj->return_to_pbx = 1;
--
-+
- if (ast_true(playtone)) {
- if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
- if (ast_waitstream(tmpchanb, "") < 0)
-@@ -3972,6 +4406,18 @@
- return 0;
- }
-
-+static int find_channel_by_group(struct ast_channel *c, void *data) {
-+ struct ast_channel *chan = data;
-+
-+ return !c->pbx &&
-+ /* Accessing 'chan' here is safe without locking, because there is no way for
-+ the channel do disappear from under us at this point. pickupgroup *could*
-+ change while we're here, but that isn't a problem. */
-+ (c != chan) &&
-+ (chan->pickupgroup & c->callgroup) &&
-+ ((c->_state == AST_STATE_RINGING) || (c->_state == AST_STATE_RING));
-+}
-+
- /*!
- * \brief Pickup a call
- * \param chan channel that initiated pickup.
-@@ -3982,21 +4428,22 @@
- */
- int ast_pickup_call(struct ast_channel *chan)
- {
-- struct ast_channel *cur = NULL;
-- int res = -1;
-+ struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan);
-
-- while ((cur = ast_channel_walk_locked(cur)) != NULL) {
-- if (!cur->pbx &&
-- (cur != chan) &&
-- (chan->pickupgroup & cur->callgroup) &&
-- ((cur->_state == AST_STATE_RINGING) ||
-- (cur->_state == AST_STATE_RING))) {
-- break;
-- }
-- ast_channel_unlock(cur);
-- }
- if (cur) {
-+ struct ast_party_connected_line connected_caller;
-+
-+ int res = -1;
- ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
-+
-+ connected_caller = cur->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);
-+
- res = ast_answer(chan);
- if (res)
- ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
-@@ -4006,24 +4453,21 @@
- res = ast_channel_masquerade(cur, chan);
- if (res)
- ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */
-+ if (!ast_strlen_zero(pickupsound)) {
-+ ast_stream_and_wait(cur, pickupsound, "");
-+ }
- ast_channel_unlock(cur);
-+ return res;
- } else {
- ast_debug(1, "No call pickup possible...\n");
-+ if (!ast_strlen_zero(pickupfailsound)) {
-+ ast_stream_and_wait(chan, pickupfailsound, "");
-+ }
- }
-- return res;
-+ return -1;
- }
-
- static char *app_bridge = "Bridge";
--static char *bridge_synopsis = "Bridge two channels";
--static char *bridge_descrip =
--"Usage: Bridge(channel[,options])\n"
--" Allows the ability to bridge two channels via the dialplan.\n"
--"The current channel is bridged to the specified 'channel'.\n"
--" Options:\n"
--" p - Play a courtesy tone to 'channel'.\n"
--"This application sets the following channel variable upon completion:\n"
--" BRIDGERESULT The result of the bridge attempt as a text string, one of\n"
--" SUCCESS | FAILURE | LOOP | NONEXISTENT | INCOMPATIBLE\n";
-
- enum {
- BRIDGE_OPT_PLAYTONE = (1 << 0),
-@@ -4092,7 +4536,6 @@
- pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
- return 0;
- }
-- ast_channel_unlock(current_dest_chan);
-
- /* answer the channel if needed */
- if (current_dest_chan->_state != AST_STATE_UP)
-@@ -4110,6 +4553,8 @@
- }
- do_bridge_masquerade(current_dest_chan, final_dest_chan);
-
-+ ast_channel_unlock(current_dest_chan);
-+
- /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
- /* try to make compatible, send error if we fail */
- if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
-@@ -4165,17 +4610,17 @@
- {
- int res;
-
-- ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
-+ ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
-
- parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
-
- if ((res = load_config()))
- return res;
-- ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features));
- ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
-- res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
-+ res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL);
- if (!res)
-- res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
-+ res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL);
- if (!res) {
- ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
- ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park);
-Index: main/http.c
-===================================================================
---- a/main/http.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/http.c (.../team/group/issue14292) (revision 178988)
-@@ -755,14 +755,14 @@
- * append a random variable to your GET request. Ex: 'something.html?r=109987734'
- */
- if (!contentlength) { /* opaque body ? just dump it hoping it is properly formatted */
-- fprintf(ser->f, "%s", out->str);
-+ fprintf(ser->f, "%s", ast_str_buffer(out));
- } else {
-- char *tmp = strstr(out->str, "\r\n\r\n");
-+ char *tmp = strstr(ast_str_buffer(out), "\r\n\r\n");
-
- if (tmp) {
- fprintf(ser->f, "Content-length: %d\r\n", contentlength);
- /* first write the header, then the body */
-- if (fwrite(out->str, 1, (tmp + 4 - out->str), ser->f) != tmp + 4 - out->str) {
-+ if (fwrite(ast_str_buffer(out), 1, (tmp + 4 - ast_str_buffer(out)), ser->f) != tmp + 4 - ast_str_buffer(out)) {
- ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
- }
- if (fwrite(tmp + 4, 1, contentlength, ser->f) != contentlength ) {
-@@ -858,7 +858,8 @@
- struct http_uri_redirect *redirect;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if ((cfg = ast_config_load2("http.conf", "http", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
-+ cfg = ast_config_load2("http.conf", "http", config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- return 0;
- }
-
-@@ -1023,7 +1024,7 @@
- {
- ast_http_uri_link(&statusuri);
- ast_http_uri_link(&staticuri);
-- ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
-
- return __ast_http_load(0);
- }
-Index: main/app.c
-===================================================================
---- a/main/app.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/app.c (.../team/group/issue14292) (revision 178988)
-@@ -33,6 +33,12 @@
- #include <regex.h>
- #include <sys/file.h> /* added this to allow to compile, sorry! */
- #include <signal.h>
-+#include <sys/time.h> /* for getrlimit(2) */
-+#include <sys/resource.h> /* for getrlimit(2) */
-+#include <stdlib.h> /* for closefrom(3) */
-+#ifdef HAVE_CAP
-+#include <sys/capability.h>
-+#endif /* HAVE_CAP */
-
- #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
- #include "asterisk/channel.h"
-@@ -44,7 +50,11 @@
- #include "asterisk/lock.h"
- #include "asterisk/indications.h"
- #include "asterisk/linkedlists.h"
-+#include "asterisk/threadstorage.h"
-
-+AST_THREADSTORAGE_PUBLIC(global_app_buf);
-+
-+
- #define MAX_OTHER_FORMATS 10
-
- static AST_RWLIST_HEAD_STATIC(groups, ast_group_info);
-@@ -65,21 +75,24 @@
- */
- int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
- {
-- struct tone_zone_sound *ts;
-+ struct ast_tone_zone_sound *ts;
- int res = 0, x = 0;
-
- if (maxlen > size)
- maxlen = size;
-
-- if (!timeout && chan->pbx)
-+ if (!timeout && chan->pbx) {
- timeout = chan->pbx->dtimeoutms / 1000.0;
-- else if (!timeout)
-+ } else if (!timeout) {
- timeout = 5;
-+ }
-
-- if ((ts = ast_get_indication_tone(chan->zone, "dial")) && ts->data[0])
-+ if ((ts = ast_get_indication_tone(chan->zone, "dial"))) {
- res = ast_playtones_start(chan, 0, ts->data, 0);
-- else
-+ ts = ast_tone_zone_sound_unref(ts);
-+ } else {
- ast_log(LOG_NOTICE, "Huh....? no dial for indications?\n");
-+ }
-
- for (x = strlen(collect); x < maxlen; ) {
- res = ast_waitfordigit(chan, timeout);
-@@ -1820,7 +1833,7 @@
- return 0;
- }
-
--int ast_get_encoded_str(const char *stream, char *result, size_t result_size)
-+char *ast_get_encoded_str(const char *stream, char *result, size_t result_size)
- {
- char *cur = result;
- size_t consumed;
-@@ -1830,23 +1843,56 @@
- stream += consumed;
- }
- *cur = '\0';
-+ return result;
-+}
-+
-+int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream)
-+{
-+ char next, *buf;
-+ size_t offset = 0;
-+ size_t consumed;
-+
-+ if (strchr(stream, '\\')) {
-+ while (!ast_get_encoded_char(stream, &next, &consumed)) {
-+ if (offset + 2 > ast_str_size(*str) && maxlen > -1) {
-+ ast_str_make_space(str, maxlen > 0 ? maxlen : (ast_str_size(*str) + 48) * 2 - 48);
-+ }
-+ if (offset + 2 > ast_str_size(*str)) {
-+ break;
-+ }
-+ buf = ast_str_buffer(*str);
-+ buf[offset++] = next;
-+ stream += consumed;
-+ }
-+ buf = ast_str_buffer(*str);
-+ buf[offset++] = '\0';
-+ ast_str_update(*str);
-+ } else {
-+ ast_str_set(str, maxlen, "%s", stream);
-+ }
- return 0;
- }
-
- void ast_close_fds_above_n(int n)
- {
-+#ifdef HAVE_CLOSEFROM
-+ closefrom(n + 1);
-+#else
- int x, null;
-+ struct rlimit rl;
-+ getrlimit(RLIMIT_NOFILE, &rl);
- null = open("/dev/null", O_RDONLY);
-- for (x = n + 1; x <= (null >= 8192 ? null : 8192); x++) {
-+ for (x = n + 1; x < rl.rlim_max; x++) {
- if (x != null) {
- /* Side effect of dup2 is that it closes any existing fd without error.
- * This prevents valgrind and other debugging tools from sending up
- * false error reports. */
-- dup2(null, x);
-+ while (dup2(null, x) < 0 && errno == EINTR);
- close(x);
- }
- }
- close(null);
-+#endif
- }
-
- int ast_safe_fork(int stop_reaper)
-@@ -1870,7 +1916,15 @@
- return pid;
- } else {
- /* Child */
-+#ifdef HAVE_CAP
-+ cap_t cap = cap_from_text("cap_net_admin-eip");
-
-+ if (cap_set_proc(cap)) {
-+ ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
-+ }
-+ cap_free(cap);
-+#endif
-+
- /* Before we unblock our signals, return our trapped signals back to the defaults */
- signal(SIGHUP, SIG_DFL);
- signal(SIGCHLD, SIG_DFL);
-Index: main/db.c
-===================================================================
---- a/main/db.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/db.c (.../team/group/issue14292) (revision 178988)
-@@ -662,7 +662,7 @@
- int astdb_init(void)
- {
- dbinit();
-- ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
- ast_manager_register("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget, "Get DB Entry");
- ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
- ast_manager_register("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel, "Delete DB Entry");
-Index: main/stdtime/localtime.c
-===================================================================
---- a/main/stdtime/localtime.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/stdtime/localtime.c (.../team/group/issue14292) (revision 178988)
-@@ -51,6 +51,9 @@
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <float.h>
-+#ifdef HAVE_INOTIFY
-+#include <sys/inotify.h>
-+#endif
-
- #include "private.h"
- #include "tzfile.h"
-@@ -147,6 +150,11 @@
- char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
- (2 * (MY_TZNAME_MAX + 1)))];
- struct lsinfo lsis[TZ_MAX_LEAPS];
-+#ifdef HAVE_INOTIFY
-+ int wd[2];
-+#else
-+ time_t mtime[2];
-+#endif
- AST_LIST_ENTRY(state) list;
- };
-
-@@ -217,6 +225,156 @@
- #define TZ_STRLEN_MAX 255
- #endif /* !defined TZ_STRLEN_MAX */
-
-+static pthread_t inotify_thread = AST_PTHREADT_NULL;
-+static ast_cond_t initialization;
-+static ast_mutex_t initialization_lock;
-+#ifdef HAVE_INOTIFY
-+static int inotify_fd = -1;
-+
-+static void *inotify_daemon(void *data)
-+{
-+ struct {
-+ struct inotify_event iev;
-+ char name[FILENAME_MAX + 1];
-+ } buf;
-+ ssize_t res;
-+ struct state *cur;
-+
-+ inotify_fd = inotify_init();
-+
-+ ast_mutex_lock(&initialization_lock);
-+ ast_cond_signal(&initialization);
-+ ast_mutex_unlock(&initialization_lock);
-+
-+ if (inotify_fd < 0) {
-+ ast_log(LOG_ERROR, "Cannot initialize file notification service: %s (%d)\n", strerror(errno), errno);
-+ inotify_thread = AST_PTHREADT_NULL;
-+ return NULL;
-+ }
-+
-+ for (;/*ever*/;) {
-+ /* This read should block, most of the time. */
-+ if ((res = read(inotify_fd, &buf, sizeof(buf))) < sizeof(buf.iev) && res > 0) {
-+ /* This should never happen */
-+ ast_log(LOG_ERROR, "Inotify read less than a full event (%zd < %zd)?!!\n", res, sizeof(buf.iev));
-+ break;
-+ } else if (res < 0) {
-+ if (errno == EINTR || errno == EAGAIN) {
-+ /* If read fails, then wait a bit, then continue */
-+ poll(NULL, 0, 10000);
-+ continue;
-+ }
-+ /* Sanity check -- this should never happen, either */
-+ ast_log(LOG_ERROR, "Inotify failed: %s\n", strerror(errno));
-+ break;
-+ }
-+ AST_LIST_LOCK(&zonelist);
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
-+ if (cur->wd[0] == buf.iev.wd || cur->wd[1] == buf.iev.wd) {
-+ AST_LIST_REMOVE_CURRENT(list);
-+ ast_free(cur);
-+ break;
-+ }
-+ }
-+ AST_LIST_TRAVERSE_SAFE_END
-+ AST_LIST_UNLOCK(&zonelist);
-+ }
-+ close(inotify_fd);
-+ inotify_thread = AST_PTHREADT_NULL;
-+ return NULL;
-+}
-+
-+static void add_notify(struct state *sp, const char *path)
-+{
-+ if (inotify_thread == AST_PTHREADT_NULL) {
-+ ast_cond_init(&initialization, NULL);
-+ ast_mutex_init(&initialization_lock);
-+ ast_mutex_lock(&initialization_lock);
-+ if (!(ast_pthread_create_background(&inotify_thread, NULL, inotify_daemon, NULL))) {
-+ /* Give the thread a chance to initialize */
-+ ast_cond_wait(&initialization, &initialization_lock);
-+ } else {
-+ ast_log(LOG_ERROR, "Unable to start notification thread\n");
-+ ast_mutex_unlock(&initialization_lock);
-+ return;
-+ }
-+ ast_mutex_unlock(&initialization_lock);
-+ }
-+
-+ if (inotify_fd > -1) {
-+ char fullpath[FILENAME_MAX + 1] = "";
-+ if (readlink(path, fullpath, sizeof(fullpath) - 1) != -1) {
-+ /* If file the symlink points to changes */
-+ sp->wd[1] = inotify_add_watch(inotify_fd, fullpath, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE );
-+ } else {
-+ sp->wd[1] = -1;
-+ }
-+ /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
-+ sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE | IN_DONT_FOLLOW);
-+ }
-+}
-+#else
-+static void *notify_daemon(void *data)
-+{
-+ struct stat st, lst;
-+ struct state *cur;
-+
-+ ast_mutex_lock(&initialization_lock);
-+ ast_cond_signal(&initialization);
-+ ast_mutex_unlock(&initialization_lock);
-+
-+ for (;/*ever*/;) {
-+ char fullname[FILENAME_MAX + 1];
-+
-+ poll(NULL, 0, 60000);
-+ AST_LIST_LOCK(&zonelist);
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zonelist, cur, list) {
-+ char *name = cur->name;
-+
-+ if (name[0] == ':')
-+ ++name;
-+ if (name[0] != '/') {
-+ (void) strcpy(fullname, TZDIR "/");
-+ (void) strcat(fullname, name);
-+ name = fullname;
-+ }
-+ stat(name, &st);
-+ lstat(name, &lst);
-+ if (st.st_mtime > cur->mtime[0] || lst.st_mtime > cur->mtime[1]) {
-+ AST_LIST_REMOVE_CURRENT(list);
-+ ast_free(cur);
-+ continue;
-+ }
-+ }
-+ AST_LIST_TRAVERSE_SAFE_END
-+ AST_LIST_UNLOCK(&zonelist);
-+ }
-+ inotify_thread = AST_PTHREADT_NULL;
-+ return NULL;
-+}
-+
-+static void add_notify(struct state *sp, const char *path)
-+{
-+ struct stat st;
-+
-+ if (inotify_thread == AST_PTHREADT_NULL) {
-+ ast_cond_init(&initialization, NULL);
-+ ast_mutex_init(&initialization_lock);
-+ ast_mutex_lock(&initialization_lock);
-+ if (!(ast_pthread_create_background(&inotify_thread, NULL, notify_daemon, NULL))) {
-+ /* Give the thread a chance to initialize */
-+ ast_cond_wait(&initialization, &initialization_lock);
-+ }
-+ ast_mutex_unlock(&initialization_lock);
-+ }
-+
-+ stat(path, &st);
-+ sp->mtime[0] = st.st_mtime;
-+ lstat(path, &st);
-+ sp->mtime[1] = st.st_mtime;
-+}
-+#endif
-+
- /*! \note
- ** Section 4.12.3 of X3.159-1989 requires that
- ** Except for the strftime function, these functions [asctime,
-@@ -305,6 +463,7 @@
- return -1;
- if ((fid = open(name, OPEN_MODE)) == -1)
- return -1;
-+ add_notify(sp, name);
- }
- nread = read(fid, u.buf, sizeof u.buf);
- if (close(fid) < 0 || nread <= 0)
-@@ -1819,3 +1978,15 @@
- return res;
- }
-
-+char *ast_strptime(const char *s, const char *format, struct ast_tm *tm)
-+{
-+ struct tm tm2 = { 0, };
-+ char *res = strptime(s, format, &tm2);
-+ memcpy(tm, &tm2, sizeof(*tm));
-+ tm->tm_usec = 0;
-+ /* strptime(3) doesn't set .tm_isdst correctly, so to force ast_mktime(3)
-+ * to deal with it correctly, we set it to -1. */
-+ tm->tm_isdst = -1;
-+ return res;
-+}
-+
-Index: main/Makefile
-===================================================================
---- a/main/Makefile (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/Makefile (.../team/group/issue14292) (revision 178988)
-@@ -18,7 +18,7 @@
- include $(ASTTOPDIR)/Makefile.moddir_rules
-
- OBJS= tcptls.o io.o sched.o logger.o frame.o loader.o config.o channel.o \
-- translate.o file.o pbx.o cli.o md5.o term.o \
-+ translate.o file.o pbx.o cli.o md5.o term.o heap.o \
- ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
- cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
- dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
-@@ -28,7 +28,8 @@
- cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
- strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
- astobj2.o hashtab.o global_datastores.o version.o \
-- features.o taskprocessor.o timing.o datastore.o
-+ features.o taskprocessor.o timing.o datastore.o xml.o xmldoc.o \
-+ strings.o
-
- # we need to link in the objects statically, not as a library, because
- # otherwise modules will not have them available if none of the static
-@@ -39,10 +40,10 @@
- # by a module.
- OBJS+=say.o
-
--AST_LIBS += $(SSL_LIB)
-+AST_LIBS += $(OPENSSL_LIB)
- AST_LIBS += $(BKTR_LIB)
-+AST_LIBS += $(LIBXML2_LIB)
-
--
- ifeq ($(POLL_AVAILABLE),)
- OBJS+=poll.o
- else
-@@ -123,7 +124,7 @@
- bison -o $@ -d --name-prefix=ast_yy ast_expr2.y
-
- ast_expr2f.c:
-- flex -o $@ --full ast_expr2.fl
-+ flex -o $@ ast_expr2.fl
- sed 's@#if __STDC_VERSION__ >= 199901L@#if !defined __STDC_VERSION__ || __STDC_VERSION__ >= 199901L@' $@ > $@.fix
- echo "#include \"asterisk.h\"" > $@
- echo >> $@
-Index: main/slinfactory.c
-===================================================================
---- a/main/slinfactory.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/slinfactory.c (.../team/group/issue14292) (revision 178988)
-@@ -32,30 +32,31 @@
- #include "asterisk/slinfactory.h"
- #include "asterisk/translate.h"
-
--/*!
-- * \brief Initialize an slinfactory
-- *
-- * \arg sf The slinfactory to initialize
-- *
-- * \return Nothing
-- */
- void ast_slinfactory_init(struct ast_slinfactory *sf)
- {
- memset(sf, 0, sizeof(*sf));
- sf->offset = sf->hold;
-+ sf->output_format = AST_FORMAT_SLINEAR;
- }
-
--/*!
-- * \brief Destroy the contents of a slinfactory
-- *
-- * \arg sf The slinfactory that is no longer needed
-- *
-- * This function will free any memory allocated for the contents of the
-- * slinfactory. It does not free the slinfactory itself. If the sf is
-- * malloc'd, then it must be explicitly free'd after calling this function.
-- *
-- * \return Nothing
-- */
-+int ast_slinfactory_init_rate(struct ast_slinfactory *sf, unsigned int sample_rate)
-+{
-+ memset(sf, 0, sizeof(*sf));
-+ sf->offset = sf->hold;
-+ switch (sample_rate) {
-+ case 8000:
-+ sf->output_format = AST_FORMAT_SLINEAR;
-+ break;
-+ case 16000:
-+ sf->output_format = AST_FORMAT_SLINEAR16;
-+ break;
-+ default:
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
- void ast_slinfactory_destroy(struct ast_slinfactory *sf)
- {
- struct ast_frame *f;
-@@ -69,14 +70,6 @@
- ast_frfree(f);
- }
-
--/*!
-- * \brief Feed audio into an slinfactory
-- *
-- * \arg sf The slinfactory to feed into
-- * \arg f Frame containing audio to feed in
-- *
-- * \return Number of frames currently in factory
-- */
- int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
- {
- struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr;
-@@ -92,15 +85,16 @@
- return 0;
- }
-
-- if (f->subclass != AST_FORMAT_SLINEAR && f->subclass != AST_FORMAT_SLINEAR16) {
-+ if (f->subclass != sf->output_format) {
- if (sf->trans && f->subclass != sf->format) {
- ast_translator_free_path(sf->trans);
- sf->trans = NULL;
- }
-
- if (!sf->trans) {
-- if (!(sf->trans = ast_translator_build_path((f->subclass == AST_FORMAT_G722 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR), f->subclass))) {
-- ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f->subclass));
-+ if (!(sf->trans = ast_translator_build_path(sf->output_format, f->subclass))) {
-+ ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n", ast_getformatname(f->subclass),
-+ ast_getformatname(sf->output_format));
- return 0;
- }
- sf->format = f->subclass;
-@@ -125,8 +119,9 @@
- }
-
- x = 0;
-- AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list)
-+ AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) {
- x++;
-+ }
-
- AST_LIST_INSERT_TAIL(&sf->queue, duped_frame, frame_list);
-
-@@ -135,15 +130,6 @@
- return x;
- }
-
--/*!
-- * \brief Read samples from an slinfactory
-- *
-- * \arg sf The slinfactory to read from
-- * \arg buf Buffer to put samples into
-- * \arg samples Number of samples wanted
-- *
-- * \return Number of samples read
-- */
- int ast_slinfactory_read(struct ast_slinfactory *sf, short *buf, size_t samples)
- {
- struct ast_frame *frame_ptr;
-@@ -198,25 +184,11 @@
- return sofar;
- }
-
--/*!
-- * \brief Retrieve number of samples currently in an slinfactory
-- *
-- * \arg sf The slinfactory to peek into
-- *
-- * \return Number of samples in slinfactory
-- */
- unsigned int ast_slinfactory_available(const struct ast_slinfactory *sf)
- {
- return sf->size;
- }
-
--/*!
-- * \brief Flush the contents of an slinfactory
-- *
-- * \arg sf The slinfactory to flush
-- *
-- * \return Nothing
-- */
- void ast_slinfactory_flush(struct ast_slinfactory *sf)
- {
- struct ast_frame *fr = NULL;
-Index: main/translate.c
-===================================================================
---- a/main/translate.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/translate.c (.../team/group/issue14292) (revision 178988)
-@@ -598,7 +598,7 @@
- }
- }
- ast_str_append(&out, -1, "\n");
-- ast_cli(a->fd, "%s", out->str);
-+ ast_cli(a->fd, "%s", ast_str_buffer(out));
- }
- AST_RWLIST_UNLOCK(&translators);
- return CLI_SUCCESS;
-@@ -676,7 +676,7 @@
- ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
-
- if (!added_cli) {
-- ast_cli_register_multiple(cli_translate, sizeof(cli_translate) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
- added_cli++;
- }
-
-Index: main/jitterbuf.c
-===================================================================
---- a/main/jitterbuf.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/jitterbuf.c (.../team/group/issue14292) (revision 178988)
-@@ -510,27 +510,33 @@
-
- jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
-
-- jb->info.frames_in++;
-+ numts = 0;
-+ if (jb->frames)
-+ numts = jb->frames->prev->ts - jb->frames->ts;
-
-- if (jb->frames && jb->dropem)
-+ if (numts >= jb->info.conf.max_jitterbuf) {
-+ if (!jb->dropem) {
-+ ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
-+ jb->info.conf.max_jitterbuf);
-+ jb->dropem = 1;
-+ }
-+ jb->info.frames_dropped++;
- return JB_DROP;
-- jb->dropem = 0;
-+ } else {
-+ jb->dropem = 0;
-+ }
-
- if (type == JB_TYPE_VOICE) {
- /* presently, I'm only adding VOICE frames to history and drift calculations; mostly because with the
- * IAX integrations, I'm sending retransmitted control frames with their awkward timestamps through */
-- if (history_put(jb,ts,now,ms))
-+ if (history_put(jb,ts,now,ms)) {
-+ jb->info.frames_dropped++;
- return JB_DROP;
-+ }
- }
-- numts = 0;
-- if (jb->frames)
-- numts = jb->frames->prev->ts - jb->frames->ts;
-- if (numts >= jb->info.conf.max_jitterbuf) {
-- ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
-- jb->info.conf.max_jitterbuf);
-- jb->dropem = 1;
-- return JB_DROP;
-- }
-+
-+ jb->info.frames_in++;
-+
- /* if put into head of queue, caller needs to reschedule */
- if (queue_put(jb,data,type,ms,ts)) {
- return JB_SCHED;
-Index: main/rtp.c
-===================================================================
---- a/main/rtp.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/rtp.c (.../team/group/issue14292) (revision 178988)
-@@ -97,13 +97,7 @@
- * RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP. A participant may be involved in multiple RTP sessions at the same time [...]"
- *
- */
--/*! \brief The value of each payload format mapping: */
--struct rtpPayloadType {
-- int isAstFormat; /*!< whether the following code is an AST_FORMAT */
-- int code;
--};
-
--
- /*! \brief RTP session description */
- struct ast_rtp {
- int s;
-@@ -1044,10 +1038,11 @@
- ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
- return &ast_null_frame;
- }
--
-+
- if (ast_test_flag(rtp, FLAG_DTMF_COMPENSATE)) {
- if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
- rtp->resp = resp;
-+ rtp->dtmfcount = 0;
- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
- f->len = 0;
- rtp->lastevent = timestamp;
-@@ -1056,15 +1051,16 @@
- if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
- rtp->resp = resp;
- f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
-+ rtp->dtmfcount = dtmftimeout;
- } else if ((event_end & 0x80) && (rtp->lastevent != seqno) && rtp->resp) {
- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
- f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */
- rtp->resp = 0;
-+ rtp->dtmfcount = 0;
- rtp->lastevent = seqno;
- }
- }
-
-- rtp->dtmfcount = dtmftimeout;
- rtp->dtmfsamples = samples;
-
- return f;
-@@ -1741,11 +1737,23 @@
- rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
- rtp->f.frametype = (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) ? AST_FRAME_VOICE : (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
-
-- if (!rtp->lastrxts)
-- rtp->lastrxts = timestamp;
--
- rtp->rxseqno = seqno;
-
-+ if (rtp->dtmfcount) {
-+ rtp->dtmfcount -= (timestamp - rtp->lastrxts);
-+
-+ if (rtp->dtmfcount < 0) {
-+ rtp->dtmfcount = 0;
-+ }
-+
-+ if (rtp->resp && !rtp->dtmfcount) {
-+ struct ast_frame *f;
-+ f = send_dtmf(rtp, AST_FRAME_DTMF_END);
-+ rtp->resp = 0;
-+ return f;
-+ }
-+ }
-+
- /* Record received timestamp as last received now */
- rtp->lastrxts = timestamp;
-
-@@ -1817,7 +1825,7 @@
- /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
- ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
- rtp->f.ts = timestamp / 8;
-- rtp->f.len = rtp->f.samples / ( (ast_format_rate(rtp->f.subclass) == 16000) ? 16 : 8 );
-+ rtp->f.len = rtp->f.samples / ((ast_format_rate(rtp->f.subclass) / 1000));
- } else if (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
- /* Video -- samples is # of samples vs. 90000 */
- if (!rtp->lastividtimestamp)
-@@ -1848,40 +1856,46 @@
-
- /* The following array defines the MIME Media type (and subtype) for each
- of our codecs, or RTP-specific data type. */
--static struct {
-+static const struct mimeType {
- struct rtpPayloadType payloadType;
-- char* type;
-- char* subtype;
-+ char *type;
-+ char *subtype;
-+ unsigned int sample_rate;
- } mimeTypes[] = {
-- {{1, AST_FORMAT_G723_1}, "audio", "G723"},
-- {{1, AST_FORMAT_GSM}, "audio", "GSM"},
-- {{1, AST_FORMAT_ULAW}, "audio", "PCMU"},
-- {{1, AST_FORMAT_ULAW}, "audio", "G711U"},
-- {{1, AST_FORMAT_ALAW}, "audio", "PCMA"},
-- {{1, AST_FORMAT_ALAW}, "audio", "G711A"},
-- {{1, AST_FORMAT_G726}, "audio", "G726-32"},
-- {{1, AST_FORMAT_ADPCM}, "audio", "DVI4"},
-- {{1, AST_FORMAT_SLINEAR}, "audio", "L16"},
-- {{1, AST_FORMAT_LPC10}, "audio", "LPC"},
-- {{1, AST_FORMAT_G729A}, "audio", "G729"},
-- {{1, AST_FORMAT_G729A}, "audio", "G729A"},
-- {{1, AST_FORMAT_G729A}, "audio", "G.729"},
-- {{1, AST_FORMAT_SPEEX}, "audio", "speex"},
-- {{1, AST_FORMAT_ILBC}, "audio", "iLBC"},
-- {{1, AST_FORMAT_G722}, "audio", "G722"},
-- {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32"},
-- {{0, AST_RTP_DTMF}, "audio", "telephone-event"},
-- {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event"},
-- {{0, AST_RTP_CN}, "audio", "CN"},
-- {{1, AST_FORMAT_JPEG}, "video", "JPEG"},
-- {{1, AST_FORMAT_PNG}, "video", "PNG"},
-- {{1, AST_FORMAT_H261}, "video", "H261"},
-- {{1, AST_FORMAT_H263}, "video", "H263"},
-- {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998"},
-- {{1, AST_FORMAT_H264}, "video", "H264"},
-- {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES"},
-- {{1, AST_FORMAT_T140RED}, "text", "RED"},
-- {{1, AST_FORMAT_T140}, "text", "T140"},
-+ {{1, AST_FORMAT_G723_1}, "audio", "G723", 8000},
-+ {{1, AST_FORMAT_GSM}, "audio", "GSM", 8000},
-+ {{1, AST_FORMAT_ULAW}, "audio", "PCMU", 8000},
-+ {{1, AST_FORMAT_ULAW}, "audio", "G711U", 8000},
-+ {{1, AST_FORMAT_ALAW}, "audio", "PCMA", 8000},
-+ {{1, AST_FORMAT_ALAW}, "audio", "G711A", 8000},
-+ {{1, AST_FORMAT_G726}, "audio", "G726-32", 8000},
-+ {{1, AST_FORMAT_ADPCM}, "audio", "DVI4", 8000},
-+ {{1, AST_FORMAT_SLINEAR}, "audio", "L16", 8000},
-+ {{1, AST_FORMAT_LPC10}, "audio", "LPC", 8000},
-+ {{1, AST_FORMAT_G729A}, "audio", "G729", 8000},
-+ {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
-+ {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
-+ {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
-+ {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
-+ /* this is the sample rate listed in the RTP profile for the G.722
-+ codec, *NOT* the actual sample rate of the media stream
-+ */
-+ {{1, AST_FORMAT_G722}, "audio", "G722", 8000},
-+ {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32", 8000},
-+ {{0, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
-+ {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
-+ {{0, AST_RTP_CN}, "audio", "CN", 8000},
-+ {{1, AST_FORMAT_JPEG}, "video", "JPEG", 90000},
-+ {{1, AST_FORMAT_PNG}, "video", "PNG", 90000},
-+ {{1, AST_FORMAT_H261}, "video", "H261", 90000},
-+ {{1, AST_FORMAT_H263}, "video", "H263", 90000},
-+ {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998", 90000},
-+ {{1, AST_FORMAT_H264}, "video", "H264", 90000},
-+ {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES", 90000},
-+ {{1, AST_FORMAT_T140RED}, "text", "RED", 1000},
-+ {{1, AST_FORMAT_T140}, "text", "T140", 1000},
-+ {{1, AST_FORMAT_SIREN7}, "audio", "G7221", 16000},
-+ {{1, AST_FORMAT_SIREN14}, "audio", "G7221", 32000},
- };
-
- /*!
-@@ -1894,7 +1908,7 @@
- * See http://www.iana.org/assignments/rtp-parameters for a list of
- * assigned values
- */
--static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
-+static const struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
- [0] = {1, AST_FORMAT_ULAW},
- #ifdef USE_DEPRECATED_G726
- [2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
-@@ -1920,6 +1934,7 @@
- [98] = {1, AST_FORMAT_H263_PLUS},
- [99] = {1, AST_FORMAT_H264},
- [101] = {0, AST_RTP_DTMF},
-+ [102] = {1, AST_FORMAT_SIREN7},
- [103] = {1, AST_FORMAT_H263_PLUS},
- [104] = {1, AST_FORMAT_MP4_VIDEO},
- [105] = {1, AST_FORMAT_T140RED}, /* Real time text chat (with redundancy encoding) */
-@@ -1927,6 +1942,7 @@
- [110] = {1, AST_FORMAT_SPEEX},
- [111] = {1, AST_FORMAT_G726},
- [112] = {1, AST_FORMAT_G726_AAL2},
-+ [115] = {1, AST_FORMAT_SIREN14},
- [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
- };
-
-@@ -2196,36 +2212,62 @@
- * an SDP "a=rtpmap:" line.
- * \return 0 if the MIME type was found and set, -1 if it wasn't found
- */
--int ast_rtp_set_rtpmap_type(struct ast_rtp *rtp, int pt,
-- char *mimeType, char *mimeSubtype,
-- enum ast_rtp_options options)
-+int ast_rtp_set_rtpmap_type_rate(struct ast_rtp *rtp, int pt,
-+ char *mimeType, char *mimeSubtype,
-+ enum ast_rtp_options options,
-+ unsigned int sample_rate)
- {
- unsigned int i;
- int found = 0;
-
-- if (pt < 0 || pt > MAX_RTP_PT)
-+ if (pt < 0 || pt > MAX_RTP_PT)
- return -1; /* bogus payload type */
--
-+
- rtp_bridge_lock(rtp);
-
- for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
-- if (strcasecmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
-- strcasecmp(mimeType, mimeTypes[i].type) == 0) {
-- found = 1;
-- rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
-- if ((mimeTypes[i].payloadType.code == AST_FORMAT_G726) &&
-- mimeTypes[i].payloadType.isAstFormat &&
-- (options & AST_RTP_OPT_G726_NONSTANDARD))
-- rtp->current_RTP_PT[pt].code = AST_FORMAT_G726_AAL2;
-- break;
-+ const struct mimeType *t = &mimeTypes[i];
-+
-+ if (strcasecmp(mimeSubtype, t->subtype)) {
-+ continue;
- }
-+
-+ if (strcasecmp(mimeType, t->type)) {
-+ continue;
-+ }
-+
-+ /* if both sample rates have been supplied, and they don't match,
-+ then this not a match; if one has not been supplied, then the
-+ rates are not compared */
-+ if (sample_rate && t->sample_rate &&
-+ (sample_rate != t->sample_rate)) {
-+ continue;
-+ }
-+
-+ found = 1;
-+ rtp->current_RTP_PT[pt] = t->payloadType;
-+
-+ if ((t->payloadType.code == AST_FORMAT_G726) &&
-+ t->payloadType.isAstFormat &&
-+ (options & AST_RTP_OPT_G726_NONSTANDARD)) {
-+ rtp->current_RTP_PT[pt].code = AST_FORMAT_G726_AAL2;
-+ }
-+
-+ break;
- }
-
- rtp_bridge_unlock(rtp);
-
-- return (found ? 0 : -1);
--}
-+ return (found ? 0 : -2);
-+}
-
-+int ast_rtp_set_rtpmap_type(struct ast_rtp *rtp, int pt,
-+ char *mimeType, char *mimeSubtype,
-+ enum ast_rtp_options options)
-+{
-+ return ast_rtp_set_rtpmap_type_rate(rtp, pt, mimeType, mimeSubtype, options, 0);
-+}
-+
- /*! \brief Return the union of all of the codecs that were set by rtp_set...() calls
- * They're returned as two distinct sets: AST_FORMATs, and AST_RTPs */
- void ast_rtp_get_current_formats(struct ast_rtp* rtp,
-@@ -2329,6 +2371,19 @@
- return "";
- }
-
-+unsigned int ast_rtp_lookup_sample_rate(int isAstFormat, int code)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
-+ if ((mimeTypes[i].payloadType.code == code) && (mimeTypes[i].payloadType.isAstFormat == isAstFormat)) {
-+ return mimeTypes[i].sample_rate;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
- char *ast_rtp_lookup_mime_multiple(char *buf, size_t size, const int capability,
- const int isAstFormat, enum ast_rtp_options options)
- {
-@@ -3679,16 +3734,27 @@
- rtp->smoother = NULL;
- }
-
-- if (!rtp->smoother && subclass != AST_FORMAT_SPEEX && subclass != AST_FORMAT_G723_1) {
-+ if (!rtp->smoother) {
- struct ast_format_list fmt = ast_codec_pref_getsize(&rtp->pref, subclass);
-- if (fmt.inc_ms) { /* if codec parameters is set / avoid division by zero */
-- if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
-- ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
-- return -1;
-+
-+ switch (subclass) {
-+ case AST_FORMAT_SPEEX:
-+ case AST_FORMAT_G723_1:
-+ case AST_FORMAT_SIREN7:
-+ case AST_FORMAT_SIREN14:
-+ /* these are all frame-based codecs and cannot be safely run through
-+ a smoother */
-+ break;
-+ default:
-+ if (fmt.inc_ms) { /* if codec parameters is set / avoid division by zero */
-+ if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
-+ ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
-+ return -1;
-+ }
-+ if (fmt.flags)
-+ ast_smoother_set_flags(rtp->smoother, fmt.flags);
-+ ast_debug(1, "Created smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
- }
-- if (fmt.flags)
-- ast_smoother_set_flags(rtp->smoother, fmt.flags);
-- ast_debug(1, "Created smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
- }
- }
- if (rtp->smoother) {
-@@ -3895,7 +3961,8 @@
- (fr->subclass == AST_CONTROL_UNHOLD) ||
- (fr->subclass == AST_CONTROL_VIDUPDATE) ||
- (fr->subclass == AST_CONTROL_T38) ||
-- (fr->subclass == AST_CONTROL_SRCUPDATE)) {
-+ (fr->subclass == AST_CONTROL_SRCUPDATE) ||
-+ (fr->subclass == AST_CONTROL_CONNECTED_LINE)) {
- if (fr->subclass == AST_CONTROL_HOLD) {
- /* If we someone went on hold we want the other side to reinvite back to us */
- if (who == c0)
-@@ -4135,7 +4202,8 @@
- (fr->subclass == AST_CONTROL_UNHOLD) ||
- (fr->subclass == AST_CONTROL_VIDUPDATE) ||
- (fr->subclass == AST_CONTROL_T38) ||
-- (fr->subclass == AST_CONTROL_SRCUPDATE)) {
-+ (fr->subclass == AST_CONTROL_SRCUPDATE) ||
-+ (fr->subclass == AST_CONTROL_CONNECTED_LINE)) {
- /* If we are going on hold, then break callback mode and P2P bridging */
- if (fr->subclass == AST_CONTROL_HOLD) {
- if (p0_callback)
-@@ -4444,41 +4512,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_cli_rtp_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "rtp debug [off|ip]";
-- e->usage =
-- "Usage: rtp debug [off]|[ip host[:port]]\n"
-- " Enable/Disable dumping of all RTP packets. If 'ip' is\n"
-- " specified, limit the dumped packets to those to and from\n"
-- " the specified 'host' with optional port.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc < 2 || a->argc > 4)
-- return CLI_SHOWUSAGE;
-- if (a->argc == 2) {
-- rtpdebug = 1;
-- memset(&rtpdebugaddr, 0, sizeof(rtpdebugaddr));
-- ast_cli(a->fd, "RTP Debugging Enabled\n");
-- } else if (a->argc == 3) {
-- if (strncasecmp(a->argv[2], "off", 3))
-- return CLI_SHOWUSAGE;
-- rtpdebug = 0;
-- ast_cli(a->fd, "RTP Debugging Disabled\n");
-- } else {
-- if (strncasecmp(a->argv[2], "ip", 2))
-- return CLI_SHOWUSAGE;
-- return rtp_do_debug_ip(a);
-- }
--
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_rtp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -4512,41 +4545,6 @@
- return CLI_SHOWUSAGE; /* default, failure */
- }
-
--static char *handle_cli_rtcp_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "rtcp debug [off|ip]";
-- e->usage =
-- "Usage: rtcp debug [off]|[ip host[:port]]\n"
-- " Enable/Disable dumping of all RTCP packets. If 'ip' is\n"
-- " specified, limit the dumped packets to those to and from\n"
-- " the specified 'host' with optional port.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc < 2 || a->argc > 4)
-- return CLI_SHOWUSAGE;
-- if (a->argc == 2) {
-- rtcpdebug = 1;
-- memset(&rtcpdebugaddr, 0, sizeof(rtcpdebugaddr));
-- ast_cli(a->fd, "RTCP Debugging Enabled\n");
-- } else if (a->argc == 3) {
-- if (strncasecmp(a->argv[2], "off", 3))
-- return CLI_SHOWUSAGE;
-- rtcpdebug = 0;
-- ast_cli(a->fd, "RTCP Debugging Disabled\n");
-- } else {
-- if (strncasecmp(a->argv[2], "ip", 2))
-- return CLI_SHOWUSAGE;
-- return rtcp_do_debug_ip(a);
-- }
--
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_rtcp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -4580,29 +4578,6 @@
- return CLI_SHOWUSAGE; /* default, failure */
- }
-
--static char *handle_cli_rtcp_stats_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "rtcp stats [off]";
-- e->usage =
-- "Usage: rtcp stats [off]\n"
-- " Enable/Disable dumping of RTCP stats.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc < 2 || a->argc > 3)
-- return CLI_SHOWUSAGE;
-- if (a->argc == 3 && strncasecmp(a->argv[2], "off", 3))
-- return CLI_SHOWUSAGE;
--
-- rtcpstats = (a->argc == 3) ? 0 : 1;
-- ast_cli(a->fd, "RTCP Stats %s\n", rtcpstats ? "Enabled" : "Disabled");
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_rtcp_set_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -4630,30 +4605,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_cli_stun_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "stun debug [off]";
-- e->usage =
-- "Usage: stun debug [off]\n"
-- " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
-- " debugging\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc < 2 || a->argc > 3)
-- return CLI_SHOWUSAGE;
-- if (a->argc == 3 && strncasecmp(a->argv[2], "off", 3))
-- return CLI_SHOWUSAGE;
--
-- stundebug = (a->argc == 3) ? 0 : 1;
-- ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -4682,16 +4633,11 @@
- return CLI_SUCCESS;
- }
-
--static struct ast_cli_entry cli_rtp_debug_deprecated = AST_CLI_DEFINE(handle_cli_rtp_debug_deprecated, "Enable/Disable RTP debugging");
--static struct ast_cli_entry cli_rtcp_debug_deprecated = AST_CLI_DEFINE(handle_cli_rtcp_debug_deprecated, "Enable/Disable RTCP debugging");
--static struct ast_cli_entry cli_rtcp_stats_deprecated = AST_CLI_DEFINE(handle_cli_rtcp_stats_deprecated, "Enable/Disable RTCP stats");
--static struct ast_cli_entry cli_stun_debug_deprecated = AST_CLI_DEFINE(handle_cli_stun_debug_deprecated, "Enable/Disable STUN debugging");
--
- static struct ast_cli_entry cli_rtp[] = {
-- AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging", .deprecate_cmd = &cli_rtp_debug_deprecated),
-- AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging", .deprecate_cmd = &cli_rtcp_debug_deprecated),
-- AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats", .deprecate_cmd = &cli_rtcp_stats_deprecated),
-- AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging", .deprecate_cmd = &cli_stun_debug_deprecated),
-+ AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging"),
-+ AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging"),
-+ AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"),
-+ AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
- };
-
- static int __ast_rtp_reload(int reload)
-@@ -4700,8 +4646,10 @@
- const char *s;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if ((cfg = ast_config_load2("rtp.conf", "rtp", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
-+ cfg = ast_config_load2("rtp.conf", "rtp", config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- return 0;
-+ }
-
- rtpstart = 5000;
- rtpend = 31000;
-@@ -4878,9 +4826,8 @@
- {
- if (f->datalen > -1) {
- struct rtp_red *red = rtp->red;
-- memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen);
-+ memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen);
- red->t140.datalen += f->datalen;
- red->t140.ts = f->ts;
- }
- }
--
-Index: main/hashtab.c
-===================================================================
---- a/main/hashtab.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/hashtab.c (.../team/group/issue14292) (revision 178988)
-@@ -38,7 +38,7 @@
- #include "asterisk/linkedlists.h"
- #include "asterisk/hashtab.h"
-
--static void ast_hashtab_resize( struct ast_hashtab *tab);
-+static void ast_hashtab_resize(struct ast_hashtab *tab);
- static void *ast_hashtab_lookup_internal(struct ast_hashtab *tab, const void *obj, unsigned int h);
-
- /* some standard, default routines for general use */
-@@ -60,7 +60,7 @@
-
- if (ai < bi)
- return -1;
--
-+
- return !(ai == bi);
- }
-
-@@ -68,7 +68,7 @@
- {
- short as = *((short *) a);
- short bs = *((short *) b);
--
-+
- if (as < bs)
- return -1;
-
-@@ -95,10 +95,10 @@
- int ast_is_prime(int num)
- {
- int tnum, limit;
--
-+
- if (!(num & 0x1)) /* even number -- not prime */
- return 0;
--
-+
- /* Loop through ODD numbers starting with 3 */
-
- tnum = 3;
-@@ -109,20 +109,19 @@
-
- /* really, we only need to check sqrt(num) numbers */
- limit = num / tnum;
--
-+
- /* we only check odd numbers */
- tnum = tnum + 2;
- }
-
- /* if we made it through the loop, the number is a prime */
--
- return 1;
- }
-
- int ast_hashtab_newsize_java(struct ast_hashtab *tab)
- {
- int i = (tab->hash_tab_size << 1); /* multiply by two */
--
-+
- while (!ast_is_prime(i))
- i++;
-
-@@ -133,7 +132,7 @@
- {
- int x = (tab->hash_tab_size << 1);
- int i = (tab->hash_tab_size + x);
--
-+
- while (!ast_is_prime(i))
- i++;
-
-@@ -150,14 +149,13 @@
- unsigned char *str = (unsigned char *) obj;
- unsigned int total;
-
-- for (total = 0; *str; str++)
-- {
-+ for (total = 0; *str; str++) {
- unsigned int tmp = total;
- total <<= 1; /* multiply by 2 */
- total += tmp; /* multiply by 3 */
- total <<= 2; /* multiply by 12 */
- total += tmp; /* multiply by 13 */
--
-+
- total += ((unsigned int)(*str));
- }
- return total;
-@@ -184,14 +182,14 @@
- unsigned int charval = toupper(*str);
-
- /* hopefully, the following is faster than multiplication by 7 */
-- /* why do I go to this bother? A good compiler will do this
-+ /* why do I go to this bother? A good compiler will do this
- anyway, if I say total *= 13 */
- /* BTW, tried *= 7, and it doesn't do as well in spreading things around! */
- total <<= 1; /* multiply by 2 */
- total += tmp; /* multiply by 3 */
- total <<= 2; /* multiply by 12 */
- total += tmp; /* multiply by 13 */
--
-+
- total += (charval);
- }
-
-@@ -215,11 +213,11 @@
- #else
- ast_hashtab_create
- #endif
--(int initial_buckets,
-- int (*compare)(const void *a, const void *b),
-- int (*resize)(struct ast_hashtab *),
-+(int initial_buckets,
-+ int (*compare)(const void *a, const void *b),
-+ int (*resize)(struct ast_hashtab *),
- int (*newsize)(struct ast_hashtab *tab),
-- unsigned int (*hash)(const void *obj),
-+ unsigned int (*hash)(const void *obj),
- int do_locking
- #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
- , const char *file, int lineno, const char *function
-@@ -363,12 +361,12 @@
- ast_rwlock_unlock(&tab->lock);
- }
-
--void ast_hashtab_destroy( struct ast_hashtab *tab, void (*objdestroyfunc)(void *obj))
-+void ast_hashtab_destroy(struct ast_hashtab *tab, void (*objdestroyfunc)(void *obj))
- {
- /* this func will free the hash table and all its memory. It
- doesn't touch the objects stored in it */
- if (tab) {
--
-+
- if (tab->do_locking)
- ast_rwlock_wrlock(&tab->lock);
-
-@@ -376,19 +374,24 @@
- /* go thru and destroy the buckets */
- struct ast_hashtab_bucket *t;
- int i;
--
-+
- while (tab->tlist) {
- t = tab->tlist;
-- if (t->object && objdestroyfunc)
-- (*objdestroyfunc)((void *) t->object); /* I cast this because I'm not going to MOD it, I'm going to DESTROY it */
--
-+ if (t->object && objdestroyfunc) {
-+ /* I cast this because I'm not going to MOD it, I'm going to DESTROY
-+ * it.
-+ */
-+ (*objdestroyfunc)((void *) t->object);
-+ }
-+
- tlist_del_item(&(tab->tlist), tab->tlist);
- free(t);
- }
--
-- for (i = 0; i < tab->hash_tab_size; i++)
-- tab->array[i] = NULL; /* not totally necc., but best to destroy old ptrs */
--
-+
-+ for (i = 0; i < tab->hash_tab_size; i++) {
-+ /* Not totally necessary, but best to destroy old pointers */
-+ tab->array[i] = NULL;
-+ }
- free(tab->array);
- }
- if (tab->do_locking) {
-@@ -403,7 +406,7 @@
- {
- unsigned int h;
- int res=0;
--
-+
- if (!tab || !obj)
- return res;
-
-@@ -424,10 +427,10 @@
- {
- int c;
- struct ast_hashtab_bucket *b;
--
-+
- if (!tab || !obj)
- return 0;
--
-+
- for (c = 0, b = tab->array[h]; b; b= b->next)
- c++;
-
-@@ -469,13 +472,13 @@
-
- if (tab->do_locking)
- ast_rwlock_unlock(&tab->lock);
--
-+
- return ret2;
- }
-
- if (tab->do_locking)
- ast_rwlock_unlock(&tab->lock);
--
-+
- return 0;
- }
-
-@@ -487,7 +490,7 @@
-
- if (!tab || !obj)
- return 0;
--
-+
- if (tab->do_locking)
- ast_rwlock_rdlock(&tab->lock);
-
-@@ -510,14 +513,14 @@
-
- if (!tab || !obj)
- return 0;
--
-+
- if (tab->do_locking)
- ast_rwlock_rdlock(&tab->lock);
--
-+
- h = hashval % tab->hash_tab_size;
-
- ret = ast_hashtab_lookup_internal(tab,obj,h);
--
-+
- if (tab->do_locking)
- ast_rwlock_unlock(&tab->lock);
-
-@@ -532,13 +535,13 @@
-
- if (!tab || !obj)
- return 0;
--
-+
- h = (*tab->hash)(obj) % tab->hash_tab_size;
--
-+
- ret = ast_hashtab_lookup_internal(tab,obj,h);
--
-- *bucket = h;
--
-+
-+ *bucket = h;
-+
- return ret;
- }
-
-@@ -548,14 +551,15 @@
-
- for (b = tab->array[h]; b; b = b->next) {
- if (!(*tab->compare)(obj,b->object)) {
-- return (void*) b->object; /* I can't touch obj in this func, but the outside world is welcome to */
-+ /* I can't touch obj in this func, but the outside world is welcome to */
-+ return (void*) b->object;
- }
- }
-
- return NULL;
- }
-
--void ast_hashtab_get_stats( struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets)
-+void ast_hashtab_get_stats(struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets)
- {
- /* returns key stats for the table */
- if (tab->do_locking)
-@@ -568,24 +572,21 @@
- ast_rwlock_unlock(&tab->lock);
- }
-
-- /* this function returns the number of elements stored in the hashtab */
--int ast_hashtab_size( struct ast_hashtab *tab)
-+/* this function returns the number of elements stored in the hashtab */
-+int ast_hashtab_size(struct ast_hashtab *tab)
- {
- return tab->hash_tab_elements;
- }
-
-- /* this function returns the size of the bucket array in the hashtab */
--int ast_hashtab_capacity( struct ast_hashtab *tab)
-+/* this function returns the size of the bucket array in the hashtab */
-+int ast_hashtab_capacity( struct ast_hashtab *tab)
- {
- return tab->hash_tab_size;
- }
-
--
--
- /* the insert operation calls this, and is wrlock'd when it does. */
- /* if you want to call it, you should set the wrlock yourself */
-
--
- static void ast_hashtab_resize( struct ast_hashtab *tab)
- {
- /* this function is called either internally, when the resize func returns 1, or
-@@ -593,10 +594,10 @@
- int newsize = (*tab->newsize)(tab), i, c;
- unsigned int h;
- struct ast_hashtab_bucket *b,*bn;
--
-+
- /* Since we keep a DLL of all the buckets in tlist,
- all we have to do is free the array, malloc a new one,
-- and then go thru the tlist array and reassign them into
-+ and then go thru the tlist array and reassign them into
- the bucket arrayj.
- */
- for (i = 0; i < tab->hash_tab_size; i++) { /* don't absolutely have to do this, but
-@@ -634,7 +635,7 @@
- {
- /* returns an iterator */
- struct ast_hashtab_iter *it;
--
-+
- if (!(it = ast_calloc(1, sizeof(*it))))
- return NULL;
-
-@@ -651,7 +652,7 @@
- {
- /* returns an iterator */
- struct ast_hashtab_iter *it;
--
-+
- if (!(it = ast_calloc(1, sizeof(*it))))
- return NULL;
-
-@@ -674,7 +675,7 @@
- {
- /* returns the next object in the list, advances iter one step */
- struct ast_hashtab_bucket *retval;
--
-+
- if (it && it->next) { /* there's a next in the bucket list */
- retval = it->next;
- it->next = retval->tnext;
-@@ -687,17 +688,17 @@
- static void *ast_hashtab_remove_object_internal(struct ast_hashtab *tab, struct ast_hashtab_bucket *b, int h)
- {
- const void *obj2;
--
-+
- if (b->prev)
- b->prev->next = b->next;
- else
- tab->array[h] = b->next;
--
-+
- if (b->next)
- b->next->prev = b->prev;
--
-+
- tlist_del_item(&(tab->tlist), b);
--
-+
- obj2 = b->object;
- b->object = b->next = (void*)2;
- free(b); /* free up the hashbucket */
-@@ -763,12 +764,12 @@
-
- h = (*tab->hash)(obj) % tab->hash_tab_size;
- for (b = tab->array[h]; b; b = b->next) {
--
-+
- if (!(*tab->compare)(obj, b->object)) {
- const void *obj2;
-
- obj2 = ast_hashtab_remove_object_internal(tab, b, h);
--
-+
- return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
- }
- }
-@@ -785,12 +786,12 @@
-
- if (!tab || !obj)
- return 0;
--
-+
- if (tab->do_locking)
- ast_rwlock_wrlock(&tab->lock);
-
- obj2 = ast_hashtab_remove_this_object_nolock(tab,obj);
--
-+
- if (tab->do_locking)
- ast_rwlock_unlock(&tab->lock);
-
-@@ -807,14 +808,14 @@
-
- if (!tab || !obj)
- return 0;
--
-+
- h = (*tab->hash)(obj) % tab->hash_tab_size;
- for (b = tab->array[h]; b; b = b->next) {
--
-+
- if (obj == b->object) {
- const void *obj2;
- obj2 = ast_hashtab_remove_object_internal(tab, b, h);
--
-+
- return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
- }
- }
-Index: main/abstract_jb.c
-===================================================================
---- a/main/abstract_jb.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/abstract_jb.c (.../team/group/issue14292) (revision 178988)
-@@ -484,6 +484,8 @@
-
- /* Create a frame log file */
- if (ast_test_flag(jbconf, AST_JB_LOG)) {
-+ char safe_logfile[30] = "/tmp/logfile-XXXXXX";
-+ int safe_fd;
- snprintf(name2, sizeof(name2), "%s", chan->name);
- tmp = strchr(name2, '/');
- if (tmp)
-@@ -497,14 +499,17 @@
- tmp = strchr(name1, '/');
- if (tmp)
- *tmp = '#';
--
-+
- snprintf(logfile_pathname, sizeof(logfile_pathname),
- "/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2);
-- jb->logfile = fopen(logfile_pathname, "w+b");
--
-- if (!jb->logfile)
-- ast_log(LOG_ERROR, "Failed to create frame log file with pathname '%s'\n", logfile_pathname);
--
-+ if (!(safe_fd = mkstemp(safe_logfile)) > -1 || unlink(logfile_pathname) || link(safe_logfile, logfile_pathname) || unlink(safe_logfile) || !(jb->logfile = fdopen(safe_fd, "w+b"))) {
-+ jb->logfile = NULL;
-+ if (safe_fd > -1) {
-+ close(safe_fd);
-+ }
-+ ast_log(LOG_ERROR, "Failed to create frame log file with pathname '%s': %s\n", logfile_pathname, strerror(errno));
-+ }
-+
- if (res == JB_IMPL_OK)
- jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
- now, frr->ts, frr->len);
-Index: main/astmm.c
-===================================================================
---- a/main/astmm.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/astmm.c (.../team/group/issue14292) (revision 178988)
-@@ -157,10 +157,15 @@
-
- static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
- {
-- int hash = HASH(ptr);
-+ int hash;
- struct ast_region *reg, *prev = NULL;
- unsigned int *fence;
-
-+ if (!ptr)
-+ return;
-+
-+ hash = HASH(ptr);
-+
- ast_mutex_lock(&reglock);
- for (reg = regions[hash]; reg; reg = reg->next) {
- if (reg->data == ptr) {
-@@ -482,7 +487,7 @@
- ast_log(LOG_ERROR, "struct ast_region has %d bytes of padding! This must be eliminated for low-fence checking to work properly!\n", (int) pad);
- }
-
-- ast_cli_register_multiple(cli_memory, sizeof(cli_memory) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_memory, ARRAY_LEN(cli_memory));
-
- snprintf(filename, sizeof(filename), "%s/mmlog", ast_config_AST_LOG_DIR);
-
-Index: main/asterisk.c
-===================================================================
---- a/main/asterisk.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/asterisk.c (.../team/group/issue14292) (revision 178988)
-@@ -22,17 +22,24 @@
- * \mainpage Asterisk -- An Open Source Telephony Toolkit
- *
- * \par Developer Documentation for Asterisk
-+ *
- * This is the main developer documentation for Asterisk. It is
-- * generated by running "make progdocs".
-+ * generated by running "make progdocs" from the Asterisk source tree.
-+ *
-+ * In addition to the information available on the Asterisk source code,
-+ * please see the appendices for information on coding guidelines,
-+ * release management, commit policies, and more.
-+ *
- * \par Additional documentation
- * \arg \ref Licensing
- * \arg \ref DevDoc
- * \arg \ref ConfigFiles
- *
-- * \section copyright Copyright and author
-+ * \section copyright Copyright and Author
- *
-- * Copyright (C) 1999 - 2008, Digium, Inc.
-- * Asterisk is a trademark registered by Digium, Inc.
-+ * Copyright (C) 1999 - 2009, Digium, Inc.
-+ * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
-+ * of <a href="http://www.digium.com">Digium, Inc</a>.
- *
- * \author Mark Spencer <markster@digium.com>
- * Also see \ref AstCREDITS
-@@ -40,9 +47,8 @@
- * 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
-+ * the project provides a web site, mailing lists, and IRC
- * channels for your use.
-- *
- */
-
- /*! \file
-@@ -72,7 +78,19 @@
- #include <sys/stat.h>
- #if defined(HAVE_SYSINFO)
- #include <sys/sysinfo.h>
-+#elif defined(HAVE_SYSCTL)
-+#include <sys/param.h>
-+#include <sys/sysctl.h>
-+#if !defined(__OpenBSD__)
-+#include <sys/vmmeter.h>
-+#if defined(__FreeBSD__)
-+#include <vm/vm_param.h>
- #endif
-+#endif
-+#if defined(HAVE_SWAPCTL)
-+#include <sys/swap.h>
-+#endif
-+#endif
- #include <regex.h>
-
- #if defined(SOLARIS)
-@@ -117,6 +135,8 @@
- #include "asterisk/devicestate.h"
- #include "asterisk/module.h"
- #include "asterisk/dsp.h"
-+#include "asterisk/buildinfo.h"
-+#include "asterisk/xmldoc.h"
-
- #include "asterisk/doxyref.h" /* Doxygen documentation */
-
-@@ -174,6 +194,8 @@
- int p[2]; /*!< Pipe */
- pthread_t t; /*!< Thread of handler */
- int mute; /*!< Is the console muted for logs */
-+ int uid; /*!< Remote user ID. */
-+ int gid; /*!< Remote group ID. */
- int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
- };
-
-@@ -246,19 +268,13 @@
- static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
- static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
-
--extern const char *ast_build_hostname;
--extern const char *ast_build_kernel;
--extern const char *ast_build_machine;
--extern const char *ast_build_os;
--extern const char *ast_build_date;
--extern const char *ast_build_user;
--
- static char *_argv[256];
- static int shuttingdown;
- static int restartnow;
- static pthread_t consolethread = AST_PTHREADT_NULL;
- static int canary_pid = 0;
- static char canary_filename[128];
-+static int canary_pipe = -1;
-
- static char randompool[256];
-
-@@ -316,6 +332,24 @@
- ast_free(find);
- }
-
-+char *ast_complete_source_filename(const char *partial, int n)
-+{
-+ struct file_version *find;
-+ size_t len = strlen(partial);
-+ int count = 0;
-+ char *res = NULL;
-+
-+ AST_RWLIST_RDLOCK(&file_versions);
-+ AST_RWLIST_TRAVERSE(&file_versions, find, list) {
-+ if (!strncasecmp(find->file, partial, len) && ++count > n) {
-+ res = ast_strdup(find->file);
-+ break;
-+ }
-+ }
-+ AST_RWLIST_UNLOCK(&file_versions);
-+ return res;
-+}
-+
- /*! \brief Find version for given module name */
- const char *ast_file_version_find(const char *file)
- {
-@@ -476,11 +510,121 @@
- return CLI_SUCCESS;
- }
-
--#if defined(HAVE_SYSINFO)
-+#if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
-+/*
-+ * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
-+ * to be based on the new swapctl(2) system call.
-+ */
-+static int swapmode(int *used, int *total)
-+{
-+ struct swapent *swdev;
-+ int nswap, rnswap, i;
-+
-+ nswap = swapctl(SWAP_NSWAP, 0, 0);
-+ if (nswap == 0)
-+ return 0;
-+
-+ swdev = ast_calloc(nswap, sizeof(*swdev));
-+ if (swdev == NULL)
-+ return 0;
-+
-+ rnswap = swapctl(SWAP_STATS, swdev, nswap);
-+ if (rnswap == -1) {
-+ ast_free(swdev);
-+ return 0;
-+ }
-+
-+ /* if rnswap != nswap, then what? */
-+
-+ /* Total things up */
-+ *total = *used = 0;
-+ for (i = 0; i < nswap; i++) {
-+ if (swdev[i].se_flags & SWF_ENABLE) {
-+ *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
-+ *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
-+ }
-+ }
-+ ast_free(swdev);
-+ return 1;
-+}
-+#elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
-+static int swapmode(int *used, int *total)
-+{
-+ *used = *total = 0;
-+ return 1;
-+}
-+#endif
-+
-+#if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
- /*! \brief Give an overview of system statistics */
- static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
-+ int64_t physmem, freeram;
-+ int totalswap = 0, freeswap = 0, nprocs = 0;
-+ long uptime = 0;
-+#if defined(HAVE_SYSINFO)
- struct sysinfo sys_info;
-+ sysinfo(&sys_info);
-+ uptime = sys_info.uptime/3600;
-+ physmem = sys_info.totalram * sys_info.mem_unit;
-+ freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
-+ totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
-+ freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
-+ nprocs = sys_info.procs;
-+#elif defined(HAVE_SYSCTL)
-+ static int pageshift;
-+ struct vmtotal vmtotal;
-+ struct timeval boottime;
-+ time_t now;
-+ int mib[2], pagesize, usedswap = 0;
-+ size_t len;
-+ /* calculate the uptime by looking at boottime */
-+ time(&now);
-+ mib[0] = CTL_KERN;
-+ mib[1] = KERN_BOOTTIME;
-+ len = sizeof(boottime);
-+ if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
-+ uptime = now - boottime.tv_sec;
-+ }
-+ uptime = uptime/3600;
-+ /* grab total physical memory */
-+ mib[0] = CTL_HW;
-+#if defined(HW_PHYSMEM64)
-+ mib[1] = HW_PHYSMEM64;
-+#else
-+ mib[1] = HW_PHYSMEM;
-+#endif
-+ len = sizeof(physmem);
-+ sysctl(mib, 2, &physmem, &len, NULL, 0);
-+
-+ pagesize = getpagesize();
-+ pageshift = 0;
-+ while (pagesize > 1) {
-+ pageshift++;
-+ pagesize >>= 1;
-+ }
-+
-+ /* we only need the amount of log(2)1024 for our conversion */
-+ pageshift -= 10;
-+
-+ /* grab vm totals */
-+ mib[0] = CTL_VM;
-+ mib[1] = VM_METER;
-+ len = sizeof(vmtotal);
-+ sysctl(mib, 2, &vmtotal, &len, NULL, 0);
-+ freeram = (vmtotal.t_free << pageshift);
-+ /* generate swap usage and totals */
-+ swapmode(&usedswap, &totalswap);
-+ freeswap = (totalswap - usedswap);
-+ /* grab number of processes */
-+#if defined(__OpenBSD__)
-+ mib[0] = CTL_KERN;
-+ mib[1] = KERN_NPROCS;
-+ len = sizeof(nprocs);
-+ sysctl(mib, 2, &nprocs, &len, NULL, 0);
-+#endif
-+#endif
-+
- switch (cmd) {
- case CLI_INIT:
- e->command = "core show sysinfo";
-@@ -491,19 +635,18 @@
- case CLI_GENERATE:
- return NULL;
- }
-- if (sysinfo(&sys_info)) {
-- ast_cli(a->fd, "FAILED to retrieve system information\n\n");
-- return CLI_FAILURE;
-- }
-+
- ast_cli(a->fd, "\nSystem Statistics\n");
- ast_cli(a->fd, "-----------------\n");
-- ast_cli(a->fd, " System Uptime: %ld hours\n", sys_info.uptime/3600);
-- ast_cli(a->fd, " Total RAM: %ld KiB\n", (sys_info.totalram * sys_info.mem_unit)/1024);
-- ast_cli(a->fd, " Free RAM: %ld KiB\n", (sys_info.freeram * sys_info.mem_unit)/1024);
-+ ast_cli(a->fd, " System Uptime: %ld hours\n", uptime);
-+ ast_cli(a->fd, " Total RAM: %ld KiB\n", (long)physmem/1024);
-+ ast_cli(a->fd, " Free RAM: %ld KiB\n", (long)freeram);
-+#if defined(HAVE_SYSINFO)
- ast_cli(a->fd, " Buffer RAM: %ld KiB\n", (sys_info.bufferram * sys_info.mem_unit)/1024);
-- ast_cli(a->fd, " Total Swap Space: %ld KiB\n", (sys_info.totalswap * sys_info.mem_unit)/1024);
-- ast_cli(a->fd, " Free Swap Space: %ld KiB\n\n", (sys_info.freeswap * sys_info.mem_unit)/1024);
-- ast_cli(a->fd, " Number of Processes: %d \n\n", sys_info.procs);
-+#endif
-+ ast_cli(a->fd, " Total Swap Space: %ld KiB\n", (long)totalswap);
-+ ast_cli(a->fd, " Free Swap Space: %ld KiB\n\n", (long)freeswap);
-+ ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
- return CLI_SUCCESS;
- }
- #endif
-@@ -873,6 +1016,15 @@
- #endif
-
- if (pid == 0) {
-+#ifdef HAVE_CAP
-+ cap_t cap = cap_from_text("cap_net_admin-eip");
-+
-+ if (cap_set_proc(cap)) {
-+ /* Careful with order! Logging cannot happen after we close FDs */
-+ ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
-+ }
-+ cap_free(cap);
-+#endif
- #ifdef HAVE_WORKING_FORK
- if (ast_opt_high_priority)
- ast_set_priority(0);
-@@ -896,7 +1048,7 @@
- }
-
- ast_unreplace_sigchld();
--#else
-+#else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
- res = -1;
- #endif
-
-@@ -993,6 +1145,54 @@
-
- static pthread_t lthread;
-
-+/*!
-+ * \brief read() function supporting the reception of user credentials.
-+ *
-+ * \param fd Socket file descriptor.
-+ * \param buffer Receive buffer.
-+ * \param size 'buffer' size.
-+ * \param con Console structure to set received credentials
-+ * \retval -1 on error
-+ * \retval the number of bytes received on success.
-+ */
-+static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
-+{
-+#if defined(SO_PEERCRED)
-+ struct ucred cred;
-+ socklen_t len = sizeof(cred);
-+#endif
-+#if defined(HAVE_GETPEEREID)
-+ uid_t uid;
-+ gid_t gid;
-+#else
-+ int uid, gid;
-+#endif
-+ int result;
-+
-+ result = read(fd, buffer, size);
-+ if (result < 0) {
-+ return result;
-+ }
-+
-+#if defined(SO_PEERCRED)
-+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
-+ return result;
-+ }
-+ uid = cred.uid;
-+ gid = cred.gid;
-+#elif defined(HAVE_GETPEEREID)
-+ if (getpeereid(fd, &uid, &gid)) {
-+ return result;
-+ }
-+#else
-+ return result;
-+#endif
-+ con->uid = uid;
-+ con->gid = gid;
-+
-+ return result;
-+}
-+
- static void *netconsole(void *vconsole)
- {
- struct console *con = vconsole;
-@@ -1020,19 +1220,19 @@
- continue;
- }
- if (fds[0].revents) {
-- res = read(con->fd, tmp, sizeof(tmp));
-+ res = read_credentials(con->fd, tmp, sizeof(tmp), con);
- if (res < 1) {
- break;
- }
- tmp[res] = 0;
- if (strncmp(tmp, "cli quit after ", 15) == 0) {
-- ast_cli_command_multiple(con->fd, res - 15, tmp + 15);
-+ ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
- break;
- }
-- ast_cli_command_multiple(con->fd, res, tmp);
-+ ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
- }
- if (fds[1].revents) {
-- res = read(con->p[0], tmp, sizeof(tmp));
-+ res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
- if (res < 1) {
- ast_log(LOG_ERROR, "read returned %d\n", res);
- break;
-@@ -1042,7 +1242,9 @@
- break;
- }
- }
-- ast_verb(3, "Remote UNIX connection disconnected\n");
-+ if (!ast_opt_hide_connect) {
-+ ast_verb(3, "Remote UNIX connection disconnected\n");
-+ }
- close(con->fd);
- close(con->p[0]);
- close(con->p[1]);
-@@ -1077,8 +1279,19 @@
- if (errno != EINTR)
- ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
- } else {
-- for (x = 0; x < AST_MAX_CONNECTS; x++) {
-- if (consoles[x].fd < 0) {
-+#if !defined(SO_PASSCRED)
-+ {
-+#else
-+ int sckopt = 1;
-+ /* turn on socket credentials passing. */
-+ if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
-+ ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
-+ } else {
-+#endif
-+ for (x = 0; x < AST_MAX_CONNECTS; x++) {
-+ if (consoles[x].fd >= 0) {
-+ continue;
-+ }
- if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
- ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
- consoles[x].fd = -1;
-@@ -1090,6 +1303,10 @@
- fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
- consoles[x].fd = s;
- consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
-+ /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
-+ to know if the user didn't send the credentials. */
-+ consoles[x].uid = -2;
-+ consoles[x].gid = -2;
- if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
- ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
- close(consoles[x].p[0]);
-@@ -1100,13 +1317,14 @@
- }
- break;
- }
-+ if (x >= AST_MAX_CONNECTS) {
-+ fdprint(s, "No more connections allowed\n");
-+ ast_log(LOG_WARNING, "No more connections allowed\n");
-+ close(s);
-+ } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
-+ ast_verb(3, "Remote UNIX connection\n");
-+ }
- }
-- if (x >= AST_MAX_CONNECTS) {
-- fdprint(s, "No more connections allowed\n");
-- ast_log(LOG_WARNING, "No more connections allowed\n");
-- close(s);
-- } else if (consoles[x].fd > -1)
-- ast_verb(3, "Remote UNIX connection\n");
- }
- }
- return NULL;
-@@ -1379,7 +1597,7 @@
- if (niceness)
- ast_module_shutdown();
- }
-- if (ast_opt_console || ast_opt_remote) {
-+ if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
- if (getenv("HOME"))
- snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
- if (!ast_strlen_zero(filename))
-@@ -1600,14 +1818,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_stop_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_stop_now(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "stop now";
-- return res;
--}
--
- static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1628,14 +1838,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_stop_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_stop_gracefully(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "stop gracefully";
-- return res;
--}
--
- static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1656,14 +1858,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_stop_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_stop_when_convenient(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "stop when convenient";
-- return res;
--}
--
- static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1684,14 +1878,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_restart_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_restart_now(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "restart now";
-- return res;
--}
--
- static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1712,14 +1898,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_restart_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_restart_gracefully(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "restart gracefully";
-- return res;
--}
--
- static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1740,14 +1918,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_restart_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_restart_when_convenient(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "restart when convenient";
-- return res;
--}
--
- static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1769,14 +1939,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_abort_shutdown_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_abort_shutdown(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "abort shutdown";
-- return res;
--}
--
- static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -1876,24 +2038,14 @@
-
- #define ASTERISK_PROMPT2 "%s*CLI> "
-
--/* deprecated cli entries */
--static struct ast_cli_entry cli_abort_shutdown_deprecated = AST_CLI_DEFINE(handle_abort_shutdown_deprecated, "Cancel a running shutdown.");
--static struct ast_cli_entry cli_stop_now_deprecated = AST_CLI_DEFINE(handle_stop_now_deprecated, "Shut down Asterisk immediately.");
--static struct ast_cli_entry cli_stop_gracefully_deprecated = AST_CLI_DEFINE(handle_stop_gracefully_deprecated, "Gracefully shut down Asterisk.");
--static struct ast_cli_entry cli_stop_when_convenient_deprecated = AST_CLI_DEFINE(handle_stop_when_convenient_deprecated, "Shut down Asterisk at empty call volume.");
--static struct ast_cli_entry cli_restart_now_deprecated = AST_CLI_DEFINE(handle_restart_now_deprecated, "Restart Asterisk immediately.");
--static struct ast_cli_entry cli_restart_gracefully_deprecated = AST_CLI_DEFINE(handle_restart_gracefully_deprecated, "Restart Asterisk gracefully.");
--static struct ast_cli_entry cli_restart_when_convenient_deprecated = AST_CLI_DEFINE(handle_restart_when_convenient_deprecated, "Restart Asterisk at empty call volume.");
--/* end deprecated cli entries */
--
- static struct ast_cli_entry cli_asterisk[] = {
-- AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown", .deprecate_cmd = &cli_abort_shutdown_deprecated),
-- AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately", .deprecate_cmd = &cli_stop_now_deprecated),
-- AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk", .deprecate_cmd = &cli_stop_gracefully_deprecated),
-- AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume", .deprecate_cmd = &cli_stop_when_convenient_deprecated),
-- AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately", .deprecate_cmd = &cli_restart_now_deprecated),
-- AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully", .deprecate_cmd = &cli_restart_gracefully_deprecated),
-- AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume", .deprecate_cmd = &cli_restart_when_convenient_deprecated),
-+ AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
-+ AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
-+ AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
-+ AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
-+ AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
-+ AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
-+ AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
- AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
- AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
- AST_CLI_DEFINE(handle_version, "Display version info"),
-@@ -1901,7 +2053,7 @@
- #if !defined(LOW_MEMORY)
- AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
- AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
--#if defined(HAVE_SYSINFO)
-+#if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
- AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
- #endif
- AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
-@@ -2023,7 +2175,7 @@
- if (prompt == NULL) {
- prompt = ast_str_create(100);
- } else if (!cli_prompt_changes) {
-- return prompt->str;
-+ return ast_str_buffer(prompt);
- } else {
- ast_str_reset(prompt);
- }
-@@ -2119,18 +2271,14 @@
- t--;
- break;
- }
-- t++;
- } else {
-- if (prompt->used + 5 > prompt->len) {
-- ast_str_make_space(&prompt, prompt->len + 5);
-- }
-- prompt->str[prompt->used++] = *t++;
-- prompt->str[prompt->used] = '\0';
-+ ast_str_append(&prompt, 0, "%c", *t);
- }
-+ t++;
- }
- if (color_used) {
- /* Force colors back to normal at end */
-- ast_str_append(&prompt, 0, "%s", term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code)));
-+ ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
- }
- } else if (remotehostname) {
- ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
-@@ -2138,7 +2286,7 @@
- ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
- }
-
-- return(prompt->str);
-+ return ast_str_buffer(prompt);
- }
-
- static char **ast_el_strtoarr(char *buf)
-@@ -2388,15 +2536,17 @@
- return 0;
- }
-
-+#define MAX_HISTORY_COMMAND_LENGTH 256
-+
- static int ast_el_add_history(char *buf)
- {
- HistEvent ev;
-
- if (el_hist == NULL || el == NULL)
- ast_el_initialize();
-- if (strlen(buf) > 256)
-+ if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
- return 0;
-- return (history(el_hist, &ev, H_ENTER, buf));
-+ return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
- }
-
- static int ast_el_write_history(char *filename)
-@@ -2411,7 +2561,7 @@
-
- static int ast_el_read_history(char *filename)
- {
-- char buf[256];
-+ char buf[MAX_HISTORY_COMMAND_LENGTH];
- FILE *f;
- int ret = -1;
-
-@@ -2422,9 +2572,8 @@
- return ret;
-
- while (!feof(f)) {
-- if (!fgets(buf, sizeof(buf), f)) {
-- continue;
-- }
-+ if (!fgets(buf, sizeof(buf), f))
-+ break;
- if (!strcmp(buf, "_HiStOrY_V2_\n"))
- continue;
- if (ast_all_zeros(buf))
-@@ -2494,18 +2643,7 @@
- else
- printf("log and verbose output currently muted ('logger mute' to unmute)\n");
- }
-- ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
-- remotehostname = hostname;
-- if (getenv("HOME"))
-- snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
-- if (el_hist == NULL || el == NULL)
-- ast_el_initialize();
-
-- el_set(el, EL_GETCFN, ast_el_read_char);
--
-- if (!ast_strlen_zero(filename))
-- ast_el_read_history(filename);
--
- if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
- struct pollfd fds;
- fds.fd = ast_consock;
-@@ -2547,6 +2685,19 @@
- }
- return;
- }
-+
-+ ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
-+ remotehostname = hostname;
-+ if (getenv("HOME"))
-+ snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
-+ if (el_hist == NULL || el == NULL)
-+ ast_el_initialize();
-+
-+ el_set(el, EL_GETCFN, ast_el_read_char);
-+
-+ if (!ast_strlen_zero(filename))
-+ ast_el_read_history(filename);
-+
- for (;;) {
- ebuf = (char *)el_gets(el, &num);
-
-@@ -2612,13 +2763,14 @@
- printf(" -q Quiet mode (suppress output)\n");
- printf(" -r Connect to Asterisk on this machine\n");
- printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
-+ printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
- printf(" -t Record soundfiles in /var/tmp and move them where they\n");
- printf(" belong after they are done\n");
- printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
- printf(" of output to the CLI\n");
- printf(" -v Increase verbosity (multiple v's = more verbose)\n");
- printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
-- printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
-+ printf(" -W Adjust terminal colors to compensate for a light background\n");
- printf("\n");
- return 0;
- }
-@@ -2637,7 +2789,7 @@
-
- if (ast_opt_override_config) {
- cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
-- if (!cfg)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
- } else
- cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
-@@ -2660,7 +2812,7 @@
- ast_set_default_eid(&g_eid);
-
- /* no asterisk.conf? no problem, use buildtime config! */
-- if (!cfg) {
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- return;
- }
-
-@@ -2831,6 +2983,12 @@
- g_eid = tmp_eid;
- } else
- ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
-+ } else if (!strcasecmp(v->name, "lightbackground")) {
-+ ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
-+ } else if (!strcasecmp(v->name, "forceblackbackground")) {
-+ ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
-+ } else if (!strcasecmp(v->name, "hideconnect")) {
-+ ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
- }
- }
- for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
-@@ -2909,6 +3067,9 @@
-
- if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
- return;
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
-+ return;
-+ }
-
- fd = open("/dev/null", O_RDWR);
- if (fd < 0) {
-@@ -2971,7 +3132,7 @@
- if (getenv("HOME"))
- snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
- /* Check for options */
-- while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:")) != -1) {
-+ while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:WB")) != -1) {
- switch (c) {
- #if defined(HAVE_SYSINFO)
- case 'e':
-@@ -3063,6 +3224,14 @@
- case 's':
- remotesock = ast_strdupa(optarg);
- break;
-+ case 'W': /* White background */
-+ ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
-+ ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
-+ break;
-+ case 'B': /* Force black background */
-+ ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
-+ ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
-+ break;
- case '?':
- exit(1);
- }
-@@ -3130,8 +3299,20 @@
- if (isroot) {
- ast_set_priority(ast_opt_high_priority);
- if (ast_opt_high_priority) {
-+ int cpipe[2];
-+
-+ /* PIPE signal ensures that astcanary dies when Asterisk dies */
-+ if (pipe(cpipe)) {
-+ fprintf(stderr, "Unable to open pipe for canary process: %s\n", strerror(errno));
-+ exit(1);
-+ }
-+ canary_pipe = cpipe[0];
-+
- snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
-
-+ /* Don't let the canary child kill Asterisk, if it dies immediately */
-+ signal(SIGPIPE, SIG_IGN);
-+
- canary_pid = fork();
- if (canary_pid == 0) {
- char canary_binary[128], *lastslash;
-@@ -3139,9 +3320,14 @@
-
- /* Reset signal handler */
- signal(SIGCHLD, SIG_DFL);
-+ signal(SIGPIPE, SIG_DFL);
-
-- for (fd = 0; fd < 100; fd++)
-+ dup2(cpipe[1], 100);
-+ close(cpipe[1]);
-+
-+ for (fd = 0; fd < 100; fd++) {
- close(fd);
-+ }
-
- execlp("astcanary", "astcanary", canary_filename, (char *)NULL);
-
-@@ -3156,6 +3342,7 @@
- _exit(1);
- } else if (canary_pid > 0) {
- pthread_t dont_care;
-+ close(cpipe[1]);
- ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
- }
-
-@@ -3223,7 +3410,7 @@
- if (has_cap) {
- cap_t cap;
-
-- cap = cap_from_text("cap_net_admin=ep");
-+ cap = cap_from_text("cap_net_admin=eip");
-
- if (cap_set_proc(cap))
- ast_log(LOG_WARNING, "Unable to install capabilities.\n");
-@@ -3352,6 +3539,11 @@
- exit(1);
- }
-
-+#ifdef AST_XML_DOCS
-+ /* Load XML documentation. */
-+ ast_xmldoc_load_documentation();
-+#endif
-+
- if (load_modules(1)) { /* Load modules, pre-load only */
- printf("%s", term_quit());
- exit(1);
-@@ -3395,6 +3587,11 @@
- exit(1);
- }
-
-+ if (ast_indications_init()) {
-+ printf("%s", term_quit());
-+ exit(1);
-+ }
-+
- ast_features_init();
-
- if (init_framer()) {
-@@ -3417,6 +3614,9 @@
- exit(1);
- }
-
-+ /* loads the cli_permissoins.conf file needed to implement cli restrictions. */
-+ ast_cli_perms_init(0);
-+
- /* AMI is initialized after loading modules because of a potential
- * conflict between issuing a module reload from manager and
- * registering manager actions. This will cause reversed locking
-@@ -3448,7 +3648,7 @@
- #endif
-
- ast_lastreloadtime = ast_startuptime = ast_tvnow();
-- ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
-
- run_startup_commands();
-
-Index: main/dsp.c
-===================================================================
---- a/main/dsp.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/dsp.c (.../team/group/issue14292) (revision 178988)
-@@ -82,7 +82,9 @@
- HZ_425 = 0,
-
- /*! For UK mode */
-- HZ_400 = 0
-+ HZ_350UK = 0,
-+ HZ_400UK,
-+ HZ_440UK
- };
-
- static struct progalias {
-@@ -102,7 +104,7 @@
- } modes[] = {
- { GSAMP_SIZE_NA, { 350, 440, 480, 620, 950, 1400, 1800 } }, /*!< North America */
- { GSAMP_SIZE_CR, { 425 } }, /*!< Costa Rica, Brazil */
-- { GSAMP_SIZE_UK, { 400 } }, /*!< UK */
-+ { GSAMP_SIZE_UK, { 350, 400, 440 } }, /*!< UK */
- };
-
- /*!\brief This value is the minimum threshold, calculated by averaging all
-@@ -322,8 +324,9 @@
- {
- int i;
-
-- for (i=0;i<count;i++)
-+ for (i = 0; i < count; i++) {
- goertzel_sample(s, samps[i]);
-+ }
- }
-
-
-@@ -481,8 +484,8 @@
- s->lasthit = 0;
- s->current_hit = 0;
- for (i = 0; i < 4; i++) {
-- goertzel_init (&s->row_out[i], dtmf_row[i], DTMF_GSIZE);
-- goertzel_init (&s->col_out[i], dtmf_col[i], DTMF_GSIZE);
-+ goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE);
-+ goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE);
- s->energy = 0.0;
- }
- s->current_sample = 0;
-@@ -511,10 +514,11 @@
- s->lost_digits = 0;
- s->digits[0] = '\0';
-
-- if (mf)
-+ if (mf) {
- ast_mf_detect_init(&s->td.mf);
-- else
-+ } else {
- ast_dtmf_detect_init(&s->td.dtmf);
-+ }
- }
-
- static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp, int samples)
-@@ -536,8 +540,9 @@
- for (start = 0; start < samples; start = end) {
- /* Process in blocks. */
- limit = samples - start;
-- if (limit > s->samples_pending)
-+ if (limit > s->samples_pending) {
- limit = s->samples_pending;
-+ }
- end = start + limit;
-
- for (i = limit, ptr = amp ; i > 0; i--, ptr++) {
-@@ -567,8 +572,9 @@
- hit = 1;
- }
-
-- if (s->hit_count)
-+ if (s->hit_count) {
- s->hit_count++;
-+ }
-
- if (hit == s->last_hit) {
- if (!hit) {
-@@ -651,12 +657,13 @@
- }
-
- hit = 0;
-- for (sample = 0; sample < samples; sample = limit) {
-+ for (sample = 0; sample < samples; sample = limit) {
- /* DTMF_GSIZE is optimised to meet the DTMF specs. */
-- if ((samples - sample) >= (DTMF_GSIZE - s->td.dtmf.current_sample))
-+ if ((samples - sample) >= (DTMF_GSIZE - s->td.dtmf.current_sample)) {
- limit = sample + (DTMF_GSIZE - s->td.dtmf.current_sample);
-- else
-+ } else {
- limit = samples;
-+ }
- /* The following unrolled loop takes only 35% (rough estimate) of the
- time of a rolled loop on the machine on which it was developed */
- for (j = sample; j < limit; j++) {
-@@ -684,30 +691,32 @@
-
- for (best_row = best_col = 0, i = 1; i < 4; i++) {
- row_energy[i] = goertzel_result (&s->td.dtmf.row_out[i]);
-- if (row_energy[i] > row_energy[best_row])
-+ if (row_energy[i] > row_energy[best_row]) {
- best_row = i;
-+ }
- col_energy[i] = goertzel_result (&s->td.dtmf.col_out[i]);
-- if (col_energy[i] > col_energy[best_col])
-+ if (col_energy[i] > col_energy[best_col]) {
- best_col = i;
-+ }
- }
- hit = 0;
- /* Basic signal level test and the twist test */
- if (row_energy[best_row] >= DTMF_THRESHOLD &&
- col_energy[best_col] >= DTMF_THRESHOLD &&
-- col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
-- col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
-+ col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST &&
-+ col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row]) {
- /* Relative peak test */
- for (i = 0; i < 4; i++) {
- if ((i != best_col &&
-- col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
-+ col_energy[i] * DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
- (i != best_row
-- && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
-+ && row_energy[i] * DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
- break;
- }
- }
- /* ... and fraction of total energy test */
- if (i >= 4 &&
-- (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->td.dtmf.energy) {
-+ (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY * s->td.dtmf.energy) {
- /* Got a hit */
- hit = dtmf_positions[(best_row << 2) + best_col];
- }
-@@ -758,7 +767,7 @@
- }
-
- /* Reinitialise the detector for the next block */
-- for (i = 0; i < 4; i++) {
-+ for (i = 0; i < 4; i++) {
- goertzel_reset(&s->td.dtmf.row_out[i]);
- goertzel_reset(&s->td.dtmf.col_out[i]);
- }
-@@ -800,10 +809,11 @@
- for (sample = 0; sample < samples; sample = limit) {
- /* 80 is optimised to meet the MF specs. */
- /* XXX So then why is MF_GSIZE defined as 120? */
-- if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample))
-+ if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample)) {
- limit = sample + (MF_GSIZE - s->td.mf.current_sample);
-- else
-+ } else {
- limit = samples;
-+ }
- /* The following unrolled loop takes only 35% (rough estimate) of the
- time of a rolled loop on the machine on which it was developed */
- for (j = sample; j < limit; j++) {
-@@ -838,7 +848,7 @@
- second_best = 0;
- }
- /*endif*/
-- for (i=2;i<6;i++) {
-+ for (i = 2; i < 6; i++) {
- energy[i] = goertzel_result(&s->td.mf.tone_out[i]);
- if (energy[i] >= energy[best]) {
- second_best = best;
-@@ -851,10 +861,10 @@
- hit = 0;
- if (energy[best] >= BELL_MF_THRESHOLD && energy[second_best] >= BELL_MF_THRESHOLD
- && energy[best] < energy[second_best]*BELL_MF_TWIST
-- && energy[best]*BELL_MF_TWIST > energy[second_best]) {
-+ && energy[best] * BELL_MF_TWIST > energy[second_best]) {
- /* Relative peak test */
- hit = -1;
-- for (i=0;i<6;i++) {
-+ for (i = 0; i < 6; i++) {
- if (i != best && i != second_best) {
- if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best]) {
- /* The best two are not clearly the best */
-@@ -871,7 +881,7 @@
- best = second_best;
- second_best = i;
- }
-- best = best*5 + second_best - 1;
-+ best = best * 5 + second_best - 1;
- hit = bell_mf_positions[best];
- /* Look for two successive similar results */
- /* The logic in the next test is:
-@@ -930,18 +940,21 @@
- {
- /* See if p1 and p2 are there, relative to i1 and i2 and total energy */
- /* Make sure absolute levels are high enough */
-- if ((p1 < TONE_MIN_THRESH) || (p2 < TONE_MIN_THRESH))
-+ if ((p1 < TONE_MIN_THRESH) || (p2 < TONE_MIN_THRESH)) {
- return 0;
-+ }
- /* Amplify ignored stuff */
- i2 *= TONE_THRESH;
- i1 *= TONE_THRESH;
- e *= TONE_THRESH;
- /* Check first tone */
-- if ((p1 < i1) || (p1 < i2) || (p1 < e))
-+ if ((p1 < i1) || (p1 < i2) || (p1 < e)) {
- return 0;
-+ }
- /* And second */
-- if ((p2 < i1) || (p2 < i2) || (p2 < e))
-+ if ((p2 < i1) || (p2 < i2) || (p2 < e)) {
- return 0;
-+ }
- /* Guess it's there... */
- return 1;
- }
-@@ -956,11 +969,13 @@
- while (len) {
- /* Take the lesser of the number of samples we need and what we have */
- pass = len;
-- if (pass > dsp->gsamp_size - dsp->gsamps)
-+ if (pass > dsp->gsamp_size - dsp->gsamps) {
- pass = dsp->gsamp_size - dsp->gsamps;
-- for (x=0;x<pass;x++) {
-- for (y=0;y<dsp->freqcount;y++)
-+ }
-+ for (x = 0; x < pass; x++) {
-+ for (y = 0; y < dsp->freqcount; y++) {
- goertzel_sample(&dsp->freqs[y], s[x]);
-+ }
- dsp->genergy += s[x] * s[x];
- }
- s += pass;
-@@ -968,8 +983,9 @@
- len -= pass;
- if (dsp->gsamps == dsp->gsamp_size) {
- float hz[7];
-- for (y=0;y<7;y++)
-+ for (y = 0; y < 7; y++) {
- hz[y] = goertzel_result(&dsp->freqs[y]);
-+ }
- switch (dsp->progmode) {
- case PROG_MODE_NA:
- if (pair_there(hz[HZ_480], hz[HZ_620], hz[HZ_350], hz[HZ_440], dsp->genergy)) {
-@@ -984,24 +1000,29 @@
- if (dsp->tstate == DSP_TONE_STATE_SPECIAL1)
- newstate = DSP_TONE_STATE_SPECIAL2;
- } else if (hz[HZ_1800] > TONE_MIN_THRESH * TONE_THRESH) {
-- if (dsp->tstate == DSP_TONE_STATE_SPECIAL2)
-+ if (dsp->tstate == DSP_TONE_STATE_SPECIAL2) {
- newstate = DSP_TONE_STATE_SPECIAL3;
-+ }
- } else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = DSP_TONE_STATE_TALKING;
-- } else
-+ } else {
- newstate = DSP_TONE_STATE_SILENCE;
-+ }
- break;
- case PROG_MODE_CR:
- if (hz[HZ_425] > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = DSP_TONE_STATE_RINGING;
- } else if (dsp->genergy > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = DSP_TONE_STATE_TALKING;
-- } else
-+ } else {
- newstate = DSP_TONE_STATE_SILENCE;
-+ }
- break;
- case PROG_MODE_UK:
-- if (hz[HZ_400] > TONE_MIN_THRESH * TONE_THRESH) {
-+ if (hz[HZ_400UK] > TONE_MIN_THRESH * TONE_THRESH) {
- newstate = DSP_TONE_STATE_HUNGUP;
-+ } else if (pair_there(hz[HZ_350UK], hz[HZ_440UK], hz[HZ_400UK], hz[HZ_400UK], dsp->genergy)) {
-+ newstate = DSP_TONE_STATE_DIALTONE;
- }
- break;
- default:
-@@ -1009,8 +1030,9 @@
- }
- if (newstate == dsp->tstate) {
- dsp->tcount++;
-- if (dsp->ringtimeout)
-+ if (dsp->ringtimeout) {
- dsp->ringtimeout++;
-+ }
- switch (dsp->tstate) {
- case DSP_TONE_STATE_RINGING:
- if ((dsp->features & DSP_PROGRESS_RINGING) &&
-@@ -1061,8 +1083,9 @@
- }
-
- /* Reset goertzel */
-- for (x=0;x<7;x++)
-+ for (x = 0; x < 7; x++) {
- dsp->freqs[x].v2 = dsp->freqs[x].v3 = 0.0;
-+ }
- dsp->gsamps = 0;
- dsp->genergy = 0.0;
- }
-@@ -1090,18 +1113,20 @@
- int x;
- int res = 0;
-
-- if (!len)
-+ if (!len) {
- return 0;
-+ }
- accum = 0;
-- for (x=0;x<len; x++)
-+ for (x = 0; x < len; x++) {
- accum += abs(s[x]);
-+ }
- accum /= len;
- if (accum < dsp->threshold) {
- /* Silent */
-- dsp->totalsilence += len/8;
-+ dsp->totalsilence += len / 8;
- if (dsp->totalnoise) {
- /* Move and save history */
-- memmove(dsp->historicnoise + DSP_HISTORY - dsp->busycount, dsp->historicnoise + DSP_HISTORY - dsp->busycount +1, dsp->busycount*sizeof(dsp->historicnoise[0]));
-+ memmove(dsp->historicnoise + DSP_HISTORY - dsp->busycount, dsp->historicnoise + DSP_HISTORY - dsp->busycount + 1, dsp->busycount * sizeof(dsp->historicnoise[0]));
- dsp->historicnoise[DSP_HISTORY - 1] = dsp->totalnoise;
- /* we don't want to check for busydetect that frequently */
- #if 0
-@@ -1112,32 +1137,36 @@
- res = 1;
- } else {
- /* Not silent */
-- dsp->totalnoise += len/8;
-+ dsp->totalnoise += len / 8;
- if (dsp->totalsilence) {
- int silence1 = dsp->historicsilence[DSP_HISTORY - 1];
- int silence2 = dsp->historicsilence[DSP_HISTORY - 2];
- /* Move and save history */
-- memmove(dsp->historicsilence + DSP_HISTORY - dsp->busycount, dsp->historicsilence + DSP_HISTORY - dsp->busycount + 1, dsp->busycount*sizeof(dsp->historicsilence[0]));
-+ memmove(dsp->historicsilence + DSP_HISTORY - dsp->busycount, dsp->historicsilence + DSP_HISTORY - dsp->busycount + 1, dsp->busycount * sizeof(dsp->historicsilence[0]));
- dsp->historicsilence[DSP_HISTORY - 1] = dsp->totalsilence;
- /* check if the previous sample differs only by BUSY_PERCENT from the one before it */
- if (silence1 < silence2) {
-- if (silence1 + silence1*BUSY_PERCENT/100 >= silence2)
-+ if (silence1 + silence1 * BUSY_PERCENT / 100 >= silence2) {
- dsp->busymaybe = 1;
-- else
-+ } else {
- dsp->busymaybe = 0;
-+ }
- } else {
-- if (silence1 - silence1*BUSY_PERCENT/100 <= silence2)
-+ if (silence1 - silence1 * BUSY_PERCENT / 100 <= silence2) {
- dsp->busymaybe = 1;
-- else
-+ } else {
- dsp->busymaybe = 0;
-+ }
- }
- }
- dsp->totalsilence = 0;
- }
-- if (totalsilence)
-+ if (totalsilence) {
- *totalsilence = dsp->totalsilence;
-- if (totalnoise)
-+ }
-+ if (totalnoise) {
- *totalnoise = dsp->totalnoise;
-+ }
- return res;
- }
-
-@@ -1148,9 +1177,10 @@
- int avgsilence = 0, hitsilence = 0;
- #endif
- int avgtone = 0, hittone = 0;
-- if (!dsp->busymaybe)
-+ if (!dsp->busymaybe) {
- return res;
-- for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) {
-+ }
-+ for (x = DSP_HISTORY - dsp->busycount; x < DSP_HISTORY; x++) {
- #ifndef BUSYDETECT_TONEONLY
- avgsilence += dsp->historicsilence[x];
- #endif
-@@ -1160,22 +1190,26 @@
- avgsilence /= dsp->busycount;
- #endif
- avgtone /= dsp->busycount;
-- for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) {
-+ for (x = DSP_HISTORY - dsp->busycount; x < DSP_HISTORY; x++) {
- #ifndef BUSYDETECT_TONEONLY
- if (avgsilence > dsp->historicsilence[x]) {
-- if (avgsilence - (avgsilence*BUSY_PERCENT/100) <= dsp->historicsilence[x])
-+ if (avgsilence - (avgsilence * BUSY_PERCENT / 100) <= dsp->historicsilence[x]) {
- hitsilence++;
-+ }
- } else {
-- if (avgsilence + (avgsilence*BUSY_PERCENT/100) >= dsp->historicsilence[x])
-+ if (avgsilence + (avgsilence * BUSY_PERCENT / 100) >= dsp->historicsilence[x]) {
- hitsilence++;
-+ }
- }
- #endif
- if (avgtone > dsp->historicnoise[x]) {
-- if (avgtone - (avgtone*BUSY_PERCENT/100) <= dsp->historicnoise[x])
-+ if (avgtone - (avgtone * BUSY_PERCENT / 100) <= dsp->historicnoise[x]) {
- hittone++;
-+ }
- } else {
-- if (avgtone + (avgtone*BUSY_PERCENT/100) >= dsp->historicnoise[x])
-+ if (avgtone + (avgtone * BUSY_PERCENT / 100) >= dsp->historicnoise[x]) {
- hittone++;
-+ }
- }
- }
- #ifndef BUSYDETECT_TONEONLY
-@@ -1187,11 +1221,13 @@
- #endif
- #ifdef BUSYDETECT_COMPARE_TONE_AND_SILENCE
- if (avgtone > avgsilence) {
-- if (avgtone - avgtone*BUSY_PERCENT/100 <= avgsilence)
-+ if (avgtone - avgtone*BUSY_PERCENT/100 <= avgsilence) {
- res = 1;
-+ }
- } else {
-- if (avgtone + avgtone*BUSY_PERCENT/100 >= avgsilence)
-+ if (avgtone + avgtone*BUSY_PERCENT/100 >= avgsilence) {
- res = 1;
-+ }
- }
- #else
- res = 1;
-@@ -1277,10 +1313,12 @@
- int len;
- struct ast_frame *outf = NULL;
-
-- if (!af)
-+ if (!af) {
- return NULL;
-- if (af->frametype != AST_FRAME_VOICE)
-+ }
-+ if (af->frametype != AST_FRAME_VOICE) {
- return af;
-+ }
-
- odata = af->data.ptr;
- len = af->datalen;
-@@ -1292,13 +1330,15 @@
- break;
- case AST_FORMAT_ULAW:
- shortdata = alloca(af->datalen * 2);
-- for (x = 0;x < len; x++)
-+ for (x = 0;x < len; x++) {
- shortdata[x] = AST_MULAW(odata[x]);
-+ }
- break;
- case AST_FORMAT_ALAW:
- shortdata = alloca(af->datalen * 2);
-- for (x = 0; x < len; x++)
-+ for (x = 0; x < len; x++) {
- shortdata[x] = AST_ALAW(odata[x]);
-+ }
- break;
- default:
- ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(af->subclass));
-@@ -1408,6 +1448,8 @@
- ast_log(LOG_WARNING, "Don't know how to represent call progress message %d\n", res);
- }
- }
-+ } else if ((dsp->features & DSP_FEATURE_WAITDIALTONE)) {
-+ res = __ast_dsp_call_progress(dsp, shortdata, len);
- }
-
- done:
-@@ -1420,18 +1462,21 @@
- case AST_FORMAT_SLINEAR:
- break;
- case AST_FORMAT_ULAW:
-- for (x = 0; x < len; x++)
-+ for (x = 0; x < len; x++) {
- odata[x] = AST_LIN2MU((unsigned short) shortdata[x]);
-+ }
- break;
- case AST_FORMAT_ALAW:
-- for (x = 0; x < len; x++)
-+ for (x = 0; x < len; x++) {
- odata[x] = AST_LIN2A((unsigned short) shortdata[x]);
-+ }
- break;
- }
-
- if (outf) {
-- if (chan)
-+ if (chan) {
- ast_queue_frame(chan, af);
-+ }
- ast_frfree(af);
- ast_set_flag(outf, AST_FRFLAG_FROM_DSP);
- return outf;
-@@ -1504,10 +1549,12 @@
-
- void ast_dsp_set_busy_count(struct ast_dsp *dsp, int cadences)
- {
-- if (cadences < 4)
-+ if (cadences < 4) {
- cadences = 4;
-- if (cadences > DSP_HISTORY)
-+ }
-+ if (cadences > DSP_HISTORY) {
- cadences = DSP_HISTORY;
-+ }
- dsp->busycount = cadences;
- }
-
-@@ -1555,8 +1602,9 @@
-
- dsp->totalsilence = 0;
- dsp->gsamps = 0;
-- for (x=0;x<4;x++)
-+ for (x = 0; x < 4; x++) {
- dsp->freqs[x].v2 = dsp->freqs[x].v3 = 0.0;
-+ }
- memset(dsp->historicsilence, 0, sizeof(dsp->historicsilence));
- memset(dsp->historicnoise, 0, sizeof(dsp->historicnoise));
- dsp->ringtimeout= 0;
-@@ -1621,6 +1669,9 @@
- struct ast_config *cfg;
-
- cfg = ast_config_load2(CONFIG_FILE_NAME, "dsp", config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
-+ return 0;
-+ }
-
- if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED) {
- const char *value;
-@@ -1629,8 +1680,9 @@
- if (value && sscanf(value, "%d", &thresholds[THRESHOLD_SILENCE]) != 1) {
- ast_log(LOG_WARNING, "%s: '%s' is not a valid silencethreshold value\n", CONFIG_FILE_NAME, value);
- thresholds[THRESHOLD_SILENCE] = 256;
-- } else if (!value)
-+ } else if (!value) {
- thresholds[THRESHOLD_SILENCE] = 256;
-+ }
-
- ast_config_destroy(cfg);
- }
-Index: main/timing.c
-===================================================================
---- a/main/timing.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/timing.c (.../team/group/issue14292) (revision 178988)
-@@ -1,9 +1,10 @@
- /*
- * Asterisk -- An open source telephony toolkit.
- *
-- * Copyright (C) 2008, Digium, Inc.
-+ * Copyright (C) 2008 - 2009, Digium, Inc.
- *
- * Kevin P. Fleming <kpfleming@digium.com>
-+ * Russell Bryant <russell@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
-@@ -21,6 +22,7 @@
- * \brief Timing source management
- *
- * \author Kevin P. Fleming <kpfleming@digium.com>
-+ * \author Russell Bryant <russell@digium.com>
- */
-
- #include "asterisk.h"
-@@ -34,13 +36,37 @@
- #include "asterisk/cli.h"
- #include "asterisk/utils.h"
- #include "asterisk/time.h"
-+#include "asterisk/heap.h"
-+#include "asterisk/module.h"
-
--AST_RWLOCK_DEFINE_STATIC(lock);
-+struct timing_holder {
-+ /*! Do _not_ move this from the beginning of the struct. */
-+ ssize_t __heap_index;
-+ struct ast_module *mod;
-+ struct ast_timing_interface *iface;
-+};
-
--static struct ast_timing_functions timer_funcs;
-+static struct ast_heap *timing_interfaces;
-
--void *ast_install_timing_functions(struct ast_timing_functions *funcs)
-+static int timing_holder_cmp(void *_h1, void *_h2)
- {
-+ struct timing_holder *h1 = _h1;
-+ struct timing_holder *h2 = _h2;
-+
-+ if (h1->iface->priority > h2->iface->priority) {
-+ return 1;
-+ } else if (h1->iface->priority == h2->iface->priority) {
-+ return 0;
-+ } else {
-+ return -1;
-+ }
-+}
-+
-+void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
-+ struct ast_module *mod)
-+{
-+ struct timing_holder *h;
-+
- if (!funcs->timer_open ||
- !funcs->timer_close ||
- !funcs->timer_set_rate ||
-@@ -52,162 +78,158 @@
- return NULL;
- }
-
-- ast_rwlock_wrlock(&lock);
--
-- if (timer_funcs.timer_open) {
-- ast_rwlock_unlock(&lock);
-- ast_log(LOG_NOTICE, "Multiple timing modules are loaded. You should only load one.\n");
-+ if (!(h = ast_calloc(1, sizeof(*h)))) {
- return NULL;
- }
--
-- timer_funcs = *funcs;
-
-- ast_rwlock_unlock(&lock);
-+ h->iface = funcs;
-+ h->mod = mod;
-
-- return &timer_funcs;
-+ ast_heap_wrlock(timing_interfaces);
-+ ast_heap_push(timing_interfaces, h);
-+ ast_heap_unlock(timing_interfaces);
-+
-+ return h;
- }
-
--void ast_uninstall_timing_functions(void *handle)
-+int ast_unregister_timing_interface(void *handle)
- {
-- ast_rwlock_wrlock(&lock);
-+ struct timing_holder *h = handle;
-+ int res = -1;
-
-- if (handle != &timer_funcs) {
-- ast_rwlock_unlock(&lock);
-- return;
-+ ast_heap_wrlock(timing_interfaces);
-+ h = ast_heap_remove(timing_interfaces, h);
-+ ast_heap_unlock(timing_interfaces);
-+
-+ if (h) {
-+ ast_free(h);
-+ h = NULL;
-+ res = 0;
- }
-
-- memset(&timer_funcs, 0, sizeof(timer_funcs));
--
-- ast_rwlock_unlock(&lock);
-+ return res;
- }
-
- int ast_timer_open(void)
- {
-- int timer;
-+ int fd = -1;
-+ struct timing_holder *h;
-
-- ast_rwlock_rdlock(&lock);
-+ ast_heap_rdlock(timing_interfaces);
-
-- if (!timer_funcs.timer_open) {
-- ast_rwlock_unlock(&lock);
-- return -1;
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ fd = h->iface->timer_open();
-+ ast_module_ref(h->mod);
- }
-
-- timer = timer_funcs.timer_open();
-+ ast_heap_unlock(timing_interfaces);
-
-- ast_rwlock_unlock(&lock);
--
-- return timer;
-+ return fd;
- }
-
- void ast_timer_close(int timer)
- {
-- ast_rwlock_rdlock(&lock);
-+ struct timing_holder *h;
-
-- if (!timer_funcs.timer_close) {
-- ast_rwlock_unlock(&lock);
-- return;
-+ ast_heap_rdlock(timing_interfaces);
-+
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ h->iface->timer_close(timer);
-+ ast_module_unref(h->mod);
- }
-
-- timer_funcs.timer_close(timer);
--
-- ast_rwlock_unlock(&lock);
-+ ast_heap_unlock(timing_interfaces);
- }
-
- int ast_timer_set_rate(int handle, unsigned int rate)
- {
-- int res;
-+ struct timing_holder *h;
-+ int res = -1;
-
-- ast_rwlock_rdlock(&lock);
-+ ast_heap_rdlock(timing_interfaces);
-
-- if (!timer_funcs.timer_set_rate) {
-- ast_rwlock_unlock(&lock);
-- return -1;
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ res = h->iface->timer_set_rate(handle, rate);
- }
-
-- res = timer_funcs.timer_set_rate(handle, rate);
-+ ast_heap_unlock(timing_interfaces);
-
-- ast_rwlock_unlock(&lock);
--
- return res;
- }
-
- void ast_timer_ack(int handle, unsigned int quantity)
- {
-- ast_rwlock_rdlock(&lock);
-+ struct timing_holder *h;
-
-- if (!timer_funcs.timer_ack) {
-- ast_rwlock_unlock(&lock);
-- return;
-+ ast_heap_rdlock(timing_interfaces);
-+
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ h->iface->timer_ack(handle, quantity);
- }
-
-- timer_funcs.timer_ack(handle, quantity);
--
-- ast_rwlock_unlock(&lock);
-+ ast_heap_unlock(timing_interfaces);
- }
-
- int ast_timer_enable_continuous(int handle)
- {
-- int result;
-+ struct timing_holder *h;
-+ int res = -1;
-
-- ast_rwlock_rdlock(&lock);
-+ ast_heap_rdlock(timing_interfaces);
-
-- if (!timer_funcs.timer_enable_continuous) {
-- ast_rwlock_unlock(&lock);
-- return -1;
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ res = h->iface->timer_enable_continuous(handle);
- }
-
-- result = timer_funcs.timer_enable_continuous(handle);
-+ ast_heap_unlock(timing_interfaces);
-
-- ast_rwlock_unlock(&lock);
--
-- return result;
-+ return res;
- }
-
- int ast_timer_disable_continuous(int handle)
- {
-- int result;
-+ struct timing_holder *h;
-+ int res = -1;
-
-- ast_rwlock_rdlock(&lock);
-+ ast_heap_rdlock(timing_interfaces);
-
-- if (!timer_funcs.timer_disable_continuous) {
-- ast_rwlock_unlock(&lock);
-- return -1;
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ res = h->iface->timer_disable_continuous(handle);
- }
-
-- result = timer_funcs.timer_disable_continuous(handle);
-+ ast_heap_unlock(timing_interfaces);
-
-- ast_rwlock_unlock(&lock);
--
-- return result;
-+ return res;
- }
-
--enum ast_timing_event ast_timer_get_event(int handle)
-+enum ast_timer_event ast_timer_get_event(int handle)
- {
-- enum ast_timing_event result;
-+ struct timing_holder *h;
-+ enum ast_timer_event res = -1;
-
-- ast_rwlock_rdlock(&lock);
-+ ast_heap_rdlock(timing_interfaces);
-
-- if (!timer_funcs.timer_get_event) {
-- ast_rwlock_unlock(&lock);
-- return -1;
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ res = h->iface->timer_get_event(handle);
- }
-
-- result = timer_funcs.timer_get_event(handle);
-+ ast_heap_unlock(timing_interfaces);
-
-- ast_rwlock_unlock(&lock);
--
-- return result;
-+ return res;
- }
-
- unsigned int ast_timer_get_max_rate(int handle)
- {
-- unsigned int res;
-+ struct timing_holder *h;
-+ unsigned int res = 0;
-
-- ast_rwlock_rdlock(&lock);
-+ ast_heap_rdlock(timing_interfaces);
-
-- res = timer_funcs.timer_get_max_rate(handle);
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ res = h->iface->timer_get_max_rate(handle);
-+ }
-
-- ast_rwlock_unlock(&lock);
-+ ast_heap_unlock(timing_interfaces);
-
- return res;
- }
-@@ -217,6 +239,7 @@
- int fd, count = 0;
- struct timeval start, end;
- unsigned int test_rate = 50;
-+ struct timing_holder *h;
-
- switch (cmd) {
- case CLI_INIT:
-@@ -242,13 +265,20 @@
- }
- }
-
-- ast_cli(a->fd, "Attempting to test a timer with %u ticks per second ...\n", test_rate);
-+ ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
-
- if ((fd = ast_timer_open()) == -1) {
- ast_cli(a->fd, "Failed to open timing fd\n");
- return CLI_FAILURE;
- }
-
-+ ast_heap_rdlock(timing_interfaces);
-+ if ((h = ast_heap_peek(timing_interfaces, 1))) {
-+ ast_cli(a->fd, "Using the '%s' timing module for this test.\n", h->iface->name);
-+ h = NULL;
-+ }
-+ ast_heap_unlock(timing_interfaces);
-+
- start = ast_tvnow();
-
- ast_timer_set_rate(fd, test_rate);
-@@ -286,5 +316,9 @@
-
- int ast_timing_init(void)
- {
-+ if (!(timing_interfaces = ast_heap_create(2, timing_holder_cmp, 0))) {
-+ return -1;
-+ }
-+
- return ast_cli_register_multiple(cli_timing, ARRAY_LEN(cli_timing));
- }
-Index: main/udptl.c
-===================================================================
---- a/main/udptl.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/udptl.c (.../team/group/issue14292) (revision 178988)
-@@ -86,7 +86,7 @@
- static int udptlfecspan;
- static int udptlmaxdatagram;
-
--#define LOCAL_FAX_MAX_DATAGRAM 400
-+#define LOCAL_FAX_MAX_DATAGRAM 1400
- #define MAX_FEC_ENTRIES 5
- #define MAX_FEC_SPAN 5
-
-@@ -159,7 +159,7 @@
- static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
-
- static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len);
--static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, uint8_t *ifp, int ifp_len);
-+static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len);
-
- static inline int udptl_debug_test_addr(struct sockaddr_in *addr)
- {
-@@ -257,7 +257,7 @@
- }
- /*- End of function --------------------------------------------------------*/
-
--static int encode_open_type(uint8_t *buf, int *len, const uint8_t *data, int num_octets)
-+static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *data, int num_octets)
- {
- int enclen;
- int octet_idx;
-@@ -273,6 +273,10 @@
- for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) {
- if ((enclen = encode_length(buf, len, num_octets)) < 0)
- return -1;
-+ if (enclen + *len > buflen) {
-+ ast_log(LOG_ERROR, "Buffer overflow detected (%d + %d > %d)\n", enclen, *len, buflen);
-+ return -1;
-+ }
- if (enclen > 0) {
- memcpy(&buf[*len], &data[octet_idx], enclen);
- *len += enclen;
-@@ -493,9 +497,9 @@
- }
- /*- End of function --------------------------------------------------------*/
-
--static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, uint8_t *ifp, int ifp_len)
-+static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len)
- {
-- uint8_t fec[LOCAL_FAX_MAX_DATAGRAM];
-+ uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2];
- int i;
- int j;
- int seq;
-@@ -525,7 +529,7 @@
- buf[len++] = seq & 0xFF;
-
- /* Encode the primary IFP packet */
-- if (encode_open_type(buf, &len, ifp, ifp_len) < 0)
-+ if (encode_open_type(buf, buflen, &len, ifp, ifp_len) < 0)
- return -1;
-
- /* Encode the appropriate type of error recovery information */
-@@ -553,8 +557,12 @@
- /* Encode the elements */
- for (i = 0; i < entries; i++) {
- j = (entry - i - 1) & UDPTL_BUF_MASK;
-- if (encode_open_type(buf, &len, s->tx[j].buf, s->tx[j].buf_len) < 0)
-+ if (encode_open_type(buf, buflen, &len, s->tx[j].buf, s->tx[j].buf_len) < 0) {
-+ if (option_debug) {
-+ ast_log(LOG_DEBUG, "Encoding failed at i=%d, j=%d\n", i, j);
-+ }
- return -1;
-+ }
- }
- break;
- case UDPTL_ERROR_CORRECTION_FEC:
-@@ -591,7 +599,7 @@
- fec[j] ^= s->tx[i].buf[j];
- }
- }
-- if (encode_open_type(buf, &len, fec, high_tide) < 0)
-+ if (encode_open_type(buf, buflen, &len, fec, high_tide) < 0)
- return -1;
- }
- break;
-@@ -888,7 +896,7 @@
- int seq;
- int len;
- int res;
-- uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
-+ uint8_t buf[LOCAL_FAX_MAX_DATAGRAM * 2];
-
- /* If we have no peer, return immediately */
- if (s->them.sin_addr.s_addr == INADDR_ANY)
-@@ -907,7 +915,7 @@
- seq = s->tx_seq_no & 0xFFFF;
-
- /* Cook up the UDPTL packet, with the relevant EC info. */
-- len = udptl_build_packet(s, buf, f->data.ptr, f->datalen);
-+ len = udptl_build_packet(s, buf, sizeof(buf), f->data.ptr, f->datalen);
-
- if (len > 0 && s->them.sin_port && s->them.sin_addr.s_addr) {
- if ((res = sendto(s->fd, buf, len, 0, (struct sockaddr *) &s->them, sizeof(s->them))) < 0)
-@@ -1087,66 +1095,6 @@
- return -1;
- }
-
--static char *handle_cli_udptl_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- struct hostent *hp;
-- struct ast_hostent ahp;
-- int port;
-- char *p;
-- char *arg;
--
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "udptl debug [off|ip]";
-- e->usage =
-- "Usage: udptl debug [off]|[ip host[:port]]\n"
-- " Enable or disable dumping of UDPTL packets.\n"
-- " If ip is specified, limit the dumped packets to those to and from\n"
-- " the specified 'host' with optional port.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc < 2 || a->argc > 4)
-- return CLI_SHOWUSAGE;
--
-- if (a->argc == 2) {
-- udptldebug = 1;
-- memset(&udptldebugaddr, 0, sizeof(udptldebugaddr));
-- ast_cli(a->fd, "UDPTL Debugging Enabled\n");
-- } else if (a->argc == 3) {
-- if (strncasecmp(a->argv[2], "off", 3))
-- return CLI_SHOWUSAGE;
-- udptldebug = 0;
-- ast_cli(a->fd, "UDPTL Debugging Disabled\n");
-- } else {
-- if (strncasecmp(a->argv[2], "ip", 2))
-- return CLI_SHOWUSAGE;
-- port = 0;
-- arg = a->argv[3];
-- p = strstr(arg, ":");
-- if (p) {
-- *p = '\0';
-- p++;
-- port = atoi(p);
-- }
-- hp = ast_gethostbyname(arg, &ahp);
-- if (hp == NULL)
-- return CLI_SHOWUSAGE;
-- udptldebugaddr.sin_family = AF_INET;
-- memcpy(&udptldebugaddr.sin_addr, hp->h_addr, sizeof(udptldebugaddr.sin_addr));
-- udptldebugaddr.sin_port = htons(port);
-- if (port == 0)
-- ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_inet_ntoa(udptldebugaddr.sin_addr));
-- else
-- ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(udptldebugaddr.sin_addr), port);
-- udptldebug = 1;
-- }
--
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct hostent *hp;
-@@ -1209,10 +1157,9 @@
- return CLI_SUCCESS;
- }
-
--static struct ast_cli_entry cli_handle_udptl_debug_deprecated = AST_CLI_DEFINE(handle_cli_udptl_debug_deprecated, "Enable/Disable UDPTL debugging");
-
- static struct ast_cli_entry cli_udptl[] = {
-- AST_CLI_DEFINE(handle_cli_udptl_set_debug, "Enable/Disable UDPTL debugging", .deprecate_cmd = &cli_handle_udptl_debug_deprecated)
-+ AST_CLI_DEFINE(handle_cli_udptl_set_debug, "Enable/Disable UDPTL debugging")
- };
-
- static void __ast_udptl_reload(int reload)
-@@ -1221,8 +1168,10 @@
- const char *s;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if ((cfg = ast_config_load2("udptl.conf", "udptl", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
-+ cfg = ast_config_load2("udptl.conf", "udptl", config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- return;
-+ }
-
- udptlstart = 4500;
- udptlend = 4999;
-@@ -1234,17 +1183,25 @@
- if (cfg) {
- if ((s = ast_variable_retrieve(cfg, "general", "udptlstart"))) {
- udptlstart = atoi(s);
-- if (udptlstart < 1024)
-+ if (udptlstart < 1024) {
-+ ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n");
- udptlstart = 1024;
-- if (udptlstart > 65535)
-+ }
-+ if (udptlstart > 65535) {
-+ ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n");
- udptlstart = 65535;
-+ }
- }
- if ((s = ast_variable_retrieve(cfg, "general", "udptlend"))) {
- udptlend = atoi(s);
-- if (udptlend < 1024)
-+ if (udptlend < 1024) {
-+ ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n");
- udptlend = 1024;
-- if (udptlend > 65535)
-+ }
-+ if (udptlend > 65535) {
-+ ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n");
- udptlend = 65535;
-+ }
- }
- if ((s = ast_variable_retrieve(cfg, "general", "udptlchecksums"))) {
- #ifdef SO_NO_CHECK
-@@ -1265,24 +1222,36 @@
- }
- if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) {
- udptlmaxdatagram = atoi(s);
-- if (udptlmaxdatagram < 0)
-- udptlmaxdatagram = 0;
-- if (udptlmaxdatagram > LOCAL_FAX_MAX_DATAGRAM)
-+ if (udptlmaxdatagram < 100) {
-+ ast_log(LOG_WARNING, "Too small T38FaxMaxDatagram size. Defaulting to 100.\n");
-+ udptlmaxdatagram = 100;
-+ }
-+ if (udptlmaxdatagram > LOCAL_FAX_MAX_DATAGRAM) {
-+ ast_log(LOG_WARNING, "Too large T38FaxMaxDatagram size. Defaulting to %d.\n", LOCAL_FAX_MAX_DATAGRAM);
- udptlmaxdatagram = LOCAL_FAX_MAX_DATAGRAM;
-+ }
- }
- if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECentries"))) {
- udptlfecentries = atoi(s);
-- if (udptlfecentries < 0)
-- udptlfecentries = 0;
-- if (udptlfecentries > MAX_FEC_ENTRIES)
-+ if (udptlfecentries < 1) {
-+ ast_log(LOG_WARNING, "Too small UDPTLFECentries value. Defaulting to 1.\n");
-+ udptlfecentries = 1;
-+ }
-+ if (udptlfecentries > MAX_FEC_ENTRIES) {
-+ ast_log(LOG_WARNING, "Too large UDPTLFECentries value. Defaulting to %d.\n", MAX_FEC_ENTRIES);
- udptlfecentries = MAX_FEC_ENTRIES;
-+ }
- }
- if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECspan"))) {
- udptlfecspan = atoi(s);
-- if (udptlfecspan < 0)
-- udptlfecspan = 0;
-- if (udptlfecspan > MAX_FEC_SPAN)
-+ if (udptlfecspan < 1) {
-+ ast_log(LOG_WARNING, "Too small UDPTLFECspan value. Defaulting to 1.\n");
-+ udptlfecspan = 1;
-+ }
-+ if (udptlfecspan > MAX_FEC_SPAN) {
-+ ast_log(LOG_WARNING, "Too large UDPTLFECspan value. Defaulting to %d.\n", MAX_FEC_SPAN);
- udptlfecspan = MAX_FEC_SPAN;
-+ }
- }
- ast_config_destroy(cfg);
- }
-@@ -1302,6 +1271,6 @@
-
- void ast_udptl_init(void)
- {
-- ast_cli_register_multiple(cli_udptl, sizeof(cli_udptl) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
- __ast_udptl_reload(0);
- }
-Index: main/frame.c
-===================================================================
---- a/main/frame.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/frame.c (.../team/group/issue14292) (revision 178988)
-@@ -98,7 +98,7 @@
- };
-
- /*! \brief Definition of supported media formats (codecs) */
--static struct ast_format_list AST_FORMAT_LIST[] = {
-+static const struct ast_format_list AST_FORMAT_LIST[] = {
- { AST_FORMAT_G723_1 , "g723", 8000, "G.723.1", 20, 30, 300, 30, 30 }, /*!< G723.1 */
- { AST_FORMAT_GSM, "gsm", 8000, "GSM", 33, 20, 300, 20, 20 }, /*!< codec_gsm.c */
- { AST_FORMAT_ULAW, "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20 }, /*!< codec_ulaw.c */
-@@ -112,7 +112,7 @@
- { AST_FORMAT_ILBC, "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30 }, /*!< codec_ilbc.c */ /* inc=30ms - workaround */
- { AST_FORMAT_G726_AAL2, "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20 }, /*!< codec_g726.c */
- { AST_FORMAT_G722, "g722", 16000, "G722", 80, 10, 150, 10, 20 }, /*!< codec_g722.c */
-- { AST_FORMAT_SLINEAR16, "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20 }, /*!< Signed linear (16kHz) */
-+ { AST_FORMAT_SLINEAR16, "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE }, /*!< Signed linear (16kHz) */
- { AST_FORMAT_JPEG, "jpeg", 0, "JPEG image"}, /*!< See format_jpeg.c */
- { AST_FORMAT_PNG, "png", 0, "PNG image"}, /*!< PNG Image format */
- { AST_FORMAT_H261, "h261", 0, "H.261 Video" }, /*!< H.261 Video Passthrough */
-@@ -120,8 +120,10 @@
- { AST_FORMAT_H263_PLUS, "h263p", 0, "H.263+ Video" }, /*!< H.263plus passthrough support See format_h263.c */
- { AST_FORMAT_H264, "h264", 0, "H.264 Video" }, /*!< Passthrough support, see format_h263.c */
- { AST_FORMAT_MP4_VIDEO, "mpeg4", 0, "MPEG4 Video" }, /*!< Passthrough support for MPEG4 */
-- { AST_FORMAT_T140RED, "red", 1, "T.140 Realtime Text with redundancy"}, /*!< Redundant T.140 Realtime Text */
-+ { AST_FORMAT_T140RED, "red", 1, "T.140 Realtime Text with redundancy"}, /*!< Redundant T.140 Realtime Text */
- { AST_FORMAT_T140, "t140", 0, "Passthrough T.140 Realtime Text" }, /*!< Passthrough support for T.140 Realtime Text */
-+ { AST_FORMAT_SIREN7, "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20 }, /*!< Binary commercial distribution */
-+ { AST_FORMAT_SIREN14, "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20 }, /*!< Binary commercial distribution */
- };
-
- struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
-@@ -246,7 +248,7 @@
- memmove(s->data, s->data + len, s->len);
- if (!ast_tvzero(s->delivery)) {
- /* If we have delivery time, increment it, otherwise, leave it at 0 */
-- s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
-+ s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(s->format)));
- }
- }
- /* Return frame */
-@@ -505,12 +507,12 @@
- }
-
-
--struct ast_format_list *ast_get_format_list_index(int idx)
-+const struct ast_format_list *ast_get_format_list_index(int idx)
- {
- return &AST_FORMAT_LIST[idx];
- }
-
--struct ast_format_list *ast_get_format_list(size_t *size)
-+const struct ast_format_list *ast_get_format_list(size_t *size)
- {
- *size = ARRAY_LEN(AST_FORMAT_LIST);
- return AST_FORMAT_LIST;
-@@ -564,6 +566,8 @@
- { "slinear", "slin"},
- { "slinear16", "slin16"},
- { "g723.1", "g723"},
-+ { "g722.1", "siren7"},
-+ { "g722.1c", "siren14"},
- };
-
- static const char *ast_expand_codec_alias(const char *in)
-@@ -944,7 +948,7 @@
-
- int init_framer(void)
- {
-- ast_cli_register_multiple(my_clis, sizeof(my_clis) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
- return 0;
- }
-
-@@ -1407,7 +1411,8 @@
-
- int ast_codec_get_samples(struct ast_frame *f)
- {
-- int samples=0;
-+ int samples = 0;
-+
- switch(f->subclass) {
- case AST_FORMAT_SPEEX:
- samples = speex_samples(f->data.ptr, f->datalen);
-@@ -1443,6 +1448,14 @@
- case AST_FORMAT_G726_AAL2:
- samples = f->datalen * 2;
- break;
-+ case AST_FORMAT_SIREN7:
-+ /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
-+ samples = f->datalen * (16000 / 4000);
-+ break;
-+ case AST_FORMAT_SIREN14:
-+ /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
-+ samples = (int) f->datalen * ((float) 32000 / 6000);
-+ break;
- default:
- ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
- }
-@@ -1453,7 +1466,7 @@
- {
- int len = 0;
-
-- /* XXX Still need speex, g723, and lpc10 XXX */
-+ /* XXX Still need speex, and lpc10 XXX */
- switch(format) {
- case AST_FORMAT_G723_1:
- len = (samples / 240) * 20;
-@@ -1481,6 +1494,14 @@
- case AST_FORMAT_G726_AAL2:
- len = samples / 2;
- break;
-+ case AST_FORMAT_SIREN7:
-+ /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
-+ len = samples / (16000 / 4000);
-+ break;
-+ case AST_FORMAT_SIREN14:
-+ /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
-+ len = (int) samples / ((float) 32000 / 6000);
-+ break;
- default:
- ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
- }
-Index: main/devicestate.c
-===================================================================
---- a/main/devicestate.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/devicestate.c (.../team/group/issue14292) (revision 178988)
-@@ -128,16 +128,16 @@
- #include "asterisk/event.h"
-
- /*! \brief Device state strings for printing */
--static const char *devstatestring[] = {
-- /* 0 AST_DEVICE_UNKNOWN */ "Unknown", /*!< Valid, but unknown state */
-- /* 1 AST_DEVICE_NOT_INUSE */ "Not in use", /*!< Not used */
-- /* 2 AST_DEVICE IN USE */ "In use", /*!< In use */
-- /* 3 AST_DEVICE_BUSY */ "Busy", /*!< Busy */
-- /* 4 AST_DEVICE_INVALID */ "Invalid", /*!< Invalid - not known to Asterisk */
-- /* 5 AST_DEVICE_UNAVAILABLE */ "Unavailable", /*!< Unavailable (not registred) */
-- /* 6 AST_DEVICE_RINGING */ "Ringing", /*!< Ring, ring, ring */
-- /* 7 AST_DEVICE_RINGINUSE */ "Ring+Inuse", /*!< Ring and in use */
-- /* 8 AST_DEVICE_ONHOLD */ "On Hold" /*!< On Hold */
-+static const char *devstatestring[][2] = {
-+ { /* 0 AST_DEVICE_UNKNOWN */ "Unknown", "UNKNOWN" }, /*!< Valid, but unknown state */
-+ { /* 1 AST_DEVICE_NOT_INUSE */ "Not in use", "NOT_INUSE" }, /*!< Not used */
-+ { /* 2 AST_DEVICE IN USE */ "In use", "INUSE" }, /*!< In use */
-+ { /* 3 AST_DEVICE_BUSY */ "Busy", "BUSY" }, /*!< Busy */
-+ { /* 4 AST_DEVICE_INVALID */ "Invalid", "INVALID" }, /*!< Invalid - not known to Asterisk */
-+ { /* 5 AST_DEVICE_UNAVAILABLE */ "Unavailable", "UNAVAILABLE" }, /*!< Unavailable (not registered) */
-+ { /* 6 AST_DEVICE_RINGING */ "Ringing", "RINGING" }, /*!< Ring, ring, ring */
-+ { /* 7 AST_DEVICE_RINGINUSE */ "Ring+Inuse", "RINGINUSE" }, /*!< Ring and in use */
-+ { /* 8 AST_DEVICE_ONHOLD */ "On Hold" "ONHOLD" }, /*!< On Hold */
- };
-
- /*!\brief Mapping for channel states to device states */
-@@ -204,9 +204,15 @@
- static int getproviderstate(const char *provider, const char *address);
-
- /*! \brief Find devicestate as text message for output */
-+const char *ast_devstate2str(enum ast_device_state devstate)
-+{
-+ return devstatestring[devstate][0];
-+}
-+
-+/* Deprecated interface (not prefixed with ast_) */
- const char *devstate2str(enum ast_device_state devstate)
- {
-- return devstatestring[devstate];
-+ return devstatestring[devstate][0];
- }
-
- enum ast_device_state ast_state_chan2dev(enum ast_channel_state chanstate)
-@@ -221,40 +227,10 @@
- return AST_DEVICE_UNKNOWN;
- }
-
-+/* Parseable */
- const char *ast_devstate_str(enum ast_device_state state)
- {
-- const char *res = "UNKNOWN";
--
-- switch (state) {
-- case AST_DEVICE_UNKNOWN:
-- break;
-- case AST_DEVICE_NOT_INUSE:
-- res = "NOT_INUSE";
-- break;
-- case AST_DEVICE_INUSE:
-- res = "INUSE";
-- break;
-- case AST_DEVICE_BUSY:
-- res = "BUSY";
-- break;
-- case AST_DEVICE_INVALID:
-- res = "INVALID";
-- break;
-- case AST_DEVICE_UNAVAILABLE:
-- res = "UNAVAILABLE";
-- break;
-- case AST_DEVICE_RINGING:
-- res = "RINGING";
-- break;
-- case AST_DEVICE_RINGINUSE:
-- res = "RINGINUSE";
-- break;
-- case AST_DEVICE_ONHOLD:
-- res = "ONHOLD";
-- break;
-- }
--
-- return res;
-+ return devstatestring[state][1];
- }
-
- enum ast_device_state ast_devstate_val(const char *val)
-@@ -478,7 +454,7 @@
-
- state = _ast_device_state(device, 0);
-
-- ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
-+ ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, ast_devstate2str(state));
-
- devstate_event(device, state);
- }
-@@ -623,7 +599,7 @@
-
- for (i = 0; i < collection->num_states; i++) {
- ast_debug(1, "Adding per-server state of '%s' for '%s'\n",
-- devstate2str(collection->states[i].state), device);
-+ ast_devstate2str(collection->states[i].state), device);
- ast_devstate_aggregate_add(&agg, collection->states[i].state);
- }
-
-@@ -645,13 +621,13 @@
- if (state == old_state) {
- /* No change since last reported device state */
- ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
-- device, devstate2str(state));
-+ device, ast_devstate2str(state));
- return;
- }
- }
-
- ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
-- device, devstate2str(state));
-+ device, ast_devstate2str(state));
-
- event = ast_event_new(AST_EVENT_DEVICE_STATE,
- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
-Index: main/taskprocessor.c
-===================================================================
---- a/main/taskprocessor.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/taskprocessor.c (.../team/group/issue14292) (revision 178988)
-@@ -114,7 +114,7 @@
- static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
-
- static struct ast_cli_entry taskprocessor_clis[] = {
-- AST_CLI_DEFINE(cli_tps_ping, "Ping a named task processors"),
-+ AST_CLI_DEFINE(cli_tps_ping, "Ping a named task processor"),
- AST_CLI_DEFINE(cli_tps_report, "List instantiated task processors and statistics"),
- };
-
-@@ -196,9 +196,9 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "core taskprocessor ping";
-+ e->command = "core ping taskprocessor";
- e->usage =
-- "Usage: core taskprocessor ping <taskprocessor>\n"
-+ "Usage: core ping taskprocessor <taskprocessor>\n"
- " Displays the time required for a task to be processed\n";
- return NULL;
- case CLI_GENERATE:
-Index: main/indications.c
-===================================================================
---- a/main/indications.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/indications.c (.../team/group/issue14292) (revision 178988)
-@@ -2,8 +2,8 @@
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2002, Pauline Middelink
-+ * 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;
-@@ -15,17 +15,12 @@
- * at the top of the source tree.
- */
-
--/*! \file
-+/*!
-+ * \file
-+ * \brief Indication Tone Handling
- *
-- * \brief Tone Management
-- *
- * \author Pauline Middelink <middelink@polyware.nl>
-- *
-- * This set of function allow us to play a list of tones on a channel.
-- * Each element has two frequencies, which are mixed together and a
-- * duration. For silence both frequencies can be set to 0.
-- * The playtones can be given as a comma separated string.
-- *
-+ * \author Russell Bryant <russell@digium.com>
- */
-
- #include "asterisk.h"
-@@ -40,23 +35,40 @@
- #include "asterisk/frame.h"
- #include "asterisk/channel.h"
- #include "asterisk/utils.h"
-+#include "asterisk/cli.h"
-+#include "asterisk/module.h"
-+#include "asterisk/astobj2.h"
-
--static int midi_tohz[128] = {
-- 8,8,9,9,10,10,11,12,12,13,14,
-- 15,16,17,18,19,20,21,23,24,25,
-- 27,29,30,32,34,36,38,41,43,46,
-- 48,51,55,58,61,65,69,73,77,82,
-- 87,92,97,103,110,116,123,130,138,146,
-- 155,164,174,184,195,207,220,233,246,261,
-- 277,293,311,329,349,369,391,415,440,466,
-- 493,523,554,587,622,659,698,739,783,830,
-- 880,932,987,1046,1108,1174,1244,1318,1396,1479,
-- 1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,
-- 2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,
-- 4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,
-- 8869,9397,9956,10548,11175,11839,12543
-- };
-+#include "asterisk/_private.h" /* _init(), _reload() */
-
-+/* Globals */
-+static const char config[] = "indications.conf";
-+
-+static const int midi_tohz[128] = {
-+ 8, 8, 9, 9, 10, 10, 11, 12, 12, 13,
-+ 14, 15, 16, 17, 18, 19, 20, 21, 23, 24,
-+ 25, 27, 29, 30, 32, 34, 36, 38, 41, 43,
-+ 46, 48, 51, 55, 58, 61, 65, 69, 73, 77,
-+ 82, 87, 92, 97, 103, 110, 116, 123, 130, 138,
-+ 146, 155, 164, 174, 184, 195, 207, 220, 233, 246,
-+ 261, 277, 293, 311, 329, 349, 369, 391, 415, 440,
-+ 466, 493, 523, 554, 587, 622, 659, 698, 739, 783,
-+ 830, 880, 932, 987, 1046, 1108, 1174, 1244, 1318, 1396,
-+ 1479, 1567, 1661, 1760, 1864, 1975, 2093, 2217, 2349, 2489,
-+ 2637, 2793, 2959, 3135, 3322, 3520, 3729, 3951, 4186, 4434,
-+ 4698, 4978, 5274, 5587, 5919, 6271, 6644, 7040, 7458, 7902,
-+ 8372, 8869, 9397, 9956, 10548, 11175, 11839, 12543
-+};
-+
-+static struct ao2_container *ast_tone_zones;
-+
-+#define NUM_TONE_ZONE_BUCKETS 53
-+
-+/*!
-+ * \note Access to this is protected by locking the ast_tone_zones container
-+ */
-+static struct ast_tone_zone *default_tone_zone;
-+
- struct playtones_item {
- int fac1;
- int init_v2_1;
-@@ -100,21 +112,26 @@
- {
- struct playtones_state *ps = params;
-
-- if (chan)
-+ if (chan) {
- ast_set_write_format(chan, ps->origwfmt);
-- if (ps->items)
-+ }
-+
-+ if (ps->items) {
- ast_free(ps->items);
-+ ps->items = NULL;
-+ }
-
- ast_free(ps);
- }
-
--static void * playtones_alloc(struct ast_channel *chan, void *params)
-+static void *playtones_alloc(struct ast_channel *chan, void *params)
- {
- struct playtones_def *pd = params;
- struct playtones_state *ps = NULL;
-
-- if (!(ps = ast_calloc(1, sizeof(*ps))))
-+ if (!(ps = ast_calloc(1, sizeof(*ps)))) {
- return NULL;
-+ }
-
- ps->origwfmt = chan->writeformat;
-
-@@ -131,10 +148,11 @@
- }
-
- /* Let interrupts interrupt :) */
-- if (pd->interruptible)
-+ if (pd->interruptible) {
- ast_set_flag(chan, AST_FLAG_WRITE_INT);
-- else
-+ } else {
- ast_clear_flag(chan, AST_FLAG_WRITE_INT);
-+ }
-
- return ps;
- }
-@@ -144,17 +162,20 @@
- struct playtones_state *ps = data;
- struct playtones_item *pi;
- int x;
-- /* we need to prepare a frame with 16 * timelen samples as we're
-- * generating SLIN audio
-- */
-+
-+ /* we need to prepare a frame with 16 * timelen samples as we're
-+ * generating SLIN audio */
-+
- len = samples * 2;
- if (len > sizeof(ps->data) / 2 - 1) {
- ast_log(LOG_WARNING, "Can't generate that much data!\n");
- return -1;
- }
-+
- memset(&ps->f, 0, sizeof(ps->f));
-
- pi = &ps->items[ps->npos];
-+
- if (ps->oldnpos != ps->npos) {
- /* Load new parameters */
- ps->v1_1 = 0;
-@@ -165,163 +186,204 @@
- ps->v3_2 = pi->init_v3_2;
- ps->oldnpos = ps->npos;
- }
-- for (x = 0; x < len/2; x++) {
-+
-+ for (x = 0; x < samples; x++) {
- ps->v1_1 = ps->v2_1;
- ps->v2_1 = ps->v3_1;
- ps->v3_1 = (pi->fac1 * ps->v2_1 >> 15) - ps->v1_1;
--
-+
- ps->v1_2 = ps->v2_2;
- ps->v2_2 = ps->v3_2;
- ps->v3_2 = (pi->fac2 * ps->v2_2 >> 15) - ps->v1_2;
- if (pi->modulate) {
- int p;
- p = ps->v3_2 - 32768;
-- if (p < 0) p = -p;
-+ if (p < 0) {
-+ p = -p;
-+ }
- p = ((p * 9) / 10) + 1;
- ps->data[x] = (ps->v3_1 * p) >> 15;
-- } else
-- ps->data[x] = ps->v3_1 + ps->v3_2;
-+ } else {
-+ ps->data[x] = ps->v3_1 + ps->v3_2;
-+ }
- }
--
-+
- ps->f.frametype = AST_FRAME_VOICE;
- ps->f.subclass = AST_FORMAT_SLINEAR;
- ps->f.datalen = len;
- ps->f.samples = samples;
- ps->f.offset = AST_FRIENDLY_OFFSET;
- ps->f.data.ptr = ps->data;
-- ps->f.delivery.tv_sec = 0;
-- ps->f.delivery.tv_usec = 0;
-- ast_write(chan, &ps->f);
-
-+ if (ast_write(chan, &ps->f)) {
-+ return -1;
-+ }
-+
- ps->pos += x;
-+
- if (pi->duration && ps->pos >= pi->duration * 8) { /* item finished? */
- ps->pos = 0; /* start new item */
- ps->npos++;
- if (ps->npos >= ps->nitems) { /* last item? */
-- if (ps->reppos == -1) /* repeat set? */
-+ if (ps->reppos == -1) { /* repeat set? */
- return -1;
-+ }
- ps->npos = ps->reppos; /* redo from top */
- }
- }
-+
- return 0;
- }
-
- static struct ast_generator playtones = {
-- alloc: playtones_alloc,
-- release: playtones_release,
-- generate: playtones_generator,
-+ .alloc = playtones_alloc,
-+ .release = playtones_release,
-+ .generate = playtones_generator,
- };
-
-+int ast_tone_zone_part_parse(const char *s, struct ast_tone_zone_part *tone_data)
-+{
-+ if (sscanf(s, "%u+%u/%u", &tone_data->freq1, &tone_data->freq2,
-+ &tone_data->time) == 3) {
-+ /* f1+f2/time format */
-+ } else if (sscanf(s, "%u+%u", &tone_data->freq1, &tone_data->freq2) == 2) {
-+ /* f1+f2 format */
-+ tone_data->time = 0;
-+ } else if (sscanf(s, "%u*%u/%u", &tone_data->freq1, &tone_data->freq2,
-+ &tone_data->time) == 3) {
-+ /* f1*f2/time format */
-+ tone_data->modulate = 1;
-+ } else if (sscanf(s, "%u*%u", &tone_data->freq1, &tone_data->freq2) == 2) {
-+ /* f1*f2 format */
-+ tone_data->time = 0;
-+ tone_data->modulate = 1;
-+ } else if (sscanf(s, "%u/%u", &tone_data->freq1, &tone_data->time) == 2) {
-+ /* f1/time format */
-+ tone_data->freq2 = 0;
-+ } else if (sscanf(s, "%u", &tone_data->freq1) == 1) {
-+ /* f1 format */
-+ tone_data->freq2 = 0;
-+ tone_data->time = 0;
-+ } else if (sscanf(s, "M%u+M%u/%u", &tone_data->freq1, &tone_data->freq2,
-+ &tone_data->time) == 3) {
-+ /* Mf1+Mf2/time format */
-+ tone_data->midinote = 1;
-+ } else if (sscanf(s, "M%u+M%u", &tone_data->freq1, &tone_data->freq2) == 2) {
-+ /* Mf1+Mf2 format */
-+ tone_data->time = 0;
-+ tone_data->midinote = 1;
-+ } else if (sscanf(s, "M%u*M%u/%u", &tone_data->freq1, &tone_data->freq2,
-+ &tone_data->time) == 3) {
-+ /* Mf1*Mf2/time format */
-+ tone_data->modulate = 1;
-+ tone_data->midinote = 1;
-+ } else if (sscanf(s, "M%u*M%u", &tone_data->freq1, &tone_data->freq2) == 2) {
-+ /* Mf1*Mf2 format */
-+ tone_data->time = 0;
-+ tone_data->modulate = 1;
-+ tone_data->midinote = 1;
-+ } else if (sscanf(s, "M%u/%u", &tone_data->freq1, &tone_data->time) == 2) {
-+ /* Mf1/time format */
-+ tone_data->freq2 = -1;
-+ tone_data->midinote = 1;
-+ } else if (sscanf(s, "M%u", &tone_data->freq1) == 1) {
-+ /* Mf1 format */
-+ tone_data->freq2 = -1;
-+ tone_data->time = 0;
-+ tone_data->midinote = 1;
-+ } else {
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
- int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst, int interruptible)
- {
-- char *s, *data = ast_strdupa(playlst); /* cute */
-- struct playtones_def d = { vol, -1, 0, 1, NULL};
-+ char *s, *data = ast_strdupa(playlst);
-+ struct playtones_def d = { vol, -1, 0, 1, NULL };
- char *stringp;
- char *separator;
--
-- if (vol < 1)
-+ static const float sample_rate = 8000.0;
-+ static const float max_sample_val = 32768.0;
-+
-+ if (vol < 1) {
- d.vol = 7219; /* Default to -8db */
-+ }
-
- d.interruptible = interruptible;
--
-- stringp=data;
-- /* the stringp/data is not null here */
-+
-+ stringp = data;
-+
- /* check if the data is separated with '|' or with ',' by default */
-- if (strchr(stringp,'|'))
-+ if (strchr(stringp,'|')) {
- separator = "|";
-- else
-+ } else {
- separator = ",";
-- s = strsep(&stringp,separator);
-- while (s && *s) {
-- int freq1, freq2, duration, modulate = 0, midinote = 0;
-+ }
-
-- if (s[0]=='!')
-+ while ((s = strsep(&stringp, separator)) && !ast_strlen_zero(s)) {
-+ struct ast_tone_zone_part tone_data = {
-+ .time = 0,
-+ };
-+
-+ s = ast_strip(s);
-+
-+ if (s[0]=='!') {
- s++;
-- else if (d.reppos == -1)
-+ } else if (d.reppos == -1) {
- d.reppos = d.nitems;
-- if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &duration) == 3) {
-- /* f1+f2/time format */
-- } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
-- /* f1+f2 format */
-- duration = 0;
-- } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &duration) == 3) {
-- /* f1*f2/time format */
-- modulate = 1;
-- } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
-- /* f1*f2 format */
-- duration = 0;
-- modulate = 1;
-- } else if (sscanf(s, "%d/%d", &freq1, &duration) == 2) {
-- /* f1/time format */
-- freq2 = 0;
-- } else if (sscanf(s, "%d", &freq1) == 1) {
-- /* f1 format */
-- freq2 = 0;
-- duration = 0;
-- } else if (sscanf(s, "M%d+M%d/%d", &freq1, &freq2, &duration) == 3) {
-- /* Mf1+Mf2/time format */
-- midinote = 1;
-- } else if (sscanf(s, "M%d+M%d", &freq1, &freq2) == 2) {
-- /* Mf1+Mf2 format */
-- duration = 0;
-- midinote = 1;
-- } else if (sscanf(s, "M%d*M%d/%d", &freq1, &freq2, &duration) == 3) {
-- /* Mf1*Mf2/time format */
-- modulate = 1;
-- midinote = 1;
-- } else if (sscanf(s, "M%d*M%d", &freq1, &freq2) == 2) {
-- /* Mf1*Mf2 format */
-- duration = 0;
-- modulate = 1;
-- midinote = 1;
-- } else if (sscanf(s, "M%d/%d", &freq1, &duration) == 2) {
-- /* Mf1/time format */
-- freq2 = -1;
-- midinote = 1;
-- } else if (sscanf(s, "M%d", &freq1) == 1) {
-- /* Mf1 format */
-- freq2 = -1;
-- duration = 0;
-- midinote = 1;
-- } else {
-- ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
-- return -1;
- }
-
-- if (midinote) {
-+ if (ast_tone_zone_part_parse(s, &tone_data)) {
-+ ast_log(LOG_ERROR, "Failed to parse tone part '%s'\n", s);
-+ continue;
-+ }
-+
-+ if (tone_data.midinote) {
- /* midi notes must be between 0 and 127 */
-- if ((freq1 >= 0) && (freq1 <= 127))
-- freq1 = midi_tohz[freq1];
-- else
-- freq1 = 0;
-
-- if ((freq2 >= 0) && (freq2 <= 127))
-- freq2 = midi_tohz[freq2];
-- else
-- freq2 = 0;
-+ if (tone_data.freq1 >= 0 && tone_data.freq1 <= 127) {
-+ tone_data.freq1 = midi_tohz[tone_data.freq1];
-+ } else {
-+ tone_data.freq1 = 0;
-+ }
-+
-+ if (tone_data.freq2 >= 0 && tone_data.freq2 <= 127) {
-+ tone_data.freq2 = midi_tohz[tone_data.freq2];
-+ } else {
-+ tone_data.freq2 = 0;
-+ }
- }
-
- if (!(d.items = ast_realloc(d.items, (d.nitems + 1) * sizeof(*d.items)))) {
- return -1;
- }
-- d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
-- d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * d.vol;
-- d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * d.vol;
-
-- d.items[d.nitems].fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
-- d.items[d.nitems].init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * d.vol;
-- d.items[d.nitems].init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * d.vol;
-- d.items[d.nitems].duration = duration;
-- d.items[d.nitems].modulate = modulate;
-+ d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (tone_data.freq1 / sample_rate)) * max_sample_val;
-+ d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (tone_data.freq1 / sample_rate)) * d.vol;
-+ d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (tone_data.freq1 / sample_rate)) * d.vol;
-+
-+ d.items[d.nitems].fac2 = 2.0 * cos(2.0 * M_PI * (tone_data.freq2 / sample_rate)) * max_sample_val;
-+ d.items[d.nitems].init_v2_2 = sin(-4.0 * M_PI * (tone_data.freq2 / sample_rate)) * d.vol;
-+ d.items[d.nitems].init_v3_2 = sin(-2.0 * M_PI * (tone_data.freq2 / sample_rate)) * d.vol;
-+
-+ d.items[d.nitems].duration = tone_data.time;
-+ d.items[d.nitems].modulate = tone_data.modulate;
-+
- d.nitems++;
-+ }
-
-- s = strsep(&stringp,separator);
-+ if (!d.nitems) {
-+ ast_log(LOG_ERROR, "No valid tone parts\n");
-+ return -1;
- }
-
- if (ast_activate_generator(chan, &playtones, &d)) {
- ast_free(d.items);
- return -1;
- }
-+
- return 0;
- }
-
-@@ -330,266 +392,735 @@
- ast_deactivate_generator(chan);
- }
-
--/*--------------------------------------------*/
-+int ast_tone_zone_count(void)
-+{
-+ return ao2_container_count(ast_tone_zones);
-+}
-
--static AST_RWLIST_HEAD_STATIC(tone_zones, tone_zone);
--static struct tone_zone *current_tonezone;
--
--struct tone_zone *ast_walk_indications(const struct tone_zone *cur)
-+struct ao2_iterator ast_tone_zone_iterator_init(void)
- {
-- struct tone_zone *tz = NULL;
--
-- AST_RWLIST_RDLOCK(&tone_zones);
-- /* If cur is not NULL, then we have to iterate through - otherwise just return the first entry */
-- if (cur) {
-- AST_RWLIST_TRAVERSE(&tone_zones, tz, list) {
-- if (tz == cur)
-- break;
-- }
-- tz = AST_RWLIST_NEXT(tz, list);
-- } else {
-- tz = AST_RWLIST_FIRST(&tone_zones);
-- }
-- AST_RWLIST_UNLOCK(&tone_zones);
--
-- return tz;
-+ return ao2_iterator_init(ast_tone_zones, 0);
- }
-
- /* Set global indication country */
--int ast_set_indication_country(const char *country)
-+static int ast_set_indication_country(const char *country)
- {
-- struct tone_zone *zone = NULL;
-+ struct ast_tone_zone *zone = NULL;
-
- /* If no country is specified or we are unable to find the zone, then return not found */
-- if (!country || !(zone = ast_get_indication_zone(country)))
-- return 1;
--
-+ if (ast_strlen_zero(country) || !(zone = ast_get_indication_zone(country))) {
-+ return -1;
-+ }
-+
- ast_verb(3, "Setting default indication country to '%s'\n", country);
-
-- /* Protect the current tonezone using the tone_zones lock as well */
-- AST_RWLIST_WRLOCK(&tone_zones);
-- current_tonezone = zone;
-- AST_RWLIST_UNLOCK(&tone_zones);
-+ ao2_lock(ast_tone_zones);
-+ if (default_tone_zone) {
-+ default_tone_zone = ast_tone_zone_unref(default_tone_zone);
-+ }
-+ default_tone_zone = ast_tone_zone_ref(zone);
-+ ao2_unlock(ast_tone_zones);
-
-- /* Zone was found */
-+ zone = ast_tone_zone_unref(zone);
-+
- return 0;
- }
-
--/* locate tone_zone, given the country. if country == NULL, use the default country */
--struct tone_zone *ast_get_indication_zone(const char *country)
-+/* locate ast_tone_zone, given the country. if country == NULL, use the default country */
-+struct ast_tone_zone *ast_get_indication_zone(const char *country)
- {
-- struct tone_zone *tz = NULL;
-- int alias_loop = 0;
-+ struct ast_tone_zone *tz = NULL;
-+ struct ast_tone_zone zone_arg = {
-+ .nrringcadence = 0,
-+ };
-
-- AST_RWLIST_RDLOCK(&tone_zones);
-+ if (ast_strlen_zero(country)) {
-+ ao2_lock(ast_tone_zones);
-+ if (default_tone_zone) {
-+ tz = ast_tone_zone_ref(default_tone_zone);
-+ }
-+ ao2_unlock(ast_tone_zones);
-
-- if (ast_strlen_zero(country)) {
-- tz = current_tonezone ? current_tonezone : AST_LIST_FIRST(&tone_zones);
-- } else {
-- do {
-- AST_RWLIST_TRAVERSE(&tone_zones, tz, list) {
-- if (!strcasecmp(tz->country, country))
-- break;
-- }
-- if (!tz)
-- break;
-- /* If this is an alias then we have to search yet again otherwise we have found the zonezone */
-- if (tz->alias && tz->alias[0])
-- country = tz->alias;
-- else
-- break;
-- } while ((++alias_loop < 20) && tz);
-+ return tz;
- }
-
-- AST_RWLIST_UNLOCK(&tone_zones);
-+ ast_copy_string(zone_arg.country, country, sizeof(zone_arg.country));
-
-- /* If we reached the maximum loops to find the proper country via alias, print out a notice */
-- if (alias_loop == 20)
-- ast_log(LOG_NOTICE, "Alias loop for '%s' is bonkers\n", country);
--
-- return tz;
-+ return ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER);
- }
-
--/* locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
--struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication)
-+struct ast_tone_zone_sound *ast_get_indication_tone(const struct ast_tone_zone *_zone, const char *indication)
- {
-- struct tone_zone_sound *ts = NULL;
-+ struct ast_tone_zone_sound *ts = NULL;
-+ /* _zone is const to the users of the API */
-+ struct ast_tone_zone *zone = (struct ast_tone_zone *) _zone;
-
-- AST_RWLIST_RDLOCK(&tone_zones);
-+ /* If no zone is specified, use the default */
-+ if (!zone) {
-+ ao2_lock(ast_tone_zones);
-+ if (default_tone_zone) {
-+ zone = ast_tone_zone_ref(default_tone_zone);
-+ }
-+ ao2_unlock(ast_tone_zones);
-
-- /* If no zone is already specified we need to try to pick one */
-- if (!zone) {
-- if (current_tonezone) {
-- zone = current_tonezone;
-- } else if (!(zone = AST_LIST_FIRST(&tone_zones))) {
-- /* No zone has been found ;( */
-- AST_RWLIST_UNLOCK(&tone_zones);
-+ if (!zone) {
- return NULL;
- }
- }
-
-+ ast_tone_zone_lock(zone);
-+
- /* Look through list of tones in the zone searching for the right one */
-- for (ts = zone->tones; ts; ts = ts->next) {
-- if (!strcasecmp(ts->name, indication))
-+ AST_LIST_TRAVERSE(&zone->tones, ts, entry) {
-+ if (!strcasecmp(ts->name, indication)) {
-+ /* Increase ref count for the reference we will return */
-+ ts = ast_tone_zone_sound_ref(ts);
- break;
-+ }
- }
-
-- AST_RWLIST_UNLOCK(&tone_zones);
-+ ast_tone_zone_unlock(zone);
-
- return ts;
- }
-
--/* helper function to delete a tone_zone in its entirety */
--static inline void free_zone(struct tone_zone* zone)
-+static void ast_tone_zone_sound_destructor(void *obj)
- {
-- while (zone->tones) {
-- struct tone_zone_sound *tmp = zone->tones->next;
-- ast_free((void *)zone->tones->name);
-- ast_free((void *)zone->tones->data);
-- ast_free(zone->tones);
-- zone->tones = tmp;
-+ struct ast_tone_zone_sound *ts = obj;
-+
-+ /* Deconstify the 'const char *'s so the compiler doesn't complain. (but it's safe) */
-+ if (ts->name) {
-+ ast_free((char *) ts->name);
-+ ts->name = NULL;
- }
-
-- if (zone->ringcadence)
-+ if (ts->data) {
-+ ast_free((char *) ts->data);
-+ ts->data = NULL;
-+ }
-+}
-+
-+/*! \brief deallocate the passed tone zone */
-+static void ast_tone_zone_destructor(void *obj)
-+{
-+ struct ast_tone_zone *zone = obj;
-+ struct ast_tone_zone_sound *current;
-+
-+ while ((current = AST_LIST_REMOVE_HEAD(&zone->tones, entry))) {
-+ current = ast_tone_zone_sound_unref(current);
-+ }
-+
-+ if (zone->ringcadence) {
- ast_free(zone->ringcadence);
-+ zone->ringcadence = NULL;
-+ }
-+}
-
-- ast_free(zone);
-+/* add a new country, if country exists, it will be replaced. */
-+static int ast_register_indication_country(struct ast_tone_zone *zone)
-+{
-+ ao2_lock(ast_tone_zones);
-+ if (!default_tone_zone) {
-+ default_tone_zone = ast_tone_zone_ref(zone);
-+ }
-+ ao2_unlock(ast_tone_zones);
-+
-+ ao2_link(ast_tone_zones, zone);
-+
-+ ast_verb(3, "Registered indication country '%s'\n", zone->country);
-+
-+ return 0;
- }
-
--/*--------------------------------------------*/
-+/* remove an existing country and all its indications, country must exist. */
-+static int ast_unregister_indication_country(const char *country)
-+{
-+ struct ast_tone_zone *tz = NULL;
-+ struct ast_tone_zone zone_arg = {
-+ .nrringcadence = 0,
-+ };
-
--/* add a new country, if country exists, it will be replaced. */
--int ast_register_indication_country(struct tone_zone *zone)
-+ ast_copy_string(zone_arg.country, country, sizeof(zone_arg.country));
-+
-+ if (!(tz = ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER))) {
-+ return -1;
-+ }
-+
-+ ao2_lock(ast_tone_zones);
-+ if (default_tone_zone == tz) {
-+ ast_tone_zone_unref(default_tone_zone);
-+ /* Get a new default, punt to the first one we find */
-+ default_tone_zone = ao2_callback(ast_tone_zones, 0, NULL, NULL);
-+ }
-+ ao2_unlock(ast_tone_zones);
-+
-+ ao2_unlink(ast_tone_zones, tz);
-+
-+ tz = ast_tone_zone_unref(tz);
-+
-+ return 0;
-+}
-+
-+/*!
-+ * \note called with the tone zone locked
-+ */
-+static int ast_register_indication(struct ast_tone_zone *zone, const char *indication,
-+ const char *tonelist)
- {
-- struct tone_zone *tz = NULL;
-+ struct ast_tone_zone_sound *ts;
-
-- AST_RWLIST_WRLOCK(&tone_zones);
-- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&tone_zones, tz, list) {
-- /* If this is not the same zone, then just continue to the next entry */
-- if (strcasecmp(zone->country, tz->country))
-- continue;
-- /* If this zone we are going to remove is the current default then make the new zone the default */
-- if (tz == current_tonezone)
-- current_tonezone = zone;
-- /* Remove from the linked list */
-- AST_RWLIST_REMOVE_CURRENT(list);
-- /* Finally free the zone itself */
-- free_zone(tz);
-- break;
-+ if (ast_strlen_zero(indication) || ast_strlen_zero(tonelist)) {
-+ return -1;
- }
-- AST_RWLIST_TRAVERSE_SAFE_END;
-
-- /* Add zone to the list */
-- AST_RWLIST_INSERT_TAIL(&tone_zones, zone, list);
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, ts, entry) {
-+ if (!strcasecmp(indication, ts->name)) {
-+ AST_LIST_REMOVE_CURRENT(entry);
-+ ts = ast_tone_zone_sound_unref(ts);
-+ break;
-+ }
-+ }
-+ AST_LIST_TRAVERSE_SAFE_END;
-
-- /* It's all over. */
-- AST_RWLIST_UNLOCK(&tone_zones);
-+ if (!(ts = ao2_alloc(sizeof(*ts), ast_tone_zone_sound_destructor))) {
-+ return -1;
-+ }
-
-- ast_verb(3, "Registered indication country '%s'\n", zone->country);
-+ if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
-+ ts = ast_tone_zone_sound_unref(ts);
-+ return -1;
-+ }
-
-+ AST_LIST_INSERT_TAIL(&zone->tones, ts, entry); /* Inherit reference */
-+
- return 0;
- }
-
--/* remove an existing country and all its indications, country must exist.
-- * Also, all countries which are an alias for the specified country are removed. */
--int ast_unregister_indication_country(const char *country)
-+/* remove an existing country's indication. Both country and indication must exist */
-+static int ast_unregister_indication(struct ast_tone_zone *zone, const char *indication)
- {
-- struct tone_zone *tz = NULL;
-+ struct ast_tone_zone_sound *ts;
- int res = -1;
-
-- AST_RWLIST_WRLOCK(&tone_zones);
-- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&tone_zones, tz, list) {
-- if (country && (strcasecmp(country, tz->country) && strcasecmp(country, tz->alias)))
-- continue;
-- /* If this tonezone is the current default then unset it */
-- if (tz == current_tonezone) {
-- ast_log(LOG_NOTICE,"Removed default indication country '%s'\n", tz->country);
-- current_tonezone = NULL;
-+ ast_tone_zone_lock(zone);
-+
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, ts, entry) {
-+ if (!strcasecmp(indication, ts->name)) {
-+ AST_LIST_REMOVE_CURRENT(entry);
-+ ts = ast_tone_zone_sound_unref(ts);
-+ res = 0;
-+ break;
- }
-- /* Remove from the list */
-- AST_RWLIST_REMOVE_CURRENT(list);
-- ast_verb(3, "Unregistered indication country '%s'\n", tz->country);
-- free_zone(tz);
-- res = 0;
- }
-- AST_RWLIST_TRAVERSE_SAFE_END;
-- AST_RWLIST_UNLOCK(&tone_zones);
-+ AST_LIST_TRAVERSE_SAFE_END;
-
-+ ast_tone_zone_unlock(zone);
-+
- return res;
- }
-
--/* add a new indication to a tone_zone. tone_zone must exist. if the indication already
-- * exists, it will be replaced. */
--int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist)
-+static struct ast_tone_zone *ast_tone_zone_alloc(void)
- {
-- struct tone_zone_sound *ts, *ps;
-+ return ao2_alloc(sizeof(struct ast_tone_zone), ast_tone_zone_destructor);
-+}
-
-- /* is it an alias? stop */
-- if (zone->alias[0])
-- return -1;
-+static char *complete_country(struct ast_cli_args *a)
-+{
-+ char *res = NULL;
-+ struct ao2_iterator i;
-+ int which = 0;
-+ size_t wordlen;
-+ struct ast_tone_zone *tz;
-
-- AST_RWLIST_WRLOCK(&tone_zones);
-- for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) {
-- if (!strcasecmp(indication,ts->name)) {
-- /* indication already there, replace */
-- ast_free((void*)ts->name);
-- ast_free((void*)ts->data);
-+ wordlen = strlen(a->word);
-+
-+ i = ao2_iterator_init(ast_tone_zones, 0);
-+ while ((tz = ao2_iterator_next(&i))) {
-+ if (!strncasecmp(a->word, tz->country, wordlen) && ++which > a->n) {
-+ res = ast_strdup(tz->country);
-+ }
-+ tz = ast_tone_zone_unref(tz);
-+ if (res) {
- break;
- }
- }
-- if (!ts) {
-- /* not there, we have to add */
-- if (!(ts = ast_malloc(sizeof(*ts)))) {
-- AST_RWLIST_UNLOCK(&tone_zones);
-- return -2;
-+
-+ return res;
-+}
-+
-+static char *handle_cli_indication_add(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct ast_tone_zone *tz;
-+ int created_country = 0;
-+ char *res = CLI_SUCCESS;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "indication add";
-+ e->usage =
-+ "Usage: indication add <country> <indication> \"<tonelist>\"\n"
-+ " Add the given indication to the country.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ if (a->pos == 2) {
-+ return complete_country(a);
-+ } else {
-+ return NULL;
- }
-- ts->next = NULL;
- }
-- if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
-- AST_RWLIST_UNLOCK(&tone_zones);
-- return -2;
-+
-+ if (a->argc != 5) {
-+ return CLI_SHOWUSAGE;
- }
-- if (ps)
-- ps->next = ts;
-- else
-- zone->tones = ts;
-- AST_RWLIST_UNLOCK(&tone_zones);
-+
-+ if (!(tz = ast_get_indication_zone(a->argv[2]))) {
-+ /* country does not exist, create it */
-+ ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n", a->argv[2]);
-+
-+ if (!(tz = ast_tone_zone_alloc())) {
-+ return CLI_FAILURE;
-+ }
-+
-+ ast_copy_string(tz->country, a->argv[2], sizeof(tz->country));
-+
-+ if (ast_register_indication_country(tz)) {
-+ ast_log(LOG_WARNING, "Unable to register new country\n");
-+ tz = ast_tone_zone_unref(tz);
-+ return CLI_FAILURE;
-+ }
-+
-+ created_country = 1;
-+ }
-+
-+ ast_tone_zone_lock(tz);
-+
-+ if (ast_register_indication(tz, a->argv[3], a->argv[4])) {
-+ ast_log(LOG_WARNING, "Unable to register indication %s/%s\n", a->argv[2], a->argv[3]);
-+ if (created_country) {
-+ ast_unregister_indication_country(a->argv[2]);
-+ }
-+ res = CLI_FAILURE;
-+ }
-+
-+ ast_tone_zone_unlock(tz);
-+
-+ tz = ast_tone_zone_unref(tz);
-+
-+ return res;
-+}
-+
-+static char *complete_indications(struct ast_cli_args *a)
-+{
-+ char *res = NULL;
-+ int which = 0;
-+ size_t wordlen;
-+ struct ast_tone_zone_sound *ts;
-+ struct ast_tone_zone *tz, tmp_tz = {
-+ .nrringcadence = 0,
-+ };
-+
-+ ast_copy_string(tmp_tz.country, a->argv[a->pos - 1], sizeof(tmp_tz.country));
-+
-+ if (!(tz = ao2_find(ast_tone_zones, &tmp_tz, OBJ_POINTER))) {
-+ return NULL;
-+ }
-+
-+ wordlen = strlen(a->word);
-+
-+ ast_tone_zone_lock(tz);
-+ AST_LIST_TRAVERSE(&tz->tones, ts, entry) {
-+ if (!strncasecmp(a->word, ts->name, wordlen) && ++which > a->n) {
-+ res = ast_strdup(ts->name);
-+ break;
-+ }
-+ }
-+ ast_tone_zone_unlock(tz);
-+
-+ tz = ast_tone_zone_unref(tz);
-+
-+ return res;
-+}
-+
-+static char *handle_cli_indication_remove(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct ast_tone_zone *tz;
-+ char *res = CLI_SUCCESS;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "indication remove";
-+ e->usage =
-+ "Usage: indication remove <country> [indication]\n"
-+ " Remove the given indication from the country.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ if (a->pos == 2) {
-+ return complete_country(a);
-+ } else if (a->pos == 3) {
-+ return complete_indications(a);
-+ }
-+ }
-+
-+ if (a->argc != 3 && a->argc != 4) {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ if (a->argc == 3) {
-+ /* remove entire country */
-+ if (ast_unregister_indication_country(a->argv[2])) {
-+ ast_log(LOG_WARNING, "Unable to unregister indication country %s\n", a->argv[2]);
-+ return CLI_FAILURE;
-+ }
-+
-+ return CLI_SUCCESS;
-+ }
-+
-+ if (!(tz = ast_get_indication_zone(a->argv[2]))) {
-+ ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n", a->argv[2], a->argv[3]);
-+ return CLI_FAILURE;
-+ }
-+
-+ if (ast_unregister_indication(tz, a->argv[3])) {
-+ ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n", a->argv[2], a->argv[3]);
-+ res = CLI_FAILURE;
-+ }
-+
-+ tz = ast_tone_zone_unref(tz);
-+
-+ return res;
-+}
-+
-+static char *handle_cli_indication_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct ast_tone_zone *tz = NULL;
-+ struct ast_str *buf;
-+ int found_country = 0;
-+ int i;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "indication show";
-+ e->usage =
-+ "Usage: indication show [<country> ...]\n"
-+ " Display either a condensed summary of all countries and indications, or a\n"
-+ " more verbose list of indications for the specified countries.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return complete_country(a);
-+ }
-+
-+ if (a->argc == 2) {
-+ struct ao2_iterator iter;
-+ /* no arguments, show a list of countries */
-+ ast_cli(a->fd, "Country Description\n");
-+ ast_cli(a->fd, "===========================\n");
-+ iter = ast_tone_zone_iterator_init();
-+ while ((tz = ao2_iterator_next(&iter))) {
-+ ast_tone_zone_lock(tz);
-+ ast_cli(a->fd, "%-7.7s %s\n", tz->country, tz->description);
-+ ast_tone_zone_unlock(tz);
-+ tz = ast_tone_zone_unref(tz);
-+ }
-+ return CLI_SUCCESS;
-+ }
-+
-+ buf = ast_str_alloca(256);
-+
-+ for (i = 2; i < a->argc; i++) {
-+ struct ast_tone_zone zone_arg = {
-+ .nrringcadence = 0,
-+ };
-+ struct ast_tone_zone_sound *ts;
-+ int j;
-+
-+ ast_copy_string(zone_arg.country, a->argv[i], sizeof(zone_arg.country));
-+
-+ if (!(tz = ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER))) {
-+ continue;
-+ }
-+
-+ if (!found_country) {
-+ found_country = 1;
-+ ast_cli(a->fd, "Country Indication PlayList\n");
-+ ast_cli(a->fd, "=====================================\n");
-+ }
-+
-+ ast_tone_zone_lock(tz);
-+
-+ ast_str_set(&buf, 0, "%-7.7s %-15.15s ", tz->country, "<ringcadence>");
-+ for (j = 0; j < tz->nrringcadence; j++) {
-+ ast_str_append(&buf, 0, "%d%s", tz->ringcadence[j],
-+ (j == tz->nrringcadence - 1) ? "" : ",");
-+ }
-+ ast_str_append(&buf, 0, "\n");
-+ ast_cli(a->fd, "%s", buf->str);
-+
-+ AST_LIST_TRAVERSE(&tz->tones, ts, entry) {
-+ ast_cli(a->fd, "%-7.7s %-15.15s %s\n", tz->country, ts->name, ts->data);
-+ }
-+
-+ ast_tone_zone_unlock(tz);
-+ tz = ast_tone_zone_unref(tz);
-+ }
-+
-+ if (!found_country) {
-+ ast_cli(a->fd, "No countries matched your criteria.\n");
-+ }
-+
-+ return CLI_SUCCESS;
-+}
-+
-+static int is_valid_tone_zone(struct ast_tone_zone *zone)
-+{
-+ int res;
-+
-+ ast_tone_zone_lock(zone);
-+ res = (!ast_strlen_zero(zone->description) && !AST_LIST_EMPTY(&zone->tones));
-+ ast_tone_zone_unlock(zone);
-+
-+ return res;
-+}
-+
-+/*!
-+ * \note This is called with the tone zone locked.
-+ */
-+static void store_tone_zone_ring_cadence(struct ast_tone_zone *zone, const char *val)
-+{
-+ char buf[1024];
-+ char *ring, *c = buf;
-+
-+ ast_copy_string(buf, val, sizeof(buf));
-+
-+ while ((ring = strsep(&c, ","))) {
-+ int *tmp, val;
-+
-+ ring = ast_strip(ring);
-+
-+ if (!isdigit(ring[0]) || (val = atoi(ring)) == -1) {
-+ ast_log(LOG_WARNING, "Invalid ringcadence given '%s'.\n", ring);
-+ continue;
-+ }
-+
-+ if (!(tmp = ast_realloc(zone->ringcadence, (zone->nrringcadence + 1) * sizeof(int)))) {
-+ return;
-+ }
-+
-+ zone->ringcadence = tmp;
-+ tmp[zone->nrringcadence] = val;
-+ zone->nrringcadence++;
-+ }
-+}
-+
-+static void store_config_tone_zone(struct ast_tone_zone *zone, const char *var,
-+ const char *value)
-+{
-+ CV_START(var, value);
-+
-+ CV_STR("description", zone->description);
-+ CV_F("ringcadence", store_tone_zone_ring_cadence(zone, value));
-+ CV_F("ringcadance", store_tone_zone_ring_cadence(zone, value));
-+
-+ ast_register_indication(zone, var, value);
-+
-+ CV_END;
-+}
-+
-+static void reset_tone_zone(struct ast_tone_zone *zone)
-+{
-+ ast_tone_zone_lock(zone);
-+
-+ zone->killme = 0;
-+
-+ if (zone->nrringcadence) {
-+ zone->nrringcadence = 0;
-+ ast_free(zone->ringcadence);
-+ zone->ringcadence = NULL;
-+ }
-+
-+ ast_tone_zone_unlock(zone);
-+}
-+
-+static int parse_tone_zone(struct ast_config *cfg, const char *country)
-+{
-+ struct ast_variable *v;
-+ struct ast_tone_zone *zone;
-+ struct ast_tone_zone tmp_zone = {
-+ .nrringcadence = 0,
-+ };
-+ int allocd = 0;
-+
-+ ast_copy_string(tmp_zone.country, country, sizeof(tmp_zone.country));
-+
-+ if ((zone = ao2_find(ast_tone_zones, &tmp_zone, OBJ_POINTER))) {
-+ reset_tone_zone(zone);
-+ } else if ((zone = ast_tone_zone_alloc())) {
-+ allocd = 1;
-+ ast_copy_string(zone->country, country, sizeof(zone->country));
-+ } else {
-+ return -1;
-+ }
-+
-+ ast_tone_zone_lock(zone);
-+ for (v = ast_variable_browse(cfg, country); v; v = v->next) {
-+ store_config_tone_zone(zone, v->name, v->value);
-+ }
-+ ast_tone_zone_unlock(zone);
-+
-+ if (allocd) {
-+ if (!is_valid_tone_zone(zone)) {
-+ ast_log(LOG_WARNING, "Indication country '%s' is invalid\n", country);
-+ } else if (ast_register_indication_country(zone)) {
-+ ast_log(LOG_WARNING, "Unable to register indication country '%s'.\n",
-+ country);
-+ }
-+ }
-+
-+ zone = ast_tone_zone_unref(zone);
-+
- return 0;
- }
-
--/* remove an existing country's indication. Both country and indication must exist */
--int ast_unregister_indication(struct tone_zone *zone, const char *indication)
-+/*!
-+ * Mark the zone and its tones before parsing configuration. We will use this
-+ * to know what to remove after configuration is parsed.
-+ */
-+static int tone_zone_mark(void *obj, void *arg, int flags)
- {
-- struct tone_zone_sound *ts,*ps = NULL, *tmp;
-+ struct ast_tone_zone *zone = obj;
-+ struct ast_tone_zone_sound *s;
-+
-+ ast_tone_zone_lock(zone);
-+
-+ zone->killme = 1;
-+
-+ AST_LIST_TRAVERSE(&zone->tones, s, entry) {
-+ s->killme = 1;
-+ }
-+
-+ ast_tone_zone_unlock(zone);
-+
-+ return 0;
-+}
-+
-+/*!
-+ * Prune tones no longer in the configuration, and have the tone zone unlinked
-+ * if it is no longer in the configuration at all.
-+ */
-+static int prune_tone_zone(void *obj, void *arg, int flags)
-+{
-+ struct ast_tone_zone *zone = obj;
-+ struct ast_tone_zone_sound *s;
-+
-+ ast_tone_zone_lock(zone);
-+
-+ AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, s, entry) {
-+ if (s->killme) {
-+ AST_LIST_REMOVE_CURRENT(entry);
-+ s = ast_tone_zone_sound_unref(s);
-+ }
-+ }
-+ AST_LIST_TRAVERSE_SAFE_END;
-+
-+ ast_tone_zone_unlock(zone);
-+
-+ return zone->killme ? CMP_MATCH : 0;
-+}
-+
-+/*! \brief load indications module */
-+static int load_indications(int reload)
-+{
-+ struct ast_config *cfg;
-+ const char *cxt = NULL;
-+ const char *country = NULL;
-+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- int res = -1;
-
-- /* is it an alias? stop */
-- if (zone->alias[0])
-+ cfg = ast_config_load2(config, "indications", config_flags);
-+
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- return -1;
-+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-+ return 0;
-+ }
-
-- AST_RWLIST_WRLOCK(&tone_zones);
-- ts = zone->tones;
-- while (ts) {
-- if (!strcasecmp(indication,ts->name)) {
-- /* indication found */
-- tmp = ts->next;
-- if (ps)
-- ps->next = tmp;
-- else
-- zone->tones = tmp;
-- ast_free((void*)ts->name);
-- ast_free((void*)ts->data);
-- ast_free(ts);
-- ts = tmp;
-- res = 0;
-+ /* Lock the container to prevent multiple simultaneous reloads */
-+ ao2_lock(ast_tone_zones);
-+
-+ ao2_callback(ast_tone_zones, OBJ_NODATA, tone_zone_mark, NULL);
-+
-+ /* Use existing config to populate the Indication table */
-+ while ((cxt = ast_category_browse(cfg, cxt))) {
-+ /* All categories but "general" are considered countries */
-+ if (!strcasecmp(cxt, "general")) {
-+ continue;
- }
-- else {
-- /* next zone please */
-- ps = ts;
-- ts = ts->next;
-+
-+ if (parse_tone_zone(cfg, cxt)) {
-+ goto return_cleanup;
- }
- }
-- /* indication not found, goodbye */
-- AST_RWLIST_UNLOCK(&tone_zones);
-+
-+ ao2_callback(ast_tone_zones, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
-+ prune_tone_zone, NULL);
-+
-+ /* determine which country is the default */
-+ country = ast_variable_retrieve(cfg, "general", "country");
-+ if (ast_strlen_zero(country) || ast_set_indication_country(country)) {
-+ ast_log(LOG_WARNING, "Unable to set the default country (for indication tones)\n");
-+ }
-+
-+ res = 0;
-+
-+return_cleanup:
-+ ao2_unlock(ast_tone_zones);
-+ ast_config_destroy(cfg);
-+
- return res;
- }
-+
-+/*! \brief CLI entries for commands provided by this module */
-+static struct ast_cli_entry cli_indications[] = {
-+ AST_CLI_DEFINE(handle_cli_indication_add, "Add the given indication to the country"),
-+ AST_CLI_DEFINE(handle_cli_indication_remove, "Remove the given indication from the country"),
-+ AST_CLI_DEFINE(handle_cli_indication_show, "Display a list of all countries/indications")
-+};
-+
-+static int ast_tone_zone_hash(const void *obj, const int flags)
-+{
-+ const struct ast_tone_zone *zone = obj;
-+
-+ return ast_str_case_hash(zone->country);
-+}
-+
-+static int ast_tone_zone_cmp(void *obj, void *arg, int flags)
-+{
-+ struct ast_tone_zone *zone = obj;
-+ struct ast_tone_zone *zone_arg = arg;
-+
-+ return (!strcasecmp(zone->country, zone_arg->country)) ?
-+ CMP_MATCH | CMP_STOP : 0;
-+}
-+
-+/*! \brief Load indications module */
-+int ast_indications_init(void)
-+{
-+ if (!(ast_tone_zones = ao2_container_alloc(NUM_TONE_ZONE_BUCKETS,
-+ ast_tone_zone_hash, ast_tone_zone_cmp))) {
-+ return -1;
-+ }
-+
-+ if (load_indications(0)) {
-+ return -1;
-+ }
-+
-+ ast_cli_register_multiple(cli_indications, ARRAY_LEN(cli_indications));
-+
-+ return 0;
-+}
-+
-+/*! \brief Reload indications module */
-+int ast_indications_reload(void)
-+{
-+ return load_indications(1);
-+}
-+
-Index: main/enum.c
-===================================================================
---- a/main/enum.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/enum.c (.../team/group/issue14292) (revision 178988)
-@@ -959,6 +959,9 @@
-
- if ((cfg = ast_config_load2("enum.conf", "enum", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
- return 0;
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
-+ return 0;
-+ }
-
- /* Destroy existing list */
- ast_mutex_lock(&enumlock);
-Index: main/astobj2.c
-===================================================================
---- a/main/astobj2.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/astobj2.c (.../team/group/issue14292) (revision 178988)
-@@ -120,6 +120,11 @@
- return p;
- }
-
-+enum ao2_callback_type {
-+ DEFAULT,
-+ WITH_DATA,
-+};
-+
- /*!
- * \brief convert from a pointer _p to an astobj2 object
- *
-@@ -135,7 +140,7 @@
- ao2_callback_fn *cmp_fn);
- static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data);
- static void *__ao2_callback(struct ao2_container *c,
-- const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
-+ const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
- char *tag, char *file, int line, const char *funcname);
- static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q);
-
-@@ -183,14 +188,23 @@
- #endif
- }
-
-+#ifndef DEBUG_THREADS
- int ao2_trylock(void *user_data)
-+#else
-+int _ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
-+#endif
- {
- struct astobj2 *p = INTERNAL_OBJ(user_data);
- int ret;
-
- if (p == NULL)
- return -1;
-- ret = ast_mutex_trylock(&p->priv_data.lock);
-+#ifndef DEBUG_THREADS
-+ ret = ast_mutex_trylock(&p->priv_data.lock);
-+#else
-+ ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock);
-+#endif
-+
- #ifdef AO2_DEBUG
- if (!ret)
- ast_atomic_fetchadd_int(&ao2.total_locked, 1);
-@@ -566,6 +580,14 @@
- }
-
- /*!
-+ * \brief similar to cb_true, but is an ao2_callback_data_fn instead
-+ */
-+static int cb_true_data(void *user_data, void *arg, void *data, int flags)
-+{
-+ return CMP_MATCH;
-+}
-+
-+/*!
- * Browse the container using different stategies accoding the flags.
- * \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
- * specified.
-@@ -574,11 +596,13 @@
- * called as often as, say, the ao2_ref func is called.
- */
- static void *__ao2_callback(struct ao2_container *c,
-- const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
-+ const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
- char *tag, char *file, int line, const char *funcname)
- {
- int i, last; /* search boundaries */
- void *ret = NULL;
-+ ao2_callback_fn *cb_default = NULL;
-+ ao2_callback_data_fn *cb_withdata = NULL;
-
- if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */
- return NULL;
-@@ -589,8 +613,22 @@
- }
-
- /* override the match function if necessary */
-- if (cb_fn == NULL) /* if NULL, match everything */
-- cb_fn = cb_true;
-+ if (cb_fn == NULL) { /* if NULL, match everything */
-+ if (type == WITH_DATA) {
-+ cb_withdata = cb_true_data;
-+ } else {
-+ cb_default = cb_true;
-+ }
-+ } else {
-+ /* We do this here to avoid the per object casting penalty (even though
-+ that is probably optimized away anyway. */
-+ if (type == WITH_DATA) {
-+ cb_withdata = cb_fn;
-+ } else {
-+ cb_default = cb_fn;
-+ }
-+ }
-+
- /*
- * XXX this can be optimized.
- * If we have a hash function and lookup by pointer,
-@@ -617,8 +655,14 @@
- struct bucket_list *cur;
-
- AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
-- int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
-+ int match = (CMP_MATCH | CMP_STOP);
-
-+ if (type == WITH_DATA) {
-+ match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags);
-+ } else {
-+ match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags);
-+ }
-+
- /* we found the object, performing operations according flags */
- if (match == 0) { /* no match, no stop, continue */
- continue;
-@@ -673,18 +717,32 @@
-
- void *_ao2_callback_debug(struct ao2_container *c,
- const enum search_flags flags,
-- ao2_callback_fn *cb_fn, void *arg,
-+ ao2_callback_fn *cb_fn, void *arg,
- char *tag, char *file, int line, const char *funcname)
- {
-- return __ao2_callback(c,flags, cb_fn, arg, tag, file, line, funcname);
-+ return __ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
- }
-
--void *_ao2_callback(struct ao2_container *c,const enum search_flags flags,
-+void *_ao2_callback(struct ao2_container *c, const enum search_flags flags,
- ao2_callback_fn *cb_fn, void *arg)
- {
-- return __ao2_callback(c,flags, cb_fn, arg, NULL, NULL, 0, NULL);
-+ return __ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
- }
-
-+void *_ao2_callback_data_debug(struct ao2_container *c,
-+ const enum search_flags flags,
-+ ao2_callback_data_fn *cb_fn, void *arg, void *data,
-+ char *tag, char *file, int line, const char *funcname)
-+{
-+ return __ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
-+}
-+
-+void *_ao2_callback_data(struct ao2_container *c, const enum search_flags flags,
-+ ao2_callback_data_fn *cb_fn, void *arg, void *data)
-+{
-+ return __ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
-+}
-+
- /*!
- * the find function just invokes the default callback with some reasonable flags.
- */
-@@ -877,9 +935,9 @@
- {
- switch (cmd) {
- case CLI_INIT:
-- e->command = "astobj2 stats";
-- e->usage = "Usage: astobj2 stats\n"
-- " Show astobj2 stats\n";
-+ e->command = "astobj2 show stats";
-+ e->usage = "Usage: astobj2 show stats\n"
-+ " Show astobj2 show stats\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
-@@ -953,7 +1011,7 @@
- ao2_t_ref(obj, -1, "test");
- }
- ast_cli(a->fd, "testing callbacks\n");
-- ao2_t_callback(c1, 0, print_cb, &a->fd,"test callback");
-+ ao2_t_callback(c1, 0, print_cb, &a->fd, "test callback");
- ast_cli(a->fd, "testing iterators, remove every second object\n");
- {
- struct ao2_iterator ai;
-@@ -974,7 +1032,7 @@
- }
- }
- ast_cli(a->fd, "testing callbacks again\n");
-- ao2_t_callback(c1, 0, print_cb, &a->fd,"test callback");
-+ ao2_t_callback(c1, 0, print_cb, &a->fd, "test callback");
-
- ast_verbose("now you should see an error message:\n");
- ao2_t_ref(&i, -1, ""); /* i is not a valid object so we print an error here */
-Index: main/cli.c
-===================================================================
---- a/main/cli.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/cli.c (.../team/group/issue14292) (revision 178988)
-@@ -33,6 +33,8 @@
- #include <signal.h>
- #include <ctype.h>
- #include <regex.h>
-+#include <pwd.h>
-+#include <grp.h>
-
- #include "asterisk/cli.h"
- #include "asterisk/linkedlists.h"
-@@ -46,6 +48,35 @@
- #include "asterisk/threadstorage.h"
-
- /*!
-+ * \brief List of restrictions per user.
-+ */
-+struct cli_perm {
-+ unsigned int permit:1; /*!< 1=Permit 0=Deny */
-+ char *command; /*!< Command name (to apply restrictions) */
-+ AST_LIST_ENTRY(cli_perm) list;
-+};
-+
-+AST_LIST_HEAD_NOLOCK(cli_perm_head, cli_perm);
-+
-+/*! \brief list of users to apply restrictions. */
-+struct usergroup_cli_perm {
-+ int uid; /*!< User ID (-1 disabled) */
-+ int gid; /*!< Group ID (-1 disabled) */
-+ struct cli_perm_head *perms; /*!< List of permissions. */
-+ AST_LIST_ENTRY(usergroup_cli_perm) list;/*!< List mechanics */
-+};
-+/*! \brief CLI permissions config file. */
-+static const char perms_config[] = "cli_permissions.conf";
-+/*! \brief Default permissions value 1=Permit 0=Deny */
-+static int cli_default_perm = 1;
-+
-+/*! \brief mutex used to prevent a user from running the 'cli reload permissions' command while
-+ * it is already running. */
-+AST_MUTEX_DEFINE_STATIC(permsconfiglock);
-+/*! \brief List of users and permissions. */
-+AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
-+
-+/*!
- * \brief map a debug or verbose value to a filename
- */
- struct ast_debug_file {
-@@ -79,8 +110,9 @@
- res = ast_str_set_va(&buf, 0, fmt, ap);
- va_end(ap);
-
-- if (res != AST_DYNSTR_BUILD_FAILED)
-- ast_carefulwrite(fd, buf->str, strlen(buf->str), 100);
-+ if (res != AST_DYNSTR_BUILD_FAILED) {
-+ ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
-+ }
- }
-
- unsigned int ast_debug_get_by_file(const char *file)
-@@ -117,6 +149,74 @@
- return res;
- }
-
-+/*! \internal
-+ * \brief Check if the user with 'uid' and 'gid' is allow to execute 'command',
-+ * if command starts with '_' then not check permissions, just permit
-+ * to run the 'command'.
-+ * if uid == -1 or gid == -1 do not check permissions.
-+ * if uid == -2 and gid == -2 is because rasterisk client didn't send
-+ * the credentials, so the cli_default_perm will be applied.
-+ * \param uid User ID.
-+ * \param gid Group ID.
-+ * \param command Command name to check permissions.
-+ * \retval 1 if has permission
-+ * \retval 0 if it is not allowed.
-+ */
-+static int cli_has_permissions(int uid, int gid, const char *command)
-+{
-+ struct usergroup_cli_perm *user_perm;
-+ struct cli_perm *perm;
-+ /* set to the default permissions general option. */
-+ int isallowg = cli_default_perm, isallowu = -1, ispattern;
-+ regex_t regexbuf;
-+
-+ /* if uid == -1 or gid == -1 do not check permissions.
-+ if uid == -2 and gid == -2 is because rasterisk client didn't send
-+ the credentials, so the cli_default_perm will be applied. */
-+ if ((uid == CLI_NO_PERMS && gid == CLI_NO_PERMS) || command[0] == '_') {
-+ return 1;
-+ }
-+
-+ if (gid < 0 && uid < 0) {
-+ return cli_default_perm;
-+ }
-+
-+ AST_RWLIST_RDLOCK(&cli_perms);
-+ AST_LIST_TRAVERSE(&cli_perms, user_perm, list) {
-+ if (user_perm->gid != gid && user_perm->uid != uid) {
-+ continue;
-+ }
-+ AST_LIST_TRAVERSE(user_perm->perms, perm, list) {
-+ if (strcasecmp(perm->command, "all") && strncasecmp(perm->command, command, strlen(perm->command))) {
-+ /* if the perm->command is a pattern, check it against command. */
-+ ispattern = !regcomp(&regexbuf, perm->command, REG_EXTENDED | REG_NOSUB | REG_ICASE);
-+ if (ispattern && regexec(&regexbuf, command, 0, NULL, 0)) {
-+ regfree(&regexbuf);
-+ continue;
-+ }
-+ if (!ispattern) {
-+ continue;
-+ }
-+ regfree(&regexbuf);
-+ }
-+ if (user_perm->uid == uid) {
-+ /* this is a user definition. */
-+ isallowu = perm->permit;
-+ } else {
-+ /* otherwise is a group definition. */
-+ isallowg = perm->permit;
-+ }
-+ }
-+ }
-+ AST_RWLIST_UNLOCK(&cli_perms);
-+ if (isallowu > -1) {
-+ /* user definition override group definition. */
-+ isallowg = isallowu;
-+ }
-+
-+ return isallowg;
-+}
-+
- static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry);
-
- static char *complete_fn(const char *word, int state)
-@@ -166,14 +266,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_load_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_load(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "load";
-- return res;
--}
--
- static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int x;
-@@ -209,14 +301,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_reload_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *s = handle_reload(e, cmd, a);
-- if (cmd == CLI_INIT) /* override command name */
-- e->command = "reload";
-- return s;
--}
--
- /*!
- * \brief Find the debug or verbose file setting
- * \arg debug 1 for debug, 0 for verbose
-@@ -234,6 +318,46 @@
- return df;
- }
-
-+static char *complete_number(const char *partial, unsigned int min, unsigned int max, int n)
-+{
-+ int i, count = 0;
-+ unsigned int prospective[2];
-+ unsigned int part = strtoul(partial, NULL, 10);
-+ char next[12];
-+
-+ if (part < min || part > max) {
-+ return NULL;
-+ }
-+
-+ for (i = 0; i < 21; i++) {
-+ if (i == 0) {
-+ prospective[0] = prospective[1] = part;
-+ } else if (part == 0 && !ast_strlen_zero(partial)) {
-+ break;
-+ } else if (i < 11) {
-+ prospective[0] = prospective[1] = part * 10 + (i - 1);
-+ } else {
-+ prospective[0] = (part * 10 + (i - 11)) * 10;
-+ prospective[1] = prospective[0] + 9;
-+ }
-+ if (i < 11 && (prospective[0] < min || prospective[0] > max)) {
-+ continue;
-+ } else if (prospective[1] < min || prospective[0] > max) {
-+ continue;
-+ }
-+
-+ if (++count > n) {
-+ if (i < 11) {
-+ snprintf(next, sizeof(next), "%u", prospective[0]);
-+ } else {
-+ snprintf(next, sizeof(next), "%u...", prospective[0] / 10);
-+ }
-+ return ast_strdup(next);
-+ }
-+ }
-+ return NULL;
-+}
-+
- static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int oldval;
-@@ -242,6 +366,7 @@
- int fd = a->fd;
- int argc = a->argc;
- char **argv = a->argv;
-+ char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
- int *dst;
- char *what;
- struct debug_file_list *dfl;
-@@ -250,7 +375,7 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "core set {debug|verbose} [off|atleast]";
-+ e->command = "core set {debug|verbose}";
- e->usage =
- "Usage: core set {debug|verbose} [atleast] <level> [filename]\n"
- " core set {debug|verbose} off\n"
-@@ -261,15 +386,38 @@
- return NULL;
-
- case CLI_GENERATE:
-+ if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
-+ char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
-+ int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
-+ if (a->n < 21 && numbermatch == 0) {
-+ return complete_number(pos, 0, 0x7fffffff, a->n);
-+ } else if (pos[0] == '0') {
-+ if (a->n == 0) {
-+ return ast_strdup("0");
-+ } else {
-+ return NULL;
-+ }
-+ } else if (a->n == (21 - numbermatch)) {
-+ if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
-+ return ast_strdup("off");
-+ } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
-+ return ast_strdup("atleast");
-+ }
-+ } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
-+ return ast_strdup("atleast");
-+ }
-+ } else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
-+ return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
-+ }
- return NULL;
- }
- /* all the above return, so we proceed with the handler.
- * we are guaranteed to be called with argc >= e->args;
- */
-
-- if (argc < e->args)
-+ if (argc <= e->args)
- return CLI_SHOWUSAGE;
-- if (!strcasecmp(argv[e->args - 2], "debug")) {
-+ if (!strcasecmp(argv[e->args - 1], "debug")) {
- dst = &option_debug;
- oldval = option_debug;
- what = "Core debug";
-@@ -278,7 +426,7 @@
- oldval = option_verbose;
- what = "Verbosity";
- }
-- if (argc == e->args && !strcasecmp(argv[e->args - 1], "off")) {
-+ if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
- unsigned int debug = (*what == 'C');
- newlevel = 0;
-
-@@ -292,17 +440,17 @@
-
- goto done;
- }
-- if (!strcasecmp(argv[e->args-1], "atleast"))
-+ if (!strcasecmp(argv[e->args], "atleast"))
- atleast = 1;
-- if (argc != e->args + atleast && argc != e->args + atleast + 1)
-+ if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
- return CLI_SHOWUSAGE;
-- if (sscanf(argv[e->args + atleast - 1], "%d", &newlevel) != 1)
-+ if (sscanf(argv[e->args + atleast], "%d", &newlevel) != 1)
- return CLI_SHOWUSAGE;
-- if (argc == e->args + atleast + 1) {
-+ if (argc == e->args + atleast + 2) {
- unsigned int debug = (*what == 'C');
- dfl = debug ? &debug_files : &verbose_files;
-
-- fn = argv[e->args + atleast];
-+ fn = argv[e->args + atleast + 1];
-
- AST_RWLIST_WRLOCK(dfl);
-
-@@ -428,14 +576,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_unload_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_unload(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "unload"; /* XXX override */
-- return res;
--}
--
- #define MODLIST_FORMAT "%-30s %-40.40s %-10d\n"
- #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
-
-@@ -498,11 +638,20 @@
- ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
- }
- x = timeval.tv_sec;
-- if (x > 0 || out->used == 0) /* if there is nothing, print 0 seconds */
-+ if (x > 0 || ast_str_strlen(out) == 0) /* if there is nothing, print 0 seconds */
- ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
-- ast_cli(fd, "%s: %s\n", prefix, out->str);
-+ ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out));
- }
-
-+static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
-+{
-+ if (e) {
-+ return AST_LIST_NEXT(e, list);
-+ } else {
-+ return AST_LIST_FIRST(&helpers);
-+ }
-+}
-+
- static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct timeval curtime = ast_tvnow();
-@@ -756,27 +905,167 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "soft hangup";
-+ e->command = "channel request hangup";
- e->usage =
-- "Usage: soft hangup <channel>\n"
-+ "Usage: channel request hangup <channel>\n"
- " Request that a channel be hung up. The hangup takes effect\n"
- " the next time the driver reads or writes from the channel\n";
- return NULL;
- case CLI_GENERATE:
-- return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
-+ return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
- }
-- if (a->argc != 3)
-+ if (a->argc != 4)
- return CLI_SHOWUSAGE;
-- c = ast_get_channel_by_name_locked(a->argv[2]);
-+ c = ast_get_channel_by_name_locked(a->argv[3]);
- if (c) {
- ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
- ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(c);
- } else
-- ast_cli(a->fd, "%s is not a known channel\n", a->argv[2]);
-+ ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
- return CLI_SUCCESS;
- }
-
-+/*! \brief handles CLI command 'cli show permissions' */
-+static char *handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct usergroup_cli_perm *cp;
-+ struct cli_perm *perm;
-+ struct passwd *pw = NULL;
-+ struct group *gr = NULL;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "cli show permissions";
-+ e->usage =
-+ "Usage: cli show permissions\n"
-+ " Shows CLI configured permissions.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return NULL;
-+ }
-+
-+ AST_RWLIST_RDLOCK(&cli_perms);
-+ AST_LIST_TRAVERSE(&cli_perms, cp, list) {
-+ if (cp->uid >= 0) {
-+ pw = getpwuid(cp->uid);
-+ if (pw) {
-+ ast_cli(a->fd, "user: %s [uid=%d]\n", pw->pw_name, cp->uid);
-+ }
-+ } else {
-+ gr = getgrgid(cp->gid);
-+ if (gr) {
-+ ast_cli(a->fd, "group: %s [gid=%d]\n", gr->gr_name, cp->gid);
-+ }
-+ }
-+ ast_cli(a->fd, "Permissions:\n");
-+ if (cp->perms) {
-+ AST_LIST_TRAVERSE(cp->perms, perm, list) {
-+ ast_cli(a->fd, "\t%s -> %s\n", perm->permit ? "permit" : "deny", perm->command);
-+ }
-+ }
-+ ast_cli(a->fd, "\n");
-+ }
-+ AST_RWLIST_UNLOCK(&cli_perms);
-+
-+ return CLI_SUCCESS;
-+}
-+
-+/*! \brief handles CLI command 'cli reload permissions' */
-+static char *handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "cli reload permissions";
-+ e->usage =
-+ "Usage: cli reload permissions\n"
-+ " Reload the 'cli_permissions.conf' file.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return NULL;
-+ }
-+
-+ ast_cli_perms_init(1);
-+
-+ return CLI_SUCCESS;
-+}
-+
-+/*! \brief handles CLI command 'cli check permissions' */
-+static char *handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct passwd *pw = NULL;
-+ struct group *gr;
-+ int gid = -1, uid = -1;
-+ char command[AST_MAX_ARGS] = "";
-+ struct ast_cli_entry *ce = NULL;
-+ int found = 0;
-+ char *group, *tmp;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "cli check permissions";
-+ e->usage =
-+ "Usage: cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]\n"
-+ " Check permissions config for a user@group or list the allowed commands for the specified user.\n"
-+ " The username or the groupname may be omitted.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ if (a->pos >= 4) {
-+ return ast_cli_generator(a->line + strlen("cli check permissions") + strlen(a->argv[3]) + 1, a->word, a->n);
-+ }
-+ return NULL;
-+ }
-+
-+ if (a->argc < 4) {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ tmp = ast_strdupa(a->argv[3]);
-+ group = strchr(tmp, '@');
-+ if (group) {
-+ gr = getgrnam(&group[1]);
-+ if (!gr) {
-+ ast_cli(a->fd, "Unknown group '%s'\n", &group[1]);
-+ return CLI_FAILURE;
-+ }
-+ group[0] = '\0';
-+ gid = gr->gr_gid;
-+ }
-+
-+ if (!group && ast_strlen_zero(tmp)) {
-+ ast_cli(a->fd, "You didn't supply a username\n");
-+ } else if (!ast_strlen_zero(tmp) && !(pw = getpwnam(tmp))) {
-+ ast_cli(a->fd, "Unknown user '%s'\n", tmp);
-+ return CLI_FAILURE;
-+ } else if (pw) {
-+ uid = pw->pw_uid;
-+ }
-+
-+ if (a->argc == 4) {
-+ while ((ce = cli_next(ce))) {
-+ /* Hide commands that start with '_' */
-+ if (ce->_full_cmd[0] == '_') {
-+ continue;
-+ }
-+ if (cli_has_permissions(uid, gid, ce->_full_cmd)) {
-+ ast_cli(a->fd, "%30.30s %s\n", ce->_full_cmd, S_OR(ce->summary, "<no description available>"));
-+ found++;
-+ }
-+ }
-+ if (!found) {
-+ ast_cli(a->fd, "You are not allowed to run any command on Asterisk\n");
-+ }
-+ } else {
-+ ast_join(command, sizeof(command), a->argv + 4);
-+ ast_cli(a->fd, "%s '%s%s%s' is %s to run command: '%s'\n", uid >= 0 ? "User" : "Group", tmp,
-+ group && uid >= 0 ? "@" : "",
-+ group ? &group[1] : "",
-+ cli_has_permissions(uid, gid, command) ? "allowed" : "not allowed", command);
-+ }
-+
-+ return CLI_SUCCESS;
-+}
-+
- static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
-
- static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-@@ -948,18 +1237,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_debugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res;
--
-- if (cmd == CLI_HANDLER && a->argc != e->args + 1)
-- return CLI_SHOWUSAGE;
-- res = handle_core_set_debug_channel(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "debug channel";
-- return res;
--}
--
- static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- char *res;
-@@ -982,7 +1259,7 @@
- {
- struct ast_channel *c=NULL;
- struct timeval now;
-- struct ast_str *out = ast_str_alloca(2048);
-+ struct ast_str *out = ast_str_thread_get(&global_app_buf, 16);
- char cdrtime[256];
- char nf[256], wf[256], rf[256];
- long elapsed_seconds=0;
-@@ -1071,14 +1348,14 @@
- (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
-
- if (pbx_builtin_serialize_variables(c, &out))
-- ast_cli(a->fd," Variables:\n%s\n", out->str);
-+ ast_cli(a->fd," Variables:\n%s\n", ast_str_buffer(out));
- if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1))
-- ast_cli(a->fd," CDR Variables:\n%s\n", out->str);
-+ ast_cli(a->fd," CDR Variables:\n%s\n", ast_str_buffer(out));
- #ifdef CHANNEL_TRACE
- trace_enabled = ast_channel_trace_is_enabled(c);
- ast_cli(a->fd, " Context Trace: %s\n", trace_enabled ? "Enabled" : "Disabled");
- if (trace_enabled && ast_channel_trace_serialize(c, &out))
-- ast_cli(a->fd, " Trace:\n%s\n", out->str);
-+ ast_cli(a->fd, " Trace:\n%s\n", ast_str_buffer(out));
- #endif
- ast_channel_unlock(c);
- return CLI_SUCCESS;
-@@ -1175,11 +1452,6 @@
- #undef FORMAT_STRING
- }
-
--static struct ast_cli_entry cli_debug_channel_deprecated = AST_CLI_DEFINE(handle_debugchan_deprecated, "Enable debugging on channel");
--static struct ast_cli_entry cli_module_load_deprecated = AST_CLI_DEFINE(handle_load_deprecated, "Load a module");
--static struct ast_cli_entry cli_module_reload_deprecated = AST_CLI_DEFINE(handle_reload_deprecated, "reload modules by name");
--static struct ast_cli_entry cli_module_unload_deprecated = AST_CLI_DEFINE(handle_unload_deprecated, "unload modules by name");
--
- static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
-
- static struct ast_cli_entry cli_cli[] = {
-@@ -1196,8 +1468,7 @@
-
- AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),
-
-- AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel",
-- .deprecate_cmd = &cli_debug_channel_deprecated),
-+ AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
-
- AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
-
-@@ -1209,15 +1480,21 @@
-
- AST_CLI_DEFINE(handle_modlist, "List modules and info"),
-
-- AST_CLI_DEFINE(handle_load, "Load a module by name", .deprecate_cmd = &cli_module_load_deprecated),
-+ AST_CLI_DEFINE(handle_load, "Load a module by name"),
-
-- AST_CLI_DEFINE(handle_reload, "Reload configuration", .deprecate_cmd = &cli_module_reload_deprecated),
-+ AST_CLI_DEFINE(handle_reload, "Reload configuration"),
-
-- AST_CLI_DEFINE(handle_unload, "Unload a module by name", .deprecate_cmd = &cli_module_unload_deprecated ),
-+ AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
-
- AST_CLI_DEFINE(handle_showuptime, "Show uptime information"),
-
- AST_CLI_DEFINE(handle_softhangup, "Request a hangup on a given channel"),
-+
-+ AST_CLI_DEFINE(handle_cli_reload_permissions, "Reload CLI permissions config"),
-+
-+ AST_CLI_DEFINE(handle_cli_show_permissions, "Show CLI permissions"),
-+
-+ AST_CLI_DEFINE(handle_cli_check_permissions, "Try a permissions config for a user"),
- };
-
- /*!
-@@ -1247,31 +1524,162 @@
- return 0;
- }
-
--/*! \brief initialize the _full_cmd string in * each of the builtins. */
--void ast_builtins_init(void)
-+/*! \brief cleanup (free) cli_perms linkedlist. */
-+static void destroy_user_perms(void)
- {
-- ast_cli_register_multiple(cli_cli, sizeof(cli_cli) / sizeof(struct ast_cli_entry));
-+ struct cli_perm *perm;
-+ struct usergroup_cli_perm *user_perm;
-+
-+ AST_RWLIST_WRLOCK(&cli_perms);
-+ while ((user_perm = AST_LIST_REMOVE_HEAD(&cli_perms, list))) {
-+ while ((perm = AST_LIST_REMOVE_HEAD(user_perm->perms, list))) {
-+ ast_free(perm->command);
-+ ast_free(perm);
-+ }
-+ ast_free(user_perm);
-+ }
-+ AST_RWLIST_UNLOCK(&cli_perms);
- }
-
--static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
-+int ast_cli_perms_init(int reload)
- {
-- if (e) {
-- return AST_LIST_NEXT(e, list);
-- } else {
-- return AST_LIST_FIRST(&helpers);
-+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-+ struct ast_config *cfg;
-+ char *cat = NULL;
-+ struct ast_variable *v;
-+ struct usergroup_cli_perm *user_group, *cp_entry;
-+ struct cli_perm *perm = NULL;
-+ struct passwd *pw;
-+ struct group *gr;
-+
-+ if (ast_mutex_trylock(&permsconfiglock)) {
-+ ast_log(LOG_NOTICE, "You must wait until last 'cli reload permissions' command finish\n");
-+ return 1;
- }
-+
-+ cfg = ast_config_load2(perms_config, "" /* core, can't reload */, config_flags);
-+ if (!cfg) {
-+ ast_log (LOG_WARNING, "No cli permissions file found (%s)\n", perms_config);
-+ ast_mutex_unlock(&permsconfiglock);
-+ return 1;
-+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-+ ast_mutex_unlock(&permsconfiglock);
-+ return 0;
-+ }
-+
-+ /* free current structures. */
-+ destroy_user_perms();
-+
-+ while ((cat = ast_category_browse(cfg, cat))) {
-+ if (!strcasecmp(cat, "general")) {
-+ /* General options */
-+ for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
-+ if (!strcasecmp(v->name, "default_perm")) {
-+ cli_default_perm = (!strcasecmp(v->value, "permit")) ? 1: 0;
-+ }
-+ }
-+ continue;
-+ }
-+
-+ /* users or groups */
-+ gr = NULL, pw = NULL;
-+ if (cat[0] == '@') {
-+ /* This is a group */
-+ gr = getgrnam(&cat[1]);
-+ if (!gr) {
-+ ast_log (LOG_WARNING, "Unknown group '%s'\n", &cat[1]);
-+ continue;
-+ }
-+ } else {
-+ /* This is a user */
-+ pw = getpwnam(cat);
-+ if (!pw) {
-+ ast_log (LOG_WARNING, "Unknown user '%s'\n", cat);
-+ continue;
-+ }
-+ }
-+ user_group = NULL;
-+ /* Check for duplicates */
-+ AST_RWLIST_WRLOCK(&cli_perms);
-+ AST_LIST_TRAVERSE(&cli_perms, cp_entry, list) {
-+ if ((pw && cp_entry->uid == pw->pw_uid) || (gr && cp_entry->gid == gr->gr_gid)) {
-+ /* if it is duplicated, just added this new settings, to
-+ the current list. */
-+ user_group = cp_entry;
-+ break;
-+ }
-+ }
-+ AST_RWLIST_UNLOCK(&cli_perms);
-+
-+ if (!user_group) {
-+ /* alloc space for the new user config. */
-+ user_group = ast_calloc(1, sizeof(*user_group));
-+ if (!user_group) {
-+ continue;
-+ }
-+ user_group->uid = (pw ? pw->pw_uid : -1);
-+ user_group->gid = (gr ? gr->gr_gid : -1);
-+ user_group->perms = ast_calloc(1, sizeof(*user_group->perms));
-+ if (!user_group->perms) {
-+ ast_free(user_group);
-+ continue;
-+ }
-+ }
-+ for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
-+ if (ast_strlen_zero(v->value)) {
-+ /* we need to check this condition cause it could break security. */
-+ ast_log(LOG_WARNING, "Empty permit/deny option in user '%s'\n", cat);
-+ continue;
-+ }
-+ if (!strcasecmp(v->name, "permit")) {
-+ perm = ast_calloc(1, sizeof(*perm));
-+ if (perm) {
-+ perm->permit = 1;
-+ perm->command = ast_strdup(v->value);
-+ }
-+ } else if (!strcasecmp(v->name, "deny")) {
-+ perm = ast_calloc(1, sizeof(*perm));
-+ if (perm) {
-+ perm->permit = 0;
-+ perm->command = ast_strdup(v->value);
-+ }
-+ } else {
-+ /* up to now, only 'permit' and 'deny' are possible values. */
-+ ast_log(LOG_WARNING, "Unknown '%s' option\n", v->name);
-+ continue;
-+ }
-+ if (perm) {
-+ /* Added the permission to the user's list. */
-+ AST_LIST_INSERT_TAIL(user_group->perms, perm, list);
-+ perm = NULL;
-+ }
-+ }
-+ AST_RWLIST_WRLOCK(&cli_perms);
-+ AST_RWLIST_INSERT_TAIL(&cli_perms, user_group, list);
-+ AST_RWLIST_UNLOCK(&cli_perms);
-+ }
-+
-+ ast_config_destroy(cfg);
-+ ast_mutex_unlock(&permsconfiglock);
-+ return 0;
- }
-
-+/*! \brief initialize the _full_cmd string in * each of the builtins. */
-+void ast_builtins_init(void)
-+{
-+ ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
-+}
-+
- /*!
- * match a word in the CLI entry.
- * returns -1 on mismatch, 0 on match of an optional word,
- * 1 on match of a full word.
- *
- * The pattern can be
-- * any_word match for equal
-- * [foo|bar|baz] optionally, one of these words
-- * {foo|bar|baz} exactly, one of these words
-- * % any word
-+ * any_word match for equal
-+ * [foo|bar|baz] optionally, one of these words
-+ * {foo|bar|baz} exactly, one of these words
-+ * % any word
- */
- static int word_match(const char *cmd, const char *cli_word)
- {
-@@ -1340,14 +1748,17 @@
- }
-
- /*!
-+ * \internal
- * \brief locate a cli command in the 'helpers' list (which must be locked).
-- * exact has 3 values:
-+ * The search compares word by word taking care of regexps in e->cmda
-+ * This function will return NULL when nothing is matched, or the ast_cli_entry that matched.
-+ * \param cmds
-+ * \param match_type has 3 possible values:
- * 0 returns if the search key is equal or longer than the entry.
-- * note that trailing optional arguments are skipped.
-+ * note that trailing optional arguments are skipped.
- * -1 true if the mismatch is on the last word XXX not true!
- * 1 true only on complete, exact match.
- *
-- * The search compares word by word taking care of regexps in e->cmda
- */
- static struct ast_cli_entry *find_cli(char *const cmds[], int match_type)
- {
-@@ -1389,6 +1800,7 @@
- cand = e;
- }
- }
-+
- return e ? e : cand;
- }
-
-@@ -1413,9 +1825,6 @@
-
- static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
- {
-- if (e->deprecate_cmd) {
-- __ast_cli_unregister(e->deprecate_cmd, e);
-- }
- if (e->inuse) {
- ast_log(LOG_WARNING, "Can't remove command that is in use\n");
- } else {
-@@ -1463,24 +1872,11 @@
- AST_RWLIST_WRLOCK(&helpers);
-
- if (find_cli(e->cmda, 1)) {
-- ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", e->_full_cmd);
-+ ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", S_OR(e->_full_cmd, e->command));
- goto done;
- }
- if (set_full_cmd(e))
- goto done;
-- if (!ed) {
-- e->deprecated = 0;
-- } else {
-- e->deprecated = 1;
-- e->summary = ed->summary;
-- e->usage = ed->usage;
-- /* XXX If command A deprecates command B, and command B deprecates command C...
-- Do we want to show command A or command B when telling the user to use new syntax?
-- This currently would show command A.
-- To show command B, you just need to always use ed->_full_cmd.
-- */
-- e->_deprecated_by = S_OR(ed->_deprecated_by, ed->_full_cmd);
-- }
-
- lf = e->cmdlen;
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&helpers, cur, list) {
-@@ -1501,11 +1897,6 @@
- done:
- AST_RWLIST_UNLOCK(&helpers);
-
-- if (e->deprecate_cmd) {
-- /* This command deprecates another command. Register that one also. */
-- __ast_cli_register(e->deprecate_cmd, e);
-- }
--
- return ret;
- }
-
-@@ -1565,9 +1956,6 @@
- /* Hide commands that start with '_' */
- if (e->_full_cmd[0] == '_')
- continue;
-- /* Hide commands that are marked as deprecated. */
-- if (e->deprecated)
-- continue;
- if (match && strncasecmp(matchstr, e->_full_cmd, len))
- continue;
- ast_cli(fd, "%30.30s %s\n", e->_full_cmd, S_OR(e->summary, "<no description available>"));
-@@ -1587,37 +1975,39 @@
- char *res = CLI_SUCCESS;
-
- if (cmd == CLI_INIT) {
-- e->command = "help";
-+ e->command = "core show help";
- e->usage =
-- "Usage: help [topic]\n"
-+ "Usage: core show help [topic]\n"
- " When called with a topic as an argument, displays usage\n"
- " information on the given command. If called without a\n"
- " topic, it provides a list of commands.\n";
- return NULL;
-
- } else if (cmd == CLI_GENERATE) {
-- /* skip first 4 or 5 chars, "help " */
-+ /* skip first 14 or 15 chars, "core show help " */
- int l = strlen(a->line);
-
-- if (l > 5)
-- l = 5;
-+ if (l > 15) {
-+ l = 15;
-+ }
- /* XXX watch out, should stop to the non-generator parts */
- return __ast_cli_generator(a->line + l, a->word, a->n, 0);
- }
-- if (a->argc == 1)
-+ if (a->argc == e->args) {
- return help1(a->fd, NULL, 0);
-+ }
-
- AST_RWLIST_RDLOCK(&helpers);
-- my_e = find_cli(a->argv + 1, 1); /* try exact match first */
-+ my_e = find_cli(a->argv + 3, 1); /* try exact match first */
- if (!my_e) {
-- res = help1(a->fd, a->argv + 1, 1 /* locked */);
-+ res = help1(a->fd, a->argv + 3, 1 /* locked */);
- AST_RWLIST_UNLOCK(&helpers);
- return res;
- }
- if (my_e->usage)
- ast_cli(a->fd, "%s", my_e->usage);
- else {
-- ast_join(fullcmd, sizeof(fullcmd), a->argv+1);
-+ ast_join(fullcmd, sizeof(fullcmd), a->argv + 3);
- ast_cli(a->fd, "No help text available for '%s'.\n", fullcmd);
- }
- AST_RWLIST_UNLOCK(&helpers);
-@@ -1836,7 +2226,9 @@
- struct ast_cli_args a = {
- .line = matchstr, .word = word,
- .pos = argindex,
-- .n = state - matchnum };
-+ .n = state - matchnum,
-+ .argv = argv,
-+ .argc = x};
- ret = e->handler(e, CLI_GENERATE, &a);
- }
- if (ret)
-@@ -1854,12 +2246,13 @@
- return __ast_cli_generator(text, word, state, 1);
- }
-
--int ast_cli_command(int fd, const char *s)
-+int ast_cli_command_full(int uid, int gid, int fd, const char *s)
- {
- char *args[AST_MAX_ARGS + 1];
- struct ast_cli_entry *e;
- int x;
- char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
-+ char tmp[AST_MAX_ARGS + 1];
- char *retval = NULL;
- struct ast_cli_args a = {
- .fd = fd, .argc = x, .argv = args+1 };
-@@ -1876,9 +2269,18 @@
- ast_atomic_fetchadd_int(&e->inuse, 1);
- AST_RWLIST_UNLOCK(&helpers);
- if (e == NULL) {
-- ast_cli(fd, "No such command '%s' (type 'help %s' for other possible commands)\n", s, find_best(args + 1));
-+ ast_cli(fd, "No such command '%s' (type 'core show help %s' for other possible commands)\n", s, find_best(args + 1));
- goto done;
- }
-+
-+ ast_join(tmp, sizeof(tmp), args + 1);
-+ /* Check if the user has rights to run this command. */
-+ if (!cli_has_permissions(uid, gid, tmp)) {
-+ ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
-+ ast_free(duplicate);
-+ return 0;
-+ }
-+
- /*
- * Within the handler, argv[-1] contains a pointer to the ast_cli_entry.
- * Remember that the array returned by parse_args is NULL-terminated.
-@@ -1889,19 +2291,9 @@
-
- if (retval == CLI_SHOWUSAGE) {
- ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
-- AST_RWLIST_RDLOCK(&helpers);
-- if (e->deprecated)
-- ast_cli(fd, "The '%s' command is deprecated and will be removed in a future release. Please use '%s' instead.\n", e->_full_cmd, e->_deprecated_by);
-- AST_RWLIST_UNLOCK(&helpers);
- } else {
- if (retval == CLI_FAILURE)
- ast_cli(fd, "Command '%s' failed.\n", s);
-- AST_RWLIST_RDLOCK(&helpers);
-- if (e->deprecated == 1) {
-- ast_cli(fd, "The '%s' command is deprecated and will be removed in a future release. Please use '%s' instead.\n", e->_full_cmd, e->_deprecated_by);
-- e->deprecated = 2;
-- }
-- AST_RWLIST_UNLOCK(&helpers);
- }
- ast_atomic_fetchadd_int(&e->inuse, -1);
- done:
-@@ -1909,7 +2301,7 @@
- return 0;
- }
-
--int ast_cli_command_multiple(int fd, size_t size, const char *s)
-+int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
- {
- char cmd[512];
- int x, y = 0, count = 0;
-@@ -1918,7 +2310,7 @@
- cmd[y] = s[x];
- y++;
- if (s[x] == '\0') {
-- ast_cli_command(fd, cmd);
-+ ast_cli_command_full(uid, gid, fd, cmd);
- y = 0;
- count++;
- }
-Index: main/dial.c
-===================================================================
---- a/main/dial.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/dial.c (.../team/group/issue14292) (revision 178988)
-@@ -53,15 +53,15 @@
-
- /*! \brief Dialing channel structure. Contains per-channel dialing options, asterisk channel, and more! */
- struct ast_dial_channel {
-- int num; /*!< Unique number for dialed channel */
-- int timeout; /*!< Maximum time allowed for attempt */
-- char *tech; /*!< Technology being dialed */
-- char *device; /*!< Device being dialed */
-- void *options[AST_DIAL_OPTION_MAX]; /*!< Channel specific options */
-- int cause; /*!< Cause code in case of failure */
-- int is_running_app:1; /*!< Is this running an application? */
-- struct ast_channel *owner; /*!< Asterisk channel */
-- AST_LIST_ENTRY(ast_dial_channel) list; /*!< Linked list information */
-+ int num; /*!< Unique number for dialed channel */
-+ int timeout; /*!< Maximum time allowed for attempt */
-+ char *tech; /*!< Technology being dialed */
-+ char *device; /*!< Device being dialed */
-+ void *options[AST_DIAL_OPTION_MAX]; /*!< Channel specific options */
-+ int cause; /*!< Cause code in case of failure */
-+ unsigned int is_running_app:1; /*!< Is this running an application? */
-+ struct ast_channel *owner; /*!< Asterisk channel */
-+ AST_LIST_ENTRY(ast_dial_channel) list; /*!< Linked list information */
- };
-
- /*! \brief Typedef for dial option enable */
-@@ -177,7 +177,7 @@
- #define S_REPLACE(s, new_val) \
- do { \
- if (s) { \
-- free(s); \
-+ ast_free(s); \
- } \
- s = (new_val); \
- } while (0)
-@@ -271,22 +271,22 @@
- /* Inherit everything from he who spawned this dial */
- if (chan) {
- ast_channel_inherit_variables(chan, channel->owner);
-+ ast_channel_datastore_inherit(chan, channel->owner);
-
- /* Copy over callerid information */
-- S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
-- S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
-- S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
- S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
-+ ast_party_redirecting_copy(&channel->owner->redirecting, &chan->redirecting);
-
-+ channel->owner->cid.cid_tns = chan->cid.cid_tns;
-+
-+ ast_copy_caller_to_connected(&channel->owner->connected, &chan->cid);
-+
- ast_string_field_set(channel->owner, language, chan->language);
- ast_string_field_set(channel->owner, accountcode, chan->accountcode);
- channel->owner->cdrflags = chan->cdrflags;
- if (ast_strlen_zero(channel->owner->musicclass))
- ast_string_field_set(channel->owner, musicclass, chan->musicclass);
-
-- channel->owner->cid.cid_pres = chan->cid.cid_pres;
-- channel->owner->cid.cid_ton = chan->cid.cid_ton;
-- channel->owner->cid.cid_tns = chan->cid.cid_tns;
- channel->owner->adsicpe = chan->adsicpe;
- channel->owner->transfercapability = chan->transfercapability;
- }
-@@ -428,6 +428,14 @@
- ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", channel->owner->name, chan->name);
- ast_indicate(chan, AST_CONTROL_SRCUPDATE);
- break;
-+ case AST_CONTROL_CONNECTED_LINE:
-+ ast_verb(3, "%s connected line has changed, passing it to %s\n", channel->owner->name, chan->name);
-+ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen);
-+ break;
-+ case AST_CONTROL_REDIRECTING:
-+ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name);
-+ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
-+ break;
- case AST_CONTROL_PROCEEDING:
- ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
- ast_indicate(chan, AST_CONTROL_PROCEEDING);
-Index: main/buildinfo.c
-===================================================================
---- a/main/buildinfo.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/buildinfo.c (.../team/group/issue14292) (revision 178988)
-@@ -23,6 +23,7 @@
- * \author Kevin P. Fleming <kpfleming@digium.com>
- */
-
-+#include "asterisk/buildinfo.h"
- #include "asterisk/build.h"
-
- const char *ast_build_hostname = BUILD_HOSTNAME;
-Index: main/heap.c
-===================================================================
---- a/main/heap.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/main/heap.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,284 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2009, Digium, Inc.
-+ *
-+ * Russell Bryant <russell@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief Max Heap data structure
-+ *
-+ * \author Russell Bryant <russell@digium.com>
-+ */
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/heap.h"
-+#include "asterisk/utils.h"
-+#include "asterisk/cli.h"
-+
-+struct ast_heap {
-+ ast_rwlock_t lock;
-+ ast_heap_cmp_fn cmp_fn;
-+ ssize_t index_offset;
-+ size_t cur_len;
-+ size_t avail_len;
-+ void **heap;
-+};
-+
-+static inline int left_node(int i)
-+{
-+ return 2 * i;
-+}
-+
-+static inline int right_node(int i)
-+{
-+ return 2 * i + 1;
-+}
-+
-+static inline int parent_node(int i)
-+{
-+ return i / 2;
-+}
-+
-+static inline void *heap_get(struct ast_heap *h, int i)
-+{
-+ return h->heap[i - 1];
-+}
-+
-+static inline ssize_t get_index(struct ast_heap *h, void *elm)
-+{
-+ ssize_t *index;
-+
-+ if (h->index_offset < 0) {
-+ return -1;
-+ }
-+
-+ index = elm + h->index_offset;
-+
-+ return *index;
-+}
-+
-+static inline void heap_set(struct ast_heap *h, int i, void *elm)
-+{
-+ h->heap[i - 1] = elm;
-+
-+ if (h->index_offset >= 0) {
-+ ssize_t *index = elm + h->index_offset;
-+ *index = i;
-+ }
-+}
-+
-+int ast_heap_verify(struct ast_heap *h)
-+{
-+ unsigned int i;
-+
-+ for (i = 1; i <= (h->cur_len / 2); i++) {
-+ int l = left_node(i);
-+ int r = right_node(i);
-+
-+ if (l <= h->cur_len) {
-+ if (h->cmp_fn(heap_get(h, i), heap_get(h, l)) <= 0) {
-+ return -1;
-+ }
-+ }
-+
-+ if (r <= h->cur_len) {
-+ if (h->cmp_fn(heap_get(h, i), heap_get(h, r)) <= 0) {
-+ return -1;
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+struct ast_heap *ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_fn,
-+ ssize_t index_offset)
-+{
-+ struct ast_heap *h;
-+
-+ if (!cmp_fn) {
-+ ast_log(LOG_ERROR, "A comparison function must be provided\n");
-+ return NULL;
-+ }
-+
-+ if (!init_height) {
-+ init_height = 8;
-+ }
-+
-+ if (!(h = ast_calloc(1, sizeof(*h)))) {
-+ return NULL;
-+ }
-+
-+ h->cmp_fn = cmp_fn;
-+ h->index_offset = index_offset;
-+ h->avail_len = (1 << init_height) - 1;
-+
-+ if (!(h->heap = ast_calloc(1, h->avail_len * sizeof(void *)))) {
-+ ast_free(h);
-+ return NULL;
-+ }
-+
-+ ast_rwlock_init(&h->lock);
-+
-+ return h;
-+}
-+
-+struct ast_heap *ast_heap_destroy(struct ast_heap *h)
-+{
-+ ast_free(h->heap);
-+ h->heap = NULL;
-+
-+ ast_rwlock_destroy(&h->lock);
-+
-+ ast_free(h);
-+
-+ return NULL;
-+}
-+
-+/*!
-+ * \brief Add a row of additional storage for the heap.
-+ */
-+static int grow_heap(struct ast_heap *h)
-+{
-+ h->avail_len = h->avail_len * 2 + 1;
-+
-+ if (!(h->heap = ast_realloc(h->heap, h->avail_len * sizeof(void *)))) {
-+ h->cur_len = h->avail_len = 0;
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+static inline void heap_swap(struct ast_heap *h, int i, int j)
-+{
-+ void *tmp;
-+
-+ tmp = heap_get(h, i);
-+ heap_set(h, i, heap_get(h, j));
-+ heap_set(h, j, tmp);
-+}
-+
-+static inline void max_heapify(struct ast_heap *h, int i)
-+{
-+ for (;;) {
-+ int l = left_node(i);
-+ int r = right_node(i);
-+ int max;
-+
-+ if (l <= h->cur_len && h->cmp_fn(heap_get(h, l), heap_get(h, i)) > 0) {
-+ max = l;
-+ } else {
-+ max = i;
-+ }
-+
-+ if (r <= h->cur_len && h->cmp_fn(heap_get(h, r), heap_get(h, max)) > 0) {
-+ max = r;
-+ }
-+
-+ if (max == i) {
-+ break;
-+ }
-+
-+ heap_swap(h, i, max);
-+
-+ i = max;
-+ }
-+}
-+
-+int ast_heap_push(struct ast_heap *h, void *elm)
-+{
-+ int i;
-+
-+ if (h->cur_len == h->avail_len && grow_heap(h)) {
-+ return -1;
-+ }
-+
-+ heap_set(h, ++(h->cur_len), elm);
-+
-+ for (i = h->cur_len;
-+ i > 1 && h->cmp_fn(heap_get(h, parent_node(i)), heap_get(h, i)) < 0;
-+ i = parent_node(i)) {
-+ heap_swap(h, i, parent_node(i));
-+ }
-+
-+ return 0;
-+}
-+
-+static void *_ast_heap_remove(struct ast_heap *h, unsigned int index)
-+{
-+ void *ret;
-+
-+ if (!index || index > h->cur_len) {
-+ return NULL;
-+ }
-+
-+ ret = heap_get(h, index);
-+ heap_set(h, index, heap_get(h, (h->cur_len)--));
-+
-+ max_heapify(h, index);
-+
-+ return ret;
-+}
-+
-+void *ast_heap_remove(struct ast_heap *h, void *elm)
-+{
-+ ssize_t i = get_index(h, elm);
-+
-+ if (i == -1) {
-+ return NULL;
-+ }
-+
-+ return _ast_heap_remove(h, i);
-+}
-+
-+void *ast_heap_pop(struct ast_heap *h)
-+{
-+ return _ast_heap_remove(h, 1);
-+}
-+
-+void *ast_heap_peek(struct ast_heap *h, unsigned int index)
-+{
-+ if (!h->cur_len || !index || index > h->cur_len) {
-+ return NULL;
-+ }
-+
-+ return heap_get(h, index);
-+}
-+
-+size_t ast_heap_size(struct ast_heap *h)
-+{
-+ return h->cur_len;
-+}
-+
-+int ast_heap_wrlock(struct ast_heap *h)
-+{
-+ return ast_rwlock_wrlock(&h->lock);
-+}
-+
-+int ast_heap_rdlock(struct ast_heap *h)
-+{
-+ return ast_rwlock_rdlock(&h->lock);
-+}
-+
-+int ast_heap_unlock(struct ast_heap *h)
-+{
-+ return ast_rwlock_unlock(&h->lock);
-+}
-+
-
-Property changes on: main/heap.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: main/logger.c
-===================================================================
---- a/main/logger.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/logger.c (.../team/group/issue14292) (revision 178988)
-@@ -35,6 +35,10 @@
-
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-+/*
-+ * WARNING: additional #include directives should NOT be placed here, they
-+ * should be placed AFTER '#undef _ASTERISK_LOGGER_H' below
-+ */
- #include "asterisk/_private.h"
- #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
- #include <signal.h>
-@@ -327,7 +331,7 @@
- const char *s;
- struct ast_flags config_flags = { 0 };
-
-- if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)))
-+ if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID)
- return;
-
- /* delete our list of log channels */
-@@ -969,8 +973,13 @@
- for (;;) {
- /* We lock the message list, and see if any message exists... if not we wait on the condition to be signalled */
- AST_LIST_LOCK(&logmsgs);
-- if (AST_LIST_EMPTY(&logmsgs))
-- ast_cond_wait(&logcond, &logmsgs.lock);
-+ if (AST_LIST_EMPTY(&logmsgs)) {
-+ if (close_logger_thread) {
-+ break;
-+ } else {
-+ ast_cond_wait(&logcond, &logmsgs.lock);
-+ }
-+ }
- next = AST_LIST_FIRST(&logmsgs);
- AST_LIST_HEAD_INIT_NOLOCK(&logmsgs);
- AST_LIST_UNLOCK(&logmsgs);
-@@ -1014,7 +1023,7 @@
- }
-
- /* register the logger cli commands */
-- ast_cli_register_multiple(cli_logger, sizeof(cli_logger) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
-
- ast_mkdir(ast_config_AST_LOG_DIR, 0777);
-
-@@ -1107,8 +1116,8 @@
- result = ast_str_set_va(&buf, BUFSIZ, fmt, ap); /* XXX BUFSIZ ? */
- va_end(ap);
- if (result != AST_DYNSTR_BUILD_FAILED) {
-- term_filter_escapes(buf->str);
-- fputs(buf->str, stdout);
-+ term_filter_escapes(ast_str_buffer(buf));
-+ fputs(ast_str_buffer(buf), stdout);
- }
- }
- return;
-@@ -1141,7 +1150,7 @@
- return;
-
- /* Copy string over */
-- strcpy(logmsg->str, buf->str);
-+ strcpy(logmsg->str, ast_str_buffer(buf));
-
- /* Set type to be normal */
- logmsg->type = LOGMSG_NORMAL;
-@@ -1270,7 +1279,7 @@
- if (!(logmsg = ast_calloc(1, sizeof(*logmsg) + res + 1)))
- return;
-
-- strcpy(logmsg->str, buf->str);
-+ strcpy(logmsg->str, ast_str_buffer(buf));
-
- ast_log(__LOG_VERBOSE, file, line, func, "%s", logmsg->str + 1);
-
-Index: main/sched.c
-===================================================================
---- a/main/sched.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/sched.c (.../team/group/issue14292) (revision 178988)
-@@ -1,7 +1,7 @@
- /*
- * Asterisk -- An open source telephony toolkit.
- *
-- * Copyright (C) 1999 - 2005, Digium, Inc.
-+ * Copyright (C) 1999 - 2008, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
-@@ -45,15 +45,17 @@
- #include "asterisk/linkedlists.h"
- #include "asterisk/dlinkedlists.h"
- #include "asterisk/hashtab.h"
-+#include "asterisk/heap.h"
-
- struct sched {
-- AST_DLLIST_ENTRY(sched) list;
-+ AST_LIST_ENTRY(sched) list;
- int id; /*!< ID number of event */
- struct timeval when; /*!< Absolute time event should take place */
- int resched; /*!< When to reschedule */
- int variable; /*!< Use return value from callback to reschedule */
- const void *data; /*!< Data */
- ast_sched_cb callback; /*!< Callback */
-+ ssize_t __heap_index;
- };
-
- struct sched_context {
-@@ -61,8 +63,8 @@
- unsigned int eventcnt; /*!< Number of events processed */
- unsigned int schedcnt; /*!< Number of outstanding schedule events */
- unsigned int highwater; /*!< highest count so far */
-- AST_DLLIST_HEAD_NOLOCK(, sched) schedq; /*!< Schedule entry and main queue */
- struct ast_hashtab *schedq_ht; /*!< hash table for fast searching */
-+ struct ast_heap *sched_heap;
-
- #ifdef SCHED_MAX_CACHE
- AST_LIST_HEAD_NOLOCK(, sched) schedc; /*!< Cache of unused schedule structures and how many */
-@@ -70,7 +72,149 @@
- #endif
- };
-
-+struct ast_sched_thread {
-+ pthread_t thread;
-+ ast_mutex_t lock;
-+ ast_cond_t cond;
-+ struct sched_context *context;
-+ unsigned int stop:1;
-+};
-
-+static void *sched_run(void *data)
-+{
-+ struct ast_sched_thread *st = data;
-+
-+ while (!st->stop) {
-+ int ms;
-+ struct timespec ts = {
-+ .tv_sec = 0,
-+ };
-+
-+ ast_mutex_lock(&st->lock);
-+
-+ if (st->stop) {
-+ ast_mutex_unlock(&st->lock);
-+ return NULL;
-+ }
-+
-+ ms = ast_sched_wait(st->context);
-+
-+ if (ms == -1) {
-+ ast_cond_wait(&st->cond, &st->lock);
-+ } else {
-+ struct timeval tv;
-+ tv = ast_tvadd(ast_tvnow(), ast_samp2tv(ms, 1000));
-+ ts.tv_sec = tv.tv_sec;
-+ ts.tv_nsec = tv.tv_usec * 1000;
-+ ast_cond_timedwait(&st->cond, &st->lock, &ts);
-+ }
-+
-+ ast_mutex_unlock(&st->lock);
-+
-+ if (st->stop) {
-+ return NULL;
-+ }
-+
-+ ast_sched_runq(st->context);
-+ }
-+
-+ return NULL;
-+}
-+
-+void ast_sched_thread_poke(struct ast_sched_thread *st)
-+{
-+ ast_mutex_lock(&st->lock);
-+ ast_cond_signal(&st->cond);
-+ ast_mutex_unlock(&st->lock);
-+}
-+
-+struct sched_context *ast_sched_thread_get_context(struct ast_sched_thread *st)
-+{
-+ return st->context;
-+}
-+
-+struct ast_sched_thread *ast_sched_thread_destroy(struct ast_sched_thread *st)
-+{
-+ if (st->thread != AST_PTHREADT_NULL) {
-+ ast_mutex_lock(&st->lock);
-+ st->stop = 1;
-+ ast_cond_signal(&st->cond);
-+ ast_mutex_unlock(&st->lock);
-+ pthread_join(st->thread, NULL);
-+ st->thread = AST_PTHREADT_NULL;
-+ }
-+
-+ ast_mutex_destroy(&st->lock);
-+ ast_cond_destroy(&st->cond);
-+
-+ if (st->context) {
-+ sched_context_destroy(st->context);
-+ st->context = NULL;
-+ }
-+
-+ ast_free(st);
-+
-+ return NULL;
-+}
-+
-+struct ast_sched_thread *ast_sched_thread_create(void)
-+{
-+ struct ast_sched_thread *st;
-+
-+ if (!(st = ast_calloc(1, sizeof(*st)))) {
-+ return NULL;
-+ }
-+
-+ ast_mutex_init(&st->lock);
-+ ast_cond_init(&st->cond, NULL);
-+
-+ st->thread = AST_PTHREADT_NULL;
-+
-+ if (!(st->context = sched_context_create())) {
-+ ast_log(LOG_ERROR, "Failed to create scheduler\n");
-+ ast_sched_thread_destroy(st);
-+ return NULL;
-+ }
-+
-+ if (ast_pthread_create_background(&st->thread, NULL, sched_run, st)) {
-+ ast_log(LOG_ERROR, "Failed to create scheduler thread\n");
-+ ast_sched_thread_destroy(st);
-+ return NULL;
-+ }
-+
-+ return st;
-+}
-+
-+int ast_sched_thread_add_variable(struct ast_sched_thread *st, int when, ast_sched_cb cb,
-+ const void *data, int variable)
-+{
-+ int res;
-+
-+ ast_mutex_lock(&st->lock);
-+ res = ast_sched_add_variable(st->context, when, cb, data, variable);
-+ if (res != -1) {
-+ ast_cond_signal(&st->cond);
-+ }
-+ ast_mutex_unlock(&st->lock);
-+
-+ return res;
-+}
-+
-+int ast_sched_thread_add(struct ast_sched_thread *st, int when, ast_sched_cb cb,
-+ const void *data)
-+{
-+ int res;
-+
-+ ast_mutex_lock(&st->lock);
-+ res = ast_sched_add(st->context, when, cb, data);
-+ if (res != -1) {
-+ ast_cond_signal(&st->cond);
-+ }
-+ ast_mutex_unlock(&st->lock);
-+
-+ return res;
-+}
-+
- /* hash routines for sched */
-
- static int sched_cmp(const void *a, const void *b)
-@@ -87,6 +231,11 @@
- return h;
- }
-
-+static int sched_time_cmp(void *a, void *b)
-+{
-+ return ast_tvcmp(((struct sched *) b)->when, ((struct sched *) a)->when);
-+}
-+
- struct sched_context *sched_context_create(void)
- {
- struct sched_context *tmp;
-@@ -96,9 +245,15 @@
-
- ast_mutex_init(&tmp->lock);
- tmp->eventcnt = 1;
--
-+
- tmp->schedq_ht = ast_hashtab_create(23, sched_cmp, ast_hashtab_resize_java, ast_hashtab_newsize_java, sched_hash, 1);
--
-+
-+ if (!(tmp->sched_heap = ast_heap_create(8, sched_time_cmp,
-+ offsetof(struct sched, __heap_index)))) {
-+ sched_context_destroy(tmp);
-+ return NULL;
-+ }
-+
- return tmp;
- }
-
-@@ -114,9 +269,13 @@
- ast_free(s);
- #endif
-
-- /* And the queue */
-- while ((s = AST_DLLIST_REMOVE_HEAD(&con->schedq, list)))
-- ast_free(s);
-+ if (con->sched_heap) {
-+ while ((s = ast_heap_pop(con->sched_heap))) {
-+ ast_free(s);
-+ }
-+ ast_heap_destroy(con->sched_heap);
-+ con->sched_heap = NULL;
-+ }
-
- ast_hashtab_destroy(con->schedq_ht, NULL);
- con->schedq_ht = NULL;
-@@ -168,16 +327,18 @@
- int ast_sched_wait(struct sched_context *con)
- {
- int ms;
-+ struct sched *s;
-
- DEBUG(ast_debug(1, "ast_sched_wait()\n"));
-
- ast_mutex_lock(&con->lock);
-- if (AST_DLLIST_EMPTY(&con->schedq)) {
-+ if ((s = ast_heap_peek(con->sched_heap, 1))) {
-+ ms = ast_tvdiff_ms(s->when, ast_tvnow());
-+ if (ms < 0) {
-+ ms = 0;
-+ }
-+ } else {
- ms = -1;
-- } else {
-- ms = ast_tvdiff_ms(AST_DLLIST_FIRST(&con->schedq)->when, ast_tvnow());
-- if (ms < 0)
-- ms = 0;
- }
- ast_mutex_unlock(&con->lock);
-
-@@ -192,53 +353,17 @@
- */
- static void schedule(struct sched_context *con, struct sched *s)
- {
-- struct sched *cur = NULL;
-- int ret;
-- int df = 0;
-- int de = 0;
-- struct sched *first = AST_DLLIST_FIRST(&con->schedq);
-- struct sched *last = AST_DLLIST_LAST(&con->schedq);
-+ ast_heap_push(con->sched_heap, s);
-
-- if (first)
-- df = ast_tvdiff_us(s->when, first->when);
-- if (last)
-- de = ast_tvdiff_us(s->when, last->when);
--
-- if (df < 0)
-- df = -df;
-- if (de < 0)
-- de = -de;
--
-- if (df < de) {
-- AST_DLLIST_TRAVERSE(&con->schedq, cur, list) {
-- if (ast_tvcmp(s->when, cur->when) == -1) {
-- AST_DLLIST_INSERT_BEFORE(&con->schedq, cur, s, list);
-- break;
-- }
-- }
-- if (!cur) {
-- AST_DLLIST_INSERT_TAIL(&con->schedq, s, list);
-- }
-- } else {
-- AST_DLLIST_TRAVERSE_BACKWARDS(&con->schedq, cur, list) {
-- if (ast_tvcmp(s->when, cur->when) == 1) {
-- AST_DLLIST_INSERT_AFTER(&con->schedq, cur, s, list);
-- break;
-- }
-- }
-- if (!cur) {
-- AST_DLLIST_INSERT_HEAD(&con->schedq, s, list);
-- }
-+ if (!ast_hashtab_insert_safe(con->schedq_ht, s)) {
-+ ast_log(LOG_WARNING,"Schedule Queue entry %d is already in table!\n", s->id);
- }
-
-- ret = ast_hashtab_insert_safe(con->schedq_ht, s);
-- if (!ret)
-- ast_log(LOG_WARNING,"Schedule Queue entry %d is already in table!\n",s->id);
--
- con->schedcnt++;
-
-- if (con->schedcnt > con->highwater)
-+ if (con->schedcnt > con->highwater) {
- con->highwater = con->schedcnt;
-+ }
- }
-
- /*! \brief
-@@ -338,31 +463,25 @@
- int _ast_sched_del(struct sched_context *con, int id, const char *file, int line, const char *function)
- #endif
- {
-- struct sched *s, tmp;
-+ struct sched *s, tmp = {
-+ .id = id,
-+ };
-
- DEBUG(ast_debug(1, "ast_sched_del(%d)\n", id));
-
- ast_mutex_lock(&con->lock);
--
-- /* OK, this is the heart of the sched performance upgrade.
-- If we have 4700 peers, we can have 4700+ entries in the
-- schedq list. searching this would take time. So, I add a
-- hashtab to the context to keep track of each entry, by id.
-- I also leave the linked list alone, almost, -- I implement
-- a doubly-linked list instead, because it would do little good
-- to look up the id in a hashtab, and then have to run thru
-- a couple thousand entries to remove it from the schedq list! */
-- tmp.id = id;
- s = ast_hashtab_lookup(con->schedq_ht, &tmp);
- if (s) {
-- struct sched *x = AST_DLLIST_REMOVE(&con->schedq, s, list);
--
-- if (!x)
-- ast_log(LOG_WARNING,"sched entry %d not in the schedq list?\n", s->id);
-+ if (!ast_heap_remove(con->sched_heap, s)) {
-+ ast_log(LOG_WARNING,"sched entry %d not in the sched heap?\n", s->id);
-+ }
-
-- if (!ast_hashtab_remove_this_object(con->schedq_ht, s))
-+ if (!ast_hashtab_remove_this_object(con->schedq_ht, s)) {
- ast_log(LOG_WARNING,"Found sched entry %d, then couldn't remove it?\n", s->id);
-+ }
-+
- con->schedcnt--;
-+
- sched_release(con, s);
- }
-
-@@ -386,47 +505,49 @@
- return 0;
- }
-
--
--char *ast_sched_report(struct sched_context *con, char *buf, int bufsiz, struct ast_cb_names *cbnames)
-+void ast_sched_report(struct sched_context *con, struct ast_str **buf, struct ast_cb_names *cbnames)
- {
-- int *countlist,i;
-+ int i, x;
- struct sched *cur;
-- char buf2[1200];
-- ast_sched_cb xxx = NULL;
-+ int countlist[cbnames->numassocs + 1];
-+ size_t heap_size;
-
-- buf[0] = 0;
-- sprintf(buf, " Highwater = %d\n schedcnt = %d\n", con->highwater, con->schedcnt);
-- countlist = ast_calloc(sizeof(int),cbnames->numassocs+1);
--
-- AST_DLLIST_TRAVERSE(&con->schedq, cur, list) {
-+ ast_str_set(buf, 0, " Highwater = %d\n schedcnt = %d\n", con->highwater, con->schedcnt);
-+
-+ ast_mutex_lock(&con->lock);
-+
-+ heap_size = ast_heap_size(con->sched_heap);
-+ for (x = 1; x <= heap_size; x++) {
-+ cur = ast_heap_peek(con->sched_heap, x);
- /* match the callback to the cblist */
-- for (i=0;i<cbnames->numassocs;i++) {
-- if (cur->callback == cbnames->cblist[i])
-+ for (i = 0; i < cbnames->numassocs; i++) {
-+ if (cur->callback == cbnames->cblist[i]) {
- break;
-+ }
- }
-- if (i < cbnames->numassocs)
-+ if (i < cbnames->numassocs) {
- countlist[i]++;
-- else {
-- xxx = cur->callback;
-+ } else {
- countlist[cbnames->numassocs]++;
- }
- }
-- for (i=0;i<cbnames->numassocs;i++) {
-- sprintf(buf2," %s : %d\n", cbnames->list[i], countlist[i]);
-- strcat(buf, buf2);
-+
-+ ast_mutex_unlock(&con->lock);
-+
-+ for (i = 0; i < cbnames->numassocs; i++) {
-+ ast_str_append(buf, 0, " %s : %d\n", cbnames->list[i], countlist[i]);
- }
-- sprintf(buf2," <unknown:%p> : %d\n", xxx, countlist[cbnames->numassocs]);
-- strcat( buf, buf2);
-- return buf;
-+
-+ ast_str_append(buf, 0, " <unknown> : %d\n", countlist[cbnames->numassocs]);
- }
--
--
-
- /*! \brief Dump the contents of the scheduler to LOG_DEBUG */
--void ast_sched_dump(const struct sched_context *con)
-+void ast_sched_dump(struct sched_context *con)
- {
- struct sched *q;
- struct timeval when = ast_tvnow();
-+ int x;
-+ size_t heap_size;
- #ifdef SCHED_MAX_CACHE
- ast_debug(1, "Asterisk Schedule Dump (%d in Q, %d Total, %d Cache, %d high-water)\n", con->schedcnt, con->eventcnt - 1, con->schedccnt, con->highwater);
- #else
-@@ -436,9 +557,12 @@
- ast_debug(1, "=============================================================\n");
- ast_debug(1, "|ID Callback Data Time (sec:ms) |\n");
- ast_debug(1, "+-----+-----------------+-----------------+-----------------+\n");
-- AST_DLLIST_TRAVERSE(&con->schedq, q, list) {
-- struct timeval delta = ast_tvsub(q->when, when);
--
-+ ast_mutex_lock(&con->lock);
-+ heap_size = ast_heap_size(con->sched_heap);
-+ for (x = 1; x <= heap_size; x++) {
-+ struct timeval delta;
-+ q = ast_heap_peek(con->sched_heap, x);
-+ delta = ast_tvsub(q->when, when);
- ast_debug(1, "|%.4d | %-15p | %-15p | %.6ld : %.6ld |\n",
- q->id,
- q->callback,
-@@ -446,8 +570,8 @@
- (long)delta.tv_sec,
- (long int)delta.tv_usec);
- }
-+ ast_mutex_unlock(&con->lock);
- ast_debug(1, "=============================================================\n");
--
- }
-
- /*! \brief
-@@ -464,19 +588,22 @@
-
- ast_mutex_lock(&con->lock);
-
-- for (numevents = 0; !AST_DLLIST_EMPTY(&con->schedq); numevents++) {
-+ for (numevents = 0; (current = ast_heap_peek(con->sched_heap, 1)); numevents++) {
- /* schedule all events which are going to expire within 1ms.
- * We only care about millisecond accuracy anyway, so this will
- * help us get more than one event at one time if they are very
- * close together.
- */
- when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000));
-- if (ast_tvcmp(AST_DLLIST_FIRST(&con->schedq)->when, when) != -1)
-+ if (ast_tvcmp(current->when, when) != -1) {
- break;
-+ }
-
-- current = AST_DLLIST_REMOVE_HEAD(&con->schedq, list);
-- if (!ast_hashtab_remove_this_object(con->schedq_ht, current))
-+ current = ast_heap_pop(con->sched_heap);
-+
-+ if (!ast_hashtab_remove_this_object(con->schedq_ht, current)) {
- ast_log(LOG_ERROR,"Sched entry %d was in the schedq list but not in the hashtab???\n", current->id);
-+ }
-
- con->schedcnt--;
-
-@@ -500,11 +627,12 @@
- */
- if (sched_settime(&current->when, current->variable? res : current->resched)) {
- sched_release(con, current);
-- } else
-+ } else {
- schedule(con, current);
-+ }
- } else {
- /* No longer needed, so release it */
-- sched_release(con, current);
-+ sched_release(con, current);
- }
- }
-
-Index: main/pbx.c
-===================================================================
---- a/main/pbx.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/pbx.c (.../team/group/issue14292) (revision 178988)
-@@ -12,7 +12,7 @@
- * 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
-+* the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-@@ -59,12 +59,12 @@
- #include "asterisk/musiconhold.h"
- #include "asterisk/app.h"
- #include "asterisk/devicestate.h"
--#include "asterisk/stringfields.h"
- #include "asterisk/event.h"
- #include "asterisk/hashtab.h"
- #include "asterisk/module.h"
- #include "asterisk/indications.h"
- #include "asterisk/taskprocessor.h"
-+#include "asterisk/xmldoc.h"
-
- /*!
- * \note I M P O R T A N T :
-@@ -87,6 +87,637 @@
- *
- */
-
-+/*** DOCUMENTATION
-+ <application name="Answer" language="en_US">
-+ <synopsis>
-+ Answer a channel if ringing.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="delay">
-+ <para>Asterisk will wait this number of milliseconds before returning to
-+ the dialplan after answering the call.</para>
-+ </parameter>
-+ <parameter name="nocdr">
-+ <para>Asterisk will send an answer signal to the calling phone, but will not
-+ set the disposition or answer time in the CDR for this call.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>If the call has not been answered, this application will
-+ answer it. Otherwise, it has no effect on the call.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Hangup</ref>
-+ </see-also>
-+ </application>
-+ <application name="BackGround" language="en_US">
-+ <synopsis>
-+ Play an audio file while waiting for digits of an extension to go to.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filenames" required="true" argsep="&amp;">
-+ <argument name="filename1" required="true" />
-+ <argument name="filename2" multiple="true" />
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="s">
-+ <para>Causes the playback of the message to be skipped
-+ if the channel is not in the <literal>up</literal> state (i.e. it
-+ hasn't been answered yet). If this happens, the
-+ application will return immediately.</para>
-+ </option>
-+ <option name="n">
-+ <para>Don't answer the channel before playing the files.</para>
-+ </option>
-+ <option name="m">
-+ <para>Only break if a digit hit matches a one digit
-+ extension in the destination context.</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ <parameter name="langoverride">
-+ <para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
-+ </parameter>
-+ <parameter name="context">
-+ <para>This is the dialplan context that this application will use when exiting
-+ to a dialed extension.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
-+ while waiting for an extension to be dialed by the calling channel. To continue waiting
-+ for digits after this application has finished playing files, the <literal>WaitExten</literal>
-+ application should be used.</para>
-+ <para>If one of the requested sound files does not exist, call processing will be terminated.</para>
-+ <para>This application sets the following channel variable upon completion:</para>
-+ <variablelist>
-+ <variable name="BACKGROUNDSTATUS">
-+ <para>The status of the background attempt as a text string.</para>
-+ <value name="SUCCESS" />
-+ <value name="FAILED" />
-+ </variable>
-+ </variablelist>
-+ </description>
-+ <see-also>
-+ <ref type="application">ControlPlayback</ref>
-+ <ref type="application">WaitExten</ref>
-+ <ref type="application">BackgroundDetect</ref>
-+ <ref type="function">TIMEOUT</ref>
-+ </see-also>
-+ </application>
-+ <application name="Busy" language="en_US">
-+ <synopsis>
-+ Indicate the Busy condition.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="timeout">
-+ <para>If specified, the calling channel will be hung up after the specified number of seconds.
-+ Otherwise, this application will wait until the calling channel hangs up.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will indicate the busy condition to the calling channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Congestion</ref>
-+ <ref type="application">Progess</ref>
-+ <ref type="application">Playtones</ref>
-+ <ref type="application">Hangup</ref>
-+ </see-also>
-+ </application>
-+ <application name="Congestion" language="en_US">
-+ <synopsis>
-+ Indicate the Congestion condition.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="timeout">
-+ <para>If specified, the calling channel will be hung up after the specified number of seconds.
-+ Otherwise, this application will wait until the calling channel hangs up.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will indicate the congestion condition to the calling channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Busy</ref>
-+ <ref type="application">Progess</ref>
-+ <ref type="application">Playtones</ref>
-+ <ref type="application">Hangup</ref>
-+ </see-also>
-+ </application>
-+ <application name="ExecIfTime" language="en_US">
-+ <synopsis>
-+ Conditional application execution based on the current time.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="day_condition" required="true">
-+ <argument name="times" required="true" />
-+ <argument name="weekdays" required="true" />
-+ <argument name="mdays" required="true" />
-+ <argument name="months" required="true" />
-+ <argument name="timezone" required="false" />
-+ </parameter>
-+ <parameter name="appname" required="true" hasparams="optional">
-+ <argument name="appargs" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will execute the specified dialplan application, with optional
-+ arguments, if the current time matches the given time specification.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Exec</ref>
-+ <ref type="application">TryExec</ref>
-+ </see-also>
-+ </application>
-+ <application name="Goto" language="en_US">
-+ <synopsis>
-+ Jump to a particular priority, extension, or context.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="context" />
-+ <parameter name="extensions" />
-+ <parameter name="priority" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will set the current context, extension, and priority in the channel structure.
-+ After it completes, the pbx engine will continue dialplan execution at the specified location.
-+ If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
-+ <replaceable>context</replaceable>, are specified, then this application will
-+ just set the specified <replaceable>priority</replaceable> of the current extension.</para>
-+ <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
-+ return a <literal>-1</literal>, and the channel and call will be terminated.</para>
-+ <para>If the location that is put into the channel information is bogus, and asterisk cannot
-+ find that location in the dialplan, then the execution engine will try to find and execute the code in
-+ the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
-+ <literal>h</literal> extension. If either or neither the <literal>h</literal> or <literal>i</literal> extensions
-+ have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
-+ What this means is that, for example, you specify a context that does not exist, then
-+ it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
-+ and the call will terminate!</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">GotoIf</ref>
-+ <ref type="application">GotoIfTime</ref>
-+ <ref type="application">Gosub</ref>
-+ <ref type="application">Macro</ref>
-+ </see-also>
-+ </application>
-+ <application name="GotoIf" language="en_US">
-+ <synopsis>
-+ Conditional goto.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="condition" required="true" />
-+ <parameter name="destination" required="true" argsep=":">
-+ <argument name="labeliftrue">
-+ <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.</para>
-+ </argument>
-+ <argument name="labeliffalse">
-+ <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.</para>
-+ </argument>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will set the current context, extension, and priority in the channel structure
-+ based on the evaluation of the given condition. After this application completes, the
-+ pbx engine will continue dialplan execution at the specified location in the dialplan.
-+ The labels are specified with the same syntax as used within the Goto application.
-+ If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
-+ next instruction. If the target location is bogus, and does not exist, the execution engine will try
-+ to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
-+ If that does not exist, it will try to execute the <literal>h</literal> extension.
-+ If either or neither the <literal>h</literal> or <literal>i</literal> extensions have been defined,
-+ the channel is hung up, and the execution of instructions on the channel is terminated.
-+ Remember that this command can set the current context, and if the context specified
-+ does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
-+ the channel and call will both be terminated!.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Goto</ref>
-+ <ref type="application">GotoIfTime</ref>
-+ <ref type="application">GosubIf</ref>
-+ <ref type="application">MacroIf</ref>
-+ </see-also>
-+ </application>
-+ <application name="GotoIfTime" language="en_US">
-+ <synopsis>
-+ Conditional Goto based on the current time.
-+ </synopsis>
-+ <syntax argsep="?">
-+ <parameter name="condition" required="true">
-+ <argument name="times" required="true" />
-+ <argument name="weekdays" required="true" />
-+ <argument name="mdays" required="true" />
-+ <argument name="months" required="true" />
-+ <argument name="timezone" required="false" />
-+ </parameter>
-+ <parameter name="destination" required="true" argsep=":">
-+ <argument name="labeliftrue" />
-+ <argument name="labeliffalse" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will set the context, extension, and priority in the channel structure
-+ based on the evaluation of the given time specification. After this application completes,
-+ the pbx engine will continue dialplan execution at the specified location in the dialplan.
-+ If the current time is within the given time specification, the channel will continue at
-+ <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
-+ If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
-+ instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
-+ Further information on the time specification can be found in examples
-+ illustrating how to do time-based context includes in the dialplan.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">GotoIf</ref>
-+ <ref type="function">IFTIME</ref>
-+ </see-also>
-+ </application>
-+ <application name="ImportVar" language="en_US">
-+ <synopsis>
-+ Import a variable from a channel into a new variable.
-+ </synopsis>
-+ <syntax argsep="=">
-+ <parameter name="newvar" required="true" />
-+ <parameter name="vardata" required="true">
-+ <argument name="channelname" required="true" />
-+ <argument name="variable" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application imports a <replaceable>variable</replaceable> from the specified
-+ <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
-+ (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
-+ application). Variables created by this application have the same inheritance properties as those
-+ created with the <literal>Set</literal> application.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Set</ref>
-+ </see-also>
-+ </application>
-+ <application name="Hangup" language="en_US">
-+ <synopsis>
-+ Hang up the calling channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="causecode">
-+ <para>If a <replaceable>causecode</replaceable> is given the channel's
-+ hangup cause will be set to the given value.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application will hang up the calling channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Answer</ref>
-+ <ref type="application">Busy</ref>
-+ <ref type="application">Congestion</ref>
-+ </see-also>
-+ </application>
-+ <application name="Incomplete" language="en_US">
-+ <synopsis>
-+ Returns AST_PBX_INCOMPLETE value.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="n">
-+ <para>If specified, then Incomplete will not attempt to answer the channel first.</para>
-+ <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Signals the PBX routines that the previous matched extension is incomplete
-+ and that further input should be allowed before matching can be considered
-+ to be complete. Can be used within a pattern match when certain criteria warrants
-+ a longer match.</para>
-+ </description>
-+ </application>
-+ <application name="NoOp" language="en_US">
-+ <synopsis>
-+ Do Nothing (No Operation).
-+ </synopsis>
-+ <syntax>
-+ <parameter name="text">
-+ <para>Any text provided can be viewed at the Asterisk CLI.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application does nothing. However, it is useful for debugging purposes.</para>
-+ <para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Verbose</ref>
-+ <ref type="application">Log</ref>
-+ </see-also>
-+ </application>
-+ <application name="Proceeding" language="en_US">
-+ <synopsis>
-+ Indicate proceeding.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>This application will request that a proceeding message be provided to the calling channel.</para>
-+ </description>
-+ </application>
-+ <application name="Progress" language="en_US">
-+ <synopsis>
-+ Indicate progress.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>This application will request that in-band progress information be provided to the calling channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Busy</ref>
-+ <ref type="application">Congestion</ref>
-+ <ref type="application">Ringing</ref>
-+ <ref type="application">Playtones</ref>
-+ </see-also>
-+ </application>
-+ <application name="RaiseException" language="en_US">
-+ <synopsis>
-+ Handle an exceptional condition.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="reason" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will jump to the <literal>e</literal> extension in the current context, setting the
-+ dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">Exception</ref>
-+ </see-also>
-+ </application>
-+ <application name="ResetCDR" language="en_US">
-+ <synopsis>
-+ Resets the Call Data Record.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="w">
-+ <para>Store the current CDR record before resetting it.</para>
-+ </option>
-+ <option name="a">
-+ <para>Store any stacked records.</para>
-+ </option>
-+ <option name="v">
-+ <para>Save CDR variables.</para>
-+ </option>
-+ <option name="e">
-+ <para>Enable CDR only (negate effects of NoCDR).</para>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application causes the Call Data Record to be reset.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">ForkCDR</ref>
-+ <ref type="application">NoCDR</ref>
-+ </see-also>
-+ </application>
-+ <application name="Ringing" language="en_US">
-+ <synopsis>
-+ Indicate ringing tone.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>This application will request that the channel indicate a ringing tone to the user.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Busy</ref>
-+ <ref type="application">Congestion</ref>
-+ <ref type="application">Progress</ref>
-+ <ref type="application">Playtones</ref>
-+ </see-also>
-+ </application>
-+ <application name="SayAlpha" language="en_US">
-+ <synopsis>
-+ Say Alpha.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will play the sounds that correspond to the letters of the
-+ given <replaceable>string</replaceable>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">SayDigits</ref>
-+ <ref type="application">SayNumber</ref>
-+ <ref type="application">SayPhonetic</ref>
-+ <ref type="function">CHANNEL</ref>
-+ </see-also>
-+ </application>
-+ <application name="SayDigits" language="en_US">
-+ <synopsis>
-+ Say Digits.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="digits" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will play the sounds that correspond to the digits of
-+ the given number. This will use the language that is currently set for the channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">SayAlpha</ref>
-+ <ref type="application">SayNumber</ref>
-+ <ref type="application">SayPhonetic</ref>
-+ <ref type="function">CHANNEL</ref>
-+ </see-also>
-+ </application>
-+ <application name="SayNumber" language="en_US">
-+ <synopsis>
-+ Say Number.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="digits" required="true" />
-+ <parameter name="gender" />
-+ </syntax>
-+ <description>
-+ <para>This application will play the sounds that correspond to the given <replaceable>digits</replaceable>.
-+ Optionally, a <replaceable>gender</replaceable> may be specified. This will use the language that is currently
-+ set for the channel. See the LANGUAGE() function for more information on setting the language for the channel.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">SayAlpha</ref>
-+ <ref type="application">SayDigits</ref>
-+ <ref type="application">SayPhonetic</ref>
-+ <ref type="function">CHANNEL</ref>
-+ </see-also>
-+ </application>
-+ <application name="SayPhonetic" language="en_US">
-+ <synopsis>
-+ Say Phonetic.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="string" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This application will play the sounds from the phonetic alphabet that correspond to the
-+ letters in the given <replaceable>string</replaceable>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">SayAlpha</ref>
-+ <ref type="application">SayDigits</ref>
-+ <ref type="application">SayNumber</ref>
-+ </see-also>
-+ </application>
-+ <application name="Set" language="en_US">
-+ <synopsis>
-+ Set channel variable or function value.
-+ </synopsis>
-+ <syntax argsep="=">
-+ <parameter name="name" required="true" />
-+ <parameter name="value" required="true" />
-+ </syntax>
-+ <description>
-+ <para>This function can be used to set the value of channel variables or dialplan functions.
-+ When setting variables, if the variable name is prefixed with <literal>_</literal>,
-+ the variable will be inherited into channels created from the current channel.
-+ If the variable name is prefixed with <literal>__</literal>, the variable will be
-+ inherited into channels created from the current channel and all children channels.</para>
-+ <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
-+ a <literal>[compat]</literal> category, and you have <literal>app_set = 1.6</literal> under that,then
-+ the behavior of this app changes, and does not strip surrounding quotes from the right hand side as
-+ it did previously in 1.4. The <literal>app_set = 1.6</literal> is only inserted if <literal>make samples</literal>
-+ is executed, or if users insert this by hand into the <filename>asterisk.conf</filename> file.
-+ The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
-+ were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
-+ protect separators and quotes in various database access strings has been greatly
-+ reduced by these changes.</para></note>
-+ </description>
-+ <see-also>
-+ <ref type="application">MSet</ref>
-+ <ref type="function">GLOBAL</ref>
-+ <ref type="function">SET</ref>
-+ <ref type="function">ENV</ref>
-+ </see-also>
-+ </application>
-+ <application name="MSet" language="en_US">
-+ <synopsis>
-+ Set channel variable(s) or function value(s).
-+ </synopsis>
-+ <syntax>
-+ <parameter name="set1" required="true" argsep="=">
-+ <argument name="name1" required="true" />
-+ <argument name="value1" required="true" />
-+ </parameter>
-+ <parameter name="set2" multiple="true" argsep="=">
-+ <argument name="name2" required="true" />
-+ <argument name="value2" required="true" />
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This function can be used to set the value of channel variables or dialplan functions.
-+ When setting variables, if the variable name is prefixed with <literal>_</literal>,
-+ the variable will be inherited into channels created from the current channel
-+ If the variable name is prefixed with <literal>__</literal>, the variable will be
-+ inherited into channels created from the current channel and all children channels.
-+ MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
-+ prone to doing things that you may not expect. For example, it strips surrounding
-+ double-quotes from the right-hand side (value). If you need to put a separator
-+ character (comma or vert-bar), you will need to escape them by inserting a backslash
-+ before them. Avoid its use if possible.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Set</ref>
-+ </see-also>
-+ </application>
-+ <application name="SetAMAFlags" language="en_US">
-+ <synopsis>
-+ Set the AMA Flags.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="flag" />
-+ </syntax>
-+ <description>
-+ <para>This application will set the channel's AMA Flags for billing purposes.</para>
-+ </description>
-+ <see-also>
-+ <ref type="function">CDR</ref>
-+ </see-also>
-+ </application>
-+ <application name="Wait" language="en_US">
-+ <synopsis>
-+ Waits for some time.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="seconds" required="true">
-+ <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
-+ application to wait for 1.5 seconds.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
-+ </description>
-+ </application>
-+ <application name="WaitExten" language="en_US">
-+ <synopsis>
-+ Waits for an extension to be entered.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="seconds">
-+ <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
-+ application to wait for 1.5 seconds.</para>
-+ </parameter>
-+ <parameter name="options">
-+ <optionlist>
-+ <option name="m">
-+ <para>Provide music on hold to the caller while waiting for an extension.</para>
-+ <argument name="x">
-+ <para>Specify the class for music on hold.</para>
-+ </argument>
-+ </option>
-+ </optionlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application waits for the user to enter a new extension for a specified number
-+ of <replaceable>seconds</replaceable>.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">Background</ref>
-+ <ref type="function">TIMEOUT</ref>
-+ </see-also>
-+ </application>
-+ <function name="EXCEPTION" language="en_US">
-+ <synopsis>
-+ Retrieve the details of the current dialplan exception.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="field" required="true">
-+ <para>The following fields are available for retrieval:</para>
-+ <enumlist>
-+ <enum name="reason">
-+ <para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
-+ value set by the RaiseException() application</para>
-+ </enum>
-+ <enum name="context">
-+ <para>The context executing when the exception occurred.</para>
-+ </enum>
-+ <enum name="exten">
-+ <para>The extension executing when the exception occurred.</para>
-+ </enum>
-+ <enum name="priority">
-+ <para>The numeric priority executing when the exception occurred.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
-+ </description>
-+ <see-also>
-+ <ref type="application">RaiseException</ref>
-+ </see-also>
-+ </function>
-+ ***/
-+
- #ifdef LOW_MEMORY
- #define EXT_DATA_SIZE 256
- #else
-@@ -127,6 +758,7 @@
- static struct ast_taskprocessor *device_state_tps;
-
- AST_THREADSTORAGE(switch_data);
-+AST_THREADSTORAGE(extensionstate_buf);
-
- /*!
- \brief ast_exten: An extension
-@@ -220,12 +852,17 @@
- char name[0]; /*!< Name of the context */
- };
-
--
- /*! \brief ast_app: A registered application */
- struct ast_app {
- int (*execute)(struct ast_channel *chan, void *data);
-- const char *synopsis; /*!< Synopsis text for 'show applications' */
-- const char *description; /*!< Description (help text) for 'show application &lt;name&gt;' */
-+ AST_DECLARE_STRING_FIELDS(
-+ AST_STRING_FIELD(synopsis); /*!< Synopsis text for 'show applications' */
-+ AST_STRING_FIELD(description); /*!< Description (help text) for 'show application &lt;name&gt;' */
-+ AST_STRING_FIELD(syntax); /*!< Syntax text for 'core show applications' */
-+ AST_STRING_FIELD(arguments); /*!< Arguments description */
-+ AST_STRING_FIELD(seealso); /*!< See also */
-+ );
-+ enum ast_doc_src docsrc;/*!< Where the documentation come from. */
- AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */
- struct ast_module *module; /*!< Module this app belongs to */
- char name[0]; /*!< Name of the application */
-@@ -309,10 +946,15 @@
- int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
- static int pbx_builtin_importvar(struct ast_channel *, void *);
- static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
--static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action);
-+static void new_find_extension(const char *str, struct scoreboard *score,
-+ struct match_char *tree, int length, int spec, const char *callerid,
-+ const char *label, enum ext_match_t action);
- static struct match_char *already_in_tree(struct match_char *current, char *pat);
--static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly);
--static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **parent);
-+static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
-+ struct ast_exten *e1, int findonly);
-+static struct match_char *add_pattern_node(struct ast_context *con,
-+ struct match_char *current, char *pattern, int is_pattern,
-+ int already, int specificity, struct match_char **parent);
- static void create_match_char_tree(struct ast_context *con);
- static struct ast_exten *get_canmatch_exten(struct match_char *node);
- static void destroy_pattern_tree(struct match_char *pattern_tree);
-@@ -325,6 +967,15 @@
- static unsigned int hashtab_hash_priority(const void *obj);
- static unsigned int hashtab_hash_labels(const void *obj);
- static void __ast_internal_context_destroy( struct ast_context *con);
-+static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
-+ int priority, const char *label, const char *callerid,
-+ const char *application, void *data, void (*datad)(void *), const char *registrar);
-+static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
-+ struct ast_exten *el, struct ast_exten *e, int replace, int lockhints);
-+static int ast_add_extension2_lockopt(struct ast_context *con,
-+ int replace, const char *extension, int priority, const char *label, const char *callerid,
-+ const char *application, void *data, void (*datad)(void *),
-+ const char *registrar, int lockconts, int lockhints);
-
- /* a func for qsort to use to sort a char array */
- static int compare_char(const void *a, const void *b)
-@@ -432,289 +1083,37 @@
- static struct pbx_builtin {
- char name[AST_MAX_APP];
- int (*execute)(struct ast_channel *chan, void *data);
-- char *synopsis;
-- char *description;
- } builtins[] =
- {
- /* These applications are built into the PBX core and do not
- need separate modules */
-
-- { "Answer", pbx_builtin_answer,
-- "Answer a channel if ringing",
-- " Answer([delay]): If the call has not been answered, this application will\n"
-- "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
-- "Asterisk will wait this number of milliseconds before returning to\n"
-- "the dialplan after answering the call.\n"
-- },
--
-- { "BackGround", pbx_builtin_background,
-- "Play an audio file while waiting for digits of an extension to go to.",
-- " Background(filename1[&filename2...][,options[,langoverride][,context]]):\n"
-- "This application will play the given list of files (do not put extension)\n"
-- "while waiting for an extension to be dialed by the calling channel. To\n"
-- "continue waiting for digits after this application has finished playing\n"
-- "files, the WaitExten application should be used. The 'langoverride' option\n"
-- "explicitly specifies which language to attempt to use for the requested sound\n"
-- "files. If a 'context' is specified, this is the dialplan context that this\n"
-- "application will use when exiting to a dialed extension."
-- " If one of the requested sound files does not exist, call processing will be\n"
-- "terminated.\n"
-- " Options:\n"
-- " s - Causes the playback of the message to be skipped\n"
-- " if the channel is not in the 'up' state (i.e. it\n"
-- " hasn't been answered yet). If this happens, the\n"
-- " application will return immediately.\n"
-- " n - Don't answer the channel before playing the files.\n"
-- " m - Only break if a digit hit matches a one digit\n"
-- " extension in the destination context.\n"
-- "This application sets the following channel variable upon completion:\n"
-- " BACKGROUNDSTATUS The status of the background attempt as a text string, one of\n"
-- " SUCCESS | FAILED\n"
-- "See Also: Playback (application) -- Play sound file(s) to the channel,\n"
-- " that cannot be interrupted\n"
-- },
--
-- { "Busy", pbx_builtin_busy,
-- "Indicate the Busy condition",
-- " Busy([timeout]): This application will indicate the busy condition to\n"
-- "the calling channel. If the optional timeout is specified, the calling channel\n"
-- "will be hung up after the specified number of seconds. Otherwise, this\n"
-- "application will wait until the calling channel hangs up.\n"
-- },
--
-- { "Congestion", pbx_builtin_congestion,
-- "Indicate the Congestion condition",
-- " Congestion([timeout]): This application will indicate the congestion\n"
-- "condition to the calling channel. If the optional timeout is specified, the\n"
-- "calling channel will be hung up after the specified number of seconds.\n"
-- "Otherwise, this application will wait until the calling channel hangs up.\n"
-- },
--
-- { "ExecIfTime", pbx_builtin_execiftime,
-- "Conditional application execution based on the current time",
-- " ExecIfTime(<times>,<weekdays>,<mdays>,<months>?appname[(appargs)]):\n"
-- "This application will execute the specified dialplan application, with optional\n"
-- "arguments, if the current time matches the given time specification.\n"
-- },
--
-- { "Goto", pbx_builtin_goto,
-- "Jump to a particular priority, extension, or context",
-- " Goto([[context,]extension,]priority): This application will set the current\n"
-- "context, extension, and priority in the channel structure. After it completes, the\n"
-- "pbx engine will continue dialplan execution at the specified location.\n"
-- "If no specific extension, or extension and context, are specified, then this\n"
-- "application will just set the specified priority of the current extension.\n"
-- " At least a priority is required as an argument, or the goto will return a -1,\n"
-- "and the channel and call will be terminated.\n"
-- " If the location that is put into the channel information is bogus, and asterisk cannot\n"
-- "find that location in the dialplan,\n"
-- "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
-- "extension in the current context. If that does not exist, it will try to execute the\n"
-- "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
-- "channel is hung up, and the execution of instructions on the channel is terminated.\n"
-- "What this means is that, for example, you specify a context that does not exist, then\n"
-- "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
-- },
--
-- { "GotoIf", pbx_builtin_gotoif,
-- "Conditional goto",
-- " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
-- "context, extension, and priority in the channel structure based on the evaluation of\n"
-- "the given condition. After this application completes, the\n"
-- "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
-- "The channel will continue at\n"
-- "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
-- "false. The labels are specified with the same syntax as used within the Goto\n"
-- "application. If the label chosen by the condition is omitted, no jump is\n"
-- "performed, and the execution passes to the next instruction.\n"
-- "If the target location is bogus, and does not exist, the execution engine will try \n"
-- "to find and execute the code in the 'i' (invalid)\n"
-- "extension in the current context. If that does not exist, it will try to execute the\n"
-- "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
-- "channel is hung up, and the execution of instructions on the channel is terminated.\n"
-- "Remember that this command can set the current context, and if the context specified\n"
-- "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
-- "the channel and call will both be terminated!\n"
-- },
--
-- { "GotoIfTime", pbx_builtin_gotoiftime,
-- "Conditional Goto based on the current time",
-- " GotoIfTime(<times>,<weekdays>,<mdays>,<months>?[labeliftrue]:[labeliffalse]):\n"
-- "This application will set the context, extension, and priority in the channel structure\n"
-- "based on the evaluation of the given time specification. After this application completes,\n"
-- "the pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
-- "If the current time is within the given time specification, the channel will continue at\n"
-- "'labeliftrue'. Otherwise the channel will continue at 'labeliffalse'. If the label chosen\n"
-- "by the condition is omitted, no jump is performed, and execution passes to the next\n"
-- "instruction. If the target jump location is bogus, the same actions would be taken as for\n"
-- "Goto.\n"
-- "Further information on the time specification can be found in examples\n"
-- "illustrating how to do time-based context includes in the dialplan.\n"
-- },
--
-- { "ImportVar", pbx_builtin_importvar,
-- "Import a variable from a channel into a new variable",
-- " ImportVar(newvar=channelname,variable): This application imports a variable\n"
-- "from the specified channel (as opposed to the current one) and stores it as\n"
-- "a variable in the current channel (the channel that is calling this\n"
-- "application). Variables created by this application have the same inheritance\n"
-- "properties as those created with the Set application. See the documentation for\n"
-- "Set for more information.\n"
-- },
--
-- { "Hangup", pbx_builtin_hangup,
-- "Hang up the calling channel",
-- " Hangup([causecode]): This application will hang up the calling channel.\n"
-- "If a causecode is given the channel's hangup cause will be set to the given\n"
-- "value.\n"
-- },
--
-- { "Incomplete", pbx_builtin_incomplete,
-- "returns AST_PBX_INCOMPLETE value",
-- " Incomplete([n]): Signals the PBX routines that the previous matched extension\n"
-- "is incomplete and that further input should be allowed before matching can\n"
-- "be considered to be complete. Can be used within a pattern match when\n"
-- "certain criteria warrants a longer match.\n"
-- " If the 'n' option is specified, then Incomplete will not attempt to answer\n"
-- "the channel first. Note that most channel types need to be in Answer state\n"
-- "in order to receive DTMF.\n"
-- },
--
-- { "NoOp", pbx_builtin_noop,
-- "Do Nothing (No Operation)",
-- " NoOp(): This application does nothing. However, it is useful for debugging\n"
-- "purposes. Any text that is provided as arguments to this application can be\n"
-- "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
-- "variables or functions without having any effect. Alternatively, see the\n"
-- "Verbose() application for finer grain control of output at custom verbose levels.\n"
-- },
--
-- { "Proceeding", pbx_builtin_proceeding,
-- "Indicate proceeding",
-- " Proceeding(): This application will request that a proceeding message\n"
-- "be provided to the calling channel.\n"
-- },
--
-- { "Progress", pbx_builtin_progress,
-- "Indicate progress",
-- " Progress(): This application will request that in-band progress information\n"
-- "be provided to the calling channel.\n"
-- },
--
-- { "RaiseException", pbx_builtin_raise_exception,
-- "Handle an exceptional condition",
-- " RaiseException(<reason>): This application will jump to the \"e\" extension\n"
-- "in the current context, setting the dialplan function EXCEPTION(). If the \"e\"\n"
-- "extension does not exist, the call will hangup.\n"
-- },
--
-- { "ResetCDR", pbx_builtin_resetcdr,
-- "Resets the Call Data Record",
-- " ResetCDR([options]): This application causes the Call Data Record to be\n"
-- "reset.\n"
-- " Options:\n"
-- " w -- Store the current CDR record before resetting it.\n"
-- " a -- Store any stacked records.\n"
-- " v -- Save CDR variables.\n"
-- " e -- Enable CDR only (negate effects of NoCDR).\n"
-- },
--
-- { "Ringing", pbx_builtin_ringing,
-- "Indicate ringing tone",
-- " Ringing(): This application will request that the channel indicate a ringing\n"
-- "tone to the user.\n"
-- },
--
-- { "SayAlpha", pbx_builtin_saycharacters,
-- "Say Alpha",
-- " SayAlpha(string): This application will play the sounds that correspond to\n"
-- "the letters of the given string.\n"
-- },
--
-- { "SayDigits", pbx_builtin_saydigits,
-- "Say Digits",
-- " SayDigits(digits): This application will play the sounds that correspond\n"
-- "to the digits of the given number. This will use the language that is currently\n"
-- "set for the channel. See the LANGUAGE function for more information on setting\n"
-- "the language for the channel.\n"
-- },
--
-- { "SayNumber", pbx_builtin_saynumber,
-- "Say Number",
-- " SayNumber(digits[,gender]): This application will play the sounds that\n"
-- "correspond to the given number. Optionally, a gender may be specified.\n"
-- "This will use the language that is currently set for the channel. See the\n"
-- "LANGUAGE function for more information on setting the language for the channel.\n"
-- },
--
-- { "SayPhonetic", pbx_builtin_sayphonetic,
-- "Say Phonetic",
-- " SayPhonetic(string): This application will play the sounds from the phonetic\n"
-- "alphabet that correspond to the letters in the given string.\n"
-- },
--
-- { "Set", pbx_builtin_setvar,
-- "Set channel variable or function value",
-- " Set(name=value)\n"
-- "This function can be used to set the value of channel variables or dialplan\n"
-- "functions. When setting variables, if the variable name is prefixed with _,\n"
-- "the variable will be inherited into channels created from the current\n"
-- "channel. If the variable name is prefixed with __, the variable will be\n"
-- "inherited into channels created from the current channel and all children\n"
-- "channels.\n"
-- "Compatibility note: If (and only if), in /etc/asterisk/asterisk.conf, you have a [compat]\n"
-- "category, and you have app_set = 1.6 under that, then the behavior of this\n"
-- "app changes, and does not strip surrounding quotes from the right hand side\n"
-- "as it did previously in 1.4. The app_set = 1.6 is only inserted if 'make samples'\n"
-- "is executed, or if users insert this by hand into the asterisk.conf file.\n"
-- "/nThe advantages of not stripping out quoting, and not caring about the\n"
-- "separator characters (comma and vertical bar) were sufficient to make these\n"
-- "changes in 1.6. Confusion about how many backslashes would be needed to properly\n"
-- "protect separators and quotes in various database access strings has been greatly\n"
-- "reduced by these changes.\n"
-- },
--
-- { "MSet", pbx_builtin_setvar_multiple,
-- "Set channel variable(s) or function value(s)",
-- " MSet(name1=value1,name2=value2,...)\n"
-- "This function can be used to set the value of channel variables or dialplan\n"
-- "functions. When setting variables, if the variable name is prefixed with _,\n"
-- "the variable will be inherited into channels created from the current\n"
-- "channel. If the variable name is prefixed with __, the variable will be\n"
-- "inherited into channels created from the current channel and all children\n"
-- "channels.\n\n"
-- "MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus\n"
-- "prone to doing things that you may not expect. For example, it strips surrounding\n"
-- "double-quotes from the right-hand side (value). If you need to put a separator\n"
-- "character (comma or vert-bar), you will need to escape them by inserting a backslash\n"
-- "before them. Avoid its use if possible.\n"
-- },
--
-- { "SetAMAFlags", pbx_builtin_setamaflags,
-- "Set the AMA Flags",
-- " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
-- " billing purposes.\n"
-- },
--
-- { "Wait", pbx_builtin_wait,
-- "Waits for some time",
-- " Wait(seconds): This application waits for a specified number of seconds.\n"
-- "Then, dialplan execution will continue at the next priority.\n"
-- " Note that the seconds can be passed with fractions of a second. For example,\n"
-- "'1.5' will ask the application to wait for 1.5 seconds.\n"
-- },
--
-- { "WaitExten", pbx_builtin_waitexten,
-- "Waits for an extension to be entered",
-- " WaitExten([seconds][,options]): This application waits for the user to enter\n"
-- "a new extension for a specified number of seconds.\n"
-- " Note that the seconds can be passed with fractions of a second. For example,\n"
-- "'1.5' will ask the application to wait for 1.5 seconds.\n"
-- " Options:\n"
-- " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
-- " Optionally, specify the class for music on hold within parenthesis.\n"
-- "See Also: Playback(application), Background(application).\n"
-- },
-+ { "Answer", pbx_builtin_answer },
-+ { "BackGround", pbx_builtin_background },
-+ { "Busy", pbx_builtin_busy },
-+ { "Congestion", pbx_builtin_congestion },
-+ { "ExecIfTime", pbx_builtin_execiftime },
-+ { "Goto", pbx_builtin_goto },
-+ { "GotoIf", pbx_builtin_gotoif },
-+ { "GotoIfTime", pbx_builtin_gotoiftime },
-+ { "ImportVar", pbx_builtin_importvar },
-+ { "Hangup", pbx_builtin_hangup },
-+ { "Incomplete", pbx_builtin_incomplete },
-+ { "NoOp", pbx_builtin_noop },
-+ { "Proceeding", pbx_builtin_proceeding },
-+ { "Progress", pbx_builtin_progress },
-+ { "RaiseException", pbx_builtin_raise_exception },
-+ { "ResetCDR", pbx_builtin_resetcdr },
-+ { "Ringing", pbx_builtin_ringing },
-+ { "SayAlpha", pbx_builtin_saycharacters },
-+ { "SayDigits", pbx_builtin_saydigits },
-+ { "SayNumber", pbx_builtin_saynumber },
-+ { "SayPhonetic", pbx_builtin_sayphonetic },
-+ { "Set", pbx_builtin_setvar },
-+ { "MSet", pbx_builtin_setvar_multiple },
-+ { "SetAMAFlags", pbx_builtin_setamaflags },
-+ { "Wait", pbx_builtin_wait },
-+ { "WaitExten", pbx_builtin_waitexten }
- };
-
- static struct ast_context *contexts;
-@@ -760,6 +1159,7 @@
- }
-
- static struct ast_context *find_context_locked(const char *context);
-+static struct ast_context *find_context(const char *context);
- int check_contexts(char *, int);
-
- int check_contexts(char *file, int line )
-@@ -1108,7 +1508,7 @@
- ast_str_set(&my_prefix, 0, "%s+ ", prefix);
-
- if (node->next_char)
-- log_match_char_tree(node->next_char, my_prefix->str);
-+ log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
-
- if (node->alt_char)
- log_match_char_tree(node->alt_char, prefix);
-@@ -1137,7 +1537,7 @@
- ast_str_set(&my_prefix, 0, "%s+ ", prefix);
-
- if (node->next_char)
-- cli_match_char_tree(node->next_char, my_prefix->str, fd);
-+ cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
-
- if (node->alt_char)
- cli_match_char_tree(node->alt_char, prefix, fd);
-@@ -1406,8 +1806,7 @@
- }
- lcurr = curr;
- }
-- if (!curr)
-- {
-+ if (!curr) {
- lcurr->alt_char = node;
- }
- }
-@@ -1469,7 +1868,8 @@
- int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
-
-
-- strncpy(extenbuf,e1->exten,sizeof(extenbuf));
-+ ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
-+
- if (e1->matchcid && l1 <= sizeof(extenbuf)) {
- strcat(extenbuf,"/");
- strcat(extenbuf,e1->cidmatch);
-@@ -1515,6 +1915,9 @@
- *s2++ = s3;
- }
- s1++; s1++;
-+ } else if (*s1 == '\0') {
-+ ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
-+ break;
- } else {
- *s2++ = *s1++;
- }
-@@ -1994,7 +2397,9 @@
- {
- struct ast_context *tmp = NULL;
- struct fake_context item;
-- strncpy(item.name,name,256);
-+
-+ ast_copy_string(item.name, name, sizeof(item.name));
-+
- ast_rdlock_contexts();
- if( contexts_table ) {
- tmp = ast_hashtab_lookup(contexts_table,&item);
-@@ -2066,8 +2471,10 @@
- tmp = bypass;
- else { /* look in contexts */
- struct fake_context item;
-- strncpy(item.name,context,256);
-- tmp = ast_hashtab_lookup(contexts_table,&item);
-+
-+ ast_copy_string(item.name, context, sizeof(item.name));
-+
-+ tmp = ast_hashtab_lookup(contexts_table, &item);
- #ifdef NOTNOW
- tmp = NULL;
- while ((tmp = ast_walk_contexts(tmp)) ) {
-@@ -2127,8 +2534,8 @@
- break;
- } else if (eval) {
- /* Substitute variables now */
-- pbx_substitute_variables_helper(chan, osw, tmpdata->str, tmpdata->len);
-- datap = tmpdata->str;
-+ pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
-+ datap = ast_str_buffer(tmpdata);
- } else {
- datap = osw;
- }
-@@ -2297,7 +2704,7 @@
- ast_log(LOG_WARNING, "Can't evaluate switch?!");
- continue;
- }
-- pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len);
-+ pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
- }
-
- /* equivalent of extension_match_core() at the switch level */
-@@ -2307,7 +2714,7 @@
- aswf = asw->matchmore;
- else /* action == E_MATCH */
- aswf = asw->exists;
-- datap = sw->eval ? tmpdata->str : sw->data;
-+ datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
- if (!aswf)
- res = 0;
- else {
-@@ -2605,15 +3012,6 @@
-
- static struct ast_custom_function exception_function = {
- .name = "EXCEPTION",
-- .synopsis = "Retrieve the details of the current dialplan exception",
-- .desc =
--"The following fields are available for retrieval:\n"
--" reason INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom\n"
--" value set by the RaiseException() application\n"
--" context The context executing when the exception occurred\n"
--" exten The extension executing when the exception occurred\n"
--" priority The numeric priority executing when the exception occurred\n",
-- .syntax = "EXCEPTION(<field>)",
- .read = acf_exception_read,
- };
-
-@@ -2660,10 +3058,10 @@
- {
- struct ast_custom_function *acf;
- /* Maximum number of characters added by terminal coloring is 22 */
-- char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
-- char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
-- char stxtitle[40], *syntax = NULL;
-- int synopsis_size, description_size, syntax_size;
-+ char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
-+ char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
-+ char stxtitle[40], *syntax = NULL, *arguments = NULL;
-+ int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
- char *ret = NULL;
- int which = 0;
- int wordlen;
-@@ -2690,50 +3088,76 @@
- return ret;
- }
-
-- if (a->argc < 4)
-+ if (a->argc < 4) {
- return CLI_SHOWUSAGE;
-+ }
-
- if (!(acf = ast_custom_function_find(a->argv[3]))) {
- ast_cli(a->fd, "No function by that name registered.\n");
- return CLI_FAILURE;
-+ }
-
-+ syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ if (!(syntax = ast_malloc(syntax_size))) {
-+ ast_cli(a->fd, "Memory allocation failure!\n");
-+ return CLI_FAILURE;
- }
-
-- if (acf->synopsis)
-- synopsis_size = strlen(acf->synopsis) + 23;
-- else
-- synopsis_size = strlen("Not available") + 23;
-- synopsis = alloca(synopsis_size);
-+ snprintf(info, sizeof(info), "\n -= Info about function '%s' =- \n\n", acf->name);
-+ term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
-+ term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
-+#ifdef AST_XML_DOCS
-+ if (acf->docsrc == AST_XML_DOC) {
-+ arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
-+ synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
-+ description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
-+ seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
-+ } else
-+#endif
-+ {
-+ synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ synopsis = ast_malloc(synopsis_size);
-
-- if (acf->desc)
-- description_size = strlen(acf->desc) + 23;
-- else
-- description_size = strlen("Not available") + 23;
-- description = alloca(description_size);
-+ description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ description = ast_malloc(description_size);
-
-- if (acf->syntax)
-- syntax_size = strlen(acf->syntax) + 23;
-- else
-- syntax_size = strlen("Not available") + 23;
-- syntax = alloca(syntax_size);
-+ arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ arguments = ast_malloc(arguments_size);
-
-- snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
-- term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
-- term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
-- term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-- term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
-- term_color(syntax,
-- acf->syntax ? acf->syntax : "Not available",
-- COLOR_CYAN, 0, syntax_size);
-- term_color(synopsis,
-- acf->synopsis ? acf->synopsis : "Not available",
-- COLOR_CYAN, 0, synopsis_size);
-- term_color(description,
-- acf->desc ? acf->desc : "Not available",
-- COLOR_CYAN, 0, description_size);
-+ seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ seealso = ast_malloc(seealso_size);
-
-- ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
-+ /* check allocated memory. */
-+ if (!synopsis || !description || !arguments || !seealso) {
-+ ast_free(synopsis);
-+ ast_free(description);
-+ ast_free(arguments);
-+ ast_free(seealso);
-+ ast_free(syntax);
-+ return CLI_FAILURE;
-+ }
-
-+ term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
-+ term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
-+ term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
-+ term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
-+ }
-+
-+ ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
-+ infotitle, syntitle, synopsis, destitle, description,
-+ stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
-+
-+ ast_free(arguments);
-+ ast_free(synopsis);
-+ ast_free(description);
-+ ast_free(seealso);
-+ ast_free(syntax);
-+
- return CLI_SUCCESS;
- }
-
-@@ -2759,23 +3183,86 @@
- return -1;
-
- AST_RWLIST_WRLOCK(&acf_root);
-- if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
-+ if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
-+ if (cur->docsrc == AST_XML_DOC) {
-+ ast_string_field_free_memory(acf);
-+ }
- ast_verb(2, "Unregistered custom function %s\n", cur->name);
-+ }
- AST_RWLIST_UNLOCK(&acf_root);
-
- return cur ? 0 : -1;
- }
-
-+/*! \internal
-+ * \brief Retrieve the XML documentation of a specified ast_custom_function,
-+ * and populate ast_custom_function string fields.
-+ * \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
-+ * but with a function 'name'.
-+ * \retval -1 On error.
-+ * \retval 0 On succes.
-+ */
-+static int acf_retrieve_docs(struct ast_custom_function *acf)
-+{
-+#ifdef AST_XML_DOCS
-+ char *tmpxml;
-+
-+ /* Let's try to find it in the Documentation XML */
-+ if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
-+ return 0;
-+ }
-+
-+ if (ast_string_field_init(acf, 128)) {
-+ return -1;
-+ }
-+
-+ /* load synopsis */
-+ tmpxml = ast_xmldoc_build_synopsis("function", acf->name);
-+ ast_string_field_set(acf, synopsis, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load description */
-+ tmpxml = ast_xmldoc_build_description("function", acf->name);
-+ ast_string_field_set(acf, desc, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load syntax */
-+ tmpxml = ast_xmldoc_build_syntax("function", acf->name);
-+ ast_string_field_set(acf, syntax, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load arguments */
-+ tmpxml = ast_xmldoc_build_arguments("function", acf->name);
-+ ast_string_field_set(acf, arguments, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load seealso */
-+ tmpxml = ast_xmldoc_build_seealso("function", acf->name);
-+ ast_string_field_set(acf, seealso, tmpxml);
-+ ast_free(tmpxml);
-+
-+ acf->docsrc = AST_XML_DOC;
-+#endif
-+
-+ return 0;
-+}
-+
- int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
- {
- struct ast_custom_function *cur;
- char tmps[80];
-
-- if (!acf)
-+ if (!acf) {
- return -1;
-+ }
-
- acf->mod = mod;
-+ acf->docsrc = AST_STATIC_DOC;
-
-+ if (acf_retrieve_docs(acf)) {
-+ return -1;
-+ }
-+
- AST_RWLIST_WRLOCK(&acf_root);
-
- AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
-@@ -2794,8 +3281,10 @@
- }
- }
- AST_RWLIST_TRAVERSE_SAFE_END;
-- if (!cur)
-+
-+ if (!cur) {
- AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
-+ }
-
- AST_RWLIST_UNLOCK(&acf_root);
-
-@@ -2871,11 +3360,11 @@
- return -1;
- }
-
--static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
-+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
- {
- /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
- char *cp4;
-- const char *tmp, *whereweare;
-+ const char *tmp, *whereweare, *orig_cp2 = cp2;
- int length, offset, offset2, isfunction;
- char *workspace = NULL;
- char *ltmp = NULL, *var = NULL;
-@@ -2955,10 +3444,11 @@
-
- /* Substitute if necessary */
- if (needsub) {
-+ size_t used;
- if (!ltmp)
- ltmp = alloca(VAR_BUF_SIZE);
-
-- pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
-+ pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
- vars = ltmp;
- } else {
- vars = var;
-@@ -3042,10 +3532,11 @@
-
- /* Substitute if necessary */
- if (needsub) {
-+ size_t used;
- if (!ltmp)
- ltmp = alloca(VAR_BUF_SIZE);
-
-- pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
-+ pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
- vars = ltmp;
- } else {
- vars = var;
-@@ -3061,16 +3552,19 @@
- }
- }
- }
-+ *used = cp2 - orig_cp2;
- }
-
- void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
- {
-- pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
-+ size_t used;
-+ pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count, &used);
- }
-
- void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
- {
-- pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
-+ size_t used;
-+ pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
- }
-
- static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
-@@ -3233,7 +3727,7 @@
- /*! \brief Check state of extension by using hints */
- static int ast_extension_state2(struct ast_exten *e)
- {
-- char hint[AST_MAX_EXTENSION] = "";
-+ struct ast_str *hint = ast_str_thread_get(&extensionstate_buf, 16);
- char *cur, *rest;
- struct ast_devstate_aggregate agg;
- enum ast_device_state state;
-@@ -3243,9 +3737,9 @@
-
- ast_devstate_aggregate_init(&agg);
-
-- ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
-+ ast_str_set(&hint, 0, "%s", ast_get_extension_app(e));
-
-- rest = hint; /* One or more devices separated with a & character */
-+ rest = ast_str_buffer(hint); /* One or more devices separated with a & character */
-
- while ( (cur = strsep(&rest, "&")) )
- ast_devstate_aggregate_add(&agg, ast_device_state(cur));
-@@ -3481,20 +3975,18 @@
- return ret;
- }
-
--/*! \brief Add hint to hint list, check initial extension state */
--static int ast_add_hint(struct ast_exten *e)
-+
-+/*! \brief Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already! */
-+static int ast_add_hint_nolock(struct ast_exten *e)
- {
- struct ast_hint *hint;
-
- if (!e)
- return -1;
-
-- AST_RWLIST_WRLOCK(&hints);
--
- /* Search if hint exists, do nothing */
- AST_RWLIST_TRAVERSE(&hints, hint, list) {
- if (hint->exten == e) {
-- AST_RWLIST_UNLOCK(&hints);
- ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
- return -1;
- }
-@@ -3503,7 +3995,6 @@
- ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
-
- if (!(hint = ast_calloc(1, sizeof(*hint)))) {
-- AST_RWLIST_UNLOCK(&hints);
- return -1;
- }
- /* Initialize and insert new item at the top */
-@@ -3511,10 +4002,21 @@
- hint->laststate = ast_extension_state2(e);
- AST_RWLIST_INSERT_HEAD(&hints, hint, list);
-
-- AST_RWLIST_UNLOCK(&hints);
- return 0;
- }
-
-+/*! \brief Add hint to hint list, check initial extension state */
-+static int ast_add_hint(struct ast_exten *e)
-+{
-+ int ret;
-+
-+ AST_RWLIST_WRLOCK(&hints);
-+ ret = ast_add_hint_nolock(e);
-+ AST_RWLIST_UNLOCK(&hints);
-+
-+ return ret;
-+}
-+
- /*! \brief Change hint for an extension */
- static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
- {
-@@ -3628,6 +4130,7 @@
-
- /*!
- * \brief collect digits from the channel into the buffer.
-+ * \param waittime is in milliseconds
- * \retval 0 on timeout or done.
- * \retval -1 on error.
- */
-@@ -4078,6 +4581,22 @@
-
- /*!
- * \brief lookup for a context with a given name,
-+ * \retval found context or NULL if not found.
-+*/
-+static struct ast_context *find_context(const char *context)
-+{
-+ struct ast_context *c = NULL;
-+ struct fake_context item;
-+
-+ ast_copy_string(item.name, context, sizeof(item.name));
-+
-+ c = ast_hashtab_lookup(contexts_table,&item);
-+
-+ return c;
-+}
-+
-+/*!
-+ * \brief lookup for a context with a given name,
- * \retval with conlock held if found.
- * \retval NULL if not found.
- */
-@@ -4150,6 +4669,7 @@
- else
- con->includes = i->next;
- /* free include and return */
-+ ast_destroy_timing(&(i->timing));
- ast_free(i);
- ret = 0;
- break;
-@@ -4419,7 +4939,8 @@
-
- ast_rdlock_contexts();
-
-- strncpy(item.name,context,256);
-+ ast_copy_string(item.name, context, sizeof(item.name));
-+
- c = ast_hashtab_lookup(contexts_table,&item);
- if (c)
- ret = 0;
-@@ -4457,7 +4978,8 @@
-
- ast_rdlock_contexts();
-
-- strncpy(item.name, context, 256);
-+ ast_copy_string(item.name, context, sizeof(item.name));
-+
- c = ast_hashtab_lookup(contexts_table,&item);
- if (c)
- ret = 0;
-@@ -4486,6 +5008,9 @@
- struct ast_app *tmp, *cur = NULL;
- char tmps[80];
- int length, res;
-+#ifdef AST_XML_DOCS
-+ char *tmpxml;
-+#endif
-
- AST_RWLIST_WRLOCK(&apps);
- AST_RWLIST_TRAVERSE(&apps, tmp, list) {
-@@ -4504,10 +5029,50 @@
- return -1;
- }
-
-+ if (ast_string_field_init(tmp, 128)) {
-+ ast_free(tmp);
-+ return -1;
-+ }
-+
-+#ifdef AST_XML_DOCS
-+ /* Try to lookup the docs in our XML documentation database */
-+ if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
-+ /* load synopsis */
-+ tmpxml = ast_xmldoc_build_synopsis("application", app);
-+ ast_string_field_set(tmp, synopsis, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load description */
-+ tmpxml = ast_xmldoc_build_description("application", app);
-+ ast_string_field_set(tmp, description, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load syntax */
-+ tmpxml = ast_xmldoc_build_syntax("application", app);
-+ ast_string_field_set(tmp, syntax, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load arguments */
-+ tmpxml = ast_xmldoc_build_arguments("application", app);
-+ ast_string_field_set(tmp, arguments, tmpxml);
-+ ast_free(tmpxml);
-+
-+ /* load seealso */
-+ tmpxml = ast_xmldoc_build_seealso("application", app);
-+ ast_string_field_set(tmp, seealso, tmpxml);
-+ ast_free(tmpxml);
-+ tmp->docsrc = AST_XML_DOC;
-+ } else {
-+#endif
-+ ast_string_field_set(tmp, synopsis, synopsis);
-+ ast_string_field_set(tmp, description, description);
-+ tmp->docsrc = AST_STATIC_DOC;
-+#ifdef AST_XML_DOCS
-+ }
-+#endif
-+
- strcpy(tmp->name, app);
- tmp->execute = execute;
-- tmp->synopsis = synopsis;
-- tmp->description = description;
- tmp->module = mod;
-
- /* Store in alphabetical order */
-@@ -4561,6 +5126,78 @@
- * Help for CLI commands ...
- */
-
-+static void print_app_docs(struct ast_app *aa, int fd)
-+{
-+ /* Maximum number of characters added by terminal coloring is 22 */
-+ char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40];
-+ char seealsotitle[40];
-+ char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL;
-+ char *seealso = NULL;
-+ int syntax_size, synopsis_size, description_size, arguments_size, seealso_size;
-+
-+ snprintf(info, sizeof(info), "\n -= Info about application '%s' =- \n\n", aa->name);
-+ term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
-+
-+ term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
-+ term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
-+
-+#ifdef AST_XML_DOCS
-+ if (aa->docsrc == AST_XML_DOC) {
-+ description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
-+ arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
-+ synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
-+ seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
-+
-+ if (!synopsis || !description || !arguments || !seealso) {
-+ goto return_cleanup;
-+ }
-+ } else
-+#endif
-+ {
-+ synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ synopsis = ast_malloc(synopsis_size);
-+
-+ description_size = strlen(S_OR(aa->description, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ description = ast_malloc(description_size);
-+
-+ arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ arguments = ast_malloc(arguments_size);
-+
-+ seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ seealso = ast_malloc(seealso_size);
-+
-+ if (!synopsis || !description || !arguments || !seealso) {
-+ goto return_cleanup;
-+ }
-+
-+ term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
-+ term_color(description, S_OR(aa->description, "Not available"), COLOR_CYAN, 0, description_size);
-+ term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
-+ term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
-+ }
-+
-+ /* Handle the syntax the same for both XML and raw docs */
-+ syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ if (!(syntax = ast_malloc(syntax_size))) {
-+ goto return_cleanup;
-+ }
-+ term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
-+
-+ ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
-+ infotitle, syntitle, synopsis, destitle, description,
-+ stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
-+
-+return_cleanup:
-+ ast_free(description);
-+ ast_free(arguments);
-+ ast_free(synopsis);
-+ ast_free(seealso);
-+ ast_free(syntax);
-+}
-+
- /*
- * \brief 'show application' CLI command implementation function...
- */
-@@ -4599,58 +5236,22 @@
- return ret;
- }
-
-- if (a->argc < 4)
-+ if (a->argc < 4) {
- return CLI_SHOWUSAGE;
-+ }
-
-- /* ... go through all applications ... */
- AST_RWLIST_RDLOCK(&apps);
- AST_RWLIST_TRAVERSE(&apps, aa, list) {
-- /* ... compare this application name with all arguments given
-- * to 'show application' command ... */
-+ /* Check for each app that was supplied as an argument */
- for (app = 3; app < a->argc; app++) {
-- if (!strcasecmp(aa->name, a->argv[app])) {
-- /* Maximum number of characters added by terminal coloring is 22 */
-- char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
-- char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
-- int synopsis_size, description_size;
-+ if (strcasecmp(aa->name, a->argv[app])) {
-+ continue;
-+ }
-
-- no_registered_app = 0;
-+ /* We found it! */
-+ no_registered_app = 0;
-
-- if (aa->synopsis)
-- synopsis_size = strlen(aa->synopsis) + 23;
-- else
-- synopsis_size = strlen("Not available") + 23;
-- synopsis = alloca(synopsis_size);
--
-- if (aa->description)
-- description_size = strlen(aa->description) + 23;
-- else
-- description_size = strlen("Not available") + 23;
-- description = alloca(description_size);
--
-- if (synopsis && description) {
-- snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", aa->name);
-- term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
-- term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-- term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
-- term_color(synopsis,
-- aa->synopsis ? aa->synopsis : "Not available",
-- COLOR_CYAN, 0, synopsis_size);
-- term_color(description,
-- aa->description ? aa->description : "Not available",
-- COLOR_CYAN, 0, description_size);
--
-- ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
-- } else {
-- /* ... one of our applications, show info ...*/
-- ast_cli(a->fd,"\n -= Info about application '%s' =- \n\n"
-- "[Synopsis]\n %s\n\n"
-- "[Description]\n%s\n",
-- aa->name,
-- aa->synopsis ? aa->synopsis : "Not available",
-- aa->description ? aa->description : "Not available");
-- }
-- }
-+ print_app_docs(aa, a->fd);
- }
- }
- AST_RWLIST_UNLOCK(&apps);
-@@ -5104,7 +5705,7 @@
-
- /* if we print something in context, make an empty line */
- if (context_info_printed)
-- ast_cli(fd, "\r\n");
-+ ast_cli(fd, "\n");
- }
- ast_unlock_contexts();
-
-@@ -5116,15 +5717,15 @@
- struct ast_context *c = NULL;
- int res = 0, old_total_exten = dpc->total_exten;
-
-- ast_cli(fd,"\r\n In-mem exten Trie for Fast Extension Pattern Matching:\r\n\r\n");
-+ ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
-
-- ast_cli(fd,"\r\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\r\n");
-- ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\r\n");
-- ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\r\n");
-- ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\r\n");
-- ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string> \r\n");
-- ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\r\n");
-- ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\r\n\r\n");
-+ ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
-+ ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
-+ ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
-+ ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
-+ ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
-+ ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
-+ ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
- ast_rdlock_contexts();
-
- /* walk all contexts ... */
-@@ -5150,14 +5751,14 @@
- {
- cli_match_char_tree(c->pattern_tree, " ", fd);
- } else {
-- ast_cli(fd,"\r\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\r\n\r\n");
-+ ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
- }
-
- ast_unlock_context(c);
-
- /* if we print something in context, make an empty line */
- if (context_info_printed)
-- ast_cli(fd, "\r\n");
-+ ast_cli(fd, "\n");
- }
- ast_unlock_contexts();
-
-@@ -5523,15 +6124,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_show_globals_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
--
-- char *res = handle_show_globals(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "core show globals";
-- return res;
--}
--
- /*! \brief CLI support for listing chanvar's variables in a parseable way */
- static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
-@@ -5558,8 +6150,8 @@
- }
-
- pbx_builtin_serialize_variables(chan, &vars);
-- if (vars->str) {
-- ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
-+ if (ast_str_strlen(vars)) {
-+ ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
- }
- ast_channel_unlock(chan);
- return CLI_SUCCESS;
-@@ -5587,14 +6179,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_set_global_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_set_global(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "core set global";
-- return res;
--}
--
- static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct ast_channel *chan;
-@@ -5630,14 +6214,6 @@
- return CLI_SUCCESS;
- }
-
--static char *handle_set_chanvar_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- char *res = handle_set_chanvar(e, cmd, a);
-- if (cmd == CLI_INIT)
-- e->command = "core set chanvar";
-- return res;
--}
--
- static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int oldval = 0;
-@@ -5695,14 +6271,6 @@
- }
-
- /*
-- * Deprecated CLI commands
-- */
--
--static struct ast_cli_entry cli_show_globals_deprecated = AST_CLI_DEFINE(handle_show_globals_deprecated, "Show global dialplan variables.");
--static struct ast_cli_entry cli_set_chanvar_deprecated = AST_CLI_DEFINE(handle_set_chanvar_deprecated, "Set a channel variable.");
--static struct ast_cli_entry cli_set_global_deprecated = AST_CLI_DEFINE(handle_set_global_deprecated, "Set global dialplan variable.");
--
--/*
- * CLI entries for upper commands ...
- */
- static struct ast_cli_entry pbx_cli[] = {
-@@ -5711,12 +6279,12 @@
- AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
- AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
- AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
-- AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables", .deprecate_cmd = &cli_show_globals_deprecated),
-+ AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
- AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
- AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
- AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
-- AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable", .deprecate_cmd = &cli_set_global_deprecated),
-- AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable", .deprecate_cmd = &cli_set_chanvar_deprecated),
-+ AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
-+ AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
- AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
- AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
- AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
-@@ -5752,6 +6320,11 @@
- unreference_cached_app(tmp);
- AST_RWLIST_REMOVE_CURRENT(list);
- ast_verb(2, "Unregistered application '%s'\n", tmp->name);
-+#ifdef AST_XML_DOCS
-+ if (tmp->docsrc == AST_XML_DOC) {
-+ ast_string_field_free_memory(tmp);
-+ }
-+#endif
- ast_free(tmp);
- break;
- }
-@@ -5777,7 +6350,7 @@
- 0);
- }
-
-- strncpy(search.name,name,sizeof(search.name));
-+ ast_copy_string(search.name, name, sizeof(search.name));
- if (!extcontexts) {
- ast_rdlock_contexts();
- local_contexts = &contexts;
-@@ -5994,13 +6567,13 @@
- }
- ast_hashtab_end_traversal(iter);
- wrlock_ver = ast_wrlock_contexts_version();
--
-+
- ast_unlock_contexts(); /* this feels real retarded, but you must do
- what you must do If this isn't done, the following
- wrlock is a guraranteed deadlock */
- ast_wrlock_contexts();
- if (ast_wrlock_contexts_version() > wrlock_ver+1) {
-- ast_log(LOG_WARNING,"Something changed the contexts in the middle of merging contexts!\n");
-+ ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
- }
-
- AST_RWLIST_WRLOCK(&hints);
-@@ -6041,7 +6614,7 @@
- * individual extension, because the pattern will no longer match first.
- */
- if (exten && exten->exten[0] == '_') {
-- ast_add_extension(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
-+ ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
- 0, exten->app, ast_strdup(exten->data), ast_free_ptr, registrar);
- /* rwlocks are not recursive locks */
- exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
-@@ -6125,15 +6698,20 @@
- {
- int i;
-
-- if (names) {
-+ if (names && *s > '9') {
- for (i = 0; names[i]; i++) {
-- if (!strcasecmp(s, names[i]))
-- return i+1;
-+ if (!strcasecmp(s, names[i])) {
-+ return i;
-+ }
- }
-- } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
-- return i;
- }
-- return 0; /* error return */
-+
-+ /* Allow months and weekdays to be specified as numbers, as well */
-+ if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
-+ /* What the array offset would have been: "1" would be at offset 0 */
-+ return i - 1;
-+ }
-+ return -1; /* error return */
- }
-
- /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
-@@ -6141,131 +6719,104 @@
- */
- static unsigned get_range(char *src, int max, char *const names[], const char *msg)
- {
-- int s, e; /* start and ending position */
-+ int start, end; /* start and ending position */
- unsigned int mask = 0;
-+ char *part;
-
- /* Check for whole range */
- if (ast_strlen_zero(src) || !strcmp(src, "*")) {
-- s = 0;
-- e = max - 1;
-- } else {
-+ return (1 << max) - 1;
-+ }
-+
-+ while ((part = strsep(&src, "&"))) {
- /* Get start and ending position */
-- char *c = strchr(src, '-');
-- if (c)
-- *c++ = '\0';
-+ char *endpart = strchr(part, '-');
-+ if (endpart) {
-+ *endpart++ = '\0';
-+ }
- /* Find the start */
-- s = lookup_name(src, names, max);
-- if (!s) {
-- ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
-- return 0;
-+ if ((start = lookup_name(part, names, max)) < 0) {
-+ ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
-+ continue;
- }
-- s--;
-- if (c) { /* find end of range */
-- e = lookup_name(c, names, max);
-- if (!e) {
-- ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
-- return 0;
-+ if (endpart) { /* find end of range */
-+ if ((end = lookup_name(endpart, names, max)) < 0) {
-+ ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
-+ continue;
- }
-- e--;
-- } else
-- e = s;
-- }
-- /* Fill the mask. Remember that ranges are cyclic */
-- mask = 1 << e; /* initialize with last element */
-- while (s != e) {
-- if (s >= max) {
-- s = 0;
-- mask |= (1 << s);
- } else {
-- mask |= (1 << s);
-- s++;
-+ end = start;
- }
-+ /* Fill the mask. Remember that ranges are cyclic */
-+ mask |= (1 << end); /* initialize with last element */
-+ while (start != end) {
-+ if (start >= max) {
-+ start = 0;
-+ }
-+ mask |= (1 << start);
-+ start++;
-+ }
- }
- return mask;
- }
-
--/*! \brief store a bitmask of valid times, one bit each 2 minute */
-+/*! \brief store a bitmask of valid times, one bit each 1 minute */
- static void get_timerange(struct ast_timing *i, char *times)
- {
-- char *e;
-+ char *endpart, *part;
- int x;
-- int s1, s2;
-- int e1, e2;
-- /* int cth, ctm; */
-+ int st_h, st_m;
-+ int endh, endm;
-+ int minute_start, minute_end;
-
- /* start disabling all times, fill the fields with 0's, as they may contain garbage */
- memset(i->minmask, 0, sizeof(i->minmask));
-
-- /* 2-minutes per bit, since the mask has only 32 bits :( */
-+ /* 1-minute per bit */
- /* Star is all times */
- if (ast_strlen_zero(times) || !strcmp(times, "*")) {
-- for (x = 0; x < 24; x++)
-+ /* 48, because each hour takes 2 integers; 30 bits each */
-+ for (x = 0; x < 48; x++) {
- i->minmask[x] = 0x3fffffff; /* 30 bits */
-+ }
- return;
- }
- /* Otherwise expect a range */
-- e = strchr(times, '-');
-- if (!e) {
-- ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
-- return;
-- }
-- *e++ = '\0';
-- /* XXX why skip non digits ? */
-- while (*e && !isdigit(*e))
-- e++;
-- if (!*e) {
-- ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
-- return;
-- }
-- if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
-- ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
-- return;
-- }
-- if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
-- ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
-- return;
-- }
-- /* XXX this needs to be optimized */
--#if 1
-- s1 = s1 * 30 + s2/2;
-- if ((s1 < 0) || (s1 >= 24*30)) {
-- ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
-- return;
-- }
-- e1 = e1 * 30 + e2/2;
-- if ((e1 < 0) || (e1 >= 24*30)) {
-- ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
-- return;
-- }
-- /* Go through the time and enable each appropriate bit */
-- for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
-- i->minmask[x/30] |= (1 << (x % 30));
-- }
-- /* Do the last one */
-- i->minmask[x/30] |= (1 << (x % 30));
--#else
-- for (cth = 0; cth < 24; cth++) {
-- /* Initialize masks to blank */
-- i->minmask[cth] = 0;
-- for (ctm = 0; ctm < 30; ctm++) {
-- if (
-- /* First hour with more than one hour */
-- (((cth == s1) && (ctm >= s2)) &&
-- ((cth < e1)))
-- /* Only one hour */
-- || (((cth == s1) && (ctm >= s2)) &&
-- ((cth == e1) && (ctm <= e2)))
-- /* In between first and last hours (more than 2 hours) */
-- || ((cth > s1) &&
-- (cth < e1))
-- /* Last hour with more than one hour */
-- || ((cth > s1) &&
-- ((cth == e1) && (ctm <= e2)))
-- )
-- i->minmask[cth] |= (1 << (ctm / 2));
-+ while ((part = strsep(&times, "&"))) {
-+ if (!(endpart = strchr(part, '-'))) {
-+ if (sscanf(part, "%d:%d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
-+ ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
-+ continue;
-+ }
-+ i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
-+ continue;
- }
-+ *endpart++ = '\0';
-+ /* why skip non digits? Mostly to skip spaces */
-+ while (*endpart && !isdigit(*endpart)) {
-+ endpart++;
-+ }
-+ if (!*endpart) {
-+ ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
-+ continue;
-+ }
-+ if (sscanf(part, "%d:%d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
-+ ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
-+ continue;
-+ }
-+ if (sscanf(endpart, "%d:%d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
-+ ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
-+ continue;
-+ }
-+ minute_start = st_h * 60 + st_m;
-+ minute_end = endh * 60 + endm;
-+ /* Go through the time and enable each appropriate bit */
-+ for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
-+ i->minmask[x / 30] |= (1 << (x % 30));
-+ }
-+ /* Do the last one */
-+ i->minmask[x / 30] |= (1 << (x % 30));
- }
--#endif
- /* All done */
- return;
- }
-@@ -6301,15 +6852,32 @@
-
- int ast_build_timing(struct ast_timing *i, const char *info_in)
- {
-- char info_save[256];
-- char *info;
-+ char *info_save, *info;
-+ int j, num_fields, last_sep = -1;
-
- /* Check for empty just in case */
-- if (ast_strlen_zero(info_in))
-+ if (ast_strlen_zero(info_in)) {
- return 0;
-+ }
-+
- /* make a copy just in case we were passed a static string */
-- ast_copy_string(info_save, info_in, sizeof(info_save));
-- info = info_save;
-+ info_save = info = ast_strdupa(info_in);
-+
-+ /* count the number of fields in the timespec */
-+ for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
-+ if (info[j] == ',') {
-+ last_sep = j;
-+ num_fields++;
-+ }
-+ }
-+
-+ /* save the timezone, if it is specified */
-+ if (num_fields == 5) {
-+ i->timezone = ast_strdup(info + last_sep + 1);
-+ } else {
-+ i->timezone = NULL;
-+ }
-+
- /* Assume everything except time */
- i->monthmask = 0xfff; /* 12 bits */
- i->daymask = 0x7fffffffU; /* 31 bits */
-@@ -6330,7 +6898,7 @@
- struct ast_tm tm;
- struct timeval now = ast_tvnow();
-
-- ast_localtime(&now, &tm, NULL);
-+ ast_localtime(&now, &tm, i->timezone);
-
- /* If it's not the right month, return */
- if (!(i->monthmask & (1 << tm.tm_mon)))
-@@ -6353,13 +6921,21 @@
-
- /* Now the tough part, we calculate if it fits
- in the right time based on min/hour */
-- if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
-+ if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
- return 0;
-
- /* If we got this far, then we're good */
- return 1;
- }
-
-+int ast_destroy_timing(struct ast_timing *i)
-+{
-+ if (i->timezone) {
-+ ast_free(i->timezone);
-+ i->timezone = NULL;
-+ }
-+ return 0;
-+}
- /*
- * errno values
- * ENOMEM - out of memory
-@@ -6394,7 +6970,7 @@
- /* Strip off timing info, and process if it is there */
- if ( (c = strchr(p, ',')) ) {
- *c++ = '\0';
-- new_include->hastime = ast_build_timing(&(new_include->timing), c);
-+ new_include->hastime = ast_build_timing(&(new_include->timing), c);
- }
- new_include->next = NULL;
- new_include->registrar = registrar;
-@@ -6404,6 +6980,7 @@
- /* ... go to last include and check if context is already included too... */
- for (i = con->includes; i; i = i->next) {
- if (!strcasecmp(i->name, new_include->name)) {
-+ ast_destroy_timing(&(new_include->timing));
- ast_free(new_include);
- ast_unlock_context(con);
- errno = EEXIST;
-@@ -6616,6 +7193,25 @@
- }
-
- /*
-+ * ast_add_extension_nolock -- use only in situations where the conlock is already held
-+ * ENOENT - no existence of context
-+ *
-+ */
-+static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
-+ int priority, const char *label, const char *callerid,
-+ const char *application, void *data, void (*datad)(void *), const char *registrar)
-+{
-+ int ret = -1;
-+ struct ast_context *c = find_context(context);
-+
-+ if (c) {
-+ ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
-+ application, data, datad, registrar, 0, 0);
-+ }
-+
-+ return ret;
-+}
-+/*
- * EBUSY - can't lock
- * ENOENT - no existence of context
- *
-@@ -6729,18 +7325,19 @@
- static int ext_strncpy(char *dst, const char *src, int len)
- {
- int count = 0;
-+ int insquares = 0;
-
- while (*src && (count < len - 1)) {
-- switch (*src) {
-- case ' ':
-- /* otherwise exten => [a-b],1,... doesn't work */
-- /* case '-': */
-- /* Ignore */
-- break;
-- default:
-- *dst = *src;
-- dst++;
-+ if (*src == '[') {
-+ insquares = 1;
-+ } else if (*src == ']') {
-+ insquares = 0;
-+ } else if (*src == ' ' && !insquares) {
-+ src++;
-+ continue;
- }
-+ *dst = *src;
-+ dst++;
- src++;
- count++;
- }
-@@ -6757,6 +7354,17 @@
- static int add_pri(struct ast_context *con, struct ast_exten *tmp,
- struct ast_exten *el, struct ast_exten *e, int replace)
- {
-+ return add_pri_lockopt(con, tmp, el, e, replace, 1);
-+}
-+
-+/*!
-+ * \brief add the extension in the priority chain.
-+ * \retval 0 on success.
-+ * \retval -1 on failure.
-+*/
-+static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
-+ struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
-+{
- struct ast_exten *ep;
- struct ast_exten *eh=e;
-
-@@ -6891,8 +7499,13 @@
- e->next = NULL; /* e is no more at the head, so e->next must be reset */
- }
- /* And immediately return success. */
-- if (tmp->priority == PRIORITY_HINT)
-- ast_add_hint(tmp);
-+ if (tmp->priority == PRIORITY_HINT) {
-+ if (lockhints) {
-+ ast_add_hint(tmp);
-+ } else {
-+ ast_add_hint_nolock(tmp);
-+ }
-+ }
- }
- return 0;
- }
-@@ -6927,6 +7540,19 @@
- const char *application, void *data, void (*datad)(void *),
- const char *registrar)
- {
-+ return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
-+}
-+
-+/*! \brief
-+ * Does all the work of ast_add_extension2, but adds two args, to determine if
-+ * context and hint locking should be done. In merge_and_delete, we need to do
-+ * this without locking, as the locks are already held.
-+ */
-+static int ast_add_extension2_lockopt(struct ast_context *con,
-+ int replace, const char *extension, int priority, const char *label, const char *callerid,
-+ const char *application, void *data, void (*datad)(void *),
-+ const char *registrar, int lockconts, int lockhints)
-+{
- /*
- * Sort extensions (or patterns) according to the rules indicated above.
- * These are implemented by the function ext_cmp()).
-@@ -6999,11 +7625,13 @@
- tmp->datad = datad;
- tmp->registrar = registrar;
-
-- ast_wrlock_context(con);
-+ if (lockconts) {
-+ ast_wrlock_context(con);
-+ }
-
- if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
- an extension, and the trie exists, then we need to incrementally add this pattern to it. */
-- strncpy(dummy_name,extension,sizeof(dummy_name));
-+ ast_copy_string(dummy_name, extension, sizeof(dummy_name));
- dummy_exten.exten = dummy_name;
- dummy_exten.matchcid = 0;
- dummy_exten.cidmatch = 0;
-@@ -7032,7 +7660,9 @@
- }
- if (e && res == 0) { /* exact match, insert in the pri chain */
- res = add_pri(con, tmp, el, e, replace);
-- ast_unlock_context(con);
-+ if (lockconts) {
-+ ast_unlock_context(con);
-+ }
- if (res < 0) {
- errno = EEXIST; /* XXX do we care ? */
- return 0; /* XXX should we return -1 maybe ? */
-@@ -7089,9 +7719,16 @@
-
- }
- ast_hashtab_insert_safe(con->root_table, tmp);
-- ast_unlock_context(con);
-- if (tmp->priority == PRIORITY_HINT)
-- ast_add_hint(tmp);
-+ if (lockconts) {
-+ ast_unlock_context(con);
-+ }
-+ if (tmp->priority == PRIORITY_HINT) {
-+ if (lockhints) {
-+ ast_add_hint(tmp);
-+ } else {
-+ ast_add_hint_nolock(tmp);
-+ }
-+ }
- }
- if (option_debug) {
- if (tmp->matchcid) {
-@@ -7777,15 +8414,33 @@
- static int pbx_builtin_answer(struct ast_channel *chan, void *data)
- {
- int delay = 0;
-+ int answer_cdr = 1;
-+ char *parse;
-+ AST_DECLARE_APP_ARGS(args,
-+ AST_APP_ARG(delay);
-+ AST_APP_ARG(answer_cdr);
-+ );
-
-- if ((chan->_state != AST_STATE_UP) && !ast_strlen_zero(data))
-+ if (ast_strlen_zero(data)) {
-+ return __ast_answer(chan, 0, 1);
-+ }
-+
-+ parse = ast_strdupa(data);
-+
-+ AST_STANDARD_APP_ARGS(args, parse);
-+
-+ if (!ast_strlen_zero(args.delay) && (chan->_state != AST_STATE_UP))
- delay = atoi(data);
-
- if (delay < 0) {
- delay = 0;
- }
-
-- return __ast_answer(chan, delay);
-+ if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
-+ answer_cdr = 0;
-+ }
-+
-+ return __ast_answer(chan, delay, answer_cdr);
- }
-
- static int pbx_builtin_incomplete(struct ast_channel *chan, void *data)
-@@ -7802,7 +8457,7 @@
- if (ast_check_hangup(chan)) {
- return -1;
- } else if (chan->_state != AST_STATE_UP && answer) {
-- __ast_answer(chan, 0);
-+ __ast_answer(chan, 0, 1);
- }
-
- return AST_PBX_INCOMPLETE;
-@@ -7882,7 +8537,7 @@
- struct ast_timing timing;
-
- if (ast_strlen_zero(data)) {
-- ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>?'labeliftrue':'labeliffalse'\n");
-+ ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
- return -1;
- }
-
-@@ -7898,6 +8553,7 @@
- branch = branch1;
- else
- branch = branch2;
-+ ast_destroy_timing(&timing);
-
- if (ast_strlen_zero(branch)) {
- ast_debug(1, "Not taking any branch\n");
-@@ -7915,7 +8571,7 @@
- char *s, *appname;
- struct ast_timing timing;
- struct ast_app *app;
-- static const char *usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>?<appname>[(<appargs>)]";
-+ static const char *usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
-
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "%s\n", usage);
-@@ -7932,11 +8588,15 @@
-
- if (!ast_build_timing(&timing, s)) {
- ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
-+ ast_destroy_timing(&timing);
- return -1;
- }
-
-- if (!ast_check_timing(&timing)) /* outside the valid time window, just return */
-+ if (!ast_check_timing(&timing)) { /* outside the valid time window, just return */
-+ ast_destroy_timing(&timing);
- return 0;
-+ }
-+ ast_destroy_timing(&timing);
-
- /* now split appname(appargs) */
- if ((s = strchr(appname, '('))) {
-@@ -8002,11 +8662,13 @@
- } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
- ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
- } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
-- const struct tone_zone_sound *ts = ast_get_indication_tone(chan->zone, "dial");
-- if (ts)
-+ struct ast_tone_zone_sound *ts = ast_get_indication_tone(chan->zone, "dial");
-+ if (ts) {
- ast_playtones_start(chan, 0, ts->data, 0);
-- else
-+ ts = ast_tone_zone_sound_unref(ts);
-+ } else {
- ast_tonepair_start(chan, 350, 440, 0, 0);
-+ }
- }
- /* Wait for "n" seconds */
- if (args.timeout && (s = atof(args.timeout)) > 0)
-@@ -8144,8 +8806,7 @@
- if (!chan)
- return 0;
-
-- (*buf)->used = 0;
-- (*buf)->str[0] = '\0';
-+ ast_str_reset(*buf);
-
- ast_channel_lock(chan);
-
-@@ -8528,22 +9189,22 @@
- }
-
- ast_verb(1, "Registering builtin applications:\n");
-- ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
- __ast_custom_function_register(&exception_function, NULL);
-
- /* Register builtin applications */
-- for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
-+ for (x = 0; x < ARRAY_LEN(builtins); x++) {
- ast_verb(1, "[%s]\n", builtins[x].name);
-- if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) {
-+ if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
- ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
- return -1;
- }
- }
--
-+
- /* Register manager application */
- ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
-
-- if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE, device_state_cb, NULL,
-+ if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
- AST_EVENT_IE_END))) {
- return -1;
- }
-Index: main/strings.c
-===================================================================
---- a/main/strings.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/main/strings.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,155 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Tilghman Lesher <tlesher@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+* the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief String manipulation API
-+ *
-+ * \author Tilghman Lesher <tilghman@digium.com>
-+ */
-+
-+/*** MAKEOPTS
-+<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes" remove_on_change=".lastclean">
-+ <member name="DEBUG_OPAQUE" displayname="Change ast_str internals to detect improper usage">
-+ <defaultenabled>yes</defaultenabled>
-+ </member>
-+</category>
-+ ***/
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/strings.h"
-+#include "asterisk/pbx.h"
-+
-+/*!
-+ * core handler for dynamic strings.
-+ * This is not meant to be called directly, but rather through the
-+ * various wrapper macros
-+ * ast_str_set(...)
-+ * ast_str_append(...)
-+ * ast_str_set_va(...)
-+ * ast_str_append_va(...)
-+ */
-+
-+int __ast_str_helper(struct ast_str **buf, size_t max_len,
-+ int append, const char *fmt, va_list ap)
-+{
-+ int res, need;
-+ int offset = (append && (*buf)->__AST_STR_LEN) ? (*buf)->__AST_STR_USED : 0;
-+ va_list aq;
-+
-+ do {
-+ if (max_len < 0) {
-+ max_len = (*buf)->__AST_STR_LEN; /* don't exceed the allocated space */
-+ }
-+ /*
-+ * Ask vsnprintf how much space we need. Remember that vsnprintf
-+ * does not count the final '\0' so we must add 1.
-+ */
-+ va_copy(aq, ap);
-+ res = vsnprintf((*buf)->__AST_STR_STR + offset, (*buf)->__AST_STR_LEN - offset, fmt, aq);
-+
-+ need = res + offset + 1;
-+ /*
-+ * If there is not enough space and we are below the max length,
-+ * reallocate the buffer and return a message telling to retry.
-+ */
-+ if (need > (*buf)->__AST_STR_LEN && (max_len == 0 || (*buf)->__AST_STR_LEN < max_len) ) {
-+ if (max_len && max_len < need) { /* truncate as needed */
-+ need = max_len;
-+ } else if (max_len == 0) { /* if unbounded, give more room for next time */
-+ need += 16 + need / 4;
-+ }
-+ if (0) { /* debugging */
-+ ast_verbose("extend from %d to %d\n", (int)(*buf)->__AST_STR_LEN, need);
-+ }
-+ if (ast_str_make_space(buf, need)) {
-+ ast_verbose("failed to extend from %d to %d\n", (int)(*buf)->__AST_STR_LEN, need);
-+ return AST_DYNSTR_BUILD_FAILED;
-+ }
-+ (*buf)->__AST_STR_STR[offset] = '\0'; /* Truncate the partial write. */
-+
-+ /* Restart va_copy before calling vsnprintf() again. */
-+ va_end(aq);
-+ continue;
-+ }
-+ break;
-+ } while (1);
-+ /* update space used, keep in mind the truncation */
-+ (*buf)->__AST_STR_USED = (res + offset > (*buf)->__AST_STR_LEN) ? (*buf)->__AST_STR_LEN : res + offset;
-+
-+ return res;
-+}
-+
-+void ast_str_substitute_variables(struct ast_str **buf, size_t maxlen, struct ast_channel *chan, const char *template)
-+{
-+ int first = 1;
-+ do {
-+ ast_str_make_space(buf, maxlen ? maxlen :
-+ (first ? strlen(template) * 2 : (*buf)->__AST_STR_LEN * 2));
-+ pbx_substitute_variables_helper_full(chan, NULL, template, (*buf)->__AST_STR_STR, (*buf)->__AST_STR_LEN - 1, &((*buf)->__AST_STR_USED));
-+ first = 0;
-+ } while (maxlen == 0 && (*buf)->__AST_STR_LEN - 5 < (*buf)->__AST_STR_USED);
-+}
-+
-+char *__ast_str_helper2(struct ast_str **buf, size_t maxlen, const char *src, size_t maxsrc, int append, int escapecommas)
-+{
-+ int dynamic = 0;
-+ char *ptr = append ? &((*buf)->__AST_STR_STR[(*buf)->__AST_STR_USED]) : (*buf)->__AST_STR_STR;
-+
-+ if (maxlen < 1) {
-+ if (maxlen == 0) {
-+ dynamic = 1;
-+ }
-+ maxlen = (*buf)->__AST_STR_LEN;
-+ }
-+
-+ while (*src && maxsrc && maxlen && (!escapecommas || (maxlen - 1))) {
-+ if (escapecommas && (*src == '\\' || *src == ',')) {
-+ *ptr++ = '\\';
-+ maxlen--;
-+ (*buf)->__AST_STR_USED++;
-+ }
-+ *ptr++ = *src++;
-+ maxsrc--;
-+ maxlen--;
-+ (*buf)->__AST_STR_USED++;
-+
-+ if (dynamic && (!maxlen || (escapecommas && !(maxlen - 1)))) {
-+ char *oldbase = (*buf)->__AST_STR_STR;
-+ size_t old = (*buf)->__AST_STR_LEN;
-+ if (ast_str_make_space(buf, (*buf)->__AST_STR_LEN * 2)) {
-+ /* If the buffer can't be extended, end it. */
-+ break;
-+ }
-+ /* What we extended the buffer by */
-+ maxlen = old;
-+
-+ ptr += (*buf)->__AST_STR_STR - oldbase;
-+ }
-+ }
-+ if (__builtin_expect(!(maxsrc && maxlen), 0)) {
-+ ptr--;
-+ }
-+ *ptr = '\0';
-+ (*buf)->__AST_STR_USED--;
-+ return (*buf)->__AST_STR_STR;
-+}
-+
-
-Property changes on: main/strings.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: main/dnsmgr.c
-===================================================================
---- a/main/dnsmgr.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/dnsmgr.c (.../team/group/issue14292) (revision 178988)
-@@ -57,7 +57,7 @@
- /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */
- char *service;
- /*! Set to 1 if the entry changes */
-- int changed:1;
-+ unsigned int changed:1;
- ast_mutex_t lock;
- AST_RWLIST_ENTRY(ast_dnsmgr_entry) list;
- /*! just 1 here, but we use calloc to allocate the correct size */
-@@ -374,8 +374,10 @@
- int was_enabled;
- int res = -1;
-
-- if ((config = ast_config_load2("dnsmgr.conf", "dnsmgr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
-+ config = ast_config_load2("dnsmgr.conf", "dnsmgr", config_flags);
-+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) {
- return 0;
-+ }
-
- /* ensure that no refresh cycles run while the reload is in progress */
- ast_mutex_lock(&refresh_lock);
-Index: main/tcptls.c
-===================================================================
---- a/main/tcptls.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/tcptls.c (.../team/group/issue14292) (revision 178988)
-@@ -97,7 +97,7 @@
- return read(tcptls_session->fd, buf, count);
- }
-
--HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count)
-+HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count)
- {
- if (tcptls_session->fd == -1) {
- ast_log(LOG_ERROR, "server_write called with an fd of -1\n");
-@@ -135,8 +135,10 @@
- /*
- * open a FILE * as appropriate.
- */
-- if (!tcptls_session->parent->tls_cfg)
-+ if (!tcptls_session->parent->tls_cfg) {
- tcptls_session->f = fdopen(tcptls_session->fd, "w+");
-+ setvbuf(tcptls_session->f, NULL, _IONBF, 0);
-+ }
- #ifdef DO_SSL
- else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) {
- SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
-@@ -436,13 +438,13 @@
-
- /* If there's no new server, stop here */
- if (desc->local_address.sin_family == 0) {
-+ ast_debug(2, "Server disabled: %s\n", desc->name);
- return;
- }
-
- desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (desc->accept_fd < 0) {
-- ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
-- desc->name, strerror(errno));
-+ ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
- return;
- }
-
-@@ -485,4 +487,5 @@
- if (desc->accept_fd != -1)
- close(desc->accept_fd);
- desc->accept_fd = -1;
-+ ast_debug(2, "Stopped server :: %s\n", desc->name);
- }
-Index: main/file.c
-===================================================================
---- a/main/file.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/file.c (.../team/group/issue14292) (revision 178988)
-@@ -292,9 +292,7 @@
- if (f->fmt->format < AST_FORMAT_AUDIO_MASK) {
- f->owner->stream = NULL;
- AST_SCHED_DEL(f->owner->sched, f->owner->streamid);
--#ifdef HAVE_DAHDI
- ast_settimeout(f->owner, 0, NULL, NULL);
--#endif
- } else {
- f->owner->vstream = NULL;
- AST_SCHED_DEL(f->owner->sched, f->owner->vstreamid);
-@@ -719,9 +717,14 @@
- ao2_ref(s, +1);
- }
- if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
-- if (fr)
-+ if (fr) {
- ast_log(LOG_WARNING, "Failed to write frame\n");
-+ ast_frfree(fr);
-+ }
- goto return_failure;
-+ }
-+ if (fr) {
-+ ast_frfree(fr);
- }
- }
- if (whennext != s->lasttimeout) {
-@@ -1356,6 +1359,6 @@
-
- int ast_file_init(void)
- {
-- ast_cli_register_multiple(cli_file, sizeof(cli_file) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_file, ARRAY_LEN(cli_file));
- return 0;
- }
-Index: main/callerid.c
-===================================================================
---- a/main/callerid.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/callerid.c (.../team/group/issue14292) (revision 178988)
-@@ -922,8 +922,10 @@
- return bytes;
- }
-
--/*! \brief Clean up phone string
-- * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
-+/*!
-+ * \brief Clean up phone string
-+ * \details
-+ * Remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
- * Basically, remove anything that could be invalid in a pattern.
- */
- void ast_shrink_phone_number(char *n)
-@@ -958,11 +960,13 @@
- n[y] = '\0';
- }
-
--/*! \brief Checks if phone number consists of valid characters
-- \param exten String that needs to be checked
-- \param valid Valid characters in string
-- \return 1 if valid string, 0 if string contains invalid characters
--*/
-+/*!
-+ * \brief Checks if phone number consists of valid characters
-+ * \param exten String that needs to be checked
-+ * \param valid Valid characters in string
-+ * \retval 1 if valid string
-+ * \retval 0 if string contains invalid characters
-+ */
- static int ast_is_valid_string(const char *exten, const char *valid)
- {
- int x;
-@@ -975,34 +979,37 @@
- return 1;
- }
-
--/*! \brief checks if string consists only of digits and * \# and +
-- \return 1 if string is valid AST phone number
-- \return 0 if not
-+/*!
-+ * \brief checks if string consists only of digits and * \# and +
-+ * \retval 1 if string is valid AST phone number
-+ * \retval 0 if not
- */
- int ast_isphonenumber(const char *n)
- {
- return ast_is_valid_string(n, "0123456789*#+");
- }
-
--/*! \brief checks if string consists only of digits and ( ) - * \# and +
-- Pre-qualifies the string for ast_shrink_phone_number()
-- \return 1 if string is valid AST shrinkable phone number
-- \return 0 if not
-+/*!
-+ * \brief checks if string consists only of digits and ( ) - * \# and +
-+ * \details
-+ * Pre-qualifies the string for ast_shrink_phone_number()
-+ * \retval 1 if string is valid AST shrinkable phone number
-+ * \retval 0 if not
- */
- int ast_is_shrinkable_phonenumber(const char *exten)
- {
- return ast_is_valid_string(exten, "0123456789*#+()-.");
- }
-
--/*! \brief parse string for caller id information
-- \return always returns 0, as the code always returns something.
-- XXX note that 'name' is not parsed consistently e.g. we have
--
-- input location name
-- " foo bar " <123> 123 ' foo bar ' (with spaces around)
-- " foo bar " NULL 'foo bar' (without spaces around)
-- The parsing of leading and trailing space/quotes should be more consistent.
--*/
-+/*!
-+ * \brief Destructively parse instr for caller id information
-+ * \return always returns 0, as the code always returns something.
-+ * \note XXX 'name' is not parsed consistently e.g. we have
-+ * input location name
-+ * " foo bar " <123> 123 ' foo bar ' (with spaces around)
-+ * " foo bar " NULL 'foo bar' (without spaces around)
-+ * The parsing of leading and trailing space/quotes should be more consistent.
-+ */
- int ast_callerid_parse(char *instr, char **name, char **location)
- {
- char *ns, *ne, *ls, *le;
-@@ -1103,68 +1110,275 @@
- return 0;
- }
-
--/*! \brief Translation table for Caller ID Presentation settings */
--static struct {
-- int val;
-+struct ast_value_translation {
-+ int value;
- const char *name;
- const char *description;
--} pres_types[] = {
-- { AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened"},
-- { AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen"},
-- { AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen"},
-- { AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number"},
-- { AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened"},
-- { AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen"},
-- { AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen"},
-- { AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number"},
-- { AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable", "Number Unavailable"},
- };
-
--/*! \brief Convert caller ID text code to value
-- used in config file parsing
-- \param data text string
-- \return value AST_PRES_ from callerid.h
--*/
-+/*! \brief Translation table for Caller ID Presentation settings */
-+static const struct ast_value_translation pres_types[] = {
-+/* *INDENT-OFF* */
-+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened" },
-+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen" },
-+ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen" },
-+ { AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number" },
-+
-+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened" },
-+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen" },
-+ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen" },
-+ { AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number" },
-+
-+ { AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER, "unavailable", "Number Unavailable" }, /* Default name to value conversion. */
-+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED, "unavailable", "Number Unavailable" },
-+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN, "unavailable", "Number Unavailable" },
-+ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN, "unavailable", "Number Unavailable" },
-+/* *INDENT-ON* */
-+};
-+
-+/*!
-+ * \brief Convert caller ID text code to value (used in config file parsing)
-+ * \param data text string from config file
-+ * \retval value AST_PRES_ from callerid.h
-+ * \retval -1 if not in table
-+ */
- int ast_parse_caller_presentation(const char *data)
- {
-- int i;
-+ int index;
-
-- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
-- if (!strcasecmp(pres_types[i].name, data))
-- return pres_types[i].val;
-- }
-+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
-+ if (!strcasecmp(pres_types[index].name, data)) {
-+ return pres_types[index].value;
-+ }
-+ } /* end for */
-
- return -1;
--}
-+} /* end ast_parse_caller_presentation() */
-
--/*! \brief Convert caller ID pres value to explanatory string
-- \param data value (see callerid.h AST_PRES_ )
-- \return string for human presentation
--*/
-+/*!
-+ * \brief Convert caller ID pres value to explanatory string
-+ * \param data AST_PRES_ value from callerid.h
-+ * \return string for human presentation
-+ */
- const char *ast_describe_caller_presentation(int data)
- {
-- int i;
-+ int index;
-
-- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
-- if (pres_types[i].val == data)
-- return pres_types[i].description;
-- }
-+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
-+ if (pres_types[index].value == data) {
-+ return pres_types[index].description;
-+ }
-+ } /* end for */
-
- return "unknown";
--}
-+} /* end ast_describe_caller_presentation() */
-
--/*! \brief Convert caller ID pres value to text code
-- \param data text string
-- \return string for config file
--*/
-+/*!
-+ * \brief Convert caller ID pres value to text code
-+ * \param data AST_PRES_ value from callerid.h
-+ * \return string for config file
-+ */
- const char *ast_named_caller_presentation(int data)
- {
-- int i;
-+ int index;
-
-- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
-- if (pres_types[i].val == data)
-- return pres_types[i].name;
-- }
-+ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
-+ if (pres_types[index].value == data) {
-+ return pres_types[index].name;
-+ }
-+ } /* end for */
-
- return "unknown";
--}
-+} /* end ast_named_caller_presentation() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+
-+
-+
-+
-+/*! \brief Translation table for redirecting reason settings */
-+static const struct ast_value_translation redirecting_reason_types[] = {
-+/* *INDENT-OFF* */
-+ { AST_REDIRECTING_REASON_UNKNOWN, "unknown", "Unknown" },
-+ { AST_REDIRECTING_REASON_USER_BUSY, "cfb", "Call Forwarding Busy" },
-+ { AST_REDIRECTING_REASON_NO_ANSWER, "cfnr", "Call Forwarding No Reply" },
-+ { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable", "Callee is Unavailable" },
-+ { AST_REDIRECTING_REASON_UNCONDITIONAL, "cfu", "Call Forwarding Unconditional" },
-+ { AST_REDIRECTING_REASON_TIME_OF_DAY, "time_of_day", "Time of Day" },
-+ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "dnd", "Do Not Disturb" },
-+ { AST_REDIRECTING_REASON_DEFLECTION, "deflection", "Call Deflection" },
-+ { AST_REDIRECTING_REASON_FOLLOW_ME, "follow_me", "Follow Me" },
-+ { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
-+ { AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
-+ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
-+/* *INDENT-ON* */
-+};
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Convert redirecting reason text code to value (used in config file parsing)
-+ *
-+ * \param data text string from config file
-+ *
-+ * \retval Q931_REDIRECTING_REASON from callerid.h
-+ * \retval -1 if not in table
-+ */
-+int ast_redirecting_reason_parse(const char *data)
-+{
-+ int index;
-+
-+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
-+ if (!strcasecmp(redirecting_reason_types[index].name, data)) {
-+ return redirecting_reason_types[index].value;
-+ }
-+ } /* end for */
-+
-+ return -1;
-+} /* end ast_redirecting_reason_parse() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Convert redirecting reason value to explanatory string
-+ *
-+ * \param data Q931_REDIRECTING_REASON from callerid.h
-+ *
-+ * \return string for human presentation
-+ */
-+const char *ast_redirecting_reason_describe(int data)
-+{
-+ int index;
-+
-+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
-+ if (redirecting_reason_types[index].value == data) {
-+ return redirecting_reason_types[index].description;
-+ }
-+ } /* end for */
-+
-+ return "not-known";
-+} /* end ast_redirecting_reason_describe() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Convert redirecting reason value to text code
-+ *
-+ * \param data Q931_REDIRECTING_REASON from callerid.h
-+ *
-+ * \return string for config file
-+ */
-+const char *ast_redirecting_reason_name(int data)
-+{
-+ int index;
-+
-+ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
-+ if (redirecting_reason_types[index].value == data) {
-+ return redirecting_reason_types[index].name;
-+ }
-+ } /* end for */
-+
-+ return "not-known";
-+} /* end ast_redirecting_reason_name() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+
-+
-+
-+
-+/*! \brief Translation table for connected line update source settings */
-+static const struct ast_value_translation connected_line_source_types[] = {
-+/* *INDENT-OFF* */
-+ { AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, "unknown", "Unknown" },
-+ { AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, "answer", "Normal Call Answering" },
-+ { AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION, "diversion", "Call Diversion (Deprecated, use REDIRECTING)" },
-+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer_active", "Call Transfer(Active)" },
-+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer", "Call Transfer(Active)" },/* Old name must come after new name. */
-+ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, "transfer_alerting", "Call Transfer(Alerting)" }
-+/* *INDENT-ON* */
-+};
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Convert connected line update source text code to value (used in config file parsing)
-+ *
-+ * \param data text string from config file
-+ *
-+ * \retval AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
-+ * \retval -1 if not in table
-+ */
-+int ast_connected_line_source_parse(const char *data)
-+{
-+ int index;
-+
-+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
-+ if (!strcasecmp(connected_line_source_types[index].name, data)) {
-+ return connected_line_source_types[index].value;
-+ }
-+ } /* end for */
-+
-+ return -1;
-+} /* end ast_connected_line_source_parse() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Convert connected line update source value to explanatory string
-+ *
-+ * \param data AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
-+ *
-+ * \return string for human presentation
-+ */
-+const char *ast_connected_line_source_describe(int data)
-+{
-+ int index;
-+
-+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
-+ if (connected_line_source_types[index].value == data) {
-+ return connected_line_source_types[index].description;
-+ }
-+ } /* end for */
-+
-+ return "not-known";
-+} /* end ast_connected_line_source_describe() */
-+
-+
-+
-+
-+/* ******************************************************************* */
-+/*!
-+ * \brief Convert connected line update source value to text code
-+ *
-+ * \param data AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
-+ *
-+ * \return string for config file
-+ */
-+const char *ast_connected_line_source_name(int data)
-+{
-+ int index;
-+
-+ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
-+ if (connected_line_source_types[index].value == data) {
-+ return connected_line_source_types[index].name;
-+ }
-+ } /* end for */
-+
-+ return "not-known";
-+} /* end ast_connected_line_source_name() */
-Index: main/audiohook.c
-===================================================================
---- a/main/audiohook.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/audiohook.c (.../team/group/issue14292) (revision 178988)
-@@ -354,7 +354,7 @@
- */
- int ast_audiohook_detach(struct ast_audiohook *audiohook)
- {
-- if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
-+ if (audiohook->status == AST_AUDIOHOOK_STATUS_NEW || audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
- return 0;
-
- audiohook->status = AST_AUDIOHOOK_STATUS_SHUTDOWN;
-Index: main/xmldoc.c
-===================================================================
---- a/main/xmldoc.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/main/xmldoc.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,1856 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief XML Documentation API
-+ *
-+ * \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
-+ */
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/_private.h"
-+#include "asterisk/paths.h"
-+#include "asterisk/linkedlists.h"
-+#include "asterisk/strings.h"
-+#include "asterisk/config.h"
-+#include "asterisk/term.h"
-+#include "asterisk/xmldoc.h"
-+
-+#ifdef AST_XML_DOCS
-+
-+/*! \brief Default documentation language. */
-+static const char default_documentation_language[] = "en_US";
-+
-+/*! \brief Number of columns to print when showing the XML documentation with a
-+ * 'core show application/function *' CLI command. Used in text wrapping.*/
-+static const int xmldoc_text_columns = 74;
-+
-+/*! \brief This is a value that we will use to let the wrapping mechanism move the cursor
-+ * backward and forward xmldoc_max_diff positions before cutting the middle of a
-+ * word, trying to find a space or a \n. */
-+static const int xmldoc_max_diff = 5;
-+
-+/*! \brief XML documentation language. */
-+static char documentation_language[6];
-+
-+/*! \brief XML documentation tree */
-+struct documentation_tree {
-+ char *filename; /*!< XML document filename. */
-+ struct ast_xml_doc *doc; /*!< Open document pointer. */
-+ AST_RWLIST_ENTRY(documentation_tree) entry;
-+};
-+
-+static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname);
-+
-+/*!
-+ * \brief Container of documentation trees
-+ *
-+ * \note A RWLIST is a sufficient container type to use here for now.
-+ * However, some changes will need to be made to implement ref counting
-+ * if reload support is added in the future.
-+ */
-+static AST_RWLIST_HEAD_STATIC(xmldoc_tree, documentation_tree);
-+
-+static const struct strcolorized_tags {
-+ const char *init; /*!< Replace initial tag with this string. */
-+ const char *end; /*!< Replace end tag with this string. */
-+ const int colorfg; /*!< Foreground color. */
-+ const char *inittag; /*!< Initial tag description. */
-+ const char *endtag; /*!< Ending tag description. */
-+} colorized_tags[] = {
-+ { "<", ">", COLOR_GREEN, "<replaceable>", "</replaceable>" },
-+ { "\'", "\'", COLOR_BLUE, "<literal>", "</literal>" },
-+ { "*", "*", COLOR_RED, "<emphasis>", "</emphasis>" },
-+ { "\"", "\"", COLOR_YELLOW, "<filename>", "</filename>" },
-+ { "\"", "\"", COLOR_CYAN, "<directory>", "</directory>" },
-+ { "${", "}", COLOR_GREEN, "<variable>", "</variable>" },
-+ { "", "", COLOR_BLUE, "<value>", "</value>" },
-+ { "", "", COLOR_BLUE, "<enum>", "</enum>" },
-+ { "\'", "\'", COLOR_GRAY, "<astcli>", "</astcli>" },
-+
-+ /* Special tags */
-+ { "", "", COLOR_YELLOW, "<note>", "</note>" },
-+ { "", "", COLOR_RED, "<warning>", "</warning>" }
-+};
-+
-+static const struct strspecial_tags {
-+ const char *tagname; /*!< Special tag name. */
-+ const char *init; /*!< Print this at the beginning. */
-+ const char *end; /*!< Print this at the end. */
-+} special_tags[] = {
-+ { "note", "<note>NOTE:</note> ", "" },
-+ { "warning", "<warning>WARNING!!!:</warning> ", "" }
-+};
-+
-+/*! \internal
-+ * \brief Calculate the space in bytes used by a format string
-+ * that will be passed to a sprintf function.
-+ * \param postbr The format string to use to calculate the length.
-+ * \retval The postbr length.
-+ */
-+static int xmldoc_postbrlen(const char *postbr)
-+{
-+ int postbrreallen = 0, i;
-+ size_t postbrlen;
-+
-+ if (!postbr) {
-+ return 0;
-+ }
-+ postbrlen = strlen(postbr);
-+ for (i = 0; i < postbrlen; i++) {
-+ if (postbr[i] == '\t') {
-+ postbrreallen += 8 - (postbrreallen % 8);
-+ } else {
-+ postbrreallen++;
-+ }
-+ }
-+ return postbrreallen;
-+}
-+
-+/*! \internal
-+ * \brief Setup postbr to be used while wrapping the text.
-+ * Add to postbr array all the spaces and tabs at the beginning of text.
-+ * \param postbr output array.
-+ * \param len text array length.
-+ * \param text Text with format string before the actual string.
-+ */
-+static void xmldoc_setpostbr(char *postbr, size_t len, const char *text)
-+{
-+ int c, postbrlen = 0;
-+
-+ if (!text) {
-+ return;
-+ }
-+
-+ for (c = 0; c < len; c++) {
-+ if (text[c] == '\t' || text[c] == ' ') {
-+ postbr[postbrlen++] = text[c];
-+ } else {
-+ break;
-+ }
-+ }
-+ postbr[postbrlen] = '\0';
-+}
-+
-+/*! \internal
-+ * \brief Try to find a space or a break in text starting at currentpost
-+ * and moving at most maxdiff positions.
-+ * Helper for xmldoc_string_wrap().
-+ * \param text Input string where it will search.
-+ * \param currentpos Current position within text.
-+ * \param maxdiff Not move more than maxdiff inside text.
-+ * \retval 1 if a space or break is found inside text while moving.
-+ * \retval 0 if no space or break is found.
-+ */
-+static int xmldoc_wait_nextspace(const char *text, int currentpos, int maxdiff)
-+{
-+ int i, textlen;
-+
-+ if (!text) {
-+ return 0;
-+ }
-+
-+ textlen = strlen(text);
-+ for (i = currentpos; i < textlen; i++) {
-+ if (text[i] == ESC) {
-+ /* Move to the end of the escape sequence */
-+ while (i < textlen && text[i] != 'm') {
-+ i++;
-+ }
-+ } else if (text[i] == ' ' || text[i] == '\n') {
-+ /* Found the next space or linefeed */
-+ return 1;
-+ } else if (i - currentpos > maxdiff) {
-+ /* We have looked the max distance and didn't find it */
-+ return 0;
-+ }
-+ }
-+
-+ /* Reached the end and did not find it */
-+
-+ return 0;
-+}
-+
-+/*! \internal
-+ * \brief Helper function for xmldoc_string_wrap().
-+ * Try to found a space or a break inside text moving backward
-+ * not more than maxdiff positions.
-+ * \param text The input string where to search for a space.
-+ * \param currentpos The current cursor position.
-+ * \param maxdiff The max number of positions to move within text.
-+ * \retval 0 If no space is found (Notice that text[currentpos] is not a space or a break)
-+ * \retval > 0 If a space or a break is found, and the result is the position relative to
-+ * currentpos.
-+ */
-+static int xmldoc_foundspace_backward(const char *text, int currentpos, int maxdiff)
-+{
-+ int i;
-+
-+ for (i = currentpos; i > 0; i--) {
-+ if (text[i] == ' ' || text[i] == '\n') {
-+ return (currentpos - i);
-+ } else if (text[i] == 'm' && (text[i - 1] >= '0' || text[i - 1] <= '9')) {
-+ /* give up, we found the end of a possible ESC sequence. */
-+ return 0;
-+ } else if (currentpos - i > maxdiff) {
-+ /* give up, we can't move anymore. */
-+ return 0;
-+ }
-+ }
-+
-+ /* we found the beginning of the text */
-+
-+ return 0;
-+}
-+
-+/*! \internal
-+ * \brief Justify a text to a number of columns.
-+ * \param text Input text to be justified.
-+ * \param columns Number of columns to preserve in the text.
-+ * \param maxdiff Try to not cut a word when goinf down.
-+ * \retval NULL on error.
-+ * \retval The wrapped text.
-+ */
-+static char *xmldoc_string_wrap(const char *text, int columns, int maxdiff)
-+{
-+ struct ast_str *tmp;
-+ char *ret, postbr[160];
-+ int count = 1, i, backspace, needtobreak = 0, colmax, textlen;
-+
-+ /* sanity check */
-+ if (!text || columns <= 0 || maxdiff < 0) {
-+ ast_log(LOG_WARNING, "Passing wrong arguments while trying to wrap the text\n");
-+ return NULL;
-+ }
-+
-+ tmp = ast_str_create(strlen(text) * 3);
-+
-+ if (!tmp) {
-+ return NULL;
-+ }
-+
-+ /* Check for blanks and tabs and put them in postbr. */
-+ xmldoc_setpostbr(postbr, sizeof(postbr), text);
-+ colmax = columns - xmldoc_postbrlen(postbr);
-+
-+ textlen = strlen(text);
-+ for (i = 0; i < textlen; i++) {
-+ if (needtobreak || !(count % colmax)) {
-+ if (text[i] == ' ') {
-+ ast_str_append(&tmp, 0, "\n%s", postbr);
-+ needtobreak = 0;
-+ count = 1;
-+ } else if (text[i] != '\n') {
-+ needtobreak = 1;
-+ if (xmldoc_wait_nextspace(text, i, maxdiff)) {
-+ /* wait for the next space */
-+ ast_str_append(&tmp, 0, "%c", text[i]);
-+ continue;
-+ }
-+ /* Try to look backwards */
-+ backspace = xmldoc_foundspace_backward(text, i, maxdiff);
-+ if (backspace) {
-+ needtobreak = 1;
-+ ast_str_truncate(tmp, -backspace);
-+ i -= backspace + 1;
-+ continue;
-+ }
-+ ast_str_append(&tmp, 0, "\n%s", postbr);
-+ needtobreak = 0;
-+ count = 1;
-+ }
-+ /* skip blanks after a \n */
-+ while (text[i] == ' ') {
-+ i++;
-+ }
-+ }
-+ if (text[i] == '\n') {
-+ xmldoc_setpostbr(postbr, sizeof(postbr), &text[i] + 1);
-+ colmax = columns - xmldoc_postbrlen(postbr);
-+ needtobreak = 0;
-+ count = 1;
-+ }
-+ if (text[i] == ESC) {
-+ /* Ignore Escape sequences. */
-+ do {
-+ ast_str_append(&tmp, 0, "%c", text[i]);
-+ i++;
-+ } while (i < textlen && text[i] != 'm');
-+ } else {
-+ count++;
-+ }
-+ ast_str_append(&tmp, 0, "%c", text[i]);
-+ }
-+
-+ ret = ast_strdup(ast_str_buffer(tmp));
-+ ast_free(tmp);
-+
-+ return ret;
-+}
-+
-+char *ast_xmldoc_printable(const char *bwinput, int withcolors)
-+{
-+ struct ast_str *colorized;
-+ char *wrapped = NULL;
-+ int i, c, len, colorsection;
-+ char *tmp;
-+ size_t bwinputlen;
-+ static const int base_fg = COLOR_CYAN;
-+
-+ if (!bwinput) {
-+ return NULL;
-+ }
-+
-+ bwinputlen = strlen(bwinput);
-+
-+ if (!(colorized = ast_str_create(256))) {
-+ return NULL;
-+ }
-+
-+ if (withcolors) {
-+ ast_term_color_code(&colorized, base_fg, 0);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+ }
-+
-+ for (i = 0; i < bwinputlen; i++) {
-+ colorsection = 0;
-+ /* Check if we are at the beginning of a tag to be colorized. */
-+ for (c = 0; c < ARRAY_LEN(colorized_tags); c++) {
-+ if (strncasecmp(bwinput + i, colorized_tags[c].inittag, strlen(colorized_tags[c].inittag))) {
-+ continue;
-+ }
-+
-+ if (!(tmp = strcasestr(bwinput + i + strlen(colorized_tags[c].inittag), colorized_tags[c].endtag))) {
-+ continue;
-+ }
-+
-+ len = tmp - (bwinput + i + strlen(colorized_tags[c].inittag));
-+
-+ /* Setup color */
-+ if (withcolors) {
-+ ast_term_color_code(&colorized, colorized_tags[c].colorfg, 0);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+ }
-+
-+ /* copy initial string replace */
-+ ast_str_append(&colorized, 0, "%s", colorized_tags[c].init);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+ {
-+ char buf[len + 1];
-+ ast_copy_string(buf, bwinput + i + strlen(colorized_tags[c].inittag), sizeof(buf));
-+ ast_str_append(&colorized, 0, "%s", buf);
-+ }
-+ if (!colorized) {
-+ return NULL;
-+ }
-+
-+ /* copy the ending string replace */
-+ ast_str_append(&colorized, 0, "%s", colorized_tags[c].end);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+
-+ /* Continue with the last color. */
-+ if (withcolors) {
-+ ast_term_color_code(&colorized, base_fg, 0);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+ }
-+
-+ i += len + strlen(colorized_tags[c].endtag) + strlen(colorized_tags[c].inittag) - 1;
-+ colorsection = 1;
-+ break;
-+ }
-+
-+ if (!colorsection) {
-+ ast_str_append(&colorized, 0, "%c", bwinput[i]);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+ }
-+ }
-+
-+ if (withcolors) {
-+ ast_term_color_code(&colorized, COLOR_BRWHITE, 0);
-+ if (!colorized) {
-+ return NULL;
-+ }
-+ }
-+
-+ /* Wrap the text, notice that string wrap will avoid cutting an ESC sequence. */
-+ wrapped = xmldoc_string_wrap(ast_str_buffer(colorized), xmldoc_text_columns, xmldoc_max_diff);
-+
-+ ast_free(colorized);
-+
-+ return wrapped;
-+}
-+
-+/*! \internal
-+ * \brief Cleanup spaces and tabs after a \n
-+ * \param text String to be cleaned up.
-+ * \param output buffer (not already allocated).
-+ * \param lastspaces Remove last spaces in the string.
-+ */
-+static void xmldoc_string_cleanup(const char *text, struct ast_str **output, int lastspaces)
-+{
-+ int i;
-+ size_t textlen;
-+
-+ if (!text) {
-+ *output = NULL;
-+ return;
-+ }
-+
-+ textlen = strlen(text);
-+
-+ *output = ast_str_create(textlen);
-+ if (!(*output)) {
-+ ast_log(LOG_ERROR, "Problem allocating output buffer\n");
-+ return;
-+ }
-+
-+ for (i = 0; i < textlen; i++) {
-+ if (text[i] == '\n' || text[i] == '\r') {
-+ /* remove spaces/tabs/\n after a \n. */
-+ while (text[i + 1] == '\t' || text[i + 1] == '\r' || text[i + 1] == '\n') {
-+ i++;
-+ }
-+ ast_str_append(output, 0, " ");
-+ continue;
-+ } else {
-+ ast_str_append(output, 0, "%c", text[i]);
-+ }
-+ }
-+
-+ /* remove last spaces (we dont want always to remove the trailing spaces). */
-+ if (lastspaces) {
-+ ast_str_trim_blanks(*output);
-+ }
-+}
-+
-+/*! \internal
-+ * \brief Get the application/function node for 'name' application/function with language 'language'
-+ * if we don't find any, get the first application with 'name' no matter which language with.
-+ * \param type 'application', 'function', ...
-+ * \param name Application or Function name.
-+ * \param language Try to get this language (if not found try with en_US)
-+ * \retval NULL on error.
-+ * \retval A node of type ast_xml_node.
-+ */
-+static struct ast_xml_node *xmldoc_get_node(const char *type, const char *name, const char *language)
-+{
-+ struct ast_xml_node *node = NULL;
-+ struct documentation_tree *doctree;
-+ const char *lang;
-+
-+ AST_RWLIST_RDLOCK(&xmldoc_tree);
-+ AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
-+ /* the core xml documents have priority over thirdparty document. */
-+ node = ast_xml_get_root(doctree->doc);
-+ while ((node = ast_xml_find_element(node, type, "name", name))) {
-+ /* Check language */
-+ lang = ast_xml_get_attribute(node, "language");
-+ if (lang && !strcmp(lang, language)) {
-+ ast_xml_free_attr(lang);
-+ break;
-+ } else if (lang) {
-+ ast_xml_free_attr(lang);
-+ }
-+ }
-+
-+ if (node && ast_xml_node_get_children(node)) {
-+ break;
-+ }
-+
-+ /* We didn't find the application documentation for the specified language,
-+ so, try to load documentation for any language */
-+ node = ast_xml_get_root(doctree->doc);
-+ if (ast_xml_node_get_children(node)) {
-+ if ((node = ast_xml_find_element(ast_xml_node_get_children(node), type, "name", name))) {
-+ break;
-+ }
-+ }
-+ }
-+ AST_RWLIST_UNLOCK(&xmldoc_tree);
-+
-+ return node;
-+}
-+
-+/*! \internal
-+ * \brief Helper function used to build the syntax, it allocates the needed buffer (or reallocates it),
-+ * and based on the reverse value it makes use of fmt to print the parameter list inside the
-+ * realloced buffer (syntax).
-+ * \param reverse We are going backwards while generating the syntax?
-+ * \param len Current length of 'syntax' buffer.
-+ * \param syntax Output buffer for the concatenated values.
-+ * \param fmt A format string that will be used in a sprintf call.
-+ */
-+static void __attribute__((format(printf, 4, 5))) xmldoc_reverse_helper(int reverse, int *len, char **syntax, const char *fmt, ...)
-+{
-+ int totlen, tmpfmtlen;
-+ char *tmpfmt, tmp;
-+ va_list ap;
-+
-+ va_start(ap, fmt);
-+ if (ast_vasprintf(&tmpfmt, fmt, ap) < 0) {
-+ va_end(ap);
-+ return;
-+ }
-+ va_end(ap);
-+
-+ tmpfmtlen = strlen(tmpfmt);
-+ totlen = *len + tmpfmtlen + 1;
-+
-+ *syntax = ast_realloc(*syntax, totlen);
-+
-+ if (!*syntax) {
-+ ast_free(tmpfmt);
-+ return;
-+ }
-+
-+ if (reverse) {
-+ memmove(*syntax + tmpfmtlen, *syntax, *len);
-+ /* Save this char, it will be overwritten by the \0 of strcpy. */
-+ tmp = (*syntax)[0];
-+ strcpy(*syntax, tmpfmt);
-+ /* Restore the already saved char. */
-+ (*syntax)[tmpfmtlen] = tmp;
-+ (*syntax)[totlen - 1] = '\0';
-+ } else {
-+ strcpy(*syntax + *len, tmpfmt);
-+ }
-+
-+ *len = totlen - 1;
-+ ast_free(tmpfmt);
-+}
-+
-+/*! \internal
-+ * \brief Check if the passed node has 'what' tags inside it.
-+ * \param node Root node to search 'what' elements.
-+ * \param what node name to search inside node.
-+ * \retval 1 If a 'what' element is found inside 'node'.
-+ * \retval 0 If no 'what' is found inside 'node'.
-+ */
-+static int xmldoc_has_inside(struct ast_xml_node *fixnode, const char *what)
-+{
-+ struct ast_xml_node *node = fixnode;
-+
-+ for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), what)) {
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+/*! \internal
-+ * \brief Check if the passed node has at least one node inside it.
-+ * \param node Root node to search node elements.
-+ * \retval 1 If a node element is found inside 'node'.
-+ * \retval 0 If no node is found inside 'node'.
-+ */
-+static int xmldoc_has_nodes(struct ast_xml_node *fixnode)
-+{
-+ struct ast_xml_node *node = fixnode;
-+
-+ for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), "text")) {
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+/*! \internal
-+ * \brief Check if the passed node has at least one specialtag.
-+ * \param node Root node to search "specialtags" elements.
-+ * \retval 1 If a "specialtag" element is found inside 'node'.
-+ * \retval 0 If no "specialtag" is found inside 'node'.
-+ */
-+static int xmldoc_has_specialtags(struct ast_xml_node *fixnode)
-+{
-+ struct ast_xml_node *node = fixnode;
-+ int i;
-+
-+ for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
-+ for (i = 0; i < ARRAY_LEN(special_tags); i++) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), special_tags[i].tagname)) {
-+ return 1;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+/*! \internal
-+ * \brief Build the syntax for a specified starting node.
-+ * \param rootnode A pointer to the ast_xml root node.
-+ * \param rootname Name of the application, function, option, etc. to build the syntax.
-+ * \param childname The name of each parameter node.
-+ * \param printparenthesis Boolean if we must print parenthesis if not parameters are found in the rootnode.
-+ * \param printrootname Boolean if we must print the rootname before the syntax and parenthesis at the begining/end.
-+ * \retval NULL on error.
-+ * \retval An ast_malloc'ed string with the syntax generated.
-+ */
-+static char *xmldoc_get_syntax_fun(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
-+{
-+#define GOTONEXT(__rev, __a) (__rev ? ast_xml_node_get_prev(__a) : ast_xml_node_get_next(__a))
-+#define ISLAST(__rev, __a) (__rev == 1 ? (ast_xml_node_get_prev(__a) ? 0 : 1) : (ast_xml_node_get_next(__a) ? 0 : 1))
-+#define MP(__a) ((multiple ? __a : ""))
-+ struct ast_xml_node *node = NULL, *firstparam = NULL, *lastparam = NULL;
-+ const char *paramtype, *multipletype, *paramnameattr, *attrargsep, *parenthesis, *argname;
-+ int reverse, required, paramcount = 0, openbrackets = 0, len = 0, hasparams=0;
-+ int reqfinode = 0, reqlanode = 0, optmidnode = 0, prnparenthesis, multiple;
-+ char *syntax = NULL, *argsep, *paramname;
-+
-+ if (ast_strlen_zero(rootname) || ast_strlen_zero(childname)) {
-+ ast_log(LOG_WARNING, "Tried to look in XML tree with faulty rootname or childname while creating a syntax.\n");
-+ return NULL;
-+ }
-+
-+ if (!rootnode || !ast_xml_node_get_children(rootnode)) {
-+ /* If the rootnode field is not found, at least print name. */
-+ ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : ""));
-+ return syntax;
-+ }
-+
-+ /* Get the argument separator from the root node attribute name 'argsep', if not found
-+ defaults to ','. */
-+ attrargsep = ast_xml_get_attribute(rootnode, "argsep");
-+ if (attrargsep) {
-+ argsep = ast_strdupa(attrargsep);
-+ ast_xml_free_attr(attrargsep);
-+ } else {
-+ argsep = ast_strdupa(",");
-+ }
-+
-+ /* Get order of evaluation. */
-+ for (node = ast_xml_node_get_children(rootnode); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), childname)) {
-+ continue;
-+ }
-+ required = 0;
-+ hasparams = 1;
-+ if ((paramtype = ast_xml_get_attribute(node, "required"))) {
-+ if (ast_true(paramtype)) {
-+ required = 1;
-+ }
-+ ast_xml_free_attr(paramtype);
-+ }
-+
-+ lastparam = node;
-+ reqlanode = required;
-+
-+ if (!firstparam) {
-+ /* first parameter node */
-+ firstparam = node;
-+ reqfinode = required;
-+ }
-+ }
-+
-+ if (!hasparams) {
-+ /* This application, function, option, etc, doesn't have any params. */
-+ ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : ""));
-+ return syntax;
-+ }
-+
-+ if (reqfinode && reqlanode) {
-+ /* check midnode */
-+ for (node = ast_xml_node_get_children(rootnode); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), childname)) {
-+ continue;
-+ }
-+ if (node != firstparam && node != lastparam) {
-+ if ((paramtype = ast_xml_get_attribute(node, "required"))) {
-+ if (!ast_true(paramtype)) {
-+ optmidnode = 1;
-+ break;
-+ }
-+ ast_xml_free_attr(paramtype);
-+ }
-+ }
-+ }
-+ }
-+
-+ if ((!reqfinode && reqlanode) || (reqfinode && reqlanode && optmidnode)) {
-+ reverse = 1;
-+ node = lastparam;
-+ } else {
-+ reverse = 0;
-+ node = firstparam;
-+ }
-+
-+ /* init syntax string. */
-+ if (reverse) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax,
-+ (printrootname ? (printrootname == 2 ? ")]" : ")"): ""));
-+ } else {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", (printrootname ? rootname : ""),
-+ (printrootname ? (printrootname == 2 ? "[(" : "(") : ""));
-+ }
-+
-+ for (; node; node = GOTONEXT(reverse, node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), childname)) {
-+ continue;
-+ }
-+
-+ /* Get the argument name, if it is not the leaf, go inside that parameter. */
-+ if (xmldoc_has_inside(node, "argument")) {
-+ parenthesis = ast_xml_get_attribute(node, "hasparams");
-+ prnparenthesis = 0;
-+ if (parenthesis) {
-+ prnparenthesis = ast_true(parenthesis);
-+ if (!strcasecmp(parenthesis, "optional")) {
-+ prnparenthesis = 2;
-+ }
-+ ast_xml_free_attr(parenthesis);
-+ }
-+ argname = ast_xml_get_attribute(node, "name");
-+ if (argname) {
-+ paramname = xmldoc_get_syntax_fun(node, argname, "argument", prnparenthesis, prnparenthesis);
-+ ast_xml_free_attr(argname);
-+ } else {
-+ /* Malformed XML, print **UNKOWN** */
-+ paramname = ast_strdup("**unknown**");
-+ }
-+ } else {
-+ paramnameattr = ast_xml_get_attribute(node, "name");
-+ if (!paramnameattr) {
-+ ast_log(LOG_WARNING, "Malformed XML %s: no %s name\n", rootname, childname);
-+ if (syntax) {
-+ /* Free already allocated syntax */
-+ ast_free(syntax);
-+ }
-+ /* to give up is ok? */
-+ ast_asprintf(&syntax, "%s%s", (printrootname ? rootname : ""), (printparenthesis ? "()" : ""));
-+ return syntax;
-+ }
-+ paramname = ast_strdup(paramnameattr);
-+ ast_xml_free_attr(paramnameattr);
-+ }
-+
-+ /* Defaults to 'false'. */
-+ multiple = 0;
-+ if ((multipletype = ast_xml_get_attribute(node, "multiple"))) {
-+ if (ast_true(multipletype)) {
-+ multiple = 1;
-+ }
-+ ast_xml_free_attr(multipletype);
-+ }
-+
-+ required = 0; /* Defaults to 'false'. */
-+ if ((paramtype = ast_xml_get_attribute(node, "required"))) {
-+ if (ast_true(paramtype)) {
-+ required = 1;
-+ }
-+ ast_xml_free_attr(paramtype);
-+ }
-+
-+ /* build syntax core. */
-+
-+ if (required) {
-+ /* First parameter */
-+ if (!paramcount) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s%s", paramname, MP("["), MP(argsep), MP("...]"));
-+ } else {
-+ /* Time to close open brackets. */
-+ while (openbrackets > 0) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, (reverse ? "[" : "]"));
-+ openbrackets--;
-+ }
-+ if (reverse) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", paramname, argsep);
-+ } else {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", argsep, paramname);
-+ }
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s", MP("["), MP(argsep), MP("...]"));
-+ }
-+ } else {
-+ /* First parameter */
-+ if (!paramcount) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s]", paramname, MP("["), MP(argsep), MP("...]"));
-+ } else {
-+ if (ISLAST(reverse, node)) {
-+ /* This is the last parameter. */
-+ if (reverse) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s]%s", paramname,
-+ MP("["), MP(argsep), MP("...]"), argsep);
-+ } else {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s[%s%s%s%s]", argsep, paramname,
-+ MP("["), MP(argsep), MP("...]"));
-+ }
-+ } else {
-+ if (reverse) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s%s%s%s]", paramname, argsep,
-+ MP("["), MP(argsep), MP("...]"));
-+ } else {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "[%s%s%s%s%s", argsep, paramname,
-+ MP("["), MP(argsep), MP("...]"));
-+ }
-+ openbrackets++;
-+ }
-+ }
-+ }
-+ ast_free(paramname);
-+
-+ paramcount++;
-+ }
-+
-+ /* Time to close open brackets. */
-+ while (openbrackets > 0) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, (reverse ? "[" : "]"));
-+ openbrackets--;
-+ }
-+
-+ /* close syntax string. */
-+ if (reverse) {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, "%s%s", (printrootname ? rootname : ""),
-+ (printrootname ? (printrootname == 2 ? "[(" : "(") : ""));
-+ } else {
-+ xmldoc_reverse_helper(reverse, &len, &syntax, (printrootname ? (printrootname == 2 ? ")]" : ")") : ""));
-+ }
-+
-+ return syntax;
-+#undef ISLAST
-+#undef GOTONEXT
-+#undef MP
-+}
-+
-+/*! \internal
-+ * \brief Parse an enumlist inside a <parameter> to generate a COMMAND
-+ * syntax.
-+ * \param fixnode A pointer to the <enumlist> node.
-+ * \retval {<unknown>} on error.
-+ * \retval A string inside brackets {} with the enum's separated by pipes |.
-+ */
-+static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
-+{
-+ struct ast_xml_node *node = fixnode;
-+ struct ast_str *paramname;
-+ char *enumname, *ret;
-+ int first = 1;
-+
-+ paramname = ast_str_create(128);
-+ if (!paramname) {
-+ return ast_strdup("{<unkown>}");
-+ }
-+
-+ ast_str_append(&paramname, 0, "{");
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), "enum")) {
-+ continue;
-+ }
-+
-+ enumname = xmldoc_get_syntax_cmd(node, "", 0);
-+ if (!enumname) {
-+ continue;
-+ }
-+ if (!first) {
-+ ast_str_append(&paramname, 0, "|");
-+ }
-+ ast_str_append(&paramname, 0, "%s", enumname);
-+ first = 0;
-+ ast_free(enumname);
-+ }
-+
-+ ast_str_append(&paramname, 0, "}");
-+
-+ ret = ast_strdup(ast_str_buffer(paramname));
-+ ast_free(paramname);
-+
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Generate a syntax of COMMAND type.
-+ * \param fixnode The <syntax> node pointer.
-+ * \param name The name of the 'command'.
-+ * \param printname Print the name of the command before the paramters?
-+ * \retval On error, return just 'name'.
-+ * \retval On success return the generated syntax.
-+ */
-+static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname)
-+{
-+ struct ast_str *syntax;
-+ struct ast_xml_node *tmpnode, *node = fixnode;
-+ char *ret, *paramname;
-+ const char *paramtype, *attrname, *literal;
-+ int required, isenum, first = 1, isliteral;
-+
-+ syntax = ast_str_create(128);
-+ if (!syntax) {
-+ /* at least try to return something... */
-+ return ast_strdup(name);
-+ }
-+
-+ /* append name to output string. */
-+ if (printname) {
-+ ast_str_append(&syntax, 0, "%s", name);
-+ first = 0;
-+ }
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
-+ continue;
-+ }
-+
-+ if (xmldoc_has_inside(node, "parameter")) {
-+ /* is this a recursive parameter. */
-+ paramname = xmldoc_get_syntax_cmd(node, "", 0);
-+ isenum = 1;
-+ } else if (!xmldoc_has_inside(node, "enumlist")) {
-+ /* this is a simple parameter. */
-+ attrname = ast_xml_get_attribute(node, "name");
-+ if (!attrname) {
-+ /* ignore this bogus parameter and continue. */
-+ continue;
-+ }
-+ paramname = ast_strdup(attrname);
-+ ast_xml_free_attr(attrname);
-+ isenum = 0;
-+ } else {
-+ /* parse enumlist (note that this is a special enumlist
-+ that is used to describe a syntax like {<param1>|<param2>|...} */
-+ for (tmpnode = ast_xml_node_get_children(node); tmpnode; tmpnode = ast_xml_node_get_next(tmpnode)) {
-+ if (!strcasecmp(ast_xml_node_get_name(tmpnode), "enumlist")) {
-+ break;
-+ }
-+ }
-+ paramname = xmldoc_parse_cmd_enumlist(tmpnode);
-+ isenum = 1;
-+ }
-+
-+ /* Is this parameter required? */
-+ required = 0;
-+ paramtype = ast_xml_get_attribute(node, "required");
-+ if (paramtype) {
-+ required = ast_true(paramtype);
-+ ast_xml_free_attr(paramtype);
-+ }
-+
-+ /* Is this a replaceable value or a fixed parameter value? */
-+ isliteral = 0;
-+ literal = ast_xml_get_attribute(node, "literal");
-+ if (literal) {
-+ isliteral = ast_true(literal);
-+ ast_xml_free_attr(literal);
-+ }
-+
-+ /* if required="false" print with [...].
-+ * if literal="true" or is enum print without <..>.
-+ * if not first print a space at the beginning.
-+ */
-+ ast_str_append(&syntax, 0, "%s%s%s%s%s%s",
-+ (first ? "" : " "),
-+ (required ? "" : "["),
-+ (isenum || isliteral ? "" : "<"),
-+ paramname,
-+ (isenum || isliteral ? "" : ">"),
-+ (required ? "" : "]"));
-+ first = 0;
-+ ast_free(paramname);
-+ }
-+
-+ /* return a common string. */
-+ ret = ast_strdup(ast_str_buffer(syntax));
-+ ast_free(syntax);
-+
-+ return ret;
-+}
-+
-+/*! \brief Types of syntax that we are able to generate. */
-+enum syntaxtype {
-+ FUNCTION_SYNTAX,
-+ COMMAND_SYNTAX
-+};
-+
-+/*! \brief Mapping between type of node and type of syntax to generate. */
-+struct strsyntaxtype {
-+ const char *type;
-+ enum syntaxtype stxtype;
-+} stxtype[] = {
-+ { "function", FUNCTION_SYNTAX },
-+ { "application", FUNCTION_SYNTAX },
-+ { "agi", COMMAND_SYNTAX }
-+};
-+
-+/*! \internal
-+ * \brief Get syntax type based on type of node.
-+ * \param type Type of node.
-+ * \retval The type of syntax to generate based on the type of node.
-+ */
-+static enum syntaxtype xmldoc_get_syntax_type(const char *type)
-+{
-+ int i;
-+ for (i=0; i < ARRAY_LEN(stxtype); i++) {
-+ if (!strcasecmp(stxtype[i].type, type)) {
-+ return stxtype[i].stxtype;
-+ }
-+ }
-+
-+ return FUNCTION_SYNTAX;
-+}
-+
-+char *ast_xmldoc_build_syntax(const char *type, const char *name)
-+{
-+ struct ast_xml_node *node;
-+ char *syntax = NULL;
-+
-+ node = xmldoc_get_node(type, name, documentation_language);
-+ if (!node) {
-+ return NULL;
-+ }
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) {
-+ break;
-+ }
-+ }
-+
-+ if (node) {
-+ if (xmldoc_get_syntax_type(type) == FUNCTION_SYNTAX) {
-+ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
-+ } else {
-+ syntax = xmldoc_get_syntax_cmd(node, name, 1);
-+ }
-+ }
-+ return syntax;
-+}
-+
-+/*! \internal
-+ * \brief Parse a <para> element.
-+ * \param node The <para> element pointer.
-+ * \param tabs Added this string before the content of the <para> element.
-+ * \param posttabs Added this string after the content of the <para> element.
-+ * \param buffer This must be an already allocated ast_str. It will be used
-+ * to store the result (if already has something it will be appended to the current
-+ * string).
-+ * \retval 1 If 'node' is a named 'para'.
-+ * \retval 2 If data is appended in buffer.
-+ * \retval 0 on error.
-+ */
-+static int xmldoc_parse_para(struct ast_xml_node *node, const char *tabs, const char *posttabs, struct ast_str **buffer)
-+{
-+ const char *tmptext;
-+ struct ast_xml_node *tmp;
-+ int ret = 0;
-+ struct ast_str *tmpstr;
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ return ret;
-+ }
-+
-+ if (strcasecmp(ast_xml_node_get_name(node), "para")) {
-+ return ret;
-+ }
-+
-+ ast_str_append(buffer, 0, "%s", tabs);
-+
-+ ret = 1;
-+
-+ for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
-+ /* Get the text inside the <para> element and append it to buffer. */
-+ tmptext = ast_xml_get_text(tmp);
-+ if (tmptext) {
-+ /* Strip \n etc. */
-+ xmldoc_string_cleanup(tmptext, &tmpstr, 0);
-+ ast_xml_free_text(tmptext);
-+ if (tmpstr) {
-+ if (strcasecmp(ast_xml_node_get_name(tmp), "text")) {
-+ ast_str_append(buffer, 0, "<%s>%s</%s>", ast_xml_node_get_name(tmp),
-+ ast_str_buffer(tmpstr), ast_xml_node_get_name(tmp));
-+ } else {
-+ ast_str_append(buffer, 0, "%s", ast_str_buffer(tmpstr));
-+ }
-+ ast_free(tmpstr);
-+ ret = 2;
-+ }
-+ }
-+ }
-+
-+ ast_str_append(buffer, 0, "%s", posttabs);
-+
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse special elements defined in 'struct special_tags' special elements must have a <para> element inside them.
-+ * \param fixnode special tag node pointer.
-+ * \param tabs put tabs before printing the node content.
-+ * \param posttabs put posttabs after printing node content.
-+ * \param buffer Output buffer, the special tags will be appended here.
-+ * \retval 0 if no special element is parsed.
-+ * \retval 1 if a special element is parsed (data is appended to buffer).
-+ * \retval 2 if a special element is parsed and also a <para> element is parsed inside the specialtag.
-+ */
-+static int xmldoc_parse_specialtags(struct ast_xml_node *fixnode, const char *tabs, const char *posttabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *node = fixnode;
-+ int ret = 0, i, count = 0;
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ return ret;
-+ }
-+
-+ for (i = 0; i < ARRAY_LEN(special_tags); i++) {
-+ if (strcasecmp(ast_xml_node_get_name(node), special_tags[i].tagname)) {
-+ continue;
-+ }
-+
-+ ret = 1;
-+ /* This is a special tag. */
-+
-+ /* concat data */
-+ if (!ast_strlen_zero(special_tags[i].init)) {
-+ ast_str_append(buffer, 0, "%s%s", tabs, special_tags[i].init);
-+ }
-+
-+ /* parse <para> elements inside special tags. */
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ /* first <para> just print it without tabs at the begining. */
-+ if (xmldoc_parse_para(node, (!count ? "" : tabs), posttabs, buffer) == 2) {
-+ ret = 2;
-+ }
-+ }
-+
-+ if (!ast_strlen_zero(special_tags[i].end)) {
-+ ast_str_append(buffer, 0, "%s%s", special_tags[i].end, posttabs);
-+ }
-+
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse an <argument> element from the xml documentation.
-+ * \param fixnode Pointer to the 'argument' xml node.
-+ * \param insideparameter If we are parsing an <argument> inside a <parameter>.
-+ * \param paramtabs pre tabs if we are inside a parameter element.
-+ * \param tabs What to be printed before the argument name.
-+ * \param buffer Output buffer to put values found inside the <argument> element.
-+ * \retval 1 If there is content inside the argument.
-+ * \retval 0 If the argument element is not parsed, or there is no content inside it.
-+ */
-+static int xmldoc_parse_argument(struct ast_xml_node *fixnode, int insideparameter, const char *paramtabs, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *node = fixnode;
-+ const char *argname;
-+ int count = 0, ret = 0;
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ return ret;
-+ }
-+
-+ /* Print the argument names */
-+ argname = ast_xml_get_attribute(node, "name");
-+ if (!argname) {
-+ return 0;
-+ }
-+ if (xmldoc_has_inside(node, "para") || xmldoc_has_specialtags(node)) {
-+ ast_str_append(buffer, 0, "%s%s%s", tabs, argname, (insideparameter ? "\n" : ""));
-+ ast_xml_free_attr(argname);
-+ } else {
-+ ast_xml_free_attr(argname);
-+ return 0;
-+ }
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (xmldoc_parse_para(node, (insideparameter ? paramtabs : (!count ? " - " : tabs)), "\n", buffer) == 2) {
-+ count++;
-+ ret = 1;
-+ } else if (xmldoc_parse_specialtags(node, (insideparameter ? paramtabs : (!count ? " - " : tabs)), "\n", buffer) == 2) {
-+ count++;
-+ ret = 1;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse a <variable> node inside a <variablelist> node.
-+ * \param node The variable node to parse.
-+ * \param tabs A string to be appended at the begining of the output that will be stored
-+ * in buffer.
-+ * \param buffer This must be an already created ast_str. It will be used
-+ * to store the result (if already has something it will be appended to the current
-+ * string).
-+ * \retval 0 if no data is appended.
-+ * \retval 1 if data is appended.
-+ */
-+static int xmldoc_parse_variable(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *tmp;
-+ const char *valname;
-+ const char *tmptext;
-+ struct ast_str *cleanstr;
-+ int ret = 0, printedpara=0;
-+
-+ for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
-+ if (xmldoc_parse_para(tmp, (ret ? tabs : ""), "\n", buffer)) {
-+ printedpara = 1;
-+ continue;
-+ } else if (xmldoc_parse_specialtags(tmp, (ret ? tabs : ""), "\n", buffer)) {
-+ printedpara = 1;
-+ continue;
-+ }
-+
-+ if (strcasecmp(ast_xml_node_get_name(tmp), "value")) {
-+ continue;
-+ }
-+
-+ /* Parse a <value> tag only. */
-+ if (!printedpara) {
-+ ast_str_append(buffer, 0, "\n");
-+ printedpara = 1;
-+ }
-+ /* Parse each <value name='valuename'>desciption</value> */
-+ valname = ast_xml_get_attribute(tmp, "name");
-+ if (valname) {
-+ ret = 1;
-+ ast_str_append(buffer, 0, "%s<value>%s</value>", tabs, valname);
-+ ast_xml_free_attr(valname);
-+ }
-+ tmptext = ast_xml_get_text(tmp);
-+ /* Check inside this node for any explanation about its meaning. */
-+ if (tmptext) {
-+ /* Cleanup text. */
-+ xmldoc_string_cleanup(tmptext, &cleanstr, 1);
-+ ast_xml_free_text(tmptext);
-+ if (cleanstr && ast_str_strlen(cleanstr) > 0) {
-+ ast_str_append(buffer, 0, ":%s", ast_str_buffer(cleanstr));
-+ }
-+ ast_free(cleanstr);
-+ }
-+ ast_str_append(buffer, 0, "\n");
-+ }
-+
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse a <variablelist> node and put all the output inside 'buffer'.
-+ * \param node The variablelist node pointer.
-+ * \param tabs A string to be appended at the begining of the output that will be stored
-+ * in buffer.
-+ * \param buffer This must be an already created ast_str. It will be used
-+ * to store the result (if already has something it will be appended to the current
-+ * string).
-+ * \retval 1 If a <variablelist> element is parsed.
-+ * \retval 0 On error.
-+ */
-+static int xmldoc_parse_variablelist(struct ast_xml_node *node, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *tmp;
-+ const char *varname;
-+ char *vartabs;
-+ int ret = 0;
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ return ret;
-+ }
-+
-+ if (strcasecmp(ast_xml_node_get_name(node), "variablelist")) {
-+ return ret;
-+ }
-+
-+ /* use this spacing (add 4 spaces) inside a variablelist node. */
-+ ast_asprintf(&vartabs, "%s ", tabs);
-+ if (!vartabs) {
-+ return ret;
-+ }
-+ for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
-+ /* We can have a <para> element inside the variable list */
-+ if ((xmldoc_parse_para(tmp, (ret ? tabs : ""), "\n", buffer))) {
-+ ret = 1;
-+ continue;
-+ } else if ((xmldoc_parse_specialtags(tmp, (ret ? tabs : ""), "\n", buffer))) {
-+ ret = 1;
-+ continue;
-+ }
-+
-+ if (!strcasecmp(ast_xml_node_get_name(tmp), "variable")) {
-+ /* Store the variable name in buffer. */
-+ varname = ast_xml_get_attribute(tmp, "name");
-+ if (varname) {
-+ ast_str_append(buffer, 0, "%s<variable>%s</variable>: ", tabs, varname);
-+ ast_xml_free_attr(varname);
-+ /* Parse the <variable> possible values. */
-+ xmldoc_parse_variable(tmp, vartabs, buffer);
-+ ret = 1;
-+ }
-+ }
-+ }
-+
-+ ast_free(vartabs);
-+
-+ return ret;
-+}
-+
-+char *ast_xmldoc_build_seealso(const char *type, const char *name)
-+{
-+ struct ast_str *outputstr;
-+ char *output;
-+ struct ast_xml_node *node;
-+ const char *typename;
-+ const char *content;
-+ int first = 1;
-+
-+ if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
-+ return NULL;
-+ }
-+
-+ /* get the application/function root node. */
-+ node = xmldoc_get_node(type, name, documentation_language);
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ return NULL;
-+ }
-+
-+ /* Find the <see-also> node. */
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), "see-also")) {
-+ break;
-+ }
-+ }
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ /* we couldnt find a <see-also> node. */
-+ return NULL;
-+ }
-+
-+ /* prepare the output string. */
-+ outputstr = ast_str_create(128);
-+ if (!outputstr) {
-+ return NULL;
-+ }
-+
-+ /* get into the <see-also> node. */
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), "ref")) {
-+ continue;
-+ }
-+
-+ /* parse the <ref> node. 'type' attribute is required. */
-+ typename = ast_xml_get_attribute(node, "type");
-+ if (!typename) {
-+ continue;
-+ }
-+ content = ast_xml_get_text(node);
-+ if (!content) {
-+ ast_xml_free_attr(typename);
-+ continue;
-+ }
-+ if (!strcasecmp(typename, "application")) {
-+ ast_str_append(&outputstr, 0, "%s%s()", (first ? "" : ", "), content);
-+ } else if (!strcasecmp(typename, "function")) {
-+ ast_str_append(&outputstr, 0, "%s%s", (first ? "" : ", "), content);
-+ } else if (!strcasecmp(typename, "astcli")) {
-+ ast_str_append(&outputstr, 0, "%s<astcli>%s</astcli>", (first ? "" : ", "), content);
-+ } else {
-+ ast_str_append(&outputstr, 0, "%s%s", (first ? "" : ", "), content);
-+ }
-+ first = 0;
-+ ast_xml_free_text(content);
-+ ast_xml_free_attr(typename);
-+ }
-+
-+ output = ast_strdup(ast_str_buffer(outputstr));
-+ ast_free(outputstr);
-+
-+ return output;
-+}
-+
-+/*! \internal
-+ * \brief Parse a <enum> node.
-+ * \brief fixnode An ast_xml_node pointer to the <enum> node.
-+ * \bried buffer The output buffer.
-+ * \retval 0 if content is not found inside the enum element (data is not appended to buffer).
-+ * \retval 1 if content is found and data is appended to buffer.
-+ */
-+static int xmldoc_parse_enum(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *node = fixnode;
-+ int ret = 0;
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if ((xmldoc_parse_para(node, (ret ? tabs : " - "), "\n", buffer))) {
-+ ret = 1;
-+ } else if ((xmldoc_parse_specialtags(node, (ret ? tabs : " - "), "\n", buffer))) {
-+ ret = 1;
-+ }
-+ }
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse a <enumlist> node.
-+ * \param fixnode As ast_xml pointer to the <enumlist> node.
-+ * \param buffer The ast_str output buffer.
-+ * \retval 0 if no <enumlist> node was parsed.
-+ * \retval 1 if a <enumlist> node was parsed.
-+ */
-+static int xmldoc_parse_enumlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *node = fixnode;
-+ const char *enumname;
-+ int ret = 0;
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (strcasecmp(ast_xml_node_get_name(node), "enum")) {
-+ continue;
-+ }
-+
-+ enumname = ast_xml_get_attribute(node, "name");
-+ if (enumname) {
-+ ast_str_append(buffer, 0, "%s<enum>%s</enum>", tabs, enumname);
-+ ast_xml_free_attr(enumname);
-+
-+ /* parse only enum elements inside a enumlist node. */
-+ if ((xmldoc_parse_enum(node, tabs, buffer))) {
-+ ret = 1;
-+ } else {
-+ ast_str_append(buffer, 0, "\n");
-+ }
-+ }
-+ }
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse an <option> node.
-+ * \param fixnode An ast_xml pointer to the <option> node.
-+ * \param tabs A string to be appended at the begining of each line being added to the
-+ * buffer string.
-+ * \param buffer The output buffer.
-+ * \retval 0 if no option node is parsed.
-+ * \retval 1 if an option node is parsed.
-+ */
-+static int xmldoc_parse_option(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *node;
-+ int ret = 0;
-+ char *optiontabs;
-+
-+ ast_asprintf(&optiontabs, "%s ", tabs);
-+ if (!optiontabs) {
-+ return ret;
-+ }
-+ for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), "argument")) {
-+ /* if this is the first data appended to buffer, print a \n*/
-+ if (!ret && ast_xml_node_get_children(node)) {
-+ /* print \n */
-+ ast_str_append(buffer, 0, "\n");
-+ }
-+ if (xmldoc_parse_argument(node, 0, NULL, optiontabs, buffer)) {
-+ ret = 1;
-+ }
-+ continue;
-+ }
-+
-+ if (xmldoc_parse_para(node, (ret ? tabs : ""), "\n", buffer)) {
-+ ret = 1;
-+ } else if (xmldoc_parse_specialtags(node, (ret ? tabs : ""), "\n", buffer)) {
-+ ret = 1;
-+ }
-+
-+ xmldoc_parse_variablelist(node, optiontabs, buffer);
-+
-+ xmldoc_parse_enumlist(node, optiontabs, buffer);
-+ }
-+ ast_free(optiontabs);
-+
-+ return ret;
-+}
-+
-+/*! \internal
-+ * \brief Parse an <optionlist> element from the xml documentation.
-+ * \param fixnode Pointer to the optionlist xml node.
-+ * \param tabs A string to be appended at the begining of each line being added to the
-+ * buffer string.
-+ * \param buffer Output buffer to put what is inside the optionlist tag.
-+ */
-+static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
-+{
-+ struct ast_xml_node *node;
-+ const char *optname, *hasparams;
-+ char *optionsyntax;
-+ int optparams;
-+
-+ for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
-+ /* Start appending every option tag. */
-+ if (strcasecmp(ast_xml_node_get_name(node), "option")) {
-+ continue;
-+ }
-+
-+ /* Get the option name. */
-+ optname = ast_xml_get_attribute(node, "name");
-+ if (!optname) {
-+ continue;
-+ }
-+
-+ optparams = 1;
-+ hasparams = ast_xml_get_attribute(node, "hasparams");
-+ if (hasparams && !strcasecmp(hasparams, "optional")) {
-+ optparams = 2;
-+ }
-+
-+ optionsyntax = xmldoc_get_syntax_fun(node, optname, "argument", 0, optparams);
-+ if (!optionsyntax) {
-+ ast_xml_free_attr(optname);
-+ ast_xml_free_attr(hasparams);
-+ continue;
-+ }
-+
-+ ast_str_append(buffer, 0, "%s%s: ", tabs, optionsyntax);
-+
-+ if (!xmldoc_parse_option(node, tabs, buffer)) {
-+ ast_str_append(buffer, 0, "\n");
-+ }
-+ ast_xml_free_attr(optname);
-+ ast_xml_free_attr(hasparams);
-+ }
-+}
-+
-+/*! \internal
-+ * \brief Parse a 'parameter' tag inside a syntax element.
-+ * \param fixnode A pointer to the 'parameter' xml node.
-+ * \param tabs A string to be appended at the beginning of each line being printed inside
-+ * 'buffer'.
-+ * \param buffer String buffer to put values found inside the parameter element.
-+ */
-+static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tabs, struct ast_str **buffer)
-+{
-+ const char *paramname;
-+ struct ast_xml_node *node = fixnode;
-+ int hasarguments, printed = 0;
-+ char *internaltabs;
-+
-+ if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
-+ return;
-+ }
-+
-+ hasarguments = xmldoc_has_inside(node, "argument");
-+ if (!(paramname = ast_xml_get_attribute(node, "name"))) {
-+ /* parameter MUST have an attribute name. */
-+ return;
-+ }
-+
-+ ast_asprintf(&internaltabs, "%s ", tabs);
-+ if (!internaltabs) {
-+ return;
-+ }
-+
-+ if (!hasarguments && xmldoc_has_nodes(node)) {
-+ ast_str_append(buffer, 0, "%s\n", paramname);
-+ ast_xml_free_attr(paramname);
-+ printed = 1;
-+ }
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), "optionlist")) {
-+ xmldoc_parse_optionlist(node, internaltabs, buffer);
-+ } else if (!strcasecmp(ast_xml_node_get_name(node), "enumlist")) {
-+ xmldoc_parse_enumlist(node, internaltabs, buffer);
-+ } else if (!strcasecmp(ast_xml_node_get_name(node), "argument")) {
-+ xmldoc_parse_argument(node, 1, internaltabs, (!hasarguments ? " " : ""), buffer);
-+ } else if (!strcasecmp(ast_xml_node_get_name(node), "para")) {
-+ if (!printed) {
-+ ast_str_append(buffer, 0, "%s\n", paramname);
-+ ast_xml_free_attr(paramname);
-+ printed = 1;
-+ }
-+ xmldoc_parse_para(node, internaltabs, "\n", buffer);
-+ continue;
-+ } else if ((xmldoc_parse_specialtags(node, internaltabs, "\n", buffer))) {
-+ continue;
-+ }
-+ }
-+ if (!printed) {
-+ ast_xml_free_attr(paramname);
-+ }
-+ ast_free(internaltabs);
-+}
-+
-+char *ast_xmldoc_build_arguments(const char *type, const char *name)
-+{
-+ struct ast_xml_node *node;
-+ struct ast_str *ret = ast_str_create(128);
-+ char *retstr = NULL;
-+
-+ if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
-+ return NULL;
-+ }
-+
-+ node = xmldoc_get_node(type, name, documentation_language);
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ return NULL;
-+ }
-+
-+ /* Find the syntax field. */
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ if (!strcasecmp(ast_xml_node_get_name(node), "syntax")) {
-+ break;
-+ }
-+ }
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ /* We couldn't find the syntax node. */
-+ return NULL;
-+ }
-+
-+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
-+ xmldoc_parse_parameter(node, "", &ret);
-+ }
-+
-+ if (ast_str_strlen(ret) > 0) {
-+ /* remove last '\n' */
-+ char *buf = ast_str_buffer(ret);
-+ if (buf[ast_str_strlen(ret) - 1] == '\n') {
-+ ast_str_truncate(ret, -1);
-+ }
-+ retstr = ast_strdup(ast_str_buffer(ret));
-+ }
-+ ast_free(ret);
-+
-+ return retstr;
-+}
-+
-+/*! \internal
-+ * \brief Return the string within a node formatted with <para> and <variablelist> elements.
-+ * \param node Parent node where content resides.
-+ * \param raw If set, return the node's content without further processing.
-+ * \param raw_wrap Wrap raw text.
-+ * \retval NULL on error
-+ * \retval Node content on success.
-+ */
-+static struct ast_str *xmldoc_get_formatted(struct ast_xml_node *node, int raw_output, int raw_wrap)
-+{
-+ struct ast_xml_node *tmp;
-+ const char *notcleanret, *tmpstr;
-+ struct ast_str *ret = ast_str_create(128);
-+
-+ if (raw_output) {
-+ notcleanret = ast_xml_get_text(node);
-+ tmpstr = notcleanret;
-+ xmldoc_string_cleanup(ast_skip_blanks(notcleanret), &ret, 0);
-+ ast_xml_free_text(tmpstr);
-+ } else {
-+ for (tmp = ast_xml_node_get_children(node); tmp; tmp = ast_xml_node_get_next(tmp)) {
-+ /* if found, parse a <para> element. */
-+ if (xmldoc_parse_para(tmp, "", "\n", &ret)) {
-+ continue;
-+ } else if (xmldoc_parse_specialtags(tmp, "", "\n", &ret)) {
-+ continue;
-+ }
-+ /* if found, parse a <variablelist> element. */
-+ xmldoc_parse_variablelist(tmp, "", &ret);
-+ xmldoc_parse_enumlist(tmp, " ", &ret);
-+ }
-+ /* remove last '\n' */
-+ /* XXX Don't modify ast_str internals manually */
-+ tmpstr = ast_str_buffer(ret);
-+ if (tmpstr[ast_str_strlen(ret) - 1] == '\n') {
-+ ast_str_truncate(ret, -1);
-+ }
-+ }
-+ return ret;
-+}
-+
-+/*!
-+ * \brief Get the content of a field (synopsis, description, etc) from an asterisk document tree
-+ * \param type Type of element (application, function, ...).
-+ * \param name Name of element (Dial, Echo, Playback, ...).
-+ * \param var Name of field to return (synopsis, description, etc).
-+ * \param raw Field only contains text, no other elements inside it.
-+ * \retval NULL On error.
-+ * \retval Field text content on success.
-+ */
-+static char *xmldoc_build_field(const char *type, const char *name, const char *var, int raw)
-+{
-+ struct ast_xml_node *node;
-+ char *ret = NULL;
-+ struct ast_str *formatted;
-+
-+ if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
-+ ast_log(LOG_ERROR, "Tried to look in XML tree with faulty values.\n");
-+ return ret;
-+ }
-+
-+ node = xmldoc_get_node(type, name, documentation_language);
-+
-+ if (!node) {
-+ ast_log(LOG_WARNING, "Counldn't find %s %s in XML documentation\n", type, name);
-+ return ret;
-+ }
-+
-+ node = ast_xml_find_element(ast_xml_node_get_children(node), var, NULL, NULL);
-+
-+ if (!node || !ast_xml_node_get_children(node)) {
-+ ast_log(LOG_DEBUG, "Cannot find variable '%s' in tree '%s'\n", name, var);
-+ return ret;
-+ }
-+
-+ formatted = xmldoc_get_formatted(node, raw, raw);
-+ if (ast_str_strlen(formatted) > 0) {
-+ ret = ast_strdup(ast_str_buffer(formatted));
-+ }
-+ ast_free(formatted);
-+
-+ return ret;
-+}
-+
-+char *ast_xmldoc_build_synopsis(const char *type, const char *name)
-+{
-+ return xmldoc_build_field(type, name, "synopsis", 1);
-+}
-+
-+char *ast_xmldoc_build_description(const char *type, const char *name)
-+{
-+ return xmldoc_build_field(type, name, "description", 0);
-+}
-+
-+/*! \brief Close and unload XML documentation. */
-+static void xmldoc_unload_documentation(void)
-+{
-+ struct documentation_tree *doctree;
-+
-+ AST_RWLIST_WRLOCK(&xmldoc_tree);
-+ while ((doctree = AST_RWLIST_REMOVE_HEAD(&xmldoc_tree, entry))) {
-+ ast_free(doctree->filename);
-+ ast_xml_close(doctree->doc);
-+ }
-+ AST_RWLIST_UNLOCK(&xmldoc_tree);
-+
-+ ast_xml_finish();
-+}
-+
-+int ast_xmldoc_load_documentation(void)
-+{
-+ struct ast_xml_node *root_node;
-+ struct ast_xml_doc *tmpdoc;
-+ struct documentation_tree *doc_tree;
-+ char *xmlpattern;
-+ struct ast_config *cfg = NULL;
-+ struct ast_variable *var = NULL;
-+ struct ast_flags cnfflags = { 0 };
-+ int globret, i, dup, duplicate;
-+ glob_t globbuf;
-+
-+ /* setup default XML documentation language */
-+ snprintf(documentation_language, sizeof(documentation_language), default_documentation_language);
-+
-+ if ((cfg = ast_config_load2("asterisk.conf", "" /* core can't reload */, cnfflags)) && cfg != CONFIG_STATUS_FILEINVALID) {
-+ for (var = ast_variable_browse(cfg, "options"); var; var = var->next) {
-+ if (!strcasecmp(var->name, "documentation_language")) {
-+ if (!ast_strlen_zero(var->value)) {
-+ snprintf(documentation_language, sizeof(documentation_language), "%s", var->value);
-+ }
-+ }
-+ }
-+ ast_config_destroy(cfg);
-+ }
-+
-+ /* initialize the XML library. */
-+ ast_xml_init();
-+
-+ /* register function to be run when asterisk finish. */
-+ ast_register_atexit(xmldoc_unload_documentation);
-+
-+ /* Get every *-LANG.xml file inside $(ASTDATADIR)/documentation */
-+ ast_asprintf(&xmlpattern, "%s/documentation{/thirdparty/,/}*-{%s,%.2s_??,%s}.xml", ast_config_AST_DATA_DIR,
-+ documentation_language, documentation_language, default_documentation_language);
-+ globbuf.gl_offs = 0; /* initialize it to silence gcc */
-+ globret = glob(xmlpattern, MY_GLOB_FLAGS, NULL, &globbuf);
-+ if (globret == GLOB_NOSPACE) {
-+ ast_log(LOG_WARNING, "Glob Expansion of pattern '%s' failed: Not enough memory\n", xmlpattern);
-+ ast_free(xmlpattern);
-+ return 1;
-+ } else if (globret == GLOB_ABORTED) {
-+ ast_log(LOG_WARNING, "Glob Expansion of pattern '%s' failed: Read error\n", xmlpattern);
-+ ast_free(xmlpattern);
-+ return 1;
-+ }
-+ ast_free(xmlpattern);
-+
-+ AST_RWLIST_WRLOCK(&xmldoc_tree);
-+ /* loop over expanded files */
-+ for (i = 0; i < globbuf.gl_pathc; i++) {
-+ /* check for duplicates (if we already [try to] open the same file. */
-+ duplicate = 0;
-+ for (dup = 0; dup < i; dup++) {
-+ if (!strcmp(globbuf.gl_pathv[i], globbuf.gl_pathv[dup])) {
-+ duplicate = 1;
-+ break;
-+ }
-+ }
-+ if (duplicate) {
-+ continue;
-+ }
-+ tmpdoc = NULL;
-+ tmpdoc = ast_xml_open(globbuf.gl_pathv[i]);
-+ if (!tmpdoc) {
-+ ast_log(LOG_ERROR, "Could not open XML documentation at '%s'\n", globbuf.gl_pathv[i]);
-+ continue;
-+ }
-+ /* Get doc root node and check if it starts with '<docs>' */
-+ root_node = ast_xml_get_root(tmpdoc);
-+ if (!root_node) {
-+ ast_log(LOG_ERROR, "Error getting documentation root node");
-+ ast_xml_close(tmpdoc);
-+ continue;
-+ }
-+ /* Check root node name for malformed xmls. */
-+ if (strcmp(ast_xml_node_get_name(root_node), "docs")) {
-+ ast_log(LOG_ERROR, "Documentation file is not well formed!\n");
-+ ast_xml_close(tmpdoc);
-+ continue;
-+ }
-+ doc_tree = ast_calloc(1, sizeof(*doc_tree));
-+ if (!doc_tree) {
-+ ast_log(LOG_ERROR, "Unable to allocate documentation_tree structure!\n");
-+ ast_xml_close(tmpdoc);
-+ continue;
-+ }
-+ doc_tree->doc = tmpdoc;
-+ doc_tree->filename = ast_strdup(globbuf.gl_pathv[i]);
-+ AST_RWLIST_INSERT_TAIL(&xmldoc_tree, doc_tree, entry);
-+ }
-+ AST_RWLIST_UNLOCK(&xmldoc_tree);
-+
-+ globfree(&globbuf);
-+
-+ return 0;
-+}
-+
-+#endif /* AST_XML_DOCS */
-+
-+
-
-Property changes on: main/xmldoc.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: main/global_datastores.c
-===================================================================
---- a/main/global_datastores.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/main/global_datastores.c (.../team/group/issue14292) (revision 178988)
-@@ -79,35 +79,8 @@
- return new_list;
- }
-
--
--static void *dial_features_duplicate(void *data)
--{
-- struct ast_dial_features *df = data, *df_copy;
--
-- if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
-- return NULL;
-- }
--
-- memcpy(df_copy, df, sizeof(*df));
--
-- return df_copy;
--}
--
--static void dial_features_destroy(void *data) {
-- struct ast_dial_features *df = data;
-- if (df) {
-- ast_free(df);
-- }
--}
--
- const struct ast_datastore_info dialed_interface_info = {
- .type = "dialed-interface",
- .destroy = dialed_interface_destroy,
- .duplicate = dialed_interface_duplicate,
- };
--
--const struct ast_datastore_info dial_features_info = {
-- .type = "dial-features",
-- .destroy = dial_features_destroy,
-- .duplicate = dial_features_duplicate,
--};
-Index: configs/skinny.conf.sample
-===================================================================
---- a/configs/skinny.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/skinny.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -63,27 +63,49 @@
- ;jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
- ;-----------------------------------------------------------------------------------
-
--;----------------------------------- DEVICE OPTIONS --------------------------------
-+[lines]
-+;----------------------------------- LINES SECTION --------------------------------
-+; Options set under [lines] apply to all lines unless explicitly set for a particular
-+; device. The options that can be set under lines are specified in GENERAL LINE OPTIONS.
-+; These options can also be set for each individual device as well as those under SPECIFIC
-+; LINE OPTIONS.
-+;
-+; Each label below [lines] in [] is a new line with the specific options specified below
-+; it. Config stops reading new lines when one of the following is found: [general], [devices]
-+; or the end of skinny.conf.
-+;
-+; Where options are common to both lines and devices, the results typically take that of
-+; the least permission. ie if a no is set for either line or device, the call will not be
-+; able to use that permission
-+;-------------------------------- GENERAL LINE OPTIONS -----------------------------
- ;earlyrtp=1 ; whether audio signalling should be provided by asterisk
-- ; (earlyrtp=1) or device generated (earlyrtp=0).
-- ; defaults to earlyrtp=1
-+; ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes
-+;transfer=1 ; whether the device is allowed to transfer. default=yes
-+;context=default ; context to use for this line.
-+;------------------------------- SPECIFIC LINE OPTIONS -----------------------------
-+;setvar= ; allows for the setting of chanvars.
- ;-----------------------------------------------------------------------------------
-
--; Typical config for 12SP+
--;[florian]
--;device=SEP00D0BA847E6B
--;version=P002G204 ; Thanks critch
-+;[100]
-+;nat=yes
-+;callerid="Customer Support" <810-234-1212>
-+;mailbox=100
-+;vmexten=8500 ; Device level voicemailmain pilot number
-+;regexten=100
-+;context=inbound
-+;linelabel="Support Line" ; Displays next to the line
-+ ; button on 7940's and 7960s
-+;[110]
-+;callerid="John Chambers" <408-526-4000>
- ;context=did
--;canreinvite=yes ; Allow media to go directly between two RTP endpoints.
--;line => 120 ; Dial(Skinny/120@florian)
-+;regexten=110
-+;linelabel="John"
-+;mailbox=110
-
-+;[120]
-+;Nothing set, so all the defaults are used
-
--; Typical config for a 7910
--;[duba] ; Device name
--;device=SEP0007EB463101 ; Official identifier
--;version=P002F202 ; Firmware version identifier
--;host=192.168.1.144
--;permit=192.168.0/24 ; Optional, used for authentication
-+;[500]
- ;nat=yes
- ;callerid="George W. Bush" <202-456-1414>
- ;setvar=CUSTID=5678 ; Channel variable to be set for all calls from this device
-@@ -96,7 +118,6 @@
- ;transfer=yes
- ;threewaycalling=yes
- ;context=default
--;line => 500 ; Dial(Skinny/500@duba)
- ;mohinterpret=default ; This option specifies a default music on hold class to
- ; use when put on hold if the channel's moh class was not
- ; explicitly set with Set(CHANNEL(musicclass)=whatever) and
-@@ -105,25 +126,56 @@
- ; when this channel places the peer on hold. It may be specified globally or on
- ; a per-user or per-peer basis.
-
-+
-+[devices]
-+;---------------------------------- DEVICES SECTION -------------------------------
-+; Options set under [devices] apply to all devices unless explicitly set for a particular
-+; device. The options that can be set under devices are specified in GENERAL DEVICE OPTIONS.
-+; These options can also be set for each individual device as well as those under SPECIFIC
-+; DEVICE OPTIONS.
-+;
-+; Each label below [devices] in [] is a new device with the specific options specified below
-+; it. Config stop reading new devices when one of the following is found: [general], [lines]
-+; or the end of skinny.conf.
-+;
-+; Where options are common to both lines and devices, the results typically take that of
-+; the least permission. ie if a no is set for either line or device, the call will not be
-+; able to use that permission
-+;------------------------------- GENERAL DEVICE OPTIONS ----------------------------
-+;earlyrtp=1 ; whether audio signalling should be provided by asterisk
-+; ; (earlyrtp=1) or device generated (earlyrtp=0). default=yes
-+;transfer=1 ; whether the device is allowed to transfer. default=yes
-+;------------------------------ SPECIFIC DEVICE OPTIONS ----------------------------
-+;device="SEPxxxxxxxxxxxx ; id of the device. Must be set.
-+;version=P002G204 ; firmware version to be loaded. If this version is different
-+; ; to the one on the device, the device will try to load this
-+; ; version from the tftp server. Set to device firmware version.
-+;-----------------------------------------------------------------------------------
-+
-+; Typical config for 12SP+
-+;[florian]
-+;device=SEP00D0BA847E6B
-+;version=P002G204 ; Thanks critch
-+;context=did
-+;canreinvite=yes ; Allow media to go directly between two RTP endpoints.
-+;line=120 ; Dial(Skinny/120@florian)
-+
-+; Typical config for a 7910
-+;[duba] ; Device name
-+;device=SEP0007EB463101 ; Official identifier
-+;version=P002F202 ; Firmware version identifier
-+;host=192.168.1.144
-+;permit=192.168.0/24 ; Optional, used for authentication
-+;line=500
-+
-+
- ; Typical config for a 7940 with dual 7914s
- ;[support]
- ;device=SEP0007EB463121
--;nat=yes
--;callerid="Customer Support" <810-234-1212>
--;mailbox=100
--;vmexten=8500 ; Device level voicemailmain pilot number
--;regexten=100
--;context=inbound
--;linelabel="Support Line" ; Displays next to the line
-- ; button on 7940's and 7960s
--;line => 100
--;callerid="John Chambers" <408-526-4000>
--;context=did
--;regexten=110
--;linelabel="John"
--;mailbox=110
--;line => 110
-+;line=100
-+;line=110
- ;speeddial => 111,Jack Smith ; Adds a speeddial button to a device.
- ;speeddial => 112@hints,Bob Peterson ; When a context is specified, the speeddial watches a dialplan hint.
- ;addon => 7914
- ;addon => 7914
-+
-Index: configs/iax.conf.sample
-===================================================================
---- a/configs/iax.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/iax.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -170,17 +170,16 @@
- ; This setting sets the maximum transmission unit for IAX2 UDP trunking.
- ; default is 1240 bytes. Zero disables this functionality and let's the O/S handle fragmentation.
- ;
--; trunkmtu = 0
-+; trunkmtu = 1240
- ;
- ; Enable IAX2 encryption. The default is no.
- ;
- ; encryption = yes
- ;
--; This is a compatibility option for older versions of IAX2 that do not support
--; key rotation with encryption. This option will disable the IAX_COMMAND_RTENC message.
--; default is on
-+; Force encryption insures no connection is established unless both sides support
-+; encryption. By turning this option on, encryption is automatically turned on as well.
- ;
--; keyrotate=off
-+; forceencryption = yes
-
- ; This option defines the maximum size an IAX2 trunk can grow to. The default value is 128000 bytes which
- ; represents 40ms uncompressed linear with 200 channels. Depending on different things though
-@@ -469,3 +468,15 @@
- ;context=default
- ;permit=0.0.0.0/0.0.0.0
-
-+;
-+; With immediate=yes, an IAX phone or a phone on an IAXy acts as a hot-line
-+; which goes immediately to the s extension when picked up. Useful for
-+; elevator phones, manual service, or other similar applications.
-+;
-+;[manual]
-+;type=friend
-+;host=dynamic
-+;immediate=yes ; go immediately to s extension when picked up
-+;secret=moofoo ; when immediate=yes is specified, secret is required
-+;context=number-please ; we start at the s extension in this context
-+;
-Index: configs/sip.conf.sample
-===================================================================
---- a/configs/sip.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/sip.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -43,13 +43,11 @@
- ; -------------------------------------------------------------
- ; Useful CLI commands to check peers/users:
- ; sip show peers Show all SIP peers (including friends)
--; sip show users Show all SIP users (including friends)
- ; sip show registry Show status of hosts we register with
- ;
- ; sip set debug Show all SIP messages
- ;
- ; module reload chan_sip.so Reload configuration file
--; Active SIP peers will not be reconfigured
- ;
- ;------- Naming devices ------------------------------------------------------
- ;
-@@ -58,12 +56,18 @@
- ; 1. Asterisk checks the SIP From: address username and matches against
- ; names of devices with type=user
- ; The name is the text between square brackets [name]
--; 2. Asterisk checks the IP address (and port number) that the INVITE
-+; 2. Asterisk checks the From: addres and matches the list of devices
-+; with a type=peer
-+; 3. Asterisk checks the IP address (and port number) that the INVITE
- ; was sent from and matches against any devices with type=peer
- ;
- ; Don't mix extensions with the names of the devices. Devices need a unique
- ; name. The device name is *not* used as phone numbers. Phone numbers are
- ; anything you declare as an extension in the dialplan (extensions.conf).
-+;
-+; When setting up trunks, make sure there's no risk that any From: username
-+; (caller ID) will match any of your device names, because then Asterisk
-+; might match the wrong device.
- ;
- ; Note: The parameter "username" is not the username and in most cases is
- ; not needed at all. Check below. In later releases, it's renamed
-@@ -164,10 +168,13 @@
- ; and subscriptions (seconds)
- ;minexpiry=60 ; Minimum length of registrations/subscriptions (default 60)
- ;defaultexpiry=120 ; Default length of incoming/outgoing registration
-+;mwiexpiry=3600 ; Expiry time for outgoing MWI subscriptions
- ;qualifyfreq=60 ; Qualification: How often to check for the
- ; host to be up in seconds
- ; Set to low value if you use low timeout for
- ; NAT of UDP sessions
-+;qualifygap=100 ; Number of milliseconds between each group of peers being qualified
-+;qualifypeers=1 ; Number of peers in a group to be qualified at the same time
- ;notifymimetype=text/plain ; Allow overriding of mime type in MWI NOTIFY
- ;buggymwi=no ; Cisco SIP firmware doesn't support the MWI RFC
- ; fully. Enable this option to not get error messages
-@@ -202,6 +209,14 @@
- ;relaxdtmf=yes ; Relax dtmf handling
- ;trustrpid = no ; If Remote-Party-ID should be trusted
- ;sendrpid = yes ; If Remote-Party-ID should be sent
-+;sendrpid = rpid ; Use the "Remote-Party-ID" header
-+ ; to send the identity of the remote party
-+ ; This is identical to sendrpid=yes
-+;sendrpid = pai ; Use the "P-Asserted-Identity" header
-+ ; to send the identity of the remote party
-+;rpid_header = rpid ; Which header should be used when sending Remote Party ID
-+ ; 'rpid' means to send "Remote-Party-ID"
-+ ; 'pai' means to send "P-Asserted-Identity"
- ;progressinband=never ; If we should generate in-band ringing always
- ; use 'never' to never use in-band signalling, even in cases
- ; where some buggy devices might not render it
-@@ -391,22 +406,25 @@
- ;subscribecontext = default ; Set a specific context for SUBSCRIBE requests
- ; Useful to limit subscriptions to local extensions
- ; Settable per peer/user also
--;notifyringing = yes ; Control whether subscriptions already INUSE get sent
-- ; RINGING when another call is sent (default: no)
-+;notifyringing = no ; Control whether subscriptions already INUSE get sent
-+ ; RINGING when another call is sent (default: yes)
- ;notifyhold = yes ; Notify subscriptions on HOLD state (default: no)
- ; Turning on notifyringing and notifyhold will add a lot
- ; more database transactions if you are using realtime.
-+;notifycid = yes ; Control whether caller ID information is sent along with
-+ ; dialog-info+xml notifications (supported by snom phones).
-+ ; Note that this feature will only work properly when the
-+ ; incoming call is using the same extension and context that
-+ ; is being used as the hint for the called extension. This means
-+ ; that it won't work when using subscribecontext for your sip
-+ ; user or peer (if subscribecontext is different than context).
-+ ; This is also limited to a single caller, meaning that if an
-+ ; extension is ringing because multiple calls are incoming,
-+ ; only one will be used as the source of caller ID. Specify
-+ ; 'ignore-context' to ignore the called context when looking
-+ ; for the caller's channel. The default value is 'no.'
- ;callcounter = yes ; Enable call counters on devices. This can be set per
- ; device too.
--;counteronpeer = yes ; Apply call counting on peers only. This will improve
-- ; status notification when you are using type=friend
-- ; Inbound calls, that really apply to the user part
-- ; of a friend will now be added to and compared with
-- ; the peer counter instead of applying two call counters,
-- ; one for the peer and one for the user.
-- ; "sip show inuse" will only show active calls on
-- ; the peer side of a "type=friend" object if this
-- ; setting is turned on.
-
- ;----------------------------------------- T.38 FAX PASSTHROUGH SUPPORT -----------------------
- ;
-@@ -420,6 +438,11 @@
- ;
- ; t38pt_udptl = yes ; Default false
- ;
-+; Fax Detect will cause the SIP channel to jump to the 'fax' extension (if it exists)
-+; after T.38 is successfully negotiated.
-+;
-+; faxdetect = yes ; Default false
-+;
- ;----------------------------------------- OUTBOUND SIP REGISTRATIONS ------------------------
- ; Asterisk can register as a SIP user agent to a SIP proxy (provider)
- ; Format for the register statement is:
-@@ -446,6 +469,20 @@
- ; and more readable because you don't have to write the parameters in two places
- ; (note that the "port" is ignored - this is a bug that should be fixed).
- ;
-+; Note that a register= line doesn't mean that we will match the incoming call in any
-+; other way than described above. If you want to control where the call enters your
-+; dialplan, which context, you want to define a peer with the hostname of the provider's
-+; server. If the provider has multiple servers to place calls to your system, you need
-+; a peer for each server.
-+;
-+; Beginning with Asterisk version 1.6.2, the "user" portion of the register line may
-+; contain a port number. Since the logical separator between a host and port number is a
-+; ':' character, and this character is already used to separate between the optional "secret"
-+; and "authuser" portions of the line, there is a bit of a hoop to jump through if you wish
-+; to use a port here. That is, you must explicitly provide a "secret" and "authuser" even if
-+; they are blank. See the third example below for an illustration.
-+;
-+;
- ; Examples:
- ;
- ;register => 1234:password@mysipprovider.com
-@@ -460,15 +497,30 @@
- ; unless you configure a [sip_proxy] section below, and configure a
- ; context.
- ; Tip 1: Avoid assigning hostname to a sip.conf section like [provider.com]
--; Tip 2: Use separate type=peer and type=user sections for SIP providers
-+; Tip 2: Use separate inbound and outbound sections for SIP providers
- ; (instead of type=friend) if you have calls in both directions
-+;
-+;register => 3456@mydomain:5082::@mysipprovider.com
-+;
-+; Note that in this example, the optional authuser and secret portions have
-+; been left blank because we have specified a port in the user section
-
- ;registertimeout=20 ; retry registration calls every 20 seconds (default)
- ;registerattempts=10 ; Number of registration attempts before we give up
- ; 0 = continue forever, hammering the other server
- ; until it accepts the registration
- ; Default is 0 tries, continue forever
--
-+;----------------------------------------- OUTBOUND MWI SUBSCRIPTIONS -------------------------
-+; Asterisk can subscribe to receive the MWI from another SIP server and store it locally for retrieval
-+; by other phones.
-+; Format for the mwi register statement is:
-+; mwi => user[:secret[:authuser]]@host[:port][/mailbox]
-+;
-+; Examples:
-+;mwi => 1234:password@mysipprovider.com/1234
-+;
-+; MWI received will be stored in the 1234 mailbox of the SIP_Remote context. It can be used by other phones by following the below:
-+; mailbox=1234@SIP_Remote
- ;----------------------------------------- NAT SUPPORT ------------------------
- ;
- ; WARNING: SIP operation behind a NAT is tricky and you really need
-@@ -593,6 +645,15 @@
- ; instead of INVITE. This can be combined with 'nonat', as
- ; 'canreinvite=update,nonat'. It implies 'yes'.
-
-+;ignoresdpversion=yes ; By default, Asterisk will honor the session version
-+ ; number in SDP packets and will only modify the SDP
-+ ; session if the version number changes. This option will
-+ ; force asterisk to ignore the SDP session version number
-+ ; and treat all SDP data as new data. This is required
-+ ; for devices that send us non standard SDP packets
-+ ; (observed with Microsoft OCS). By default this option is
-+ ; off.
-+
- ;----------------------------------------- REALTIME SUPPORT ------------------------
- ; For additional information on ARA, the Asterisk Realtime Architecture,
- ; please read realtime.txt and extconfig.txt in the /doc directory of the
-@@ -715,74 +776,93 @@
- ; Peer auth= override all other authentication settings if we match on realm
-
- ;------------------------------------------------------------------------------
--; Users and peers have different settings available. Friends have all settings,
--; since a friend is both a peer and a user
-+; DEVICE CONFIGURATION
-+;
-+; The SIP channel has two types of devices, the friend and the peer.
-+; * The type=friend is a device type that accepts both incoming and outbound calls,
-+; where Asterisk match on the From: username on incoming calls.
-+; (A synonym for friend is "user"). This is a type you use for your local
-+; SIP phones.
-+; * The type=peer also handles both incoming and outbound calls. On inbound calls,
-+; Asterisk only matches on IP/port, not on names. This is mostly used for SIP
-+; trunks.
- ;
--; User config options: Peer configuration:
--; -------------------- -------------------
--; context context
--; callingpres callingpres
--; permit permit
--; deny deny
--; secret secret
--; md5secret md5secret
--; transport transport
--; dtmfmode dtmfmode
--; canreinvite canreinvite
--; nat nat
--; callgroup callgroup
--; pickupgroup pickupgroup
--; language language
--; allow allow
--; disallow disallow
--; insecure insecure
--; trustrpid trustrpid
--; progressinband progressinband
--; promiscredir promiscredir
--; useclientcode useclientcode
--; accountcode accountcode
--; setvar setvar
--; callerid callerid
--; amaflags amaflags
--; call-limit call-limit (deprecated)
--; callcounter callcounter
--; allowoverlap allowoverlap
--; allowsubscribe allowsubscribe
--; allowtransfer allowtransfer
--; subscribecontext subscribecontext
--; videosupport videosupport
--; maxcallbitrate maxcallbitrate
--; rfc2833compensate mailbox
--; session-timers busylevel
--; session-expires
--; session-minse template
--; session-refresher fromdomain
--; t38pt_usertpsource regexten
--; fromuser
--; host
--; port
--; qualify
--; defaultip
--; defaultuser
--; rtptimeout
--; rtpholdtimeout
--; sendrpid
--; outboundproxy
--; rfc2833compensate
--; callbackextension
--; registertrying
--; session-timers
--; session-expires
--; session-minse
--; session-refresher
--; timert1
--; timerb
--; qualifyfreq
--; t38pt_usertpsource
--; contactpermit ; Limit what a host may register as (a neat trick
--; contactdeny ; is to register at the same IP as a SIP provider,
--; ; then call oneself, and get redirected to that
--; ; same location).
-+; For device names, we recommend using only a-z, numerics (0-9) and underscore
-+;
-+; For local phones, type=friend works most of the time
-+;
-+; If you have one-way audio, you probably have NAT problems.
-+; If Asterisk is on a public IP, and the phone is inside of a NAT device
-+; you will need to configure nat option for those phones.
-+; Also, turn on qualify=yes to keep the nat session open
-+;
-+; Configuration options available
-+; --------------------
-+; context
-+; callingpres
-+; permit
-+; deny
-+; secret
-+; md5secret
-+; remotesecret
-+; transport
-+; dtmfmode
-+; canreinvite
-+; nat
-+; callgroup
-+; pickupgroup
-+; language
-+; allow
-+; disallow
-+; insecure
-+; trustrpid
-+; progressinband
-+; promiscredir
-+; useclientcode
-+; accountcode
-+; setvar
-+; callerid
-+; amaflags
-+; callcounter
-+; busylevel
-+; allowoverlap
-+; allowsubscribe
-+; allowtransfer
-+; ignoresdpversion
-+; subscribecontext
-+; template
-+; videosupport
-+; maxcallbitrate
-+; rfc2833compensate
-+; mailbox
-+; session-timers
-+; session-expires
-+; session-minse
-+; session-refresher
-+; t38pt_usertpsource
-+; regexten
-+; fromdomain
-+; fromuser
-+; host
-+; port
-+; qualify
-+; defaultip
-+; defaultuser
-+; rtptimeout
-+; rtpholdtimeout
-+; sendrpid
-+; outboundproxy
-+; rfc2833compensate
-+; callbackextension
-+; registertrying
-+; timert1
-+; timerb
-+; qualifyfreq
-+; t38pt_usertpsource
-+; contactpermit ; Limit what a host may register as (a neat trick
-+; contactdeny ; is to register at the same IP as a SIP provider,
-+; ; then call oneself, and get redirected to that
-+; ; same location).
-
- ;[sip_proxy]
- ; For incoming calls only. Example: FWD (Free World Dialup)
-@@ -794,7 +874,7 @@
-
- ;[sip_proxy-out]
- ;type=peer ; we only want to call out, not be called
--;secret=guessit
-+;remotesecret=guessit ; Our password to their service
- ;defaultuser=yourusername ; Authentication user for outbound proxies
- ;fromuser=yourusername ; Many SIP providers require this!
- ;fromdomain=provider.sip.domain
-@@ -814,28 +894,14 @@
- ;type=peer
- ;host=sip.provider1.com
- ;fromuser=4015552299 ; how your provider knows you
--;secret=youwillneverguessit
-+;remotesecret=youwillneverguessit ; The password we use to authenticate to them
-+;secret=gissadetdu ; The password they use to contact us
- ;callbackextension=123 ; Register with this server and require calls coming back to this extension
- ;transport=udp,tcp ; This sets the transport type to udp for outgoing, and will
- ; ; accept both tcp and udp. Default is udp. The first transport
- ; ; listed will always be used for outgoing connections.
-
--;------------------------------------------------------------------------------
--; Definitions of locally connected SIP devices
- ;
--; type = user a device that authenticates to us by "from" field to place calls
--; type = peer a device we place calls to or that calls us and we match by host
--; type = friend two configurations (peer+user) in one
--;
--; For device names, we recommend using only a-z, numerics (0-9) and underscore
--;
--; For local phones, type=friend works most of the time
--;
--; If you have one-way audio, you probably have NAT problems.
--; If Asterisk is on a public IP, and the phone is inside of a NAT device
--; you will need to configure nat option for those phones.
--; Also, turn on qualify=yes to keep the nat session open
--;
- ; Because you might have a large number of similar sections, it is generally
- ; convenient to use templates for the common parameters, and add them
- ; the the various sections. Examples are below, and we can even leave
-@@ -999,7 +1065,7 @@
- ;defaultip=192.168.0.4 ; IP address to use until registration
- ;defaultuser=goran ; Username to use when calling this device before registration
- ; Normally you do NOT need to set this parameter
--;setvar=CUSTID=5678 ; Channel variable to be set for all calls from this device
-+;setvar=CUSTID=5678 ; Channel variable to be set for all calls from or to this device
- ;setvar=ATTENDED_TRANSFER_COMPLETE_SOUND=beep ; This channel variable will
- ; cause the given audio file to
- ; be played upon completion of
-Index: configs/cli_permissions.conf.sample
-===================================================================
---- a/configs/cli_permissions.conf.sample (.../tags/1.6.1-rc1) (revision 0)
-+++ b/configs/cli_permissions.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,82 @@
-+;
-+; CLI permissions configuration example for Asterisk
-+;
-+; All the users that you want to connect with asterisk using
-+; rasterisk, should have write/read access to the
-+; asterisk socket (asterisk.ctl). You could change the permissions
-+; of this file in 'asterisk.conf' config parameter: 'astctlpermissions' (0666)
-+; found on the [files] section.
-+;
-+; general options:
-+;
-+; default_perm = permit | deny
-+; This is the default permissions to apply for a user that
-+; does not has a permissions definided.
-+;
-+; user options:
-+; permit = <command name> | all ; allow the user to run 'command' |
-+; ; allow the user to run 'all' the commands
-+; deny = <command name> | all ; disallow the user to run 'command' |
-+; ; disallow the user to run 'all' commands.
-+;
-+
-+[general]
-+
-+default_perm=permit ; To leave asterisk working as normal
-+ ; we should set this parameter to 'permit'
-+;
-+; Follows the per-users permissions configs.
-+;
-+; This list is read in the sequence that is being written, so
-+; In this example the user 'eliel' is allow to run only the following
-+; commands:
-+; sip show peer
-+; core set debug
-+; core set verbose
-+; If the user is not specified, the default_perm option will be apply to
-+; every command.
-+;
-+; Notice that you can also use regular expressions to allow or deny access to a
-+; certain command like: 'core show application D*'. In this example the user will be
-+; allowed to view the documentation for all the applications starting with 'D'.
-+; Another regular expression could be: 'channel originate SIP/[0-9]* extension *'
-+; allowing the user to use 'channel originate' on a sip channel and with the 'extension'
-+; parameter and avoiding the use of the 'application' parameter.
-+;
-+; We can also use the templates syntax:
-+; [supportTemplate](!)
-+; deny=all
-+; permit=sip show ; all commands starting with 'sip show' will be allowed
-+; permit=core show
-+;
-+; You can specify permissions for a local group instead of a user,
-+; just put a '@' and we will know that is a group.
-+; IMPORTANT NOTE: Users permissions overwrite group permissions.
-+;
-+;[@adm]
-+;deny=all
-+;permit=sip
-+;permit=core
-+;
-+;
-+;[eliel]
-+;deny=all
-+;permit=sip show peer
-+;deny=sip show peers
-+;permit=core set
-+;
-+;
-+;User 'tommy' inherits from template 'supportTemplate':
-+; deny=all
-+; permit=sip show
-+; permit=core show
-+;[tommy](supportTemplate)
-+;permit=core set debug
-+;permit=dialplan show
-+;
-+;
-+;[mark]
-+;deny=all
-+;permit=all
-+;
-+;
-
-Property changes on: configs/cli_permissions.conf.sample
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: configs/indications.conf.sample
-===================================================================
---- a/configs/indications.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/indications.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -1,7 +1,10 @@
-+;
- ; indications.conf
-+;
- ; Configuration file for location specific tone indications
--; used by the pbx_indications module.
- ;
-+
-+;
- ; NOTE:
- ; When adding countries to this file, please keep them in alphabetical
- ; order according to the 2-character country codes!
-@@ -9,7 +12,7 @@
- ; The [general] category is for certain global variables.
- ; All other categories are interpreted as location specific indications
- ;
--;
-+
- [general]
- country=us ; default location
-
-@@ -17,9 +20,6 @@
- ; [example]
- ; description = string
- ; The full name of your country, in English.
--; alias = iso[,iso]*
--; List of other countries 2-letter iso codes, which have the same
--; tone indications.
- ; ringcadence = num[,num]*
- ; List of durations the physical bell rings.
- ; dial = tonelist
-@@ -56,8 +56,6 @@
- ; element = [!]freq[+|*freq2][/duration]
- ; tonelist = element[,element]*
- ;
--; Please note that SPACES ARE NOT ALLOWED in tone lists!
--;
-
- [at]
- description = Austria
-Index: configs/voicemail.conf.sample
-===================================================================
---- a/configs/voicemail.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/voicemail.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -316,7 +316,7 @@
- ;4300 => 3456,Ben Rigas,ben@american-computer.net
- ;4310 => -5432,Sales,sales@marko.net
- ;4069 => 6522,Matt Brooks,matt@marko.net,,|tz=central|attach=yes|saycid=yes|dialout=fromvm|callback=fromvm|review=yes|operator=yes|envelope=yes|moveheard=yes|sayduration=yes|saydurationm=1
--;4073 => 1099,Bianca Paige,bianca@biancapaige.com,,delete=1
-+;4073 => 1099,Bianca Paige,bianca@biancapaige.com,,delete=1|emailsubject=You have a new voicemail.|emailbody=Click on the attachment to listen.
- ;4110 => 3443,Rob Flynn,rflynn@blueridge.net
- ;4235 => 1234,Jim Holmes,jim@astricon.ips,,Tz=european
-
-@@ -339,3 +339,11 @@
- ;111 => 7383,Pete,pete@acme-widgets.com,,tz=central
- ;112 => 6262,Nancy,nancy@acme-widgets.com
- ;
-+
-+;
-+; When using IMAP storage, imapuser and imappassword can be used to specify the
-+; user's credentials.
-+;
-+;[imapvm]
-+;4324 => 7764,Ellis Redding,red@buxton.us,,imapuser=eredding|imappassword=g3tbusy
-+;4325 => 2392,Andrew Dufresne,andy@dufresne.info,,imapuser=adufresne|imappassword=rockh@mmer
-Index: configs/misdn.conf.sample
-===================================================================
---- a/configs/misdn.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/misdn.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -7,13 +7,13 @@
- ; for debugging and general setup, things that are not bound to port groups
- ;
-
--[general]
-+[general]
- ;
- ; Sets the Path to the misdn-init.conf (for nt_ptp mode checking)
- ;
- misdn_init=/etc/misdn-init.conf
-
--; set debugging flag:
-+; set debugging flag:
- ; 0 - No Debug
- ; 1 - mISDN Messages and * - Messages, and * - State changes
- ; 2 - Messages + Message specific Informations (e.g. bearer capability)
-@@ -26,8 +26,8 @@
-
-
-
--; set debugging file and flags for mISDNuser (NT-Stack)
--;
-+; set debugging file and flags for mISDNuser (NT-Stack)
-+;
- ; flags can be or'ed with the following values:
- ;
- ; DBGM_NET 0x00000001
-@@ -57,7 +57,7 @@
- ntdebugfile=/var/log/misdn-nt.log
-
-
--; some pbx systems do cut the L1 for some milliseconds, to avoid
-+; some pbx systems do cut the L1 for some milliseconds, to avoid
- ; dropping running calls, we can set this flag to yes and tell
- ; mISDNuser not to drop the calls on L2_RELEASE
- ntkeepcalls=no
-@@ -76,26 +76,13 @@
- bridging=no
-
-
--;
--; watches the L1s of every port. If one l1 is down it tries to
--; get it up. The timeout is given in seconds. with 0 as value it
--; does not watch the l1 at all
--;
--; default value: 0
--;
--; this option is only read at loading time of chan_misdn,
--; which means you need to unload and load chan_misdn to change the
--; value, an asterisk restart should do the trick
--;
--l1watcher_timeout=0
--
- ; stops dialtone after getting first digit on nt Port
- ;
- ; default value: yes
- ;
- stop_tone_after_first_digit=yes
-
--; whether to append overlapdialed Digits to Extension or not
-+; whether to append overlapdialed Digits to Extension or not
- ;
- ; default value: yes
- ;
-@@ -122,19 +109,6 @@
- ;
- crypt_keys=test,muh
-
--; users sections:
--;
--; name your sections as you which but not "general" !
--; the sections are Groups, you can dial out in extensions.conf
--; with Dial(mISDN/g:extern/101) where extern is a section name,
--; chan_misdn tries every port in this section to find a
--; new free channel
--;
--
--; The default section is not a group section, it just contains config elements
--; which are inherited by group sections.
--;
--
- ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
- ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
- ; SIP channel. Defaults to "no". An enabled jitterbuffer will
-@@ -161,6 +135,17 @@
- ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
- ;-----------------------------------------------------------------------------------
-
-+; users sections:
-+;
-+; name your sections as you wish but not "general" or "default" !
-+; the sections are Groups, you can dial out in extensions.conf
-+; with Dial(mISDN/g:extern/101) where extern is a section name,
-+; chan_misdn tries every port in this section to find a
-+; new free channel
-+;
-+; The default section is not a group section, it just contains config elements
-+; which are inherited by group sections.
-+;
- [default]
-
- ; define your default context here
-@@ -182,7 +167,7 @@
-
- ;
- ; Either if we should produce DTMF Tones ourselves
--;
-+;
- senddtmf=yes
-
- ;
-@@ -205,14 +190,26 @@
- ;
- allowed_bearers=all
-
--; Prefixes for national and international, those are put before the
--; oad if an according dialplan is set by the other end.
-+; Prefixes for national and international Type-Of-Number. These are
-+; inserted before any number (caller, dialed, connected, redirecting,
-+; redirection) received from the ISDN link if that number has the
-+; correspondng Type-Of-Number.
-+; See the dialplan options.
- ;
--; default values: nationalprefix : 0
--; internationalprefix : 00
-+; default values:
-+; unknownprefix=
-+; internationalprefix=00
-+; nationalprefix=0
-+; netspecificprefix=
-+; subscriberprefix=
-+; abbreviatedprefix=
- ;
-+;unknownprefix=
-+internationalprefix=00
- nationalprefix=0
--internationalprefix=00
-+;netspecificprefix=
-+;subscriberprefix=
-+;abbreviatedprefix=
-
- ; set rx/tx gains between -8 and 8 to change the RX/TX Gain
- ;
-@@ -222,7 +219,7 @@
- rxgain=0
- txgain=0
-
--; some telcos especially in NL seem to need this set to yes, also in
-+; some telcos especially in NL seem to need this set to yes, also in
- ; switzerland this seems to be important
- ;
- ; default value: no
-@@ -232,7 +229,20 @@
-
-
- ;
--; This option defines, if chan_misdn should check the L1 on a PMP
-+; Monitors L1 of the port. If L1 is down it tries
-+; to bring it up. The polling timeout is given in seconds.
-+; Setting the value to 0 disables monitoring L1 of the port.
-+;
-+; default value: 0
-+;
-+; This option is only read at chan_misdn loading time.
-+; You need to unload and load chan_misdn to change the
-+; value. An asterisk restart will also do the trick.
-+;
-+l1watcher_timeout=0
-+
-+;
-+; This option defines, if chan_misdn should check the L1 on a PMP
- ; before making a group call on it. The L1 may go down for PMP Ports
- ; so we might need this.
- ; But be aware! a broken or plugged off cable might be used for a group call
-@@ -245,19 +255,19 @@
-
-
- ;
--; in PMP this option defines which cause should be sent out to
-+; in PMP this option defines which cause should be sent out to
- ; the 3. caller. chan_misdn does not support callwaiting on TE
--; PMP side. This allows to modify the RELEASE_COMPLETE cause
-+; PMP side. This allows to modify the RELEASE_COMPLETE cause
- ; at least.
- ;
- reject_cause=16
-
-
- ;
--; Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),
--; this requests additional Infos, so we can waitfordigits
-+; Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),
-+; this requests additional Infos, so we can waitfordigits
- ; without much issues. This works only for PTP Ports
--;
-+;
- ; default value: no
- ;
- need_more_infos=no
-@@ -279,30 +289,31 @@
- method=standard
-
-
--; specify if chan_misdn should collect digits before going into the
-+; specify if chan_misdn should collect digits before going into the
- ; dialplan, you can choose yes=4 Seconds, no, or specify the amount
- ; of seconds you need;
--;
-+;
- overlapdial=yes
-
- ;
--; dialplan means Type Of Number in ISDN Terms (for outgoing calls)
-+; dialplan means Type Of Number in ISDN Terms
-+; There are different types of the dialplan:
- ;
--; there are different types of the dialplan:
-+; dialplan -> for outgoing call's dialed number
-+; localdialplan -> for outgoing call's callerid
-+; (if -1 is set use the value from the asterisk channel)
-+; cpndialplan -> for incoming call's connected party number sent to caller
-+; (if -1 is set use the value from the asterisk channel)
- ;
--; dialplan -> outgoing Number
--; localdialplan -> callerid
--; cpndialplan -> connected party number
-+; dialplan options:
- ;
--; dialplan options:
--;
- ; 0 - unknown
- ; 1 - International
- ; 2 - National
-+; 3 - Network-Specific
- ; 4 - Subscriber
-+; 5 - Abbreviated
- ;
--; This setting is used for outgoing calls
--;
- ; default value: 0
- ;
- dialplan=0
-@@ -312,7 +323,7 @@
-
-
- ;
--; turn this to no if you don't mind correct handling of Progress Indicators
-+; turn this to no if you don't mind correct handling of Progress Indicators
- ;
- early_bconnect=yes
-
-@@ -320,16 +331,16 @@
- ;
- ; turn this on if you like to send Tone Indications to a Incoming
- ; isdn channel on a TE Port. Rarely used, only if the Telco allows
--; you to send indications by yourself, normally the Telco sends the
-+; you to send indications by yourself, normally the Telco sends the
- ; indications to the remote party.
--;
-+;
- ; default: no
- ;
- incoming_early_audio=no
-
- ; uncomment the following to get into s extension at extension conf
- ; there you can use DigitTimeout if you can't or don't want to use
--; isdn overlap dial.
-+; isdn overlap dial.
- ; note: This will jump into the s exten for every exten!
- ;
- ; default value: no
-@@ -337,7 +348,7 @@
- ;always_immediate=no
-
- ;
--; set this to yes if you want to generate your own dialtone
-+; set this to yes if you want to generate your own dialtone
- ; with always_immediate=yes, else chan_misdn generates the dialtone
- ;
- ; default value: no
-@@ -345,9 +356,9 @@
- nodialtone=no
-
-
--; uncomment the following if you want callers which called exactly the
-+; uncomment the following if you want callers which called exactly the
- ; base number (so no extension is set) jump to the s extension.
--; if the user dials something more it jumps to the correct extension
-+; if the user dials something more it jumps to the correct extension
- ; instead
- ;
- ; default value: no
-@@ -368,18 +379,40 @@
- ;callgroup=1
- ;pickupgroup=1
-
-+; Set the outgoing caller id to the value.
-+;callerid="name" <number>
-
- ;
- ; these are the exact isdn screening and presentation indicators
--; if -1 is given for both values the presentation indicators are used
--; from asterisks SetCallerPres application.
--; s=0, p=0 -> callerid presented not screened
--; s=1, p=1 -> callerid presented but screened (the remote end does not see it!)
--;
-+; if -1 is given for either value the presentation indicators are used
-+; from asterisks CALLERPRES function.
-+; s=0, p=0 -> callerid presented
-+; s=1, p=1 -> callerid restricted (the remote end does not see it!)
-+;
- ; default values s=-1, p=-1
- presentation=-1
- screen=-1
-
-+; 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.
-+;
-+display_connected=0
-+
-+; 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.
-+;
-+display_setup=0
-+
- ; This enables echo cancellation with the given number of taps.
- ; Be aware: Move this setting only to outgoing portgroups!
- ; A value of zero turns echo cancellation off.
-@@ -390,18 +423,9 @@
- ;
- ;echocancel=no
-
--; Set this to no to disable echotraining. You can enter a number > 10
--; the value is a multiple of 0.125 ms.
- ;
--; default value: no
--; yes = 2000
--; no = 0
-+; chan_misdns jitterbuffer, default 4000
- ;
--echotraining=no
--
--;
--; chan_misdns jitterbuffer, default 4000
--;
- jitterbuffer=4000
-
- ;
-@@ -411,7 +435,7 @@
-
-
- ;
--; change this to yes, if you want to bridge a mISDN data channel to
-+; change this to yes, if you want to bridge a mISDN data channel to
- ; another channel type or to an application.
- ;
- hdlc=no
-@@ -419,8 +443,8 @@
-
- ;
- ; defines the maximum amount of incoming calls per port for
--; this group. Calls which exceed the maximum will be marked with
--; the channel variable MAX_OVERFLOW. It will contain the amount of
-+; this group. Calls which exceed the maximum will be marked with
-+; the channel variable MAX_OVERFLOW. It will contain the amount of
- ; overflowed calls
- ;
- max_incoming=-1
-@@ -432,7 +456,7 @@
- max_outgoing=-1
-
- [intern]
--; define your ports, e.g. 1,2 (depends on mISDN-driver loading order)
-+; define your ports, e.g. 1,2 (depends on mISDN-driver loading order)
- ports=1,2
- ; context where to go to when incoming Call on one of the above ports
- context=Intern
-@@ -444,21 +468,21 @@
- ; configs. For backwards compatibility you can still set ptp here.
- ;
- ports=3
--
-+
- [first_extern]
- ; again port defs
- ports=4
- ; again a context for incoming calls
- context=Extern1
--; msns for te ports, listen on those numbers on the above ports, and
-+; msns for te ports, listen on those numbers on the above ports, and
- ; indicate the incoming calls to asterisk
--; here you can give a comma separated list or simply an '*' for
--; any msn.
-+; here you can give a comma separated list or simply an '*' for
-+; any msn.
- msns=*
-
- ; here an example with given msns
- [second_extern]
- ports=5
- context=Extern2
--callerid=15
-+callerid="Asterisk" <1234>
- msns=102,144,101,104
-Index: configs/phoneprov.conf.sample
-===================================================================
---- a/configs/phoneprov.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/phoneprov.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -53,8 +53,65 @@
- static_file => sip.ver,plain/text
- static_file => sip.cfg
- static_file => custom.cfg
--${TOLOWER(${MAC})}.cfg => 000000000000.cfg ; Dynamically generated files.
--${TOLOWER(${MAC})}-phone.cfg => 000000000000-phone.cfg ; (relative to AST_DATA_DIR/phoneprov)
--config/${TOLOWER(${MAC})} => polycom.xml ; Dynamic Filename => template file
--${TOLOWER(${MAC})}-directory.xml => 000000000000-directory.xml
-+static_file => 2201-06642-001.bootrom.ld,application/octet-stream
-+static_file => 2201-06642-001.sip.ld,application/octet-stream
-+static_file => 2345-11000-001.bootrom.ld,application/octet-stream
-+static_file => 2345-11300-001.bootrom.ld,application/octet-stream
-+static_file => 2345-11300-010.bootrom.ld,application/octet-stream
-+static_file => 2345-11300-010.sip.ld,application/octet-stream
-+static_file => 2345-11402-001.bootrom.ld,application/octet-stream
-+static_file => 2345-11402-001.sip.ld,application/octet-stream
-+static_file => 2345-11500-001.bootrom.ld,application/octet-stream
-+static_file => 2345-11500-010.bootrom.ld,application/octet-stream
-+static_file => 2345-11500-020.bootrom.ld,application/octet-stream
-+static_file => 2345-11500-030.bootrom.ld,application/octet-stream
-+static_file => 2345-11500-030.sip.ld,application/octet-stream
-+static_file => 2345-11500-040.bootrom.ld,application/octet-stream
-+static_file => 2345-11500-040.sip.ld,application/octet-stream
-+static_file => 2345-11600-001.bootrom.ld,application/octet-stream
-+static_file => 2345-11600-001.sip.ld,application/octet-stream
-+static_file => 2345-11605-001.bootrom.ld,application/octet-stream
-+static_file => 2345-11605-001.sip.ld,application/octet-stream
-+static_file => 2345-12200-001.bootrom.ld,application/octet-stream
-+static_file => 2345-12200-001.sip.ld,application/octet-stream
-+static_file => 2345-12200-002.bootrom.ld,application/octet-stream
-+static_file => 2345-12200-002.sip.ld,application/octet-stream
-+static_file => 2345-12200-004.bootrom.ld,application/octet-stream
-+static_file => 2345-12200-004.sip.ld,application/octet-stream
-+static_file => 2345-12200-005.bootrom.ld,application/octet-stream
-+static_file => 2345-12200-005.sip.ld,application/octet-stream
-+static_file => 2345-12500-001.bootrom.ld,application/octet-stream
-+static_file => 2345-12500-001.sip.ld,application/octet-stream
-+static_file => 2345-12560-001.bootrom.ld,application/octet-stream
-+static_file => 2345-12560-001.sip.ld,application/octet-stream
-+static_file => 2345-12600-001.bootrom.ld,application/octet-stream
-+static_file => 2345-12600-001.sip.ld,application/octet-stream
-+static_file => 2345-12670-001.bootrom.ld,application/octet-stream
-+static_file => 2345-12670-001.sip.ld,application/octet-stream
-+static_file => 3111-15600-001.bootrom.ld,application/octet-stream
-+static_file => 3111-15600-001.sip.ld,application/octet-stream
-+static_file => 3111-40000-001.bootrom.ld,application/octet-stream
-+static_file => 3111-40000-001.sip.ld,application/octet-stream
-+static_file => SoundPointIPWelcome.wav,application/octet-stream
-+static_file => SoundPointIPLocalization/Japanese_Japan/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Norwegian_Norway/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Spanish_Spain/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Portuguese_Portugal/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/English_United_Kingdom/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/English_United_States/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Russian_Russia/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Italian_Italy/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Chinese_China/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Swedish_Sweden/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/English_Canada/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/German_Germany/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/French_France/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Danish_Denmark/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Dutch_Netherlands/SoundPointIP-dictionary.xml
-+static_file => SoundPointIPLocalization/Korean_Korea/SoundPointIP-dictionary.xml
-+
-+${MAC}.cfg => 000000000000.cfg ; Dynamically generated files.
-+${MAC}-phone.cfg => 000000000000-phone.cfg ; (relative to AST_DATA_DIR/phoneprov)
-+config/${MAC} => polycom.xml ; Dynamic Filename => template file
-+${MAC}-directory.xml => 000000000000-directory.xml
- setvar => CUSTOM_CONFIG=/var/lib/asterisk/phoneprov/configs/custom.cfg ; Custom variable
-Index: configs/func_odbc.conf.sample
-===================================================================
---- a/configs/func_odbc.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/func_odbc.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -19,7 +19,7 @@
- ; inclusion in the SQL statement.
- ;
- ;
--; The following variables are available in this configuration file:
-+; The following options are available in this configuration file:
- ;
- ; readhandle A comma-separated list of DSNs (from res_odbc.conf) to use when
- ; executing the readsql statement. Each DSN is tried, in
-@@ -31,6 +31,8 @@
- ; readhandle. "dsn" is a synonym for "writehandle".
- ; readsql The statement to execute when reading from the function class.
- ; writesql The statement to execute when writing to the function class.
-+; insertsql The statement to execute when writing to the function class
-+; succeeds, but initially indicates that 0 rows were affected.
- ; prefix Normally, all function classes are prefixed with "ODBC" to keep
- ; them uniquely named. You may choose to change this prefix, which
- ; may be useful to segregate a collection of certain function
-@@ -42,6 +44,28 @@
- ; HASH(). If commas are not escaped, then values will be separated
- ; at the comma within fields. Please note that turning this option
- ; off is incompatible with the functionality of HASH().
-+; synopsis Appears in the synopsis field for the command
-+; 'core show function <function name>'
-+; mode This option may be set to 'multirow' to allow the function
-+; specified to return more than a single row. However, this
-+; changes the way that func_odbc normally works. Instead of the
-+; invocation of the function returning a row, it returns an opaque
-+; ID, which may be passed to ODBC_FETCH() to return each row in
-+; turn. ODBC_FETCH_STATUS returns SUCCESS or FAILURE, to indicate
-+; whether any results were stored, and you should call ODBC_Finish
-+; on the ID to clean up any remaining results when you are done
-+; with the query. Also, the variable ODBCROWS is set initially,
-+; which may be used in an iterative fashion to return each row in
-+; the result.
-+; Please note that multirow queries are isolated to the channel,
-+; and rows may not be fetched outside of the channel where the
-+; query was initially performed. Additionally, as the results are
-+; associated with a channel, mode=multirow is incompatible with
-+; the global space.
-+; rowlimit An additional option for within mode=multirow, rowlimit limits
-+; the total number of rows which can be stored for that query.
-+; Otherwise, func_odbc will attempt to store all rows in the
-+; resultset, up to the maximum amount of memory.
-
-
- ; ODBC_SQL - Allow an SQL statement to be built entirely in the dialplan
-@@ -57,21 +81,12 @@
- ; "writehandle", if it is important to separate reads and
- ; writes to different databases.
- readsql=SELECT COUNT(*) FROM exgirlfriends WHERE callerid='${SQL_ESC(${ARG1})}'
-+syntax=<callerid>
-+synopsis=Check if a specified callerid is contained in the ex-gf database
-
- ; ODBC_PRESENCE - Retrieve and update presence
- [PRESENCE]
- dsn=mysql1
- readsql=SELECT location FROM presence WHERE id='${SQL_ESC(${ARG1})}'
- writesql=UPDATE presence SET location='${SQL_ESC(${VAL1})}' WHERE id='${SQL_ESC(${ARG1})}'
--;prefix=OFFICE ; Changes this function from ODBC_PRESENCE to OFFICE_PRESENCE
--;escapecommas=no ; Normally, commas within a field are escaped such that each
-- ; field may be separated into individual variables with ARRAY.
-- ; This option turns that behavior off [default=yes].
--;mode=multirow ; Enable multirow fetching. Instead of returning results directly,
-- ; mode=multirow queries will return a result-id, which can be passed
-- ; multiple times to ODBC_FETCH, and that function will return each
-- ; row, in order. You can add to this the following parameter:
--;rowlimit=5 ; rowlimit will limit the number of rows retrieved and stored from
-- ; the database. If not specified, all rows, up to available memory,
-- ; will be retrieved and stored.
-
-Index: configs/musiconhold.conf.sample
-===================================================================
---- a/configs/musiconhold.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/musiconhold.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -29,6 +29,11 @@
- ; Files can be present in as many formats as you wish, and the
- ; 'best' format will be chosen at playback time.
- ;
-+; The path specified can be either an absolute path (starts with '/'),
-+; or a relative path; relative paths are interpreted as being relative
-+; to the 'astvarlibdir' in asterisk.conf, which defaults to
-+; /var/lib/asterisk.
-+;
- ; NOTE:
- ; If you are not using "autoload" in modules.conf, then you
- ; must ensure that the format modules for any formats you wish
-@@ -39,11 +44,11 @@
-
- [default]
- mode=files
--directory=/var/lib/asterisk/moh
-+directory=moh
- ;
- ;[native-random]
- ;mode=files
--;directory=/var/lib/asterisk/moh
-+;directory=moh
- ;digit=# ; If this option is set for a class, then when callers are
- ; ; listening to music on hold, they can press this digit, and
- ; ; they will switch to listening to this music class.
-@@ -51,7 +56,7 @@
-
- ;[native-alphabetical]
- ;mode=files
--;directory=/var/lib/asterisk/moh
-+;directory=moh
- ;sort=alpha ; Sort the files in alphabetical order. If this option is
- ; ; not specified, the sort order is undefined.
-
-Index: configs/res_ldap.conf.sample
-===================================================================
---- a/configs/res_ldap.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/res_ldap.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -56,7 +56,7 @@
- ; Sip Users Table
- ;
- [sip]
--name = uid
-+name = cn
- amaflags = AstAccountAMAFlags
- callgroup = AstAccountCallGroup
- callerid = AstAccountCallerID
-@@ -91,7 +91,7 @@
- ipaddr = AstAccountIPAddress
- defaultuser = AstAccountDefaultUser
- regserver = AstAccountRegistrationServer
--additionalFilter=(objectClass=AstAccountSIP)
-+additionalFilter=(objectClass=AsteriskSIPUser)
-
- ;
- ; IAX Users Table
-Index: configs/extensions.conf.sample
-===================================================================
---- a/configs/extensions.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/extensions.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -106,6 +106,14 @@
- ; that includes contexts within other contexts. The #include command works
- ; in all asterisk configuration files.
- ;#include "filename.conf"
-+;
-+; You can execute a program or script that produces config files, and they
-+; will be inserted where you insert the #exec command. The #exec command
-+; works on all asterisk configuration files. However, you will need to
-+; activate them within asterisk.conf with the "execincludes" option. They
-+; are otherwise considered a security risk.
-+;#exec /opt/bin/build-extra-contexts.sh
-+;
-
- ; The "Globals" category contains global variables that can be referenced
- ; in the dialplan with the GLOBAL dialplan function:
-@@ -137,8 +145,14 @@
- ;
- TRUNKMSD=1 ; MSD digits to strip (usually 1 or 0)
- ;TRUNK=IAX2/user:pass@provider
--
- ;
-+; WARNING WARNING WARNING WARNING
-+; If you load any other extension configuration engine, such as pbx_ael.so,
-+; your global variables may be overridden by that file. Please take care to
-+; use only one location to set global variables, and you will likely save
-+; yourself a ton of grief.
-+; WARNING WARNING WARNING WARNING
-+;
- ; Any category other than "General" and "Globals" represent
- ; extension contexts, which are collections of extensions.
- ;
-@@ -182,18 +196,17 @@
- ;
- ;[context]
- ;exten => someexten,{priority|label{+|-}offset}[(alias)],application(arg1,arg2,...)
--;exten => someexten,{priority|label{+|-}offset}[(alias)],application,arg1|arg2...
- ;
- ; Timing list for includes is
- ;
--; <time range>|<days of week>|<days of month>|<months>
-+; <time range>,<days of week>,<days of month>,<months>[,<timezone>]
- ;
- ; Note that ranges may be specified to wrap around the ends. Also, minutes are
- ; fine-grained only down to the closest even minute.
- ;
--;include => daytime|9:00-17:00|mon-fri|*|*
--;include => weekend|*|sat-sun|*|*
--;include => weeknights|17:02-8:58|mon-fri|*|*
-+;include => daytime,9:00-17:00,mon-fri,*,*
-+;include => weekend,*,sat-sun,*,*
-+;include => weeknights,17:02-8:58,mon-fri,*,*
- ;
- ; ignorepat can be used to instruct drivers to not cancel dialtone upon receipt
- ; of a particular pattern. The most commonly used example is of course '9'
-@@ -445,9 +458,9 @@
- exten => _X.,n,Set(LOCAL(cntx)=${ARG5})
-
- exten => _X.,n,Set(LOCAL(mbx)="${ext}"$["${cntx}" ? "@${cntx}" :: ""])
--exten => _X.,n,Dial(${dev},20|p) ; Ring the interface, 20 seconds maximum, call screening
-- ; option (or use P for databased call screening)
--exten => _X.,n,Goto(stdexten-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)
-+exten => _X.,n,Dial(${dev},20,p) ; Ring the interface, 20 seconds maximum, call screening
-+ ; option (or use P for databased call _X.creening)
-+exten => _X.,n,Goto(s-${DIALSTATUS},1) ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)
-
- exten => stdexten-NOANSWER,1,Voicemail(${mbx},u) ; If unavailable, send to voicemail w/ unavail announce
- exten => stdexten-NOANSWER,n,NoOp(Finish stdPrivacyexten NOANSWER)
-@@ -464,8 +477,7 @@
- exten => _stdexten-.,1,Goto(s-NOANSWER,1) ; Treat anything else as no answer
-
- exten => a,1,VoicemailMain(${mbx}) ; If they press *, send the user into VoicemailMain
--exten => a,n,Return()
-- ; does this ever return?
-+exten => a,n,Return
-
- [macro-page];
- ;
-@@ -475,12 +487,12 @@
- ;
- ; ${ARG1} - Device to page
-
--exten => s,1,ChanIsAvail(${ARG1}|js) ; j is for Jump and s is for ANY call
-+exten => s,1,ChanIsAvail(${ARG1},s) ; s is for ANY call
- exten => s,n,GoToIf([${AVAILSTATUS} = "1"]?autoanswer:fail)
- exten => s,n(autoanswer),Set(_ALERT_INFO="RA") ; This is for the PolyComs
- exten => s,n,SIPAddHeader(Call-Info: Answer-After=0) ; This is for the Grandstream, Snoms, and Others
- exten => s,n,NoOp() ; Add others here and Post on the Wiki!!!!
--exten => s,n,Dial(${ARG1}||)
-+exten => s,n,Dial(${ARG1})
- exten => s,n(fail),Hangup
-
-
-@@ -557,7 +569,7 @@
- ; System Wide Page at extension 7999
- ;
- exten => 7999,1,Set(TIMEOUT(absolute)=60)
--exten => 7999,2,Page(Local/Grandstream1@page&Local/Xlite1@page&Local/1234@page/n|d)
-+exten => 7999,2,Page(Local/Grandstream1@page&Local/Xlite1@page&Local/1234@page/n,d)
-
- ; Give voicemail at extension 8500
- ;
-@@ -630,11 +642,11 @@
- ;exten => 6275,1,Gosub(stdexten(6275,${MARK}))
- ; assuming ${MARK} is something like DAHDI/2
- ;exten => 6275,n,Goto(default,s,1) ; exited Voicemail
--;exten => mark,1,Goto(6275|1) ; alias mark to 6275
-+;exten => mark,1,Goto(6275,1) ; alias mark to 6275
- ;exten => 6536,1,Gosub(stdexten(6236,${WIL}))
- ; Ditto for wil
- ;exten => 6536,n,Goto(default,s,1) ; exited Voicemail
--;exten => wil,1,Goto(6236|1)
-+;exten => wil,1,Goto(6236,1)
-
- ;If you want to subscribe to the status of a parking space, this is
- ;how you do it. Subscribe to extension 6600 in sip, and you will see
-Index: configs/cli_aliases.conf.sample
-===================================================================
---- a/configs/cli_aliases.conf.sample (.../tags/1.6.1-rc1) (revision 0)
-+++ b/configs/cli_aliases.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,185 @@
-+;
-+; CLI Aliases configuration
-+;
-+; This module also registers a "cli show aliases" CLI command to list
-+; configured CLI aliases.
-+
-+[general]
-+; Here you define what alias templates you want to use. You can also define
-+; multiple templates to use as well. If you do, and there is a conflict, then
-+; the first alias defined will win.
-+;
-+template = friendly ; By default, include friendly aliases
-+;template = asterisk12 ; Asterisk 1.2 style syntax
-+;template = asterisk14 ; Asterisk 1.4 style syntax
-+;template = individual_custom ; see [individual_custom] example below which
-+ ; includes a list of aliases from an external
-+ ; file
-+
-+
-+; Because the Asterisk CLI syntax follows a "module verb argument" syntax,
-+; sometimes we run into an issue between being consistant with this format
-+; in the core system, and maintaining system friendliness. In order to get
-+; around this we're providing some useful aliases by default.
-+;
-+[friendly]
-+hangup request=channel request hangup
-+originate=channel originate
-+help=core show help
-+pri intense debug span=pri set debug 2 span
-+
-+; CLI Alias Templates
-+; -------------------
-+;
-+; You can define several alias templates.
-+; It works with context templates like all other configuration files
-+;
-+;[asterisk](!)
-+; To create an alias you simply set the variable name as the alias and variable
-+; value as the real CLI command you want executed
-+;
-+;die die die=stop now
-+
-+;[asterisk16](asterisk)
-+; Alias for making voicemail reload actually do module reload app_voicemail.so
-+;voicemail reload=module reload app_voicemail.so
-+; This will make the CLI command "mr" behave as though it is "module reload".
-+;mr=module reload
-+;
-+;
-+; In addition, you could also include a flat file of aliases which is loaded by
-+; the [individual_custom] template in the [general] section.
-+;
-+;[individual_custom]
-+;#include "/etc/asterisk/aliases"
-+
-+; Implemented CLI Alias Templates
-+; -------------------------------
-+;
-+; Below here we have provided you with some templates, easily allowing you to
-+; utilize previous Asterisk CLI commands with any version of Asterisk. In this
-+; way you will be able to use Asterisk 1.2 and 1.4 style CLI syntax with any
-+; version Asterisk going forward into the future.
-+;
-+; We have also separated out the vanilla syntax into a context template which
-+; allows you to keep your custom changes separate of the standard templates
-+; we have provided you. In this way you can clearly see your custom changes,
-+; and also allowing you to combine various templates as you see fit.
-+;
-+; The naming scheme we have used is recommended, but certainly is not enforced
-+; by Asterisk. If you wish to use the provided templates, simply define the
-+; context name which does not utilize the '_tpl' at the end. For example,
-+; if you would like to use the Asterisk 1.2 style syntax, define in the
-+; [general] section
-+
-+[asterisk12_tpl](!)
-+show channeltypes=core show channeltypes
-+show channeltype=core show channeltype
-+show manager command=manager show command
-+show manager commands=manager show commands
-+show manager connected=manager show connected
-+show manager eventq=manager show eventq
-+rtp no debug=rtp set debug off
-+rtp rtcp debug ip=rtcp debug ip
-+rtp rtcp debug=rtcp debug
-+rtp rtcp no debug=rtcp debug off
-+rtp rtcp stats=rtcp stats
-+rtp rtcp no stats=rtcp stats off
-+stun no debug=stun debug off
-+udptl no debug=udptl debug off
-+show image formats=core show image formats
-+show file formats=core show file formats
-+show applications=core show applications
-+show functions=core show functions
-+show switches=core show switches
-+show hints=core show hints
-+show globals=core show globals
-+show function=core show function
-+show application=core show application
-+set global=core set global
-+show dialplan=dialplan show
-+show codecs=core show codecs
-+show audio codecs=core show audio codecs
-+show video codecs=core show video codecs
-+show image codecs=core show image codecs
-+show codec=core show codec
-+moh classes show=moh show classes
-+moh files show=moh show files
-+agi no debug=agi debug off
-+show agi=agi show
-+dump agihtml=agi dumphtml
-+show features=feature show
-+show indications=indication show
-+answer=console answer
-+hangup=console hangup
-+flash=console flash
-+dial=console dial
-+mute=console mute
-+unmute=console unmute
-+transfer=console transfer
-+send text=console send text
-+autoanswer=console autoanswer
-+oss boost=console boost
-+console=console active
-+save dialplan=dialplan save
-+add extension=dialplan add extension
-+remove extension=dialplan remove extension
-+add ignorepat=dialplan add ignorepat
-+remove ignorepat=dialplan remove ignorepat
-+include context=dialplan add include
-+dont include=dialplan remove include
-+extensions reload=dialplan reload
-+show translation=core show translation
-+convert=file convert
-+show queue=queue show
-+add queue member=queue add member
-+remove queue member=queue remove member
-+ael no debug=ael nodebug
-+sip debug=sip set debug
-+sip no debug=sip set debug off
-+show voicemail users=voicemail show users
-+show voicemail zones=voicemail show zones
-+iax2 trunk debug=iax2 set debug trunk
-+iax2 jb debug=iax2 set debug jb
-+iax2 no debug=iax2 set debug off
-+iax2 no trunk debug=iax2 set debug trunk off
-+iax2 no jb debug=iax2 set debug jb off
-+show agents=agent show
-+show agents online=agent show online
-+show memory allocations=memory show allocations
-+show memory summary=memory show summary
-+show version=core show version
-+show version files=core show file version
-+show profile=core show profile
-+clear profile=core clear profile
-+
-+[asterisk12](asterisk12_tpl)
-+; add any additional custom commands you want below here, for example:
-+;die quickly=stop now
-+
-+[asterisk14_tpl](!)
-+cdr status=cdr show status
-+rtp debug=rtp set debug on
-+rtcp debug=rtcp set debug on
-+rtcp stats=rtcp set stats on
-+stun debug=stun set debug on
-+udptl debug=udptl set debug on
-+core show globals=dialplan show globals
-+core set global=dialplan set global
-+core set chanvar=dialplan set chanvar
-+agi dumphtml=agi dump html
-+ael debug=ael set debug
-+funcdevstate list=devstate list
-+sip history=sip set history on
-+skinny debug=skinny set debug on
-+mgcp set debug=mgcp set debug on
-+abort shutdown=core abort shutdown
-+stop now=core stop now
-+stop gracefully=core stop gracefully
-+stop when convenient=core stop when convenient
-+restart now=core restart now
-+restart gracefully=core restart gracefully
-+restart when convenient=core restart when convenient
-+
-+[asterisk14](asterisk14_tpl)
-+; add any additional custom commands you want below here.
-
-Property changes on: configs/cli_aliases.conf.sample
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: configs/cdr_adaptive_odbc.conf.sample
-===================================================================
---- a/configs/cdr_adaptive_odbc.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/cdr_adaptive_odbc.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -28,6 +28,7 @@
- ;[third]
- ;connection=sqlserver
- ;table=AsteriskCDR
-+;usegmtime=yes ; defaults to no
- ;alias src => source
- ;alias channel => source_channel
- ;alias dst => dest
-@@ -36,5 +37,26 @@
- ; Any filter specified MUST match exactly or the CDR will be discarded
- ;filter accountcode => somename
- ;filter src => 123
-+;
-+; Additionally, we now support setting static values per column. Reason
-+; for this is to allow different sections to specify different values for
-+; a certain named column, presumably separated by filters.
-+;static "Some Special Value" => identifier_code
-
-
-+; On Wednesday 10 September 2008 21:11:16 Tilghman Lesher wrote:
-+;
-+; I thought that the sample cdr_adaptive_odbc.conf was rather clear, but
-+; apparently not. The point of this module is to allow you log whatever you
-+; like in terms of the CDR variables. Do you want to log uniqueid? Then simply
-+; ensure that your table has that column. If you don't want the column, ensure
-+; that it does not exist in the table structure. If you'd like to call uniqueid
-+; something else in your table, simply provide an alias in the configuration
-+; file that maps the standard CDR field name (uniqueid) to whatever column
-+; name you like. Perhaps you'd like some extra CDR values logged that aren't
-+; in the standard repertoire of CDR variables (some that come to mind are
-+; certain values used for LCR: route, per_minute_cost, and per_minute_price).
-+; Simply set those CDR variables in your dialplan, i.e. Set(CDR(route)=27),
-+; ensure that a corresponding column exists in your table, and cdr_adaptive_odbc
-+; will do the rest.
-+
-Index: configs/followme.conf.sample
-===================================================================
---- a/configs/followme.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/followme.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -13,23 +13,23 @@
- ; The global default keypress for the callee to decline taking the current call. This can
- ; be a single digit or multiple digits. Default is "2".
- ;
--call-from-prompt=>followme/call-from
-+call_from_prompt=>followme/call-from
- ; The global default for the 'Incoming call from' message.
- ;
--norecording-prompt=>followme/no-recording
-+norecording_prompt=>followme/no-recording
- ; The global default for the 'You have an incoming call' message when the caller elects
- ; not to leave their name or the option isn't set for them to do so.
- ;
--options-prompt=>followme/options
-+options_prompt=>followme/options
- ; The global default for the 'Press 1 to accept this call or press 2 to decline it' message.
- ;
--pls-hold-prompt=>followme/pls-hold-while-try
-+pls_hold_prompt=>followme/pls-hold-while-try
- ; The global default for 'Please hold while we try and connect your call' message.
- ;
--status-prompt=>followme/status
-+status_prompt=>followme/status
- ; The global default for 'The party you're calling isn't at their desk' message.
- ;
--sorry-prompt=>followme/sorry
-+sorry_prompt=>followme/sorry
- ; The global default for 'I'm sorry, but we were unable to locate your party' message.
- ;
- ;
-@@ -59,27 +59,27 @@
- ; The keypress for the callee to decline taking the current call. This can
- ; be a single digit or multiple digits. Default is the global default.
- ;
--call-from-prompt=>followme/call-from
-+call_from_prompt=>followme/call-from
- ; The 'Incoming call from' message prompt. Default is the global default.
- ;
--followme-norecording-prompt=>followme/no-recording
-+norecording_prompt=>followme/no-recording
- ; The 'You have an incoming call' message prompt when the caller elects
- ; not to leave their name or the option isn't set for them to do so. Default
- ; is the global default.
- ;
--followme-options-prompt=>followme/options
-+options_prompt=>followme/options
- ; The 'Press 1 to accept this call or press 2 to decline it' message prompt.
- ; Default is the global default.
- ;
--followme-pls-hold-prompt=>followme/pls-hold-while-try
-+pls_hold_prompt=>followme/pls-hold-while-try
- ; The 'Please hold while we try and connect your call' message prompt.
- ; Default is the global default.
- ;
--followme-status-prompt=>followme/status
-+status_prompt=>followme/status
- ; The 'The party you're calling isn't at their desk' message prompt.
- ; Default is the global default.
- ;
--followme-sorry-prompt=>followme/sorry
-+sorry_prompt=>followme/sorry
- ; The 'I'm sorry, but we were unable to locate your party' message prompt. Default
- ; is the global default.
-
-Index: configs/chan_dahdi.conf.sample
-===================================================================
---- a/configs/chan_dahdi.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/chan_dahdi.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -1,27 +1,22 @@
- ;
--; DAHDI telephony
-+; DAHDI Telephony Configuration file
- ;
--; Configuration file
--;
- ; You need to restart Asterisk to re-configure the DAHDI channel
--; CLI> module reload chan_dahdi.so
--; will reload the configuration file,
--; but not all configuration options are
--; re-configured during a reload (signalling, as well as
--; PRI and SS7-related settings cannot be changed on a
--; reload.
-+; CLI> module reload chan_dahdi.so
-+; will reload the configuration file, but not all configuration options
-+; are re-configured during a reload (signalling, as well as PRI and
-+; SS7-related settings cannot be changed on a reload).
- ;
--; This file documents many configuration variables. Normally unless you
--; know what a variable means or that it should be changed, there's no
--; reason to unrem lines.
-+; This file documents many configuration variables. Normally unless you know
-+; what a variable means or that it should be changed, there's no reason to
-+; un-comment those lines.
- ;
--; remmed-out examples below (those lines that begin with a ';' but no
--; space afterwards) typically show a value that is not the defauult value,
--; but would make sense under cetain circumstances. The default values
--; are usually sane. Thus you should typically not touch them unless you
--; know what they mean or you know you should change them.
-+; Examples below that are commented out (those lines that begin with a ';' but
-+; no space afterwards) typically show a value that is not the default value,
-+; but would make sense under certain circumstances. The default values are
-+; usually sane. Thus you should typically not touch them unless you know what
-+; they mean or you know you should change them.
-
--
- [trunkgroups]
- ;
- ; Trunk groups are used for NFAS or GR-303 connections.
-@@ -40,7 +35,7 @@
- ; Spanmap: Associates a span with a trunk group
- ; spanmap => <dahdispan>,<trunkgroup>[,<logicalspan>]
- ;
--; dahdispan is the DAHDI span number to associate
-+; dahdispan is the DAHDI span number to associate
- ; trunkgroup is the trunkgroup (specified above) for the mapping
- ; logicalspan is the logical span number within the trunk group to use.
- ; if unspecified, no logical span number is used.
-@@ -62,13 +57,13 @@
- ;
- ; Switchtype: Only used for PRI.
- ;
--; national: National ISDN 2 (default)
--; dms100: Nortel DMS100
--; 4ess: AT&T 4ESS
--; 5ess: Lucent 5ESS
--; euroisdn: EuroISDN (common in Europe)
--; ni1: Old National ISDN 1
--; qsig: Q.SIG
-+; national: National ISDN 2 (default)
-+; dms100: Nortel DMS100
-+; 4ess: AT&T 4ESS
-+; 5ess: Lucent 5ESS
-+; euroisdn: EuroISDN (common in Europe)
-+; ni1: Old National ISDN 1
-+; qsig: Q.SIG
- ;
- ;switchtype=euroisdn
- ;
-@@ -185,6 +180,20 @@
- ;
- ;priexclusive = yes
- ;
-+;
-+; If you need to use the logical channel mapping with your Q.SIG PRI instead
-+; of the physical mapping you must use the qsigchannelmapping option.
-+;
-+; logical: Use the logical channel mapping
-+; physical: Use physical channel mapping (default)
-+;
-+;qsigchannelmapping=logical
-+;
-+; If you wish to ignore remote hold indications (and use MOH that is supplied over
-+; the B channel) enable this option.
-+;
-+;discardremoteholdretrieval=yes
-+;
- ; ISDN Timers
- ; All of the ISDN timers and counters that are used are configurable. Specify
- ; the timer name, and its value (in ms for timers).
-@@ -221,8 +230,8 @@
- ; featdmf_ta: Feature Group D (The real thing, MF (domestic, US)) through
- ; a Tandem Access point
- ; featb: Feature Group B (MF (domestic, US))
--; fgccama Feature Group C-CAMA (DP DNIS, MF ANI)
--; fgccamamf Feature Group C-CAMA MF (MF DNIS, MF ANI)
-+; fgccama: Feature Group C-CAMA (DP DNIS, MF ANI)
-+; fgccamamf: Feature Group C-CAMA MF (MF DNIS, MF ANI)
- ; fxs_ls: FXS (Loop Start)
- ; fxs_gs: FXS (Ground Start)
- ; fxs_ks: FXS (Kewl Start)
-@@ -233,8 +242,8 @@
- ; pri_net: PRI signalling, Network side
- ; gr303fxoks_net: GR-303 Signalling, FXO Loopstart, Network side
- ; gr303fxsks_cpe: GR-303 Signalling, FXS Loopstart, CPE side
--; sf: SF (Inband Tone) Signalling
--; sf_w: SF Wink
-+; sf: SF (Inband Tone) Signalling
-+; sf_w: SF Wink
- ; sf_featd: SF Feature Group D (The fake, Adtran style, DTMF)
- ; sf_featdmf: SF Feature Group D (The real thing, MF (domestic, US))
- ; sf_featb: SF Feature Group B (MF (domestic, US))
-@@ -319,7 +328,7 @@
- ; enable dring detection after caller ID for those countries like Australia
- ; where the ring cadence is changed *after* the caller ID spill:
- ;
--;distinctiveringaftercid=yes
-+;distinctiveringaftercid=yes
- ;
- ; Whether or not to use caller ID:
- ;
-@@ -352,6 +361,13 @@
- ;
- ;hidecallerid=yes
- ;
-+; On UK analog lines, the caller hanging up determines the end of calls. So
-+; Asterisk hanging up the line may or may not end a call (DAHDI could just as
-+; easily be re-attaching to a prior incoming call that was not yet hung up).
-+; This option changes the hangup to wait for a dialtone on the line, before
-+; marking the line as once again available for use with outgoing calls.
-+;waitfordialtone=yes
-+;
- ; The following option enables receiving MWI on FXO lines. The default
- ; value is no.
- ; The mwimonitor can take the following values
-@@ -378,6 +394,17 @@
- ;
- ;mwimonitornotify=/usr/local/bin/dahdinotify.sh
- ;
-+; The following keyword 'mwisendtype' enables various VMWI methods on FXS lines (if supported).
-+; The default is to send FSK only.
-+; The following options are available;
-+; 'rpas' Ring Pulse Alert Signal, alerts intelligent phones that a FSK message is about to be sent.
-+; 'lrev' Line reversed to indicate messages waiting.
-+; 'hvdc' 90Vdc OnHook DC voltage to indicate messages waiting.
-+; 'hvac' or 'neon' 90Vac OnHook AC voltage to light Neon bulb.
-+; 'nofsk' Disables FSK MWI spills from being sent out.
-+; It is feasible that multiple options can be enabled.
-+;mwisendtype=rpas,lrev
-+;
- ; Whether or not to enable call waiting on internal extensions
- ; With this set to 'yes', busy extensions will hear the call-waiting
- ; tone, and can use hook-flash to switch between callers. The Dial()
-@@ -388,12 +415,14 @@
- ; Whether or not restrict outgoing caller ID (will be sent as ANI only, not
- ; available for the user)
- ; Mostly use with FXS ports
-+; Does nothing. Use hidecallerid instead.
- ;
- ;restrictcid=no
- ;
--; Whether or not use the caller ID presentation for the outgoing call that the
--; calling switch is sending.
--; See README.callingpres. FIXME: file no longer exists.
-+; Whether or not to use the caller ID presentation from the Asterisk channel
-+; for outgoing calls.
-+; See dialplan function CALLERID(pres) for more information.
-+; Only applies to PRI and SS7 channels.
- ;
- usecallingpres=yes
- ;
-@@ -706,6 +735,15 @@
- ;faxdetect=outgoing
- ;faxdetect=no
- ;
-+; When 'faxdetect' is used, one could use 'faxbuffers' to configure the DAHDI
-+; transmit buffer policy. The default is *OFF*. When this configuration
-+; option is used, the faxbuffer policy will be used for the life of the call
-+; after a fax tone is detected. The faxbuffer policy is reverted after the
-+; call is torn down. The sample below will result in 6 buffers and a full
-+; buffer policy.
-+;
-+;faxbuffers=>6,full
-+;
- ; This option specifies a preference for which music on hold class this channel
- ; should listen to when put on hold if the music class has not been set on the
- ; channel with Set(CHANNEL(musicclass)=whatever) in the dialplan, and the peer
-@@ -886,9 +924,9 @@
- ;
- ; unknown: Unknown
- ; subscriber: Subscriber
--; national: National
-+; national: National
- ; international: International
--; dynamic: Dynamically selects the appropriate dialplan
-+; dynamic: Dynamically selects the appropriate dialplan
- ;
- ;ss7_called_nai=dynamic
- ;
-@@ -896,9 +934,9 @@
- ;
- ; unknown: Unknown
- ; subscriber: Subscriber
--; national: National
-+; national: National
- ; international: International
--; dynamic: Dynamically selects the appropriate dialplan
-+; dynamic: Dynamically selects the appropriate dialplan
- ;
- ;ss7_calling_nai=dynamic
- ;
-Index: configs/queues.conf.sample
-===================================================================
---- a/configs/queues.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/queues.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -365,25 +365,58 @@
- ; The contents of MONITOR_FILENAME will also be unescaped from ^{X} to ${X} and
- ; all variables will be evaluated just prior to recording being started.
- ;
-+; ---------------------- Queue Empty Options ----------------------------------
- ;
--; This setting controls whether callers can join a queue with no members. There
--; are three choices:
-+; Asterisk has provided the "joinempty" and "leavewhenempty" options for a while
-+; with tenuous definitions of what they actually mean. The "joinempty" option controls
-+; whether a caller may join a queue depending on several factors of member availability.
-+; Similarly, then leavewhenempty option controls whether a caller may remain in a queue
-+; he has already joined. Both options take a comma-separated list of factors which
-+; contribute towards whether a caller may join/remain in the queue. The list of
-+; factors which contribute to these option is as follows:
-+;
-+; paused: a member is not considered available if he is paused
-+; penalty: a member is not considered available if his penalty is less than QUEUE_MAX_PENALTY
-+; inuse: a member is not considered available if he is currently on a call
-+; ringing: a member is not considered available if his phone is currently ringing
-+; unavailable: This applies mainly to Agent channels. If the agent is a member of the queue
-+; but has not logged in, then do not consider the member to be available
-+; invalid: Do not consider a member to be available if he has an "invalid" device state.
-+; This generally is caused by an error condition in the member's channel driver.
-+; unknown: Do not consider a member to be available if we are unable to determine the member's
-+; current device state.
-+; wrapup: A member is not considered available if he is currently in his wrapuptime after
-+; taking a call.
-+;
-+; For the "joinempty" option, when a caller attempts to enter a queue, the members of that
-+; queue are examined. If all members are deemed to be unavailable due to any of the conditions
-+; listed for the "joinempty" option, then the caller will be unable to enter the queue. For the
-+; "leavewhenempty" option, the state of the members of the queue are checked periodically during
-+; the caller's stay in the queue. If all of the members are unavailable due to any of the above
-+; conditions, then the caller will be removed from the queue.
-+;
-+; Some examples:
- ;
--; yes - callers can join a queue with no members or only unavailable members
--; no - callers cannot join a queue with no members
--; strict - callers cannot join a queue with no members or only unavailable
--; members
--; loose - same as strict, but paused queue members do not count as unavailable
-+;joinempty = paused,inuse,invalid
- ;
--; joinempty = yes
-+; A caller will not be able to enter a queue if at least one member cannot be found
-+; who is not paused, on the phone, or who has an invalid device state.
- ;
-+;leavewhenempty = inuse,ringing
- ;
--; If you wish to remove callers from the queue when new callers cannot join,
--; set this setting to one of the same choices for 'joinempty'
-+; A caller will be removed from the queue if at least one member cannot be found
-+; who is not on the phone, or whose phone is not ringing.
- ;
--; leavewhenempty = yes
-+; For the sake of backwards-compatibility, the joinempty and leavewhenempty
-+; options also accept the strings "yes" "no" "strict" and "loose". The following
-+; serves as a translation for these values:
- ;
-+; yes - (empty) for joinempty; penalty,paused,invalid for leavewhenempty
-+; no - penalty,paused,invalid for joinempty; (empty) for leavewhenempty
-+; strict - penalty,paused,invalid,unavailable
-+; loose - penalty,invalid
- ;
-+
- ; If this is set to yes, the following manager events will be generated:
- ; AgentCalled, AgentDump, AgentConnect, AgentComplete; setting this to
- ; vars also sends all channel variables with the event.
-Index: configs/cdr.conf.sample
-===================================================================
---- a/configs/cdr.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/cdr.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -65,6 +65,15 @@
- ; retrieved inside of of this extension.
- ;endbeforehexten=no
-
-+; Normally, the 'billsec' field logged to the backends (text files or databases)
-+; is simply the end time (hangup time) minus the answer time in seconds. Internally,
-+; asterisk stores the time in terms of microseconds and seconds. By setting
-+; initiatedseconds to 'yes', you can force asterisk to report any seconds
-+; that were initiated (a sort of round up method). Technically, this is
-+; when the microsecond part of the end time is greater than the microsecond
-+; part of the answer time, then the billsec time is incremented one second.
-+;initiatedseconds=no
-+
- ;
- ;
- ; CHOOSING A CDR "BACKEND" (what kind of output to generate)
-Index: configs/features.conf.sample
-===================================================================
---- a/configs/features.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/features.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -23,6 +23,10 @@
- ; one of: callee, caller, both, no (default is no)
- ;parkedcallreparking = caller ; Enables or disables DTMF based parking when picking up a parked call.
- ; one of: callee, caller, both, no (default is no)
-+;parkedcallhangup = caller ; Enables or disables DTMF based hangups when picking up a parked call.
-+ ; one of: callee, caller, both, no (default is no)
-+;parkedcallrecording = caller ; Enables or disables DTMF based one-touch recording when picking up a parked call.
-+ ; one of: callee, caller, both, no (default is no)
- ;adsipark = yes ; if you want ADSI parking announcements
- ;findslot => next ; Continue to the 'next' free parking space.
- ; Defaults to 'first' available
-@@ -35,8 +39,10 @@
- ;xfersound = beep ; to indicate an attended transfer is complete
- ;xferfailsound = beeperr ; to indicate a failed transfer
- ;pickupexten = *8 ; Configure the pickup extension. (default is *8)
--;featuredigittimeout = 500 ; Max time (ms) between digits for
-- ; feature activation (default is 500 ms)
-+;pickupsound = beep ; to indicate a successful pickup (default: no sound)
-+;pickupfailsound = beeperr ; to indicate that the pickup failed (default: no sound)
-+;featuredigittimeout = 2000 ; Max time (ms) between digits for
-+ ; feature activation (default is 2000 ms)
- ;atxfernoanswertimeout = 15 ; Timeout for answer on attended transfer default is 15 seconds.
- ;atxferdropcall = no ; If someone does an attended transfer, then hangs up before the transferred
- ; caller is connected, then by default, the system will try to call back the
-Index: configs/res_odbc.conf.sample
-===================================================================
---- a/configs/res_odbc.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/res_odbc.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -47,6 +47,13 @@
- password => thegrouch
- pre-connect => yes
- sanitysql => select count(*) from systables
-+; forcecommit => no ; Default to committing uncommitted transactions?
-+; isolation => read_committed ; Isolation level; supported levels are:
-+ ; read_uncommitted, read_committed, repeatable_read,
-+ ; serializable. Note that not all databases support
-+ ; all isolation levels (e.g. Postgres only supports
-+ ; repeatable_read and serializable). See database
-+ ; documentation for further information.
- ;
- ; Many databases have a default of '\' to escape special characters. MS SQL
- ; Server does not.
-Index: configs/jabber.conf.sample
-===================================================================
---- a/configs/jabber.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/jabber.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -1,7 +1,9 @@
- [general]
- ;debug=yes ;;Turn on debugging by default.
--;autoprune=yes ;;Auto remove users from buddy list.
--;autoregister=yes ;;Auto register users from buddy list.
-+;autoprune=yes ;;Auto remove users from buddy list. Depending on your
-+ ;;setup (ie, using your personal Gtalk account for a test)
-+ ;;you might lose your contacts list. Default is 'no'.
-+;autoregister=yes ;;Auto register users from buddy list.
-
- ;[asterisk] ;;label
- ;type=client ;;Client or Component connection
-Index: configs/res_snmp.conf.sample
-===================================================================
---- a/configs/res_snmp.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/res_snmp.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -1,6 +1,17 @@
- ;
- ; Configuration file for res_snmp
-+;---------------------------------
- ;
-+; Res_snmp can run as a subagent or standalone SNMP agent. The standalone snmp
-+; agent is based on net-snmp and will read a configuration file called
-+; asterisk.conf in the net-snmp configuration file path, starting with
-+; /etc/snmp on many systems.
-+;
-+; If you use the subagent model, you need to enable agentx in snmpd.conf
-+; Note that you can only run one Asterisk on the system in this case.
-+;
-+; Please read documentat in doc/snmp.txt to get more information about
-+; snmp support in Asterisk
-
- [general]
- ; We run as a subagent per default -- to run as a full agent
-Index: configs/extconfig.conf.sample
-===================================================================
---- a/configs/extconfig.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/extconfig.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -60,5 +60,18 @@
- ;queues => odbc,asterisk
- ;queue_members => odbc,asterisk
- ;musiconhold => mysql,asterisk
--;queue_log => mysql,aasterisk
-+;queue_log => mysql,asterisk
-+;
-+;
-+; While most dynamic realtime engines are automatically used when defined in
-+; this file, 'extensions', distinctively, is not. To activate dynamic realtime
-+; extensions, you must turn them on in each respective context within
-+; extensions.conf with a switch statement. The syntax is:
-+; switch => Realtime/[[db_context@]tablename]/<opts>
-+; The only option available currently is the 'p' option, which disallows
-+; extension pattern queries to the database. If you have no patterns defined
-+; in a particular context, this will save quite a bit of CPU time. However,
-+; note that using dynamic realtime extensions is not recommended anymore as a
-+; best practice; instead, you should consider writing a static dialplan with
-+; proper data abstraction via a tool like func_odbc.
-
-Index: configs/modules.conf.sample
-===================================================================
---- a/configs/modules.conf.sample (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/configs/modules.conf.sample (.../team/group/issue14292) (revision 178988)
-@@ -18,9 +18,6 @@
- ;preload => res_odbc.so
- ;preload => res_config_odbc.so
- ;
--; res_phoneprov requires func_strings.so to be loaded:
--preload => func_strings.so
--;
- ; Uncomment the following if you wish to use the Speech Recognition API
- ;preload => res_speech.so
- ;
-Index: makeopts.in
-===================================================================
---- a/makeopts.in (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/makeopts.in (.../team/group/issue14292) (revision 178988)
-@@ -24,6 +24,7 @@
- DOWNLOAD=@DOWNLOAD@
- RUBBER=@RUBBER@
- KPATHSEA=@KPATHSEA@
-+XMLSTARLET=@XMLSTARLET@
- MD5=@MD5@
-
- BUILD_PLATFORM=@BUILD_PLATFORM@
-@@ -69,8 +70,8 @@
- AST_SHADOW_WARNINGS=@AST_SHADOW_WARNINGS@
- AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@
-
--ASOUND_INCLUDE=@ALSA_INCLUDE@
--ASOUND_LIB=@ALSA_LIB@
-+ALSA_INCLUDE=@ALSA_INCLUDE@
-+ALSA_LIB=@ALSA_LIB@
-
- CURL_INCLUDE=@CURL_INCLUDE@
- CURL_LIB=@CURL_LIB@
-@@ -84,6 +85,9 @@
- FREETDS_INCLUDE=@FREETDS_INCLUDE@
- FREETDS_LIB=@FREETDS_LIB@
-
-+GENERIC_ODBC_INCLUDE=@GENERIC_ODBC_INCLUDE@
-+GENERIC_ODBC_LIB=@GENERIC_ODBC_LIB@
-+
- GMIME_INCLUDE=@GMIME_INCLUDE@
- GMIME_LIB=@GMIME_LIB@
-
-@@ -108,6 +112,9 @@
- IMAP_TK_INCLUDE=@IMAP_TK_INCLUDE@
- IMAP_TK_LIB=@IMAP_TK_LIB@
-
-+IODBC_INCLUDE=@IODBC_INCLUDE@
-+IODBC_LIB=@IODBC_LIB@
-+
- JACK_INCLUDE=@JACK_INCLUDE@
- JACK_LIB=@JACK_LIB@
-
-@@ -138,8 +145,8 @@
-
- # ossaudio can optionally use ffmpeg, x11, sdl and sdl_image.
- # Because sdl_image in turn depends on sdl, we don't duplicate the include
--OSSAUDIO_INCLUDE=@OSS_INCLUDE@ @FFMPEG_INCLUDE@ @SDL_INCLUDE@ @X11_INCLUDE@
--OSSAUDIO_LIB=@OSS_LIB@ @FFMPEG_LIB@ @SDL_LIB@ @SDL_IMAGE_LIB@ @X11_LIB@
-+OSS_INCLUDE=@OSS_INCLUDE@ @FFMPEG_INCLUDE@ @SDL_INCLUDE@ @X11_INCLUDE@
-+OSS_LIB=@OSS_LIB@ @FFMPEG_LIB@ @SDL_LIB@ @SDL_IMAGE_LIB@ @X11_LIB@
-
- PGSQL_INCLUDE=@PGSQL_INCLUDE@
- PGSQL_LIB=@PGSQL_LIB@
-@@ -195,8 +202,8 @@
- SQLITE3_INCLUDE=@SQLITE3_INCLUDE@
- SQLITE3_LIB=@SQLITE3_LIB@
-
--SSL_INCLUDE=@OPENSSL_INCLUDE@
--SSL_LIB=@OPENSSL_LIB@
-+OPENSSL_INCLUDE=@OPENSSL_INCLUDE@
-+OPENSSL_LIB=@OPENSSL_LIB@
-
- CRYPTO_INCLUDE=@CRYPTO_INCLUDE@
- CRYPTO_LIB=@CRYPTO_LIB@
-@@ -213,8 +220,8 @@
- VORBIS_INCLUDE=@VORBIS_INCLUDE@
- VORBIS_LIB=@VORBIS_LIB@
-
--VPBAPI_INCLUDE=@VPB_INCLUDE@
--VPBAPI_LIB=@VPB_LIB@
-+VPB_INCLUDE=@VPB_INCLUDE@
-+VPB_LIB=@VPB_LIB@
-
- DAHDI_INCLUDE=@DAHDI_INCLUDE@
-
-@@ -240,9 +247,13 @@
- TERMCAP_LIB=@TERMCAP_LIB@
- TERMCAP_DIR=@TERMCAP_DIR@
-
-+LIBXML2_INCLUDE=@LIBXML2_INCLUDE@
-+LIBXML2_LIB=@LIBXML2_LIB@
-+
- TINFO_INCLUDE=@TINFO_INCLUDE@
- TINFO_LIB=@TINFO_LIB@
- TINFO_DIR=@TINFO_DIR@
-
- # if poll is not present, let the makefile know.
- POLL_AVAILABLE=@HAS_POLL@
-+TIMERFD_INCLUDE=@TIMERFD_INCLUDE@
-Index: res/res_config_sqlite.c
-===================================================================
---- a/res/res_config_sqlite.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_config_sqlite.c (.../team/group/issue14292) (revision 178988)
-@@ -123,6 +123,9 @@
- } \
- MACRO_END
-
-+AST_THREADSTORAGE(sql_buf);
-+AST_THREADSTORAGE(where_buf);
-+
- /*!
- * Maximum number of loops before giving up executing a query. Calls to
- * sqlite_xxx() functions which can return SQLITE_BUSY
-@@ -299,7 +302,7 @@
- * \retval 0 if an error occurred.
- */
- static size_t get_params(va_list ap, const char ***params_ptr,
-- const char ***vals_ptr);
-+ const char ***vals_ptr, int warn);
-
- /*!
- * \brief SQLite callback function for RealTime configuration.
-@@ -396,6 +399,8 @@
- */
- static int realtime_update_handler(const char *database, const char *table,
- const char *keyfield, const char *entity, va_list ap);
-+static int realtime_update2_handler(const char *database, const char *table,
-+ va_list ap);
-
- /*!
- * \brief Asterisk callback function for RealTime configuration (variable
-@@ -484,6 +489,7 @@
- .store_func = realtime_store_handler,
- .destroy_func = realtime_destroy_handler,
- .update_func = realtime_update_handler,
-+ .update2_func = realtime_update2_handler,
- .require_func = realtime_require_handler,
- .unload_func = realtime_unload_handler,
- };
-@@ -733,7 +739,7 @@
-
- config = ast_config_load(RES_CONFIG_SQLITE_CONF_FILE, config_flags);
-
-- if (!config) {
-+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_ERROR, "Unable to load " RES_CONFIG_SQLITE_CONF_FILE "\n");
- return 1;
- }
-@@ -783,6 +789,7 @@
- struct sqlite_cache_tables *tbl = find_table(cdr_table);
- struct sqlite_cache_columns *col;
- struct ast_str *sql1 = ast_str_create(160), *sql2 = ast_str_create(16);
-+ int first = 1;
-
- if (!tbl) {
- ast_log(LOG_WARNING, "No such table: %s\n", cdr_table);
-@@ -799,33 +806,32 @@
- continue;
- }
- if (sscanf(tmp, "%d", &scannum) == 1) {
-- ast_str_append(&sql1, 0, "%s,", col->name);
-- ast_str_append(&sql2, 0, "%d,", scannum);
-+ ast_str_append(&sql1, 0, "%s%s", first ? "" : ",", col->name);
-+ ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", scannum);
- }
- } else {
- ast_cdr_getvar(cdr, col->name, &tmp, workspace, sizeof(workspace), 0, 0);
- if (!tmp) {
- continue;
- }
-- ast_str_append(&sql1, 0, "%s,", col->name);
-+ ast_str_append(&sql1, 0, "%s%s", first ? "" : ",", col->name);
- tmp = sqlite_mprintf("%Q", tmp);
-- ast_str_append(&sql2, 0, "%s,", tmp);
-+ ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", tmp);
- sqlite_freemem(tmp);
- }
-+ first = 0;
- }
- release_table(tbl);
-
-- sql1->str[--sql1->used] = '\0';
-- sql2->str[--sql2->used] = '\0';
-- ast_str_append(&sql1, 0, "%s)", sql2->str);
-+ ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
- ast_free(sql2);
-
-- ast_debug(1, "SQL query: %s\n", sql1->str);
-+ ast_debug(1, "SQL query: %s\n", ast_str_buffer(sql1));
-
- ast_mutex_lock(&mutex);
-
- RES_CONFIG_SQLITE_BEGIN
-- error = sqlite_exec(db, sql1->str, NULL, NULL, &errormsg);
-+ error = sqlite_exec(db, ast_str_buffer(sql1), NULL, NULL, &errormsg);
- RES_CONFIG_SQLITE_END(error)
-
- ast_mutex_unlock(&mutex);
-@@ -951,7 +957,7 @@
- return cfg;
- }
-
--static size_t get_params(va_list ap, const char ***params_ptr, const char ***vals_ptr)
-+static size_t get_params(va_list ap, const char ***params_ptr, const char ***vals_ptr, int warn)
- {
- const char **tmp, *param, *val, **params, **vals;
- size_t params_count;
-@@ -983,8 +989,9 @@
- if (params_count > 0) {
- *params_ptr = params;
- *vals_ptr = vals;
-- } else
-+ } else if (warn) {
- ast_log(LOG_WARNING, "1 parameter and 1 value at least required\n");
-+ }
-
- return params_count;
- }
-@@ -1031,7 +1038,7 @@
- return NULL;
- }
-
-- params_count = get_params(ap, &params, &vals);
-+ params_count = get_params(ap, &params, &vals, 1);
-
- if (params_count == 0)
- return NULL;
-@@ -1040,10 +1047,10 @@
-
- /* \cond DOXYGEN_CAN_PARSE_THIS */
- #undef QUERY
--#define QUERY "SELECT * FROM '%q' WHERE commented = 0 AND %q%s '%q'"
-+#define QUERY "SELECT * FROM '%q' WHERE%s %q%s '%q'"
- /* \endcond */
-
-- query = sqlite_mprintf(QUERY, table, params[0], op, vals[0]);
-+ query = sqlite_mprintf(QUERY, table, !strcmp(config_table, table) ? " commented = 0 AND" : "", params[0], op, vals[0]);
-
- if (!query) {
- ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
-@@ -1176,7 +1183,7 @@
- return NULL;
- }
-
-- if (!(params_count = get_params(ap, &params, &vals))) {
-+ if (!(params_count = get_params(ap, &params, &vals, 1))) {
- ast_config_destroy(cfg);
- return NULL;
- }
-@@ -1288,7 +1295,7 @@
- return -1;
- }
-
-- if (!(params_count = get_params(ap, &params, &vals)))
-+ if (!(params_count = get_params(ap, &params, &vals, 1)))
- return -1;
-
- /* \cond DOXYGEN_CAN_PARSE_THIS */
-@@ -1357,6 +1364,80 @@
- return rows_num;
- }
-
-+static int realtime_update2_handler(const char *database, const char *table,
-+ va_list ap)
-+{
-+ char *errormsg = NULL, *tmp1, *tmp2;
-+ int error, rows_num, first = 1;
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
-+ struct ast_str *where = ast_str_thread_get(&where_buf, 100);
-+ const char *param, *value;
-+
-+ if (!table) {
-+ ast_log(LOG_WARNING, "Table name unspecified\n");
-+ return -1;
-+ }
-+
-+ if (!sql) {
-+ return -1;
-+ }
-+
-+ ast_str_set(&sql, 0, "UPDATE %s SET", table);
-+ ast_str_set(&where, 0, " WHERE");
-+
-+ while ((param = va_arg(ap, const char *))) {
-+ value = va_arg(ap, const char *);
-+ ast_str_append(&where, 0, "%s %s = %s",
-+ first ? "" : " AND",
-+ tmp1 = sqlite_mprintf("%q", param),
-+ tmp2 = sqlite_mprintf("%Q", value));
-+ sqlite_freemem(tmp1);
-+ sqlite_freemem(tmp2);
-+ first = 0;
-+ }
-+
-+ if (first) {
-+ ast_log(LOG_ERROR, "No criteria specified on update to '%s@%s'!\n", table, database);
-+ return -1;
-+ }
-+
-+ first = 1;
-+ while ((param = va_arg(ap, const char *))) {
-+ value = va_arg(ap, const char *);
-+ ast_str_append(&sql, 0, "%s %s = %s",
-+ first ? "" : ",",
-+ tmp1 = sqlite_mprintf("%q", param),
-+ tmp2 = sqlite_mprintf("%Q", value));
-+ sqlite_freemem(tmp1);
-+ sqlite_freemem(tmp2);
-+ first = 0;
-+ }
-+
-+ ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
-+ ast_debug(1, "SQL query: %s\n", ast_str_buffer(sql));
-+
-+ ast_mutex_lock(&mutex);
-+
-+ RES_CONFIG_SQLITE_BEGIN
-+ error = sqlite_exec(db, ast_str_buffer(sql), NULL, NULL, &errormsg);
-+ RES_CONFIG_SQLITE_END(error)
-+
-+ if (!error) {
-+ rows_num = sqlite_changes(db);
-+ } else {
-+ rows_num = -1;
-+ }
-+
-+ ast_mutex_unlock(&mutex);
-+
-+ if (error) {
-+ ast_log(LOG_WARNING, "%s\n", S_OR(errormsg, sqlite_error_string(error)));
-+ }
-+ sqlite_freemem(errormsg);
-+
-+ return rows_num;
-+}
-+
- static int realtime_store_handler(const char *database, const char *table, va_list ap)
- {
- char *errormsg = NULL, *tmp_str, *tmp_keys = NULL, *tmp_keys2 = NULL, *tmp_vals = NULL, *tmp_vals2 = NULL;
-@@ -1370,7 +1451,7 @@
- return -1;
- }
-
-- if (!(params_count = get_params(ap, &params, &vals)))
-+ if (!(params_count = get_params(ap, &params, &vals, 1)))
- return -1;
-
- /* \cond DOXYGEN_CAN_PARSE_THIS */
-@@ -1394,10 +1475,10 @@
- }
-
- if ( tmp_vals2 ) {
-- tmp_vals = sqlite_mprintf("%s, '%q'", tmp_vals2, params[i]);
-+ tmp_vals = sqlite_mprintf("%s, '%q'", tmp_vals2, vals[i]);
- sqlite_freemem(tmp_vals2);
- } else {
-- tmp_vals = sqlite_mprintf("'%q'", params[i]);
-+ tmp_vals = sqlite_mprintf("'%q'", vals[i]);
- }
- if (!tmp_vals) {
- ast_log(LOG_WARNING, "Unable to reallocate SQL query\n");
-@@ -1455,7 +1536,7 @@
- const char *keyfield, const char *entity, va_list ap)
- {
- char *query, *errormsg = NULL, *tmp_str;
-- const char **params, **vals;
-+ const char **params = NULL, **vals = NULL;
- size_t params_count;
- int error, rows_num;
- size_t i;
-@@ -1465,8 +1546,7 @@
- return -1;
- }
-
-- if (!(params_count = get_params(ap, &params, &vals)))
-- return -1;
-+ params_count = get_params(ap, &params, &vals, 0);
-
- /* \cond DOXYGEN_CAN_PARSE_THIS */
- #undef QUERY
-@@ -1511,10 +1591,11 @@
- error = sqlite_exec(db, query, NULL, NULL, &errormsg);
- RES_CONFIG_SQLITE_END(error)
-
-- if (!error)
-+ if (!error) {
- rows_num = sqlite_changes(db);
-- else
-+ } else {
- rows_num = -1;
-+ }
-
- ast_mutex_unlock(&mutex);
-
-@@ -1654,7 +1735,7 @@
- static int unload_module(void)
- {
- if (cli_status_registered)
-- ast_cli_unregister_multiple(cli_status, sizeof(cli_status) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_status, ARRAY_LEN(cli_status));
-
- if (cdr_registered)
- ast_cdr_unregister(RES_CONFIG_SQLITE_NAME);
-@@ -1769,7 +1850,7 @@
- cdr_registered = 1;
- }
-
-- error = ast_cli_register_multiple(cli_status, sizeof(cli_status) / sizeof(struct ast_cli_entry));
-+ error = ast_cli_register_multiple(cli_status, ARRAY_LEN(cli_status));
-
- if (error) {
- unload_module();
-Index: res/res_config_odbc.c
-===================================================================
---- a/res/res_config_odbc.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_config_odbc.c (.../team/group/issue14292) (revision 178988)
-@@ -29,8 +29,6 @@
- */
-
- /*** MODULEINFO
-- <depend>unixodbc</depend>
-- <depend>ltdl</depend>
- <depend>res_odbc</depend>
- ***/
-
-@@ -47,6 +45,8 @@
- #include "asterisk/res_odbc.h"
- #include "asterisk/utils.h"
-
-+AST_THREADSTORAGE(sql_buf);
-+
- struct custom_prepare_struct {
- const char *sql;
- const char *extra;
-@@ -476,7 +476,148 @@
- return -1;
- }
-
-+struct update2_prepare_struct {
-+ const char *database;
-+ const char *table;
-+ va_list ap;
-+};
-+
-+static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
-+{
-+ int res, x = 1, first = 1;
-+ struct update2_prepare_struct *ups = data;
-+ const char *newparam, *newval;
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
-+ SQLHSTMT stmt;
-+ va_list ap;
-+ struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
-+ struct odbc_cache_columns *column;
-+
-+ if (!sql) {
-+ if (tableptr) {
-+ ast_odbc_release_table(tableptr);
-+ }
-+ return NULL;
-+ }
-+
-+ if (!tableptr) {
-+ ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'. Update will fail!\n", ups->table, ups->database);
-+ return NULL;
-+ }
-+
-+ 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_odbc_release_table(tableptr);
-+ return NULL;
-+ }
-+
-+ ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
-+
-+ /* Start by finding the second set of parameters */
-+ va_copy(ap, ups->ap);
-+
-+ while ((newparam = va_arg(ap, const char *))) {
-+ newval = va_arg(ap, const char *);
-+ }
-+
-+ while ((newparam = va_arg(ap, const char *))) {
-+ newval = va_arg(ap, const char *);
-+ if ((column = ast_odbc_find_column(tableptr, newparam))) {
-+ ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
-+ SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
-+ first = 0;
-+ } else {
-+ ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
-+ }
-+ }
-+ va_end(ap);
-+
-+ /* Restart search, because we need to add the search parameters */
-+ va_copy(ap, ups->ap);
-+ ast_str_append(&sql, 0, "WHERE");
-+ first = 1;
-+
-+ while ((newparam = va_arg(ap, const char *))) {
-+ newval = va_arg(ap, const char *);
-+ if (!(column = ast_odbc_find_column(tableptr, newparam))) {
-+ ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", newparam, ups->table, ups->database);
-+ ast_odbc_release_table(tableptr);
-+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-+ return NULL;
-+ }
-+ ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
-+ SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
-+ first = 0;
-+ }
-+ va_end(ap);
-+
-+ /* Done with the table metadata */
-+ ast_odbc_release_table(tableptr);
-+
-+ res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
-+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-+ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
-+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-+ return NULL;
-+ }
-+
-+ return stmt;
-+}
-+
- /*!
-+ * \brief Execute an UPDATE query
-+ * \param database
-+ * \param table
-+ * \param ap list containing one or more field/value set(s).
-+ *
-+ * Update a database table, preparing the sql statement from a list of
-+ * key/value pairs specified in ap. The lookup pairs are specified first
-+ * and are separated from the update pairs by a sentinel value.
-+ * Sub-in the values to the prepared statement and execute it.
-+ *
-+ * \retval number of rows affected
-+ * \retval -1 on failure
-+*/
-+static int update2_odbc(const char *database, const char *table, va_list ap)
-+{
-+ struct odbc_obj *obj;
-+ SQLHSTMT stmt;
-+ struct update2_prepare_struct ups = { .database = database, .table = table, };
-+ struct ast_str *sql;
-+ int res;
-+ SQLLEN rowcount = 0;
-+
-+ va_copy(ups.ap, ap);
-+
-+ if (!(obj = ast_odbc_request_obj(database, 0))) {
-+ return -1;
-+ }
-+
-+ if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
-+ ast_odbc_release_obj(obj);
-+ return -1;
-+ }
-+
-+ res = SQLRowCount(stmt, &rowcount);
-+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-+ ast_odbc_release_obj(obj);
-+
-+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-+ /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
-+ sql = ast_str_thread_get(&sql_buf, 16);
-+ ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
-+ return -1;
-+ }
-+
-+ if (rowcount >= 0) {
-+ return (int)rowcount;
-+ }
-+
-+ return -1;
-+}
-+
-+/*!
- * \brief Excute an INSERT query
- * \param database
- * \param table
-@@ -901,6 +1042,7 @@
- .store_func = store_odbc,
- .destroy_func = destroy_odbc,
- .update_func = update_odbc,
-+ .update2_func = update2_odbc,
- .require_func = require_odbc,
- .unload_func = ast_odbc_clear_cache,
- };
-Index: res/res_timing_pthread.c
-===================================================================
---- a/res/res_timing_pthread.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_timing_pthread.c (.../team/group/issue14292) (revision 178988)
-@@ -45,10 +45,12 @@
- static void pthread_timer_ack(int handle, unsigned int quantity);
- static int pthread_timer_enable_continuous(int handle);
- static int pthread_timer_disable_continuous(int handle);
--static enum ast_timing_event pthread_timer_get_event(int handle);
-+static enum ast_timer_event pthread_timer_get_event(int handle);
- static unsigned int pthread_timer_get_max_rate(int handle);
-
--static struct ast_timing_functions pthread_timing_functions = {
-+static struct ast_timing_interface pthread_timing = {
-+ .name = "pthread",
-+ .priority = 0, /* use this as a last resort */
- .timer_open = pthread_timer_open,
- .timer_close = pthread_timer_close,
- .timer_set_rate = pthread_timer_set_rate,
-@@ -250,10 +252,10 @@
- return 0;
- }
-
--static enum ast_timing_event pthread_timer_get_event(int handle)
-+static enum ast_timer_event pthread_timer_get_event(int handle)
- {
- struct pthread_timer *timer;
-- enum ast_timing_event res = AST_TIMING_EVENT_EXPIRED;
-+ enum ast_timer_event res = AST_TIMING_EVENT_EXPIRED;
-
- if (!(timer = find_timer(handle, 0))) {
- return res;
-@@ -486,22 +488,26 @@
- return AST_MODULE_LOAD_DECLINE;
- }
-
-- return (timing_funcs_handle = ast_install_timing_functions(&pthread_timing_functions)) ?
-+ return (timing_funcs_handle = ast_register_timing_interface(&pthread_timing)) ?
- AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
- }
-
- static int unload_module(void)
- {
--#if 0
-- /* XXX code to stop the timing thread ... */
-+ int res;
-
-- ast_uninstall_timing_functions(timing_funcs_handle);
-- ao2_ref(pthread_timers, -1);
--#endif
-+ ast_mutex_lock(&timing_thread.lock);
-+ timing_thread.stop = 1;
-+ ast_cond_signal(&timing_thread.cond);
-+ ast_mutex_unlock(&timing_thread.lock);
-+ pthread_join(timing_thread.thread, NULL);
-
-- /* This module can not currently be unloaded. No use count handling is being done. */
-+ if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
-+ ao2_ref(pthread_timers, -1);
-+ pthread_timers = NULL;
-+ }
-
-- return -1;
-+ return res;
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "pthread Timing Interface");
-Index: res/res_agi.c
-===================================================================
---- a/res/res_agi.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_agi.c (.../team/group/issue14292) (revision 178988)
-@@ -21,6 +21,8 @@
- * \brief AGI - the Asterisk Gateway Interface
- *
- * \author Mark Spencer <markster@digium.com>
-+ *
-+ * \todo Convert the rest of the AGI commands over to XML documentation
- */
-
- #include "asterisk.h"
-@@ -51,14 +53,256 @@
- #include "asterisk/utils.h"
- #include "asterisk/lock.h"
- #include "asterisk/strings.h"
--#include "asterisk/agi.h"
- #include "asterisk/manager.h"
- #include "asterisk/ast_version.h"
- #include "asterisk/speech.h"
- #include "asterisk/manager.h"
- #include "asterisk/features.h"
-+#include "asterisk/term.h"
-+#include "asterisk/xmldoc.h"
-
-+#define AST_API_MODULE
-+#include "asterisk/agi.h"
-+
-+/*** DOCUMENTATION
-+ <agi name="answer" language="en_US">
-+ <synopsis>
-+ Answer channel
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Answers channel if not already in answer state. Returns <literal>-1</literal> on
-+ channel failure, or <literal>0</literal> if successful.</para>
-+ </description>
-+ <see-also>
-+ <ref type="agi">hangup</ref>
-+ </see-also>
-+ </agi>
-+ <agi name="channel status" language="en_US">
-+ <synopsis>
-+ Returns status of the connected channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channelname" />
-+ </syntax>
-+ <description>
-+ <para>Returns the status of the specified <replaceable>channelname</replaceable>.
-+ If no channel name is given then returns the status of the current channel.</para>
-+ <para>Return values:</para>
-+ <enumlist>
-+ <enum name="0">
-+ <para>Channel is down and available.</para>
-+ </enum>
-+ <enum name="1">
-+ <para>Channel is down, but reserved.</para>
-+ </enum>
-+ <enum name="2">
-+ <para>Channel is off hook.</para>
-+ </enum>
-+ <enum name="3">
-+ <para>Digits (or equivalent) have been dialed.</para>
-+ </enum>
-+ <enum name="4">
-+ <para>Line is ringing.</para>
-+ </enum>
-+ <enum name="5">
-+ <para>Remote end is ringing.</para>
-+ </enum>
-+ <enum name="6">
-+ <para>Line is up.</para>
-+ </enum>
-+ <enum name="7">
-+ <para>Line is busy.</para>
-+ </enum>
-+ </enumlist>
-+ </description>
-+ </agi>
-+ <agi name="database del" language="en_US">
-+ <synopsis>
-+ Removes database key/value
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Deletes an entry in the Asterisk database for a given
-+ <replaceable>family</replaceable> and <replaceable>key</replaceable>.</para>
-+ <para>Returns <literal>1</literal> if successful, <literal>0</literal>
-+ otherwise.</para>
-+ </description>
-+ </agi>
-+ <agi name="database deltree" language="en_US">
-+ <synopsis>
-+ Removes database keytree/value
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="keytree" />
-+ </syntax>
-+ <description>
-+ <para>Deletes a <replaceable>family</replaceable> or specific <replaceable>keytree</replaceable>
-+ within a <replaceable>family</replaceable> in the Asterisk database.</para>
-+ <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
-+ </description>
-+ </agi>
-+ <agi name="database get" language="en_US">
-+ <synopsis>
-+ Gets database value
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Retrieves an entry in the Asterisk database for a given <replaceable>family</replaceable>
-+ and <replaceable>key</replaceable>.</para>
-+ <para>Returns <literal>0</literal> if <replaceable>key</replaceable> is not set.
-+ Returns <literal>1</literal> if <replaceable>key</replaceable> is set and returns the variable
-+ in parenthesis.</para>
-+ <para>Example return code: 200 result=1 (testvariable)</para>
-+ </description>
-+ </agi>
-+ <agi name="database put" language="en_US">
-+ <synopsis>
-+ Adds/updates database value
-+ </synopsis>
-+ <syntax>
-+ <parameter name="family" required="true" />
-+ <parameter name="key" required="true" />
-+ <parameter name="value" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Adds or updates an entry in the Asterisk database for a given
-+ <replaceable>family</replaceable>, <replaceable>key</replaceable>, and
-+ <replaceable>value</replaceable>.</para>
-+ <para>Returns <literal>1</literal> if successful, <literal>0</literal> otherwise.</para>
-+ </description>
-+ </agi>
-+ <agi name="exec" language="en_US">
-+ <synopsis>
-+ Executes a given Application
-+ </synopsis>
-+ <syntax>
-+ <parameter name="application" required="true" />
-+ <parameter name="options" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Executes <replaceable>application</replaceable> with given
-+ <replaceable>options</replaceable>.</para>
-+ <para>Returns whatever the <replaceable>application</replaceable> returns, or
-+ <literal>-2</literal> on failure to find <replaceable>application</replaceable>.</para>
-+ </description>
-+ </agi>
-+ <agi name="get data" language="en_US">
-+ <synopsis>
-+ Prompts for DTMF on a channel
-+ </synopsis>
-+ <syntax>
-+ <parameter name="file" required="true" />
-+ <parameter name="timeout" />
-+ <parameter name="maxdigits" />
-+ </syntax>
-+ <description>
-+ <para>Stream the given <replaceable>file</replaceable>, and recieve DTMF data.</para>
-+ <para>Returns the digits received from the channel at the other end.</para>
-+ </description>
-+ </agi>
-+ <agi name="get full variable" language="en_US">
-+ <synopsis>
-+ Evaluates a channel expression
-+ </synopsis>
-+ <syntax>
-+ <parameter name="variablename" required="true" />
-+ <parameter name="channel name" />
-+ </syntax>
-+ <description>
-+ <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set
-+ or channel does not exist. Returns <literal>1</literal> if <replaceable>variablename</replaceable>
-+ is set and returns the variable in parenthesis. Understands complex variable names and builtin
-+ variables, unlike GET VARIABLE.</para>
-+ <para>Example return code: 200 result=1 (testvariable)</para>
-+ </description>
-+ </agi>
-+ <agi name="get option" language="en_US">
-+ <synopsis>
-+ Stream file, prompt for DTMF, with timeout.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="filename" required="true" />
-+ <parameter name="escape_digits" required="true" />
-+ <parameter name="timeout" />
-+ </syntax>
-+ <description>
-+ <para>Behaves similar to STREAM FILE but used with a timeout option.</para>
-+ </description>
-+ <see-also>
-+ <ref type="agi">stream file</ref>
-+ </see-also>
-+ </agi>
-+ <agi name="get variable" language="en_US">
-+ <synopsis>
-+ Gets a channel variable.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="variablename" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Returns <literal>0</literal> if <replaceable>variablename</replaceable> is not set.
-+ Returns <literal>1</literal> if <replaceable>variablename</replaceable> is set and returns
-+ the variable in parentheses.</para>
-+ <para>Example return code: 200 result=1 (testvariable)</para>
-+ </description>
-+ </agi>
-+ <agi name="hangup" language="en_US">
-+ <synopsis>
-+ Hangup the current channel.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="channelname" />
-+ </syntax>
-+ <description>
-+ <para>Hangs up the specified channel. If no channel name is given, hangs
-+ up the current channel</para>
-+ </description>
-+ </agi>
-+ <agi name="noop" language="en_US">
-+ <synopsis>
-+ Does nothing.
-+ </synopsis>
-+ <syntax />
-+ <description>
-+ <para>Does nothing.</para>
-+ </description>
-+ </agi>
-+ <agi name="set music" language="en_US">
-+ <synopsis>
-+ Enable/Disable Music on hold generator
-+ </synopsis>
-+ <syntax>
-+ <parameter required="true">
-+ <enumlist>
-+ <enum>
-+ <parameter name="on" literal="true" required="true" />
-+ </enum>
-+ <enum>
-+ <parameter name="off" literal="true" required="true" />
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ <parameter name="class" required="true" />
-+ </syntax>
-+ <description>
-+ <para>Enables/Disables the music on hold generator. If <replaceable>class</replaceable>
-+ is not specified, then the <literal>default</literal> music on hold class will be
-+ used.</para>
-+ <para>Always returns <literal>0</literal>.</para>
-+ </description>
-+ </agi>
-+ ***/
-+
- #define MAX_ARGS 128
-+#define MAX_CMD_LEN 80
- #define AGI_NANDFS_RETRY 3
- #define AGI_BUF_LEN 2048
-
-@@ -87,7 +331,7 @@
- "AGISIGHUP channel variable to \"no\" before executing the AGI application.\n"
- " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
- "on file descriptor 3.\n\n"
--" Use the CLI command 'agi show' to list available agi commands.\n"
-+" Use the CLI command 'agi show commnands' to list available agi commands.\n"
- " This application sets the following channel variable upon completion:\n"
- " AGISTATUS The status of the attempt to the run the AGI script\n"
- " text string, one of SUCCESS | FAILURE | NOTFOUND | HANGUP\n";
-@@ -135,13 +379,13 @@
-
- if (agidebug) {
- if (chan) {
-- ast_verbose("<%s>AGI Tx >> %s", chan->name, buf->str);
-+ ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
- } else {
-- ast_verbose("AGI Tx >> %s", buf->str);
-+ ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
- }
- }
-
-- return ast_carefulwrite(fd, buf->str, buf->used, 100);
-+ return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
- }
-
- /* linked list of AGI commands ready to be executed by Async AGI */
-@@ -1618,12 +1862,12 @@
- }
-
- do {
-- res = ast_db_get(argv[2], argv[3], buf->str, buf->len);
-- buf->used = strlen(buf->str);
-- if (buf->used < buf->len - 1) {
-+ res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
-+ ast_str_update(buf);
-+ if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
- break;
- }
-- if (ast_str_make_space(&buf, buf->len * 2)) {
-+ if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
- break;
- }
- } while (1);
-@@ -1631,7 +1875,7 @@
- if (res)
- ast_agi_send(agi->fd, chan, "200 result=0\n");
- else
-- ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf->str);
-+ ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
-
- ast_free(buf);
- return RESULT_SUCCESS;
-@@ -2004,93 +2248,19 @@
- return RESULT_SUCCESS;
- }
-
--static char usage_setmusic[] =
--" Usage: SET MUSIC ON <on|off> <class>\n"
--" Enables/Disables the music on hold generator. If <class> is\n"
--" not specified, then the default music on hold class will be used.\n"
--" Always returns 0.\n";
--
--static char usage_dbput[] =
--" Usage: DATABASE PUT <family> <key> <value>\n"
--" Adds or updates an entry in the Asterisk database for a\n"
--" given family, key, and value.\n"
--" Returns 1 if successful, 0 otherwise.\n";
--
--static char usage_dbget[] =
--" Usage: DATABASE GET <family> <key>\n"
--" Retrieves an entry in the Asterisk database for a\n"
--" given family and key.\n"
--" Returns 0 if <key> is not set. Returns 1 if <key>\n"
--" is set and returns the variable in parentheses.\n"
--" Example return code: 200 result=1 (testvariable)\n";
--
--static char usage_dbdel[] =
--" Usage: DATABASE DEL <family> <key>\n"
--" Deletes an entry in the Asterisk database for a\n"
--" given family and key.\n"
--" Returns 1 if successful, 0 otherwise.\n";
--
--static char usage_dbdeltree[] =
--" Usage: DATABASE DELTREE <family> [keytree]\n"
--" Deletes a family or specific keytree within a family\n"
--" in the Asterisk database.\n"
--" Returns 1 if successful, 0 otherwise.\n";
--
- static char usage_verbose[] =
- " Usage: VERBOSE <message> <level>\n"
- " Sends <message> to the console via verbose message system.\n"
- " <level> is the the verbose level (1-4)\n"
- " Always returns 1.\n";
-
--static char usage_getvariable[] =
--" Usage: GET VARIABLE <variablename>\n"
--" Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
--" is set and returns the variable in parentheses.\n"
--" example return code: 200 result=1 (testvariable)\n";
--
--static char usage_getvariablefull[] =
--" Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
--" Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
--"if <variablename> is set and returns the variable in parenthesis. Understands\n"
--"complex variable names and builtin variables, unlike GET VARIABLE.\n"
--" example return code: 200 result=1 (testvariable)\n";
--
- static char usage_setvariable[] =
- " Usage: SET VARIABLE <variablename> <value>\n";
-
--static char usage_channelstatus[] =
--" Usage: CHANNEL STATUS [<channelname>]\n"
--" Returns the status of the specified channel.\n"
--" If no channel name is given the returns the status of the\n"
--" current channel. Return values:\n"
--" 0 Channel is down and available\n"
--" 1 Channel is down, but reserved\n"
--" 2 Channel is off hook\n"
--" 3 Digits (or equivalent) have been dialed\n"
--" 4 Line is ringing\n"
--" 5 Remote end is ringing\n"
--" 6 Line is up\n"
--" 7 Line is busy\n";
--
- static char usage_setcallerid[] =
- " Usage: SET CALLERID <number>\n"
- " Changes the callerid of the current channel.\n";
-
--static char usage_exec[] =
--" Usage: EXEC <application> <options>\n"
--" Executes <application> with given <options>.\n"
--" Returns whatever the application returns, or -2 on failure to find application\n";
--
--static char usage_hangup[] =
--" Usage: HANGUP [<channelname>]\n"
--" Hangs up the specified channel.\n"
--" If no channel name is given, hangs up the current channel\n";
--
--static char usage_answer[] =
--" Usage: ANSWER\n"
--" Answers channel if not already in answer state. Returns -1 on\n"
--" channel failure, or 0 if successful.\n";
--
- static char usage_waitfordigit[] =
- " Usage: WAIT FOR DIGIT <timeout>\n"
- " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
-@@ -2152,10 +2322,6 @@
- " extension must not be included in the filename.\n\n"
- " Note: ffchar and rewchar default to * and # respectively.\n";
-
--static char usage_getoption[] =
--" Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
--" Behaves similar to STREAM FILE but used with a timeout option.\n";
--
- static char usage_saynumber[] =
- " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
- " Say a given number, returning early if any of the given DTMF digits\n"
-@@ -2211,11 +2377,6 @@
- " completes without a digit pressed, the ASCII numerical value of the digit\n"
- " if one was pressed, or -1 on error/hangup.\n";
-
--static char usage_getdata[] =
--" Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
--" Stream the given file, and recieve DTMF data. Returns the digits received\n"
--"from the channel at the other end.\n";
--
- static char usage_setcontext[] =
- " Usage: SET CONTEXT <desired context>\n"
- " Sets the context for continuation upon exiting the application.\n";
-@@ -2247,10 +2408,6 @@
- " future. Of course it can be hungup before then as well. Setting to 0 will\n"
- " cause the autohangup feature to be disabled on this channel.\n";
-
--static char usage_noop[] =
--" Usage: NoOp\n"
--" Does nothing.\n";
--
- static char usage_speechcreate[] =
- " Usage: SPEECH CREATE <engine>\n"
- " Create a speech object to be used by the other Speech AGI commands.\n";
-@@ -2287,19 +2444,19 @@
- * \brief AGI commands list
- */
- static struct agi_command commands[] = {
-- { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
-- { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
-- { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
-- { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
-- { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
-- { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput , 1 },
-- { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec , 1 },
-- { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata , 0 },
-- { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull , 1 },
-- { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption , 0 },
-- { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable , 1 },
-- { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup , 0 },
-- { { "noop", NULL }, handle_noop, "Does nothing", usage_noop , 1 },
-+ { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
-+ { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
-+ { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
-+ { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
-+ { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
-+ { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
-+ { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
-+ { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
-+ { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
-+ { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
-+ { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
-+ { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
-+ { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
- { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
- { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
- { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
-@@ -2316,7 +2473,7 @@
- { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
- { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
- { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
-- { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic , 0 },
-+ { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
- { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
- { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
- { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
-@@ -2338,7 +2495,7 @@
-
- static char *help_workhorse(int fd, char *match[])
- {
-- char fullcmd[80], matchstr[80];
-+ char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
- struct agi_command *e;
-
- if (match)
-@@ -2364,11 +2521,21 @@
-
- int ast_agi_register(struct ast_module *mod, agi_command *cmd)
- {
-- char fullcmd[80];
-+ char fullcmd[MAX_CMD_LEN];
-
- ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
-
-- if (!find_command(cmd->cmda,1)) {
-+ if (!find_command(cmd->cmda,1)) {
-+ cmd->docsrc = AST_STATIC_DOC;
-+#ifdef AST_XML_DOCS
-+ if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
-+ cmd->summary = ast_xmldoc_build_synopsis("agi", fullcmd);
-+ cmd->usage = ast_xmldoc_build_description("agi", fullcmd);
-+ cmd->syntax = ast_xmldoc_build_syntax("agi", fullcmd);
-+ cmd->seealso = ast_xmldoc_build_seealso("agi", fullcmd);
-+ cmd->docsrc = AST_XML_DOC;
-+ }
-+#endif
- cmd->mod = mod;
- AST_RWLIST_WRLOCK(&agi_commands);
- AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
-@@ -2387,7 +2554,7 @@
- {
- struct agi_command *e;
- int unregistered = 0;
-- char fullcmd[80];
-+ char fullcmd[MAX_CMD_LEN];
-
- ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
-
-@@ -2397,6 +2564,16 @@
- AST_RWLIST_REMOVE_CURRENT(list);
- if (mod != ast_module_info->self)
- ast_module_unref(ast_module_info->self);
-+#ifdef AST_XML_DOCS
-+ if (e->docsrc == AST_XML_DOC) {
-+ ast_free(e->summary);
-+ ast_free(e->usage);
-+ ast_free(e->syntax);
-+ ast_free(e->seealso);
-+ e->summary = NULL, e->usage = NULL;
-+ e->syntax = NULL, e->seealso = NULL;
-+ }
-+#endif
- unregistered=1;
- break;
- }
-@@ -2772,26 +2949,92 @@
- static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct agi_command *command;
-- char fullcmd[80];
-+ char fullcmd[MAX_CMD_LEN];
-+ int error = 0;
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "agi show";
-+ e->command = "agi show commands [topic]";
- e->usage =
-- "Usage: agi show [topic]\n"
-+ "Usage: agi show commands [topic]\n"
- " When called with a topic as an argument, displays usage\n"
- " information on the given command. If called without a\n"
- " topic, it provides a list of AGI commands.\n";
- case CLI_GENERATE:
- return NULL;
- }
-- if (a->argc < e->args)
-+ if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
- return CLI_SHOWUSAGE;
-- if (a->argc > e->args) {
-+ if (a->argc > e->args - 1) {
- command = find_command(a->argv + e->args, 1);
- if (command) {
-- ast_cli(a->fd, "%s", command->usage);
-- ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
-+ char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
-+ char info[30 + MAX_CMD_LEN]; /* '-= Info about...' */
-+ char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS]; /* '-= Info about...' with colors */
-+ char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
-+ char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Description]\n with colors */
-+ char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Runs Dead]\n with colors */
-+ char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS]; /* 'Yes' or 'No' with colors */
-+ char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS]; /* [See Also]\n with colors */
-+ char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
-+ size_t synlen, desclen, seealsolen, stxlen;
-+
-+ term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
-+ term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
-+ term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
-+ term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
-+ term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
-+ term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
-+
-+ ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
-+ snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
-+ term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
-+#ifdef AST_XML_DOCS
-+ if (command->docsrc == AST_XML_DOC) {
-+ synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
-+ description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
-+ seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
-+ if (!seealso || !description || !synopsis) {
-+ error = 1;
-+ goto return_cleanup;
-+ }
-+ } else
-+#endif
-+ {
-+ synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ synopsis = ast_malloc(synlen);
-+
-+ desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ description = ast_malloc(desclen);
-+
-+ seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ seealso = ast_malloc(seealsolen);
-+
-+ if (!synopsis || !description || !seealso) {
-+ error = 1;
-+ goto return_cleanup;
-+ }
-+ term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
-+ term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
-+ term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
-+ }
-+
-+ stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
-+ syntax = ast_malloc(stxlen);
-+ if (!syntax) {
-+ error = 1;
-+ goto return_cleanup;
-+ }
-+ term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
-+
-+ ast_cli(a->fd, "%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n", infotitle, stxtitle, syntax,
-+ desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
-+ seealsotitle, seealso);
-+return_cleanup:
-+ ast_free(synopsis);
-+ ast_free(description);
-+ ast_free(syntax);
-+ ast_free(seealso);
- } else {
- if (find_command(a->argv + e->args, -1)) {
- return help_workhorse(a->fd, a->argv + e->args);
-@@ -2803,7 +3046,7 @@
- } else {
- return help_workhorse(a->fd, NULL);
- }
-- return CLI_SUCCESS;
-+ return (error ? CLI_FAILURE : CLI_SUCCESS);
- }
-
- /*! \brief Convert string to use HTML escaped characters
-@@ -2840,7 +3083,7 @@
- static int write_htmldump(char *filename)
- {
- struct agi_command *command;
-- char fullcmd[80];
-+ char fullcmd[MAX_CMD_LEN];
- FILE *htmlfile;
-
- if (!(htmlfile = fopen(filename, "wt")))
-@@ -2852,7 +3095,10 @@
-
- AST_RWLIST_RDLOCK(&agi_commands);
- AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
-- char *stringp, *tempstr;
-+#ifdef AST_XML_DOCS
-+ char *stringptmp;
-+#endif
-+ char *tempstr, *stringp;
-
- if (!command->cmda[0]) /* end ? */
- break;
-@@ -2863,8 +3109,12 @@
-
- fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
- fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
--
-+#ifdef AST_XML_DOCS
-+ stringptmp = ast_xmldoc_printable(command->usage, 0);
-+ stringp = stringptmp;
-+#else
- stringp = command->usage;
-+#endif
- tempstr = strsep(&stringp, "\n");
-
- fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
-@@ -2878,6 +3128,9 @@
- }
- fprintf(htmlfile, "</TD></TR>\n");
- fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
-+#ifdef AST_XML_DOCS
-+ ast_free(stringptmp);
-+#endif
- }
- AST_RWLIST_UNLOCK(&agi_commands);
- fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
-@@ -2885,30 +3138,6 @@
- return 0;
- }
-
--static char *handle_cli_agi_dumphtml_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "agi dumphtml";
-- e->usage =
-- "Usage: agi dumphtml <filename>\n"
-- " Dumps the AGI command list in HTML format to the given\n"
-- " file.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
-- if (a->argc < e->args + 1)
-- return CLI_SHOWUSAGE;
--
-- if (write_htmldump(a->argv[2]) < 0) {
-- ast_cli(a->fd, "Could not create file '%s'\n", a->argv[2]);
-- return CLI_SHOWUSAGE;
-- }
-- ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[2]);
-- return CLI_SUCCESS;
--}
--
- static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
-@@ -3036,18 +3265,16 @@
- return agi_exec(chan, data);
- }
-
--static struct ast_cli_entry cli_agi_dumphtml_deprecated = AST_CLI_DEFINE(handle_cli_agi_dumphtml_deprecated, "Dumps a list of AGI commands in HTML format");
--
- static struct ast_cli_entry cli_agi[] = {
- AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
- AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
- AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
-- AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format", .deprecate_cmd = &cli_agi_dumphtml_deprecated)
-+ AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
- };
-
- static int unload_module(void)
- {
-- ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
- /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
- we know that these commands were registered by this module and are still registered
- */
-@@ -3060,7 +3287,7 @@
-
- static int load_module(void)
- {
-- ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
- /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
- no other commands have been registered yet
- */
-Index: res/res_config_ldap.c
-===================================================================
---- a/res/res_config_ldap.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_config_ldap.c (.../team/group/issue14292) (revision 178988)
-@@ -89,6 +89,7 @@
- struct ast_variable *attributes; /*!< attribute names conversion */
- struct ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
- AST_LIST_ENTRY(ldap_table_config) entry;
-+ /* TODO: Make proxies work */
- };
-
- /*! \brief Should be locked before using it */
-@@ -788,7 +789,7 @@
- do {
- /* freeing ldap_result further down */
- result = ldap_search_ext_s(ldapConn, clean_basedn,
-- LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
-+ LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
- &ldap_result_msg);
- if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
- ast_log(LOG_DEBUG, "Failed to query database. Try %d/10\n",
-@@ -807,7 +808,7 @@
-
- if (result != LDAP_SUCCESS) {
- ast_log(LOG_WARNING, "Failed to query database. Check debug for more info.\n");
-- ast_log(LOG_WARNING, "Query: %s\n", filter->str);
-+ ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
- ast_log(LOG_WARNING, "Query Failed because: %s\n", ldap_err2string(result));
- } else {
- /* this is where we create the variables from the search result
-@@ -817,7 +818,7 @@
- vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
- } else {
- ast_debug(1, "Could not find any entry matching %s in base dn %s.\n",
-- filter->str, clean_basedn);
-+ ast_str_buffer(filter), clean_basedn);
- }
-
- ldap_msgfree(ldap_result_msg);
-@@ -1245,7 +1246,7 @@
- do {
- /* freeing ldap_result further down */
- result = ldap_search_ext_s(ldapConn, clean_basedn,
-- LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
-+ LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
- &ldap_result_msg);
- if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
- ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
-@@ -1265,7 +1266,7 @@
-
- if (result != LDAP_SUCCESS) {
- ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
-- ast_log(LOG_WARNING, "Query: %s\n", filter->str);
-+ ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
- ast_log(LOG_WARNING, "Query Failed because: %s\n",
- ldap_err2string(result));
-
-@@ -1305,12 +1306,199 @@
- return num_entries;
- }
-
-+static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
-+{
-+ int error = 0;
-+ LDAPMessage *ldap_entry = NULL;
-+ LDAPMod **ldap_mods;
-+ const char *newparam = NULL;
-+ const char *newval = NULL;
-+ char *dn;
-+ int num_entries = 0;
-+ int i = 0;
-+ int mods_size = 0;
-+ int mod_exists = 0;
-+ struct ldap_table_config *table_config = NULL;
-+ char *clean_basedn = NULL;
-+ struct ast_str *filter = NULL;
-+ int tries = 0;
-+ int result = 0;
-+ LDAPMessage *ldap_result_msg = NULL;
-+
-+ if (!table_name) {
-+ ast_log(LOG_WARNING, "No table_name specified.\n");
-+ return -1;
-+ }
-+
-+ if (!(filter = ast_str_create(80)))
-+ return -1;
-+
-+ ast_mutex_lock(&ldap_lock);
-+
-+ /* We now have our complete statement; Lets connect to the server and execute it. */
-+ if (!ldap_reconnect()) {
-+ ast_mutex_unlock(&ldap_lock);
-+ ast_free(filter);
-+ return -1;
-+ }
-+
-+ table_config = table_config_for_table_name(table_name);
-+ if (!table_config) {
-+ ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
-+ ast_mutex_unlock(&ldap_lock);
-+ ast_free(filter);
-+ return -1;
-+ }
-+
-+ clean_basedn = cleaned_basedn(NULL, basedn);
-+
-+ /* Create the filter with the table additional filter and the parameter/value pairs we were given */
-+ ast_str_append(&filter, 0, "(&");
-+ if (table_config && table_config->additional_filter) {
-+ ast_str_append(&filter, 0, "%s", table_config->additional_filter);
-+ }
-+ if (table_config != base_table_config && base_table_config
-+ && base_table_config->additional_filter) {
-+ ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
-+ }
-+
-+ /* Get multiple lookup keyfields and values */
-+ while ((newparam = va_arg(ap, const char *))) {
-+ newval = va_arg(ap, const char *);
-+ append_var_and_value_to_filter(&filter, table_config, newparam, newval);
-+ }
-+ ast_str_append(&filter, 0, ")");
-+
-+ /* Create the modification array with the parameter/value pairs we were given,
-+ * if there are several parameters with the same name, we collect them into
-+ * one parameter/value pair and delimit them with a semicolon */
-+ newparam = va_arg(ap, const char *);
-+ newparam = convert_attribute_name_to_ldap(table_config, newparam);
-+ newval = va_arg(ap, const char *);
-+ if (!newparam || !newval) {
-+ ast_log(LOG_WARNING,
-+ "LINE(%d): need at least one parameter to modify.\n", __LINE__);
-+ ast_free(filter);
-+ ast_free(clean_basedn);
-+ return -1;
-+ }
-+
-+ mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
-+ ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
-+ ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
-+
-+ ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
-+ ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
-+ strcpy(ldap_mods[0]->mod_type, newparam);
-+
-+ ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
-+ ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
-+ strcpy(ldap_mods[0]->mod_values[0], newval);
-+
-+ while ((newparam = va_arg(ap, const char *))) {
-+ newparam = convert_attribute_name_to_ldap(table_config, newparam);
-+ newval = va_arg(ap, const char *);
-+ mod_exists = 0;
-+
-+ for (i = 0; i < mods_size - 1; i++) {
-+ if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
-+ /* We have the parameter allready, adding the value as a semicolon delimited value */
-+ ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
-+ strcat(ldap_mods[i]->mod_values[0], ";");
-+ strcat(ldap_mods[i]->mod_values[0], newval);
-+ mod_exists = 1;
-+ break;
-+ }
-+ }
-+
-+ /* create new mod */
-+ if (!mod_exists) {
-+ mods_size++;
-+ ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
-+ ldap_mods[mods_size - 1] = NULL;
-+ ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
-+
-+ ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
-+
-+ ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
-+ strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
-+
-+ ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
-+ ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
-+ strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
-+ }
-+ }
-+ /* freeing ldap_mods further down */
-+
-+ do {
-+ /* freeing ldap_result further down */
-+ result = ldap_search_ext_s(ldapConn, clean_basedn,
-+ LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
-+ &ldap_result_msg);
-+ if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
-+ ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
-+ tries + 1);
-+ tries++;
-+ if (tries < 3) {
-+ usleep(500000L * tries);
-+ if (ldapConn) {
-+ ldap_unbind_ext_s(ldapConn, NULL, NULL);
-+ ldapConn = NULL;
-+ }
-+ if (!ldap_reconnect())
-+ break;
-+ }
-+ }
-+ } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
-+
-+ if (result != LDAP_SUCCESS) {
-+ ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
-+ ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
-+ ast_log(LOG_WARNING, "Query Failed because: %s\n",
-+ ldap_err2string(result));
-+
-+ ast_mutex_unlock(&ldap_lock);
-+ if (filter)
-+ free(filter);
-+ if (clean_basedn)
-+ free(clean_basedn);
-+ ldap_msgfree(ldap_result_msg);
-+ ldap_mods_free(ldap_mods, 0);
-+ return -1;
-+ }
-+ /* Ready to update */
-+ if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
-+ for (i = 0; option_debug > 2 && i < mods_size - 1; i++)
-+ ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
-+
-+ ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
-+
-+ for (i = 0; ldap_entry; i++) {
-+ dn = ldap_get_dn(ldapConn, ldap_entry);
-+ if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS)
-+ ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
-+
-+ ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
-+ }
-+ }
-+
-+ ast_mutex_unlock(&ldap_lock);
-+ if (filter)
-+ free(filter);
-+ if (clean_basedn)
-+ free(clean_basedn);
-+ ldap_msgfree(ldap_result_msg);
-+ ldap_mods_free(ldap_mods, 0);
-+ return num_entries;
-+}
-+
- static struct ast_config_engine ldap_engine = {
- .name = "ldap",
- .load_func = config_ldap,
- .realtime_func = realtime_ldap,
- .realtime_multi_func = realtime_multi_ldap,
-- .update_func = update_ldap
-+ .update_func = update_ldap,
-+ .update2_func = update2_ldap,
- };
-
- static int load_module(void)
-@@ -1327,7 +1515,7 @@
-
- ast_config_engine_register(&ldap_engine);
- ast_verb(1, "LDAP RealTime driver loaded.\n");
-- ast_cli_register_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
-
- ast_mutex_unlock(&ldap_lock);
-
-@@ -1345,7 +1533,7 @@
- ldap_unbind_ext_s(ldapConn, NULL, NULL);
- ldapConn = NULL;
- }
-- ast_cli_unregister_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
- ast_config_engine_deregister(&ldap_engine);
- ast_verb(1, "LDAP RealTime unloaded.\n");
-
-@@ -1391,8 +1579,7 @@
- char *category_name = NULL;
-
- config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
--
-- if (!config) {
-+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
- return -1;
- }
-@@ -1530,9 +1717,9 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "realtime ldap status";
-+ e->command = "realtime show ldap status";
- e->usage =
-- "Usage: realtime ldap status\n"
-+ "Usage: realtime show ldap status\n"
- " Shows connection information for the LDAP RealTime driver\n";
- return NULL;
- case CLI_GENERATE:
-Index: res/res_odbc.c
-===================================================================
---- a/res/res_odbc.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_odbc.c (.../team/group/issue14292) (revision 178988)
-@@ -1,7 +1,7 @@
- /*
- * Asterisk -- An open source telephony toolkit.
- *
-- * Copyright (C) 1999 - 2005, Digium, Inc.
-+ * Copyright (C) 1999 - 2008, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
-@@ -25,12 +25,13 @@
- *
- * \author Mark Spencer <markster@digium.com>
- * \author Anthony Minessale II <anthmct@yahoo.com>
-+ * \author Tilghman Lesher <tilghman@digium.com>
- *
- * \arg See also: \ref cdr_odbc
- */
-
- /*** MODULEINFO
-- <depend>unixodbc</depend>
-+ <depend>generic_odbc</depend>
- <depend>ltdl</depend>
- ***/
-
-@@ -48,7 +49,70 @@
- #include "asterisk/res_odbc.h"
- #include "asterisk/time.h"
- #include "asterisk/astobj2.h"
-+#include "asterisk/app.h"
-+#include "asterisk/strings.h"
-+#include "asterisk/threadstorage.h"
-
-+/*** DOCUMENTATION
-+ <function name="ODBC" language="en_US">
-+ <synopsis>
-+ Controls ODBC transaction properties.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="property" required="true">
-+ <enumlist>
-+ <enum name="transaction">
-+ <para>Gets or sets the active transaction ID. If set, and the transaction ID does not
-+ exist and a <replaceable>database name</replaceable> is specified as an argument, it will be created.</para>
-+ </enum>
-+ <enum name="forcecommit">
-+ <para>Controls whether a transaction will be automatically committed when the channel
-+ hangs up. Defaults to false. If a <replaceable>transaction ID</replaceable> is specified in the optional argument,
-+ the property will be applied to that ID, otherwise to the current active ID.</para>
-+ </enum>
-+ <enum name="isolation">
-+ <para>Controls the data isolation on uncommitted transactions. May be one of the
-+ following: <literal>read_committed</literal>, <literal>read_uncommitted</literal>,
-+ <literal>repeatable_read</literal>, or <literal>serializable</literal>. Defaults to the
-+ database setting in <filename>res_odbc.conf</filename> or <literal>read_committed</literal>
-+ if not specified. If a <replaceable>transaction ID</replaceable> is specified as an optional argument, it will be
-+ applied to that ID, otherwise the current active ID.</para>
-+ </enum>
-+ </enumlist>
-+ </parameter>
-+ <parameter name="argument" required="false" />
-+ </syntax>
-+ <description>
-+ <para>The ODBC() function allows setting several properties to influence how a connected
-+ database processes transactions.</para>
-+ </description>
-+ </function>
-+ <application name="ODBC_Commit" language="en_US">
-+ <synopsis>
-+ Commits a currently open database transaction.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="transaction ID" required="no" />
-+ </syntax>
-+ <description>
-+ <para>Commits the database transaction specified by <replaceable>transaction ID</replaceable>
-+ or the current active transaction, if not specified.</para>
-+ </description>
-+ </application>
-+ <application name="ODBC_Rollback" language="en_US">
-+ <synopsis>
-+ Rollback a currently open database transaction.
-+ </synopsis>
-+ <syntax>
-+ <parameter name="transaction ID" required="no" />
-+ </syntax>
-+ <description>
-+ <para>Rolls back the database transaction specified by <replaceable>transaction ID</replaceable>
-+ or the current active transaction, if not specified.</para>
-+ </description>
-+ </application>
-+ ***/
-+
- struct odbc_class
- {
- AST_LIST_ENTRY(odbc_class) list;
-@@ -58,12 +122,14 @@
- char *password;
- char *sanitysql;
- SQLHENV env;
-- unsigned int haspool:1; /* Boolean - TDS databases need this */
-- unsigned int delme:1; /* Purge the class */
-- unsigned int backslash_is_escape:1; /* On this database, the backslash is a native escape sequence */
-- unsigned int limit; /* 1023 wasn't enough for some people */
-- unsigned int count; /* Running count of pooled connections */
-- unsigned int idlecheck; /* Recheck the connection if it is idle for this long */
-+ unsigned int haspool:1; /*!< Boolean - TDS databases need this */
-+ unsigned int delme:1; /*!< Purge the class */
-+ unsigned int backslash_is_escape:1; /*!< On this database, the backslash is a native escape sequence */
-+ unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */
-+ unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
-+ unsigned int limit; /*!< Maximum number of database handles we will allow */
-+ int count; /*!< Running count of pooled connections */
-+ unsigned int idlecheck; /*!< Recheck the connection if it is idle for this long (in seconds) */
- struct ao2_container *obj_container;
- };
-
-@@ -74,19 +140,248 @@
- static odbc_status odbc_obj_connect(struct odbc_obj *obj);
- static odbc_status odbc_obj_disconnect(struct odbc_obj *obj);
- static int odbc_register_class(struct odbc_class *class, int connect);
-+static void odbc_txn_free(void *data);
-+static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx);
-
-+AST_THREADSTORAGE(errors_buf);
-+
-+static struct ast_datastore_info txn_info = {
-+ .type = "ODBC_Transaction",
-+ .destroy = odbc_txn_free,
-+};
-+
-+struct odbc_txn_frame {
-+ AST_LIST_ENTRY(odbc_txn_frame) list;
-+ struct ast_channel *owner;
-+ struct odbc_obj *obj; /*!< Database handle within which transacted statements are run */
-+ /*!\brief Is this record the current active transaction within the channel?
-+ * Note that the active flag is really only necessary for statements which
-+ * are triggered from the dialplan, as there isn't a direct correlation
-+ * between multiple statements. Applications wishing to use transactions
-+ * may simply perform each statement on the same odbc_obj, which keeps the
-+ * transaction persistent.
-+ */
-+ unsigned int active:1;
-+ unsigned int forcecommit:1; /*!< Should uncommitted transactions be auto-committed on handle release? */
-+ unsigned int isolation; /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
-+ char name[0]; /*!< Name of this transaction ID */
-+};
-+
-+static const char *isolation2text(int iso)
-+{
-+ if (iso == SQL_TXN_READ_COMMITTED) {
-+ return "read_committed";
-+ } else if (iso == SQL_TXN_READ_UNCOMMITTED) {
-+ return "read_uncommitted";
-+ } else if (iso == SQL_TXN_SERIALIZABLE) {
-+ return "serializable";
-+ } else if (iso == SQL_TXN_REPEATABLE_READ) {
-+ return "repeatable_read";
-+ } else {
-+ return "unknown";
-+ }
-+}
-+
-+static int text2isolation(const char *txt)
-+{
-+ if (strncasecmp(txt, "read_", 5) == 0) {
-+ if (strncasecmp(txt + 5, "c", 1) == 0) {
-+ return SQL_TXN_READ_COMMITTED;
-+ } else if (strncasecmp(txt + 5, "u", 1) == 0) {
-+ return SQL_TXN_READ_UNCOMMITTED;
-+ } else {
-+ return 0;
-+ }
-+ } else if (strncasecmp(txt, "ser", 3) == 0) {
-+ return SQL_TXN_SERIALIZABLE;
-+ } else if (strncasecmp(txt, "rep", 3) == 0) {
-+ return SQL_TXN_REPEATABLE_READ;
-+ } else {
-+ return 0;
-+ }
-+}
-+
-+static struct odbc_txn_frame *find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
-+{
-+ struct ast_datastore *txn_store;
-+ AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
-+ struct odbc_txn_frame *txn = NULL;
-+
-+ if (!chan && obj && obj->txf && obj->txf->owner) {
-+ chan = obj->txf->owner;
-+ } else if (!chan) {
-+ /* No channel == no transaction */
-+ return NULL;
-+ }
-+
-+ ast_channel_lock(chan);
-+ if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
-+ oldlist = txn_store->data;
-+ } else {
-+ /* Need to create a new datastore */
-+ if (!(txn_store = ast_datastore_alloc(&txn_info, NULL))) {
-+ ast_log(LOG_ERROR, "Unable to allocate a new datastore. Cannot create a new transaction.\n");
-+ ast_channel_unlock(chan);
-+ return NULL;
-+ }
-+
-+ if (!(oldlist = ast_calloc(1, sizeof(*oldlist)))) {
-+ ast_log(LOG_ERROR, "Unable to allocate datastore list head. Cannot create a new transaction.\n");
-+ ast_datastore_free(txn_store);
-+ ast_channel_unlock(chan);
-+ return NULL;
-+ }
-+
-+ txn_store->data = oldlist;
-+ AST_LIST_HEAD_INIT(oldlist);
-+ ast_channel_datastore_add(chan, txn_store);
-+ }
-+
-+ AST_LIST_LOCK(oldlist);
-+ ast_channel_unlock(chan);
-+
-+ /* Scanning for an object is *fast*. Scanning for a name is much slower. */
-+ if (obj != NULL || active == 1) {
-+ AST_LIST_TRAVERSE(oldlist, txn, list) {
-+ if (txn->obj == obj || txn->active) {
-+ AST_LIST_UNLOCK(oldlist);
-+ return txn;
-+ }
-+ }
-+ }
-+
-+ if (name != NULL) {
-+ AST_LIST_TRAVERSE(oldlist, txn, list) {
-+ if (!strcasecmp(txn->name, name)) {
-+ AST_LIST_UNLOCK(oldlist);
-+ return txn;
-+ }
-+ }
-+ }
-+
-+ /* Nothing found, create one */
-+ if (name && obj && (txn = ast_calloc(1, sizeof(*txn) + strlen(name) + 1))) {
-+ struct odbc_txn_frame *otxn;
-+
-+ strcpy(txn->name, name); /* SAFE */
-+ txn->obj = obj;
-+ txn->isolation = obj->parent->isolation;
-+ txn->forcecommit = obj->parent->forcecommit;
-+ txn->owner = chan;
-+ txn->active = 1;
-+
-+ /* On creation, the txn becomes active, and all others inactive */
-+ AST_LIST_TRAVERSE(oldlist, otxn, list) {
-+ otxn->active = 0;
-+ }
-+ AST_LIST_INSERT_TAIL(oldlist, txn, list);
-+
-+ obj->txf = txn;
-+ obj->tx = 1;
-+ }
-+ AST_LIST_UNLOCK(oldlist);
-+
-+ return txn;
-+}
-+
-+static struct odbc_txn_frame *release_transaction(struct odbc_txn_frame *tx)
-+{
-+ if (!tx) {
-+ return NULL;
-+ }
-+
-+ ast_debug(2, "release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->obj, tx->obj ? tx->obj->txf : NULL);
-+
-+ /* If we have an owner, disassociate */
-+ if (tx->owner) {
-+ struct ast_datastore *txn_store;
-+ AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
-+
-+ ast_channel_lock(tx->owner);
-+ if ((txn_store = ast_channel_datastore_find(tx->owner, &txn_info, NULL))) {
-+ oldlist = txn_store->data;
-+ AST_LIST_LOCK(oldlist);
-+ AST_LIST_REMOVE(oldlist, tx, list);
-+ AST_LIST_UNLOCK(oldlist);
-+ }
-+ ast_channel_unlock(tx->owner);
-+ tx->owner = NULL;
-+ }
-+
-+ if (tx->obj) {
-+ /* If we have any uncommitted transactions, they are handled when we release the object */
-+ struct odbc_obj *obj = tx->obj;
-+ /* Prevent recursion during destruction */
-+ tx->obj->txf = NULL;
-+ tx->obj = NULL;
-+ odbc_release_obj2(obj, tx);
-+ }
-+ ast_free(tx);
-+ return NULL;
-+}
-+
-+static void odbc_txn_free(void *vdata)
-+{
-+ struct odbc_txn_frame *tx;
-+ AST_LIST_HEAD(, odbc_txn_frame) *oldlist = vdata;
-+
-+ ast_debug(2, "odbc_txn_free(%p) called\n", vdata);
-+
-+ AST_LIST_LOCK(oldlist);
-+ while ((tx = AST_LIST_REMOVE_HEAD(oldlist, list))) {
-+ release_transaction(tx);
-+ }
-+ AST_LIST_UNLOCK(oldlist);
-+ AST_LIST_HEAD_DESTROY(oldlist);
-+ ast_free(oldlist);
-+}
-+
-+static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
-+{
-+ struct ast_datastore *txn_store;
-+ AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
-+ struct odbc_txn_frame *active = NULL, *txn;
-+
-+ if (!chan && tx && tx->owner) {
-+ chan = tx->owner;
-+ }
-+
-+ ast_channel_lock(chan);
-+ if (!(txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
-+ ast_channel_unlock(chan);
-+ return -1;
-+ }
-+
-+ oldlist = txn_store->data;
-+ AST_LIST_LOCK(oldlist);
-+ AST_LIST_TRAVERSE(oldlist, txn, list) {
-+ if (txn == tx) {
-+ txn->active = 1;
-+ active = txn;
-+ } else {
-+ txn->active = 0;
-+ }
-+ }
-+ AST_LIST_UNLOCK(oldlist);
-+ ast_channel_unlock(chan);
-+ return active ? 0 : -1;
-+}
-+
- static void odbc_class_destructor(void *data)
- {
- struct odbc_class *class = data;
- /* Due to refcounts, we can safely assume that any objects with a reference
- * to us will prevent our destruction, so we don't need to worry about them.
- */
-- if (class->username)
-+ if (class->username) {
- ast_free(class->username);
-- if (class->password)
-+ }
-+ if (class->password) {
- ast_free(class->password);
-- if (class->sanitysql)
-+ }
-+ if (class->sanitysql) {
- ast_free(class->sanitysql);
-+ }
- ao2_ref(class->obj_container, -1);
- SQLFreeHandle(SQL_HANDLE_ENV, class->env);
- }
-@@ -99,9 +394,11 @@
- static void odbc_obj_destructor(void *data)
- {
- struct odbc_obj *obj = data;
-+ struct odbc_class *class = obj->parent;
-+ obj->parent = NULL;
- odbc_obj_disconnect(obj);
- ast_mutex_destroy(&obj->lock);
-- ao2_ref(obj->parent, -1);
-+ ao2_ref(class, -1);
- }
-
- static void destroy_table_cache(struct odbc_cache_tables *table) {
-@@ -151,18 +448,18 @@
-
- if (!obj) {
- ast_log(LOG_WARNING, "Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
-+ AST_RWLIST_UNLOCK(&odbc_tables);
- return NULL;
- }
-
- /* Table structure not already cached; build it now. */
- do {
--retry:
- res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
- if (try == 0) {
- try = 1;
- ast_odbc_sanity_check(obj);
-- goto retry;
-+ continue;
- }
- ast_log(LOG_WARNING, "SQL Alloc Handle failed on connection '%s'!\n", database);
- break;
-@@ -174,7 +471,7 @@
- try = 1;
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- ast_odbc_sanity_check(obj);
-- goto retry;
-+ continue;
- }
- ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.\n", database);
- break;
-@@ -224,7 +521,8 @@
-
- AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
- AST_RWLIST_RDLOCK(&(tableptr->columns));
-- } while (0);
-+ break;
-+ } while (1);
-
- AST_RWLIST_UNLOCK(&odbc_tables);
-
-@@ -276,6 +574,9 @@
-
- if (stmt) {
- break;
-+ } else if (obj->tx) {
-+ ast_log(LOG_WARNING, "Failed to execute, but unable to reconnect, as we're transactional.\n");
-+ break;
- } else {
- obj->up = 0;
- ast_log(LOG_WARNING, "SQL Exec Direct failed. Attempting a reconnect...\n");
-@@ -319,22 +620,29 @@
- }
- }
-
-- ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
-- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-- stmt = NULL;
-+ if (obj->tx) {
-+ ast_log(LOG_WARNING, "SQL Execute error, but unable to reconnect, as we're transactional.\n");
-+ break;
-+ } else {
-+ ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
-+ SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-+ stmt = NULL;
-
-- obj->up = 0;
-- /*
-- * While this isn't the best way to try to correct an error, this won't automatically
-- * fail when the statement handle invalidates.
-- */
-- ast_odbc_sanity_check(obj);
-- continue;
-- } else
-+ obj->up = 0;
-+ /*
-+ * While this isn't the best way to try to correct an error, this won't automatically
-+ * fail when the statement handle invalidates.
-+ */
-+ ast_odbc_sanity_check(obj);
-+ continue;
-+ }
-+ } else {
- obj->last_used = ast_tvnow();
-+ }
- break;
-- } else if (attempt == 0)
-+ } else if (attempt == 0) {
- ast_odbc_sanity_check(obj);
-+ }
- }
-
- return stmt;
-@@ -366,7 +674,23 @@
- return res;
- }
-
-+SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind)
-+{
-+ SQLRETURN res;
-
-+ if (pmaxlen == 0) {
-+ if (SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
-+ ast_str_make_space(buf, *StrLen_or_Ind + 1);
-+ }
-+ } else if (pmaxlen > 0) {
-+ ast_str_make_space(buf, pmaxlen);
-+ }
-+ res = SQLGetData(StatementHandle, ColumnNumber, TargetType, ast_str_buffer(*buf), ast_str_size(*buf), StrLen_or_Ind);
-+ ast_str_update(*buf);
-+
-+ return res;
-+}
-+
- int ast_odbc_sanity_check(struct odbc_obj *obj)
- {
- char *test_sql = "select 1";
-@@ -394,7 +718,7 @@
- SQLFreeHandle (SQL_HANDLE_STMT, stmt);
- }
-
-- if (!obj->up) { /* Try to reconnect! */
-+ if (!obj->up && !obj->tx) { /* Try to reconnect! */
- ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
- odbc_obj_disconnect(obj);
- odbc_obj_connect(obj);
-@@ -409,7 +733,7 @@
- struct ast_variable *v;
- char *cat;
- const char *dsn, *username, *password, *sanitysql;
-- int enabled, pooling, limit, bse;
-+ int enabled, pooling, limit, bse, forcecommit, isolation;
- unsigned int idlecheck;
- int preconnect = 0, res = 0;
- struct ast_flags config_flags = { 0 };
-@@ -417,7 +741,7 @@
- struct odbc_class *new;
-
- config = ast_config_load(cfg, config_flags);
-- if (!config) {
-+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load config file res_odbc.conf\n");
- return -1;
- }
-@@ -435,6 +759,8 @@
- pooling = 0;
- limit = 0;
- bse = 1;
-+ forcecommit = 0;
-+ isolation = SQL_TXN_READ_COMMITTED;
- for (v = ast_variable_browse(config, cat); v; v = v->next) {
- if (!strcasecmp(v->name, "pooling")) {
- if (ast_true(v->value))
-@@ -469,6 +795,13 @@
- sanitysql = v->value;
- } else if (!strcasecmp(v->name, "backslash_is_escape")) {
- bse = ast_true(v->value);
-+ } else if (!strcasecmp(v->name, "forcecommit")) {
-+ forcecommit = ast_true(v->value);
-+ } else if (!strcasecmp(v->name, "isolation")) {
-+ if ((isolation = text2isolation(v->value)) == 0) {
-+ ast_log(LOG_ERROR, "Unrecognized value for 'isolation': '%s' in section '%s'\n", v->value, cat);
-+ isolation = SQL_TXN_READ_COMMITTED;
-+ }
- }
- }
-
-@@ -502,6 +835,8 @@
- }
-
- new->backslash_is_escape = bse ? 1 : 0;
-+ new->forcecommit = forcecommit ? 1 : 0;
-+ new->isolation = isolation;
- new->idlecheck = idlecheck;
-
- if (cat)
-@@ -556,10 +891,11 @@
- while ((class = ao2_iterator_next(&aoi))) {
- if (!strncasecmp(a->word, class->name, length) && ++which > a->n) {
- ret = ast_strdup(class->name);
-- ao2_ref(class, -1);
-+ }
-+ ao2_ref(class, -1);
-+ if (ret) {
- break;
- }
-- ao2_ref(class, -1);
- }
- if (!ret && !strncasecmp(a->word, "all", length) && ++which > a->n) {
- ret = ast_strdup("all");
-@@ -596,10 +932,11 @@
- ao2_ref(current, -1);
- }
- } else {
-- /* Should only ever be one of these */
-+ /* Should only ever be one of these (unless there are transactions) */
- struct ao2_iterator aoi2 = ao2_iterator_init(class->obj_container, 0);
- while ((current = ao2_iterator_next(&aoi2))) {
-- ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
-+ ast_cli(a->fd, " Pooled: No\n Connected: %s\n", current->used ? "In use" :
-+ current->up && ast_odbc_sanity_check(current) ? "Yes" : "No");
- ao2_ref(current, -1);
- }
- }
-@@ -625,8 +962,9 @@
- if (preconnect) {
- /* Request and release builds a connection */
- obj = ast_odbc_request_obj(class->name, 0);
-- if (obj)
-+ if (obj) {
- ast_odbc_release_obj(obj);
-+ }
- }
-
- return 0;
-@@ -636,115 +974,333 @@
- }
- }
-
--void ast_odbc_release_obj(struct odbc_obj *obj)
-+static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
- {
-- /* For pooled connections, this frees the connection to be
-- * reused. For non-pooled connections, it does nothing. */
-- obj->used = 0;
-+ SQLINTEGER nativeerror=0, numfields=0;
-+ SQLSMALLINT diagbytes=0, i;
-+ unsigned char state[10], diagnostic[256];
-+
-+ ast_debug(2, "odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->txf);
-+ if (tx) {
-+ ast_debug(1, "called on a transactional handle with %s\n", tx->forcecommit ? "COMMIT" : "ROLLBACK");
-+ if (SQLEndTran(SQL_HANDLE_DBC, obj->con, tx->forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
-+ /* Handle possible transaction commit failure */
-+ SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
-+ if (!strcmp((char *)state, "25S02") || !strcmp((char *)state, "08007")) {
-+ /* These codes mean that a commit failed and a transaction
-+ * is still active. We must rollback, or things will get
-+ * very, very weird for anybody using the handle next. */
-+ SQLEndTran(SQL_HANDLE_DBC, obj->con, SQL_ROLLBACK);
-+ }
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ }
-+
-+ /* Transaction is done, reset autocommit */
-+ if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
-+ SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ }
-+ }
-+
- #ifdef DEBUG_THREADS
- obj->file[0] = '\0';
- obj->function[0] = '\0';
- obj->lineno = 0;
- #endif
-+
-+ /* For pooled connections, this frees the connection to be
-+ * reused. For non-pooled connections, it does nothing. */
-+ obj->used = 0;
-+ if (obj->txf) {
-+ /* Prevent recursion -- transaction is already closed out. */
-+ obj->txf->obj = NULL;
-+ obj->txf = release_transaction(obj->txf);
-+ }
- ao2_ref(obj, -1);
- }
-
-+void ast_odbc_release_obj(struct odbc_obj *obj)
-+{
-+ struct odbc_txn_frame *tx = find_transaction(NULL, obj, NULL, 0);
-+ odbc_release_obj2(obj, tx);
-+}
-+
- int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
- {
- return obj->parent->backslash_is_escape;
- }
-
-+static int commit_exec(struct ast_channel *chan, void *data)
-+{
-+ struct odbc_txn_frame *tx;
-+ SQLINTEGER nativeerror=0, numfields=0;
-+ SQLSMALLINT diagbytes=0, i;
-+ unsigned char state[10], diagnostic[256];
-+
-+ if (ast_strlen_zero(data)) {
-+ tx = find_transaction(chan, NULL, NULL, 1);
-+ } else {
-+ tx = find_transaction(chan, NULL, data, 0);
-+ }
-+
-+ pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", "OK");
-+
-+ if (tx) {
-+ if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_COMMIT) == SQL_ERROR) {
-+ struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
-+ ast_str_reset(errors);
-+
-+ /* Handle possible transaction commit failure */
-+ SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
-+ ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ pbx_builtin_setvar_helper(chan, "COMMIT_RESULT", ast_str_buffer(errors));
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int rollback_exec(struct ast_channel *chan, void *data)
-+{
-+ struct odbc_txn_frame *tx;
-+ SQLINTEGER nativeerror=0, numfields=0;
-+ SQLSMALLINT diagbytes=0, i;
-+ unsigned char state[10], diagnostic[256];
-+
-+ if (ast_strlen_zero(data)) {
-+ tx = find_transaction(chan, NULL, NULL, 1);
-+ } else {
-+ tx = find_transaction(chan, NULL, data, 0);
-+ }
-+
-+ pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", "OK");
-+
-+ if (tx) {
-+ if (SQLEndTran(SQL_HANDLE_DBC, tx->obj->con, SQL_ROLLBACK) == SQL_ERROR) {
-+ struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
-+ ast_str_reset(errors);
-+
-+ /* Handle possible transaction commit failure */
-+ SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
-+ ast_log(LOG_WARNING, "SQLEndTran returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ pbx_builtin_setvar_helper(chan, "ROLLBACK_RESULT", ast_str_buffer(errors));
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int aoro2_class_cb(void *obj, void *arg, int flags)
-+{
-+ struct odbc_class *class = obj;
-+ char *name = arg;
-+ if (!strcmp(class->name, name) && !class->delme) {
-+ return CMP_MATCH | CMP_STOP;
-+ }
-+ return 0;
-+}
-+
-+#define USE_TX (void *)(long)1
-+#define NO_TX (void *)(long)2
-+#define EOR_TX (void *)(long)3
-+
-+static int aoro2_obj_cb(void *vobj, void *arg, int flags)
-+{
-+ struct odbc_obj *obj = vobj;
-+ ast_mutex_lock(&obj->lock);
-+ if ((arg == NO_TX && !obj->tx) || (arg == EOR_TX && !obj->used) || (arg == USE_TX && obj->tx && !obj->used)) {
-+ obj->used = 1;
-+ ast_mutex_unlock(&obj->lock);
-+ return CMP_MATCH | CMP_STOP;
-+ }
-+ ast_mutex_unlock(&obj->lock);
-+ return 0;
-+}
-+
- #ifdef DEBUG_THREADS
--struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
-+struct odbc_obj *_ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
- #else
--struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
-+struct odbc_obj *ast_odbc_request_obj2(const char *name, struct ast_flags flags)
- #endif
- {
- struct odbc_obj *obj = NULL;
- struct odbc_class *class;
-- struct ao2_iterator aoi = ao2_iterator_init(class_container, 0);
-+ SQLINTEGER nativeerror=0, numfields=0;
-+ SQLSMALLINT diagbytes=0, i;
-+ unsigned char state[10], diagnostic[256];
-
-- while ((class = ao2_iterator_next(&aoi))) {
-- if (!strcmp(class->name, name) && !class->delme) {
-- break;
-- }
-- ao2_ref(class, -1);
-+ if (!(class = ao2_callback(class_container, 0, aoro2_class_cb, (char *) name))) {
-+ return NULL;
- }
-
-- if (!class)
-- return NULL;
-+ ast_assert(ao2_ref(class, 0) > 1);
-
- if (class->haspool) {
- /* Recycle connections before building another */
-- aoi = ao2_iterator_init(class->obj_container, 0);
-- while ((obj = ao2_iterator_next(&aoi))) {
-- if (! obj->used) {
-- ast_mutex_lock(&obj->lock);
-- obj->used = 1;
-- ast_mutex_unlock(&obj->lock);
-- break;
-- }
-- ao2_ref(obj, -1);
-+ obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, EOR_TX);
-+
-+ if (obj) {
-+ ast_assert(ao2_ref(obj, 0) > 1);
- }
-
- if (!obj && (class->count < class->limit)) {
-- class->count++;
- obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
- if (!obj) {
- ao2_ref(class, -1);
- return NULL;
- }
-+ ast_assert(ao2_ref(obj, 0) == 1);
- ast_mutex_init(&obj->lock);
- /* obj inherits the outstanding reference to class */
- obj->parent = class;
-+ class = NULL;
- if (odbc_obj_connect(obj) == ODBC_FAIL) {
- ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
- ao2_ref(obj, -1);
-+ ast_assert(ao2_ref(class, 0) > 0);
- obj = NULL;
- } else {
- obj->used = 1;
-- ao2_link(class->obj_container, obj);
-+ ao2_link(obj->parent->obj_container, obj);
-+ ast_atomic_fetchadd_int(&obj->parent->count, +1);
- }
-- class = NULL;
- } else {
- /* Object is not constructed, so delete outstanding reference to class. */
- ao2_ref(class, -1);
- class = NULL;
- }
-+
-+ if (obj && ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
-+ /* Ensure this connection has autocommit turned off. */
-+ if (SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
-+ SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ }
-+ }
-+ } else if (ast_test_flag(&flags, RES_ODBC_INDEPENDENT_CONNECTION)) {
-+ /* Non-pooled connections -- but must use a separate connection handle */
-+ if (!(obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, USE_TX))) {
-+ obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
-+ if (!obj) {
-+ ao2_ref(class, -1);
-+ return NULL;
-+ }
-+ ast_mutex_init(&obj->lock);
-+ /* obj inherits the outstanding reference to class */
-+ obj->parent = class;
-+ class = NULL;
-+ if (odbc_obj_connect(obj) == ODBC_FAIL) {
-+ ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
-+ ao2_ref(obj, -1);
-+ obj = NULL;
-+ } else {
-+ obj->used = 1;
-+ ao2_link(obj->parent->obj_container, obj);
-+ ast_atomic_fetchadd_int(&obj->parent->count, +1);
-+ }
-+ }
-+
-+ if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
-+ SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ }
- } else {
- /* Non-pooled connection: multiple modules can use the same connection. */
-- aoi = ao2_iterator_init(class->obj_container, 0);
-- while ((obj = ao2_iterator_next(&aoi))) {
-- /* Non-pooled connection: if there is an entry, return it */
-- break;
-- }
--
-- if (obj) {
-+ if ((obj = ao2_callback(class->obj_container, 0, aoro2_obj_cb, NO_TX))) {
- /* Object is not constructed, so delete outstanding reference to class. */
-+ ast_assert(ao2_ref(class, 0) > 1);
- ao2_ref(class, -1);
- class = NULL;
- } else {
- /* No entry: build one */
-- obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor);
-- if (!obj) {
-+ if (!(obj = ao2_alloc(sizeof(*obj), odbc_obj_destructor))) {
-+ ast_assert(ao2_ref(class, 0) > 1);
- ao2_ref(class, -1);
- return NULL;
- }
- ast_mutex_init(&obj->lock);
- /* obj inherits the outstanding reference to class */
- obj->parent = class;
-+ class = NULL;
- if (odbc_obj_connect(obj) == ODBC_FAIL) {
- ast_log(LOG_WARNING, "Failed to connect to %s\n", name);
- ao2_ref(obj, -1);
- obj = NULL;
- } else {
-- ao2_link(class->obj_container, obj);
-+ ao2_link(obj->parent->obj_container, obj);
-+ ast_assert(ao2_ref(obj, 0) > 1);
- }
-- class = NULL;
- }
-+
-+ if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_AUTOCOMMIT, (void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
-+ SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ }
- }
-
-- if (obj && check) {
-+ /* Set the isolation property */
-+ if (obj && SQLSetConnectAttr(obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)obj->parent->isolation, 0) == SQL_ERROR) {
-+ SQLGetDiagField(SQL_HANDLE_DBC, obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (obj && ast_test_flag(&flags, RES_ODBC_SANITY_CHECK)) {
- ast_odbc_sanity_check(obj);
- } else if (obj && obj->parent->idlecheck > 0 && ast_tvdiff_sec(ast_tvnow(), obj->last_used) > obj->parent->idlecheck)
- odbc_obj_connect(obj);
-@@ -758,15 +1314,64 @@
- #endif
- ast_assert(class == NULL);
-
-+ if (obj) {
-+ ast_assert(ao2_ref(obj, 0) > 1);
-+ }
- return obj;
- }
-
-+#ifdef DEBUG_THREADS
-+struct odbc_obj *_ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
-+#else
-+struct odbc_obj *ast_odbc_request_obj(const char *name, int check)
-+#endif
-+{
-+ struct ast_flags flags = { check ? RES_ODBC_SANITY_CHECK : 0 };
-+#ifdef DEBUG_THREADS
-+ return _ast_odbc_request_obj2(name, flags, file, function, lineno);
-+#else
-+ return ast_odbc_request_obj2(name, flags);
-+#endif
-+}
-+
-+struct odbc_obj *ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
-+{
-+ struct ast_datastore *txn_store;
-+ AST_LIST_HEAD(, odbc_txn_frame) *oldlist;
-+ struct odbc_txn_frame *txn = NULL;
-+
-+ if (!chan) {
-+ /* No channel == no transaction */
-+ return NULL;
-+ }
-+
-+ ast_channel_lock(chan);
-+ if ((txn_store = ast_channel_datastore_find(chan, &txn_info, NULL))) {
-+ oldlist = txn_store->data;
-+ } else {
-+ ast_channel_unlock(chan);
-+ return NULL;
-+ }
-+
-+ AST_LIST_LOCK(oldlist);
-+ ast_channel_unlock(chan);
-+
-+ AST_LIST_TRAVERSE(oldlist, txn, list) {
-+ if (txn->obj && txn->obj->parent && !strcmp(txn->obj->parent->name, objname)) {
-+ AST_LIST_UNLOCK(oldlist);
-+ return txn->obj;
-+ }
-+ }
-+ AST_LIST_UNLOCK(oldlist);
-+ return NULL;
-+}
-+
- static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
- {
- int res;
- SQLINTEGER err;
- short int mlen;
-- unsigned char msg[200], stat[10];
-+ unsigned char msg[200], state[10];
-
- /* Nothing to disconnect */
- if (!obj->con) {
-@@ -777,17 +1382,19 @@
-
- res = SQLDisconnect(obj->con);
-
-- if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
-- ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
-- } else {
-- ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
-+ if (obj->parent) {
-+ if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
-+ ast_log(LOG_DEBUG, "Disconnected %d from %s [%s]\n", res, obj->parent->name, obj->parent->dsn);
-+ } else {
-+ ast_log(LOG_DEBUG, "res_odbc: %s [%s] already disconnected\n", obj->parent->name, obj->parent->dsn);
-+ }
- }
-
- if ((res = SQLFreeHandle(SQL_HANDLE_DBC, obj->con) == SQL_SUCCESS)) {
- obj->con = NULL;
- ast_log(LOG_DEBUG, "Database handle deallocated\n");
- } else {
-- SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
-+ SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, state, &err, msg, 100, &mlen);
- ast_log(LOG_WARNING, "Unable to deallocate database handle? %d errno=%d %s\n", res, (int)err, msg);
- }
-
-@@ -849,6 +1456,146 @@
- return ODBC_SUCCESS;
- }
-
-+static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
-+{
-+ AST_DECLARE_APP_ARGS(args,
-+ AST_APP_ARG(property);
-+ AST_APP_ARG(opt);
-+ );
-+ struct odbc_txn_frame *tx;
-+
-+ AST_STANDARD_APP_ARGS(args, data);
-+ if (strcasecmp(args.property, "transaction") == 0) {
-+ if ((tx = find_transaction(chan, NULL, NULL, 1))) {
-+ ast_copy_string(buf, tx->name, len);
-+ return 0;
-+ }
-+ } else if (strcasecmp(args.property, "isolation") == 0) {
-+ if (!ast_strlen_zero(args.opt)) {
-+ tx = find_transaction(chan, NULL, args.opt, 0);
-+ } else {
-+ tx = find_transaction(chan, NULL, NULL, 1);
-+ }
-+ if (tx) {
-+ ast_copy_string(buf, isolation2text(tx->isolation), len);
-+ return 0;
-+ }
-+ } else if (strcasecmp(args.property, "forcecommit") == 0) {
-+ if (!ast_strlen_zero(args.opt)) {
-+ tx = find_transaction(chan, NULL, args.opt, 0);
-+ } else {
-+ tx = find_transaction(chan, NULL, NULL, 1);
-+ }
-+ if (tx) {
-+ ast_copy_string(buf, tx->forcecommit ? "1" : "0", len);
-+ return 0;
-+ }
-+ }
-+ return -1;
-+}
-+
-+static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
-+{
-+ AST_DECLARE_APP_ARGS(args,
-+ AST_APP_ARG(property);
-+ AST_APP_ARG(opt);
-+ );
-+ struct odbc_txn_frame *tx;
-+ SQLINTEGER nativeerror=0, numfields=0;
-+ SQLSMALLINT diagbytes=0, i;
-+ unsigned char state[10], diagnostic[256];
-+
-+ AST_STANDARD_APP_ARGS(args, s);
-+ if (strcasecmp(args.property, "transaction") == 0) {
-+ /* Set active transaction */
-+ struct odbc_obj *obj;
-+ if ((tx = find_transaction(chan, NULL, value, 0))) {
-+ mark_transaction_active(chan, tx);
-+ } else {
-+ /* No such transaction, create one */
-+ struct ast_flags flags = { RES_ODBC_INDEPENDENT_CONNECTION };
-+ if (ast_strlen_zero(args.opt) || !(obj = ast_odbc_request_obj2(args.opt, flags))) {
-+ ast_log(LOG_ERROR, "Could not create transaction: invalid database specification '%s'\n", S_OR(args.opt, ""));
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_DB");
-+ return -1;
-+ }
-+ if (!(tx = find_transaction(chan, obj, value, 0))) {
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
-+ return -1;
-+ }
-+ obj->tx = 1;
-+ }
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
-+ return 0;
-+ } else if (strcasecmp(args.property, "forcecommit") == 0) {
-+ /* Set what happens when an uncommitted transaction ends without explicit Commit or Rollback */
-+ if (ast_strlen_zero(args.opt)) {
-+ tx = find_transaction(chan, NULL, NULL, 1);
-+ } else {
-+ tx = find_transaction(chan, NULL, args.opt, 0);
-+ }
-+ if (!tx) {
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
-+ return -1;
-+ }
-+ if (ast_true(value)) {
-+ tx->forcecommit = 1;
-+ } else if (ast_false(value)) {
-+ tx->forcecommit = 0;
-+ } else {
-+ ast_log(LOG_ERROR, "Invalid value for forcecommit: '%s'\n", S_OR(value, ""));
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
-+ return -1;
-+ }
-+
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
-+ return 0;
-+ } else if (strcasecmp(args.property, "isolation") == 0) {
-+ /* How do uncommitted transactions affect reads? */
-+ int isolation = text2isolation(value);
-+ if (ast_strlen_zero(args.opt)) {
-+ tx = find_transaction(chan, NULL, NULL, 1);
-+ } else {
-+ tx = find_transaction(chan, NULL, args.opt, 0);
-+ }
-+ if (!tx) {
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "FAILED_TO_CREATE");
-+ return -1;
-+ }
-+ if (isolation == 0) {
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "INVALID_VALUE");
-+ ast_log(LOG_ERROR, "Invalid isolation specification: '%s'\n", S_OR(value, ""));
-+ } else if (SQLSetConnectAttr(tx->obj->con, SQL_ATTR_TXN_ISOLATION, (void *)(long)isolation, 0) == SQL_ERROR) {
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "SQL_ERROR");
-+ SQLGetDiagField(SQL_HANDLE_DBC, tx->obj->con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
-+ for (i = 0; i < numfields; i++) {
-+ SQLGetDiagRec(SQL_HANDLE_DBC, tx->obj->con, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
-+ ast_log(LOG_WARNING, "SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
-+ if (i > 10) {
-+ ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields);
-+ break;
-+ }
-+ }
-+ } else {
-+ pbx_builtin_setvar_helper(chan, "ODBC_RESULT", "OK");
-+ tx->isolation = isolation;
-+ }
-+ return 0;
-+ } else {
-+ ast_log(LOG_ERROR, "Unknown property: '%s'\n", args.property);
-+ return -1;
-+ }
-+}
-+
-+static struct ast_custom_function odbc_function = {
-+ .name = "ODBC",
-+ .read = acf_transaction_read,
-+ .write = acf_transaction_write,
-+};
-+
-+static const char *app_commit = "ODBC_Commit";
-+static const char *app_rollback = "ODBC_Rollback";
-+
- static int reload(void)
- {
- struct odbc_cache_tables *table;
-@@ -932,7 +1679,10 @@
- return AST_MODULE_LOAD_DECLINE;
- if (load_odbc_config() == -1)
- return AST_MODULE_LOAD_DECLINE;
-- ast_cli_register_multiple(cli_odbc, sizeof(cli_odbc) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_odbc, ARRAY_LEN(cli_odbc));
-+ ast_register_application_xml(app_commit, commit_exec);
-+ ast_register_application_xml(app_rollback, rollback_exec);
-+ ast_custom_function_register(&odbc_function);
- ast_log(LOG_NOTICE, "res_odbc loaded.\n");
- return 0;
- }
-Index: res/ael/ael.tab.c
-===================================================================
---- a/res/ael/ael.tab.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/ael/ael.tab.c (.../team/group/issue14292) (revision 178988)
-@@ -511,7 +511,7 @@
- /* YYFINAL -- State number of the termination state. */
- #define YYFINAL 17
- /* YYLAST -- Last index in YYTABLE. */
--#define YYLAST 327
-+#define YYLAST 373
-
- /* YYNTOKENS -- Number of terminals. */
- #define YYNTOKENS 44
-@@ -520,7 +520,7 @@
- /* YYNRULES -- Number of rules. */
- #define YYNRULES 142
- /* YYNRULES -- Number of states. */
--#define YYNSTATES 288
-+#define YYNSTATES 281
-
- /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
- #define YYUNDEFTOK 2
-@@ -594,17 +594,17 @@
- -1, 43, -1, 37, -1, 50, 3, 48, 4, 59,
- 5, -1, 23, -1, -1, 24, -1, 24, 23, -1,
- 23, 24, -1, 15, 43, 6, 58, 7, 4, 92,
-- 5, -1, 16, 4, 53, 5, -1, -1, 54, 53,
-+ 5, -1, 16, 4, 53, 5, -1, -1, 53, 54,
- -1, 1, 53, -1, -1, 43, 9, 55, 43, 8,
- -1, -1, 42, 43, 9, 57, 43, 8, -1, -1,
- 43, -1, 58, 10, 43, -1, 58, 1, -1, -1,
-- 60, 59, -1, 1, 59, -1, 62, -1, 99, -1,
-+ 59, 60, -1, 1, 59, -1, 62, -1, 99, -1,
- 94, -1, 95, -1, 61, -1, 54, -1, 56, -1,
- 43, 1, -1, 8, -1, 17, 25, 43, 8, -1,
- 43, 25, 74, -1, 43, 14, 43, 25, 74, -1,
- 31, 43, 25, 74, -1, 32, 6, 70, 7, 43,
- 25, 74, -1, 31, 32, 6, 70, 7, 43, 25,
-- 74, -1, -1, 74, 63, -1, 1, 63, -1, 71,
-+ 74, -1, -1, 63, 74, -1, 1, 63, -1, 71,
- 11, 71, 11, 71, -1, 43, -1, 64, 13, 71,
- 13, 71, 13, 71, -1, -1, 6, 67, 69, 7,
- -1, 19, 66, -1, 22, 66, -1, 20, 6, 65,
-@@ -628,12 +628,12 @@
- 84, 89, 7, -1, 43, 6, 7, -1, -1, 43,
- 6, 86, -1, 85, 89, 7, -1, 85, 7, -1,
- 43, -1, -1, 69, -1, -1, 89, 10, 88, -1,
-- -1, 91, 90, -1, 35, 43, 11, 63, -1, 37,
-- 11, 63, -1, 36, 43, 11, 63, -1, -1, 93,
-- 92, -1, 74, -1, 99, -1, 38, 43, 4, 63,
-+ -1, 90, 91, -1, 35, 43, 11, 63, -1, 37,
-+ 11, 63, -1, 36, 43, 11, 63, -1, -1, 92,
-+ 93, -1, 74, -1, 99, -1, 38, 43, 4, 63,
- 5, -1, 39, 4, 96, 5, -1, 40, 4, 96,
-- 5, -1, -1, 43, 8, 96, -1, 43, 14, 43,
-- 8, 96, -1, 1, 96, -1, 48, -1, 48, 13,
-+ 5, -1, -1, 96, 43, 8, -1, 96, 43, 14,
-+ 43, 8, -1, 1, 96, -1, 48, -1, 48, 13,
- 65, -1, 97, 8, -1, 98, 97, 8, -1, 98,
- 1, -1, 41, 4, 98, 5, -1, 41, 4, 5,
- -1
-@@ -746,91 +746,91 @@
- {
- 14, 9, 0, 0, 13, 15, 0, 0, 3, 6,
- 0, 7, 8, 0, 0, 17, 16, 1, 5, 4,
-- 0, 27, 0, 0, 0, 0, 11, 10, 0, 28,
-- 0, 22, 23, 19, 21, 0, 30, 0, 0, 0,
-- 0, 42, 0, 0, 0, 0, 0, 0, 0, 0,
-- 39, 40, 0, 0, 38, 34, 36, 37, 35, 125,
-- 29, 0, 33, 0, 0, 0, 0, 0, 0, 0,
-- 0, 41, 0, 0, 12, 32, 0, 94, 0, 0,
-+ 0, 27, 0, 0, 11, 10, 0, 28, 0, 22,
-+ 19, 0, 21, 0, 30, 0, 0, 23, 0, 0,
-+ 125, 29, 0, 33, 12, 42, 0, 0, 0, 0,
-+ 0, 0, 0, 0, 39, 40, 32, 38, 34, 36,
-+ 37, 35, 0, 0, 0, 0, 0, 0, 0, 0,
-+ 0, 0, 41, 0, 0, 0, 18, 94, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-- 0, 0, 74, 75, 0, 84, 127, 118, 0, 0,
-- 125, 128, 24, 0, 0, 0, 62, 0, 0, 0,
-- 0, 0, 142, 136, 0, 0, 25, 0, 44, 0,
-- 0, 0, 0, 0, 55, 0, 57, 0, 58, 0,
-- 69, 97, 0, 104, 0, 91, 90, 92, 79, 0,
-- 0, 111, 87, 78, 96, 114, 60, 117, 0, 86,
-- 88, 18, 126, 43, 0, 46, 0, 0, 0, 63,
-- 135, 0, 0, 130, 131, 0, 138, 140, 141, 0,
-- 0, 0, 51, 73, 50, 108, 85, 0, 120, 53,
-- 0, 0, 0, 0, 0, 70, 0, 0, 0, 76,
-- 0, 106, 77, 0, 83, 0, 112, 0, 93, 61,
-- 113, 116, 0, 0, 0, 64, 65, 133, 0, 137,
-- 139, 0, 45, 110, 118, 0, 0, 0, 0, 0,
-- 120, 67, 0, 59, 0, 0, 0, 99, 71, 98,
-+ 0, 0, 74, 75, 0, 84, 127, 118, 0, 126,
-+ 128, 24, 0, 0, 0, 62, 0, 0, 0, 0,
-+ 142, 136, 0, 0, 25, 0, 44, 0, 0, 0,
-+ 0, 55, 0, 57, 0, 58, 0, 69, 97, 0,
-+ 104, 0, 91, 90, 92, 79, 0, 0, 111, 87,
-+ 78, 96, 114, 60, 117, 0, 86, 88, 43, 0,
-+ 46, 0, 0, 0, 63, 135, 130, 0, 131, 0,
-+ 138, 140, 141, 0, 0, 0, 51, 73, 50, 108,
-+ 85, 0, 120, 53, 0, 0, 0, 0, 0, 70,
-+ 0, 0, 0, 76, 0, 106, 77, 0, 83, 0,
-+ 112, 0, 93, 61, 113, 116, 0, 0, 0, 64,
-+ 65, 133, 0, 137, 139, 0, 45, 110, 118, 0,
-+ 0, 67, 0, 59, 0, 0, 0, 99, 71, 98,
- 105, 0, 0, 0, 95, 115, 119, 0, 0, 0,
-- 0, 26, 0, 56, 0, 0, 0, 72, 121, 68,
-+ 0, 26, 0, 56, 72, 0, 0, 0, 121, 68,
- 66, 0, 0, 0, 0, 0, 0, 107, 80, 129,
-- 89, 0, 47, 134, 109, 0, 0, 123, 0, 0,
-- 103, 102, 101, 100, 0, 48, 122, 124, 0, 52,
-- 0, 0, 81, 54, 0, 0, 0, 82
-+ 89, 0, 47, 134, 109, 0, 0, 0, 0, 0,
-+ 103, 102, 101, 100, 0, 48, 0, 0, 123, 0,
-+ 52, 0, 122, 124, 0, 81, 54, 0, 0, 0,
-+ 82
- };
-
- /* YYDEFGOTO[NTERM-NUM]. */
- static const yytype_int16 yydefgoto[] =
- {
-- -1, 6, 7, 8, 113, 9, 10, 11, 12, 24,
-- 92, 39, 93, 170, 30, 52, 53, 54, 55, 120,
-- 180, 181, 125, 177, 94, 147, 107, 182, 131, 95,
-- 121, 193, 274, 284, 202, 198, 132, 191, 134, 123,
-- 214, 97, 196, 98, 236, 148, 219, 220, 99, 100,
-- 56, 57, 110, 114, 115, 58
-+ -1, 6, 7, 8, 111, 9, 10, 11, 12, 23,
-+ 92, 42, 93, 164, 28, 39, 56, 57, 58, 118,
-+ 174, 175, 122, 171, 94, 144, 106, 176, 128, 95,
-+ 168, 187, 264, 277, 196, 192, 129, 185, 131, 120,
-+ 208, 97, 190, 98, 226, 145, 210, 238, 62, 99,
-+ 59, 60, 108, 112, 113, 61
- };
-
- /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
- STATE-NUM. */
--#define YYPACT_NINF -219
-+#define YYPACT_NINF -209
- static const yytype_int16 yypact[] =
- {
-- 102, -219, -25, 40, 24, 29, 70, 249, -219, -219,
-- 74, -219, -219, 107, 11, -219, -219, -219, -219, -219,
-- -6, 65, 11, 137, 148, 11, -219, -219, 152, -219,
-- 87, -219, -219, -219, -219, 123, -219, 173, 126, 136,
-- 123, -219, 159, -11, 186, 190, 194, 196, 158, 86,
-- -219, -219, 203, 123, -219, -219, -219, -219, -219, 177,
-- -219, 201, -219, 170, 208, 191, 179, 12, 12, 19,
-- 214, -219, 181, 213, -219, -219, 115, -219, 183, 222,
-- 222, 223, 222, 36, 187, 226, 228, 229, 232, 222,
-- 202, 182, -219, -219, 213, -219, -219, 16, 113, 239,
-- 177, -219, -219, 240, 179, 213, -219, 22, 12, 101,
-- 246, 248, -219, 241, 250, 10, -219, 234, -219, 56,
-- 255, 56, 256, 253, -219, 259, -219, 224, -219, 26,
-- 225, 157, 258, 119, 261, -219, -219, -219, -219, 213,
-- 266, -219, -219, -219, 254, -219, 231, -219, 59, -219,
-- -219, -219, -219, -219, 60, -219, 233, 235, 236, -219,
-- -219, 12, 237, -219, -219, 224, -219, -219, -219, 263,
-- 238, 213, -219, -219, -219, 270, -219, 242, 124, -1,
-- 269, 276, 273, 187, 187, -219, 187, 243, 187, -219,
-- 244, 274, -219, 247, -219, 115, -219, 213, -219, -219,
-- -219, 251, 252, 257, 264, -219, -219, -219, 283, -219,
-- -219, 284, -219, -219, 242, 286, 260, 262, 285, 292,
-- 124, 265, 267, -219, 267, 172, 15, 176, -219, 165,
-- -219, -6, 290, 294, -219, -219, -219, 293, 277, 213,
-- 12, -219, 129, -219, 295, 296, 56, -219, -219, -219,
-- 268, 291, 298, 187, 187, 187, 187, -219, -219, -219,
-- -219, 213, -219, -219, -219, 56, 56, -219, 267, 267,
-- 301, 301, 301, 301, 271, -219, -219, -219, 300, -219,
-- 307, 267, -219, -219, 275, 309, 213, -219
-+ 262, -209, -32, 21, 5, 13, 69, 296, -209, -209,
-+ 112, -209, -209, 115, 14, -209, -209, -209, -209, -209,
-+ -29, 85, 14, 0, -209, -209, 129, -209, 116, 92,
-+ -209, 140, -209, 105, -209, 147, 125, -209, 105, 99,
-+ -209, -209, 132, 252, -209, -209, 163, -25, 159, 182,
-+ 186, 197, 162, 242, -209, -209, -209, -209, -209, -209,
-+ -209, -209, 165, 201, 170, 222, 204, 187, 16, 16,
-+ 68, 223, -209, 190, 246, 59, -209, -209, 193, 234,
-+ 234, 236, 234, -27, 212, 249, 251, 255, 238, 234,
-+ 228, 292, -209, -209, 246, -209, -209, 15, 146, -209,
-+ -209, -209, 273, 187, 246, -209, 107, 16, 25, 29,
-+ -209, 269, 279, 39, -209, 265, -209, 19, 192, 299,
-+ 294, -209, 302, -209, 264, -209, 70, 266, 161, 300,
-+ 168, 305, -209, -209, -209, -209, 246, 306, -209, -209,
-+ -209, 293, -209, 272, -209, 84, -209, -209, -209, 113,
-+ -209, 274, 275, 278, -209, 280, -209, 76, -209, 264,
-+ -209, -209, -209, 308, 281, 246, 246, -209, -209, 315,
-+ -209, 282, -209, 22, 313, 320, 317, 212, 212, -209,
-+ 212, 286, 212, -209, 287, 318, -209, 288, -209, 59,
-+ -209, 246, -209, -209, -209, 290, 291, 295, 310, -209,
-+ -209, -209, 297, -209, -209, 328, -209, -209, 282, 330,
-+ 122, 298, 301, -209, 301, 171, 86, 205, -209, 121,
-+ -209, -29, 331, 219, -209, -209, -209, 334, 321, 246,
-+ 335, -209, 102, -209, -209, 304, 307, 337, -209, -209,
-+ 309, 332, 338, 212, 212, 212, 212, -209, -209, -209,
-+ -209, 246, -209, -209, -209, 340, 342, 19, 301, 301,
-+ 343, 343, 343, 343, 312, -209, 19, 19, 246, 344,
-+ -209, 348, 246, 246, 301, -209, -209, 316, 351, 246,
-+ -209
- };
-
- /* YYPGOTO[NTERM-NUM]. */
- static const yytype_int16 yypgoto[] =
- {
-- -219, -219, -219, 310, -19, -219, -219, -219, -219, 125,
-- 5, -219, -15, -219, -219, -31, -219, -219, -219, -114,
-- -219, 154, 25, -219, -219, 143, 217, -218, -82, -219,
-- -59, -219, -219, -219, -219, -219, -219, -219, -219, -219,
-- -219, -219, -219, -219, -219, 108, 103, -219, 227, -219,
-- -219, -219, -65, 209, -219, -51
-+ -209, -209, -209, 353, -19, -209, -209, -209, -209, 339,
-+ 137, -209, -30, -209, -209, 324, -209, -209, -209, -114,
-+ -209, 206, -54, -209, -209, 195, 260, -208, -82, -209,
-+ -62, -209, -209, -209, -209, -209, -209, -209, -209, -209,
-+ -209, -209, -209, -209, -209, 156, -209, -209, -209, -209,
-+ -209, -209, 1, 254, -209, 311
- };
-
- /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
-@@ -840,76 +840,86 @@
- #define YYTABLE_NINF -133
- static const yytype_int16 yytable[] =
- {
-- 96, 28, 133, 111, 251, 172, 252, 174, 101, 62,
-- -66, 167, 22, 108, 118, 168, -20, -132, 13, 25,
-- 51, 64, 75, 145, 112, 51, 187, 25, 254, 156,
-- 25, 26, 65, 157, 158, 144, 183, 27, 51, 184,
-- 50, 96, 221, 160, 14, 50, 155, 26, 15, 101,
-- 278, 279, 16, 27, 23, 109, 26, 119, 50, 146,
-- 76, -49, 27, 283, 77, 159, 200, 203, 78, 201,
-- 17, 157, 158, 129, 79, 80, 81, 20, 82, 130,
-- 194, 233, 83, 84, 85, 86, 87, 71, 36, 88,
-- 89, -49, -49, -49, 37, 32, 207, 38, 48, 91,
-- 72, 225, 226, 159, 227, 126, 229, 128, 29, 161,
-- 1, 73, 212, 21, 139, 162, 119, 2, 3, 76,
-- -49, 149, 150, 77, 40, 4, 5, 78, -31, 190,
-- 187, 41, 267, 79, 80, 81, 264, 82, 234, 201,
-- 42, 83, 84, 85, 86, 87, 32, 31, 88, 89,
-- 34, 276, 277, 33, 43, 44, 35, 48, 91, 216,
-- 217, 218, 45, 46, 47, 48, 49, 186, 187, 60,
-- 188, 270, 271, 272, 273, 263, 187, 59, 256, 61,
-- 262, 76, 253, 187, 63, 77, 255, 187, 141, 78,
-- 142, 32, 66, 143, 67, 79, 80, 81, 68, 82,
-- 69, 70, 275, 83, 84, 85, 86, 87, 74, 102,
-- 88, 89, 257, 103, 104, 90, 105, 76, 47, 48,
-- 91, 77, 106, 116, 117, 78, 122, 287, 124, 127,
-- 130, 79, 80, 81, 135, 82, 136, 137, 138, 83,
-- 84, 85, 86, 87, 151, 140, 88, 89, 153, -2,
-- 18, 163, -14, 164, 165, 48, 91, 1, 166, 171,
-- 173, 176, 175, 178, 2, 3, 189, 179, 185, 192,
-- 195, 210, 4, 5, 199, 197, 204, 213, 205, 206,
-- 208, 211, 222, 223, 224, 146, 228, 230, 231, 239,
-- 232, 240, 241, 243, 235, 237, 246, 247, 258, 259,
-- 238, 260, 261, 244, 268, 245, 265, 266, 249, 269,
-- 250, 221, 187, 281, 280, 282, 286, 19, 285, 209,
-- 215, 154, 242, 248, 169, 0, 0, 152
-+ 96, 26, 130, 166, 241, 30, 242, 65, 24, 55,
-+ 126, 13, 116, 55, 25, 22, 127, 107, 66, -20,
-+ 117, -132, 142, -49, -49, 14, 123, -49, 125, 15,
-+ 156, -49, 141, -66, 158, 136, 16, -49, -49, -49,
-+ 161, -49, 150, 31, 162, -49, -49, -49, -49, -49,
-+ 269, 270, -49, -49, -49, -49, -49, -20, 143, -132,
-+ 117, -49, -49, -49, -49, 211, 276, -49, 157, 17,
-+ 109, -49, 157, 110, 188, 223, 24, -49, -49, -49,
-+ 177, -49, 25, 178, 201, -49, -49, -49, -49, -49,
-+ 202, 194, -49, -49, 195, 215, 216, 181, 217, 244,
-+ 219, -49, -49, 206, 44, 24, 38, 45, 155, 254,
-+ -31, 25, 195, -31, 151, 20, 46, 34, 152, 153,
-+ 197, 21, -31, 35, 152, 153, 36, 234, 27, 224,
-+ 47, 48, 181, 33, 246, 31, -31, -31, 49, 50,
-+ 51, 52, 53, 268, -31, -31, -31, -31, -31, 37,
-+ 154, 40, 272, 273, 146, 147, 154, 235, 236, 237,
-+ 32, 260, 261, 262, 263, 67, 32, 252, 41, 75,
-+ 76, 180, 181, 77, 182, 63, 54, 78, 184, 181,
-+ 54, 243, 181, 79, 80, 81, 68, 82, 64, 265,
-+ 69, 83, 84, 85, 86, 87, 75, 167, 88, 89,
-+ 77, 70, 247, 90, 78, 71, 51, 52, 91, 101,
-+ 79, 80, 81, 102, 82, 245, 181, 280, 83, 84,
-+ 85, 86, 87, 75, 249, 88, 89, 77, 103, 104,
-+ 105, 78, 114, 115, 52, 91, 119, 79, 80, 81,
-+ 121, 82, 124, 72, 135, 83, 84, 85, 86, 87,
-+ 75, 37, 88, 89, 77, 127, 73, 132, 78, 133,
-+ 45, 52, 91, 134, 79, 80, 81, 74, 82, 46,
-+ 1, 137, 83, 84, 85, 86, 87, 2, 3, 88,
-+ 89, 148, 159, 47, 48, 4, 5, 160, 52, 91,
-+ 165, 49, 50, 51, 52, 53, -2, 18, 138, -14,
-+ 139, 37, 170, 140, 1, 169, 172, 173, 183, 179,
-+ 189, 2, 3, 186, 191, 193, 204, 198, 199, 4,
-+ 5, 200, 207, 157, 205, 143, 212, 213, 214, 218,
-+ 220, 222, 221, 225, 227, 229, 231, 233, 228, 248,
-+ 230, 239, 250, 253, 240, 258, 251, 255, 257, 259,
-+ 256, 266, 211, 267, 181, 271, 275, 274, 279, 278,
-+ 19, 29, 43, 149, 232, 203, 209, 163, 0, 0,
-+ 0, 0, 0, 100
- };
-
- static const yytype_int16 yycheck[] =
- {
-- 59, 20, 84, 68, 222, 119, 224, 121, 59, 40,
-- 11, 1, 1, 1, 73, 5, 5, 5, 43, 14,
-- 35, 32, 53, 7, 5, 40, 11, 22, 13, 7,
-- 25, 37, 43, 11, 12, 94, 10, 43, 53, 13,
-- 35, 100, 43, 108, 4, 40, 105, 37, 24, 100,
-- 268, 269, 23, 43, 43, 43, 37, 1, 53, 43,
-- 4, 5, 43, 281, 8, 43, 7, 7, 12, 10,
-- 0, 11, 12, 37, 18, 19, 20, 3, 22, 43,
-- 139, 195, 26, 27, 28, 29, 30, 1, 1, 33,
-- 34, 35, 36, 37, 7, 9, 161, 10, 42, 43,
-- 14, 183, 184, 43, 186, 80, 188, 82, 43, 8,
-- 8, 25, 171, 6, 89, 14, 1, 15, 16, 4,
-- 5, 8, 9, 8, 1, 23, 24, 12, 5, 10,
-- 11, 8, 246, 18, 19, 20, 7, 22, 197, 10,
-- 17, 26, 27, 28, 29, 30, 9, 22, 33, 34,
-- 25, 265, 266, 5, 31, 32, 4, 42, 43, 35,
-- 36, 37, 39, 40, 41, 42, 43, 10, 11, 43,
-- 13, 253, 254, 255, 256, 240, 11, 4, 13, 43,
-- 239, 4, 10, 11, 25, 8, 10, 11, 6, 12,
-- 8, 9, 6, 11, 4, 18, 19, 20, 4, 22,
-- 4, 43, 261, 26, 27, 28, 29, 30, 5, 8,
-- 33, 34, 231, 43, 6, 38, 25, 4, 41, 42,
-- 43, 8, 43, 9, 43, 12, 43, 286, 6, 6,
-- 43, 18, 19, 20, 8, 22, 8, 8, 6, 26,
-- 27, 28, 29, 30, 5, 43, 33, 34, 8, 0,
-- 1, 5, 3, 5, 13, 42, 43, 8, 8, 25,
-- 5, 8, 6, 4, 15, 16, 8, 43, 43, 8,
-- 4, 8, 23, 24, 43, 21, 43, 7, 43, 43,
-- 43, 43, 13, 7, 11, 43, 43, 43, 14, 25,
-- 43, 8, 8, 7, 43, 43, 11, 5, 8, 5,
-- 43, 8, 25, 43, 13, 43, 11, 11, 43, 11,
-- 43, 43, 11, 13, 43, 8, 7, 7, 43, 165,
-- 177, 104, 214, 220, 115, -1, -1, 100
-+ 62, 20, 84, 117, 212, 5, 214, 32, 37, 39,
-+ 37, 43, 74, 43, 43, 1, 43, 1, 43, 5,
-+ 1, 5, 7, 4, 5, 4, 80, 8, 82, 24,
-+ 5, 12, 94, 11, 5, 89, 23, 18, 19, 20,
-+ 1, 22, 104, 43, 5, 26, 27, 28, 29, 30,
-+ 258, 259, 33, 34, 35, 36, 37, 43, 43, 43,
-+ 1, 42, 43, 4, 5, 43, 274, 8, 43, 0,
-+ 69, 12, 43, 5, 136, 189, 37, 18, 19, 20,
-+ 10, 22, 43, 13, 8, 26, 27, 28, 29, 30,
-+ 14, 7, 33, 34, 10, 177, 178, 11, 180, 13,
-+ 182, 42, 43, 165, 5, 37, 1, 8, 107, 7,
-+ 5, 43, 10, 8, 7, 3, 17, 1, 11, 12,
-+ 7, 6, 17, 7, 11, 12, 10, 5, 43, 191,
-+ 31, 32, 11, 4, 13, 43, 31, 32, 39, 40,
-+ 41, 42, 43, 257, 39, 40, 41, 42, 43, 9,
-+ 43, 4, 266, 267, 8, 9, 43, 35, 36, 37,
-+ 23, 243, 244, 245, 246, 6, 29, 229, 43, 4,
-+ 5, 10, 11, 8, 13, 43, 39, 12, 10, 11,
-+ 43, 10, 11, 18, 19, 20, 4, 22, 25, 251,
-+ 4, 26, 27, 28, 29, 30, 4, 5, 33, 34,
-+ 8, 4, 221, 38, 12, 43, 41, 42, 43, 8,
-+ 18, 19, 20, 43, 22, 10, 11, 279, 26, 27,
-+ 28, 29, 30, 4, 5, 33, 34, 8, 6, 25,
-+ 43, 12, 9, 43, 42, 43, 43, 18, 19, 20,
-+ 6, 22, 6, 1, 6, 26, 27, 28, 29, 30,
-+ 4, 9, 33, 34, 8, 43, 14, 8, 12, 8,
-+ 8, 42, 43, 8, 18, 19, 20, 25, 22, 17,
-+ 8, 43, 26, 27, 28, 29, 30, 15, 16, 33,
-+ 34, 8, 13, 31, 32, 23, 24, 8, 42, 43,
-+ 25, 39, 40, 41, 42, 43, 0, 1, 6, 3,
-+ 8, 9, 8, 11, 8, 6, 4, 43, 8, 43,
-+ 4, 15, 16, 8, 21, 43, 8, 43, 43, 23,
-+ 24, 43, 7, 43, 43, 43, 13, 7, 11, 43,
-+ 43, 43, 14, 43, 43, 25, 8, 7, 43, 8,
-+ 43, 43, 8, 8, 43, 13, 25, 43, 11, 11,
-+ 43, 11, 43, 11, 11, 43, 8, 13, 7, 43,
-+ 7, 22, 38, 103, 208, 159, 171, 113, -1, -1,
-+ -1, -1, -1, 62
- };
-
- /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-@@ -918,33 +928,33 @@
- {
- 0, 8, 15, 16, 23, 24, 45, 46, 47, 49,
- 50, 51, 52, 43, 4, 24, 23, 0, 1, 47,
-- 3, 6, 1, 43, 53, 54, 37, 43, 48, 43,
-- 58, 53, 9, 5, 53, 4, 1, 7, 10, 55,
-- 1, 8, 17, 31, 32, 39, 40, 41, 42, 43,
-- 54, 56, 59, 60, 61, 62, 94, 95, 99, 4,
-- 43, 43, 59, 25, 32, 43, 6, 4, 4, 4,
-- 43, 1, 14, 25, 5, 59, 4, 8, 12, 18,
-+ 3, 6, 1, 53, 37, 43, 48, 43, 58, 53,
-+ 5, 43, 54, 4, 1, 7, 10, 9, 1, 59,
-+ 4, 43, 55, 59, 5, 8, 17, 31, 32, 39,
-+ 40, 41, 42, 43, 54, 56, 60, 61, 62, 94,
-+ 95, 99, 92, 43, 25, 32, 43, 6, 4, 4,
-+ 4, 43, 1, 14, 25, 4, 5, 8, 12, 18,
- 19, 20, 22, 26, 27, 28, 29, 30, 33, 34,
-- 38, 43, 54, 56, 68, 73, 74, 85, 87, 92,
-- 93, 99, 8, 43, 6, 25, 43, 70, 1, 43,
-- 96, 96, 5, 48, 97, 98, 9, 43, 74, 1,
-- 63, 74, 43, 83, 6, 66, 66, 6, 66, 37,
-- 43, 72, 80, 72, 82, 8, 8, 8, 6, 66,
-- 43, 6, 8, 11, 74, 7, 43, 69, 89, 8,
-- 9, 5, 92, 8, 70, 74, 7, 11, 12, 43,
-- 96, 8, 14, 5, 5, 13, 8, 1, 5, 97,
-- 57, 25, 63, 5, 63, 6, 8, 67, 4, 43,
-- 64, 65, 71, 10, 13, 43, 10, 11, 13, 8,
-- 10, 81, 8, 75, 74, 4, 86, 21, 79, 43,
-- 7, 10, 78, 7, 43, 43, 43, 96, 43, 65,
-- 8, 43, 74, 7, 84, 69, 35, 36, 37, 90,
-- 91, 43, 13, 7, 11, 72, 72, 72, 43, 72,
-+ 38, 43, 54, 56, 68, 73, 74, 85, 87, 93,
-+ 99, 8, 43, 6, 25, 43, 70, 1, 96, 96,
-+ 5, 48, 97, 98, 9, 43, 74, 1, 63, 43,
-+ 83, 6, 66, 66, 6, 66, 37, 43, 72, 80,
-+ 72, 82, 8, 8, 8, 6, 66, 43, 6, 8,
-+ 11, 74, 7, 43, 69, 89, 8, 9, 8, 70,
-+ 74, 7, 11, 12, 43, 96, 5, 43, 5, 13,
-+ 8, 1, 5, 97, 57, 25, 63, 5, 74, 6,
-+ 8, 67, 4, 43, 64, 65, 71, 10, 13, 43,
-+ 10, 11, 13, 8, 10, 81, 8, 75, 74, 4,
-+ 86, 21, 79, 43, 7, 10, 78, 7, 43, 43,
-+ 43, 8, 14, 65, 8, 43, 74, 7, 84, 69,
-+ 90, 43, 13, 7, 11, 72, 72, 72, 43, 72,
- 43, 14, 43, 63, 74, 43, 88, 43, 43, 25,
-- 8, 8, 89, 7, 43, 43, 11, 5, 90, 43,
-+ 43, 8, 89, 7, 5, 35, 36, 37, 91, 43,
- 43, 71, 71, 10, 13, 10, 13, 48, 8, 5,
-- 8, 25, 74, 96, 7, 11, 11, 63, 13, 11,
-- 72, 72, 72, 72, 76, 74, 63, 63, 71, 71,
-- 43, 13, 8, 71, 77, 43, 7, 74
-+ 8, 25, 74, 8, 7, 43, 43, 11, 13, 11,
-+ 72, 72, 72, 72, 76, 74, 11, 11, 63, 71,
-+ 71, 43, 63, 63, 13, 8, 71, 77, 43, 7,
-+ 74
- };
-
- #define yyerrok (yyerrstatus = 0)
-@@ -1469,7 +1479,7 @@
- case 43: /* "word" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1473 "ael.tab.c"
-+#line 1483 "ael.tab.c"
- break;
- case 46: /* "objects" */
- #line 170 "ael.y"
-@@ -1477,7 +1487,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1481 "ael.tab.c"
-+#line 1491 "ael.tab.c"
- break;
- case 47: /* "object" */
- #line 170 "ael.y"
-@@ -1485,12 +1495,12 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1489 "ael.tab.c"
-+#line 1499 "ael.tab.c"
- break;
- case 48: /* "context_name" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1494 "ael.tab.c"
-+#line 1504 "ael.tab.c"
- break;
- case 49: /* "context" */
- #line 170 "ael.y"
-@@ -1498,7 +1508,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1502 "ael.tab.c"
-+#line 1512 "ael.tab.c"
- break;
- case 51: /* "macro" */
- #line 170 "ael.y"
-@@ -1506,7 +1516,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1510 "ael.tab.c"
-+#line 1520 "ael.tab.c"
- break;
- case 52: /* "globals" */
- #line 170 "ael.y"
-@@ -1514,7 +1524,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1518 "ael.tab.c"
-+#line 1528 "ael.tab.c"
- break;
- case 53: /* "global_statements" */
- #line 170 "ael.y"
-@@ -1522,7 +1532,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1526 "ael.tab.c"
-+#line 1536 "ael.tab.c"
- break;
- case 54: /* "assignment" */
- #line 170 "ael.y"
-@@ -1530,7 +1540,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1534 "ael.tab.c"
-+#line 1544 "ael.tab.c"
- break;
- case 56: /* "local_assignment" */
- #line 170 "ael.y"
-@@ -1538,7 +1548,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1542 "ael.tab.c"
-+#line 1552 "ael.tab.c"
- break;
- case 58: /* "arglist" */
- #line 170 "ael.y"
-@@ -1546,7 +1556,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1550 "ael.tab.c"
-+#line 1560 "ael.tab.c"
- break;
- case 59: /* "elements" */
- #line 170 "ael.y"
-@@ -1554,7 +1564,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1558 "ael.tab.c"
-+#line 1568 "ael.tab.c"
- break;
- case 60: /* "element" */
- #line 170 "ael.y"
-@@ -1562,7 +1572,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1566 "ael.tab.c"
-+#line 1576 "ael.tab.c"
- break;
- case 61: /* "ignorepat" */
- #line 170 "ael.y"
-@@ -1570,7 +1580,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1574 "ael.tab.c"
-+#line 1584 "ael.tab.c"
- break;
- case 62: /* "extension" */
- #line 170 "ael.y"
-@@ -1578,7 +1588,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1582 "ael.tab.c"
-+#line 1592 "ael.tab.c"
- break;
- case 63: /* "statements" */
- #line 170 "ael.y"
-@@ -1586,12 +1596,12 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1590 "ael.tab.c"
-+#line 1600 "ael.tab.c"
- break;
- case 64: /* "timerange" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1595 "ael.tab.c"
-+#line 1605 "ael.tab.c"
- break;
- case 65: /* "timespec" */
- #line 170 "ael.y"
-@@ -1599,12 +1609,12 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1603 "ael.tab.c"
-+#line 1613 "ael.tab.c"
- break;
- case 66: /* "test_expr" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1608 "ael.tab.c"
-+#line 1618 "ael.tab.c"
- break;
- case 68: /* "if_like_head" */
- #line 170 "ael.y"
-@@ -1612,22 +1622,22 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1616 "ael.tab.c"
-+#line 1626 "ael.tab.c"
- break;
- case 69: /* "word_list" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1621 "ael.tab.c"
-+#line 1631 "ael.tab.c"
- break;
- case 71: /* "word3_list" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1626 "ael.tab.c"
-+#line 1636 "ael.tab.c"
- break;
- case 72: /* "goto_word" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1631 "ael.tab.c"
-+#line 1641 "ael.tab.c"
- break;
- case 73: /* "switch_statement" */
- #line 170 "ael.y"
-@@ -1635,7 +1645,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1639 "ael.tab.c"
-+#line 1649 "ael.tab.c"
- break;
- case 74: /* "statement" */
- #line 170 "ael.y"
-@@ -1643,7 +1653,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1647 "ael.tab.c"
-+#line 1657 "ael.tab.c"
- break;
- case 79: /* "opt_else" */
- #line 170 "ael.y"
-@@ -1651,7 +1661,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1655 "ael.tab.c"
-+#line 1665 "ael.tab.c"
- break;
- case 80: /* "target" */
- #line 170 "ael.y"
-@@ -1659,12 +1669,12 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1663 "ael.tab.c"
-+#line 1673 "ael.tab.c"
- break;
- case 81: /* "opt_pri" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1668 "ael.tab.c"
-+#line 1678 "ael.tab.c"
- break;
- case 82: /* "jumptarget" */
- #line 170 "ael.y"
-@@ -1672,7 +1682,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1676 "ael.tab.c"
-+#line 1686 "ael.tab.c"
- break;
- case 83: /* "macro_call" */
- #line 170 "ael.y"
-@@ -1680,7 +1690,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1684 "ael.tab.c"
-+#line 1694 "ael.tab.c"
- break;
- case 85: /* "application_call_head" */
- #line 170 "ael.y"
-@@ -1688,7 +1698,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1692 "ael.tab.c"
-+#line 1702 "ael.tab.c"
- break;
- case 87: /* "application_call" */
- #line 170 "ael.y"
-@@ -1696,12 +1706,12 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1700 "ael.tab.c"
-+#line 1710 "ael.tab.c"
- break;
- case 88: /* "opt_word" */
- #line 183 "ael.y"
- { free((yyvaluep->str));};
--#line 1705 "ael.tab.c"
-+#line 1715 "ael.tab.c"
- break;
- case 89: /* "eval_arglist" */
- #line 170 "ael.y"
-@@ -1709,7 +1719,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1713 "ael.tab.c"
-+#line 1723 "ael.tab.c"
- break;
- case 90: /* "case_statements" */
- #line 170 "ael.y"
-@@ -1717,7 +1727,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1721 "ael.tab.c"
-+#line 1731 "ael.tab.c"
- break;
- case 91: /* "case_statement" */
- #line 170 "ael.y"
-@@ -1725,7 +1735,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1729 "ael.tab.c"
-+#line 1739 "ael.tab.c"
- break;
- case 92: /* "macro_statements" */
- #line 170 "ael.y"
-@@ -1733,7 +1743,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1737 "ael.tab.c"
-+#line 1747 "ael.tab.c"
- break;
- case 93: /* "macro_statement" */
- #line 170 "ael.y"
-@@ -1741,7 +1751,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1745 "ael.tab.c"
-+#line 1755 "ael.tab.c"
- break;
- case 94: /* "switches" */
- #line 170 "ael.y"
-@@ -1749,7 +1759,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1753 "ael.tab.c"
-+#line 1763 "ael.tab.c"
- break;
- case 95: /* "eswitches" */
- #line 170 "ael.y"
-@@ -1757,7 +1767,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1761 "ael.tab.c"
-+#line 1771 "ael.tab.c"
- break;
- case 96: /* "switchlist" */
- #line 170 "ael.y"
-@@ -1765,7 +1775,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1769 "ael.tab.c"
-+#line 1779 "ael.tab.c"
- break;
- case 97: /* "included_entry" */
- #line 170 "ael.y"
-@@ -1773,7 +1783,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1777 "ael.tab.c"
-+#line 1787 "ael.tab.c"
- break;
- case 98: /* "includeslist" */
- #line 170 "ael.y"
-@@ -1781,7 +1791,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1785 "ael.tab.c"
-+#line 1795 "ael.tab.c"
- break;
- case 99: /* "includes" */
- #line 170 "ael.y"
-@@ -1789,7 +1799,7 @@
- destroy_pval((yyvaluep->pval));
- prev_word=0;
- };
--#line 1793 "ael.tab.c"
-+#line 1803 "ael.tab.c"
- break;
-
- default:
-@@ -3013,20 +3023,20 @@
-
- case 133:
- #line 665 "ael.y"
-- { (yyval.pval) = linku1(nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])), (yyvsp[(3) - (3)].pval)); ;}
-+ { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval),nword((yyvsp[(2) - (3)].str), &(yylsp[(2) - (3)]))); ;}
- break;
-
- case 134:
- #line 666 "ael.y"
- {
- char *x;
-- if (asprintf(&x,"%s@%s", (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str)) < 0) {
-+ if (asprintf(&x,"%s@%s", (yyvsp[(2) - (5)].str), (yyvsp[(4) - (5)].str)) < 0) {
- ast_log(LOG_WARNING, "asprintf() failed\n");
- (yyval.pval) = NULL;
- } else {
-- free((yyvsp[(1) - (5)].str));
-- free((yyvsp[(3) - (5)].str));
-- (yyval.pval) = linku1(nword(x, &(yylsp[(1) - (5)])), (yyvsp[(5) - (5)].pval));
-+ free((yyvsp[(2) - (5)].str));
-+ free((yyvsp[(4) - (5)].str));
-+ (yyval.pval) = linku1((yyvsp[(1) - (5)].pval),nword(x, &(yylsp[(2) - (5)])));
- }
- ;}
- break;
-@@ -3079,7 +3089,7 @@
-
-
- /* Line 1267 of yacc.c. */
--#line 3083 "ael.tab.c"
-+#line 3093 "ael.tab.c"
- default: break;
- }
- YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-Index: res/ael/ael.y
-===================================================================
---- a/res/ael/ael.y (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/ael/ael.y (.../team/group/issue14292) (revision 178988)
-@@ -159,7 +159,7 @@
-
- /* there will be two shift/reduce conflicts, they involve the if statement, where a single statement occurs not wrapped in curlies in the "true" section
- the default action to shift will attach the else to the preceeding if. */
--%expect 3
-+%expect 30
- %error-verbose
-
- /*
-@@ -235,7 +235,7 @@
- ;
-
- global_statements : { $$ = NULL; }
-- | assignment global_statements {$$ = linku1($1, $2); }
-+ | global_statements assignment {$$ = linku1($1, $2); }
- | error global_statements {$$=$2;}
- ;
-
-@@ -259,7 +259,7 @@
- ;
-
- elements : {$$=0;}
-- | element elements { $$ = linku1($1, $2); }
-+ | elements element { $$ = linku1($1, $2); }
- | error elements { $$=$2;}
- ;
-
-@@ -311,7 +311,7 @@
-
- /* list of statements in a block or after a case label - can be empty */
- statements : /* empty */ { $$ = NULL; }
-- | statement statements { $$ = linku1($1, $2); }
-+ | statements statement { $$ = linku1($1, $2); }
- | error statements {$$=$2;}
- ;
-
-@@ -622,7 +622,7 @@
- ;
-
- case_statements: /* empty */ { $$ = NULL; }
-- | case_statement case_statements { $$ = linku1($1, $2); }
-+ | case_statements case_statement { $$ = linku1($1, $2); }
- ;
-
- case_statement: KW_CASE word COLON statements {
-@@ -640,7 +640,7 @@
- ;
-
- macro_statements: /* empty */ { $$ = NULL; }
-- | macro_statement macro_statements { $$ = linku1($1, $2); }
-+ | macro_statements macro_statement { $$ = linku1($1, $2); }
- ;
-
- macro_statement : statement {$$=$1;}
-@@ -662,16 +662,16 @@
- ;
-
- switchlist : /* empty */ { $$ = NULL; }
-- | word SEMI switchlist { $$ = linku1(nword($1, &@1), $3); }
-- | word AT word SEMI switchlist {
-+ | switchlist word SEMI { $$ = linku1($1,nword($2, &@2)); }
-+ | switchlist word AT word SEMI {
- char *x;
-- if (asprintf(&x,"%s@%s", $1, $3) < 0) {
-+ if (asprintf(&x,"%s@%s", $2, $4) < 0) {
- ast_log(LOG_WARNING, "asprintf() failed\n");
- $$ = NULL;
- } else {
-- free($1);
-- free($3);
-- $$ = linku1(nword(x, &@1), $5);
-+ free($2);
-+ free($4);
-+ $$ = linku1($1,nword(x, &@2));
- }
- }
- | error switchlist {$$=$2;}
-Index: res/res_snmp.c
-===================================================================
---- a/res/res_snmp.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_snmp.c (.../team/group/issue14292) (revision 178988)
-@@ -52,7 +52,7 @@
- res_snmp_enabled = 0;
- res_snmp_agentx_subagent = 1;
- cfg = ast_config_load("res_snmp.conf", config_flags);
-- if (!cfg) {
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Could not load res_snmp.conf\n");
- return 0;
- }
-Index: res/res_limit.c
-===================================================================
---- a/res/res_limit.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_limit.c (.../team/group/issue14292) (revision 178988)
-@@ -44,22 +44,23 @@
- int resource;
- char limit[3];
- char desc[40];
-+ char clicmd[15];
- } limits[] = {
-- { RLIMIT_CPU, "-t", "cpu time" },
-- { RLIMIT_FSIZE, "-f", "file size" },
-- { RLIMIT_DATA, "-d", "program data segment" },
-- { RLIMIT_STACK, "-s", "program stack size" },
-- { RLIMIT_CORE, "-c", "core file size" },
-+ { RLIMIT_CPU, "-t", "cpu time", "time" },
-+ { RLIMIT_FSIZE, "-f", "file size" , "file" },
-+ { RLIMIT_DATA, "-d", "program data segment", "data" },
-+ { RLIMIT_STACK, "-s", "program stack size", "stack" },
-+ { RLIMIT_CORE, "-c", "core file size", "core" },
- #ifdef RLIMIT_RSS
-- { RLIMIT_RSS, "-m", "resident memory" },
-- { RLIMIT_MEMLOCK, "-l", "amount of memory locked into RAM" },
-+ { RLIMIT_RSS, "-m", "resident memory", "memory" },
-+ { RLIMIT_MEMLOCK, "-l", "amount of memory locked into RAM", "locked" },
- #endif
- #ifdef RLIMIT_NPROC
-- { RLIMIT_NPROC, "-u", "number of processes" },
-+ { RLIMIT_NPROC, "-u", "number of processes", "processes" },
- #endif
-- { RLIMIT_NOFILE, "-n", "number of file descriptors" },
-+ { RLIMIT_NOFILE, "-n", "number of file descriptors", "descriptors" },
- #ifdef VMEM_DEF
-- { VMEM_DEF, "-v", "virtual memory" },
-+ { VMEM_DEF, "-v", "virtual memory", "virtual" },
- #endif
- };
-
-@@ -67,7 +68,7 @@
- {
- size_t i;
- for (i = 0; i < ARRAY_LEN(limits); i++) {
-- if (!strcasecmp(string, limits[i].limit))
-+ if (!strcasecmp(string, limits[i].clicmd))
- return limits[i].resource;
- }
- return -1;
-@@ -77,7 +78,7 @@
- {
- size_t i;
- for (i = 0; i < ARRAY_LEN(limits); i++) {
-- if (!strcmp(string, limits[i].limit))
-+ if (!strcmp(string, limits[i].clicmd))
- return limits[i].desc;
- }
- return "<unknown>";
-@@ -91,9 +92,9 @@
- if (a->pos > 1)
- return NULL;
- for (i = 0; i < ARRAY_LEN(limits); i++) {
-- if (!strncasecmp(limits[i].limit, a->word, wordlen)) {
-+ if (!strncasecmp(limits[i].clicmd, a->word, wordlen)) {
- if (++which > a->n)
-- return ast_strdup(limits[i].limit);
-+ return ast_strdup(limits[i].clicmd);
- }
- }
- return NULL;
-@@ -108,41 +109,41 @@
- case CLI_INIT:
- e->command = "ulimit";
- e->usage =
-- "Usage: ulimit {-d|"
-+ "Usage: ulimit {data|"
- #ifdef RLIMIT_RSS
-- "-l|"
-+ "limit|"
- #endif
-- "-f|"
-+ "file|"
- #ifdef RLIMIT_RSS
-- "-m|"
-+ "memory|"
- #endif
-- "-s|-t|"
-+ "stack|time|"
- #ifdef RLIMIT_NPROC
-- "-u|"
-+ "processes|"
- #endif
- #ifdef VMEM_DEF
-- "-v|"
-+ "virtual|"
- #endif
-- "-c|-n} [<num>]\n"
-+ "core|descriptors} [<num>]\n"
- " Shows or sets the corresponding resource limit.\n"
-- " -d Process data segment [readonly]\n"
-+ " data Process data segment [readonly]\n"
- #ifdef RLIMIT_RSS
-- " -l Memory lock size [readonly]\n"
-+ " lock Memory lock size [readonly]\n"
- #endif
-- " -f File size\n"
-+ " file File size\n"
- #ifdef RLIMIT_RSS
-- " -m Process resident memory [readonly]\n"
-+ " memory Process resident memory [readonly]\n"
- #endif
-- " -s Process stack size [readonly]\n"
-- " -t CPU usage [readonly]\n"
-+ " stack Process stack size [readonly]\n"
-+ " time CPU usage [readonly]\n"
- #ifdef RLIMIT_NPROC
-- " -u Child processes\n"
-+ " processes Child processes\n"
- #endif
- #ifdef VMEM_DEF
-- " -v Process virtual memory [readonly]\n"
-+ " virtual Process virtual memory [readonly]\n"
- #endif
-- " -c Core dump file size\n"
-- " -n Number of file descriptors\n";
-+ " core Core dump file size\n"
-+ " descriptors Number of file descriptors\n";
- return NULL;
- case CLI_GENERATE:
- return complete_ulimit(a);
-@@ -152,11 +153,11 @@
- return CLI_SHOWUSAGE;
-
- if (a->argc == 1) {
-- char arg2[3];
-+ char arg2[15];
- char *newargv[2] = { "ulimit", arg2 };
- for (resource = 0; resource < ARRAY_LEN(limits); resource++) {
- struct ast_cli_args newArgs = { .argv = newargv, .argc = 2 };
-- ast_copy_string(arg2, limits[resource].limit, sizeof(arg2));
-+ ast_copy_string(arg2, limits[resource].clicmd, sizeof(arg2));
- handle_cli_ulimit(e, CLI_HANDLER, &newArgs);
- }
- return CLI_SUCCESS;
-Index: res/res_timing_dahdi.c
-===================================================================
---- a/res/res_timing_dahdi.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_timing_dahdi.c (.../team/group/issue14292) (revision 178988)
-@@ -50,10 +50,12 @@
- static void dahdi_timer_ack(int handle, unsigned int quantity);
- static int dahdi_timer_enable_continuous(int handle);
- static int dahdi_timer_disable_continuous(int handle);
--static enum ast_timing_event dahdi_timer_get_event(int handle);
-+static enum ast_timer_event dahdi_timer_get_event(int handle);
- static unsigned int dahdi_timer_get_max_rate(int handle);
-
--static struct ast_timing_functions dahdi_timing_functions = {
-+static struct ast_timing_interface dahdi_timing = {
-+ .name = "DAHDI",
-+ .priority = 100,
- .timer_open = dahdi_timer_open,
- .timer_close = dahdi_timer_close,
- .timer_set_rate = dahdi_timer_set_rate,
-@@ -110,7 +112,7 @@
- return ioctl(handle, DAHDI_TIMERPONG, &flags) ? -1 : 0;
- }
-
--static enum ast_timing_event dahdi_timer_get_event(int handle)
-+static enum ast_timer_event dahdi_timer_get_event(int handle)
- {
- int res;
- int event;
-@@ -182,17 +184,13 @@
- return AST_MODULE_LOAD_DECLINE;
- }
-
-- return (timing_funcs_handle = ast_install_timing_functions(&dahdi_timing_functions)) ?
-+ return (timing_funcs_handle = ast_register_timing_interface(&dahdi_timing)) ?
- AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
- }
-
- static int unload_module(void)
- {
-- /* ast_uninstall_timing_functions(timing_funcs_handle); */
--
-- /* This module can not currently be unloaded. No use count handling is being done. */
--
-- return -1;
-+ return ast_unregister_timing_interface(timing_funcs_handle);
- }
-
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI Timing Interface");
-Index: res/res_convert.c
-===================================================================
---- a/res/res_convert.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_convert.c (.../team/group/issue14292) (revision 178988)
-@@ -147,13 +147,13 @@
-
- static int unload_module(void)
- {
-- ast_cli_unregister_multiple(cli_convert, sizeof(cli_convert) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_convert, ARRAY_LEN(cli_convert));
- return 0;
- }
-
- static int load_module(void)
- {
-- ast_cli_register_multiple(cli_convert, sizeof(cli_convert) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_convert, ARRAY_LEN(cli_convert));
- return AST_MODULE_LOAD_SUCCESS;
- }
-
-Index: res/ais/evt.c
-===================================================================
---- a/res/ais/evt.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/ais/evt.c (.../team/group/issue14292) (revision 178988)
-@@ -271,9 +271,9 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "ais evt show event channels";
-+ e->command = "ais show evt event channels";
- e->usage =
-- "Usage: ais evt show event channels\n"
-+ "Usage: ais show evt event channels\n"
- " List configured event channels for the (EVT) Eventing service.\n";
- return NULL;
-
-@@ -475,7 +475,7 @@
- const char *cat = NULL;
- struct ast_flags config_flags = { 0 };
-
-- if (!(cfg = ast_config_load(filename, config_flags)))
-+ if (!(cfg = ast_config_load(filename, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID)
- return;
-
- while ((cat = ast_category_browse(cfg, cat))) {
-Index: res/ais/clm.c
-===================================================================
---- a/res/ais/clm.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/ais/clm.c (.../team/group/issue14292) (revision 178988)
-@@ -78,9 +78,9 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "ais clm show members";
-+ e->command = "ais show clm members";
- e->usage =
-- "Usage: ais clm show members\n"
-+ "Usage: ais show clm members\n"
- " List members of the cluster using the CLM (Cluster Membership) service.\n";
- return NULL;
-
-Index: res/Makefile
-===================================================================
---- a/res/Makefile (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/Makefile (.../team/group/issue14292) (revision 178988)
-@@ -29,6 +29,8 @@
- res_agi.so_LIBS:= -lres_speech.so
- endif
-
-+res_config_ldap.o: ASTCFLAGS+=-DLDAP_DEPRECATED
-+
- ael/ael_lex.o: ael/ael_lex.c ../include/asterisk/ael_structs.h ael/ael.tab.h
- ael/ael_lex.o: ASTCFLAGS+=-I. -Iael -Wno-unused
-
-Index: res/res_jabber.c
-===================================================================
---- a/res/res_jabber.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_jabber.c (.../team/group/issue14292) (revision 178988)
-@@ -59,6 +59,115 @@
- #include "asterisk/astdb.h"
- #include "asterisk/manager.h"
-
-+/*** DOCUMENTATION
-+ <application name="JabberSend" language="en_US">
-+ <synopsis>
-+ Send a Jabber Message
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Jabber" required="true">
-+ <para>Client or transport Asterisk uses to connect to Jabber.</para>
-+ </parameter>
-+ <parameter name="JID" required="true">
-+ <para>XMPP/Jabber JID (Name) of recipient.</para>
-+ </parameter>
-+ <parameter name="Message" required="true">
-+ <para>Message to be sent to the buddy.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Allows user to send a message to a receipent via XMPP.</para>
-+ </description>
-+ </application>
-+ <application name="JabberStatus" language="en_US">
-+ <synopsis>
-+ Retrieve the status of a jabber list member
-+ </synopsis>
-+ <syntax>
-+ <parameter name="Jabber" required="true">
-+ <para>Client or transport Asterisk users to connect to Jabber.</para>
-+ </parameter>
-+ <parameter name="JID" required="true">
-+ <para>XMPP/Jabber JID (Name) of recipient.</para>
-+ </parameter>
-+ <parameter name="Variable" required="true">
-+ <para>Variable to store the status of requested user.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>This application is deprecated. Please use the JABBER_STATUS() function instead.</para>
-+ <para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
-+ The return value in the <replaceable>Variable</replaceable>will be one of the following.</para>
-+ <enumlist>
-+ <enum name="1">
-+ <para>Online.</para>
-+ </enum>
-+ <enum name="2">
-+ <para>Chatty.</para>
-+ </enum>
-+ <enum name="3">
-+ <para>Away.</para>
-+ </enum>
-+ <enum name="4">
-+ <para>Extended Away.</para>
-+ </enum>
-+ <enum name="5">
-+ <para>Do Not Disturb.</para>
-+ </enum>
-+ <enum name="6">
-+ <para>Offline.</para>
-+ </enum>
-+ <enum name="7">
-+ <para>Not In Roster.</para>
-+ </enum>
-+ </enumlist>
-+ </description>
-+ </application>
-+ <function name="JABBER_STATUS" language="en_US">
-+ <synopsis>
-+ Retrieve the status of a jabber list member
-+ </synopsis>
-+ <syntax>
-+ <parameter name="sender" required="true">
-+ <para>XMPP/Jabber ID (Name) of sender.</para>
-+ </parameter>
-+ <parameter name="buddy" required="true">
-+ <para>XMPP/Jabber JID (Name) of recipient.</para>
-+ </parameter>
-+ <parameter name="resource">
-+ <para>Client or transport Asterisk users to connect to Jabber.</para>
-+ </parameter>
-+ </syntax>
-+ <description>
-+ <para>Retrieves the numeric status associated with the specified buddy <replaceable>JID</replaceable>.
-+ The return value will be one of the following.</para>
-+ <enumlist>
-+ <enum name="1">
-+ <para>Online.</para>
-+ </enum>
-+ <enum name="2">
-+ <para>Chatty.</para>
-+ </enum>
-+ <enum name="3">
-+ <para>Away.</para>
-+ </enum>
-+ <enum name="4">
-+ <para>Extended Away.</para>
-+ </enum>
-+ <enum name="5">
-+ <para>Do Not Disturb.</para>
-+ </enum>
-+ <enum name="6">
-+ <para>Offline.</para>
-+ </enum>
-+ <enum name="7">
-+ <para>Not In Roster.</para>
-+ </enum>
-+ </enumlist>
-+ </description>
-+ </function>
-+ ***/
-+
- /*! \todo This should really be renamed to xmpp.conf. For backwards compatibility, we
- need to read both files */
- #define JABBER_CONFIG "jabber.conf"
-@@ -96,7 +205,6 @@
- static int aji_initialize(struct aji_client *client);
- static int aji_client_connect(void *data, ikspak *pak);
- static void aji_set_presence(struct aji_client *client, char *to, char *from, int level, char *desc);
--static char *aji_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
- static char *aji_do_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
- static char *aji_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
- static char *aji_show_clients(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
-@@ -123,9 +231,8 @@
- static int aji_register_transport2(void *data, ikspak *pak);
- */
-
--static struct ast_cli_entry cli_aji_do_debug_deprecated = AST_CLI_DEFINE(aji_do_debug_deprecated, "Enable/disable jabber debugging");
- static struct ast_cli_entry aji_cli[] = {
-- AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug", .deprecate_cmd = &cli_aji_do_debug_deprecated),
-+ AST_CLI_DEFINE(aji_do_set_debug, "Enable/Disable Jabber debug"),
- AST_CLI_DEFINE(aji_do_reload, "Reload Jabber configuration"),
- AST_CLI_DEFINE(aji_show_clients, "Show state of clients and components"),
- AST_CLI_DEFINE(aji_show_buddies, "Show buddy lists of our clients"),
-@@ -134,32 +241,13 @@
-
- static char *app_ajisend = "JabberSend";
-
--static char *ajisend_synopsis = "JabberSend(jabber,screenname,message)";
--
--static char *ajisend_descrip =
--"JabberSend(Jabber,ScreenName,Message)\n"
--" Jabber - Client or transport Asterisk uses to connect to Jabber\n"
--" ScreenName - XMPP/Jabber JID (Name) of recipient\n"
--" Message - Message to be sent to the budd (UTF8)y\n";
--
- static char *app_ajistatus = "JabberStatus";
-
--static char *ajistatus_synopsis = "JabberStatus(Jabber,ScreenName,Variable)";
--
--static char *ajistatus_descrip =
--"JabberStatus(Jabber,ScreenName,Variable)\n"
--" Jabber - Client or transport Asterisk uses to connect to Jabber\n"
--" ScreenName - User Name to retrieve status from.\n"
--" Variable - Variable to store presence in will be 1-6.\n"
--" In order, 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline\n"
--" If not in roster variable will be set to 7\n\n"
--"Note: This application is deprecated. Please use the JABBER_STATUS() function instead.\n";
--
- struct aji_client_container clients;
- struct aji_capabilities *capabilities = NULL;
-
- /*! \brief Global flags, initialized to default values */
--static struct ast_flags globalflags = { AJI_AUTOPRUNE | AJI_AUTOREGISTER };
-+static struct ast_flags globalflags = { AJI_AUTOREGISTER };
-
- /*!
- * \brief Deletes the aji_client data structure.
-@@ -364,7 +452,7 @@
- ast_log(LOG_WARNING, "JabberStatus is deprecated. Please use the JABBER_STATUS dialplan function in the future.\n");
-
- if (!data) {
-- ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<screenname>[/<resource>],<varname>\n");
-+ ast_log(LOG_ERROR, "Usage: JabberStatus(<sender>,<jid>[/<resource>],<varname>\n");
- return 0;
- }
- s = ast_strdupa(data);
-@@ -448,15 +536,7 @@
-
- static struct ast_custom_function jabberstatus_function = {
- .name = "JABBER_STATUS",
-- .synopsis = "Retrieve buddy status",
-- .syntax = "JABBER_STATUS(<sender>,<buddy>[/<resource>])",
- .read = acf_jabberstatus_read,
-- .desc =
--"Retrieves the numeric status associated with the specified buddy (jid). If the\n"
--"buddy does not exist in the buddylist, returns 7.\n"
--"Status will be 1-7.\n"
--" 1=Online, 2=Chatty, 3=Away, 4=XAway, 5=DND, 6=Offline\n"
--" If not in roster variable will be set to 7\n\n",
- };
-
- /*!
-@@ -2075,7 +2155,7 @@
- ASTOBJ_RDLOCK(iterator);
- /* For an aji_buddy, both AUTOPRUNE and AUTOREGISTER will never
- * be called at the same time */
-- if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) {
-+ if (ast_test_flag(&iterator->flags, AJI_AUTOPRUNE)) { /* If autoprune is set on jabber.conf */
- res = ast_aji_send(client, iks_make_s10n(IKS_TYPE_UNSUBSCRIBE, iterator->name,
- "GoodBye. Your status is no longer needed by Asterisk the Open Source PBX"
- " so I am no longer subscribing to your presence.\n"));
-@@ -2390,46 +2470,6 @@
- }
-
- /*!
-- * \brief Turn on/off console debugging (deprecated, use aji_do_set_debug).
-- * \return CLI_SUCCESS.
-- */
--static char *aji_do_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
--
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "jabber debug [off]";
-- e->usage =
-- "Usage: jabber debug [off]\n"
-- " Enables/disables dumping of Jabber packets for debugging purposes.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc == 2) {
-- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
-- ASTOBJ_RDLOCK(iterator);
-- iterator->debug = 1;
-- ASTOBJ_UNLOCK(iterator);
-- });
-- ast_cli(a->fd, "Jabber Debugging Enabled.\n");
-- return CLI_SUCCESS;
-- } else if (a->argc == 3) {
-- if (!strncasecmp(a->argv[2], "off", 3)) {
-- ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
-- ASTOBJ_RDLOCK(iterator);
-- iterator->debug = 0;
-- ASTOBJ_UNLOCK(iterator);
-- });
-- ast_cli(a->fd, "Jabber Debugging Disabled.\n");
-- return CLI_SUCCESS;
-- }
-- }
-- return CLI_SHOWUSAGE; /* defaults to invalid */
--}
--
--/*!
- * \brief Reload jabber module.
- * \return CLI_SUCCESS.
- */
-@@ -2768,14 +2808,6 @@
- } else {
- iks_filter_add_rule(client->f, aji_client_info_handler, client, IKS_RULE_NS, "http://jabber.org/protocol/disco#info", IKS_RULE_DONE);
- }
-- if (!strchr(client->user, '/') && !client->component) { /*client */
-- resource = NULL;
-- if (asprintf(&resource, "%s/asterisk", client->user) >= 0) {
-- client->jid = iks_id_new(client->stack, resource);
-- ast_free(resource);
-- }
-- } else
-- client->jid = iks_id_new(client->stack, client->user);
- iks_set_log_hook(client->p, aji_log_hook);
- ASTOBJ_UNLOCK(client);
- ASTOBJ_CONTAINER_LINK(&clients,client);
-@@ -2878,21 +2910,22 @@
- return -1;
-
- /* Reset flags to default value */
-- ast_set_flag(&globalflags, AJI_AUTOPRUNE | AJI_AUTOREGISTER);
-+ ast_set_flag(&globalflags, AJI_AUTOREGISTER);
-
-- if (!cfg) {
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "No such configuration file %s\n", JABBER_CONFIG);
- return 0;
- }
-
- cat = ast_category_browse(cfg, NULL);
- for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
-- if (!strcasecmp(var->name, "debug"))
-+ if (!strcasecmp(var->name, "debug")) {
- debug = (ast_false(ast_variable_retrieve(cfg, "general", "debug"))) ? 0 : 1;
-- else if (!strcasecmp(var->name, "autoprune"))
-+ } else if (!strcasecmp(var->name, "autoprune")) {
- ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOPRUNE);
-- else if (!strcasecmp(var->name, "autoregister"))
-+ } else if (!strcasecmp(var->name, "autoregister")) {
- ast_set2_flag(&globalflags, ast_true(var->value), AJI_AUTOREGISTER);
-+ }
- }
-
- while (cat) {
-@@ -2942,9 +2975,9 @@
- static char mandescr_jabber_send[] =
- "Description: Sends a message to a Jabber Client.\n"
- "Variables: \n"
--" Jabber: Client or transport Asterisk uses to connect to JABBER.\n"
--" ScreenName: User Name to message.\n"
--" Message: Message to be sent to the buddy\n";
-+" Jabber: Client or transport Asterisk uses to connect to JABBER\n"
-+" JID: XMPP/Jabber JID (Name) of recipient\n"
-+" Message: Message to be sent to the buddy\n";
-
- /*!
- * \brief Send a Jabber Message via call from the Manager
-@@ -3022,7 +3055,7 @@
- static int unload_module(void)
- {
-
-- ast_cli_unregister_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(aji_cli, ARRAY_LEN(aji_cli));
- ast_unregister_application(app_ajisend);
- ast_unregister_application(app_ajistatus);
- ast_manager_unregister("JabberSend");
-@@ -3050,9 +3083,9 @@
- return AST_MODULE_LOAD_DECLINE;
- ast_manager_register2("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send,
- "Sends a message to a Jabber Client", mandescr_jabber_send);
-- ast_register_application(app_ajisend, aji_send_exec, ajisend_synopsis, ajisend_descrip);
-- ast_register_application(app_ajistatus, aji_status_exec, ajistatus_synopsis, ajistatus_descrip);
-- ast_cli_register_multiple(aji_cli, sizeof(aji_cli) / sizeof(struct ast_cli_entry));
-+ ast_register_application_xml(app_ajisend, aji_send_exec);
-+ ast_register_application_xml(app_ajistatus, aji_status_exec);
-+ ast_cli_register_multiple(aji_cli, ARRAY_LEN(aji_cli));
- ast_custom_function_register(&jabberstatus_function);
-
- return 0;
-Index: res/res_config_curl.c
-===================================================================
---- a/res/res_config_curl.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_config_curl.c (.../team/group/issue14292) (revision 178988)
-@@ -88,7 +88,7 @@
- va_end(ap);
-
- ast_str_append(&query, 0, ")}");
-- pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-
- /* Remove any trailing newline characters */
- if ((stringp = strchr(buffer, '\r')) || (stringp = strchr(buffer, '\n')))
-@@ -170,7 +170,7 @@
- ast_str_append(&query, 0, ")}");
-
- /* Do the CURL query */
-- pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-
- if (!(cfg = ast_config_new()))
- goto exit_multi;
-@@ -258,7 +258,7 @@
- va_end(ap);
-
- ast_str_append(&query, 0, ")}");
-- pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-
- /* Line oriented output */
- stringp = buffer;
-@@ -275,6 +275,69 @@
- return -1;
- }
-
-+static int update2_curl(const char *url, const char *unused, va_list ap)
-+{
-+ struct ast_str *query;
-+ char buf1[200], buf2[200];
-+ const char *newparam, *newval;
-+ char *stringp;
-+ int rowcount = -1, lookup = 1, first = 1;
-+ const int EncodeSpecialChars = 1, bufsize = 100;
-+ char *buffer;
-+
-+ if (!ast_custom_function_find("CURL")) {
-+ ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
-+ return -1;
-+ }
-+
-+ if (!(query = ast_str_create(1000)))
-+ return -1;
-+
-+ if (!(buffer = ast_malloc(bufsize))) {
-+ ast_free(query);
-+ return -1;
-+ }
-+
-+ ast_str_set(&query, 0, "${CURL(%s/update?", url);
-+
-+ for (;;) {
-+ if ((newparam = va_arg(ap, const char *)) == SENTINEL) {
-+ if (lookup) {
-+ lookup = 0;
-+ ast_str_append(&query, 0, ",");
-+ /* Back to the first parameter; we don't need a starting '&' */
-+ first = 1;
-+ continue;
-+ } else {
-+ break;
-+ }
-+ }
-+ newval = va_arg(ap, const char *);
-+ ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
-+ ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
-+ ast_str_append(&query, 0, "%s%s=%s", first ? "" : "&", buf1, buf2);
-+ }
-+ va_end(ap);
-+
-+ ast_str_append(&query, 0, ")}");
-+ /* TODO: Make proxies work */
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-+
-+ /* Line oriented output */
-+ stringp = buffer;
-+ while (*stringp <= ' ')
-+ stringp++;
-+ sscanf(stringp, "%d", &rowcount);
-+
-+ ast_free(buffer);
-+ ast_free(query);
-+
-+ if (rowcount >= 0)
-+ return (int)rowcount;
-+
-+ return -1;
-+}
-+
- /*!
- * \brief Execute an INSERT query
- * \param url
-@@ -322,7 +385,7 @@
- va_end(ap);
-
- ast_str_append(&query, 0, ")}");
-- pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-
- stringp = buffer;
- while (*stringp <= ' ')
-@@ -389,7 +452,7 @@
- va_end(ap);
-
- ast_str_append(&query, 0, ")}");
-- pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-
- /* Line oriented output */
- stringp = buffer;
-@@ -448,7 +511,7 @@
- va_end(ap);
-
- ast_str_append(&query, 0, ")}");
-- pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, sizeof(buffer));
- return atoi(buffer);
- }
-
-@@ -481,7 +544,7 @@
- ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
-
- /* Do the CURL query */
-- pbx_substitute_variables_helper(NULL, query->str, buffer, bufsize);
-+ pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
-
- /* Line oriented output */
- stringp = buffer;
-@@ -535,6 +598,7 @@
- .store_func = store_curl,
- .destroy_func = destroy_curl,
- .update_func = update_curl,
-+ .update2_func = update2_curl,
- .require_func = require_curl,
- };
-
-Index: res/res_smdi.c
-===================================================================
---- a/res/res_smdi.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_smdi.c (.../team/group/issue14292) (revision 178988)
-@@ -848,7 +848,7 @@
- int msdstrip = 0; /* strip zero digits */
- long msg_expiry = SMDI_MSG_EXPIRY_TIME;
-
-- if (!(conf = ast_config_load(config_file, config_flags))) {
-+ if (!(conf = ast_config_load(config_file, config_flags)) || conf == CONFIG_STATUS_FILEINVALID) {
- if (reload)
- ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
- else
-Index: res/res_timing_timerfd.c
-===================================================================
---- a/res/res_timing_timerfd.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/res/res_timing_timerfd.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,282 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Mark Michelson <mmichelson@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*!
-+ * \file
-+ * \author Mark Michelson <mmichelson@digium.com>
-+ *
-+ * \brief timerfd timing interface
-+ */
-+
-+/*** MODULEINFO
-+ <depend>timerfd</depend>
-+ ***/
-+
-+#include "asterisk.h"
-+
-+#include <sys/timerfd.h>
-+
-+#include "asterisk/module.h"
-+#include "asterisk/astobj2.h"
-+#include "asterisk/timing.h"
-+#include "asterisk/logger.h"
-+#include "asterisk/utils.h"
-+#include "asterisk/time.h"
-+
-+static void *timing_funcs_handle;
-+
-+static int timerfd_timer_open(void);
-+static void timerfd_timer_close(int handle);
-+static int timerfd_timer_set_rate(int handle, unsigned int rate);
-+static void timerfd_timer_ack(int handle, unsigned int quantity);
-+static int timerfd_timer_enable_continuous(int handle);
-+static int timerfd_timer_disable_continuous(int handle);
-+static enum ast_timer_event timerfd_timer_get_event(int handle);
-+static unsigned int timerfd_timer_get_max_rate(int handle);
-+
-+static struct ast_timing_interface timerfd_timing = {
-+ .name = "timerfd",
-+ .priority = 200,
-+ .timer_open = timerfd_timer_open,
-+ .timer_close = timerfd_timer_close,
-+ .timer_set_rate = timerfd_timer_set_rate,
-+ .timer_ack = timerfd_timer_ack,
-+ .timer_enable_continuous = timerfd_timer_enable_continuous,
-+ .timer_disable_continuous = timerfd_timer_disable_continuous,
-+ .timer_get_event = timerfd_timer_get_event,
-+ .timer_get_max_rate = timerfd_timer_get_max_rate,
-+};
-+
-+static struct ao2_container *timerfd_timers;
-+
-+#define TIMERFD_TIMER_BUCKETS 563
-+#define TIMERFD_MAX_RATE 1000
-+
-+struct timerfd_timer {
-+ int handle;
-+ struct itimerspec saved_timer;
-+ unsigned int is_continuous:1;
-+};
-+
-+static int timerfd_timer_hash(const void *obj, const int flags)
-+{
-+ const struct timerfd_timer *timer = obj;
-+
-+ return timer->handle;
-+}
-+
-+static int timerfd_timer_cmp(void *obj, void *args, int flags)
-+{
-+ struct timerfd_timer *timer1 = obj, *timer2 = args;
-+ return timer1->handle == timer2->handle ? CMP_MATCH | CMP_STOP : 0;
-+}
-+
-+static void timer_destroy(void *obj)
-+{
-+ struct timerfd_timer *timer = obj;
-+ close(timer->handle);
-+}
-+
-+static int timerfd_timer_open(void)
-+{
-+ struct timerfd_timer *timer;
-+ int handle;
-+
-+ if (!(timer = ao2_alloc(sizeof(*timer), timer_destroy))) {
-+ ast_log(LOG_ERROR, "Could not allocate memory for timerfd_timer structure\n");
-+ return -1;
-+ }
-+ if ((handle = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
-+ ast_log(LOG_ERROR, "Failed to create timerfd timer: %s\n", strerror(errno));
-+ ao2_ref(timer, -1);
-+ return -1;
-+ }
-+
-+ timer->handle = handle;
-+ ao2_link(timerfd_timers, timer);
-+ /* Get rid of the reference from the allocation */
-+ ao2_ref(timer, -1);
-+ return handle;
-+}
-+
-+static void timerfd_timer_close(int handle)
-+{
-+ struct timerfd_timer *our_timer, find_helper = {
-+ .handle = handle,
-+ };
-+
-+ if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
-+ ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
-+ return;
-+ }
-+
-+ ao2_unlink(timerfd_timers, our_timer);
-+ ao2_ref(our_timer, -1);
-+}
-+
-+static int timerfd_timer_set_rate(int handle, unsigned int rate)
-+{
-+ struct timerfd_timer *our_timer, find_helper = {
-+ .handle = handle,
-+ };
-+
-+ if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
-+ ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
-+ return -1;
-+ }
-+
-+ our_timer->saved_timer.it_value.tv_sec = 0;
-+ our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L;
-+ our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec;
-+ our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec;
-+
-+ return timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
-+}
-+
-+static void timerfd_timer_ack(int handle, unsigned int quantity)
-+{
-+ uint64_t expirations;
-+ int read_result = 0;
-+
-+ do {
-+ read_result = read(handle, &expirations, sizeof(expirations));
-+ if (read_result == -1) {
-+ if (errno == EINTR) {
-+ continue;
-+ } else {
-+ ast_log(LOG_ERROR, "Read error: %s\n", strerror(errno));
-+ break;
-+ }
-+ }
-+ } while (read_result != sizeof(expirations));
-+
-+ if (expirations != quantity) {
-+ ast_debug(2, "Expected to acknowledge %u ticks but got %llu instead\n", quantity, (unsigned long long) expirations);
-+ }
-+}
-+
-+static int timerfd_timer_enable_continuous(int handle)
-+{
-+ int res;
-+ struct itimerspec continuous_timer = {
-+ .it_value.tv_nsec = 1L,
-+ };
-+ struct timerfd_timer *our_timer, find_helper = {
-+ .handle = handle,
-+ };
-+
-+ if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
-+ ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
-+ return -1;
-+ }
-+
-+ if (our_timer->is_continuous) {
-+ /*It's already in continous mode, no need to do
-+ * anything further
-+ */
-+ ao2_ref(our_timer, -1);
-+ return 0;
-+ }
-+
-+ res = timerfd_settime(handle, 0, &continuous_timer, &our_timer->saved_timer);
-+ our_timer->is_continuous = 1;
-+ ao2_ref(our_timer, -1);
-+ return res;
-+}
-+
-+static int timerfd_timer_disable_continuous(int handle)
-+{
-+ int res;
-+ struct timerfd_timer *our_timer, find_helper = {
-+ .handle = handle,
-+ };
-+
-+ if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
-+ ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
-+ return -1;
-+ }
-+
-+ if(!our_timer->is_continuous) {
-+ /* No reason to do anything if we're not
-+ * in continuous mode
-+ */
-+ ao2_ref(our_timer, -1);
-+ return 0;
-+ }
-+
-+ res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL);
-+ our_timer->is_continuous = 0;
-+ memset(&our_timer->saved_timer, 0, sizeof(our_timer->saved_timer));
-+ ao2_ref(our_timer, -1);
-+ return res;
-+}
-+
-+static enum ast_timer_event timerfd_timer_get_event(int handle)
-+{
-+ enum ast_timer_event res;
-+ struct timerfd_timer *our_timer, find_helper = {
-+ .handle = handle,
-+ };
-+
-+ if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) {
-+ ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle);
-+ return -1;
-+ }
-+
-+ if (our_timer->is_continuous) {
-+ res = AST_TIMING_EVENT_CONTINUOUS;
-+ } else {
-+ res = AST_TIMING_EVENT_EXPIRED;
-+ }
-+
-+ ao2_ref(our_timer, -1);
-+ return res;
-+}
-+
-+static unsigned int timerfd_timer_get_max_rate(int handle)
-+{
-+ return TIMERFD_MAX_RATE;
-+}
-+
-+static int load_module(void)
-+{
-+ if (!(timerfd_timers = ao2_container_alloc(TIMERFD_TIMER_BUCKETS, timerfd_timer_hash, timerfd_timer_cmp))) {
-+ return AST_MODULE_LOAD_DECLINE;
-+ }
-+
-+ if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) {
-+ ao2_ref(timerfd_timers, -1);
-+ return AST_MODULE_LOAD_DECLINE;
-+ }
-+
-+ return AST_MODULE_LOAD_SUCCESS;
-+}
-+
-+static int unload_module(void)
-+{
-+ int res;
-+
-+ if (!(res = ast_unregister_timing_interface(timing_funcs_handle))) {
-+ ao2_ref(timerfd_timers, -1);
-+ timerfd_timers = NULL;
-+ }
-+
-+ return res;
-+}
-+
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Timerfd Timing Interface");
-
-Property changes on: res/res_timing_timerfd.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: res/res_realtime.c
-===================================================================
---- a/res/res_realtime.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_realtime.c (.../team/group/issue14292) (revision 178988)
-@@ -78,7 +78,8 @@
- return CLI_SUCCESS;
- }
-
--static char *cli_realtime_update(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) {
-+static char *cli_realtime_update(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
- int res = 0;
-
- switch (cmd) {
-@@ -95,36 +96,170 @@
- return NULL;
- }
-
--
- if (a->argc < 7)
- return CLI_SHOWUSAGE;
-
- res = ast_update_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], SENTINEL);
-
-- if(res < 0) {
-+ if (res < 0) {
- ast_cli(a->fd, "Failed to update. Check the debug log for possible SQL related entries.\n");
- return CLI_FAILURE;
- }
-
-- ast_cli(a->fd, "Updated %d RealTime record%s.\n", res, ESS(res));
-+ ast_cli(a->fd, "Updated %d RealTime record%s.\n", res, ESS(res));
-
- return CLI_SUCCESS;
- }
-
-+static char *cli_realtime_update2(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ int res = -1;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "realtime update2";
-+ e->usage =
-+ "Usage: realtime update2 <family> <colmatch> <valuematch> [... <colmatch5> <valuematch5>] NULL <colupdate> <newvalue>\n"
-+ " Update a single variable using the RealTime driver.\n"
-+ " You must supply a family name, a column to update on, a new value, column to match, and value to match.\n"
-+ " Ex: realtime update sipfriends name bobsphone port 4343\n"
-+ " will execute SQL as UPDATE sipfriends SET port = 4343 WHERE name = bobsphone\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return NULL;
-+ }
-+
-+ if (a->argc < 7)
-+ return CLI_SHOWUSAGE;
-+
-+ if (a->argc == 7) {
-+ res = ast_update2_realtime(a->argv[2], a->argv[3], a->argv[4], SENTINEL, a->argv[5], a->argv[6], SENTINEL);
-+ } else if (a->argc == 9) {
-+ res = ast_update2_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], SENTINEL, a->argv[7], a->argv[8], SENTINEL);
-+ } else if (a->argc == 11) {
-+ res = ast_update2_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], SENTINEL, a->argv[9], a->argv[10], SENTINEL);
-+ } else if (a->argc == 13) {
-+ res = ast_update2_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], a->argv[9], a->argv[10], SENTINEL, a->argv[11], a->argv[12], SENTINEL);
-+ } else if (a->argc == 15) {
-+ res = ast_update2_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], a->argv[9], a->argv[10], a->argv[11], a->argv[12], SENTINEL, a->argv[13], a->argv[14], SENTINEL);
-+ } else {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ if (res < 0) {
-+ ast_cli(a->fd, "Failed to update. Check the debug log for possible SQL related entries.\n");
-+ return CLI_FAILURE;
-+ }
-+
-+ ast_cli(a->fd, "Updated %d RealTime record%s.\n", res, ESS(res));
-+
-+ return CLI_SUCCESS;
-+}
-+
-+static char *cli_realtime_store(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ int res = -1;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "realtime store";
-+ e->usage =
-+ "Usage: realtime store <family> <colname1> <value1> [<colname2> <value2> [... <colname5> <value5>]]\n"
-+ " Create a stored row using the RealTime driver.\n"
-+ " You must supply a family name and name/value pairs (up to 5). If\n"
-+ " you need to store more than 5 key/value pairs, start with the first\n"
-+ " five, then use 'realtime update' or 'realtime update2' to add\n"
-+ " additional columns.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return NULL;
-+ }
-+
-+ if (a->argc < 5) {
-+ return CLI_SHOWUSAGE;
-+ } else if (a->argc == 5) {
-+ res = ast_store_realtime(a->argv[2], a->argv[3], a->argv[4], SENTINEL);
-+ } else if (a->argc == 7) {
-+ res = ast_store_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], SENTINEL);
-+ } else if (a->argc == 9) {
-+ res = ast_store_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], SENTINEL);
-+ } else if (a->argc == 11) {
-+ res = ast_store_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], a->argv[9], a->argv[10], SENTINEL);
-+ } else if (a->argc == 13) {
-+ res = ast_store_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], a->argv[9], a->argv[10], a->argv[11], a->argv[12], SENTINEL);
-+ } else {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ if (res < 0) {
-+ ast_cli(a->fd, "Failed to store record. Check the debug log for possible SQL related entries.\n");
-+ return CLI_FAILURE;
-+ }
-+
-+ ast_cli(a->fd, "Stored RealTime record.\n");
-+
-+ return CLI_SUCCESS;
-+}
-+
-+static char *cli_realtime_destroy(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ int res = -1;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "realtime destroy";
-+ e->usage =
-+ "Usage: realtime destroy <family> <colmatch1> <valuematch1> [<colmatch2> <valuematch2> [... <colmatch5> <valuematch5>]]\n"
-+ " Remove a stored row using the RealTime driver.\n"
-+ " You must supply a family name and name/value pairs (up to 5).\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return NULL;
-+ }
-+
-+ if (a->argc < 5) {
-+ return CLI_SHOWUSAGE;
-+ } else if (a->argc == 5) {
-+ res = ast_destroy_realtime(a->argv[2], a->argv[3], a->argv[4], SENTINEL);
-+ } else if (a->argc == 7) {
-+ res = ast_destroy_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], SENTINEL);
-+ } else if (a->argc == 9) {
-+ res = ast_destroy_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], SENTINEL);
-+ } else if (a->argc == 11) {
-+ res = ast_destroy_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], a->argv[9], a->argv[10], SENTINEL);
-+ } else if (a->argc == 13) {
-+ res = ast_destroy_realtime(a->argv[2], a->argv[3], a->argv[4], a->argv[5], a->argv[6], a->argv[7], a->argv[8], a->argv[9], a->argv[10], a->argv[11], a->argv[12], SENTINEL);
-+ } else {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ if (res < 0) {
-+ ast_cli(a->fd, "Failed to remove record. Check the debug log for possible SQL related entries.\n");
-+ return CLI_FAILURE;
-+ }
-+
-+ ast_cli(a->fd, "Removed %d RealTime record%s.\n", res, ESS(res));
-+
-+ return CLI_SUCCESS;
-+}
-+
- static struct ast_cli_entry cli_realtime[] = {
- AST_CLI_DEFINE(cli_realtime_load, "Used to print out RealTime variables."),
- AST_CLI_DEFINE(cli_realtime_update, "Used to update RealTime variables."),
-+ AST_CLI_DEFINE(cli_realtime_update2, "Used to test the RealTime update2 method"),
-+ AST_CLI_DEFINE(cli_realtime_store, "Store a new row into a RealTime database"),
-+ AST_CLI_DEFINE(cli_realtime_destroy, "Delete a row from a RealTime database"),
- };
-
- static int unload_module(void)
- {
-- ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
- return 0;
- }
-
- static int load_module(void)
- {
-- ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
- return AST_MODULE_LOAD_SUCCESS;
- }
-
-Index: res/res_clialiases.c
-===================================================================
---- a/res/res_clialiases.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/res/res_clialiases.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,260 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Joshua Colp <jcolp@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief CLI Aliases
-+ *
-+ * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
-+ *
-+ * This module provides the capability to create aliases to other
-+ * CLI commands.
-+ */
-+
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/module.h"
-+#include "asterisk/config.h"
-+#include "asterisk/cli.h"
-+#include "asterisk/astobj2.h"
-+
-+/*! Maximum number of buckets for CLI aliases */
-+#define MAX_ALIAS_BUCKETS 53
-+
-+/*! Configuration file used for this application */
-+static const char config_file[] = "cli_aliases.conf";
-+
-+struct cli_alias {
-+ struct ast_cli_entry cli_entry; /*!< Actual CLI structure used for this alias */
-+ char *alias; /*!< CLI Alias */
-+ char *real_cmd; /*!< Actual CLI command it is aliased to */
-+};
-+
-+static struct ao2_container *cli_aliases;
-+
-+/*! \brief Hashing function used for aliases */
-+static int alias_hash_cb(const void *obj, const int flags)
-+{
-+ const struct cli_alias *alias = obj;
-+ return ast_str_hash(alias->cli_entry.command);
-+}
-+
-+/*! \brief Comparison function used for aliases */
-+static int alias_cmp_cb(void *obj, void *arg, int flags)
-+{
-+ const struct cli_alias *alias0 = obj, *alias1 = arg;
-+
-+ return (alias0->cli_entry.command == alias1->cli_entry.command ? CMP_MATCH | CMP_STOP : 0);
-+}
-+
-+/*! \brief Destruction function used for aliases */
-+static void alias_destroy(void *obj)
-+{
-+ struct cli_alias *alias = obj;
-+
-+ /* Unregister the CLI entry from the core */
-+ ast_cli_unregister(&alias->cli_entry);
-+
-+ return;
-+}
-+
-+/*! \brief Function which passes through an aliased CLI command to the real one */
-+static char *cli_alias_passthrough(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ struct cli_alias *alias;
-+ struct cli_alias tmp = {
-+ .cli_entry.command = e->command,
-+ };
-+ char *generator;
-+ const char *line;
-+
-+ /* Try to find the alias based on the CLI entry */
-+ if (!(alias = ao2_find(cli_aliases, &tmp, OBJ_POINTER))) {
-+ return 0;
-+ }
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ ao2_ref(alias, -1);
-+ return NULL;
-+ case CLI_GENERATE:
-+ line = a->line;
-+ line += (strlen(alias->alias));
-+ if (!ast_strlen_zero(a->word)) {
-+ struct ast_str *real_cmd = ast_str_alloca(strlen(alias->real_cmd) + strlen(line) + 1);
-+ ast_str_append(&real_cmd, 0, "%s%s", alias->real_cmd, line);
-+ generator = ast_cli_generator(ast_str_buffer(real_cmd), a->word, a->n);
-+ } else {
-+ generator = ast_cli_generator(alias->real_cmd, a->word, a->n);
-+ }
-+ ao2_ref(alias, -1);
-+ return generator;
-+ }
-+
-+ /* If they gave us extra arguments we need to construct a string to pass in */
-+ if (a->argc != e->args) {
-+ struct ast_str *real_cmd = ast_str_alloca(2048);
-+ int i;
-+
-+ ast_str_append(&real_cmd, 0, "%s", alias->real_cmd);
-+
-+ /* Add the additional arguments that have been passed in */
-+ for (i = e->args + 1; i <= a->argc; i++) {
-+ ast_str_append(&real_cmd, 0, " %s", a->argv[i - 1]);
-+ }
-+
-+ ast_cli_command(a->fd, ast_str_buffer(real_cmd));
-+ } else {
-+ ast_cli_command(a->fd, alias->real_cmd);
-+ }
-+
-+ ao2_ref(alias, -1);
-+
-+ return CLI_SUCCESS;
-+}
-+
-+/*! \brief CLI Command to display CLI Aliases */
-+static char *alias_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+#define FORMAT "%-50.50s %-50.50s\n"
-+ struct cli_alias *alias;
-+ struct ao2_iterator i;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "cli show aliases";
-+ e->usage =
-+ "Usage: cli show aliases\n"
-+ " Displays a list of aliased CLI commands.\n";
-+ return NULL;
-+ case CLI_GENERATE:
-+ return NULL;
-+ }
-+
-+ ast_cli(a->fd, FORMAT, "Alias Command", "Real Command");
-+
-+ i = ao2_iterator_init(cli_aliases, 0);
-+
-+ for (; (alias = ao2_iterator_next(&i)); ao2_ref(alias, -1)) {
-+ ast_cli(a->fd, FORMAT, alias->alias, alias->real_cmd);
-+ }
-+
-+ return CLI_SUCCESS;
-+#undef FORMAT
-+}
-+
-+/*! \brief CLI commands to interact with things */
-+static struct ast_cli_entry cli_alias[] = {
-+ AST_CLI_DEFINE(alias_show, "Show CLI command aliases"),
-+};
-+
-+/*! \brief Function called to to see if an alias is marked for destruction, they always are! */
-+static int alias_marked(void *obj, void *arg, int flags)
-+{
-+ return CMP_MATCH;
-+}
-+
-+/*! \brief Function called to load or reload the configuration file */
-+static void load_config(int reload)
-+{
-+ struct ast_config *cfg = NULL;
-+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-+ struct cli_alias *alias;
-+ struct ast_variable *v, *v1;
-+
-+ if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "res_clialiases configuration file '%s' not found\n", config_file);
-+ return;
-+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-+ return;
-+ }
-+
-+ /* Destroy any existing CLI aliases */
-+ if (reload) {
-+ ao2_callback(cli_aliases, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , alias_marked, NULL);
-+ }
-+
-+ for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
-+ if (strcmp(v->name, "template")) {
-+ ast_log(LOG_WARNING, "%s is not a correct option in [%s]\n", v->name, "general");
-+ continue;
-+ }
-+ /* Read in those there CLI aliases */
-+ for (v1 = ast_variable_browse(cfg, v->value); v1; v1 = v1->next) {
-+ if (!(alias = ao2_alloc((sizeof(*alias) + strlen(v1->name) + strlen(v1->value) + 2), alias_destroy))) {
-+ continue;
-+ }
-+ alias->alias = ((char *) alias) + sizeof(*alias);
-+ alias->real_cmd = ((char *) alias->alias) + strlen(v1->name) + 1;
-+ strcpy(alias->alias, v1->name);
-+ strcpy(alias->real_cmd, v1->value);
-+ alias->cli_entry.handler = cli_alias_passthrough;
-+ alias->cli_entry.command = alias->alias;
-+ alias->cli_entry.usage = "Aliased CLI Command";
-+
-+ ast_cli_register(&alias->cli_entry);
-+ ao2_link(cli_aliases, alias);
-+ ast_verbose(VERBOSE_PREFIX_2 "Aliased CLI command '%s' to '%s'\n", v1->name, v1->value);
-+ ao2_ref(alias, -1);
-+ }
-+ }
-+
-+ ast_config_destroy(cfg);
-+
-+ return;
-+}
-+
-+/*! \brief Function called to reload the module */
-+static int reload_module(void)
-+{
-+ load_config(1);
-+ return 0;
-+}
-+
-+/*! \brief Function called to unload the module */
-+static int unload_module(void)
-+{
-+ ao2_ref(cli_aliases, -1);
-+
-+ ast_cli_unregister_multiple(cli_alias, ARRAY_LEN(cli_alias));
-+
-+ return 0;
-+}
-+
-+/*! \brief Function called to load the module */
-+static int load_module(void)
-+{
-+ if (!(cli_aliases = ao2_container_alloc(MAX_ALIAS_BUCKETS, alias_hash_cb, alias_cmp_cb))) {
-+ return AST_MODULE_LOAD_DECLINE;
-+ }
-+
-+ load_config(0);
-+
-+ ast_cli_register_multiple(cli_alias, ARRAY_LEN(cli_alias));
-+
-+ return AST_MODULE_LOAD_SUCCESS;
-+}
-+
-+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "CLI Aliases",
-+ .load = load_module,
-+ .unload = unload_module,
-+ .reload = reload_module,
-+ );
-
-Property changes on: res/res_clialiases.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: res/res_clioriginate.c
-===================================================================
---- a/res/res_clioriginate.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_clioriginate.c (.../team/group/issue14292) (revision 178988)
-@@ -122,26 +122,26 @@
- char *res;
- switch (cmd) {
- case CLI_INIT:
-- e->command = "originate";
-+ e->command = "channel originate";
- e->usage =
- " There are two ways to use this command. A call can be originated between a\n"
- "channel and a specific application, or between a channel and an extension in\n"
- "the dialplan. This is similar to call files or the manager originate action.\n"
- "Calls originated with this command are given a timeout of 30 seconds.\n\n"
-
-- "Usage1: originate <tech/data> application <appname> [appdata]\n"
-+ "Usage1: channel originate <tech/data> application <appname> [appdata]\n"
- " This will originate a call between the specified channel tech/data and the\n"
- "given application. Arguments to the application are optional. If the given\n"
- "arguments to the application include spaces, all of the arguments to the\n"
- "application need to be placed in quotation marks.\n\n"
-
-- "Usage2: originate <tech/data> extension [exten@][context]\n"
-+ "Usage2: channel originate <tech/data> extension [exten@][context]\n"
- " This will originate a call between the specified channel tech/data and the\n"
- "given extension. If no context is specified, the 'default' context will be\n"
- "used. If no extension is given, the 's' extension will be used.\n";
- return NULL;
- case CLI_GENERATE:
-- if (a->pos != 2)
-+ if (a->pos != 3)
- return NULL;
-
- /* ugly, can be removed when CLI entries have ast_module pointers */
-@@ -152,35 +152,84 @@
- return res;
- }
-
-- if (ast_strlen_zero(a->argv[1]) || ast_strlen_zero(a->argv[2]))
-+ if (ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3]))
- return CLI_SHOWUSAGE;
-
- /* ugly, can be removed when CLI entries have ast_module pointers */
- ast_module_ref(ast_module_info->self);
-
-- if (!strcasecmp("application", a->argv[2])) {
-- res = orig_app(a->fd, a->argv[1], a->argv[3], a->argv[4]);
-- } else if (!strcasecmp("extension", a->argv[2])) {
-- res = orig_exten(a->fd, a->argv[1], a->argv[3]);
-- } else
-+ if (!strcasecmp("application", a->argv[3])) {
-+ res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);
-+ } else if (!strcasecmp("extension", a->argv[3])) {
-+ res = orig_exten(a->fd, a->argv[2], a->argv[4]);
-+ } else {
-+ ast_log(LOG_WARNING, "else");
- res = CLI_SHOWUSAGE;
-+ }
-
- ast_module_unref(ast_module_info->self);
-
- return res;
- }
-
-+static char *handle_redirect(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-+{
-+ const char *name, *dest;
-+ struct ast_channel *chan;
-+ int res;
-+
-+ switch (cmd) {
-+ case CLI_INIT:
-+ e->command = "channel redirect";
-+ e->usage = ""
-+ "Usage: channel redirect <channel> <[[context,]exten,]priority>\n"
-+ " Redirect an active channel to a specified extension.\n";
-+ /*! \todo It would be nice to be able to redirect 2 channels at the same
-+ * time like you can with AMI redirect. However, it is not possible to acquire
-+ * two channels without the potential for a deadlock with how ast_channel structs
-+ * are managed today. Once ast_channel is a refcounted object, this command
-+ * will be able to support that. */
-+ return NULL;
-+ case CLI_GENERATE:
-+ return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
-+ }
-+
-+ if (a->argc != e->args + 2) {
-+ return CLI_SHOWUSAGE;
-+ }
-+
-+ name = a->argv[2];
-+ dest = a->argv[3];
-+
-+ chan = ast_get_channel_by_name_locked(name);
-+ if (!chan) {
-+ ast_cli(a->fd, "Channel '%s' not found\n", name);
-+ return CLI_FAILURE;
-+ }
-+
-+ res = ast_async_parseable_goto(chan, dest);
-+
-+ ast_channel_unlock(chan);
-+
-+ if (!res) {
-+ ast_cli(a->fd, "Channel '%s' successfully redirected to %s\n", name, dest);
-+ } else {
-+ ast_cli(a->fd, "Channel '%s' failed to be redirected to %s\n", name, dest);
-+ }
-+
-+ return res ? CLI_FAILURE : CLI_SUCCESS;
-+}
-+
- static struct ast_cli_entry cli_cliorig[] = {
- AST_CLI_DEFINE(handle_orig, "Originate a call"),
-+ AST_CLI_DEFINE(handle_redirect, "Redirect a call"),
- };
-
--/*! \brief Unload orginate module */
- static int unload_module(void)
- {
- return ast_cli_unregister_multiple(cli_cliorig, ARRAY_LEN(cli_cliorig));
- }
-
--/*! \brief Load orginate module */
- static int load_module(void)
- {
- int res;
-@@ -188,4 +237,4 @@
- return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
- }
-
--AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call origination from the CLI");
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call origination and redirection from the CLI");
-Index: res/res_config_pgsql.c
-===================================================================
---- a/res/res_config_pgsql.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_config_pgsql.c (.../team/group/issue14292) (revision 178988)
-@@ -42,6 +42,10 @@
- #include "asterisk/cli.h"
-
- AST_MUTEX_DEFINE_STATIC(pgsql_lock);
-+AST_THREADSTORAGE(sql_buf);
-+AST_THREADSTORAGE(findtable_buf);
-+AST_THREADSTORAGE(where_buf);
-+AST_THREADSTORAGE(escapebuf_buf);
-
- #define RES_CONFIG_PGSQL_CONF "res_pgsql.conf"
-
-@@ -59,7 +63,7 @@
- };
-
- struct tables {
-- ast_mutex_t lock;
-+ ast_rwlock_t lock;
- AST_LIST_HEAD_NOLOCK(psql_columns, columns) columns;
- AST_LIST_ENTRY(tables) list;
- char name[0];
-@@ -87,15 +91,24 @@
- AST_CLI_DEFINE(handle_cli_realtime_pgsql_cache, "Shows cached tables within the PostgreSQL realtime driver"),
- };
-
-+#define ESCAPE_STRING(buffer, stringname) \
-+ do { \
-+ int len; \
-+ if ((len = strlen(stringname)) > (ast_str_size(buffer) - 1) / 2) { \
-+ ast_str_make_space(&buffer, len * 2 + 1); \
-+ } \
-+ PQescapeStringConn(pgsqlConn, ast_str_buffer(buffer), stringname, len, &pgresult); \
-+ } while (0)
-+
- static void destroy_table(struct tables *table)
- {
- struct columns *column;
-- ast_mutex_lock(&table->lock);
-+ ast_rwlock_wrlock(&table->lock);
- while ((column = AST_LIST_REMOVE_HEAD(&table->columns, list))) {
- ast_free(column);
- }
-- ast_mutex_unlock(&table->lock);
-- ast_mutex_destroy(&table->lock);
-+ ast_rwlock_unlock(&table->lock);
-+ ast_rwlock_destroy(&table->lock);
- ast_free(table);
- }
-
-@@ -103,7 +116,7 @@
- {
- struct columns *column;
- struct tables *table;
-- struct ast_str *sql = ast_str_create(330);
-+ struct ast_str *sql = ast_str_thread_get(&findtable_buf, 330);
- char *pgerror;
- PGresult *result;
- char *fname, *ftype, *flen, *fnotnull, *fdef;
-@@ -113,7 +126,7 @@
- AST_LIST_TRAVERSE(&psql_tables, table, list) {
- if (!strcasecmp(table->name, tablename)) {
- ast_debug(1, "Found table in cache; now locking\n");
-- ast_mutex_lock(&table->lock);
-+ ast_rwlock_rdlock(&table->lock);
- ast_debug(1, "Lock cached table; now returning\n");
- AST_LIST_UNLOCK(&psql_tables);
- return table;
-@@ -124,7 +137,7 @@
-
- /* Not found, scan the table */
- ast_str_set(&sql, 0, "SELECT a.attname, t.typname, a.attlen, a.attnotnull, d.adsrc, a.atttypmod FROM pg_class c, pg_type t, pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.atthasdef AND d.adrelid = a.attrelid AND d.adnum = a.attnum WHERE c.oid = a.attrelid AND a.atttypid = t.oid AND (a.attnum > 0) AND c.relname = '%s' ORDER BY c.relname, attnum", tablename);
-- result = PQexec(pgsqlConn, sql->str);
-+ result = PQexec(pgsqlConn, ast_str_buffer(sql));
- ast_debug(1, "Query of table structure complete. Now retrieving results.\n");
- if (PQresultStatus(result) != PGRES_TUPLES_OK) {
- pgerror = PQresultErrorMessage(result);
-@@ -140,9 +153,9 @@
- return NULL;
- }
- strcpy(table->name, tablename); /* SAFE */
-- ast_mutex_init(&table->lock);
-+ ast_rwlock_init(&table->lock);
- AST_LIST_HEAD_INIT_NOLOCK(&table->columns);
--
-+
- rows = PQntuples(result);
- for (i = 0; i < rows; i++) {
- fname = PQgetvalue(result, i, 0);
-@@ -186,23 +199,39 @@
- PQclear(result);
-
- AST_LIST_INSERT_TAIL(&psql_tables, table, list);
-- ast_mutex_lock(&table->lock);
-+ ast_rwlock_rdlock(&table->lock);
- AST_LIST_UNLOCK(&psql_tables);
- return table;
- }
-
--static struct ast_variable *realtime_pgsql(const char *database, const char *table, va_list ap)
-+#define release_table(table) ast_rwlock_unlock(&(table)->lock);
-+
-+static struct columns *find_column(struct tables *t, const char *colname)
- {
-+ struct columns *column;
-+
-+ /* Check that the column exists in the table */
-+ AST_LIST_TRAVERSE(&t->columns, column, list) {
-+ if (strcmp(column->name, colname) == 0) {
-+ return column;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, va_list ap)
-+{
- PGresult *result = NULL;
-- int num_rows = 0, pgerror;
-- char sql[256], escapebuf[513];
-+ int num_rows = 0, pgresult;
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
-+ struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
- char *stringp;
- char *chunk;
- char *op;
- const char *newparam, *newval;
- struct ast_variable *var = NULL, *prev = NULL;
-
-- if (!table) {
-+ if (!tablename) {
- ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
- return NULL;
- }
-@@ -216,7 +245,7 @@
- if (pgsqlConn) {
- PQfinish(pgsqlConn);
- pgsqlConn = NULL;
-- };
-+ }
- return NULL;
- }
-
-@@ -224,15 +253,14 @@
- If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
- op = strchr(newparam, ' ') ? "" : " =";
-
-- PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
- va_end(ap);
- return NULL;
- }
-
-- snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
-- escapebuf);
-+ ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- if (!strchr(newparam, ' '))
-@@ -240,15 +268,14 @@
- else
- op = "";
-
-- PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
- va_end(ap);
- return NULL;
- }
-
-- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
-- op, escapebuf);
-+ ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
- }
- va_end(ap);
-
-@@ -259,10 +286,10 @@
- return NULL;
- }
-
-- if (!(result = PQexec(pgsqlConn, sql))) {
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
- ast_log(LOG_WARNING,
-- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
-+ "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
- ast_mutex_unlock(&pgsql_lock);
- return NULL;
-@@ -272,8 +299,8 @@
- && result_status != PGRES_TUPLES_OK
- && result_status != PGRES_NONFATAL_ERROR) {
- ast_log(LOG_WARNING,
-- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
-+ "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", tablename, database);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
- PQresultErrorMessage(result), PQresStatus(result_status));
- ast_mutex_unlock(&pgsql_lock);
-@@ -281,7 +308,7 @@
- }
- }
-
-- ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql);
-+ ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
-
- if ((num_rows = PQntuples(result)) > 0) {
- int i = 0;
-@@ -318,7 +345,7 @@
- }
- ast_free(fieldnames);
- } else {
-- ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s.\n", table);
-+ ast_debug(1, "Postgresql RealTime: Could not find any rows in table %s@%s.\n", tablename, database);
- }
-
- ast_mutex_unlock(&pgsql_lock);
-@@ -330,8 +357,9 @@
- static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
- {
- PGresult *result = NULL;
-- int num_rows = 0, pgerror;
-- char sql[256], escapebuf[513];
-+ int num_rows = 0, pgresult;
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
-+ struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
- const char *initfield = NULL;
- char *stringp;
- char *chunk;
-@@ -358,7 +386,7 @@
- if (pgsqlConn) {
- PQfinish(pgsqlConn);
- pgsqlConn = NULL;
-- };
-+ }
- return NULL;
- }
-
-@@ -375,15 +403,14 @@
- else
- op = "";
-
-- PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
- va_end(ap);
- return NULL;
- }
-
-- snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
-- escapebuf);
-+ ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- if (!strchr(newparam, ' '))
-@@ -391,19 +418,18 @@
- else
- op = "";
-
-- PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
- va_end(ap);
- return NULL;
- }
-
-- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
-- op, escapebuf);
-+ ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
- }
-
- if (initfield) {
-- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
-+ ast_str_append(&sql, 0, " ORDER BY %s", initfield);
- }
-
- va_end(ap);
-@@ -415,10 +441,10 @@
- return NULL;
- }
-
-- if (!(result = PQexec(pgsqlConn, sql))) {
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
- ast_log(LOG_WARNING,
-- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
-+ "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
- ast_mutex_unlock(&pgsql_lock);
- return NULL;
-@@ -428,8 +454,8 @@
- && result_status != PGRES_TUPLES_OK
- && result_status != PGRES_NONFATAL_ERROR) {
- ast_log(LOG_WARNING,
-- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
-+ "PostgreSQL RealTime: Failed to query %s@%s. Check debug for more info.\n", table, database);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
- PQresultErrorMessage(result), PQresStatus(result_status));
- ast_mutex_unlock(&pgsql_lock);
-@@ -437,7 +463,7 @@
- }
- }
-
-- ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql);
-+ ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, ast_str_buffer(sql));
-
- if ((num_rows = PQntuples(result)) > 0) {
- int numFields = PQnfields(result);
-@@ -490,22 +516,20 @@
- const char *lookup, va_list ap)
- {
- PGresult *result = NULL;
-- int numrows = 0, pgerror;
-- char escapebuf[513];
-+ int numrows = 0, pgresult;
- const char *newparam, *newval;
-- struct ast_str *sql = ast_str_create(100);
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
-+ struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
- struct tables *table;
- struct columns *column = NULL;
-
- if (!tablename) {
- ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
-- ast_free(sql);
- return -1;
- }
-
- if (!(table = find_table(tablename))) {
- ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
-- ast_free(sql);
- return -1;
- }
-
-@@ -518,9 +542,8 @@
- if (pgsqlConn) {
- PQfinish(pgsqlConn);
- pgsqlConn = NULL;
-- };
-- ast_mutex_unlock(&table->lock);
-- ast_free(sql);
-+ }
-+ release_table(table);
- return -1;
- }
-
-@@ -533,77 +556,65 @@
-
- if (!column) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
-- ast_mutex_unlock(&table->lock);
-- ast_free(sql);
-+ release_table(table);
- return -1;
- }
-
- /* Create the first part of the query using the first parameter/value pairs we just extracted
- If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-
-- PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
- va_end(ap);
-- ast_mutex_unlock(&table->lock);
-- ast_free(sql);
-+ release_table(table);
- return -1;
- }
-- ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, escapebuf);
-+ ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
-
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
-
-- /* If the column is not within the table, then skip it */
-- AST_LIST_TRAVERSE(&table->columns, column, list) {
-- if (strcmp(column->name, newparam) == 0) {
-- break;
-- }
-- }
--
-- if (!column) {
-+ if (!find_column(table, newparam)) {
- ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
- continue;
- }
-
-- PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
- va_end(ap);
-- ast_mutex_unlock(&table->lock);
-- ast_free(sql);
-+ release_table(table);
- return -1;
- }
-
-- ast_str_append(&sql, 0, ", %s = '%s'", newparam, escapebuf);
-+ ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
- }
- va_end(ap);
-- ast_mutex_unlock(&table->lock);
-+ release_table(table);
-
-- PQescapeStringConn(pgsqlConn, escapebuf, lookup, (sizeof(escapebuf) - 1) / 2, &pgerror);
-- if (pgerror) {
-+ ESCAPE_STRING(escapebuf, lookup);
-+ if (pgresult) {
- ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", lookup);
- va_end(ap);
-- ast_free(sql);
- return -1;
- }
-
-- ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, escapebuf);
-+ ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(escapebuf));
-
-- ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", sql->str);
-+ ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
-
- /* We now have our complete statement; Lets connect to the server and execute it. */
- ast_mutex_lock(&pgsql_lock);
- if (!pgsql_reconnect(database)) {
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(sql);
- return -1;
- }
-
-- if (!(result = PQexec(pgsqlConn, sql->str))) {
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
- ast_mutex_unlock(&pgsql_lock);
- ast_free(sql);
-@@ -615,7 +626,7 @@
- && result_status != PGRES_NONFATAL_ERROR) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
- PQresultErrorMessage(result), PQresStatus(result_status));
- ast_mutex_unlock(&pgsql_lock);
-@@ -642,22 +653,145 @@
- return -1;
- }
-
--#define ESCAPE_STRING(buffer, stringname) \
-- do { \
-- int len; \
-- if ((len = strlen(stringname)) > (buffer->len - 1) / 2) { \
-- ast_str_make_space(&buffer, len * 2 + 1); \
-- } \
-- PQescapeStringConn(pgsqlConn, buffer->str, stringname, len, &pgresult); \
-- } while (0)
-+static int update2_pgsql(const char *database, const char *tablename, va_list ap)
-+{
-+ PGresult *result = NULL;
-+ int numrows = 0, pgresult, first = 1;
-+ struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
-+ const char *newparam, *newval;
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
-+ struct ast_str *where = ast_str_thread_get(&where_buf, 100);
-+ struct tables *table;
-
-+ if (!tablename) {
-+ ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
-+ return -1;
-+ }
-+
-+ if (!escapebuf || !sql || !where) {
-+ /* Memory error, already handled */
-+ return -1;
-+ }
-+
-+ if (!(table = find_table(tablename))) {
-+ ast_log(LOG_ERROR, "Table '%s' does not exist!!\n", tablename);
-+ return -1;
-+ }
-+
-+ ast_str_set(&sql, 0, "UPDATE %s SET ", tablename);
-+ ast_str_set(&where, 0, "WHERE");
-+
-+ while ((newparam = va_arg(ap, const char *))) {
-+ if (!find_column(table, newparam)) {
-+ ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
-+ release_table(table);
-+ return -1;
-+ }
-+
-+ newval = va_arg(ap, const char *);
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
-+ ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
-+ release_table(table);
-+ ast_free(sql);
-+ return -1;
-+ }
-+ ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
-+ first = 0;
-+ }
-+
-+ if (first) {
-+ ast_log(LOG_WARNING,
-+ "PostgreSQL RealTime: Realtime update requires at least 1 parameter and 1 value to search on.\n");
-+ if (pgsqlConn) {
-+ PQfinish(pgsqlConn);
-+ pgsqlConn = NULL;
-+ }
-+ release_table(table);
-+ return -1;
-+ }
-+
-+ /* Now retrieve the columns to update */
-+ first = 1;
-+ while ((newparam = va_arg(ap, const char *))) {
-+ newval = va_arg(ap, const char *);
-+
-+ /* If the column is not within the table, then skip it */
-+ if (!find_column(table, newparam)) {
-+ ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
-+ continue;
-+ }
-+
-+ ESCAPE_STRING(escapebuf, newval);
-+ if (pgresult) {
-+ ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
-+ release_table(table);
-+ ast_free(sql);
-+ return -1;
-+ }
-+
-+ ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
-+ }
-+ release_table(table);
-+
-+ ast_str_append(&sql, 0, " %s", ast_str_buffer(where));
-+
-+ ast_debug(1, "PostgreSQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
-+
-+ /* We now have our complete statement; connect to the server and execute it. */
-+ ast_mutex_lock(&pgsql_lock);
-+ if (!pgsql_reconnect(database)) {
-+ ast_mutex_unlock(&pgsql_lock);
-+ return -1;
-+ }
-+
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
-+ ast_log(LOG_WARNING,
-+ "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
-+ ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
-+ ast_mutex_unlock(&pgsql_lock);
-+ return -1;
-+ } else {
-+ ExecStatusType result_status = PQresultStatus(result);
-+ if (result_status != PGRES_COMMAND_OK
-+ && result_status != PGRES_TUPLES_OK
-+ && result_status != PGRES_NONFATAL_ERROR) {
-+ ast_log(LOG_WARNING,
-+ "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
-+ ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
-+ PQresultErrorMessage(result), PQresStatus(result_status));
-+ ast_mutex_unlock(&pgsql_lock);
-+ return -1;
-+ }
-+ }
-+
-+ numrows = atoi(PQcmdTuples(result));
-+ ast_mutex_unlock(&pgsql_lock);
-+
-+ ast_debug(1, "PostgreSQL RealTime: Updated %d rows on table: %s\n", numrows, tablename);
-+
-+ /* From http://dev.pgsql.com/doc/pgsql/en/pgsql-affected-rows.html
-+ * An integer greater than zero indicates the number of rows affected
-+ * Zero indicates that no records were updated
-+ * -1 indicates that the query returned an error (although, if the query failed, it should have been caught above.)
-+ */
-+
-+ if (numrows >= 0) {
-+ return (int) numrows;
-+ }
-+
-+ return -1;
-+}
-+
- static int store_pgsql(const char *database, const char *table, va_list ap)
- {
- PGresult *result = NULL;
- Oid insertid;
-- struct ast_str *buf = ast_str_create(256);
-- struct ast_str *sql1 = ast_str_create(256);
-- struct ast_str *sql2 = ast_str_create(256);
-+ struct ast_str *buf = ast_str_thread_get(&escapebuf_buf, 256);
-+ struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
-+ struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
- int pgresult;
- const char *newparam, *newval;
-
-@@ -689,30 +823,27 @@
- /* Create the first part of the query using the first parameter/value pairs we just extracted
- If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
- ESCAPE_STRING(buf, newparam);
-- ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, buf->str);
-+ ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
- ESCAPE_STRING(buf, newval);
-- ast_str_set(&sql2, 0, ") VALUES ('%s'", buf->str);
-+ ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- ESCAPE_STRING(buf, newparam);
-- ast_str_append(&sql1, 0, ", %s", buf->str);
-+ ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
- ESCAPE_STRING(buf, newval);
-- ast_str_append(&sql2, 0, ", '%s'", buf->str);
-+ ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
- }
- va_end(ap);
-- ast_str_append(&sql1, 0, "%s)", sql2->str);
-+ ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
-
-- ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", sql1->str);
-+ ast_debug(1, "PostgreSQL RealTime: Insert SQL: %s\n", ast_str_buffer(sql1));
-
-- if (!(result = PQexec(pgsqlConn, sql1->str))) {
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql1)))) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql1->str);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(sql1);
-- ast_free(sql2);
-- ast_free(buf);
- return -1;
- } else {
- ExecStatusType result_status = PQresultStatus(result);
-@@ -721,22 +852,16 @@
- && result_status != PGRES_NONFATAL_ERROR) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql1->str);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql1));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
- PQresultErrorMessage(result), PQresStatus(result_status));
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(sql1);
-- ast_free(sql2);
-- ast_free(buf);
- return -1;
- }
- }
-
- insertid = PQoidValue(result);
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(sql1);
-- ast_free(sql2);
-- ast_free(buf);
-
- ast_debug(1, "PostgreSQL RealTime: row inserted on table: %s, id: %u\n", table, insertid);
-
-@@ -757,8 +882,8 @@
- PGresult *result = NULL;
- int numrows = 0;
- int pgresult;
-- struct ast_str *sql = ast_str_create(256);
-- struct ast_str *buf1 = ast_str_create(60), *buf2 = ast_str_create(60);
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
-+ struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60);
- const char *newparam, *newval;
-
- if (!table) {
-@@ -793,26 +918,23 @@
-
- ESCAPE_STRING(buf1, keyfield);
- ESCAPE_STRING(buf2, lookup);
-- ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, buf1->str, buf2->str);
-+ ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- ESCAPE_STRING(buf1, newparam);
- ESCAPE_STRING(buf2, newval);
-- ast_str_append(&sql, 0, " AND %s = '%s'", buf1->str, buf2->str);
-+ ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
- }
- va_end(ap);
-
-- ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", sql->str);
-+ ast_debug(1, "PostgreSQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
-
-- if (!(result = PQexec(pgsqlConn, sql->str))) {
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(buf1);
-- ast_free(buf2);
-- ast_free(sql);
- return -1;
- } else {
- ExecStatusType result_status = PQresultStatus(result);
-@@ -821,22 +943,16 @@
- && result_status != PGRES_NONFATAL_ERROR) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql->str);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
- PQresultErrorMessage(result), PQresStatus(result_status));
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(buf1);
-- ast_free(buf2);
-- ast_free(sql);
- return -1;
- }
- }
-
- numrows = atoi(PQcmdTuples(result));
- ast_mutex_unlock(&pgsql_lock);
-- ast_free(buf1);
-- ast_free(buf2);
-- ast_free(sql);
-
- ast_debug(1, "PostgreSQL RealTime: Deleted %d rows on table: %s\n", numrows, table);
-
-@@ -861,9 +977,7 @@
- long num_rows;
- struct ast_variable *new_v;
- struct ast_category *cur_cat = NULL;
-- char sqlbuf[1024] = "";
-- char *sql = sqlbuf;
-- size_t sqlleft = sizeof(sqlbuf);
-+ struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
- char last[80] = "";
- int last_cat_metric = 0;
-
-@@ -874,11 +988,11 @@
- return NULL;
- }
-
-- ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
-- ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
-- ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
-+ ast_str_set(&sql, 0, "SELECT category, var_name, var_val, cat_metric FROM %s "
-+ "WHERE filename='%s' and commented=0"
-+ "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ", table, file);
-
-- ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", sqlbuf);
-+ ast_debug(1, "PostgreSQL RealTime: Static SQL: %s\n", ast_str_buffer(sql));
-
- /* We now have our complete statement; Lets connect to the server and execute it. */
- ast_mutex_lock(&pgsql_lock);
-@@ -887,10 +1001,10 @@
- return NULL;
- }
-
-- if (!(result = PQexec(pgsqlConn, sqlbuf))) {
-+ if (!(result = PQexec(pgsqlConn, ast_str_buffer(sql)))) {
- ast_log(LOG_WARNING,
-- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
-+ "PostgreSQL RealTime: Failed to query '%s@%s'. Check debug for more info.\n", table, database);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
- ast_mutex_unlock(&pgsql_lock);
- return NULL;
-@@ -901,7 +1015,7 @@
- && result_status != PGRES_NONFATAL_ERROR) {
- ast_log(LOG_WARNING,
- "PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
-- ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
-+ ast_debug(1, "PostgreSQL RealTime: Query: %s\n", ast_str_buffer(sql));
- ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
- PQresultErrorMessage(result), PQresStatus(result_status));
- ast_mutex_unlock(&pgsql_lock);
-@@ -1049,16 +1163,16 @@
- ast_mutex_lock(&pgsql_lock);
- if (!pgsql_reconnect(database)) {
- ast_mutex_unlock(&pgsql_lock);
-- ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
-+ ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
- ast_free(sql);
- continue;
- }
-
- ast_debug(1, "About to run ALTER query on table '%s' to add column '%s'\n", tablename, elm);
-- result = PQexec(pgsqlConn, sql->str);
-+ result = PQexec(pgsqlConn, ast_str_buffer(sql));
- ast_debug(1, "Finished running ALTER query on table '%s'\n", tablename);
- if (PQresultStatus(result) != PGRES_COMMAND_OK) {
-- ast_log(LOG_ERROR, "Unable to add column: %s\n", sql->str);
-+ ast_log(LOG_ERROR, "Unable to add column: %s\n", ast_str_buffer(sql));
- }
- PQclear(result);
- ast_mutex_unlock(&pgsql_lock);
-@@ -1067,7 +1181,7 @@
- }
- }
- }
-- ast_mutex_unlock(&table->lock);
-+ release_table(table);
- return res;
- }
-
-@@ -1101,6 +1215,7 @@
- .store_func = store_pgsql,
- .destroy_func = destroy_pgsql,
- .update_func = update_pgsql,
-+ .update2_func = update2_pgsql,
- .require_func = require_pgsql,
- .unload_func = unload_pgsql,
- };
-@@ -1112,7 +1227,7 @@
-
- ast_config_engine_register(&pgsql_engine);
- ast_verb(1, "PostgreSQL RealTime driver loaded.\n");
-- ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
-
- return 0;
- }
-@@ -1127,7 +1242,7 @@
- PQfinish(pgsqlConn);
- pgsqlConn = NULL;
- }
-- ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_realtime, ARRAY_LEN(cli_realtime));
- ast_config_engine_deregister(&pgsql_engine);
- ast_verb(1, "PostgreSQL RealTime unloaded.\n");
-
-@@ -1157,10 +1272,12 @@
- const char *s;
- struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if ((config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
-+ config = ast_config_load(RES_CONFIG_PGSQL_CONF, config_flags);
-+ if (config == CONFIG_STATUS_FILEUNCHANGED) {
- return 0;
-+ }
-
-- if (!config) {
-+ if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load config %s\n", RES_CONFIG_PGSQL_CONF);
- return 0;
- }
-@@ -1282,9 +1399,9 @@
- if (!ast_strlen_zero(dbpass))
- ast_str_append(&connInfo, 0, " password=%s", dbpass);
-
-- ast_debug(1, "%u connInfo=%s\n", (unsigned int)connInfo->len, connInfo->str);
-- pgsqlConn = PQconnectdb(connInfo->str);
-- ast_debug(1, "%u connInfo=%s\n", (unsigned int)connInfo->len, connInfo->str);
-+ ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
-+ pgsqlConn = PQconnectdb(ast_str_buffer(connInfo));
-+ ast_debug(1, "%u connInfo=%s\n", (unsigned int)ast_str_size(connInfo), ast_str_buffer(connInfo));
- ast_free(connInfo);
- connInfo = NULL;
-
-@@ -1313,13 +1430,13 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "realtime pgsql cache";
-+ e->command = "realtime show pgsql cache";
- e->usage =
-- "Usage: realtime pgsql cache [<table>]\n"
-+ "Usage: realtime show pgsql cache [<table>]\n"
- " Shows table cache for the PostgreSQL RealTime driver\n";
- return NULL;
- case CLI_GENERATE:
-- if (a->argc != 3) {
-+ if (a->argc != 4) {
- return NULL;
- }
- l = strlen(a->word);
-@@ -1335,25 +1452,25 @@
- return ret;
- }
-
-- if (a->argc == 3) {
-+ if (a->argc == 4) {
- /* List of tables */
- AST_LIST_LOCK(&psql_tables);
- AST_LIST_TRAVERSE(&psql_tables, cur, list) {
- ast_cli(a->fd, "%s\n", cur->name);
- }
- AST_LIST_UNLOCK(&psql_tables);
-- } else if (a->argc == 4) {
-+ } else if (a->argc == 5) {
- /* List of columns */
-- if ((cur = find_table(a->argv[3]))) {
-+ if ((cur = find_table(a->argv[4]))) {
- struct columns *col;
-- ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[3]);
-+ ast_cli(a->fd, "Columns for Table Cache '%s':\n", a->argv[4]);
- ast_cli(a->fd, "%-20.20s %-20.20s %-3.3s %-8.8s\n", "Name", "Type", "Len", "Nullable");
- AST_LIST_TRAVERSE(&cur->columns, col, list) {
- ast_cli(a->fd, "%-20.20s %-20.20s %3d %-8.8s\n", col->name, col->type, col->len, col->notnull ? "NOT NULL" : "");
- }
-- ast_mutex_unlock(&cur->lock);
-+ release_table(cur);
- } else {
-- ast_cli(a->fd, "No such table '%s'\n", a->argv[3]);
-+ ast_cli(a->fd, "No such table '%s'\n", a->argv[4]);
- }
- }
- return 0;
-@@ -1366,16 +1483,16 @@
-
- switch (cmd) {
- case CLI_INIT:
-- e->command = "realtime pgsql status";
-+ e->command = "realtime show pgsql status";
- e->usage =
-- "Usage: realtime pgsql status\n"
-+ "Usage: realtime show pgsql status\n"
- " Shows connection information for the PostgreSQL RealTime driver\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-
-- if (a->argc != 3)
-+ if (a->argc != 4)
- return CLI_SHOWUSAGE;
-
- if (pgsqlConn && PQstatus(pgsqlConn) == CONNECTION_OK) {
-Index: res/res_phoneprov.c
-===================================================================
---- a/res/res_phoneprov.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_phoneprov.c (.../team/group/issue14292) (revision 178988)
-@@ -26,10 +26,6 @@
- * \author Terry Wilson <twilson@digium.com>
- */
-
--/*** MODULEINFO
-- <depend>func_strings</depend>
-- ***/
--
- #include "asterisk.h"
-
- #include <sys/ioctl.h>
-@@ -83,6 +79,7 @@
- PP_CALLERID,
- PP_TIMEZONE,
- PP_LINENUMBER,
-+ PP_LINEKEYS,
- PP_VAR_LIST_LENGTH, /* This entry must always be the last in the list */
- };
-
-@@ -101,6 +98,7 @@
- { PP_CALLERID, "cid_number", "CALLERID" },
- { PP_TIMEZONE, "timezone", "TIMEZONE" },
- { PP_LINENUMBER, "linenumber", "LINE" },
-+ { PP_LINEKEYS, "linekeys", "LINEKEYS" },
- };
-
- /*! \brief structure to hold file data */
-@@ -172,7 +170,7 @@
-
- static char global_server[80] = ""; /*!< Server to substitute into templates */
- static char global_serverport[6] = ""; /*!< Server port to substitute into templates */
--static char global_default_profile[80] = ""; /*!< Default profile to use if one isn't specified */
-+static char global_default_profile[80] = ""; /*!< Default profile to use if one isn't specified */
-
- /*! \brief List of global variables currently available: VOICEMAIL_EXTEN, EXTENSION_LENGTH */
- static struct varshead global_variables;
-@@ -190,7 +188,7 @@
- if (!strcasecmp(ftype, mimetypes[x].ext))
- return mimetypes[x].mtype;
- }
--
-+
- return NULL;
- }
-
-@@ -245,8 +243,8 @@
- static int profile_hash_fn(const void *obj, const int flags)
- {
- const struct phone_profile *profile = obj;
--
-- return ast_str_hash(profile->name);
-+
-+ return ast_str_case_hash(profile->name);
- }
-
- static int profile_cmp_fn(void *obj, void *arg, int flags)
-@@ -291,15 +289,15 @@
- static int routes_hash_fn(const void *obj, const int flags)
- {
- const struct http_route *route = obj;
--
-- return ast_str_hash(route->uri);
-+
-+ return ast_str_case_hash(route->uri);
- }
-
- static int routes_cmp_fn(void *obj, void *arg, int flags)
- {
- const struct http_route *route1 = obj, *route2 = arg;
-
-- return !strcmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0;
-+ return !strcasecmp(route1->uri, route2->uri) ? CMP_MATCH | CMP_STOP : 0;
- }
-
- static void route_destructor(void *obj)
-@@ -314,7 +312,7 @@
- {
- int len = 0;
- FILE *f;
--
-+
- if (!(f = fopen(filename, "r"))) {
- *ret = NULL;
- return -1;
-@@ -360,7 +358,7 @@
- snprintf(buffer, sizeof(buffer), "%d", tzoffset);
- var = ast_var_assign("TZOFFSET", buffer);
- if (var)
-- AST_LIST_INSERT_TAIL(headp, var, entries);
-+ AST_LIST_INSERT_TAIL(headp, var, entries);
-
- if (!dstenable)
- return;
-@@ -368,7 +366,7 @@
- if ((var = ast_var_assign("DST_ENABLE", "1")))
- AST_LIST_INSERT_TAIL(headp, var, entries);
-
-- when.tv_sec = dststart;
-+ when.tv_sec = dststart;
- ast_localtime(&when, &tm_info, zone);
-
- snprintf(buffer, sizeof(buffer), "%d", tm_info.tm_mon+1);
-@@ -445,7 +443,7 @@
- "Content-Length: %d\r\n"
- "Content-Type: %s\r\n\r\n",
- ast_get_version(), buf, len, route->file->mime_type);
--
-+
- while ((len = read(fd, buf, sizeof(buf))) > 0) {
- if (fwrite(buf, 1, len, ser->f) != len) {
- if (errno != EPIPE) {
-@@ -480,7 +478,7 @@
-
- /* XXX This is a hack -- maybe sum length of all variables in route->user->headp and add that? */
- bufsize = len + VAR_BUF_SIZE;
--
-+
- /* malloc() instead of alloca() here, just in case the file is bigger than
- * we have enough stack space for. */
- if (!(tmp = ast_calloc(1, bufsize))) {
-@@ -513,7 +511,7 @@
- }
-
- pbx_substitute_variables_varshead(AST_LIST_FIRST(&route->user->extensions)->headp, file, tmp, bufsize);
--
-+
- if (file) {
- ast_free(file);
- }
-@@ -537,7 +535,7 @@
- *status = 404;
- *title = strdup("Not Found");
- *contentlength = 0;
-- return ast_http_error(404, "Not Found", NULL, "Nothing to see here. Move along.");
-+ return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
-
- out500:
- route = unref_route(route);
-@@ -555,7 +553,7 @@
- static void build_route(struct phoneprov_file *pp_file, struct user *user, char *uri)
- {
- struct http_route *route;
--
-+
- if (!(route = ao2_alloc(sizeof(*route), route_destructor))) {
- return;
- }
-@@ -592,7 +590,7 @@
- profile = unref_profile(profile);
- return;
- }
--
-+
- if (!(profile->headp = ast_calloc(1, sizeof(*profile->headp)))) {
- profile = unref_profile(profile);
- return;
-@@ -613,7 +611,7 @@
- AST_APP_ARG(varname);
- AST_APP_ARG(varval);
- );
--
-+
- AST_NONSTANDARD_APP_ARGS(args, value_copy, '=');
- do {
- if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
-@@ -630,7 +628,7 @@
- } else {
- struct phoneprov_file *pp_file;
- char *file_extension;
-- char *value_copy = ast_strdupa(v->value);
-+ char *value_copy = ast_strdupa(v->value);
-
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(filename);
-@@ -715,15 +713,15 @@
- if (!(exten = ast_calloc(1, sizeof(*exten)))) {
- return NULL;
- }
--
-+
- if (ast_string_field_init(exten, 32)) {
- ast_free(exten);
- exten = NULL;
- return NULL;
- }
--
-+
- ast_string_field_set(exten, name, name);
--
-+
- if (!(exten->headp = ast_calloc(1, sizeof(*exten->headp)))) {
- ast_free(exten);
- exten = NULL;
-@@ -747,6 +745,10 @@
- tmp = "1";
- }
- exten->index = atoi(tmp);
-+ } else if (i == PP_LINEKEYS) {
-+ if (!tmp) {
-+ tmp = "1";
-+ }
- }
-
- if (tmp && (var = ast_var_assign(pp_variable_list[i].template_var, tmp))) {
-@@ -787,8 +789,8 @@
- static int users_hash_fn(const void *obj, const int flags)
- {
- const struct user *user = obj;
--
-- return ast_str_hash(user->macaddress);
-+
-+ return ast_str_case_hash(user->macaddress);
- }
-
- static int users_cmp_fn(void *obj, void *arg, int flags)
-@@ -811,7 +813,7 @@
- if (user->profile) {
- user->profile = unref_profile(user->profile);
- }
--
-+
- ast_string_field_free_memory(user);
- }
-
-@@ -833,12 +835,11 @@
- {
- struct user *user;
-
--
- if (!(user = ao2_alloc(sizeof(*user), user_destructor))) {
- profile = unref_profile(profile);
- return NULL;
- }
--
-+
- if (ast_string_field_init(user, 32)) {
- profile = unref_profile(profile);
- user = unref_user(user);
-@@ -914,12 +915,12 @@
-
- /* Try to grab the port from sip.conf. If we don't get it here, we'll set it
- * to whatever is set in phoneprov.conf or default to 5060 */
-- if ((cfg = ast_config_load("sip.conf", config_flags))) {
-+ if ((cfg = ast_config_load("sip.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
- ast_copy_string(global_serverport, S_OR(ast_variable_retrieve(cfg, "general", "bindport"), "5060"), sizeof(global_serverport));
- ast_config_destroy(cfg);
- }
-
-- if (!(cfg = ast_config_load("users.conf", config_flags))) {
-+ if (!(cfg = ast_config_load("users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load users.conf\n");
- return 0;
- }
-@@ -941,7 +942,7 @@
- }
- }
-
-- if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags))) {
-+ if (!(phoneprov_cfg = ast_config_load("phoneprov.conf", config_flags)) || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_ERROR, "Unable to load config phoneprov.conf\n");
- ast_config_destroy(cfg);
- return -1;
-@@ -962,7 +963,7 @@
- else if (!strcasecmp(v->name, "default_profile"))
- ast_copy_string(global_default_profile, v->value, sizeof(global_default_profile));
- }
-- } else
-+ } else
- build_profile(cat, ast_variable_browse(phoneprov_cfg, cat));
- }
-
-@@ -978,11 +979,11 @@
- if (!strcasecmp(cat, "general")) {
- continue;
- }
--
-+
- if (!strcasecmp(cat, "authentication"))
- continue;
-
-- if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp)))
-+ if (!((tmp = ast_variable_retrieve(cfg, cat, "autoprov")) && ast_true(tmp)))
- continue;
-
- if (!(mac = ast_variable_retrieve(cfg, cat, "macaddress"))) {
-@@ -1056,7 +1057,7 @@
- {
- struct ao2_iterator i;
- struct http_route *route;
--
-+
- i = ao2_iterator_init(http_routes, 0);
- while ((route = ao2_iterator_next(&i))) {
- ao2_unlink(http_routes, route);
-@@ -1127,11 +1128,11 @@
- char path[PATH_MAX];
- char *file;
- int filelen;
-- AST_DECLARE_APP_ARGS(args,
-+ AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(mac);
- AST_APP_ARG(template);
- );
--
-+
- AST_STANDARD_APP_ARGS(args, data);
-
- if (ast_strlen_zero(args.mac) || ast_strlen_zero(args.template)) {
-@@ -1187,7 +1188,7 @@
- #define FORMAT "%-40.40s %-30.30s\n"
- struct ao2_iterator i;
- struct http_route *route;
--
-+
- switch(cmd) {
- case CLI_INIT:
- e->command = "phoneprov show routes";
-@@ -1247,13 +1248,13 @@
-
- AST_LIST_HEAD_INIT_NOLOCK(&global_variables);
- ast_mutex_init(&globals_lock);
--
-+
- ast_custom_function_register(&pp_each_user_function);
- ast_custom_function_register(&pp_each_extension_function);
- ast_cli_register_multiple(pp_cli, ARRAY_LEN(pp_cli));
-
- set_config();
-- ast_http_uri_link(&phoneprovuri);
-+ ast_http_uri_link(&phoneprovuri);
-
- return 0;
- }
-@@ -1285,7 +1286,7 @@
- return 0;
- }
-
--static int reload(void)
-+static int reload(void)
- {
- struct ast_var_t *var;
-
-Index: res/res_adsi.c
-===================================================================
---- a/res/res_adsi.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_adsi.c (.../team/group/issue14292) (revision 178988)
-@@ -1021,10 +1021,10 @@
- char *name, *sname;
- init_state();
-
-- if (!(conf = ast_config_load("adsi.conf", config_flags)))
-+ conf = ast_config_load("adsi.conf", config_flags);
-+ if (conf == CONFIG_STATUS_FILEMISSING || conf == CONFIG_STATUS_FILEUNCHANGED || conf == CONFIG_STATUS_FILEINVALID) {
- return;
-- else if (conf == CONFIG_STATUS_FILEUNCHANGED)
-- return;
-+ }
- for (v = ast_variable_browse(conf, "intro"); v; v = v->next) {
- if (!strcasecmp(v->name, "alignment"))
- alignment = str2align(v->value);
-Index: res/res_crypto.c
-===================================================================
---- a/res/res_crypto.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_crypto.c (.../team/group/issue14292) (revision 178988)
-@@ -27,7 +27,7 @@
- */
-
- /*** MODULEINFO
-- <depend>ssl</depend>
-+ <depend>openssl</depend>
- ***/
-
- #include "asterisk.h"
-@@ -587,7 +587,7 @@
- {
- SSL_library_init();
- ERR_load_crypto_strings();
-- ast_cli_register_multiple(cli_crypto, sizeof(cli_crypto) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_crypto, ARRAY_LEN(cli_crypto));
-
- /* Install ourselves into stubs */
- ast_key_get = __ast_key_get;
-Index: res/snmp/agent.c
-===================================================================
---- a/res/snmp/agent.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/snmp/agent.c (.../team/group/issue14292) (revision 178988)
-@@ -483,8 +483,8 @@
- break;
- case ASTCHANVARIABLES:
- if (pbx_builtin_serialize_variables(chan, &out)) {
-- *var_len = strlen(out->str);
-- ret = (u_char *)out->str;
-+ *var_len = ast_str_strlen(out);
-+ ret = (u_char *)ast_str_buffer(out);
- }
- break;
- case ASTCHANFLAGS:
-@@ -569,9 +569,9 @@
- case ASTCHANTYPECHANNELS:
- long_ret = 0;
- for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
-- ast_channel_unlock(chan);
- if (chan->tech == tech)
- long_ret++;
-+ ast_channel_unlock(chan);
- }
- return (u_char *)&long_ret;
- default:
-@@ -644,23 +644,34 @@
- int exact, size_t *var_len, WriteMethod **write_method)
- {
- static unsigned long long_ret;
-- struct tone_zone *tz = NULL;
-+ static char ret_buf[128];
-+ struct ast_tone_zone *tz = NULL;
-
- if (header_generic(vp, name, length, exact, var_len, write_method))
- return NULL;
-
- switch (vp->magic) {
- case ASTINDCOUNT:
-+ {
-+ struct ao2_iterator i;
-+
- long_ret = 0;
-- while ( (tz = ast_walk_indications(tz)) )
-+
-+ i = ast_tone_zone_iterator_init();
-+ while ((tz = ao2_iterator_next(&i))) {
-+ tz = ast_tone_zone_unref(tz);
- long_ret++;
-+ }
-
-- return (u_char *)&long_ret;
-+ return (u_char *) &long_ret;
-+ }
- case ASTINDCURRENT:
- tz = ast_get_indication_zone(NULL);
- if (tz) {
-- *var_len = strlen(tz->country);
-- return (u_char *)tz->country;
-+ ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
-+ *var_len = strlen(ret_buf);
-+ tz = ast_tone_zone_unref(tz);
-+ return (u_char *) ret_buf;
- }
- *var_len = 0;
- return NULL;
-@@ -674,34 +685,47 @@
- int exact, size_t *var_len, WriteMethod **write_method)
- {
- static unsigned long long_ret;
-- struct tone_zone *tz = NULL;
-+ static char ret_buf[256];
-+ struct ast_tone_zone *tz = NULL;
- int i;
-+ struct ao2_iterator iter;
-
-- if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
-+ if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) {
- return NULL;
-+ }
-
- i = name[*length - 1] - 1;
-- while ( (tz = ast_walk_indications(tz)) && i )
-- i--;
-- if (tz == NULL)
-+
-+ iter = ast_tone_zone_iterator_init();
-+
-+ while ((tz = ao2_iterator_next(&iter)) && i) {
-+ tz = ast_tone_zone_unref(tz);
-+ i--;
-+ }
-+
-+ if (tz == NULL) {
- return NULL;
-+ }
-
- switch (vp->magic) {
- case ASTINDINDEX:
- long_ret = name[*length - 1];
- return (u_char *)&long_ret;
- case ASTINDCOUNTRY:
-- *var_len = strlen(tz->country);
-- return (u_char *)tz->country;
-+ ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
-+ tz = ast_tone_zone_unref(tz);
-+ *var_len = strlen(ret_buf);
-+ return (u_char *) ret_buf;
- case ASTINDALIAS:
-- if (tz->alias) {
-- *var_len = strlen(tz->alias);
-- return (u_char *)tz->alias;
-- }
-+ /* No longer exists */
- return NULL;
- case ASTINDDESCRIPTION:
-- *var_len = strlen(tz->description);
-- return (u_char *)tz->description;
-+ ast_tone_zone_lock(tz);
-+ ast_copy_string(ret_buf, tz->description, sizeof(ret_buf));
-+ ast_tone_zone_unlock(tz);
-+ tz = ast_tone_zone_unref(tz);
-+ *var_len = strlen(ret_buf);
-+ return (u_char *) ret_buf;
- default:
- break;
- }
-Index: res/res_musiconhold.c
-===================================================================
---- a/res/res_musiconhold.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_musiconhold.c (.../team/group/issue14292) (revision 178988)
-@@ -65,6 +65,7 @@
- #include "asterisk/stringfields.h"
- #include "asterisk/linkedlists.h"
- #include "asterisk/manager.h"
-+#include "asterisk/paths.h"
- #include "asterisk/astobj2.h"
-
- #define INITIAL_NUM_FILES 8
-@@ -213,7 +214,7 @@
-
- state->save_pos = state->pos;
-
-- state->class = mohclass_unref(state->class);
-+ mohclass_unref(state->class);
- }
-
- static int ast_moh_files_next(struct ast_channel *chan)
-@@ -314,8 +315,6 @@
-
- if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
- chan->music_state = state;
-- state->class = mohclass_ref(class);
-- state->save_pos = -1;
- } else {
- state = chan->music_state;
- }
-@@ -325,17 +324,13 @@
- }
-
- if (state->class != class) {
-- /* (re-)initialize */
-- if (state->class) {
-- state->class = mohclass_unref(state->class);
-- }
- memset(state, 0, sizeof(*state));
-- state->class = mohclass_ref(class);
-- if (ast_test_flag(state->class, MOH_RANDOMIZE) && class->total_files) {
-+ if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
- state->pos = ast_random() % class->total_files;
- }
- }
-
-+ state->class = mohclass_ref(class);
- state->origwfmt = chan->writeformat;
-
- ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name);
-@@ -898,6 +893,7 @@
-
- DIR *files_DIR;
- struct dirent *files_dirent;
-+ char dir_path[PATH_MAX];
- char path[PATH_MAX];
- char filepath[PATH_MAX];
- char *ext;
-@@ -905,9 +901,17 @@
- int dirnamelen;
- int i;
-
-- files_DIR = opendir(class->dir);
-+ if (class->dir[0] != '/') {
-+ ast_copy_string(dir_path, ast_config_AST_VAR_DIR, sizeof(dir_path));
-+ strncat(dir_path, "/", sizeof(dir_path) - 1);
-+ strncat(dir_path, class->dir, sizeof(dir_path) - 1);
-+ } else {
-+ ast_copy_string(dir_path, class->dir, sizeof(dir_path));
-+ }
-+ ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
-+ files_DIR = opendir(dir_path);
- if (!files_DIR) {
-- ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
-+ ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
- return -1;
- }
-
-@@ -915,12 +919,12 @@
- ast_free(class->filearray[i]);
-
- class->total_files = 0;
-- dirnamelen = strlen(class->dir) + 2;
-+ dirnamelen = strlen(dir_path) + 2;
- if (!getcwd(path, sizeof(path))) {
- ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
- return -1;
- }
-- if (chdir(class->dir) < 0) {
-+ if (chdir(dir_path) < 0) {
- ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
- return -1;
- }
-@@ -937,7 +941,7 @@
- if (!strchr(files_dirent->d_name, '.'))
- continue;
-
-- snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
-+ snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
-
- if (stat(filepath, &statbuf))
- continue;
-@@ -1423,8 +1427,9 @@
-
- cfg = ast_config_load("musiconhold.conf", config_flags);
-
-- if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- return 0;
-+ }
-
- if (reload) {
- ao2_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL);
-@@ -1653,7 +1658,7 @@
-
- res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc);
- ast_register_atexit(ast_moh_destroy);
-- ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
-+ ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
- if (!res)
- res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc);
- if (!res)
-@@ -1708,7 +1713,7 @@
- res |= ast_unregister_application(set_moh);
- res |= ast_unregister_application(start_moh);
- res |= ast_unregister_application(stop_moh);
-- ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
-+ ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
- ast_unregister_atexit(ast_moh_destroy);
-
- return res;
-Index: res/res_http_post.c
-===================================================================
---- a/res/res_http_post.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/res/res_http_post.c (.../team/group/issue14292) (revision 178988)
-@@ -37,6 +37,9 @@
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <gmime/gmime.h>
-+#if defined (__OpenBSD__) || defined(__FreeBSD__)
-+#include <libgen.h>
-+#endif
-
- #include "asterisk/linkedlists.h"
- #include "asterisk/http.h"
-@@ -153,17 +156,153 @@
- return cbinfo.count;
- }
-
-+
-+/* Find a sequence of bytes within a binary array. */
-+static int find_sequence(char * inbuf, int inlen, char * matchbuf, int matchlen)
-+{
-+ int current;
-+ int comp;
-+ int found = 0;
-+
-+ for (current = 0; current < inlen-matchlen; current++, inbuf++) {
-+ if (*inbuf == *matchbuf) {
-+ found=1;
-+ for (comp = 1; comp < matchlen; comp++) {
-+ if (inbuf[comp] != matchbuf[comp]) {
-+ found = 0;
-+ break;
-+ }
-+ }
-+ if (found) {
-+ break;
-+ }
-+ }
-+ }
-+ if (found) {
-+ return current;
-+ } else {
-+ return -1;
-+ }
-+}
-+
-+/*
-+* The following is a work around to deal with how IE7 embeds the local file name
-+* within the Mime header using full WINDOWS file path with backslash directory delimiters.
-+* This section of code attempts to isolate the directory path and remove it
-+* from what is written into the output file. In addition, it changes
-+* esc chars (i.e. backslashes) to forward slashes.
-+* This function has two modes. The first to find a boundary marker. The
-+* second is to find the filename immediately after the boundary.
-+*/
-+static int readmimefile(FILE * fin, FILE * fout, char * boundary, int contentlen)
-+{
-+ int find_filename = 0;
-+ char buf[4096];
-+ int marker;
-+ int x;
-+ int char_in_buf = 0;
-+ int num_to_read;
-+ int boundary_len;
-+ char * path_end, * path_start, * filespec;
-+
-+ if (NULL == fin || NULL == fout || NULL == boundary || 0 >= contentlen) {
-+ return -1;
-+ }
-+
-+ boundary_len = strlen(boundary);
-+ while (0 < contentlen || 0 < char_in_buf) {
-+ /* determine how much I will read into the buffer */
-+ if (contentlen > sizeof(buf) - char_in_buf) {
-+ num_to_read = sizeof(buf)- char_in_buf;
-+ } else {
-+ num_to_read = contentlen;
-+ }
-+
-+ if (0 < num_to_read) {
-+ if (fread(&(buf[char_in_buf]), 1, num_to_read, fin) < num_to_read) {
-+ ast_log(LOG_WARNING, "fread() failed: %s\n", strerror(errno));
-+ num_to_read = 0;
-+ }
-+ contentlen -= num_to_read;
-+ char_in_buf += num_to_read;
-+ }
-+ /* If I am looking for the filename spec */
-+ if (find_filename) {
-+ path_end = filespec = NULL;
-+ x = strlen("filename=\"");
-+ marker = find_sequence(buf, char_in_buf, "filename=\"", x );
-+ if (0 <= marker) {
-+ marker += x; /* Index beyond the filename marker */
-+ path_start = &buf[marker];
-+ for (path_end = path_start, x = 0; x < char_in_buf-marker; x++, path_end++) {
-+ if ('\\' == *path_end) { /* convert backslashses to forward slashes */
-+ *path_end = '/';
-+ }
-+ if ('\"' == *path_end) { /* If at the end of the file name spec */
-+ *path_end = '\0'; /* temporarily null terminate the file spec for basename */
-+ filespec = basename(path_start);
-+ *path_end = '\"';
-+ break;
-+ }
-+ }
-+ }
-+ if (filespec) { /* If the file name path was found in the header */
-+ if (fwrite(buf, 1, marker, fout) != marker) {
-+ ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-+ }
-+ x = (int)(path_end+1 - filespec);
-+ if (fwrite(filespec, 1, x, fout) != x) {
-+ ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-+ }
-+ x = (int)(path_end+1 - buf);
-+ memmove(buf, &(buf[x]), char_in_buf-x);
-+ char_in_buf -= x;
-+ }
-+ find_filename = 0;
-+ } else { /* I am looking for the boundary marker */
-+ marker = find_sequence(buf, char_in_buf, boundary, boundary_len);
-+ if (0 > marker) {
-+ if (char_in_buf < (boundary_len)) {
-+ /*no possibility to find the boundary, write all you have */
-+ if (fwrite(buf, 1, char_in_buf, fout) != char_in_buf) {
-+ ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-+ }
-+ char_in_buf = 0;
-+ } else {
-+ /* write all except for area where the boundary marker could be */
-+ if (fwrite(buf, 1, char_in_buf -(boundary_len -1), fout) != char_in_buf - (boundary_len - 1)) {
-+ ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-+ }
-+ x = char_in_buf -(boundary_len -1);
-+ memmove(buf, &(buf[x]), char_in_buf-x);
-+ char_in_buf = (boundary_len -1);
-+ }
-+ } else {
-+ /* write up through the boundary, then look for filename in the rest */
-+ if (fwrite(buf, 1, marker + boundary_len, fout) != marker + boundary_len) {
-+ ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-+ }
-+ x = marker + boundary_len;
-+ memmove(buf, &(buf[x]), char_in_buf-x);
-+ char_in_buf -= marker + boundary_len;
-+ find_filename =1;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+
- static struct ast_str *http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength)
- {
- struct ast_variable *var;
- unsigned long ident = 0;
-- char buf[4096];
- FILE *f;
-- size_t res;
- int content_len = 0;
- struct ast_str *post_dir;
- GMimeMessage *message;
- int message_count = 0;
-+ char * boundary_marker = NULL;
-
- if (!urih) {
- return ast_http_error((*status = 400),
-@@ -213,23 +352,23 @@
- return NULL;
- }
- ast_debug(1, "Got a Content-Length of %d\n", content_len);
-+ } else if (!strcasecmp(var->name, "Content-Type")) {
-+ boundary_marker = strstr(var->value, "boundary=");
-+ if (boundary_marker) {
-+ boundary_marker += strlen("boundary=");
-+ }
- }
- }
-
- fprintf(f, "\r\n");
-
-- for (res = sizeof(buf); content_len; content_len -= res) {
-- if (content_len < res) {
-- res = content_len;
-+ if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) {
-+ if (option_debug) {
-+ ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n");
- }
-- if (fread(buf, 1, res, ser->f) != res) {
-- ast_log(LOG_WARNING, "fread() failed: %s\n", strerror(errno));
-- continue;
-- }
-- if (fwrite(buf, 1, res, f) != res) {
-- ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
-- continue;
-- }
-+ fclose(f);
-+
-+ return NULL;
- }
-
- if (fseek(f, SEEK_SET, 0)) {
-@@ -251,7 +390,7 @@
- NULL, "The was an error parsing the request.");
- }
-
-- if (!(message_count = process_message(message, post_dir->str))) {
-+ if (!(message_count = process_message(message, ast_str_buffer(post_dir)))) {
- ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
- g_object_unref(message);
- return ast_http_error((*status = 400),
-@@ -272,7 +411,8 @@
- struct ast_variable *v;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if ((cfg = ast_config_load2("http.conf", "http", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
-+ cfg = ast_config_load2("http.conf", "http", config_flags);
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
- return 0;
- }
-
-Index: README
-===================================================================
---- a/README (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/README (.../team/group/issue14292) (revision 178988)
-@@ -4,7 +4,7 @@
- === by Mark Spencer <markster@digium.com>
- === and the Asterisk.org developer community
- ===
--=== Copyright (C) 2001-2008 Digium, Inc.
-+=== Copyright (C) 2001-2009 Digium, Inc.
- === and other copyright holders.
- ===============================================================================
-
-@@ -68,8 +68,8 @@
- * All Analog and Digital Interface cards from Digium (www.digium.com)
- * QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net)
- * any full duplex sound card supported by ALSA, OSS, or PortAudio
-- * any ISDN card supported by mISDN on Linux (BRI)
-- * The Xorcom AstriBank channel bank
-+ * any ISDN card supported by mISDN on Linux
-+ * The Xorcom Astribank channel bank
- * VoiceTronix OpenLine products
-
- -------------------------------------------------------------------------------
-@@ -276,7 +276,7 @@
- If this release of Asterisk was downloaded from a tarball, then some
- additional documentation should have been included.
- * doc/tex/asterisk.pdf --- PDF version of the documentation
-- * doc/tex/asterisk/index.html --- HTML version of the documentation
-+ * doc/tex/asterisk/index.html --- HTML version of the documentation
-
- Finally, you may wish to visit the web site and join the mailing list if
- you're interested in getting more information.
-Index: contrib/init.d/rc.archlinux.asterisk
-===================================================================
---- a/contrib/init.d/rc.archlinux.asterisk (.../tags/1.6.1-rc1) (revision 0)
-+++ b/contrib/init.d/rc.archlinux.asterisk (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,51 @@
-+#!/bin/bash
-+#
-+# Start/stop/restart Asterisk PBX
-+#
-+# Version: 0.1 by Sherif Nagy AKA DarKnesS_WolF <sherif.nagy@gmail.com> BASED ON THE SLACKWARE INIT SCRIPT
-+#
-+# 10.10.2008 - Initial Version
-+#
-+. /etc/rc.conf
-+. /etc/rc.d/functions
-+DAEMON=__ASTERISK_SBIN_DIR__/asterisk
-+ASTVARRUNDIR=__ASTERISK_VARRUN_DIR__
-+
-+case "$1" in
-+ start)
-+ stat_busy "Starting Asterisk..."
-+ if [ ! -d $ASTVARRUNDIR ]; then
-+ mkdir -p $ASTVARRUNDIR
-+ fi
-+ if [ -x $DAEMON ]; then
-+ # Check if Asterisk is already running. If it is, then bug out, because
-+ # starting safe_asterisk when Asterisk is running is very bad.
-+ VERSION=`${DAEMON} -rx 'core show version'`
-+ if [ "`echo $VERSION | cut -c 1-8`" = "Asterisk" ]; then
-+ echo "Asterisk is already running. $0 will exit now."
-+ exit 1
-+ fi
-+ ${DAEMON}
-+ stat_done
-+ fi
-+ ;;
-+ stop)
-+ if [ -r ${ASTVARRUNDIR}/asterisk.pid ]; then
-+ stat_busy "Stoping Asterisk..."
-+ ${DAEMON} -rx "core stop now" > /dev/null 2&>1
-+ if [ $? -gt 0 ]; then
-+ stat_fail
-+ else
-+ stat_done
-+ fi
-+ fi
-+ ;;
-+ restart)
-+ $0 stop
-+ sleep 2
-+ $0 start
-+ ;;
-+ *)
-+ echo "usage $0 start|stop|restart" ;;
-+esac
-+exit 0
-
-Property changes on: contrib/init.d/rc.archlinux.asterisk
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:executable
- + *
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: contrib/init.d/rc.suse.asterisk
-===================================================================
---- a/contrib/init.d/rc.suse.asterisk (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/init.d/rc.suse.asterisk (.../team/group/issue14292) (revision 178988)
-@@ -105,7 +105,7 @@
- }
-
- reload() {
-- $DAEMON -rx 'reload' > /dev/null 2> /dev/null
-+ $DAEMON -rx 'module reload' > /dev/null 2> /dev/null
- }
-
- # See how we were called.
-Index: contrib/init.d/rc.mandriva.asterisk
-===================================================================
---- a/contrib/init.d/rc.mandriva.asterisk (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/init.d/rc.mandriva.asterisk (.../team/group/issue14292) (revision 178988)
-@@ -142,7 +142,7 @@
- ;;
- stop)
- gprintf "Stopping asterisk: "
-- asterisk -r -x "stop gracefully" >/dev/null 2>&1
-+ asterisk -r -x "core stop gracefully" >/dev/null 2>&1
- killall -9 mpg123 2>/dev/null
- success
- echo
-@@ -154,13 +154,13 @@
- ;;
- reload)
- gprintf "Reloading asterisk: "
-- asterisk -r -x "reload" >/dev/null 2>&1
-+ asterisk -r -x "module reload" >/dev/null 2>&1
- success
- echo
- ;;
- stopnow)
- gprintf "Stopping asterisk: "
-- asterisk -r -x "stop now" >/dev/null 2>&1
-+ asterisk -r -x "core stop now" >/dev/null 2>&1
- success
- echo
- ;;
-Index: contrib/init.d/rc.debian.asterisk
-===================================================================
---- a/contrib/init.d/rc.debian.asterisk (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/init.d/rc.debian.asterisk (.../team/group/issue14292) (revision 178988)
-@@ -21,7 +21,9 @@
- NAME=asterisk
- DESC="Asterisk PBX"
- # Full path to asterisk binary
--DAEMON=/usr/sbin/asterisk
-+DAEMON=__ASTERISK_SBIN_DIR__/asterisk
-+ASTVARRUNDIR=__ASTERISK_VARRUN_DIR__
-+ASTETCDIR=__ASTERISK_ETC_DIR__
- TRUE=/bin/true
-
- # Uncomment this ONLY if you know what you are doing.
-@@ -42,8 +44,8 @@
- exit 0
- fi
-
--if ! [ -d /etc/asterisk ] ; then
-- echo "ERROR: /etc/asterisk directory not found"
-+if ! [ -d $ASTETCDIR ] ; then
-+ echo "ERROR: $ASTETCDIR directory not found"
- exit 0
- fi
-
-@@ -61,12 +63,18 @@
- fi
-
- log_begin_msg "Starting $DESC: $NAME"
-- if [ $AST_USER ] ; then
-- ASTARGS="-U $AST_USER"
-- fi
-- if [ $AST_GROUP ] ; then
-- ASTARGS="$ASTARGS -G $AST_GROUP"
-- fi
-+ if [ ! -d $ASTVARRUNDIR ]; then
-+ mkdir -p $ASTVARRUNDIR
-+ fi
-+
-+ if [ $AST_USER ] ; then
-+ ASTARGS="-U $AST_USER"
-+ chown $AST_USER $ASTVARRUNDIR
-+ fi
-+ if [ $AST_GROUP ] ; then
-+ ASTARGS="$ASTARGS -G $AST_GROUP"
-+ chown $AST_GROUP $ASTVARRUNDIR
-+ fi
- # "start-stop-daemon --oknodo" returns 0 even if Asterisk was already running (as LSB expects):
- start-stop-daemon --start --oknodo --exec $DAEMON -- $ASTARGS
- log_end_msg $?
-@@ -79,7 +87,7 @@
- ;;
- reload)
- echo "Reloading $DESC configuration files."
-- $DAEMON -rx 'reload' > /dev/null 2> /dev/null
-+ $DAEMON -rx 'module reload' > /dev/null 2> /dev/null
- ;;
- restart|force-reload)
- $0 stop
-Index: contrib/init.d/rc.redhat.asterisk
-===================================================================
---- a/contrib/init.d/rc.redhat.asterisk (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/init.d/rc.redhat.asterisk (.../team/group/issue14292) (revision 178988)
-@@ -113,7 +113,7 @@
- }
-
- reload() {
-- $DAEMON -rx 'reload' > /dev/null 2> /dev/null
-+ $DAEMON -rx 'module reload' > /dev/null 2> /dev/null
- }
-
- # See how we were called.
-Index: contrib/scripts/vmdb.sql
-===================================================================
---- a/contrib/scripts/vmdb.sql (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/scripts/vmdb.sql (.../team/group/issue14292) (revision 178988)
-@@ -1,6 +1,6 @@
- DROP TABLE IF EXISTS voicemail;
- CREATE TABLE voicemail (
-- -- All of these column names are very specific, including "uniqueid". Do not change them if you wish voicemail to work.
-+ -- "uniqueid" is a required column prior to 1.6.2. As of that version, it may be omitted.
- uniqueid INT(5) NOT NULL AUTO_INCREMENT PRIMARY KEY,
- -- Mailbox context.
- context CHAR(80) NOT NULL DEFAULT 'default',
-Index: contrib/scripts/safe_asterisk_restart
-===================================================================
---- a/contrib/scripts/safe_asterisk_restart (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/scripts/safe_asterisk_restart (.../team/group/issue14292) (revision 178988)
-@@ -101,8 +101,8 @@
-
- # doing the dirty work
- [[ $TRY_STOP_NOW_FIRST ]] && docmd "Asking asterisk kindly to shutdown" "$ASTERISK -rx 'stop now'"
--docmd "Sending asterisk processes the TERM signal" "killall -15 $PROCVICTIMS"
--docmd "Sending asterisk processes KILL signal" "killall -9 $PROCVICTIMS"
-+docmd "Sending asterisk processes the TERM signal" "pkill -15 $PROCVICTIMS"
-+docmd "Sending asterisk processes KILL signal" "pkill -9 $PROCVICTIMS"
- docmd "Starting safe_asterisk" "$SAFE_ASTERISK"
- for i in $PROCVICTIMS
- do
-Index: contrib/scripts/realtime_pgsql.sql
-===================================================================
---- a/contrib/scripts/realtime_pgsql.sql (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/scripts/realtime_pgsql.sql (.../team/group/issue14292) (revision 178988)
-@@ -118,6 +118,7 @@
- weight int8,
- timeoutrestart bool,
- setinterfacevar bool,
-+autopause varchar(128),
- PRIMARY KEY (name)
- ) WITHOUT OIDS;
- ALTER TABLE queue_table OWNER TO asterisk;
-@@ -125,9 +126,11 @@
- drop table queue_member_table;
- CREATE TABLE queue_member_table
- (
-+uniqueid serial,
- queue_name varchar(128),
- interface varchar(128),
- penalty int8,
-+paused int8,
- PRIMARY KEY (queue_name, interface)
- ) WITHOUT OIDS;
-
-Index: contrib/scripts/live_ast
-===================================================================
---- a/contrib/scripts/live_ast (.../tags/1.6.1-rc1) (revision 0)
-+++ b/contrib/scripts/live_ast (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,261 @@
-+#!/bin/sh
-+
-+# live_ast: run asterisk from a newly-built copy with minimal changes.
-+
-+# Copyright (C) 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com>
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-+# USA
-+
-+# This script allows you to install Asterisk into a subdirectory of
-+# your source distribution and run it from there.
-+#
-+# Example usage:
-+#
-+# contrib/scripts/live_ast conf-file # optionally. and now edit live/live.conf
-+# # edit live/live.conf
-+# contrib/scripts/live_ast configure
-+# make
-+# contrib/scripts/live_ast install
-+# contrib/scripts/live_ast samples
-+# contrib/scripts/live_ast run
-+# contrib/scripts/live_ast run -r
-+# ./live/asterisk -r # Same as run -r
-+#
-+# A standard debugging cycle of a code in a module:
-+#
-+# # edit apps/app_skel.c
-+# contrib/scripts/live_ast install
-+# contrib/scripts/live_ast run -r
-+# # and in the CLI:
-+# module unload app_skel.so
-+# module load app_skel.so
-+#
-+# If you have external scripts that run asterisk, use the script
-+# live/asterisk that is generated by the 'samples' command. In this case you
-+# should probably also rem-out the line 'astvarrundir' and maybe also
-+# 'astetcdir' in live/etc/asterisk.conf .
-+#
-+####################### Begin Samples
-+# optional environment variables. Set those in live/live.conf or in
-+# your envirnment.
-+#
-+# LIVE_AST_LIBPRI_PATH:
-+# To use a libpri SVN directory (without running 'make install': make include
-+# a symlink to the current directory:
-+# ln -s . /path/to/checkout/of/libpri/include
-+# Be sure to run there 'make'. Then set in live.conf:
-+#LIVE_AST_LIBPRI_PATH="/path/to/checkout/of/libpri"
-+#
-+# LIVE_AST_ZAPTEL_PATH:
-+# Likewise, the same trick can be used to build vs. a local copy of zaptel:
-+# ln -s /path/to/checkout/of/zaptel/include .
-+# ln -s /path/to/checkout/of/zaptel/zaptel .
-+#LIVE_AST_ZPATEL_PATH="/path/to/checkout/of/zaptel"
-+#
-+#LIVE_AST_DAHDI_PATH="/path/to/dahdi-linux/dir"
-+#LIVE_AST_DAHDITOOLS_PATH="/path/to/dahdi-tools/dir"
-+#
-+# Another alternative for Zaptel is to use the live_zap script included
-+# with the Zaptel distribution. The following should work after you used
-+# './live_zap install' or even with a copy generated with
-+# './live_zap rsync' . '/apth/to/zaptel' is the directory containing the
-+# live/ subdirectory:
-+#
-+#LIVE_AST_ZAPLIVE_PATH="/path/to/zaptel"
-+#
-+# LIVE_AST_LD_PATH_EXTRA:
-+# space-separated or colon-separated directories to add to
-+# LD_LIBRARY_PATH. It is added before any existing components of
-+# LD_LIBRARY_PATH.
-+#LIVE_AST_LD_PATH_EXTRA="$HOME/lib:$HOME/libtest /opt/testapp"
-+#
-+# LIVE_AST_CONFIGURE_PARAMS:
-+# Extra parameters to pass to ./configure.
-+#LIVE_AST_CONFIGURE_PARAMS="--enable-dev-mode"
-+#
-+# LIVE_AST_FORCE_DEF_CONF:
-+# If set to a non-empty value, always regenerate menuselect config.
-+# This avoids emenselect's nag about "configuration has changed" that
-+# happens occasionally after an svn update.
-+#LIVE_AST_FORCE_DEF_CONF=yes
-+#
-+# LIVE_AST_BRISTUFFED_LIBPRI
-+# A hack to use the second, "bristuffed" copy of libpri that exists
-+# e.g. in the Debian libpri-dev package. If set to a non-empty value,
-+# live_ast will edit makeopts to use that second copy after ./configure
-+# is run.
-+#LIVE_AST_BRISTUFFED_LIBPRI=yes
-+#
-+# LIVE_AST_FOR_SYSTEM
-+# When generating asterisk.conf, use most components from the installed
-+# system. Also provide a sane var-run directory for those of us who want
-+# to do the right thing and run asterisk as non-root.
-+#LIVE_AST_FOR_SYSTEM=yes
-+####################### End Samples
-+
-+BASE_DIR="$PWD/live"
-+AST_CONF_DIR="$BASE_DIR/etc/asterisk"
-+AST_CONF="$AST_CONF_DIR/asterisk.conf"
-+AST_BIN="$BASE_DIR/usr/sbin/asterisk"
-+GDB_INIT="$BASE_DIR/gdbinit"
-+LIVE_CONF="$BASE_DIR/live.conf"
-+DISABLED_MODS="chan_h323 pbx_dundi"
-+DISABLED_MODS_FILE="modules-disabled.conf"
-+
-+if [ -r "$LIVE_CONF" ]; then . "$LIVE_CONF"; fi
-+
-+if [ "$LIVE_AST_LIBPRI_PATH" != '' ]; then
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-pri=$LIVE_AST_LIBPRI_PATH"
-+ LIVE_AST_LD_PATH_EXTRA="$LIVE_AST_LD_PATH_EXTRA $LIVE_AST_LIBPRI_PATH"
-+fi
-+
-+if [ "$LIVE_AST_ZAPTEL_PATH" != '' ]; then
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-tonezone=$LIVE_AST_ZAPTEL_PATH"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-zaptel=$LIVE_AST_ZAPTEL_PATH"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-zaptel_transcode=$LIVE_AST_ZAPTEL_PATH"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-zaptel_vldtmf=$LIVE_AST_ZAPTEL_PATH"
-+ LIVE_AST_LD_PATH_EXTRA="$LIVE_AST_LD_PATH_EXTRA $LIVE_AST_ZAPTEL_PATH"
-+fi
-+
-+if [ "$LIVE_AST_DAHDI_PATH" != '' ]; then
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-dahdi=$LIVE_AST_DAHDI_PATH"
-+fi
-+
-+if [ "$LIVE_AST_DAHDITOOLS_PATH" != '' ]; then
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-tonezone=$LIVE_AST_DAHDITOOLS_PATH"
-+ LIVE_AST_LD_PATH_EXTRA="$LIVE_AST_LD_PATH_EXTRA $LIVE_AST_DAHDITOOLS_PATH"
-+fi
-+
-+if [ "$LIVE_AST_ZPALIVE_PATH" != '' ]; then
-+ ZAPLIVE_USR_DIR="$LIVE_AST_ZPALIVE_PATH/live/usr"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-tonezone=$ZAPLIVE_USR_DIR"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-zaptel=$ZAPALIVE_USR_DIR"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-zaptel_transcode=$ZAPALIVE_USR_DIR"
-+ LIVE_AST_CONFIGURE_PARAMS="$LIVE_AST_CONFIGURE_PARAMS --with-zaptel_vldtmf=$ZAPALIVE_USR_DIR"
-+ LIVE_AST_LD_PATH_EXTRA="$LIVE_AST_LD_PATH_EXTRA $ZAPLIVE_USR_DIR/lib"
-+fi
-+
-+# gets rid of excessive spaces. Leves nothing if there were only white spaces:
-+LIVE_AST_LD_PATH_EXTRA=`echo $LIVE_AST_LD_PATH_EXTRA | tr ' ' :`
-+
-+set_ld_env() {
-+ if [ "$LIVE_AST_LD_PATH_EXTRA$LD_LIBRARY_PATH" = '' ]; then return; fi
-+
-+ LD_LIBRARY_PATH=`echo $LIVE_AST_LD_PATH_EXTRA $LD_LIBRARY_PATH | tr ' ' :`
-+ export LD_LIBRARY_PATH
-+}
-+
-+# if live.conf does not exist, generate it from the sample
-+gen_live_conf() {
-+ if [ -r $LIVE_CONF ]; then return; fi
-+ # TODO: `dirname $LIVE_CONF` in case someone redefines it?
-+ mkdir -p $BASE_DIR
-+ sed -n -e '/^#* Begin Samples/,/^#* End Samples/p' "$0" \
-+ | sed -e '/^#* \(Begin\|End\) Samples/d' >"$LIVE_CONF"
-+}
-+
-+case "$1" in
-+configure)
-+ shift
-+ ./configure $LIVE_AST_CONFIGURE_PARAMS "$@"
-+ if [ "$LIVE_AST_FORCE_DEF_CONF" != '' ]; then
-+ rm -f menuselect.makeopts
-+ fi
-+ if [ "$LIVE_AST_BRISTUFFED_LIBPRI" != '' ]; then
-+ sed -i \
-+ -e 's|^\(PRI_INCLUDE=\).*|\1-I/usr/include/bristuffed|' \
-+ -e 's|^\(PRI_LIB=\).*|\1-lpri-bristuffed|' \
-+ makeopts
-+ fi
-+ ;;
-+install)
-+ make install DESTDIR="$BASE_DIR"
-+ ;;
-+samples)
-+ make samples DESTDIR="$BASE_DIR"
-+ if [ "$LIVE_AST_FOR_SYSTEM" != '' ]; then
-+ cat <<EOF >"$AST_CONF"
-+[directories]
-+; rem-out any of the following to use Asterisk's defaults:
-+;astetcdir => $BASE_DIR/etc/asterisk
-+astmoddir => $BASE_DIR/usr/lib/asterisk/modules
-+;astvarlibdir => $BASE_DIR/var/lib/asterisk
-+;astdatadir => $BASE_DIR/var/lib/asterisk
-+;astagidir => $BASE_DIR/var/lib/asterisk/agi
-+;astrundir => $BASE_DIR/var/run
-+astrundir => /var/run/asterisk
-+;astspooldir => $BASE_DIR/var/spool/asterisk
-+;astlogdir => $BASE_DIR/var/log/asterisk
-+EOF
-+ else
-+ cat <<EOF >"$AST_CONF"
-+[directories]
-+; rem-out any of the following to use Asterisk's defaults:
-+astetcdir => $BASE_DIR/etc/asterisk
-+astmoddir => $BASE_DIR/usr/lib/asterisk/modules
-+astvarlibdir => $BASE_DIR/var/lib/asterisk
-+astdatadir => $BASE_DIR/var/lib/asterisk
-+astagidir => $BASE_DIR/var/lib/asterisk/agi
-+astrundir => $BASE_DIR/var/run
-+astspooldir => $BASE_DIR/var/spool/asterisk
-+astlogdir => $BASE_DIR/var/log/asterisk
-+EOF
-+ fi
-+ # disable some modules that bind on a port that is already in use by a
-+ # main Asterisk copy, and would crash asterisk in failing:
-+ rm -f "$AST_CONF_DIR/$DISABLED_MODS_FILE"
-+ for mod in $DISABLED_MODS; do
-+ echo "noload => $mod.so" >> "$AST_CONF_DIR/$DISABLED_MODS_FILE"
-+ done
-+ echo "#include $DISABLED_MODS_FILE" >> "$AST_CONF_DIR/modules.conf"
-+
-+ cat <<EOF >"$GDB_INIT"
-+set args -C "$AST_CONF" -c
-+EOF
-+cat <<EOF >"$BASE_DIR/asterisk"
-+#!/bin/sh
-+# a wrapper to run asterisk from the "live" copy:
-+cd "$PWD"
-+exec "$0" run "\$@"
-+EOF
-+ chmod +x "$BASE_DIR/asterisk"
-+ # Generate a sample config file for live_ast itself:
-+ gen_live_conf
-+ ;;
-+conf-file)
-+ # Just regenerate live.conf from the sample if it does not already exist:
-+ gen_live_conf
-+ ;;
-+run)
-+ shift
-+ set_ld_env
-+ $AST_BIN -C $AST_CONF "$@"
-+ ;;
-+gdb)
-+ set_ld_env
-+ gdb -x $GDB_INIT $AST_BIN
-+ ;;
-+*)
-+ echo "$0: Usage: Equivalent of:"
-+ echo "$0 configure [params] ./configure [params]"
-+ echo "$0 install make install"
-+ echo "$0 samples make samples"
-+ echo "$0 run [params] asterisk [params]"
-+ echo "$0 gdb gdb asterisk"
-+ echo "$0 conf-file create live.conf if it does exist"
-+ exit 1
-+ ;;
-+esac
-
-Property changes on: contrib/scripts/live_ast
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:executable
- + *
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: contrib/scripts/safe_asterisk
-===================================================================
---- a/contrib/scripts/safe_asterisk (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/scripts/safe_asterisk (.../team/group/issue14292) (revision 178988)
-@@ -12,7 +12,8 @@
- DUMPDROP=/tmp
- SLEEPSECS=4
- ASTSBINDIR=__ASTERISK_SBIN_DIR__
--ASTPIDFILE=__ASTERISK_VARRUN_DIR__/asterisk.pid
-+ASTVARRUNDIR=__ASTERISK_VARRUN_DIR__
-+ASTPIDFILE=${ASTVARRUNDIR}/asterisk.pid
-
- # comment this line out to have this script _not_ kill all mpg123 processes when
- # asterisk exits
-@@ -91,6 +92,11 @@
- # set the process's filemax to whatever set above
- ulimit -n $MAXFILES
-
-+ if [ ! -d ${ASTVARRUNDIR} ]; then
-+ mkdir -p ${ASTVARRUNDIR}
-+ chmod 770 ${ASTVARRUNDIR}
-+ fi
-+
- fi
-
- if test "x$UMASK" != "x"; then
-@@ -192,7 +198,7 @@
- sleep $SLEEPSECS
- if [ $KILLALLMPG123 ]
- then
-- killall -9 mpg123
-+ pkill -9 mpg123
- fi
- done
- }
-Index: contrib/scripts/sip_nat_settings
-===================================================================
---- a/contrib/scripts/sip_nat_settings (.../tags/1.6.1-rc1) (revision 0)
-+++ b/contrib/scripts/sip_nat_settings (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,72 @@
-+#!/bin/sh
-+
-+# sip_nat_settings: generate NAT settings for sip.conf of an Asterisk system
-+# that is behind a NAT router.
-+#
-+# This is a script to generate sane defaults for externip and localnet
-+# of sip.conf. The output should be included in the [general] section of
-+# sip.conf .
-+#
-+# Multiple network interfaces: If you have multiple network interfaces,
-+# this script will generate a 'localnet' line for each of them that has a
-+# broadcast (ipv4) address, except the loopback interface (lo). You can
-+# later rem-out all of those you don't need.
-+#
-+# Alternatively, provide a network interface as a parameter an a localnet
-+# line will only be generated for its network.
-+#
-+# Copyright (C) 2005 by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software
-+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+
-+WGET=`which wget`
-+FETCH=`which fetch`
-+if [ -x ${WGET} ]; then
-+ externip=`${WGET} -q -O- http://www.whatismyip.org`
-+elif [ -x ${FETCH} ]; then
-+ externip=`${FETCH} -q -o - http://www.whatismyip.org`
-+else
-+ echo "no binary found to contact http://www.whatismyip.org"
-+ exit 1
-+fi
-+
-+# optional parameter: network interface to use. By default: none.
-+IFACE="$1"
-+
-+OS=`uname -s`
-+case "$OS" in
-+Linux)
-+ echo "externip = $externip"
-+ /sbin/ifconfig $IFACE | grep 'inet addr:' | grep Bcast \
-+ | sed -e 's/^.*Bcast:\([0-9.]*\)\s*Mask:\([0-9.]*\)\s*$/localnet = \1\/\2/'
-+ ;;
-+OpenBSD|FreeBSD)
-+ if [ "${OS}" = "FreeBSD" ]; then
-+ VER=`uname -r | cut -d . -f 1`
-+ if [ ${VER} -lt 7 ]; then
-+ echo "Unsupported OS"
-+ exit 1
-+ fi
-+ fi
-+ echo "externip = $externip"
-+ ip=`/sbin/ifconfig $IFACE | awk '/\tinet .* broadcast/{print $6}'`
-+ x=`/sbin/ifconfig $IFACE | awk '/\tinet .* broadcast/{print $4}'`
-+ printf 'localnet = %s/%u.%u.%u.%u\n' $ip $(($x>>24&0xff)) $(($x>>16&0xff)) $(($x>>8&0xff)) $(($x&0xff))
-+ ;;
-+*)
-+ echo >&2 "$0: Unsupported OS $OS"
-+ exit 1
-+ ;;
-+esac
-
-Property changes on: contrib/scripts/sip_nat_settings
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:executable
- + *
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: contrib/asterisk-ng-doxygen
-===================================================================
---- a/contrib/asterisk-ng-doxygen (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/contrib/asterisk-ng-doxygen (.../team/group/issue14292) (revision 178988)
-@@ -178,6 +178,7 @@
- # You can put \n's in the value part of an alias to insert newlines.
-
- ALIASES = "extref=\xrefitem extref \"ExtRef\" \"External references\""
-+ALIASES += "AsteriskTrunkWarning=\note The information contained on this page may be out of date. To make sure you get the most current information, please make sure that you are using the documentation generated from Asterisk trunk."
-
- # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
- # sources only. Doxygen will then generate output that is more tailored for C.
-@@ -1098,7 +1099,9 @@
- AST_RWDLLIST_HEAD_STATIC \
- AST_DLLIST_ENTRY \
- AST_RWDLLIST_ENTRY \
-- AST_CLI_DEFINE
-+ AST_CLI_DEFINE \
-+ AST_OPTIONAL_API \
-+ AST_OPTIONAL_API_ATTR
-
- # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
- # doxygen's preprocessor will remove all function-like macros that are alone
-Index: codecs/slin_ulaw_ex.h
-===================================================================
---- a/codecs/slin_ulaw_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_ulaw_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * \brief slin_ulaw_ex.h --
-- *
-- * Signed 16-bit audio data, 10 milliseconds worth at 8 kHz.
-- *
-- * Source: g723.example
-- *
-- * Copyright (C) 2001-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_ulaw_ex[] = {
-- 0xcac0, 0xcdeb, 0xd116, 0xd441, 0xd76c, 0xda97, 0xddc2, 0xe0ed,
-- 0x0000, 0x032b, 0x0656, 0x0981, 0x0cac, 0x0fd7, 0x1302, 0x162d,
-- 0x1958, 0x1c83, 0x1fae, 0x22d9, 0x2604, 0x292f, 0x2c5a, 0x2f85,
-- 0x32b0, 0x35db, 0x3906, 0x3c31, 0x3f5c, 0x4287, 0x45b2, 0x48dd,
-- 0xb168, 0xb493, 0xb7be, 0xbae9, 0xbe14, 0xc13f, 0xc46a, 0xc795,
-- 0xe418, 0xe743, 0xea6e, 0xed99, 0xf0c4, 0xf3ef, 0xf71a, 0xfa45,
-- 0x9810, 0x9b3b, 0x9e66, 0xa191, 0xa4bc, 0xa7e7, 0xab12, 0xae3d,
-- 0x4c08, 0x4f33, 0x525e, 0x5589, 0x58b4, 0x5bdf, 0x5f0a, 0x6235,
-- 0x6560, 0x688b, 0x6bb6, 0x6ee1, 0x720c, 0x7537, 0x7862, 0x7b8d,
-- 0x7eb8, 0x81e3, 0x850e, 0x8839, 0x8b64, 0x8e8f, 0x91ba, 0x94e5,
--};
-Index: codecs/slin_lpc10_ex.h
-===================================================================
---- a/codecs/slin_lpc10_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_lpc10_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,21 +0,0 @@
--/*! \file
-- * \brief Signed 16-bit audio data
-- *
-- * Source: example.slin
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_lpc10_ex[] = {
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000 };
-Index: codecs/slin_g722_ex.h
-===================================================================
---- a/codecs/slin_g722_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_g722_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * \brief slin_g722_ex.h --
-- *
-- * Signed 16-bit audio data, 10 milliseconds worth at 8 kHz.
-- *
-- * Source: g723.example
-- *
-- * Copyright (C) 2001-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_g722_ex[] = {
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
--};
-Index: codecs/g722_slin_ex.h
-===================================================================
---- a/codecs/g722_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/g722_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * \brief g722_slin_ex.h --
-- *
-- * 4-bit ADPCM data, 20 milliseconds worth at 8 kHz.
-- *
-- * Source: g723.example
-- *
-- * Copyright (C) 2001-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char g722_slin_ex[] = {
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
--};
-Index: codecs/slin_adpcm_ex.h
-===================================================================
---- a/codecs/slin_adpcm_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_adpcm_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * \brief slin_adpcm_ex.h --
-- *
-- * Signed 16-bit audio data, 10 milliseconds worth at 8 kHz.
-- *
-- * Source: g723.example
-- *
-- * Copyright (C) 2001-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_adpcm_ex[] = {
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
--};
-Index: codecs/adpcm_slin_ex.h
-===================================================================
---- a/codecs/adpcm_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/adpcm_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * adpcm_slin_ex.h --
-- *
-- * \brief 4-bit ADPCM data, 20 milliseconds worth at 8 kHz.
-- *
-- * Source: g723.example
-- *
-- * Copyright (C) 2001-2005, Digium, Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char adpcm_slin_ex[] = {
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
--};
-Index: codecs/slin_g726_ex.h
-===================================================================
---- a/codecs/slin_g726_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_g726_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * \brief slin_adpcm_ex.h --
-- *
-- * Signed 16-bit audio data, 10 milliseconds worth at 8 kHz.
-- *
-- * Source: g726.example
-- *
-- * Copyright (C) 2001-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_g726_ex[] = {
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
--};
-Index: codecs/g726_slin_ex.h
-===================================================================
---- a/codecs/g726_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/g726_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * adpcm_slin_ex.h --
-- *
-- * \brief 4-bit G.726 data, 20 milliseconds worth at 8 kHz.
-- *
-- * Source: g726.example
-- *
-- * Copyright (C) 2001-2005, Digium, Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char g726_slin_ex[] = {
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
--};
-Index: codecs/slin_gsm_ex.h
-===================================================================
---- a/codecs/slin_gsm_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_gsm_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,28 +0,0 @@
--/*! \file
-- * \brief Signed 16-bit audio data
-- *
-- * Source: gsm.example
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_gsm_ex[] = {
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 0xfff8, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 0x0008, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--0x0008, 000000, 000000, 000000, 0xfff8, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 0x0008, 000000, 000000, 000000 };
-Index: codecs/gsm_slin_ex.h
-===================================================================
---- a/codecs/gsm_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/gsm_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,16 +0,0 @@
--/*! \file
-- * \brief 8-bit raw data
-- *
-- * Source: gsm.example
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char gsm_slin_ex[] = {
--0xda, 0xa6, 0xac, 0x2d, 0xa3, 0x50, 000, 0x49, 0x24, 0x92,
--0x49, 0x24, 0x50, 0x40, 0x49, 0x24, 0x92, 0x37, 0x24, 0x52,
--000, 0x49, 0x24, 0x92, 0x47, 0x24, 0x50, 0x80, 0x46, 0xe3,
--0x6d, 0xb8, 0xdc };
-Index: codecs/slin_resample_ex.h
-===================================================================
---- a/codecs/slin_resample_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_resample_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,43 +0,0 @@
--/*! \file
-- * \brief slin_resample_ex.h --
-- *
-- * Copyright (C) 2007, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- */
--
--static signed short slin16_slin8_ex[] = {
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
--};
--
--static signed short slin8_slin16_ex[] = {
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
--};
-Index: codecs/ulaw_slin_ex.h
-===================================================================
---- a/codecs/ulaw_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/ulaw_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,25 +0,0 @@
--/*! \file
-- * \brief ulaw_slin_ex.h --
-- *
-- * 4-bit ADPCM data, 20 milliseconds worth at 8 kHz.
-- *
-- * Source: g723.example
-- *
-- * Copyright (C) 2001-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char ulaw_slin_ex[] = {
-- 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
-- 0x10, 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a,
-- 0x20, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f,
-- 0x30, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x51, 0x54,
-- 0x40, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69,
-- 0x50, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e,
-- 0x60, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x93,
-- 0x70, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8,
-- 0x80, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
-- 0x90, 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2
--};
-Index: codecs/slin_ilbc_ex.h
-===================================================================
---- a/codecs/slin_ilbc_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_ilbc_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,28 +0,0 @@
--/*! \file
-- * \brief Signed 16-bit audio data
-- *
-- * Source: gsm.example
-- *
-- * Copyright (C) 1999-2005, Digium Inc
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_ilbc_ex[] = {
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 0xfff8, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 0x0008, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--0x0008, 000000, 000000, 000000, 0xfff8, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
--000000, 000000, 000000, 000000, 000000, 000000, 0x0008, 000000, 000000, 000000 };
-Index: codecs/ilbc_slin_ex.h
-===================================================================
---- a/codecs/ilbc_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/ilbc_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,17 +0,0 @@
--/*! \file
-- * \brief Raw 8-bit data
-- *
-- * Source: ilbc.out
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char ilbc_slin_ex[] = {
--0xff, 0xa0, 0xff, 0xfa, 0xf, 0x60, 0x12, 0x11, 0xa2, 0x47,
--0x22, 0x8c, 00, 00, 0x1, 0x2, 0x80, 0x43, 0xa0, 0x40,
--0x33, 0xff, 0xcf, 0xc0, 0xf3, 0xf3, 0x3f, 0x8f, 0x3f, 0xff,
--0xff, 0xff, 0xff, 0xfc, 0xf9, 0xe5, 0x55, 0x78, 0xb, 0xca,
--0xe1, 0x27, 0x94, 0x7b, 0xa8, 0x91, 0x2c, 0x36, 0x8, 0x56 };
-Index: codecs/lpc10_slin_ex.h
-===================================================================
---- a/codecs/lpc10_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/lpc10_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,13 +0,0 @@
--/*! \file
-- * \brief 8-bit raw data
-- *
-- * Source: example.lpc10
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char lpc10_slin_ex[] = {
--0x1, 0x8, 0x31, 0x8, 0x31, 0x80, 0x30 };
-Index: codecs/slin_speex_ex.h
-===================================================================
---- a/codecs/slin_speex_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/slin_speex_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,262 +0,0 @@
--/*! \file
-- * \brief Signed 16-bit audio data, 500ms of speech at 8kHz to ensure no DTX triggered
-- *
-- * Source: speex.example
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static signed short slin_speex_ex[] = {
--0x4a00, 0xa700, 0x6d00, 0x4900, 0x5800, 0x3e00, 0x1b00, 0x1400, 0xf9ff, 0xe4ff, 0x0a00, 0xf0ff, 0xbbff, 0x0200, 0x0800, 0xd6ff,
--0xf1ff, 0x1200, 0x0500, 0x1000, 0x0f00, 0x0700, 0x4100, 0x2800, 0xf4ff, 0x2900, 0x3100, 0xf4ff, 0xefff, 0xdaff, 0xdaff, 0xc2ff,
--0xa5ff, 0xccff, 0xd4ff, 0xc7ff, 0xe6ff, 0x0600, 0x0c00, 0x1900, 0x1200, 0x0d00, 0x2900, 0x1e00, 0xf4ff, 0x0000, 0x1200, 0xf5ff,
--0xe5ff, 0x0000, 0x0000, 0xf1ff, 0x0300, 0x0b00, 0xfdff, 0x0500, 0x0f00, 0x0600, 0x0d00, 0x0f00, 0x0000, 0xfdff, 0xfcff, 0xe5ff,
--0xdcff, 0xe0ff, 0xafff, 0xb2ff, 0xe4ff, 0xceff, 0xe2ff, 0x0000, 0x1600, 0x2600, 0x2400, 0x3f00, 0x4a00, 0x3d00, 0x2b00, 0x2f00,
--0x4300, 0x1000, 0x0300, 0x0700, 0xe9ff, 0xf3ff, 0xebff, 0xd9ff, 0xe5ff, 0xf9ff, 0xeeff, 0xe9ff, 0x0500, 0x0a00, 0x0300, 0x0800,
--0x1800, 0x1c00, 0x1000, 0x1300, 0x0d00, 0x0400, 0x0200, 0xf9ff, 0xe4ff, 0xe6ff, 0xe0ff, 0xd9ff, 0xecff, 0xf2ff, 0xe8ff, 0xfdff,
--0x1100, 0x0d00, 0x0b00, 0x1100, 0x1100, 0x1200, 0x0c00, 0x0400, 0x0900, 0x0d00, 0x0100, 0xfdff, 0x0000, 0xfdff, 0x0000, 0xffff,
--0xf5ff, 0xfcff, 0x0600, 0xfeff, 0x0000, 0x0300, 0x1300, 0x1700, 0x0300, 0x0700, 0xf0ff, 0xe1ff, 0xd7ff, 0xd1ff, 0xc6ff, 0xc2ff,
--0xf2ff, 0xf0ff, 0xecff, 0x0700, 0x3200, 0x2d00, 0x0400, 0x2200, 0x2900, 0x1900, 0x2400, 0x0500, 0x1900, 0x1f00, 0xfeff, 0x0d00,
--0x0600, 0xebff, 0xf5ff, 0x0600, 0xebff, 0xe3ff, 0x0c00, 0x0d00, 0xefff, 0x1100, 0x3a00, 0x0700, 0x1700, 0x2f00, 0xf7ff, 0x0700,
--0x2600, 0xd9ff, 0xb8ff, 0xeaff, 0xbeff, 0x9eff, 0xc7ff, 0xccff, 0xc4ff, 0xeeff, 0x0000, 0xfdff, 0x1200, 0x1d00, 0x3100, 0x3600,
--0x2d00, 0x3c00, 0x4700, 0x3000, 0x2000, 0x2300, 0x1800, 0x0900, 0xffff, 0xeaff, 0xe7ff, 0xe8ff, 0xd3ff, 0xc5ff, 0xe1ff, 0xedff,
--0xe4ff, 0xfaff, 0xe3ff, 0xacff, 0xcdff, 0xd4ff, 0xabff, 0xa6ff, 0xdaff, 0x0500, 0xf1ff, 0xfaff, 0x3800, 0x7000, 0x4100, 0x1c00,
--0x4b00, 0x5300, 0x3a00, 0x2a00, 0x1400, 0x2000, 0x1c00, 0x1500, 0x0500, 0xf6ff, 0x0000, 0x1300, 0xfaff, 0xe9ff, 0x0000, 0x0a00,
--0xfcff, 0xfaff, 0x1000, 0x1200, 0x0900, 0x0c00, 0x0400, 0x0000, 0x0800, 0xffff, 0xe7ff, 0xe2ff, 0xe6ff, 0xd5ff, 0xdaff, 0xe0ff,
--0xdcff, 0xeeff, 0x0200, 0xfbff, 0x0000, 0x1000, 0x1100, 0x1500, 0x1900, 0x1400, 0x1900, 0x1c00, 0x1500, 0x1000, 0x0d00, 0x0b00,
--0x0700, 0x0200, 0xf6ff, 0xf5ff, 0xf9ff, 0xecff, 0xe8ff, 0xeeff, 0xf4ff, 0xf4ff, 0xeeff, 0xecff, 0xebff, 0xd7ff, 0xd8ff, 0xeaff,
--0xe0ff, 0xddff, 0x0100, 0x0500, 0xf8ff, 0x1800, 0x2d00, 0x1d00, 0x1a00, 0x2100, 0x1f00, 0x1f00, 0x1a00, 0x0f00, 0x0300, 0x0d00,
--0x0e00, 0xfeff, 0x0000, 0xfeff, 0x0000, 0x0000, 0xf1ff, 0xfaff, 0x0a00, 0x0100, 0xf5ff, 0x0300, 0x0e00, 0x0300, 0x0200, 0x0000,
--0x0800, 0x0700, 0xf8ff, 0xf5ff, 0xf1ff, 0xefff, 0xe9ff, 0xe0ff, 0xe0ff, 0xedff, 0xf0ff, 0xedff, 0xfcff, 0xffff, 0xfdff, 0x0a00,
--0x0f00, 0x0e00, 0x0f00, 0x1700, 0x1400, 0x0700, 0x0500, 0x0800, 0x0000, 0x0200, 0x0400, 0xfaff, 0xffff, 0x0200, 0xfaff, 0xfbff,
--0x0300, 0x0400, 0x0400, 0x0100, 0xe7ff, 0xd4ff, 0xdbff, 0xe2ff, 0xe0ff, 0xd0ff, 0xe7ff, 0x0700, 0xf2ff, 0x0000, 0x2d00, 0x2000,
--0x1800, 0x2c00, 0x1f00, 0x2600, 0x2200, 0x0e00, 0x0e00, 0x0000, 0x0400, 0x0800, 0x0300, 0xfbff, 0x0500, 0x1d00, 0x0000, 0xfbff,
--0x2e00, 0x2500, 0x0600, 0x1c00, 0x2600, 0x1600, 0x0e00, 0x0200, 0xf9ff, 0x0000, 0xe1ff, 0xc0ff, 0xd5ff, 0xc9ff, 0xb6ff, 0xbcff,
--0xccff, 0xc9ff, 0xcbff, 0xe5ff, 0xeaff, 0xf0ff, 0xfeff, 0x0000, 0x0b00, 0x1f00, 0x2000, 0x1b00, 0x2000, 0x2400, 0x1800, 0x1200,
--0x1700, 0x0c00, 0x0b00, 0x0d00, 0xfdff, 0xf5ff, 0x0000, 0xf9ff, 0xefff, 0xfaff, 0xf7ff, 0xf0ff, 0xe7ff, 0xcbff, 0xd1ff, 0xedff,
--0xf5ff, 0xfcff, 0xfeff, 0x1e00, 0x3200, 0x2200, 0x3800, 0x4f00, 0x3800, 0x2c00, 0x4000, 0x3e00, 0x2e00, 0x2900, 0x1200, 0x0500,
--0x0700, 0x0000, 0xf2ff, 0xf2ff, 0xf8ff, 0xf5ff, 0xf7ff, 0xeaff, 0xefff, 0x0100, 0xfcff, 0xf9ff, 0x0000, 0x0700, 0xf9ff, 0xf2ff,
--0xf9ff, 0xf0ff, 0xf1ff, 0xe7ff, 0xddff, 0xe1ff, 0xddff, 0xd9ff, 0xdaff, 0xe1ff, 0xe2ff, 0xe5ff, 0xe5ff, 0xf0ff, 0xfaff, 0xf4ff,
--0xfdff, 0x1100, 0x0e00, 0x0e00, 0x1800, 0x1600, 0x1200, 0x1400, 0x1500, 0x1200, 0x0b00, 0x0600, 0x0c00, 0x0500, 0x0100, 0x0b00,
--0x0200, 0xfaff, 0xffff, 0xf9ff, 0xe8ff, 0xd0ff, 0xc9ff, 0xd5ff, 0xe0ff, 0xe6ff, 0xedff, 0xf5ff, 0x1100, 0x1300, 0x1f00, 0x3600,
--0x2900, 0x2200, 0x2c00, 0x3700, 0x2d00, 0x2000, 0x1a00, 0x0800, 0xfaff, 0xfcff, 0xf6ff, 0xf2ff, 0xebff, 0xf7ff, 0x0200, 0xf1ff,
--0xf5ff, 0x0d00, 0x0900, 0xf9ff, 0x1000, 0x2000, 0x0a00, 0xf9ff, 0xffff, 0xf9ff, 0xf2ff, 0xeeff, 0xdbff, 0xd8ff, 0xdbff, 0xdaff,
--0xdaff, 0xdfff, 0xe6ff, 0xecff, 0xedff, 0xf0ff, 0x0500, 0x0900, 0x0400, 0x0f00, 0x2600, 0x2700, 0x2200, 0x2b00, 0x1700, 0x1100,
--0x2a00, 0x2200, 0x0c00, 0x0200, 0x0100, 0x0200, 0xfeff, 0xfaff, 0xf7ff, 0xf3ff, 0xf1ff, 0xf5ff, 0xf6ff, 0xe8ff, 0xd3ff, 0xcdff,
--0xdbff, 0xebff, 0xedff, 0xf0ff, 0xfbff, 0x1400, 0x1700, 0x2000, 0x3400, 0x2700, 0x1a00, 0x2100, 0x2e00, 0x2900, 0x1e00, 0x0c00,
--0xfbff, 0xfbff, 0xf9ff, 0xf3ff, 0xf4ff, 0xe8ff, 0xecff, 0x0300, 0xf8ff, 0xf4ff, 0x0100, 0x0600, 0xf7ff, 0x0900, 0x1e00, 0x0f00,
--0x0900, 0x0700, 0x0000, 0x0000, 0x0000, 0xf5ff, 0xebff, 0xefff, 0xf3ff, 0xeeff, 0xf0ff, 0xf1ff, 0xefff, 0xf0ff, 0xf6ff, 0xfcff,
--0xf9ff, 0xf8ff, 0xfbff, 0x0300, 0x0900, 0x0800, 0x0900, 0x0100, 0x0200, 0x0c00, 0x0e00, 0x0300, 0xfdff, 0xfcff, 0xfbff, 0xfbff,
--0xf9ff, 0xf3ff, 0xf3ff, 0xecff, 0xf6ff, 0xfbff, 0xf4ff, 0xecff, 0xd6ff, 0xdcff, 0xf1ff, 0xf1ff, 0xeeff, 0xf6ff, 0x0600, 0x0a00,
--0x1000, 0x1e00, 0x1b00, 0x1100, 0x1800, 0x2800, 0x2500, 0x2600, 0x1c00, 0x0e00, 0x0900, 0x0e00, 0x0800, 0x0200, 0xfaff, 0xf5ff,
--0x0300, 0xf8ff, 0xfcff, 0x0500, 0x0500, 0x0000, 0xfaff, 0x0b00, 0x1c00, 0x0d00, 0xfdff, 0x0200, 0x0100, 0xfbff, 0xf5ff, 0xe8ff,
--0xe8ff, 0xecff, 0xdaff, 0xd1ff, 0xddff, 0xdeff, 0xd8ff, 0xdeff, 0xedff, 0xf3ff, 0xf8ff, 0x0100, 0x1100, 0x2300, 0x2800, 0x3100,
--0x3200, 0x3500, 0x3a00, 0x3e00, 0x3400, 0x2700, 0x2100, 0x1400, 0x0900, 0xf7ff, 0xfaff, 0xf3ff, 0xe2ff, 0xeaff, 0xe3ff, 0xdfff,
--0xd7ff, 0xc9ff, 0xdaff, 0xe4ff, 0xe0ff, 0xe4ff, 0xefff, 0xf4ff, 0xf6ff, 0x0000, 0x0100, 0x0000, 0x0600, 0x0c00, 0x0c00, 0x1000,
--0x1900, 0x1600, 0x1500, 0x1600, 0x1100, 0x1400, 0x1200, 0x1300, 0x0900, 0x0d00, 0x1400, 0x0e00, 0x1900, 0x1400, 0x0900, 0x0600,
--0x1600, 0x1900, 0x0800, 0x0300, 0x0000, 0xf5ff, 0xedff, 0xeaff, 0xdbff, 0xdcff, 0xcbff, 0xb7ff, 0xbfff, 0xc3ff, 0xc2ff, 0xbfff,
--0xcbff, 0xdaff, 0xe7ff, 0xf9ff, 0x0600, 0x1b00, 0x2c00, 0x2900, 0x3d00, 0x4b00, 0x4700, 0x4b00, 0x4a00, 0x4300, 0x3700, 0x3300,
--0x1f00, 0x1400, 0x1000, 0x0f00, 0x0c00, 0x0000, 0xf6ff, 0xe7ff, 0xe7ff, 0xdeff, 0xd3ff, 0xe1ff, 0xdeff, 0xd9ff, 0xe0ff, 0xe8ff,
--0xf1ff, 0xeaff, 0xe8ff, 0xf5ff, 0xf7ff, 0xf6ff, 0xf7ff, 0xf4ff, 0xf8ff, 0xfcff, 0x0100, 0xfcff, 0xf7ff, 0x0100, 0x0600, 0x0100,
--0x0700, 0x0200, 0x0c00, 0x1000, 0x0e00, 0x1c00, 0x1a00, 0x1a00, 0x1800, 0x2200, 0x1f00, 0x1600, 0x1700, 0x0b00, 0xfbff, 0xfcff,
--0xeaff, 0xd6ff, 0xdfff, 0xcbff, 0xc0ff, 0xc0ff, 0xbcff, 0xc1ff, 0xc5ff, 0xd1ff, 0xdaff, 0xecff, 0xffff, 0xfeff, 0x1000, 0x2700,
--0x2400, 0x2400, 0x3800, 0x3600, 0x3100, 0x3300, 0x2800, 0x2000, 0x1e00, 0x1d00, 0x0800, 0x0400, 0x1600, 0x0900, 0x0000, 0x0d00,
--0x0100, 0xefff, 0xf1ff, 0xedff, 0xe0ff, 0xe6ff, 0xf5ff, 0xe1ff, 0xdaff, 0xf3ff, 0xf6ff, 0xeeff, 0xf1ff, 0xf9ff, 0xfbff, 0x0000,
--0x0700, 0x0900, 0x0d00, 0x1c00, 0x1d00, 0x1b00, 0x1a00, 0x2500, 0x2500, 0x1a00, 0x1600, 0x0e00, 0x0c00, 0x0b00, 0x0500, 0x0100,
--0x0200, 0x0000, 0xfbff, 0xfcff, 0xfdff, 0xfcff, 0xfcff, 0xf9ff, 0xf6ff, 0xf3ff, 0xeaff, 0xe6ff, 0xecff, 0xe8ff, 0xdfff, 0xe6ff,
--0xddff, 0xdaff, 0xecff, 0xefff, 0xf2ff, 0xfdff, 0x0100, 0xffff, 0x0800, 0x1700, 0x1000, 0x1300, 0x2100, 0x1b00, 0x1800, 0x1a00,
--0x1200, 0x1000, 0x2000, 0x1100, 0x0000, 0x0700, 0x0500, 0xfdff, 0xfcff, 0x0300, 0xf2ff, 0xeaff, 0xe1ff, 0xcdff, 0xd2ff, 0xe0ff,
--0xe0ff, 0xd5ff, 0xdfff, 0xf3ff, 0xf7ff, 0xfcff, 0x1100, 0x1800, 0x1900, 0x2100, 0x2600, 0x2800, 0x2900, 0x2d00, 0x2400, 0x1b00,
--0x1a00, 0x1000, 0x0800, 0x0500, 0xfcff, 0xf1ff, 0xf4ff, 0xf6ff, 0xf2ff, 0xf6ff, 0xffff, 0xffff, 0x0000, 0x0a00, 0x0a00, 0xfbff,
--0x0200, 0x0700, 0xf9ff, 0xf2ff, 0xeaff, 0xedff, 0xdfff, 0xd9ff, 0xe3ff, 0xd8ff, 0xdbff, 0xddff, 0xe2ff, 0xefff, 0xf6ff, 0xffff,
--0x0000, 0x0d00, 0x1500, 0x1600, 0x2200, 0x2800, 0x2700, 0x2900, 0x3700, 0x2d00, 0x2500, 0x2c00, 0x2900, 0x1100, 0x0600, 0xfdff,
--0xedff, 0xeaff, 0xddff, 0xcfff, 0xc9ff, 0xc0ff, 0xa8ff, 0xa8ff, 0xbeff, 0xceff, 0xd6ff, 0xe1ff, 0xf4ff, 0x1000, 0x1100, 0x1e00,
--0x3e00, 0x3c00, 0x3c00, 0x3d00, 0x3e00, 0x3300, 0x3000, 0x2b00, 0x1300, 0x0b00, 0x0600, 0xfaff, 0xf6ff, 0xf4ff, 0xe9ff, 0xedff,
--0x0000, 0xf8ff, 0xfbff, 0x0400, 0x0300, 0x0a00, 0x1400, 0x1300, 0x0100, 0x0b00, 0x0400, 0xf9ff, 0xf8ff, 0xeeff, 0xe9ff, 0xdeff,
--0xe1ff, 0xdaff, 0xd7ff, 0xe5ff, 0xd2ff, 0xd3ff, 0xe3ff, 0xe7ff, 0xedff, 0xf5ff, 0x0000, 0x0600, 0x1300, 0x1f00, 0x1c00, 0x2600,
--0x2b00, 0x3100, 0x2d00, 0x3100, 0x2e00, 0x2600, 0x1900, 0x1100, 0x0400, 0xf3ff, 0xf3ff, 0xdcff, 0xdbff, 0xddff, 0xd2ff, 0xccff,
--0xbbff, 0xc3ff, 0xe4ff, 0xf4ff, 0xf6ff, 0xfbff, 0x1600, 0x2100, 0x1600, 0x2000, 0x2500, 0x1b00, 0x2700, 0x2100, 0x1400, 0x0d00,
--0x1300, 0x0800, 0xfbff, 0xf8ff, 0xecff, 0xeeff, 0x0000, 0xefff, 0xeeff, 0xfcff, 0x0000, 0xfeff, 0x0600, 0x0700, 0x0200, 0x1400,
--0x1600, 0x0700, 0x0d00, 0x1400, 0x0e00, 0x0900, 0x0b00, 0x0500, 0xfaff, 0x0600, 0x0000, 0xf2ff, 0xfaff, 0xf6ff, 0xe9ff, 0xecff,
--0xecff, 0xe2ff, 0xe7ff, 0xf3ff, 0xf6ff, 0xf4ff, 0x0000, 0x0000, 0xffff, 0x1400, 0x0f00, 0x0f00, 0x1500, 0x1400, 0x1100, 0x1200,
--0x0c00, 0x0400, 0x0500, 0xffff, 0x0200, 0xfbff, 0xf5ff, 0xfeff, 0xf5ff, 0xe5ff, 0xe3ff, 0xe4ff, 0xe6ff, 0x0a00, 0xffff, 0xf3ff,
--0x0900, 0x0d00, 0xfbff, 0x0700, 0x0c00, 0xffff, 0x1200, 0x1e00, 0xfdff, 0x0700, 0x1c00, 0x1200, 0x0f00, 0x1200, 0x1500, 0xfbff,
--0x1200, 0x2300, 0xf9ff, 0x0300, 0x0d00, 0xf2ff, 0xf2ff, 0xf5ff, 0xd8ff, 0xd0ff, 0xddff, 0xd8ff, 0xc4ff, 0xdbff, 0xe0ff, 0xd6ff,
--0xecff, 0xd8ff, 0xf7ff, 0x1100, 0xffff, 0x1500, 0x2a00, 0x1c00, 0x1800, 0x2200, 0x1500, 0x0800, 0x1d00, 0x1600, 0x0800, 0x1300,
--0x0500, 0xecff, 0x1100, 0x0a00, 0x1700, 0x0900, 0xffff, 0x2700, 0x1b00, 0x0b00, 0x1400, 0x1200, 0xecff, 0x1000, 0x1800, 0xdfff,
--0xfbff, 0xf1ff, 0x9bff, 0x90ff, 0x97ff, 0x81ff, 0xf2ff, 0xf9ff, 0x8cff, 0xcbff, 0x3300, 0x0200, 0x1300, 0x4f00, 0x1600, 0x2700,
--0x7400, 0x4000, 0x2a00, 0x4e00, 0x4b00, 0x1800, 0x2b00, 0x3900, 0x1c00, 0x2500, 0x1000, 0xf1ff, 0xf9ff, 0xf5ff, 0xdbff, 0xdbff,
--0x0000, 0x0b00, 0xd7ff, 0xcbff, 0xecff, 0xdfff, 0xebff, 0xe5ff, 0xafff, 0xdfff, 0xe5ff, 0xbeff, 0xc9ff, 0x0000, 0xe0ff, 0xcdff,
--0x1d00, 0x1b00, 0xefff, 0x1c00, 0x2100, 0x1100, 0x3200, 0x3400, 0x1d00, 0x2d00, 0x2600, 0x3b00, 0x3600, 0x4200, 0x0a00, 0x0000,
--0x5f00, 0x4000, 0x0000, 0x1000, 0x2800, 0xeaff, 0xd9ff, 0xcdff, 0xf8ff, 0x8400, 0xc1ff, 0xbefe, 0x56ff, 0x7fff, 0xe5fe, 0xf5ff,
--0x3600, 0x4aff, 0x24ff, 0x6800, 0xdf00, 0x1600, 0x6d00, 0x7b00, 0xf200, 0xd500, 0x0700, 0x2300, 0x3500, 0x0600, 0xeaff, 0xd1ff,
--0x95ff, 0xd5ff, 0x0300, 0xbcff, 0xe0ff, 0x0000, 0x2500, 0x3100, 0xdf00, 0x6700, 0x0300, 0x6900, 0x2a00, 0x3f00, 0x0400, 0x7dff,
--0x58ff, 0xb2ff, 0x7bff, 0x71ff, 0xa1ff, 0x7dff, 0xd0ff, 0x1700, 0x0000, 0x0700, 0x5900, 0x4b00, 0x4b00, 0x4700, 0xf8ff, 0x4300,
--0x5e00, 0x0d00, 0xdaff, 0x1300, 0x0e00, 0x0f00, 0x2d00, 0xeaff, 0x1400, 0x6200, 0x3a00, 0xe3ff, 0x0c00, 0x1600, 0xfbff, 0xe8ff,
--0xfbff, 0x6700, 0xe3ff, 0x8eff, 0xf2fe, 0x25fe, 0x9bfe, 0x54ff, 0x94ff, 0x94ff, 0x7dff, 0x3000, 0x9401, 0xce01, 0x5601, 0x0e01,
--0xd300, 0x4f01, 0xdf00, 0x6fff, 0x25ff, 0x79ff, 0x5eff, 0x51ff, 0xd4ff, 0xbaff, 0x1b00, 0xbe00, 0x4a00, 0xf3ff, 0x2800, 0x4500,
--0x5e00, 0x1800, 0x84ff, 0x8aff, 0xc7ff, 0xc2ff, 0x8aff, 0xd7fe, 0x16ff, 0x0000, 0x1300, 0xf7ff, 0xbcff, 0xc3ff, 0x5500, 0x7c00,
--0x5a00, 0x5400, 0x2d00, 0x2d00, 0x2b00, 0xf9ff, 0xfcff, 0x0500, 0xddff, 0x1d00, 0x6600, 0x7a00, 0x9200, 0x3700, 0x0e00, 0x5600,
--0x2500, 0xcfff, 0xfdff, 0xe3ff, 0xc5ff, 0xcdff, 0x00ff, 0x67ff, 0xb100, 0x3200, 0x3200, 0xc800, 0xcdff, 0xaaff, 0x4dff, 0x42fd,
--0xc4fd, 0x3500, 0x2a00, 0x99ff, 0x1d00, 0xe500, 0x4e02, 0xf802, 0x6f01, 0xd4ff, 0x4f00, 0x7300, 0x88ff, 0x20ff, 0x81fe, 0x9afe,
--0xb2ff, 0x6800, 0x9100, 0x9700, 0x3001, 0x5500, 0xf4ff, 0xa400, 0xb2ff, 0xdeff, 0x1500, 0x05ff, 0x4fff, 0xe6ff, 0xaaff, 0xc9ff,
--0x0000, 0xafff, 0xeeff, 0x8200, 0x1800, 0xc7ff, 0xf1ff, 0xd5ff, 0x3000, 0x1d00, 0x50ff, 0x89ff, 0x82ff, 0x7cff, 0x2000, 0x1d00,
--0x0d00, 0x9500, 0x8c00, 0x2d00, 0x5b00, 0x2200, 0xf8ff, 0x6700, 0x7800, 0x3e00, 0xa800, 0x9100, 0xbfff, 0xccff, 0xdaff, 0x9bff,
--0x8400, 0x98ff, 0xa4fe, 0xddff, 0x1200, 0x2e00, 0xf100, 0x3500, 0x73ff, 0x99ff, 0xd1fd, 0x97fd, 0x0500, 0x7800, 0x3400, 0xc700,
--0xfc00, 0x8201, 0x6002, 0x8201, 0xb5ff, 0xaeff, 0xa5ff, 0x15ff, 0x90ff, 0x53ff, 0xccfe, 0x8eff, 0x9d00, 0xef00, 0x0601, 0xf300,
--0xa4ff, 0x5cff, 0x0b00, 0xfcff, 0x0d00, 0xd9ff, 0x3cff, 0x60ff, 0x5400, 0x3400, 0x2b00, 0x4800, 0xbbff, 0x0300, 0x5a00, 0xf5ff,
--0xc7ff, 0xe5ff, 0x91ff, 0xfeff, 0x0000, 0x51ff, 0xa8ff, 0x57ff, 0x74ff, 0x3a00, 0x6500, 0x5400, 0x0e00, 0x2900, 0x3800, 0x3d00,
--0x3300, 0x1100, 0x4400, 0x7200, 0x5c00, 0x6f00, 0x4c00, 0xc8ff, 0xa6ff, 0xc4ff, 0x9bff, 0x6a00, 0x1000, 0xccfe, 0xc6ff, 0x7e00,
--0x8aff, 0x6b00, 0xae00, 0x7bff, 0x71ff, 0xa0fd, 0x05fd, 0xc5ff, 0x5001, 0x1801, 0x9a01, 0x3f01, 0x1701, 0xc102, 0xd901, 0x83ff,
--0x35ff, 0xa7fe, 0x52fe, 0x98ff, 0x9eff, 0xcbfe, 0x90ff, 0xe100, 0x4801, 0xa001, 0x5101, 0x59ff, 0x04ff, 0xc3ff, 0x1800, 0x4400,
--0xe7ff, 0x22ff, 0x1dff, 0x4000, 0x2c00, 0x4b00, 0x7800, 0xa3ff, 0xd9ff, 0x7b00, 0x1a00, 0xb7ff, 0xb4ff, 0x70ff, 0xb6ff, 0x2200,
--0xc9ff, 0x35ff, 0xaeff, 0x2b00, 0x4700, 0x5100, 0xe6ff, 0x1100, 0x5900, 0x0500, 0xf0ff, 0x2300, 0x5b00, 0xbd00, 0xec00, 0xc500,
--0x8200, 0x93ff, 0x39ff, 0xafff, 0xbfff, 0x5200, 0x9cff, 0x49fe, 0x7fff, 0xa600, 0xfcff, 0xaa00, 0x7000, 0xf8fe, 0x64fe, 0xf7fc,
--0x73fd, 0x2100, 0xa001, 0xe501, 0x4a02, 0x3701, 0xe500, 0x7402, 0x6601, 0xb5ff, 0x5eff, 0x69fe, 0x40fe, 0xc8ff, 0xe6ff, 0x1cff,
--0xd1ff, 0xc900, 0x6601, 0xdf01, 0xf300, 0x67ff, 0xdcfe, 0x50ff, 0x2500, 0x7400, 0x0900, 0x42ff, 0x32ff, 0xe2ff, 0x2e00, 0x8700,
--0x2800, 0x84ff, 0xd4ff, 0x5a00, 0x1000, 0xc1ff, 0xafff, 0x62ff, 0xa7ff, 0x2700, 0x1100, 0xc5ff, 0xe2ff, 0xeeff, 0xb8ff, 0x3200,
--0x8b00, 0x0d00, 0x2600, 0x7b00, 0xf4ff, 0x6dff, 0x3d00, 0x9600, 0x8800, 0x2201, 0xa500, 0xf1ff, 0xe7ff, 0x9fff, 0x70ff, 0xe9ff,
--0x3a00, 0x5fff, 0xe8fe, 0x52ff, 0x0f00, 0x8e00, 0xb300, 0x3800, 0x1aff, 0x77fe, 0x13fd, 0x9afc, 0x6dff, 0xe301, 0x5602, 0x9902,
--0x3b01, 0xa6ff, 0x1501, 0x1a02, 0xa300, 0xebff, 0x1aff, 0xe6fd, 0x09ff, 0x6700, 0x5800, 0xefff, 0x4500, 0xd100, 0x6601, 0x5301,
--0x5600, 0x0eff, 0x9dfe, 0x91ff, 0x2400, 0x8500, 0xd7ff, 0xeffe, 0x39ff, 0xddff, 0x8c00, 0xa500, 0x0c00, 0x86ff, 0xd0ff, 0x2f00,
--0x1200, 0xf1ff, 0xbfff, 0x88ff, 0xd1ff, 0x4900, 0x2100, 0xbcff, 0xb1ff, 0x9aff, 0xf1ff, 0x8300, 0x6400, 0x3b00, 0x3e00, 0x2400,
--0xa3ff, 0x0000, 0x8200, 0x4b00, 0xa800, 0xe600, 0x0300, 0x2cff, 0x82ff, 0x0b00, 0x4300, 0x5600, 0xa9ff, 0xcdfe, 0x15ff, 0x6700,
--0xed00, 0x8a00, 0xe3ff, 0x74fe, 0xe3fc, 0xd1fc, 0x98fe, 0x2601, 0x7b02, 0x8d02, 0x8001, 0x3f00, 0xd300, 0x9501, 0xfe00, 0xeeff,
--0x50ff, 0x67fe, 0x81fe, 0xe8ff, 0x4900, 0x1200, 0x6800, 0xc000, 0xc200, 0x0c01, 0xb100, 0x7bff, 0x2fff, 0x91ff, 0xd6ff, 0xfeff,
--0xfeff, 0x63ff, 0x35ff, 0x0700, 0x7100, 0x6600, 0x4400, 0xceff, 0x9cff, 0x1100, 0x4500, 0xdfff, 0xabff, 0x96ff, 0x96ff, 0x1000,
--0x5b00, 0x0f00, 0xc2ff, 0xe3ff, 0xfdff, 0x3a00, 0x9000, 0x4c00, 0x1400, 0xe6ff, 0xe2ff, 0xc0ff, 0xf3ff, 0x4300, 0x1a00, 0x5100,
--0x7300, 0x3100, 0xc2ff, 0xebff, 0x5a00, 0x1e00, 0xafff, 0x3aff, 0x3cff, 0x80ff, 0x5a00, 0xf500, 0xffff, 0x57ff, 0x39ff, 0xe8fd,
--0x65fd, 0x65ff, 0x7d01, 0xfb01, 0x5b02, 0x7501, 0x9aff, 0x6000, 0x7701, 0x6b00, 0x94ff, 0x31ff, 0xe2fd, 0x85fe, 0x9300, 0xab00,
--0x4900, 0x9300, 0x5900, 0x3b00, 0x0701, 0x9000, 0x47ff, 0x4eff, 0x6cff, 0xedff, 0x5c00, 0x0000, 0x33ff, 0x81ff, 0x6200, 0x7400,
--0x9b00, 0x3400, 0x67ff, 0x94ff, 0x3100, 0x2800, 0xfeff, 0xfdff, 0xa3ff, 0x9fff, 0x2100, 0x2400, 0xebff, 0xf5ff, 0xe4ff, 0xe0ff,
--0x3f00, 0x5100, 0x1600, 0x1a00, 0xe7ff, 0xe0ff, 0xd4ff, 0x0000, 0x1200, 0x0500, 0x5b00, 0xc200, 0x5000, 0xcbff, 0x3b00, 0xe5ff,
--0x9fff, 0xf0ff, 0xd4ff, 0x76ff, 0x40ff, 0x2200, 0x8c00, 0x0f00, 0x5700, 0x5fff, 0xdffc, 0xfbfc, 0xe8ff, 0xc501, 0xa202, 0xbc02,
--0x6300, 0x49ff, 0x0b01, 0x7001, 0x6f00, 0xe2ff, 0x72fe, 0x84fd, 0x7dff, 0xcc00, 0x7300, 0x7c00, 0x5e00, 0xf1ff, 0xa200, 0x2101,
--0xd4ff, 0x46ff, 0x5eff, 0x82ff, 0x4800, 0x7d00, 0xd2ff, 0x71ff, 0xe3ff, 0x1b00, 0x7b00, 0x5c00, 0xc4ff, 0x84ff, 0x76ff, 0xe5ff,
--0x2b00, 0x3500, 0x1500, 0xe2ff, 0x99ff, 0x73ff, 0x9bff, 0xc7ff, 0xc8ff, 0x0000, 0x2d00, 0x4100, 0x3400, 0x2600, 0xf1ff, 0xd6ff,
--0x0900, 0x1300, 0xe0ff, 0x5c00, 0xbc00, 0x4700, 0x2500, 0xd5ff, 0x5eff, 0xb5ff, 0x4800, 0x3200, 0x0a00, 0x5bff, 0x91ff, 0x9b00,
--0x7000, 0x6400, 0x0800, 0xa7fd, 0x41fc, 0x8dfe, 0x3c01, 0x0102, 0x4b03, 0x0002, 0x58ff, 0x8b00, 0xc401, 0xad00, 0x5c00, 0x7aff,
--0x8efd, 0x85fe, 0x5600, 0x4000, 0x5700, 0xd200, 0xa700, 0xd400, 0xbb01, 0x7500, 0x1bff, 0x11ff, 0x47ff, 0x0700, 0x7500, 0x3c00,
--0x67ff, 0x05ff, 0x91ff, 0x4300, 0x6700, 0x3300, 0x1200, 0x94ff, 0x8dff, 0x1e00, 0xd6ff, 0x98ff, 0xafff, 0x9bff, 0x55ff, 0x97ff,
--0xaeff, 0x86ff, 0xc1ff, 0x2f00, 0x5200, 0x7100, 0x7600, 0xfdff, 0x9fff, 0xc3ff, 0xe5ff, 0xd9ff, 0x1500, 0x7e00, 0x3c00, 0x8200,
--0x5900, 0x60ff, 0x8cff, 0x1e00, 0x3400, 0x4300, 0x3800, 0x1dff, 0xbffe, 0xd2ff, 0xcf00, 0xff00, 0x5c00, 0x36ff, 0xd4fd, 0x85fc,
--0x18fe, 0xa301, 0x2e02, 0xfc01, 0x9d02, 0xf400, 0x4400, 0xbf01, 0xea00, 0x40ff, 0x83ff, 0x05ff, 0x5afe, 0xc5ff, 0x5100, 0xa4ff,
--0x8f00, 0x8501, 0x2501, 0x2e01, 0xd300, 0x21ff, 0xe0fe, 0xd1ff, 0x0400, 0x5a00, 0xd2ff, 0x62ff, 0xcfff, 0xc0ff, 0xfbff, 0x2b00,
--0xf9ff, 0xd6ff, 0xf7ff, 0xfbff, 0xb7ff, 0xc6ff, 0x2eff, 0x52ff, 0x3900, 0x1500, 0xc2ff, 0xf0ff, 0xc6ff, 0xccff, 0x7f00, 0x9500,
--0x0200, 0x0b00, 0x0000, 0x98ff, 0xa3ff, 0xb9ff, 0xacff, 0x4600, 0x8a00, 0x9300, 0x1300, 0x94ff, 0xd4ff, 0x2a00, 0x1301, 0xce00,
--0x78ff, 0xa7fe, 0xa1fe, 0x76ff, 0xe200, 0xfe00, 0xecff, 0xadff, 0x6fff, 0xe4fd, 0x2afd, 0x51ff, 0x3f01, 0x8c01, 0x9202, 0xac01,
--0xf4ff, 0x0d01, 0x7601, 0x0800, 0xd5ff, 0xafff, 0x9cfe, 0x2dff, 0x2200, 0x85ff, 0xbdff, 0xd500, 0xc000, 0xd300, 0x2701, 0x0700,
--0x12ff, 0xb6ff, 0xf5ff, 0xebff, 0x7900, 0xc7ff, 0x4dff, 0x5c00, 0x9800, 0xf9ff, 0xa4ff, 0xa4ff, 0x6bff, 0xafff, 0x2a00, 0xceff,
--0xc2ff, 0xc6ff, 0xb9ff, 0x3600, 0x5a00, 0xdbff, 0xa1ff, 0xe1ff, 0x1500, 0x3e00, 0x5d00, 0x0400, 0xccff, 0x2000, 0x1900, 0xa7ff,
--0x77ff, 0x9dff, 0xfdff, 0x4a00, 0xcd00, 0x0300, 0x8bff, 0x0000, 0xf0ff, 0xa100, 0xbf00, 0xdaff, 0x04ff, 0x2aff, 0x76ff, 0xe1ff,
--0x8b00, 0x8100, 0x3700, 0x4700, 0x2fff, 0x1ffd, 0xd7fd, 0x6a00, 0x6c01, 0x9301, 0x9c01, 0x5900, 0x3c00, 0x9f01, 0x6201, 0xbfff,
--0x28ff, 0x69ff, 0x63ff, 0xf5ff, 0x0a00, 0x2cff, 0x91ff, 0x9e00, 0x1c01, 0x0d01, 0x7900, 0xa9ff, 0x3aff, 0x2b00, 0x3500, 0xc4ff,
--0xc5ff, 0x77ff, 0xb8ff, 0x9600, 0xaa00, 0xd4ff, 0x97ff, 0xdfff, 0xc3ff, 0x1a00, 0xf9ff, 0x65ff, 0x81ff, 0xa7ff, 0xd0ff, 0x2a00,
--0x0600, 0x0800, 0x2d00, 0xebff, 0x2000, 0x6d00, 0x6a00, 0x5900, 0x5700, 0x0c00, 0x85ff, 0x9bff, 0xe4ff, 0x0400, 0x4000, 0xd7ff,
--0x0f00, 0x1f00, 0xf2ff, 0xb800, 0x6c00, 0xacff, 0x59ff, 0x2eff, 0x5fff, 0x1f00, 0x5200, 0x1f00, 0x2700, 0x3e00, 0xcdfe, 0x09fd,
--0x87fd, 0x2300, 0x0802, 0x8401, 0x2f01, 0x7c00, 0x9c00, 0x0302, 0xb301, 0x8fff, 0xc2fe, 0x25ff, 0x0000, 0x6e00, 0xabff, 0xedfe,
--0x54ff, 0xa800, 0xa301, 0x4801, 0x1900, 0x8eff, 0xf2ff, 0x7000, 0x6c00, 0xc6ff, 0x02ff, 0x34ff, 0x0000, 0x6c00, 0x4f00, 0x55ff,
--0x65ff, 0x3c00, 0x4d00, 0x1d00, 0x81ff, 0x49ff, 0xaaff, 0x2300, 0x1600, 0xaaff, 0x92ff, 0xb7ff, 0x7100, 0x4900, 0xf8ff, 0x4900,
--0x5700, 0x9f00, 0xa100, 0x5b00, 0xb6ff, 0x8bff, 0x0700, 0x3300, 0x3e00, 0xa2ff, 0x99ff, 0x2e00, 0x1200, 0x9500, 0x9200, 0xceff,
--0x99ff, 0xa9ff, 0x77ff, 0x5fff, 0xc7ff, 0x1c00, 0x1b00, 0x5400, 0x9fff, 0xd8fd, 0xe8fc, 0xaefe, 0x7301, 0x8a01, 0xd700, 0x6b00,
--0x6600, 0xfa01, 0x9d02, 0x5e00, 0xddfe, 0x75ff, 0x1f00, 0x8500, 0x6dff, 0x3ffe, 0xc4fe, 0x7200, 0x5401, 0xe600, 0x2900, 0xd8ff,
--0x6900, 0xe800, 0x9400, 0xd8ff, 0x45ff, 0x6aff, 0xedff, 0xf4ff, 0xf3ff, 0x8cff, 0x7aff, 0x1e00, 0x3a00, 0xfcff, 0xc7ff, 0xbbff,
--0xd1ff, 0x1300, 0x1c00, 0xc1ff, 0xbfff, 0xd6ff, 0x1300, 0x5100, 0xf7ff, 0x77ff, 0xe4ff, 0x9000, 0xa400, 0x9a00, 0x5300, 0xacff,
--0xa5ff, 0x3a00, 0x3800, 0x0000, 0xe2ff, 0xe3ff, 0x4300, 0xc400, 0x5e00, 0x90ff, 0xb4ff, 0x3a00, 0xf6ff, 0x8eff, 0x86ff, 0xcbfe,
--0x49ff, 0xe400, 0x7f00, 0x5cff, 0x80fe, 0x61fd, 0x78fe, 0xf601, 0x4001, 0xabff, 0xc500, 0xe000, 0xf201, 0x0c03, 0x7e00, 0x6ffe,
--0xceff, 0x7100, 0xd0ff, 0x6dff, 0x5cfe, 0x4afe, 0x5800, 0x6d01, 0x0e00, 0xc7ff, 0x2e00, 0x2a00, 0xc800, 0xe500, 0x89ff, 0x3cff,
--0x5900, 0x1a00, 0xcfff, 0x0b00, 0x71ff, 0x87ff, 0x7000, 0x3100, 0x95ff, 0xe1ff, 0x0000, 0xe9ff, 0x4700, 0x0300, 0x7aff, 0xf1ff,
--0x3700, 0xc9ff, 0xfcff, 0x0000, 0xd0ff, 0x6800, 0x9500, 0xdfff, 0xfaff, 0xe7ff, 0xe9ff, 0x9600, 0x1700, 0xbbff, 0x0b00, 0x5300,
--0x9000, 0x9c00, 0x1900, 0x97ff, 0xd7ff, 0x6100, 0x2400, 0xbdfe, 0xe0fe, 0xb0ff, 0xb0ff, 0x6400, 0x5500, 0x0dff, 0xdafe, 0x38fe,
--0xe1fd, 0x6200, 0x3801, 0xeaff, 0xe200, 0xf901, 0xd901, 0x4802, 0x8001, 0x25ff, 0xd7ff, 0xfa00, 0x7bff, 0xc8fe, 0xe4fe, 0x76fe,
--0xb4ff, 0xa800, 0xd5ff, 0xa7ff, 0x4d00, 0x6d00, 0x6e00, 0xb600, 0xe3ff, 0xc3ff, 0x6600, 0x1b00, 0xa3ff, 0xc0ff, 0xbaff, 0x90ff,
--0x0a00, 0x1c00, 0x99ff, 0x0900, 0x5000, 0xd6ff, 0x0e00, 0x7400, 0x1f00, 0xf5ff, 0x0d00, 0xc3ff, 0xe6ff, 0x4400, 0xebff, 0x9dff,
--0xdfff, 0x5a00, 0x1c00, 0x80ff, 0xd4ff, 0x1f00, 0x1200, 0x4e00, 0x6f00, 0xd900, 0x7d00, 0x9aff, 0xdbff, 0x4000, 0x2300, 0xd1ff,
--0xa3ff, 0x89ff, 0x74ff, 0xbdff, 0xb5ff, 0xe8ff, 0x4900, 0x0b00, 0xc6ff, 0x5aff, 0x6dfe, 0xc6fe, 0x3400, 0x6700, 0x2300, 0x9500,
--0xa300, 0x2901, 0x0a02, 0xf200, 0x7fff, 0x3800, 0x7e00, 0xedff, 0xb8ff, 0x0fff, 0xeafe, 0xdeff, 0x4500, 0xdcff, 0xcaff, 0x0d00,
--0x3d00, 0x7b00, 0x7c00, 0xffff, 0xf5ff, 0x2600, 0x1500, 0xe2ff, 0xd8ff, 0xc6ff, 0xb8ff, 0xf7ff, 0xf6ff, 0xd4ff, 0xf7ff, 0x1300,
--0xf7ff, 0x0800, 0xf3ff, 0xbbff, 0xb5ff, 0xfcff, 0xcaff, 0xc4ff, 0xfcff, 0xd2ff, 0xfeff, 0x2500, 0x2000, 0x0400, 0x0000, 0x0200,
--0x1000, 0x1e00, 0x1900, 0x2a00, 0x1600, 0x2e00, 0x5500, 0x1b00, 0x1f00, 0x1200, 0x2600, 0x6600, 0x3700, 0xfbff, 0x2200, 0x1300,
--0xffff, 0xfbff, 0xcaff, 0x97ff, 0x9eff, 0x95ff, 0x9aff, 0xceff, 0xa2ff, 0x6fff, 0xabff, 0x0000, 0x2400, 0x0c00, 0xf2ff, 0x0f00,
--0x6100, 0x7500, 0x4200, 0xfeff, 0x1c00, 0x5a00, 0x4a00, 0x2300, 0x0b00, 0x0f00, 0x0900, 0x1900, 0xfcff, 0xe0ff, 0xfdff, 0x1200,
--0x1100, 0x1200, 0x1700, 0x1800, 0x1500, 0x1500, 0x0500, 0xf7ff, 0xf9ff, 0x0800, 0xffff, 0x0300, 0x0000, 0xccff, 0xdaff, 0x0200,
--0xe5ff, 0xa7ff, 0x9cff, 0xb4ff, 0xd0ff, 0xcaff, 0xdbff, 0xc9ff, 0xd3ff, 0x0a00, 0x0500, 0x0600, 0x1500, 0x1400, 0x2d00, 0x5900,
--0x3000, 0x0900, 0x1300, 0x0800, 0x2000, 0x3600, 0x0500, 0x0000, 0xf6ff, 0x0700, 0x1900, 0xf5ff, 0x1000, 0x1300, 0xcdff, 0xbdff,
--0xd7ff, 0xe0ff, 0xd6ff, 0xe6ff, 0xbfff, 0xdfff, 0x3500, 0x1700, 0x0000, 0x2900, 0x4c00, 0x4600, 0x4500, 0x4a00, 0x2100, 0x3c00,
--0x4000, 0x0a00, 0xeeff, 0xedff, 0xe6ff, 0xe1ff, 0xe0ff, 0xeeff, 0x0100, 0x0a00, 0x1300, 0x0900, 0x0500, 0x0c00, 0x0600, 0xf2ff,
--0xecff, 0xe1ff, 0xe3ff, 0xe2ff, 0xe6ff, 0xe6ff, 0xf8ff, 0x0500, 0x0200, 0x0800, 0xe2ff, 0xdfff, 0x0000, 0x0300, 0xffff, 0x0000,
--0x1200, 0x1300, 0x0600, 0x0c00, 0xfcff, 0x1200, 0x1000, 0xfcff, 0x0800, 0x0900, 0xfbff, 0xf6ff, 0xfeff, 0xfbff, 0xfeff, 0xf1ff,
--0xfbff, 0x0400, 0x0600, 0x1700, 0x2500, 0x0e00, 0xdbff, 0xb8ff, 0xc9ff, 0xcfff, 0xb2ff, 0xbeff, 0xcdff, 0xc7ff, 0xe2ff, 0x0500,
--0x2400, 0x1600, 0x2300, 0x3900, 0x4c00, 0x5400, 0x4200, 0x3a00, 0x3100, 0x3e00, 0x2e00, 0x0800, 0xf6ff, 0xf2ff, 0xf7ff, 0xfaff,
--0xf7ff, 0xf3ff, 0x0600, 0x0f00, 0x0300, 0xffff, 0xf9ff, 0xe6ff, 0x0a00, 0x1f00, 0x0a00, 0x0300, 0xf8ff, 0xecff, 0xf2ff, 0xfdff,
--0xccff, 0xbbff, 0xe5ff, 0xe6ff, 0xb3ff, 0xc7ff, 0x0000, 0xfaff, 0xf2ff, 0x0d00, 0x1000, 0x0e00, 0x2300, 0x1c00, 0x0f00, 0x1c00,
--0x1700, 0x0b00, 0x1000, 0x0c00, 0x0400, 0x0100, 0x0200, 0x0300, 0x0000, 0xfdff, 0x0300, 0x0500, 0x0700, 0x0a00, 0x0600, 0x0400,
--0x0100, 0xf5ff, 0xecff, 0xf2ff, 0xf5ff, 0xecff, 0x0200, 0xfdff, 0xe0ff, 0x0800, 0x1b00, 0x0300, 0x0000, 0x0700, 0x0500, 0x0400,
--0x0100, 0xf0ff, 0xefff, 0x0100, 0xfcff, 0xfaff, 0x0700, 0x0600, 0x0e00, 0x1500, 0x0800, 0x0500, 0x0d00, 0x1100, 0x0800, 0x0a00,
--0x0600, 0xf8ff, 0xfdff, 0x0400, 0x2200, 0x2800, 0x1500, 0x0f00, 0x1800, 0x0e00, 0xfcff, 0xf9ff, 0xefff, 0xe5ff, 0xc5ff, 0xb4ff,
--0xc3ff, 0xcfff, 0xcbff, 0xcdff, 0xe4ff, 0xf7ff, 0x0300, 0x1300, 0xffff, 0xf8ff, 0x0e00, 0x0900, 0xfeff, 0xfeff, 0xfeff, 0xfbff,
--0x0300, 0x0a00, 0x0a00, 0x0f00, 0x1100, 0x0d00, 0x0800, 0x0e00, 0x1600, 0x0d00, 0x0900, 0x0900, 0x0100, 0x0200, 0x0000, 0xebff,
--0xfbff, 0x0200, 0xdeff, 0xf8ff, 0x0c00, 0xf8ff, 0xefff, 0x0100, 0x0000, 0x0200, 0x0500, 0x0f00, 0x1900, 0x2400, 0x2d00, 0x1b00,
--0x1500, 0x1b00, 0x1e00, 0x1200, 0x0100, 0x0000, 0xfeff, 0x0200, 0x0400, 0xfeff, 0xfaff, 0x0200, 0x0b00, 0x1d00, 0x2e00, 0x0100,
--0xf7ff, 0x0d00, 0x0300, 0xf7ff, 0xfbff, 0xf5ff, 0xeaff, 0xe8ff, 0xc9ff, 0xccff, 0xe2ff, 0xe2ff, 0xdeff, 0xe5ff, 0xf0ff, 0xfaff,
--0x0900, 0x0700, 0xe8ff, 0xedff, 0x0300, 0xfdff, 0xf3ff, 0xf8ff, 0x0e00, 0x0b00, 0x1800, 0x1200, 0x0100, 0x0f00, 0x1300, 0x1100,
--0x0e00, 0x1700, 0x1500, 0x0800, 0x0500, 0xf1ff, 0xe5ff, 0xe3ff, 0xd9ff, 0xceff, 0xc6ff, 0xbeff, 0xe5ff, 0xf2ff, 0xebff, 0xf1ff,
--0x0200, 0xffff, 0x0900, 0x1000, 0x1000, 0x1300, 0x2a00, 0x3700, 0x2c00, 0x3000, 0x3000, 0x2300, 0x2100, 0x2500, 0x1d00, 0x1700,
--0x1b00, 0x1800, 0x1800, 0x1900, 0x0f00, 0x0a00, 0x1300, 0x1e00, 0x1600, 0x0f00, 0xffff, 0x0200, 0xf2ff, 0xe3ff, 0xdfff, 0xdbff,
--0xd5ff, 0xc2ff, 0xb8ff, 0xb3ff, 0xbaff, 0xc4ff, 0xc9ff, 0xd1ff, 0xe4ff, 0xfcff, 0xfbff, 0xfeff, 0x0c00, 0x0c00, 0x1300, 0x2200,
--0x2300, 0x2100, 0x2b00, 0x3700, 0x2c00, 0x2d00, 0x2d00, 0x2300, 0x2800, 0x2300, 0x1300, 0x1800, 0x1000, 0xedff, 0xe1ff, 0xd6ff,
--0xbcff, 0xb8ff, 0xb3ff, 0x98ff, 0x9bff, 0xb7ff, 0xcfff, 0xd6ff, 0xe5ff, 0xecff, 0xf5ff, 0x0000, 0x0600, 0x1600, 0x1100, 0x1a00,
--0x3100, 0x3700, 0x3800, 0x3700, 0x3b00, 0x3900, 0x3700, 0x3200, 0x3400, 0x3600, 0x2e00, 0x2800, 0x2700, 0x1e00, 0x1800, 0x1800,
--0x1000, 0x1400, 0x0900, 0xfcff, 0xf7ff, 0xf1ff, 0xe4ff, 0xd7ff, 0xd7ff, 0xd2ff, 0xc1ff, 0xc1ff, 0xc8ff, 0xc3ff, 0xc5ff, 0xd6ff,
--0xddff, 0xdfff, 0xf0ff, 0x0000, 0x0300, 0x0300, 0x0900, 0x0a00, 0x1700, 0x2200, 0x1700, 0x2000, 0x3100, 0x3200, 0x3300, 0x2e00,
--0x2800, 0x1d00, 0x2600, 0x2200, 0x1800, 0x1300, 0x0200, 0xf0ff, 0xd3ff, 0xc8ff, 0xc0ff, 0xbbff, 0xbbff, 0xb4ff, 0xaaff, 0xbaff,
--0xd7ff, 0xe9ff, 0xf2ff, 0xfcff, 0x0500, 0x1000, 0x1900, 0x1a00, 0x2100, 0x1b00, 0x1d00, 0x2a00, 0x1d00, 0x1000, 0x0b00, 0x0c00,
--0x0b00, 0x0600, 0x0100, 0x0400, 0x0900, 0x0900, 0x0600, 0x0500, 0x0800, 0x0f00, 0x1100, 0xfcff, 0x0900, 0x0c00, 0x0400, 0x0500,
--0x0000, 0xf8ff, 0xf3ff, 0xf7ff, 0xefff, 0xe7ff, 0xeeff, 0xf1ff, 0xf2ff, 0xf5ff, 0xfbff, 0xfdff, 0xffff, 0x0000, 0x0100, 0x0000,
--0xfeff, 0xffff, 0x0000, 0x0000, 0x0100, 0xffff, 0x0000, 0x0400, 0x0500, 0x0200, 0xffff, 0x0000, 0xfeff, 0xfcff, 0xfbff, 0xf7ff,
--0xf3ff, 0xf1ff, 0xf6ff, 0xf1ff, 0xf4ff, 0xf7ff, 0xfaff, 0xfeff, 0x0700, 0x0e00, 0x1300, 0x1e00, 0x2000, 0x2200, 0x2000, 0x2200,
--0x1d00, 0x1c00, 0x1d00, 0x1b00, 0x1600, 0x1b00, 0x1900, 0x1200, 0x0d00, 0x0a00, 0x0500, 0x0000, 0xebff, 0xddff, 0xe1ff, 0xe0ff,
--0xddff, 0xdcff, 0xdeff, 0xdeff, 0xe6ff, 0xebff, 0xeeff, 0xf4ff, 0xffff, 0x0100, 0x0a00, 0x0b00, 0x0100, 0x0600, 0x1600, 0x0e00,
--0x0a00, 0x1100, 0x1500, 0x1000, 0x1000, 0x0d00, 0x0b00, 0x0900, 0x0500, 0xfbff, 0xffff, 0x0200, 0x0000, 0x0100, 0x0100, 0x0200,
--0xfbff, 0x0000, 0xfaff, 0xf4ff, 0xedff, 0xedff, 0xe9ff, 0xe4ff, 0xe2ff, 0xdeff, 0xdbff, 0xe0ff, 0xe0ff, 0xe3ff, 0xe9ff, 0xf3ff,
--0xf7ff, 0x0700, 0x0b00, 0x0000, 0x0f00, 0x1b00, 0x1700, 0x1600, 0x2100, 0x2600, 0x2700, 0x2e00, 0x2600, 0x2300, 0x2000, 0x1800,
--0x0e00, 0x0b00, 0x0200, 0x0300, 0xf3ff, 0xe2ff, 0xe0ff, 0xe0ff, 0xe1ff, 0xdeff, 0xe3ff, 0xe4ff, 0xf2ff, 0xf1ff, 0xfcff, 0xf9ff,
--0xf8ff, 0x0000, 0x0300, 0x0900, 0x0a00, 0x0e00, 0x0300, 0x0600, 0x0400, 0x0400, 0x0100, 0x0200, 0x0000, 0x0000, 0xffff, 0xfcff,
--0x0100, 0x0100, 0x0300, 0x0400, 0x0800, 0x0500, 0x0500, 0x0000, 0xfaff, 0xffff, 0x0100, 0xfcff, 0xfeff, 0x0000, 0xfcff, 0xf6ff,
--0xf5ff, 0xf3ff, 0xf3ff, 0xf0ff, 0xf7ff, 0xfcff, 0x0100, 0x0e00, 0x1800, 0x1900, 0x1d00, 0x2800, 0x2400, 0x2000, 0x2400, 0x2000,
--0x1400, 0x0d00, 0x0000, 0xf9ff, 0xeeff, 0xe7ff, 0xe6ff, 0xe3ff, 0xe0ff, 0xdbff, 0xe6ff, 0xeeff, 0xf4ff, 0xfdff, 0xfeff, 0xffff,
--0x0000, 0x0400, 0x0000, 0x0500, 0x0500, 0x0900, 0x0500, 0x0600, 0x0c00, 0x0d00, 0x1200, 0x0c00, 0x0d00, 0x0a00, 0x0d00, 0x0b00,
--0x0500, 0x0100, 0x0100, 0xfeff, 0xfdff, 0xfaff, 0xfaff, 0xfaff, 0xfbff, 0xf9ff, 0xf8ff, 0xf8ff, 0xf7ff, 0xf8ff, 0xf6ff, 0xf3ff,
--0xf8ff, 0xf6ff, 0xf4ff, 0xf2ff, 0xf1ff, 0xefff, 0xf5ff, 0xf3ff, 0xf6ff, 0xfcff, 0xfdff, 0xfcff, 0xffff, 0x0100, 0x0000, 0x0000,
--0x0400, 0x1000, 0x1000, 0x1300, 0x1700, 0x1e00, 0x1400, 0x1200, 0x1400, 0x0e00, 0x1400, 0x1100, 0x0600, 0xfbff, 0xf3ff, 0xe9ff,
--0xebff, 0xe8ff, 0xe2ff, 0xe7ff, 0xebff, 0xf1ff, 0xf5ff, 0xfeff, 0x0100, 0xffff, 0xfaff, 0xfdff, 0xfeff, 0xfeff, 0xfeff, 0xffff,
--0x0900, 0x0c00, 0x1100, 0x1400, 0x1100, 0x1200, 0x0d00, 0x0b00, 0x0f00, 0x0f00, 0x0a00, 0x0600, 0xfeff, 0x0000, 0xfeff, 0xf9ff,
--0xfcff, 0xfaff, 0xf8ff, 0xfbff, 0xfeff, 0xf9ff, 0xfcff, 0xf7ff, 0xfbff, 0xf5ff, 0xfcff, 0x0900, 0x0000, 0x0a00, 0x0600, 0xfeff,
--0xfbff, 0x1700, 0x1000, 0x0800, 0x1100, 0x0800, 0xf2ff, 0x0400, 0x0300, 0x0000, 0x1d00, 0x1b00, 0x0b00, 0xf1ff, 0xd8ff, 0xddff,
--0xeeff, 0xdfff, 0xd0ff, 0xf0ff, 0xf3ff, 0xf4ff, 0x0300, 0x1000, 0xf9ff, 0xf3ff, 0x1000, 0x1e00, 0x0e00, 0xfdff, 0xfaff, 0xfdff,
--0x1100, 0xfeff, 0x1d00, 0x3100, 0x0300, 0xf8ff, 0x0c00, 0x1700, 0x1300, 0x0200, 0xfdff, 0x0900, 0x0800, 0xf8ff, 0xf9ff, 0xfaff,
--0xf3ff, 0x0400, 0xfcff, 0xf5ff, 0x0100, 0xfaff, 0xe3ff, 0xe4ff, 0xf8ff, 0x0000, 0x0300, 0xf1ff, 0xe1ff, 0x0000, 0xf7ff, 0xf4ff,
--0xefff, 0xdfff, 0x0900, 0x1600, 0xe0ff, 0xf5ff, 0x1500, 0x0900, 0xfdff, 0x0300, 0x1200, 0x1900, 0xffff, 0x0e00, 0x3e00, 0x3400,
--0xe3ff, 0xfbff, 0x2c00, 0xfdff, 0xe5ff, 0x0300, 0x0800, 0x0200, 0xe5ff, 0xe0ff, 0x0900, 0x1500, 0xdeff, 0xe1ff, 0xf8ff, 0xe0ff,
--0xddff, 0x1500, 0x1f00, 0xecff, 0x0c00, 0x6aff, 0x0700, 0x2600, 0xecfe, 0xac01, 0x8500, 0xa9fe, 0xa200, 0x6700, 0xb8ff, 0x8f00,
--0xf9ff, 0xa1ff, 0xd100, 0xc1fe, 0x8900, 0x4a01, 0x6dfe, 0xf9ff, 0x1301, 0xb1ff, 0xbaff, 0xac00, 0x1401, 0x7bfe, 0x16ff, 0x8e01,
--0x92ff, 0x03ff, 0x7202, 0xedff, 0x58fe, 0x6b00, 0x0300, 0xc6ff, 0x5600, 0xadff, 0xd5ff, 0xe800, 0x85ff, 0x16ff, 0xd000, 0x2600,
--0xacff, 0x3f00, 0x47fe, 0x6000, 0x3b02, 0xc1fe, 0x56fe, 0x3001, 0xc2ff, 0xfffe, 0xf4ff, 0x2400, 0x5000, 0x1f00, 0x38ff, 0x0200,
--0x6800, 0xc800, 0x45ff, 0xb1ff, 0xeb00, 0x0100, 0xaaff, 0x0f00, 0x7f00, 0x2400, 0x8d00, 0xa5ff, 0x0600, 0xa501, 0xa5ff, 0x67ff,
--0xb700, 0x0e00, 0xa6ff, 0xe1ff, 0x0c00, 0xf4ff, 0xf1ff, 0x29ff, 0x0cff, 0xb1ff, 0x2fff, 0xfffe, 0xe0ff, 0x1900, 0xe1ff, 0x1600,
--0x5b00, 0x6200, 0x7d00, 0x1f00, 0x1300, 0x6100, 0x4500, 0xf3ff, 0xb400, 0x7800, 0x5d00, 0x1600, 0x4500, 0x4700, 0x1200, 0x0a00,
--0xd5ff, 0x5a00, 0x3400, 0xf4ff, 0x3600, 0xbeff, 0xe1ff, 0x0300, 0xb6ff, 0xa5ff, 0xc2ff, 0x98ff, 0xc5ff, 0x2100, 0xdbff, 0x2d00,
--0x1400, 0xd4ff, 0x2e00, 0x0a00, 0xfaff, 0x0a00, 0x0300, 0xd9ff, 0xc3ff, 0x6600, 0x1d00, 0x80ff, 0x0700, 0x2300, 0x0eff, 0xacff,
--0x0500, 0xacff, 0x1400, 0x4600, 0x5000, 0x6400, 0xad00, 0x4900, 0x2c00, 0x7900, 0x3000, 0xc7ff, 0xbbff, 0x8cff, 0xa3ff, 0x5800,
--0xcfff, 0xddfe, 0x8fff, 0xc3ff, 0x78fe, 0x51ff, 0xceff, 0x62ff, 0x2b00, 0xbd00, 0x7300, 0xe000, 0x7901, 0x8900, 0x6e00, 0xf000,
--0x5100, 0xd5ff, 0xcfff, 0xacff, 0xe1ff, 0xc400, 0x71ff, 0xbffd, 0xacff, 0xfdff, 0x5dfe, 0x43ff, 0xa000, 0x9b00, 0xab00, 0x1f01,
--0x0b01, 0x7e01, 0x1f01, 0xddff, 0xfcff, 0x3200, 0x3fff, 0x16ff, 0x1500, 0xc7ff, 0xddfe, 0x64ff, 0xe6fe, 0x4efe, 0x26ff, 0x4dff,
--0x30ff, 0x2800, 0x2401, 0xe300, 0x6301, 0xdf01, 0xa801, 0xb001, 0x5701, 0xc500, 0x8100, 0x3600, 0xa7ff, 0xd6ff, 0x6100, 0x0eff,
--0x82fe, 0x9eff, 0xa8ff, 0x03ff, 0x97ff, 0x7300, 0x8200, 0x6600, 0x6000, 0x6700, 0x7c00, 0xdeff, 0x2fff, 0x57ff, 0x83ff, 0x26ff,
--0xf3fe, 0x37ff, 0x49ff, 0xe6fe, 0x04ff, 0x66ff, 0x8dff, 0xa6ff, 0x0100, 0x8300, 0xbc00, 0xf200, 0x2501, 0x6301, 0x6601, 0x2b01,
--0xed00, 0xbe00, 0x6400, 0x2400, 0x2f00, 0x0d00, 0xe0ff, 0xe5ff, 0xbeff, 0xc4ff, 0x0e00, 0x0600, 0xebff, 0xfbff, 0xd1ff, 0xa5ff,
--0x7eff, 0x48ff, 0x2dff, 0x35ff, 0x19ff, 0x62ff, 0x30ff, 0x40ff, 0xbfff, 0x6fff, 0x7eff, 0x0600, 0xe4ff, 0xbaff, 0x4000, 0xae00,
--0x8f00, 0x8500, 0xab00, 0xd500, 0xa900, 0x5800, 0x4d00, 0x4a00, 0x1f00, 0xe3ff, 0xd5ff, 0x0500, 0x0e00, 0x5eff, 0xbfff, 0x9500 };
-Index: codecs/speex_slin_ex.h
-===================================================================
---- a/codecs/speex_slin_ex.h (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/speex_slin_ex.h (.../team/group/issue14292) (revision 178988)
-@@ -1,16 +0,0 @@
--/*! \file
-- * \brief Random Data data
-- *
-- * Source: speex.raw
-- *
-- * Copyright (C) 1999-2005, Digium Inc.
-- *
-- * Distributed under the terms of the GNU General Public License
-- *
-- */
--
--static unsigned char speex_slin_ex[] = {
--0x2e, 0x8e, 0x0f, 0x9a, 0x20, 0000, 0x01, 0x7f, 0xff, 0xff,
--0xff, 0xff, 0xff, 0x91, 0000, 0xbf, 0xff, 0xff, 0xff, 0xff,
--0xff, 0xdc, 0x80, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
--0x98, 0x7f, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xf7, 0x80 };
-Index: codecs/lpc10/chanwr.c
-===================================================================
---- a/codecs/lpc10/chanwr.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/lpc10/chanwr.c (.../team/group/issue14292) (revision 178988)
-@@ -29,6 +29,7 @@
- -lf2c -lm (in that order)
- */
-
-+#include <stdlib.h>
- #include "f2c.h"
-
- /* *********************************************************************** */
-@@ -228,5 +229,5 @@
- /* Subroutine */ int chanrd_(integer *order, integer *ipitv, integer *irms,
- integer *irc, integer *ibits)
- {
-- return chanwr_0_(1, order, ipitv, irms, irc, ibits, 0);
-+ return chanwr_0_(1, order, ipitv, irms, irc, ibits, NULL);
- }
-Index: codecs/codec_ulaw.c
-===================================================================
---- a/codecs/codec_ulaw.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_ulaw.c (.../team/group/issue14292) (revision 178988)
-@@ -36,10 +36,9 @@
- #define BUFFER_SAMPLES 8096 /* size for the translation buffers */
-
- /* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_ulaw.h"
-
--#include "slin_ulaw_ex.h"
--#include "ulaw_slin_ex.h"
--
- /*! \brief convert and store samples in outbuf */
- static int ulawtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
- {
-@@ -73,41 +72,7 @@
- return 0;
- }
-
--/*! * \brief ulawToLin_Sample */
--static struct ast_frame *ulawtolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_ULAW;
-- f.datalen = sizeof(ulaw_slin_ex);
-- f.samples = sizeof(ulaw_slin_ex);
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = ulaw_slin_ex;
-- return &f;
--}
--
- /*!
-- * \brief LinToulaw_Sample
-- */
--
--static struct ast_frame *lintoulaw_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_ulaw_ex);
-- /* Assume 8000 Hz */
-- f.samples = sizeof(slin_ulaw_ex) / 2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_ulaw_ex;
-- return &f;
--}
--
--/*!
- * \brief The complete translator for ulawToLin.
- */
-
-@@ -116,7 +81,7 @@
- .srcfmt = AST_FORMAT_ULAW,
- .dstfmt = AST_FORMAT_SLINEAR,
- .framein = ulawtolin_framein,
-- .sample = ulawtolin_sample,
-+ .sample = ulaw_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
- .plc_samples = 160,
-@@ -131,7 +96,7 @@
- .srcfmt = AST_FORMAT_SLINEAR,
- .dstfmt = AST_FORMAT_ULAW,
- .framein = lintoulaw_framein,
-- .sample = lintoulaw_sample,
-+ .sample = slin8_sample,
- .buf_size = BUFFER_SAMPLES,
- .buffer_samples = BUFFER_SAMPLES,
- };
-@@ -141,10 +106,8 @@
- struct ast_variable *var;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- ulawtolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/codec_resample.c
-===================================================================
---- a/codecs/codec_resample.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_resample.c (.../team/group/issue14292) (revision 178988)
-@@ -49,7 +49,7 @@
- #include "asterisk/module.h"
- #include "asterisk/translate.h"
-
--#include "slin_resample_ex.h"
-+#include "asterisk/slin.h"
-
- #define RESAMPLER_QUALITY 1
-
-@@ -69,9 +69,9 @@
- {
- struct slin16_to_slin8_pvt *resamp_pvt = pvt->pvt;
-
-- resamp_pvt->resample_factor = 0.5;
-+ resamp_pvt->resample_factor = 8000.0 / 16000.0;
-
-- if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, 0.5, 0.5)))
-+ if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
- return -1;
-
- return 0;
-@@ -81,9 +81,9 @@
- {
- struct slin8_to_slin16_pvt *resamp_pvt = pvt->pvt;
-
-- resamp_pvt->resample_factor = 2.0;
-+ resamp_pvt->resample_factor = 16000.0 / 8000.0;
-
-- if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, 2.0, 2.0)))
-+ if (!(resamp_pvt->resampler = resample_open(RESAMPLER_QUALITY, resamp_pvt->resample_factor, resamp_pvt->resample_factor)))
- return -1;
-
- return 0;
-@@ -168,34 +168,6 @@
- return resample_frame(pvt, resampler, resample_factor, f);
- }
-
--static struct ast_frame *slin16_to_slin8_sample(void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_SLINEAR16,
-- .datalen = sizeof(slin16_slin8_ex),
-- .samples = ARRAY_LEN(slin16_slin8_ex),
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = slin16_slin8_ex,
-- };
--
-- return &f;
--}
--
--static struct ast_frame *slin8_to_slin16_sample(void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_SLINEAR,
-- .datalen = sizeof(slin8_slin16_ex),
-- .samples = ARRAY_LEN(slin8_slin16_ex),
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = slin8_slin16_ex,
-- };
--
-- return &f;
--}
--
- static struct ast_translator slin16_to_slin8 = {
- .name = "slin16_to_slin8",
- .srcfmt = AST_FORMAT_SLINEAR16,
-@@ -203,7 +175,7 @@
- .newpvt = slin16_to_slin8_new,
- .destroy = slin16_to_slin8_destroy,
- .framein = slin16_to_slin8_framein,
-- .sample = slin16_to_slin8_sample,
-+ .sample = slin16_sample,
- .desc_size = sizeof(struct slin16_to_slin8_pvt),
- .buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
- .buf_size = OUTBUF_SIZE,
-@@ -216,7 +188,7 @@
- .newpvt = slin8_to_slin16_new,
- .destroy = slin8_to_slin16_destroy,
- .framein = slin8_to_slin16_framein,
-- .sample = slin8_to_slin16_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct slin8_to_slin16_pvt),
- .buffer_samples = (OUTBUF_SIZE / sizeof(int16_t)),
- .buf_size = OUTBUF_SIZE,
-Index: codecs/codec_ilbc.c
-===================================================================
---- a/codecs/codec_ilbc.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_ilbc.c (.../team/group/issue14292) (revision 178988)
-@@ -40,10 +40,6 @@
- #include "ilbc/iLBC_encode.h"
- #include "ilbc/iLBC_decode.h"
-
--/* Sample frame data */
--#include "slin_ilbc_ex.h"
--#include "ilbc_slin_ex.h"
--
- #define USE_ILBC_ENHANCER 0
- #define ILBC_MS 30
- /* #define ILBC_MS 20 */
-@@ -52,6 +48,10 @@
- #define ILBC_SAMPLES 240 /* 30ms at 8000 hz */
- #define BUFFER_SAMPLES 8000
-
-+/* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_ilbc.h"
-+
- struct ilbc_coder_pvt {
- iLBC_Enc_Inst_t enc;
- iLBC_Dec_Inst_t dec;
-@@ -77,35 +77,6 @@
- return 0;
- }
-
--static struct ast_frame *lintoilbc_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_ilbc_ex);
-- f.samples = sizeof(slin_ilbc_ex)/2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_ilbc_ex;
-- return &f;
--}
--
--static struct ast_frame *ilbctolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_ILBC;
-- f.datalen = sizeof(ilbc_slin_ex);
-- /* All frames are 30 ms long */
-- f.samples = ILBC_SAMPLES;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = ilbc_slin_ex;
-- return &f;
--}
--
- /*! \brief decode a frame and store in outbuf */
- static int ilbctolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
- {
-@@ -194,7 +165,7 @@
- .dstfmt = AST_FORMAT_SLINEAR,
- .newpvt = ilbctolin_new,
- .framein = ilbctolin_framein,
-- .sample = ilbctolin_sample,
-+ .sample = ilbc_sample,
- .desc_size = sizeof(struct ilbc_coder_pvt),
- .buf_size = BUFFER_SAMPLES * 2,
- .native_plc = 1,
-@@ -207,7 +178,7 @@
- .newpvt = lintoilbc_new,
- .framein = lintoilbc_framein,
- .frameout = lintoilbc_frameout,
-- .sample = lintoilbc_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct ilbc_coder_pvt),
- .buf_size = (BUFFER_SAMPLES * ILBC_FRAME_LEN + ILBC_SAMPLES - 1) / ILBC_SAMPLES,
- };
-Index: codecs/codec_dahdi.c
-===================================================================
---- a/codecs/codec_dahdi.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_dahdi.c (.../team/group/issue14292) (revision 178988)
-@@ -38,7 +38,7 @@
- #include <netinet/in.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
--
-+#include <sys/poll.h>
- #include <dahdi/user.h>
-
- #include "asterisk/lock.h"
-@@ -49,9 +49,13 @@
- #include "asterisk/channel.h"
- #include "asterisk/utils.h"
- #include "asterisk/linkedlists.h"
-+#include "asterisk/ulaw.h"
-
--#define BUFFER_SAMPLES 8000
-+#define BUFFER_SIZE 8000
-
-+#define G723_SAMPLES 240
-+#define G729_SAMPLES 160
-+
- static unsigned int global_useplc = 0;
-
- static struct channel_usage {
-@@ -79,16 +83,53 @@
-
- static AST_LIST_HEAD_STATIC(translators, translator);
-
--struct pvt {
-+struct codec_dahdi_pvt {
- int fd;
-- int fake;
--#ifdef DEBUG_TRANSCODE
-- int totalms;
-- int lasttotalms;
--#endif
- struct dahdi_transcoder_formats fmts;
-+ unsigned int softslin:1;
-+ unsigned int fake:2;
-+ uint16_t required_samples;
-+ uint16_t samples_in_buffer;
-+ uint8_t ulaw_buffer[1024];
- };
-
-+/* Only used by a decoder */
-+static int ulawtolin(struct ast_trans_pvt *pvt)
-+{
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-+ int i = dahdip->required_samples;
-+ uint8_t *src = &dahdip->ulaw_buffer[0];
-+ int16_t *dst = pvt->outbuf.i16 + pvt->datalen;
-+
-+ /* convert and copy in outbuf */
-+ while (i--) {
-+ *dst++ = AST_MULAW(*src++);
-+ }
-+
-+ return 0;
-+}
-+
-+/* Only used by an encoder. */
-+static int lintoulaw(struct ast_trans_pvt *pvt, struct ast_frame *f)
-+{
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-+ int i = f->samples;
-+ uint8_t *dst = &dahdip->ulaw_buffer[dahdip->samples_in_buffer];
-+ int16_t *src = f->data.ptr;
-+
-+ if (dahdip->samples_in_buffer + i > sizeof(dahdip->ulaw_buffer)) {
-+ ast_log(LOG_ERROR, "Out of buffer space!\n");
-+ return -i;
-+ }
-+
-+ while (i--) {
-+ *dst++ = AST_LIN2MU(*src++);
-+ }
-+
-+ dahdip->samples_in_buffer += f->samples;
-+ return 0;
-+}
-+
- static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct channel_usage copy;
-@@ -117,89 +158,211 @@
- return CLI_SUCCESS;
- }
-
--static int dahdi_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
-+static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buffer, const ssize_t count)
- {
- int res;
-- struct pvt *dahdip = pvt->pvt;
--
-- if (f->subclass) {
-- /* Give the frame to the hardware transcoder... */
-- res = write(dahdip->fd, f->data.ptr, f->datalen);
-+ struct pollfd p = {0};
-+ if (!count) return;
-+ res = write(dahdip->fd, buffer, count);
-+ if (option_verbose > 10) {
- if (-1 == res) {
-- ast_log(LOG_ERROR, "Failed to write to /dev/dahdi/transcode: %s\n", strerror(errno));
-+ ast_log(LOG_ERROR, "Failed to write to transcoder: %s\n", strerror(errno));
- }
-- if (f->datalen != res) {
-- ast_log(LOG_ERROR, "Requested write of %d bytes, but only wrote %d bytes.\n", f->datalen, res);
-+ if (count != res) {
-+ ast_log(LOG_ERROR, "Requested write of %zd bytes, but only wrote %d bytes.\n", count, res);
- }
-- res = -1;
-- pvt->samples += f->samples;
-- } else {
-- /* Fake a return frame for calculation purposes */
-+ }
-+ p.fd = dahdip->fd;
-+ p.events = POLLOUT;
-+ res = poll(&p, 1, 50);
-+}
-+
-+static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
-+{
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-+
-+ if (!f->subclass) {
-+ /* We're just faking a return for calculation purposes. */
- dahdip->fake = 2;
- pvt->samples = f->samples;
-- res = 0;
-+ return 0;
- }
-- return res;
-+
-+ /* Buffer up the packets and send them to the hardware if we
-+ * have enough samples set up. */
-+ if (dahdip->softslin) {
-+ if (lintoulaw(pvt, f)) {
-+ return -1;
-+ }
-+ } else {
-+ /* NOTE: If softslin support is not needed, and the sample
-+ * size is equal to the required sample size, we wouldn't
-+ * need this copy operation. But at the time this was
-+ * written, only softslin is supported. */
-+ if (dahdip->samples_in_buffer + f->samples > sizeof(dahdip->ulaw_buffer)) {
-+ ast_log(LOG_ERROR, "Out of buffer space.\n");
-+ return -1;
-+ }
-+ memcpy(&dahdip->ulaw_buffer[dahdip->samples_in_buffer], f->data.ptr, f->samples);
-+ dahdip->samples_in_buffer += f->samples;
-+ }
-+
-+ while (dahdip->samples_in_buffer > dahdip->required_samples) {
-+ dahdi_write_frame(dahdip, dahdip->ulaw_buffer, dahdip->required_samples);
-+ dahdip->samples_in_buffer -= dahdip->required_samples;
-+ if (dahdip->samples_in_buffer) {
-+ /* Shift any remaining bytes down. */
-+ memmove(dahdip->ulaw_buffer, &dahdip->ulaw_buffer[dahdip->required_samples],
-+ dahdip->samples_in_buffer);
-+ }
-+ }
-+ pvt->samples += f->samples;
-+ pvt->datalen = 0;
-+ return -1;
- }
-
--static struct ast_frame *dahdi_frameout(struct ast_trans_pvt *pvt)
-+static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt)
- {
-- struct pvt *dahdip = pvt->pvt;
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-+ int res;
-
-- if (0 == dahdip->fake) {
-- int res;
-- /* Let's check to see if there is a new frame for us.... */
-- res = read(dahdip->fd, pvt->outbuf.uc + pvt->datalen, pvt->t->buf_size - pvt->datalen);
-- if (-1 == res) {
-- if (EWOULDBLOCK == errno) {
-- /* Nothing waiting... */
-- return NULL;
-- } else {
-- ast_log(LOG_ERROR, "Failed to read from /dev/dahdi/transcode: %s\n", strerror(errno));
-- return NULL;
-- }
-+ if (2 == dahdip->fake) {
-+ dahdip->fake = 1;
-+ pvt->f.frametype = AST_FRAME_VOICE;
-+ pvt->f.subclass = 0;
-+ pvt->f.samples = dahdip->required_samples;
-+ pvt->f.data.ptr = NULL;
-+ pvt->f.offset = 0;
-+ pvt->f.datalen = 0;
-+ pvt->f.mallocd = 0;
-+ ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
-+ pvt->samples = 0;
-+
-+ return &pvt->f;
-+
-+ } else if (1 == dahdip->fake) {
-+ dahdip->fake = 0;
-+ return NULL;
-+ }
-+
-+ res = read(dahdip->fd, pvt->outbuf.c + pvt->datalen, pvt->t->buf_size - pvt->datalen);
-+ if (-1 == res) {
-+ if (EWOULDBLOCK == errno) {
-+ /* Nothing waiting... */
-+ return NULL;
- } else {
-- pvt->f.samples = res;
-- pvt->f.datalen = res;
-- pvt->datalen = 0;
-- pvt->f.frametype = AST_FRAME_VOICE;
-- pvt->f.subclass = 1 << (pvt->t->dstfmt);
-- pvt->f.mallocd = 0;
-- pvt->f.offset = AST_FRIENDLY_OFFSET;
-- pvt->f.src = pvt->t->name;
-- pvt->f.data.ptr = pvt->outbuf.uc;
-- ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
-+ ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
-+ return NULL;
-+ }
-+ } else {
-+ pvt->f.datalen = res;
-+ pvt->f.samples = dahdip->required_samples;
-+ pvt->f.frametype = AST_FRAME_VOICE;
-+ pvt->f.subclass = 1 << (pvt->t->dstfmt);
-+ pvt->f.mallocd = 0;
-+ pvt->f.offset = AST_FRIENDLY_OFFSET;
-+ pvt->f.src = pvt->t->name;
-+ pvt->f.data.ptr = pvt->outbuf.c;
-+ ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
-
-- return &pvt->f;
-+ pvt->samples = 0;
-+ pvt->datalen = 0;
-+ return &pvt->f;
-+ }
-+
-+ /* Shouldn't get here... */
-+ return NULL;
-+}
-+
-+static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
-+{
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-+
-+ if (!f->subclass) {
-+ /* We're just faking a return for calculation purposes. */
-+ dahdip->fake = 2;
-+ pvt->samples = f->samples;
-+ return 0;
-+ }
-+
-+ if (!f->datalen) {
-+ if (f->samples != dahdip->required_samples) {
-+ ast_log(LOG_ERROR, "%d != %d %d\n", f->samples, dahdip->required_samples, f->datalen);
- }
-+ }
-+ dahdi_write_frame(dahdip, f->data.ptr, f->datalen);
-+ pvt->samples += f->samples;
-+ pvt->datalen = 0;
-+ return -1;
-+}
-
-- } else if (2 == dahdip->fake) {
-+static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
-+{
-+ int res;
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-
-+ if (2 == dahdip->fake) {
- dahdip->fake = 1;
- pvt->f.frametype = AST_FRAME_VOICE;
- pvt->f.subclass = 0;
-- pvt->f.samples = 160;
-+ pvt->f.samples = dahdip->required_samples;
- pvt->f.data.ptr = NULL;
- pvt->f.offset = 0;
- pvt->f.datalen = 0;
- pvt->f.mallocd = 0;
- ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
- pvt->samples = 0;
--
- return &pvt->f;
--
- } else if (1 == dahdip->fake) {
--
-+ pvt->samples = 0;
-+ dahdip->fake = 0;
- return NULL;
-+ }
-
-+ /* Let's check to see if there is a new frame for us.... */
-+ if (dahdip->softslin) {
-+ res = read(dahdip->fd, dahdip->ulaw_buffer, sizeof(dahdip->ulaw_buffer));
-+ } else {
-+ res = read(dahdip->fd, pvt->outbuf.c + pvt->datalen, pvt->t->buf_size - pvt->datalen);
- }
-+
-+ if (-1 == res) {
-+ if (EWOULDBLOCK == errno) {
-+ /* Nothing waiting... */
-+ return NULL;
-+ } else {
-+ ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
-+ return NULL;
-+ }
-+ } else {
-+ if (dahdip->softslin) {
-+ ulawtolin(pvt);
-+ pvt->f.datalen = res * 2;
-+ } else {
-+ pvt->f.datalen = res;
-+ }
-+ pvt->datalen = 0;
-+ pvt->f.frametype = AST_FRAME_VOICE;
-+ pvt->f.subclass = 1 << (pvt->t->dstfmt);
-+ pvt->f.mallocd = 0;
-+ pvt->f.offset = AST_FRIENDLY_OFFSET;
-+ pvt->f.src = pvt->t->name;
-+ pvt->f.data.ptr = pvt->outbuf.c;
-+ pvt->f.samples = dahdip->required_samples;
-+ ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
-+ pvt->samples = 0;
-+
-+ return &pvt->f;
-+ }
-+
- /* Shouldn't get here... */
- return NULL;
- }
-
-+
- static void dahdi_destroy(struct ast_trans_pvt *pvt)
- {
-- struct pvt *dahdip = pvt->pvt;
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
-
- switch (dahdip->fmts.dstfmt) {
- case AST_FORMAT_G729A:
-@@ -218,20 +381,44 @@
- {
- /* Request translation through zap if possible */
- int fd;
-- struct pvt *dahdip = pvt->pvt;
-+ struct codec_dahdi_pvt *dahdip = pvt->pvt;
- int flags;
--
-- if ((fd = open("/dev/dahdi/transcode", O_RDWR)) < 0) {
-- ast_log(LOG_ERROR, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno));
-+ int tried_once = 0;
-+ const char *dev_filename = "/dev/dahdi/transcode";
-+
-+ if ((fd = open(dev_filename, O_RDWR)) < 0) {
-+ ast_log(LOG_ERROR, "Failed to open %s: %s\n", dev_filename, strerror(errno));
- return -1;
- }
--
-+
- dahdip->fmts.srcfmt = (1 << source);
- dahdip->fmts.dstfmt = (1 << dest);
-
-- ast_log(LOG_VERBOSE, "Opening transcoder channel from %d to %d.\n", source, dest);
-+ ast_log(LOG_DEBUG, "Opening transcoder channel from %d to %d.\n", source, dest);
-
-+retry:
- if (ioctl(fd, DAHDI_TC_ALLOCATE, &dahdip->fmts)) {
-+ if ((ENODEV == errno) && !tried_once) {
-+ /* We requested to translate to/from an unsupported
-+ * format. Most likely this is because signed linear
-+ * was not supported by any hardware devices even
-+ * though this module always registers signed linear
-+ * support. In this case we'll retry, requesting
-+ * support for ULAW instead of signed linear and then
-+ * we'll just convert from ulaw to signed linear in
-+ * software. */
-+ if (AST_FORMAT_SLINEAR == dahdip->fmts.srcfmt) {
-+ ast_log(LOG_DEBUG, "Using soft_slin support on source\n");
-+ dahdip->softslin = 1;
-+ dahdip->fmts.srcfmt = AST_FORMAT_ULAW;
-+ } else if (AST_FORMAT_SLINEAR == dahdip->fmts.dstfmt) {
-+ ast_log(LOG_DEBUG, "Using soft_slin support on destination\n");
-+ dahdip->softslin = 1;
-+ dahdip->fmts.dstfmt = AST_FORMAT_ULAW;
-+ }
-+ tried_once = 1;
-+ goto retry;
-+ }
- ast_log(LOG_ERROR, "Unable to attach to transcoder: %s\n", strerror(errno));
- close(fd);
-
-@@ -246,8 +433,12 @@
-
- dahdip->fd = fd;
-
-+ dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt)&AST_FORMAT_G723_1) ? G723_SAMPLES : G729_SAMPLES;
-+
- switch (dahdip->fmts.dstfmt) {
- case AST_FORMAT_G729A:
-+ ast_atomic_fetchadd_int(&channels.encoders, +1);
-+ break;
- case AST_FORMAT_G723_1:
- ast_atomic_fetchadd_int(&channels.encoders, +1);
- break;
-@@ -276,33 +467,65 @@
- return &f;
- }
-
-+static int is_encoder(struct translator *zt)
-+{
-+ if (zt->t.srcfmt&(AST_FORMAT_ULAW|AST_FORMAT_ALAW|AST_FORMAT_SLINEAR)) {
-+ return 1;
-+ } else {
-+ return 0;
-+ }
-+}
-+
- static int register_translator(int dst, int src)
- {
-- struct translator *dahdi;
-+ struct translator *zt;
- int res;
-
-- if (!(dahdi = ast_calloc(1, sizeof(*dahdi))))
-+ if (!(zt = ast_calloc(1, sizeof(*zt)))) {
- return -1;
-+ }
-
-- snprintf((char *) (dahdi->t.name), sizeof(dahdi->t.name), "dahdi%sto%s",
-+ snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
- ast_getformatname((1 << src)), ast_getformatname((1 << dst)));
-- dahdi->t.srcfmt = (1 << src);
-- dahdi->t.dstfmt = (1 << dst);
-- dahdi->t.newpvt = dahdi_new;
-- dahdi->t.framein = dahdi_framein;
-- dahdi->t.frameout = dahdi_frameout;
-- dahdi->t.destroy = dahdi_destroy;
-- dahdi->t.sample = fakesrc_sample;
-- dahdi->t.useplc = global_useplc;
-- dahdi->t.buf_size = BUFFER_SAMPLES * 2;
-- dahdi->t.desc_size = sizeof(struct pvt);
-- if ((res = ast_register_translator(&dahdi->t))) {
-- ast_free(dahdi);
-+ zt->t.srcfmt = (1 << src);
-+ zt->t.dstfmt = (1 << dst);
-+ zt->t.buf_size = BUFFER_SIZE;
-+ if (is_encoder(zt)) {
-+ zt->t.framein = dahdi_encoder_framein;
-+ zt->t.frameout = dahdi_encoder_frameout;
-+#if 0
-+ zt->t.buffer_samples = 0;
-+#endif
-+ } else {
-+ zt->t.framein = dahdi_decoder_framein;
-+ zt->t.frameout = dahdi_decoder_frameout;
-+#if 0
-+ if (AST_FORMAT_G723_1 == zt->t.srcfmt) {
-+ zt->t.plc_samples = G723_SAMPLES;
-+ } else {
-+ zt->t.plc_samples = G729_SAMPLES;
-+ }
-+ zt->t.buffer_samples = zt->t.plc_samples * 8;
-+#endif
-+ }
-+ zt->t.destroy = dahdi_destroy;
-+ zt->t.buffer_samples = 0;
-+ zt->t.newpvt = dahdi_new;
-+ zt->t.sample = fakesrc_sample;
-+#if 0
-+ zt->t.useplc = global_useplc;
-+#endif
-+ zt->t.useplc = 0;
-+ zt->t.native_plc = 0;
-+
-+ zt->t.desc_size = sizeof(struct codec_dahdi_pvt);
-+ if ((res = ast_register_translator(&zt->t))) {
-+ ast_free(zt);
- return -1;
- }
-
- AST_LIST_LOCK(&translators);
-- AST_LIST_INSERT_HEAD(&translators, dahdi, entry);
-+ AST_LIST_INSERT_HEAD(&translators, zt, entry);
- AST_LIST_UNLOCK(&translators);
-
- global_format_map.map[dst][src] = 1;
-@@ -334,12 +557,12 @@
-
- static void unregister_translators(void)
- {
-- struct translator *current;
-+ struct translator *cur;
-
- AST_LIST_LOCK(&translators);
-- while ((current = AST_LIST_REMOVE_HEAD(&translators, entry))) {
-- ast_unregister_translator(&current->t);
-- ast_free(current);
-+ while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
-+ ast_unregister_translator(&cur->t);
-+ ast_free(cur);
- }
- AST_LIST_UNLOCK(&translators);
- }
-@@ -350,18 +573,17 @@
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
-
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- global_useplc = ast_true(var->value);
-- ast_verb(3, "codec_dahdi: %susing generic PLC\n",
-- global_useplc ? "" : "not ");
-+ ast_verb(3, "codec_dahdi: %susing generic PLC\n",
-+ global_useplc ? "" : "not ");
- }
- }
-+
- ast_config_destroy(cfg);
- return 0;
- }
-@@ -402,8 +624,25 @@
- for (info.tcnum = 0; !(res = ioctl(fd, DAHDI_TC_GETINFO, &info)); info.tcnum++) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name);
-+
-+ /* Complex codecs need to support signed linear. If the
-+ * hardware transcoder does not natively support signed linear
-+ * format, we will emulate it in software directly in this
-+ * module. Also, do not allow direct ulaw/alaw to complex
-+ * codec translation, since that will prevent the generic PLC
-+ * functions from working. */
-+ if (info.dstfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
-+ info.dstfmts |= AST_FORMAT_SLINEAR;
-+ info.dstfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
-+ }
-+ if (info.srcfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
-+ info.srcfmts |= AST_FORMAT_SLINEAR;
-+ info.srcfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
-+ }
-+
- build_translators(&map, info.dstfmts, info.srcfmts);
- ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
-+
- }
-
- close(fd);
-@@ -446,6 +685,7 @@
-
- static int load_module(void)
- {
-+ ast_ulaw_init();
- if (parse_config(0))
- return AST_MODULE_LOAD_DECLINE;
- find_transcoders();
-@@ -457,4 +697,4 @@
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
-- );
-+ );
-Index: codecs/ex_ulaw.h
-===================================================================
---- a/codecs/ex_ulaw.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_ulaw.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,37 @@
-+/*! \file
-+ * \brief 8-bit data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_ulaw[] = {
-+ 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
-+ 0x10, 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a,
-+ 0x20, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f,
-+ 0x30, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x51, 0x54,
-+ 0x40, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69,
-+ 0x50, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e,
-+ 0x60, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x93,
-+ 0x70, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8,
-+ 0x80, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
-+ 0x90, 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2,
-+};
-+
-+static struct ast_frame *ulaw_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_ULAW,
-+ .datalen = sizeof(ex_ulaw),
-+ .samples = ARRAY_LEN(ex_ulaw),
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_ulaw,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_ulaw.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/ex_ilbc.h
-===================================================================
---- a/codecs/ex_ilbc.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_ilbc.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,33 @@
-+/*! \file
-+ * \brief Raw 8-bit data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_ilbc[] = {
-+ 0xff, 0xa0, 0xff, 0xfa, 0x0f, 0x60, 0x12, 0x11, 0xa2, 0x47,
-+ 0x22, 0x8c, 0x00, 0x00, 0x01, 0x02, 0x80, 0x43, 0xa0, 0x40,
-+ 0x33, 0xff, 0xcf, 0xc0, 0xf3, 0xf3, 0x3f, 0x8f, 0x3f, 0xff,
-+ 0xff, 0xff, 0xff, 0xfc, 0xf9, 0xe5, 0x55, 0x78, 0x0b, 0xca,
-+ 0xe1, 0x27, 0x94, 0x7b, 0xa8, 0x91, 0x2c, 0x36, 0x08, 0x56,
-+};
-+
-+static struct ast_frame *ilbc_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_ILBC,
-+ .datalen = sizeof(ex_ilbc),
-+ /* All frames are 30 ms long */
-+ .samples = ILBC_SAMPLES,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_ilbc,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_ilbc.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/codec_lpc10.c
-===================================================================
---- a/codecs/codec_lpc10.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_lpc10.c (.../team/group/issue14292) (revision 178988)
-@@ -39,8 +39,8 @@
- #include "lpc10/lpc10.h"
-
- /* Sample frame data */
--#include "slin_lpc10_ex.h"
--#include "lpc10_slin_ex.h"
-+#include "asterisk/slin.h"
-+#include "ex_lpc10.h"
-
- /* We use a very strange format here... I have no idea why... The frames are 180
- samples long, which isn't even an even number of milliseconds... Not only that
-@@ -75,37 +75,6 @@
- return (tmp->lpc10.dec = create_lpc10_decoder_state()) ? 0 : -1;
- }
-
--static struct ast_frame *lintolpc10_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_lpc10_ex);
-- /* Assume 8000 Hz */
-- f.samples = LPC10_SAMPLES_PER_FRAME;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_lpc10_ex;
-- return &f;
--}
--
--static struct ast_frame *lpc10tolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_LPC10;
-- f.datalen = sizeof(lpc10_slin_ex);
-- /* All frames are 22 ms long (maybe a little more -- why did he choose
-- LPC10_SAMPLES_PER_FRAME sample frames anyway?? */
-- f.samples = LPC10_SAMPLES_PER_FRAME;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = lpc10_slin_ex;
-- return &f;
--}
--
- static void extract_bits(INT32 *bits, unsigned char *c)
- {
- int x;
-@@ -229,7 +198,7 @@
- .newpvt = lpc10_dec_new,
- .framein = lpc10tolin_framein,
- .destroy = lpc10_destroy,
-- .sample = lpc10tolin_sample,
-+ .sample = lpc10_sample,
- .desc_size = sizeof(struct lpc10_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .plc_samples = LPC10_SAMPLES_PER_FRAME,
-@@ -244,7 +213,7 @@
- .framein = lintolpc10_framein,
- .frameout = lintolpc10_frameout,
- .destroy = lpc10_destroy,
-- .sample = lintolpc10_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct lpc10_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = LPC10_BYTES_IN_COMPRESSED_FRAME * (1 + BUFFER_SAMPLES / LPC10_SAMPLES_PER_FRAME),
-@@ -255,10 +224,8 @@
- struct ast_variable *var;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- lpc10tolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/codec_g722.c
-===================================================================
---- a/codecs/codec_g722.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_g722.c (.../team/group/issue14292) (revision 178988)
-@@ -46,12 +46,12 @@
- #define BUFFER_SAMPLES 8096 /* size for the translation buffers */
- #define BUF_SHIFT 5
-
--/* Sample frame data */
--
- #include "g722/g722.h"
--#include "slin_g722_ex.h"
--#include "g722_slin_ex.h"
-
-+/* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_g722.h"
-+
- struct g722_encoder_pvt {
- g722_encode_state_t g722;
- };
-@@ -132,69 +132,13 @@
- return 0;
- }
-
--static struct ast_frame *g722tolin_sample(void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_G722,
-- .datalen = sizeof(g722_slin_ex),
-- .samples = sizeof(g722_slin_ex) * 2,
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = g722_slin_ex,
-- };
--
-- return &f;
--}
--
--static struct ast_frame *g722tolin16_sample(void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_G722,
-- .datalen = sizeof(g722_slin_ex),
-- .samples = sizeof(g722_slin_ex) * 2,
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = g722_slin_ex,
-- };
--
-- return &f;
--}
--
--static struct ast_frame *lintog722_sample (void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_SLINEAR,
-- .datalen = sizeof(slin_g722_ex),
-- .samples = ARRAY_LEN(slin_g722_ex),
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = slin_g722_ex,
-- };
--
-- return &f;
--}
--
--static struct ast_frame *lin16tog722_sample (void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_SLINEAR16,
-- .datalen = sizeof(slin_g722_ex),
-- .samples = ARRAY_LEN(slin_g722_ex),
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = slin_g722_ex,
-- };
--
-- return &f;
--}
--
- static struct ast_translator g722tolin = {
- .name = "g722tolin",
- .srcfmt = AST_FORMAT_G722,
- .dstfmt = AST_FORMAT_SLINEAR,
- .newpvt = g722tolin_new, /* same for both directions */
- .framein = g722tolin_framein,
-- .sample = g722tolin_sample,
-+ .sample = g722_sample,
- .desc_size = sizeof(struct g722_decoder_pvt),
- .buffer_samples = BUFFER_SAMPLES / sizeof(int16_t),
- .buf_size = BUFFER_SAMPLES,
-@@ -207,7 +151,7 @@
- .dstfmt = AST_FORMAT_G722,
- .newpvt = lintog722_new, /* same for both directions */
- .framein = lintog722_framein,
-- .sample = lintog722_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct g722_encoder_pvt),
- .buffer_samples = BUFFER_SAMPLES * 2,
- .buf_size = BUFFER_SAMPLES,
-@@ -219,7 +163,7 @@
- .dstfmt = AST_FORMAT_SLINEAR16,
- .newpvt = g722tolin16_new, /* same for both directions */
- .framein = g722tolin_framein,
-- .sample = g722tolin16_sample,
-+ .sample = g722_sample,
- .desc_size = sizeof(struct g722_decoder_pvt),
- .buffer_samples = BUFFER_SAMPLES / sizeof(int16_t),
- .buf_size = BUFFER_SAMPLES,
-@@ -232,7 +176,7 @@
- .dstfmt = AST_FORMAT_G722,
- .newpvt = lin16tog722_new, /* same for both directions */
- .framein = lintog722_framein,
-- .sample = lin16tog722_sample,
-+ .sample = slin16_sample,
- .desc_size = sizeof(struct g722_encoder_pvt),
- .buffer_samples = BUFFER_SAMPLES * 2,
- .buf_size = BUFFER_SAMPLES,
-@@ -244,10 +188,8 @@
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- g722tolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/codec_a_mu.c
-===================================================================
---- a/codecs/codec_a_mu.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_a_mu.c (.../team/group/issue14292) (revision 178988)
-@@ -38,10 +38,10 @@
- static unsigned char mu2a[256];
- static unsigned char a2mu[256];
-
--/* Sample frame data (Mu data is okay) */
-+/* Sample frame data */
-+#include "ex_ulaw.h"
-+#include "ex_alaw.h"
-
--#include "ulaw_slin_ex.h"
--
- /*! \brief convert frame data and store into the buffer */
- static int alawtoulaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
- {
-@@ -74,43 +74,12 @@
- return 0;
- }
-
--/*
-- * alawToLin_Sample. Just random data, somehow...
-- */
--static struct ast_frame *alawtoulaw_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_ALAW;
-- f.datalen = sizeof(ulaw_slin_ex);
-- f.samples = sizeof(ulaw_slin_ex);
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = ulaw_slin_ex; /* XXX what ? */
-- return &f;
--}
--
--static struct ast_frame *ulawtoalaw_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_ULAW;
-- f.datalen = sizeof(ulaw_slin_ex);
-- f.samples = sizeof(ulaw_slin_ex);
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = ulaw_slin_ex;
-- return &f;
--}
--
- static struct ast_translator alawtoulaw = {
- .name = "alawtoulaw",
- .srcfmt = AST_FORMAT_ALAW,
- .dstfmt = AST_FORMAT_ULAW,
- .framein = alawtoulaw_framein,
-- .sample = alawtoulaw_sample,
-+ .sample = alaw_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES,
- };
-@@ -120,7 +89,7 @@
- .srcfmt = AST_FORMAT_ULAW,
- .dstfmt = AST_FORMAT_ALAW,
- .framein = ulawtoalaw_framein,
-- .sample = ulawtoalaw_sample,
-+ .sample = ulaw_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES,
- };
-Index: codecs/ex_lpc10.h
-===================================================================
---- a/codecs/ex_lpc10.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_lpc10.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,30 @@
-+/*! \file
-+ * \brief
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_lpc10[] = {
-+ 0x01, 0x08, 0x31, 0x08, 0x31, 0x80, 0x30,
-+};
-+
-+static struct ast_frame *lpc10_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_LPC10,
-+ .datalen = sizeof(ex_lpc10),
-+ /* All frames are 22 ms long (maybe a little more -- why did he choose
-+ LPC10_SAMPLES_PER_FRAME sample frames anyway?? */
-+ .samples = LPC10_SAMPLES_PER_FRAME,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_lpc10,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_lpc10.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/codec_speex.c
-===================================================================
---- a/codecs/codec_speex.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_speex.c (.../team/group/issue14292) (revision 178988)
-@@ -53,10 +53,6 @@
- #include "asterisk/config.h"
- #include "asterisk/utils.h"
-
--/* Sample frame data */
--#include "slin_speex_ex.h"
--#include "speex_slin_ex.h"
--
- /* codec variables */
- static int quality = 3;
- static int complexity = 2;
-@@ -84,6 +80,10 @@
- #define BUFFER_SAMPLES 8000
- #define SPEEX_SAMPLES 160
-
-+/* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_speex.h"
-+
- struct speex_coder_pvt {
- void *speex;
- SpeexBits bits;
-@@ -154,36 +154,6 @@
- return 0;
- }
-
--static struct ast_frame *lintospeex_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_speex_ex);
-- /* Assume 8000 Hz */
-- f.samples = sizeof(slin_speex_ex)/2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_speex_ex;
-- return &f;
--}
--
--static struct ast_frame *speextolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SPEEX;
-- f.datalen = sizeof(speex_slin_ex);
-- /* All frames are 20 ms long */
-- f.samples = SPEEX_SAMPLES;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = speex_slin_ex;
-- return &f;
--}
--
- /*! \brief convert and store into outbuf */
- static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
- {
-@@ -346,7 +316,7 @@
- .newpvt = speextolin_new,
- .framein = speextolin_framein,
- .destroy = speextolin_destroy,
-- .sample = speextolin_sample,
-+ .sample = speex_sample,
- .desc_size = sizeof(struct speex_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
-@@ -361,7 +331,7 @@
- .framein = lintospeex_framein,
- .frameout = lintospeex_frameout,
- .destroy = lintospeex_destroy,
-- .sample = lintospeex_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct speex_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
-@@ -375,10 +345,8 @@
- int res;
- float res_f;
-
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
-
- for (var = ast_variable_browse(cfg, "speex"); var; var = var->next) {
- if (!strcasecmp(var->name, "quality")) {
-Index: codecs/codec_alaw.c
-===================================================================
---- a/codecs/codec_alaw.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_alaw.c (.../team/group/issue14292) (revision 178988)
-@@ -35,11 +35,10 @@
-
- #define BUFFER_SAMPLES 8096 /* size for the translation buffers */
-
--/* Sample frame data (Mu data is okay) */
-+/* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_alaw.h"
-
--#include "slin_ulaw_ex.h"
--#include "ulaw_slin_ex.h"
--
- /*! \brief decode frame into lin and fill output buffer. */
- static int alawtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
- {
-@@ -72,42 +71,12 @@
- return 0;
- }
-
--/*! \brief alawToLin_Sample */
--static struct ast_frame *alawtolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_ALAW;
-- f.datalen = sizeof(ulaw_slin_ex);
-- f.samples = sizeof(ulaw_slin_ex);
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = ulaw_slin_ex;
-- return &f;
--}
--
--/*! \brief LinToalaw_Sample */
--static struct ast_frame *lintoalaw_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_ulaw_ex);
-- f.samples = sizeof(slin_ulaw_ex) / 2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_ulaw_ex;
-- return &f;
--}
--
- static struct ast_translator alawtolin = {
- .name = "alawtolin",
- .srcfmt = AST_FORMAT_ALAW,
- .dstfmt = AST_FORMAT_SLINEAR,
- .framein = alawtolin_framein,
-- .sample = alawtolin_sample,
-+ .sample = alaw_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
- .plc_samples = 160,
-@@ -118,7 +87,7 @@
- .srcfmt = AST_FORMAT_SLINEAR,
- .dstfmt = AST_FORMAT_ALAW,
- .framein = lintoalaw_framein,
-- .sample = lintoalaw_sample,
-+ .sample = slin8_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES,
- };
-@@ -128,10 +97,8 @@
- struct ast_variable *var;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- alawtolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/codec_adpcm.c
-===================================================================
---- a/codecs/codec_adpcm.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_adpcm.c (.../team/group/issue14292) (revision 178988)
-@@ -44,10 +44,9 @@
- #define BUFFER_SAMPLES 8096 /* size for the translation buffers */
-
- /* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_adpcm.h"
-
--#include "slin_adpcm_ex.h"
--#include "adpcm_slin_ex.h"
--
- /*
- * Step size index shift table
- */
-@@ -285,43 +284,12 @@
- }
-
-
--/*! \brief AdpcmToLin_Sample */
--static struct ast_frame *adpcmtolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_ADPCM;
-- f.datalen = sizeof(adpcm_slin_ex);
-- f.samples = sizeof(adpcm_slin_ex) * 2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = adpcm_slin_ex;
-- return &f;
--}
--
--/*! \brief LinToAdpcm_Sample */
--static struct ast_frame *lintoadpcm_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_adpcm_ex);
-- /* Assume 8000 Hz */
-- f.samples = sizeof(slin_adpcm_ex) / 2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_adpcm_ex;
-- return &f;
--}
--
- static struct ast_translator adpcmtolin = {
- .name = "adpcmtolin",
- .srcfmt = AST_FORMAT_ADPCM,
- .dstfmt = AST_FORMAT_SLINEAR,
- .framein = adpcmtolin_framein,
-- .sample = adpcmtolin_sample,
-+ .sample = adpcm_sample,
- .desc_size = sizeof(struct adpcm_decoder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
-@@ -334,7 +302,7 @@
- .dstfmt = AST_FORMAT_ADPCM,
- .framein = lintoadpcm_framein,
- .frameout = lintoadpcm_frameout,
-- .sample = lintoadpcm_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof (struct adpcm_encoder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES/ 2, /* 2 samples per byte */
-@@ -345,10 +313,8 @@
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
- struct ast_variable *var;
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var ; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- adpcmtolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/ex_g722.h
-===================================================================
---- a/codecs/ex_g722.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_g722.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,47 @@
-+/*! \file
-+ * \brief 8-bit data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_g722[] = {
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+};
-+
-+static struct ast_frame *g722_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_G722,
-+ .datalen = sizeof(ex_g722),
-+ .samples = ARRAY_LEN(ex_g722),
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_g722,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_g722.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/codec_g726.c
-===================================================================
---- a/codecs/codec_g726.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_g726.c (.../team/group/issue14292) (revision 178988)
-@@ -58,10 +58,9 @@
- #define BUF_SHIFT 5
-
- /* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_g726.h"
-
--#include "slin_g726_ex.h"
--#include "g726_slin_ex.h"
--
- /*
- * The following is the definition of the state structure
- * used by the G.726 encoder and decoder to preserve their internal
-@@ -786,41 +785,13 @@
- return 0;
- }
-
--static struct ast_frame *g726tolin_sample(void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_G726,
-- .datalen = sizeof(g726_slin_ex),
-- .samples = sizeof(g726_slin_ex) * 2, /* 2 samples per byte */
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = g726_slin_ex,
-- };
--
-- return &f;
--}
--
--static struct ast_frame *lintog726_sample (void)
--{
-- static struct ast_frame f = {
-- .frametype = AST_FRAME_VOICE,
-- .subclass = AST_FORMAT_SLINEAR,
-- .datalen = sizeof(slin_g726_ex),
-- .samples = sizeof(slin_g726_ex) / 2, /* 1 sample per 2 bytes */
-- .src = __PRETTY_FUNCTION__,
-- .data.ptr = slin_g726_ex,
-- };
--
-- return &f;
--}
--
- static struct ast_translator g726tolin = {
- .name = "g726tolin",
- .srcfmt = AST_FORMAT_G726,
- .dstfmt = AST_FORMAT_SLINEAR,
- .newpvt = lintog726_new, /* same for both directions */
- .framein = g726tolin_framein,
-- .sample = g726tolin_sample,
-+ .sample = g726_sample,
- .desc_size = sizeof(struct g726_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
-@@ -833,7 +804,7 @@
- .dstfmt = AST_FORMAT_G726,
- .newpvt = lintog726_new, /* same for both directions */
- .framein = lintog726_framein,
-- .sample = lintog726_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct g726_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES/2,
-@@ -845,7 +816,7 @@
- .dstfmt = AST_FORMAT_SLINEAR,
- .newpvt = lintog726_new, /* same for both directions */
- .framein = g726aal2tolin_framein,
-- .sample = g726tolin_sample,
-+ .sample = g726_sample,
- .desc_size = sizeof(struct g726_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
-@@ -858,7 +829,7 @@
- .dstfmt = AST_FORMAT_G726_AAL2,
- .newpvt = lintog726_new, /* same for both directions */
- .framein = lintog726aal2_framein,
-- .sample = lintog726_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof(struct g726_coder_pvt),
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES / 2,
-@@ -869,7 +840,7 @@
- .srcfmt = AST_FORMAT_G726,
- .dstfmt = AST_FORMAT_G726_AAL2,
- .framein = g726tog726aal2_framein, /* same for both directions */
-- .sample = lintog726_sample,
-+ .sample = g726_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES,
- };
-@@ -879,7 +850,7 @@
- .srcfmt = AST_FORMAT_G726_AAL2,
- .dstfmt = AST_FORMAT_G726,
- .framein = g726tog726aal2_framein, /* same for both directions */
-- .sample = lintog726_sample,
-+ .sample = g726_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES,
- };
-@@ -890,10 +861,8 @@
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- g726tolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/codec_gsm.c
-===================================================================
---- a/codecs/codec_gsm.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/codecs/codec_gsm.c (.../team/group/issue14292) (revision 178988)
-@@ -47,15 +47,15 @@
-
- #include "../formats/msgsm.h"
-
--/* Sample frame data */
--#include "slin_gsm_ex.h"
--#include "gsm_slin_ex.h"
--
- #define BUFFER_SAMPLES 8000
- #define GSM_SAMPLES 160
- #define GSM_FRAME_LEN 33
- #define MSGSM_FRAME_LEN 65
-
-+/* Sample frame data */
-+#include "asterisk/slin.h"
-+#include "ex_gsm.h"
-+
- struct gsm_translator_pvt { /* both gsm2lin and lin2gsm */
- gsm gsm;
- int16_t buf[BUFFER_SAMPLES]; /* lin2gsm, temporary storage */
-@@ -68,36 +68,6 @@
- return (tmp->gsm = gsm_create()) ? 0 : -1;
- }
-
--static struct ast_frame *lintogsm_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_SLINEAR;
-- f.datalen = sizeof(slin_gsm_ex);
-- /* Assume 8000 Hz */
-- f.samples = sizeof(slin_gsm_ex)/2;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = slin_gsm_ex;
-- return &f;
--}
--
--static struct ast_frame *gsmtolin_sample(void)
--{
-- static struct ast_frame f;
-- f.frametype = AST_FRAME_VOICE;
-- f.subclass = AST_FORMAT_GSM;
-- f.datalen = sizeof(gsm_slin_ex);
-- /* All frames are 20 ms long */
-- f.samples = GSM_SAMPLES;
-- f.mallocd = 0;
-- f.offset = 0;
-- f.src = __PRETTY_FUNCTION__;
-- f.data.ptr = gsm_slin_ex;
-- return &f;
--}
--
- /*! \brief decode and store in outbuf. */
- static int gsmtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
- {
-@@ -203,7 +173,7 @@
- .newpvt = gsm_new,
- .framein = gsmtolin_framein,
- .destroy = gsm_destroy_stuff,
-- .sample = gsmtolin_sample,
-+ .sample = gsm_sample,
- .buffer_samples = BUFFER_SAMPLES,
- .buf_size = BUFFER_SAMPLES * 2,
- .desc_size = sizeof (struct gsm_translator_pvt ),
-@@ -218,7 +188,7 @@
- .framein = lintogsm_framein,
- .frameout = lintogsm_frameout,
- .destroy = gsm_destroy_stuff,
-- .sample = lintogsm_sample,
-+ .sample = slin8_sample,
- .desc_size = sizeof (struct gsm_translator_pvt ),
- .buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES,
- };
-@@ -229,10 +199,8 @@
- struct ast_variable *var;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
- struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
-- if (cfg == NULL)
-+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
- return 0;
-- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
- for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
- if (!strcasecmp(var->name, "genericplc")) {
- gsmtolin.useplc = ast_true(var->value) ? 1 : 0;
-Index: codecs/ex_alaw.h
-===================================================================
---- a/codecs/ex_alaw.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_alaw.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,37 @@
-+/*! \file
-+ * \brief 8-bit data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_alaw[] = {
-+ 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
-+ 0x10, 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a,
-+ 0x20, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f,
-+ 0x30, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x51, 0x54,
-+ 0x40, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69,
-+ 0x50, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e,
-+ 0x60, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x93,
-+ 0x70, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8,
-+ 0x80, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
-+ 0x90, 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2,
-+};
-+
-+static struct ast_frame *alaw_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_ALAW,
-+ .datalen = sizeof(ex_alaw),
-+ .samples = ARRAY_LEN(ex_alaw),
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_alaw,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_alaw.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/ex_adpcm.h
-===================================================================
---- a/codecs/ex_adpcm.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_adpcm.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,32 @@
-+/*! \file
-+ * \brief 4-bit ADPCM data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_adpcm[] = {
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+};
-+
-+static struct ast_frame *adpcm_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_ADPCM,
-+ .datalen = sizeof(ex_adpcm),
-+ .samples = ARRAY_LEN(ex_adpcm) * 2,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_adpcm,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_adpcm.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/ex_speex.h
-===================================================================
---- a/codecs/ex_speex.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_speex.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,32 @@
-+/*! \file
-+ * \brief Random Data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_speex[] = {
-+ 0x2e, 0x8e, 0x0f, 0x9a, 0x20, 0000, 0x01, 0x7f, 0xff, 0xff,
-+ 0xff, 0xff, 0xff, 0x91, 0000, 0xbf, 0xff, 0xff, 0xff, 0xff,
-+ 0xff, 0xdc, 0x80, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+ 0x98, 0x7f, 0xff, 0xff, 0xff, 0xe8, 0xff, 0xf7, 0x80,
-+};
-+
-+static struct ast_frame *speex_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_SPEEX,
-+ .datalen = sizeof(ex_speex),
-+ /* All frames are 20 ms long */
-+ .samples = SPEEX_SAMPLES,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_speex,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_speex.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/ex_g726.h
-===================================================================
---- a/codecs/ex_g726.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_g726.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,32 @@
-+/*! \file
-+ * \brief 4-bit G.726 data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_g726[] = {
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+};
-+
-+static struct ast_frame *g726_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_G726,
-+ .datalen = sizeof(ex_g726),
-+ .samples = ARRAY_LEN(ex_g726) * 2, /* 2 samples per byte */
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_g726,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_g726.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: codecs/ex_gsm.h
-===================================================================
---- a/codecs/ex_gsm.h (.../tags/1.6.1-rc1) (revision 0)
-+++ b/codecs/ex_gsm.h (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,32 @@
-+/*! \file
-+ * \brief 8-bit raw data
-+ *
-+ * Copyright (C) 2008, Digium, Inc.
-+ *
-+ * Distributed under the terms of the GNU General Public License
-+ *
-+ */
-+
-+static uint8_t ex_gsm[] = {
-+ 0xda, 0xa6, 0xac, 0x2d, 0xa3, 0x50, 0x00, 0x49, 0x24, 0x92,
-+ 0x49, 0x24, 0x50, 0x40, 0x49, 0x24, 0x92, 0x37, 0x24, 0x52,
-+ 0x00, 0x49, 0x24, 0x92, 0x47, 0x24, 0x50, 0x80, 0x46, 0xe3,
-+ 0x6d, 0xb8, 0xdc,
-+};
-+
-+static struct ast_frame *gsm_sample(void)
-+{
-+ static struct ast_frame f = {
-+ .frametype = AST_FRAME_VOICE,
-+ .subclass = AST_FORMAT_GSM,
-+ .datalen = sizeof(ex_gsm),
-+ /* All frames are 20 ms long */
-+ .samples = GSM_SAMPLES,
-+ .mallocd = 0,
-+ .offset = 0,
-+ .src = __PRETTY_FUNCTION__,
-+ .data.ptr = ex_gsm,
-+ };
-+
-+ return &f;
-+}
-
-Property changes on: codecs/ex_gsm.h
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: utils/hashtest2.c
-===================================================================
---- a/utils/hashtest2.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/hashtest2.c (.../team/group/issue14292) (revision 178988)
-@@ -59,6 +59,11 @@
- char *val;
- };
-
-+char *pbx_substitute_variables_helper_full(struct ast_channel *chan, struct varshead *head, const char *cp1, char *cp2, int maxlen, size_t *used);
-+char *pbx_substitute_variables_helper_full(struct ast_channel *chan, struct varshead *head, const char *cp1, char *cp2, int maxlen, size_t *used)
-+{
-+ return NULL;
-+}
-
- static int hash_string(const void *obj, const int flags)
- {
-Index: utils/extconf.c
-===================================================================
---- a/utils/extconf.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/extconf.c (.../team/group/issue14292) (revision 178988)
-@@ -3244,20 +3244,24 @@
- * return the index of the matching entry, starting from 1.
- * If names is not supplied, try numeric values.
- */
--
- static int lookup_name(const char *s, char *const names[], int max)
- {
- int i;
-
-- if (names) {
-+ if (names && *s > '9') {
- for (i = 0; names[i]; i++) {
-- if (!strcasecmp(s, names[i]))
-- return i+1;
-+ if (!strcasecmp(s, names[i])) {
-+ return i;
-+ }
- }
-- } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
-- return i;
- }
-- return 0; /* error return */
-+
-+ /* Allow months and weekdays to be specified as numbers, as well */
-+ if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
-+ /* What the array offset would have been: "1" would be at offset 0 */
-+ return i - 1;
-+ }
-+ return -1; /* error return */
- }
-
- /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
-@@ -3265,45 +3269,43 @@
- */
- static unsigned get_range(char *src, int max, char *const names[], const char *msg)
- {
-- int s, e; /* start and ending position */
-+ int start, end; /* start and ending position */
- unsigned int mask = 0;
-+ char *part;
-
- /* Check for whole range */
- if (ast_strlen_zero(src) || !strcmp(src, "*")) {
-- s = 0;
-- e = max - 1;
-- } else {
-+ return (1 << max) - 1;
-+ }
-+
-+ while ((part = strsep(&src, "&"))) {
- /* Get start and ending position */
-- char *c = strchr(src, '-');
-- if (c)
-- *c++ = '\0';
-+ char *endpart = strchr(part, '-');
-+ if (endpart) {
-+ *endpart++ = '\0';
-+ }
- /* Find the start */
-- s = lookup_name(src, names, max);
-- if (!s) {
-- ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
-- return 0;
-+ if ((start = lookup_name(part, names, max)) < 0) {
-+ ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
-+ continue;
- }
-- s--;
-- if (c) { /* find end of range */
-- e = lookup_name(c, names, max);
-- if (!e) {
-- ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
-- return 0;
-+ if (endpart) { /* find end of range */
-+ if ((end = lookup_name(endpart, names, max)) < 0) {
-+ ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
-+ continue;
- }
-- e--;
-- } else
-- e = s;
-- }
-- /* Fill the mask. Remember that ranges are cyclic */
-- mask = 1 << e; /* initialize with last element */
-- while (s != e) {
-- if (s >= max) {
-- s = 0;
-- mask |= (1 << s);
- } else {
-- mask |= (1 << s);
-- s++;
-+ end = start;
- }
-+ /* Fill the mask. Remember that ranges are cyclic */
-+ mask |= (1 << end); /* initialize with last element */
-+ while (start != end) {
-+ if (start >= max) {
-+ start = 0;
-+ }
-+ mask |= (1 << start);
-+ start++;
-+ }
- }
- return mask;
- }
-@@ -3311,85 +3313,60 @@
- /*! \brief store a bitmask of valid times, one bit each 2 minute */
- static void get_timerange(struct ast_timing *i, char *times)
- {
-- char *e;
-+ char *endpart, *part;
- int x;
-- int s1, s2;
-- int e1, e2;
-- /* int cth, ctm; */
-+ int st_h, st_m;
-+ int endh, endm;
-+ int minute_start, minute_end;
-
- /* start disabling all times, fill the fields with 0's, as they may contain garbage */
- memset(i->minmask, 0, sizeof(i->minmask));
-
-- /* 2-minutes per bit, since the mask has only 32 bits :( */
-+ /* 1-minute per bit */
- /* Star is all times */
- if (ast_strlen_zero(times) || !strcmp(times, "*")) {
-- for (x=0; x<24; x++)
-+ /* 48, because each hour takes 2 integers; 30 bits each */
-+ for (x = 0; x < 48; x++) {
- i->minmask[x] = 0x3fffffff; /* 30 bits */
-+ }
- return;
- }
- /* Otherwise expect a range */
-- e = strchr(times, '-');
-- if (!e) {
-- ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
-- return;
-- }
-- *e++ = '\0';
-- /* XXX why skip non digits ? */
-- while (*e && !isdigit(*e))
-- e++;
-- if (!*e) {
-- ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
-- return;
-- }
-- if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
-- ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
-- return;
-- }
-- if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
-- ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
-- return;
-- }
-- /* XXX this needs to be optimized */
--#if 1
-- s1 = s1 * 30 + s2/2;
-- if ((s1 < 0) || (s1 >= 24*30)) {
-- ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
-- return;
-- }
-- e1 = e1 * 30 + e2/2;
-- if ((e1 < 0) || (e1 >= 24*30)) {
-- ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
-- return;
-- }
-- /* Go through the time and enable each appropriate bit */
-- for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
-- i->minmask[x/30] |= (1 << (x % 30));
-- }
-- /* Do the last one */
-- i->minmask[x/30] |= (1 << (x % 30));
--#else
-- for (cth=0; cth<24; cth++) {
-- /* Initialize masks to blank */
-- i->minmask[cth] = 0;
-- for (ctm=0; ctm<30; ctm++) {
-- if (
-- /* First hour with more than one hour */
-- (((cth == s1) && (ctm >= s2)) &&
-- ((cth < e1)))
-- /* Only one hour */
-- || (((cth == s1) && (ctm >= s2)) &&
-- ((cth == e1) && (ctm <= e2)))
-- /* In between first and last hours (more than 2 hours) */
-- || ((cth > s1) &&
-- (cth < e1))
-- /* Last hour with more than one hour */
-- || ((cth > s1) &&
-- ((cth == e1) && (ctm <= e2)))
-- )
-- i->minmask[cth] |= (1 << (ctm / 2));
-+ while ((part = strsep(&times, "&"))) {
-+ if (!(endpart = strchr(part, '-'))) {
-+ if (sscanf(part, "%d:%d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
-+ ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
-+ continue;
-+ }
-+ i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
-+ continue;
- }
-+ *endpart++ = '\0';
-+ /* why skip non digits? Mostly to skip spaces */
-+ while (*endpart && !isdigit(*endpart)) {
-+ endpart++;
-+ }
-+ if (!*endpart) {
-+ ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
-+ continue;
-+ }
-+ if (sscanf(part, "%d:%d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
-+ ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
-+ continue;
-+ }
-+ if (sscanf(endpart, "%d:%d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
-+ ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
-+ continue;
-+ }
-+ minute_start = st_h * 60 + st_m;
-+ minute_end = endh * 60 + endm;
-+ /* Go through the time and enable each appropriate bit */
-+ for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
-+ i->minmask[x / 30] |= (1 << (x % 30));
-+ }
-+ /* Do the last one */
-+ i->minmask[x / 30] |= (1 << (x % 30));
- }
--#endif
- /* All done */
- return;
- }
-@@ -4500,27 +4477,44 @@
-
- int ast_build_timing(struct ast_timing *i, const char *info_in)
- {
-- char info_save[256];
-- char *info;
-+ char *info_save, *info;
-+ int j, num_fields, last_sep = -1;
-
- /* Check for empty just in case */
-- if (ast_strlen_zero(info_in))
-+ if (ast_strlen_zero(info_in)) {
- return 0;
-+ }
-+
- /* make a copy just in case we were passed a static string */
-- ast_copy_string(info_save, info_in, sizeof(info_save));
-- info = info_save;
-+ info_save = info = ast_strdupa(info_in);
-+
-+ /* count the number of fields in the timespec */
-+ for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
-+ if (info[j] == ',') {
-+ last_sep = j;
-+ num_fields++;
-+ }
-+ }
-+
-+ /* save the timezone, if it is specified */
-+ if (num_fields == 5) {
-+ i->timezone = ast_strdup(info + last_sep + 1);
-+ } else {
-+ i->timezone = NULL;
-+ }
-+
- /* Assume everything except time */
- i->monthmask = 0xfff; /* 12 bits */
- i->daymask = 0x7fffffffU; /* 31 bits */
- i->dowmask = 0x7f; /* 7 bits */
- /* on each call, use strsep() to move info to the next argument */
-- get_timerange(i, strsep(&info, "|"));
-+ get_timerange(i, strsep(&info, "|,"));
- if (info)
-- i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
-+ i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
- if (info)
-- i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
-+ i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
- if (info)
-- i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
-+ i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
- return 1;
- }
-
-@@ -5164,7 +5158,7 @@
- /* Strip off timing info, and process if it is there */
- if ( (c = strchr(p, '|')) ) {
- *c++ = '\0';
-- new_include->hastime = ast_build_timing(&(new_include->timing), c);
-+ new_include->hastime = ast_build_timing(&(new_include->timing), c);
- }
- new_include->next = NULL;
- new_include->registrar = registrar;
-Index: utils/check_expr.c
-===================================================================
---- a/utils/check_expr.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/check_expr.c (.../team/group/issue14292) (revision 178988)
-@@ -27,57 +27,6 @@
- #define AST_API_MODULE 1
- #include "asterisk/lock.h"
-
--#include "asterisk/strings.h"
--
--/* I included this from utils.c, so as not to have everything in that .c
-- file included */
--/*!
-- * core handler for dynamic strings.
-- * This is not meant to be called directly, but rather through the
-- * various wrapper macros
-- * ast_str_set(...)
-- * ast_str_append(...)
-- * ast_str_set_va(...)
-- * ast_str_append_va(...)
-- */
--int __attribute__((format(printf, 4, 0))) __ast_str_helper(struct ast_str **buf, size_t max_len,
-- int append, const char *fmt, va_list ap)
--{
-- int res, need;
-- int offset = (append && (*buf)->len) ? (*buf)->used : 0;
--
-- if (max_len < 0)
-- max_len = (*buf)->len; /* don't exceed the allocated space */
-- /*
-- * Ask vsnprintf how much space we need. Remember that vsnprintf
-- * does not count the final '\0' so we must add 1.
-- */
-- res = vsnprintf((*buf)->str + offset, (*buf)->len - offset, fmt, ap);
--
-- need = res + offset + 1;
-- /*
-- * If there is not enough space and we are below the max length,
-- * reallocate the buffer and return a message telling to retry.
-- */
-- if (need > (*buf)->len && (max_len == 0 || (*buf)->len < max_len) ) {
-- if (max_len && max_len < need) /* truncate as needed */
-- need = max_len;
-- else if (max_len == 0) /* if unbounded, give more room for next time */
-- need += 16 + need/4;
-- if (ast_str_make_space(buf, need)) {
-- return AST_DYNSTR_BUILD_FAILED;
-- }
-- (*buf)->str[offset] = '\0'; /* Truncate the partial write. */
--
-- /* va_end() and va_start() must be done before calling
-- * vsnprintf() again. */
-- return AST_DYNSTR_BUILD_RETRY;
-- }
-- /* update space used, keep in mind the truncation */
-- (*buf)->used = (res + offset > (*buf)->len) ? (*buf)->len : res + offset;
--
-- return res;
--}
- #ifndef DEBUG_THREADS
- enum ast_lock_type {
- AST_MUTEX,
-@@ -85,7 +34,23 @@
- AST_WRLOCK,
- };
- #endif
-+#ifdef DEBUG_THREADLOCALS
-+#define MALLOC_FAILURE_MSG \
-+ ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
-
-+void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func);
-+
-+void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func)
-+{
-+ void *p;
-+
-+ if (!(p = calloc(num, len)))
-+ MALLOC_FAILURE_MSG;
-+
-+ return p;
-+}
-+#endif
-+
- #if !defined(LOW_MEMORY)
- #ifdef HAVE_BKTR
- void ast_store_lock_info(enum ast_lock_type type, const char *filename,
-Index: utils/refcounter.c
-===================================================================
---- a/utils/refcounter.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/refcounter.c (.../team/group/issue14292) (revision 178988)
-@@ -69,6 +69,11 @@
- struct rc_hist *last;
- };
-
-+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
-+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
-+{
-+}
-+
- static unsigned int hashtab_hash_rc(const void *obj)
- {
- const struct rc_obj *rc = obj;
-Index: utils/muted.c
-===================================================================
---- a/utils/muted.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/muted.c (.../team/group/issue14292) (revision 178988)
-@@ -35,6 +35,8 @@
- *
- */
-
-+#include "asterisk/autoconfig.h"
-+
- #ifdef __Darwin__
- #include <CoreAudio/AudioHardware.h>
- #elif defined(__linux__) || defined(__FreeBSD__)
-Index: utils/hashtest.c
-===================================================================
---- a/utils/hashtest.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/hashtest.c (.../team/group/issue14292) (revision 178988)
-@@ -50,6 +50,11 @@
- }
- #endif
-
-+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
-+void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used)
-+{
-+}
-+
- struct ht_element
- {
- char *key;
-Index: utils/astcanary.c
-===================================================================
---- a/utils/astcanary.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/astcanary.c (.../team/group/issue14292) (revision 178988)
-@@ -30,7 +30,7 @@
- * At one time, canaries were carried along with coal miners down
- * into a mine. Their purpose was to alert the miners when they
- * had drilled into a pocket of methane gas or another noxious
-- * substance. The canary, being the most sensitive animal would
-+ * substance. The canary, being the most sensitive animal, would
- * immediately fall over. Seeing this, the miners could take
- * action to escape the mine, seeing an imminent danger.
- *
-@@ -57,9 +57,21 @@
- * the same time. This is also why this canary must exist as a
- * completely separate process and not simply as a thread within
- * Asterisk itself.
-+ *
-+ * Quote:
-+ * "The nice value set with setpriority() shall be applied to the
-+ * process. If the process is multi-threaded, the nice value shall
-+ * affect all system scope threads in the process."
-+ *
-+ * Source:
-+ * http://www.opengroup.org/onlinepubs/000095399/functions/setpriority.html
-+ *
-+ * In answer to the question, what aren't system scope threads, the
-+ * answer is, in Asterisk, nothing. Process scope threads are the
-+ * alternative, but they aren't supported in Linux.
- */
-
--const char explanation[] =
-+static const char explanation[] =
- "This file is created when Asterisk is run with a realtime priority (-p). It\n"
- "must continue to exist, and the astcanary process must be allowed to continue\n"
- "running, or else the Asterisk process will, within a short period of time,\n"
-Index: utils/Makefile
-===================================================================
---- a/utils/Makefile (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/utils/Makefile (.../team/group/issue14292) (revision 178988)
-@@ -75,10 +75,11 @@
- rm -f *.s *.i
- rm -f md5.c strcompat.c ast_expr2.c ast_expr2f.c pbx_ael.c pval.c hashtab.c
- rm -f aelparse.c aelbison.c conf2ael
-- rm -f utils.c threadstorage.c sha1.c astobj2.c hashtest2 hashtest refcounter
-+ rm -f utils.c strings.c threadstorage.c sha1.c astobj2.c hashtest2 hashtest refcounter
-
- md5.c: $(ASTTOPDIR)/main/md5.c
-- @cp $< $@
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- md5.o: ASTCFLAGS+=-DSTANDALONE
-
- astman: astman.o md5.o
-@@ -89,38 +90,47 @@
- stereorize: LIBS+=-lm
-
- hashtab.c: $(ASTTOPDIR)/main/hashtab.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
-+
- hashtab.o: ASTCFLAGS+=-DSTANDALONE
-
- strcompat.c: $(ASTTOPDIR)/main/strcompat.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- strcompat.o: ASTCFLAGS+=-DSTANDALONE
-
- pval.c: $(ASTTOPDIR)/res/ael/pval.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- pval.o : ASTCFLAGS+=-DSTANDALONE
-
- ast_expr2.c: $(ASTTOPDIR)/main/ast_expr2.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- ast_expr2.o: ASTCFLAGS+=-DSTANDALONE
-
- ast_expr2f.c: $(ASTTOPDIR)/main/ast_expr2f.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- ast_expr2f.o: ASTCFLAGS+=-DSTANDALONE -I$(ASTTOPDIR)/main -Wno-unused
-
- check_expr: check_expr.o ast_expr2.o ast_expr2f.o strcompat.o threadstorage.o clicompat.o
- check_expr.o: ASTCFLAGS+=-DSTANDALONE
-
- aelbison.c: $(ASTTOPDIR)/res/ael/ael.tab.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- aelbison.o: ASTCFLAGS+=-I$(ASTTOPDIR)/res/ael -DYYENABLE_NLS=0 -DSTANDALONE
-
- pbx_ael.c: $(ASTTOPDIR)/pbx/pbx_ael.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- pbx_ael.o: ASTCFLAGS+=-DSTANDALONE
-
- aelparse.c: $(ASTTOPDIR)/res/ael/ael_lex.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
-
- ael_main.o: ASTCFLAGS+=-DSTANDALONE
-
-@@ -128,28 +138,37 @@
- aelparse: aelparse.o aelbison.o pbx_ael.o hashtab.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
-
- astobj2.c: $(ASTTOPDIR)/main/astobj2.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- astobj2.o: ASTCFLAGS+=-DSTANDALONE
-
- utils.c: $(ASTTOPDIR)/main/utils.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- utils.o: ASTCFLAGS+=-DSTANDALONE
-
-+strings.c: $(ASTTOPDIR)/main/strings.c
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
-+strings.o: ASTCFLAGS+=-DSTANDALONE
-+
- sha1.c: $(ASTTOPDIR)/main/sha1.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- sha1.o: ASTCFLAGS+=-DSTANDALONE
-
- threadstorage.c: $(ASTTOPDIR)/main/threadstorage.c
-- @cp "$<" "$@"
-+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
-+ $(CMD_PREFIX) cp "$<" "$@"
- threadstorage.o: ASTCFLAGS+=-DSTANDALONE
-
- hashtest2.o: ASTCFLAGS+=-O0 -DSTANDALONE
--hashtest2: hashtest2.o md5.o utils.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o
-+hashtest2: hashtest2.o md5.o utils.o strings.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o
-
--hashtest: hashtest.o md5.o hashtab.o utils.o sha1.o strcompat.o threadstorage.o clicompat.o
-+hashtest: hashtest.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o
- hashtest.o: ASTCFLAGS+=-O0 -DSTANDALONE
-
--refcounter: refcounter.o md5.o hashtab.o utils.o sha1.o strcompat.o threadstorage.o clicompat.o
-+refcounter: refcounter.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o
- refcounter.o: ASTCFLAGS+=-O0 -DSTANDALONE
-
- extconf.o: extconf.c
-
-Property changes on: utils
-___________________________________________________________________
-Modified: svn:ignore
- - *.d
-*.i
-*.s
-aelbison.c
-aelparse
-aelparse.c
-ast_expr2.c
-ast_expr2f.c
-astman
-astobj2.c
-check_expr
-conf2ael
-hashtab.c
-hashtest
-hashtest2
-md5.c
-muted
-pbx_ael.c
-pval.c
-sha1.c
-smsq
-stereorize
-strcompat.c
-streamplayer
-threadstorage.c
-utils.c
-astcanary
-refcounter
-
- + *.d
-*.i
-*.s
-aelbison.c
-aelparse
-aelparse.c
-ast_expr2.c
-ast_expr2f.c
-astman
-astobj2.c
-check_expr
-conf2ael
-hashtab.c
-hashtest
-hashtest2
-md5.c
-muted
-pbx_ael.c
-pval.c
-sha1.c
-smsq
-stereorize
-strcompat.c
-streamplayer
-strings.c
-threadstorage.c
-utils.c
-astcanary
-refcounter
-
-
-
-Property changes on: UPGRADE-1.6.txt
-___________________________________________________________________
-Added: svn:mergeinfo
-
-Index: cdr/cdr_pgsql.c
-===================================================================
---- a/cdr/cdr_pgsql.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_pgsql.c (.../team/group/issue14292) (revision 178988)
-@@ -73,37 +73,31 @@
-
- static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
-
--#define LENGTHEN_BUF1(size) \
-- do { \
-- /* Lengthen buffer, if necessary */ \
-- if ((newsize = lensql + (size) + 3) > sizesql) { \
-- if ((tmp = ast_realloc(sql, (newsize / 512 + 1) * 512))) { \
-- sql = tmp; \
-- sizesql = (newsize / 512 + 1) * 512; \
-- } else { \
-+#define LENGTHEN_BUF1(size) \
-+ do { \
-+ /* Lengthen buffer, if necessary */ \
-+ if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \
-+ if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 3) / 512 + 1) * 512) != 0) { \
- ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR failed.\n"); \
-- ast_free(sql); \
-- ast_free(sql2); \
-- AST_RWLIST_UNLOCK(&psql_columns); \
-- return -1; \
-- } \
-- } \
-+ ast_free(sql); \
-+ ast_free(sql2); \
-+ AST_RWLIST_UNLOCK(&psql_columns); \
-+ return -1; \
-+ } \
-+ } \
- } while (0)
-
--#define LENGTHEN_BUF2(size) \
-- do { \
-- if ((newsize = lensql2 + (size) + 3) > sizesql2) { \
-- if ((tmp = ast_realloc(sql2, (newsize / 512 + 1) * 512))) { \
-- sql2 = tmp; \
-- sizesql2 = (newsize / 512 + 1) * 512; \
-- } else { \
-+#define LENGTHEN_BUF2(size) \
-+ do { \
-+ if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \
-+ if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \
- ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR failed.\n"); \
-- ast_free(sql); \
-- ast_free(sql2); \
-- AST_RWLIST_UNLOCK(&psql_columns); \
-- return -1; \
-- } \
-- } \
-+ ast_free(sql); \
-+ ast_free(sql2); \
-+ AST_RWLIST_UNLOCK(&psql_columns); \
-+ return -1; \
-+ } \
-+ } \
- } while (0)
-
- static int pgsql_log(struct ast_cdr *cdr)
-@@ -129,10 +123,10 @@
-
- if (connected) {
- struct columns *cur;
-- int lensql, lensql2, sizesql = maxsize, sizesql2 = maxsize2, newsize;
-- char *sql = ast_calloc(sizeof(char), sizesql), *sql2 = ast_calloc(sizeof(char), sizesql2), *tmp, *value;
-- char buf[257], escapebuf[513];
--
-+ struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
-+ char buf[257], escapebuf[513], *value;
-+ int first = 1;
-+
- if (!sql || !sql2) {
- if (sql) {
- ast_free(sql);
-@@ -143,8 +137,8 @@
- return -1;
- }
-
-- lensql = snprintf(sql, sizesql, "INSERT INTO %s (", table);
-- lensql2 = snprintf(sql2, sizesql2, " VALUES (");
-+ ast_str_set(&sql, 0, "INSERT INTO %s (", table);
-+ ast_str_set(&sql2, 0, " VALUES (");
-
- AST_RWLIST_RDLOCK(&psql_columns);
- AST_RWLIST_TRAVERSE(&psql_columns, cur, list) {
-@@ -157,83 +151,86 @@
- if (cur->notnull && !cur->hasdefault) {
- /* Field is NOT NULL (but no default), must include it anyway */
- LENGTHEN_BUF1(strlen(cur->name) + 2);
-- lensql += snprintf(sql + lensql, sizesql - lensql, "\"%s\",", cur->name);
-+ ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
- LENGTHEN_BUF2(3);
-- strcat(sql2, "'',");
-- lensql2 += 3;
-+ ast_str_append(&sql2, 0, "%s''", first ? "" : ",");
-+ first = 0;
- }
- continue;
- }
-
- LENGTHEN_BUF1(strlen(cur->name) + 2);
-- lensql += snprintf(sql + lensql, sizesql - lensql, "\"%s\",", cur->name);
-+ ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
-
- if (strcmp(cur->name, "start") == 0 || strcmp(cur->name, "calldate") == 0) {
- if (strncmp(cur->type, "int", 3) == 0) {
-- LENGTHEN_BUF2(12);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%ld", cdr->start.tv_sec);
-+ LENGTHEN_BUF2(13);
-+ ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->start.tv_sec);
- } else if (strncmp(cur->type, "float", 5) == 0) {
-- LENGTHEN_BUF2(30);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
-+ LENGTHEN_BUF2(31);
-+ ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->start.tv_sec + (double)cdr->start.tv_usec / 1000000.0);
- } else {
- /* char, hopefully */
-- LENGTHEN_BUF2(30);
-+ LENGTHEN_BUF2(31);
- ast_localtime(&cdr->start, &tm, NULL);
-- lensql2 += ast_strftime(sql2 + lensql2, sizesql2 - lensql2, DATE_FORMAT, &tm);
-+ ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-+ ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
- }
- } else if (strcmp(cur->name, "answer") == 0) {
- if (strncmp(cur->type, "int", 3) == 0) {
-- LENGTHEN_BUF2(12);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%ld", cdr->answer.tv_sec);
-+ LENGTHEN_BUF2(13);
-+ ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->answer.tv_sec);
- } else if (strncmp(cur->type, "float", 5) == 0) {
-- LENGTHEN_BUF2(30);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
-+ LENGTHEN_BUF2(31);
-+ ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->answer.tv_sec + (double)cdr->answer.tv_usec / 1000000.0);
- } else {
- /* char, hopefully */
-- LENGTHEN_BUF2(30);
-+ LENGTHEN_BUF2(31);
- ast_localtime(&cdr->start, &tm, NULL);
-- lensql2 += ast_strftime(sql2 + lensql2, sizesql2 - lensql2, DATE_FORMAT, &tm);
-+ ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-+ ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
- }
- } else if (strcmp(cur->name, "end") == 0) {
- if (strncmp(cur->type, "int", 3) == 0) {
-- LENGTHEN_BUF2(12);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%ld", cdr->end.tv_sec);
-+ LENGTHEN_BUF2(13);
-+ ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", cdr->end.tv_sec);
- } else if (strncmp(cur->type, "float", 5) == 0) {
-- LENGTHEN_BUF2(30);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
-+ LENGTHEN_BUF2(31);
-+ ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec + (double)cdr->end.tv_usec / 1000000.0);
- } else {
- /* char, hopefully */
-- LENGTHEN_BUF2(30);
-+ LENGTHEN_BUF2(31);
- ast_localtime(&cdr->end, &tm, NULL);
-- lensql2 += ast_strftime(sql2 + lensql2, sizesql2 - lensql2, DATE_FORMAT, &tm);
-+ ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
-+ ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
- }
- } else if (strcmp(cur->name, "duration") == 0 || strcmp(cur->name, "billsec") == 0) {
- if (cur->type[0] == 'i') {
- /* Get integer, no need to escape anything */
- ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
-- LENGTHEN_BUF2(12);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%s", value);
-+ LENGTHEN_BUF2(13);
-+ ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
- } else if (strncmp(cur->type, "float", 5) == 0) {
- struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer;
-- LENGTHEN_BUF2(30);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%f", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
-+ LENGTHEN_BUF2(31);
-+ ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
- } else {
- /* Char field, probably */
- struct timeval *when = cur->name[0] == 'd' ? &cdr->start : &cdr->answer;
-- LENGTHEN_BUF2(30);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%f'", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
-+ LENGTHEN_BUF2(31);
-+ ast_str_append(&sql2, 0, "%s'%f'", first ? "" : ",", (double)cdr->end.tv_sec - when->tv_sec + cdr->end.tv_usec / 1000000.0 - when->tv_usec / 1000000.0);
- }
- } else if (strcmp(cur->name, "disposition") == 0 || strcmp(cur->name, "amaflags") == 0) {
- if (strncmp(cur->type, "int", 3) == 0) {
- /* Integer, no need to escape anything */
- ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 1);
-- LENGTHEN_BUF2(12);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%s", value);
-+ LENGTHEN_BUF2(13);
-+ ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", value);
- } else {
- /* Although this is a char field, there are no special characters in the values for these fields */
- ast_cdr_getvar(cdr, cur->name, &value, buf, sizeof(buf), 0, 0);
-- LENGTHEN_BUF2(30);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%s'", value);
-+ LENGTHEN_BUF2(31);
-+ ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", value);
- }
- } else {
- /* Arbitrary field, could be anything */
-@@ -241,20 +238,20 @@
- if (strncmp(cur->type, "int", 3) == 0) {
- long long whatever;
- if (value && sscanf(value, "%lld", &whatever) == 1) {
-- LENGTHEN_BUF2(25);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%lld", whatever);
-+ LENGTHEN_BUF2(26);
-+ ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", whatever);
- } else {
-- LENGTHEN_BUF2(1);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "0");
-+ LENGTHEN_BUF2(2);
-+ ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
- }
- } else if (strncmp(cur->type, "float", 5) == 0) {
- long double whatever;
- if (value && sscanf(value, "%Lf", &whatever) == 1) {
-- LENGTHEN_BUF2(50);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "%30Lf", whatever);
-+ LENGTHEN_BUF2(51);
-+ ast_str_append(&sql2, 0, "%s%30Lf", first ? "" : ",", whatever);
- } else {
-- LENGTHEN_BUF2(1);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "0");
-+ LENGTHEN_BUF2(2);
-+ ast_str_append(&sql2, 0, "%s0", first ? "" : ",");
- }
- /* XXX Might want to handle dates, times, and other misc fields here XXX */
- } else {
-@@ -262,20 +259,16 @@
- PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL);
- else
- escapebuf[0] = '\0';
-- LENGTHEN_BUF2(strlen(escapebuf) + 2);
-- lensql2 += snprintf(sql2 + lensql2, sizesql2 - lensql2, "'%s'", escapebuf);
-+ LENGTHEN_BUF2(strlen(escapebuf) + 3);
-+ ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", escapebuf);
- }
- }
-- LENGTHEN_BUF2(1);
-- strcat(sql2 + lensql2, ",");
-- lensql2++;
-+ first = 0;
- }
- AST_RWLIST_UNLOCK(&psql_columns);
-- LENGTHEN_BUF1(lensql2);
-- sql[lensql - 1] = ')';
-- sql2[lensql2 - 1] = ')';
-- strcat(sql + lensql, sql2);
-- ast_verb(11, "[%s]\n", sql);
-+ LENGTHEN_BUF1(ast_str_strlen(sql2) + 2);
-+ ast_str_append(&sql, 0, ")%s)", ast_str_buffer(sql2));
-+ ast_verb(11, "[%s]\n", ast_str_buffer(sql));
-
- ast_debug(2, "inserting a CDR record.\n");
-
-@@ -303,7 +296,7 @@
- return -1;
- }
- }
-- result = PQexec(conn, sql);
-+ result = PQexec(conn, ast_str_buffer(sql));
- if (PQresultStatus(result) != PGRES_COMMAND_OK) {
- pgerror = PQresultErrorMessage(result);
- ast_log(LOG_ERROR, "Failed to insert call detail record into database!\n");
-@@ -314,7 +307,7 @@
- ast_log(LOG_ERROR, "Connection reestablished.\n");
- connected = 1;
- PQclear(result);
-- result = PQexec(conn, sql);
-+ result = PQexec(conn, ast_str_buffer(sql));
- if (PQresultStatus(result) != PGRES_COMMAND_OK) {
- pgerror = PQresultErrorMessage(result);
- ast_log(LOG_ERROR, "HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n");
-@@ -376,7 +369,7 @@
- struct ast_config *cfg;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if ((cfg = ast_config_load(config, config_flags)) == NULL) {
-+ if ((cfg = ast_config_load(config, config_flags)) == NULL || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load config for PostgreSQL CDR's: %s\n", config);
- return -1;
- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-Index: cdr/cdr_odbc.c
-===================================================================
---- a/cdr/cdr_odbc.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_odbc.c (.../team/group/issue14292) (revision 178988)
-@@ -29,7 +29,7 @@
- */
-
- /*** MODULEINFO
-- <depend>unixodbc</depend>
-+ <depend>generic_odbc</depend>
- <depend>ltdl</depend>
- ***/
-
-@@ -159,7 +159,7 @@
-
- do {
- cfg = ast_config_load(config_file, config_flags);
-- if (!cfg) {
-+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config_file);
- res = AST_MODULE_LOAD_DECLINE;
- break;
-@@ -226,7 +226,7 @@
- }
- } while (0);
-
-- if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED)
-+ if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID)
- ast_config_destroy(cfg);
- return res;
- }
-Index: cdr/cdr_radius.c
-===================================================================
---- a/cdr/cdr_radius.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_radius.c (.../team/group/issue14292) (revision 178988)
-@@ -228,7 +228,7 @@
- int res;
- const char *tmp;
-
-- if ((cfg = ast_config_load(cdr_config, config_flags))) {
-+ if ((cfg = ast_config_load(cdr_config, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
- ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
- ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID);
- ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD);
-Index: cdr/cdr_custom.c
-===================================================================
---- a/cdr/cdr_custom.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_custom.c (.../team/group/issue14292) (revision 178988)
-@@ -67,6 +67,11 @@
- if ((cfg = ast_config_load("cdr_custom.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
- return 0;
-
-+ if (cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "Invalid config file\n");
-+ return 1;
-+ }
-+
- strcpy(format, "");
- strcpy(master, "");
- ast_mutex_lock(&lock);
-Index: cdr/cdr_manager.c
-===================================================================
---- a/cdr/cdr_manager.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_manager.c (.../team/group/issue14292) (revision 178988)
-@@ -62,6 +62,11 @@
- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
- return 0;
-
-+ if (cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_ERROR, "Config file '%s' could not be parsed\n", CONF_FILE);
-+ return 1;
-+ }
-+
- if (reload && customfields) {
- ast_free(customfields);
- }
-@@ -90,7 +95,7 @@
- v = ast_variable_browse(cfg, cat);
- while (v) {
- if (customfields && !ast_strlen_zero(v->name) && !ast_strlen_zero(v->value)) {
-- if( (customfields->used + strlen(v->value) + strlen(v->name) + 14) < customfields->len) {
-+ if ((ast_str_strlen(customfields) + strlen(v->value) + strlen(v->name) + 14) < ast_str_size(customfields)) {
- ast_str_append(&customfields, -1, "%s: ${CDR(%s)}\r\n", v->value, v->name);
- ast_log(LOG_NOTICE, "Added mapping %s: ${CDR(%s)}\n", v->value, v->name);
- } else {
-@@ -140,10 +145,10 @@
-
- buf[0] = 0;
- /* Custom fields handling */
-- if (customfields != NULL && customfields->used > 0) {
-+ if (customfields != NULL && ast_str_strlen(customfields)) {
- memset(&dummy, 0, sizeof(dummy));
- dummy.cdr = cdr;
-- pbx_substitute_variables_helper(&dummy, customfields->str, buf, sizeof(buf) - 1);
-+ pbx_substitute_variables_helper(&dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
- }
-
- manager_event(EVENT_FLAG_CDR, "Cdr",
-Index: cdr/cdr_tds.c
-===================================================================
---- a/cdr/cdr_tds.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_tds.c (.../team/group/issue14292) (revision 178988)
-@@ -426,7 +426,7 @@
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
- cfg = ast_config_load(config, config_flags);
-- if (!cfg) {
-+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_NOTICE, "Unable to load TDS config for CDRs: %s\n", config);
- return 0;
- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-Index: cdr/cdr_csv.c
-===================================================================
---- a/cdr/cdr_csv.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_csv.c (.../team/group/issue14292) (revision 178988)
-@@ -96,7 +96,7 @@
- const char *tmp;
- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-
-- if (!(cfg = ast_config_load(config, config_flags))) {
-+ if (!(cfg = ast_config_load(config, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "unable to load config: %s\n", config);
- return 0;
- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-Index: cdr/cdr_sqlite3_custom.c
-===================================================================
---- a/cdr/cdr_sqlite3_custom.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_sqlite3_custom.c (.../team/group/issue14292) (revision 178988)
-@@ -101,13 +101,10 @@
- ast_free(save);
- return -1;
- }
-- if (!column_string->used)
-- ast_str_set(&column_string, 0, "%s", escaped);
-- else
-- ast_str_append(&column_string, 0, ",%s", escaped);
-+ ast_str_append(&column_string, 0, "%s%s", ast_str_strlen(column_string) ? "," : "", escaped);
- sqlite3_free(escaped);
- }
-- if (!(columns = ast_strdup(column_string->str))) {
-+ if (!(columns = ast_strdup(ast_str_buffer(column_string)))) {
- ast_log(LOG_ERROR, "Out of memory copying columns string for table '%s.'\n", table);
- ast_free(column_string);
- ast_free(save);
-@@ -158,17 +155,16 @@
- struct ast_variable *mappingvar;
- const char *tmp;
-
-- if (!(cfg = ast_config_load(config_file, config_flags))) {
-- if (reload)
-- ast_log(LOG_WARNING, "Failed to reload configuration file.\n");
-- else
-- ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
-+ if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
-+ ast_log(LOG_WARNING, "Failed to %sload configuration file. %s\n", reload ? "re" : "", reload ? "" : "Module not activated.");
- return -1;
-- } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
- return 0;
-+ }
-
-- if (reload)
-+ if (reload) {
- free_config();
-+ }
-
- ast_mutex_lock(&lock);
-
-@@ -180,17 +176,15 @@
- }
-
- /* Mapping must have a table name */
-- tmp = ast_variable_retrieve(cfg, "master", "table");
-- if (!ast_strlen_zero(tmp))
-+ if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, "master", "table"))) {
- ast_copy_string(table, tmp, sizeof(table));
-- else {
-+ } else {
- ast_log(LOG_WARNING, "Table name not specified. Assuming cdr.\n");
- strcpy(table, "cdr");
- }
-
- /* Columns */
-- tmp = ast_variable_retrieve(cfg, "master", "columns");
-- if (load_column_config(tmp)) {
-+ if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) {
- ast_mutex_unlock(&lock);
- ast_config_destroy(cfg);
- free_config();
-@@ -198,8 +192,7 @@
- }
-
- /* Values */
-- tmp = ast_variable_retrieve(cfg, "master", "values");
-- if (load_values_config(tmp)) {
-+ if (load_values_config(ast_variable_retrieve(cfg, "master", "values"))) {
- ast_mutex_unlock(&lock);
- ast_config_destroy(cfg);
- free_config();
-@@ -230,8 +223,9 @@
- columns = NULL;
- }
-
-- while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list)))
-+ while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) {
- ast_free(value);
-+ }
-
- ast_mutex_unlock(&lock);
-
-@@ -253,16 +247,12 @@
- struct ast_str *value_string = ast_str_create(1024);
- dummy.cdr = cdr;
- AST_LIST_TRAVERSE(&sql_values, value, list) {
-- memset(subst_buf, 0, sizeof(subst_buf));
- pbx_substitute_variables_helper(&dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
- escaped = sqlite3_mprintf("%q", subst_buf);
-- if (!value_string->used)
-- ast_str_append(&value_string, 0, "'%s'", escaped);
-- else
-- ast_str_append(&value_string, 0, ",'%s'", escaped);
-+ ast_str_append(&value_string, 0, "%s'%s'", ast_str_strlen(value_string) ? "," : "", escaped);
- sqlite3_free(escaped);
- }
-- sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, value_string->str);
-+ sql = sqlite3_mprintf("INSERT INTO %q (%s) VALUES (%s)", table, columns, ast_str_buffer(value_string));
- ast_debug(1, "About to log: %s\n", sql);
- ast_free(value_string);
- }
-@@ -272,8 +262,9 @@
- /* XXX This seems awful arbitrary... */
- for (count = 0; count < 5; count++) {
- res = sqlite3_exec(db, sql, NULL, NULL, &error);
-- if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
-+ if (res != SQLITE_BUSY && res != SQLITE_LOCKED) {
- break;
-+ }
- usleep(200);
- }
-
-@@ -282,8 +273,9 @@
- sqlite3_free(error);
- }
-
-- if (sql)
-+ if (sql) {
- sqlite3_free(sql);
-+ }
-
- ast_mutex_unlock(&lock);
-
-@@ -313,8 +305,9 @@
- free_config();
- return AST_MODULE_LOAD_DECLINE;
- }
-- } else
-+ } else {
- return AST_MODULE_LOAD_DECLINE;
-+ }
-
- /* is the database there? */
- snprintf(filename, sizeof(filename), "%s/master.db", ast_config_AST_LOG_DIR);
-Index: cdr/cdr_sqlite.c
-===================================================================
---- a/cdr/cdr_sqlite.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_sqlite.c (.../team/group/issue14292) (revision 178988)
-@@ -87,25 +87,27 @@
- #endif
- ");";
-
-+static void format_date(char *buffer, size_t length, struct timeval *when)
-+{
-+ struct ast_tm tm;
-+
-+ ast_localtime(when, &tm, NULL);
-+ ast_strftime(buffer, length, DATE_FORMAT, &tm);
-+}
-+
- static int sqlite_log(struct ast_cdr *cdr)
- {
- int res = 0;
- char *zErr = 0;
-- struct ast_tm tm;
- char startstr[80], answerstr[80], endstr[80];
- int count;
-
- ast_mutex_lock(&sqlite_lock);
-
-- ast_localtime(&cdr->start, &tm, NULL);
-- ast_strftime(startstr, sizeof(startstr), DATE_FORMAT, &tm);
-+ format_date(startstr, sizeof(startstr), &cdr->start);
-+ format_date(answerstr, sizeof(answerstr), &cdr->answer);
-+ format_date(endstr, sizeof(endstr), &cdr->end);
-
-- ast_localtime(&cdr->answer, &tm, NULL);
-- ast_strftime(answerstr, sizeof(answerstr), DATE_FORMAT, &tm);
--
-- ast_localtime(&cdr->end, &tm, NULL);
-- ast_strftime(endstr, sizeof(endstr), DATE_FORMAT, &tm);
--
- for(count=0; count<5; count++) {
- res = sqlite_exec_printf(db,
- "INSERT INTO cdr ("
-Index: cdr/cdr_adaptive_odbc.c
-===================================================================
---- a/cdr/cdr_adaptive_odbc.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/cdr/cdr_adaptive_odbc.c (.../team/group/issue14292) (revision 178988)
-@@ -25,7 +25,8 @@
- */
-
- /*** MODULEINFO
-- <depend>unixodbc</depend>
-+ <depend>generic_odbc</depend>
-+ <depend>ltdl</depend>
- ***/
-
- #include "asterisk.h"
-@@ -57,6 +58,7 @@
- char *name;
- char *cdrname;
- char *filtervalue;
-+ char *staticvalue;
- SQLSMALLINT type;
- SQLINTEGER size;
- SQLSMALLINT decimals;
-@@ -69,6 +71,7 @@
- struct tables {
- char *connection;
- char *table;
-+ unsigned int usegmtime:1;
- AST_LIST_HEAD_NOLOCK(odbc_columns, columns) columns;
- AST_RWLIST_ENTRY(tables) list;
- };
-@@ -86,14 +89,14 @@
- char columnname[80];
- char connection[40];
- char table[40];
-- int lenconnection, lentable;
-+ int lenconnection, lentable, usegmtime = 0;
- SQLLEN sqlptr;
- int res = 0;
- SQLHSTMT stmt = NULL;
- struct ast_flags config_flags = { 0 }; /* Part of our config comes from the database */
-
- cfg = ast_config_load(CONFIG, config_flags);
-- if (!cfg) {
-+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "Unable to load " CONFIG ". No adaptive ODBC CDRs.\n");
- return -1;
- }
-@@ -110,6 +113,10 @@
- ast_copy_string(connection, tmp, sizeof(connection));
- lenconnection = strlen(connection);
-
-+ if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "usegmtime"))) {
-+ usegmtime = ast_true(tmp);
-+ }
-+
- /* When loading, we want to be sure we can connect. */
- obj = ast_odbc_request_obj(connection, 1);
- if (!obj) {
-@@ -146,6 +153,7 @@
- break;
- }
-
-+ tableptr->usegmtime = usegmtime;
- tableptr->connection = (char *)tableptr + sizeof(*tableptr);
- tableptr->table = (char *)tableptr + sizeof(*tableptr) + lenconnection + 1;
- ast_copy_string(tableptr->connection, connection, lenconnection + 1);
-@@ -179,7 +187,7 @@
- }
-
- while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
-- char *cdrvar = "";
-+ char *cdrvar = "", *staticvalue = "";
-
- SQLGetData(stmt, 4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
-
-@@ -195,10 +203,19 @@
- cdrvar = ast_strip(alias);
- ast_verb(3, "Found alias %s for column %s in %s@%s\n", cdrvar, columnname, tableptr->table, tableptr->connection);
- break;
-+ } else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, columnname) == 0) {
-+ char *item = ast_strdupa(var->name + 6);
-+ item = ast_strip(item);
-+ if (item[0] == '"' && item[strlen(item) - 1] == '"') {
-+ /* Remove surrounding quotes */
-+ item[strlen(item) - 1] = '\0';
-+ item++;
-+ }
-+ staticvalue = item;
- }
- }
-
-- entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1 + strlen(cdrvar) + 1);
-+ entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1 + strlen(cdrvar) + 1 + strlen(staticvalue) + 1);
- if (!entry) {
- ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, table, connection);
- res = -1;
-@@ -210,9 +227,15 @@
- if (!ast_strlen_zero(cdrvar)) {
- entry->cdrname = entry->name + strlen(columnname) + 1;
- strcpy(entry->cdrname, cdrvar);
-- } else /* Point to same place as the column name */
-+ } else { /* Point to same place as the column name */
- entry->cdrname = (char *)entry + sizeof(*entry);
-+ }
-
-+ if (!ast_strlen_zero(staticvalue)) {
-+ entry->staticvalue = entry->cdrname + strlen(entry->cdrname) + 1;
-+ strcpy(entry->staticvalue, staticvalue);
-+ }
-+
- SQLGetData(stmt, 5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
- SQLGetData(stmt, 7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
- SQLGetData(stmt, 9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
-@@ -293,8 +316,8 @@
- #define LENGTHEN_BUF1(size) \
- do { \
- /* Lengthen buffer, if necessary */ \
-- if (sql->used + size + 1 > sql->len) { \
-- if (ast_str_make_space(&sql, ((sql->len + size + 1) / 512 + 1) * 512) != 0) { \
-+ if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \
-+ if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 1) / 512 + 1) * 512) != 0) { \
- ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
- ast_free(sql); \
- ast_free(sql2); \
-@@ -306,8 +329,8 @@
-
- #define LENGTHEN_BUF2(size) \
- do { \
-- if (sql2->used + size + 1 > sql2->len) { \
-- if (ast_str_make_space(&sql2, ((sql2->len + size + 3) / 512 + 1) * 512) != 0) { \
-+ if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \
-+ if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \
- ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
- ast_free(sql); \
- ast_free(sql2); \
-@@ -344,21 +367,38 @@
- }
-
- AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
-+ int first = 1;
- ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
- ast_str_set(&sql2, 0, " VALUES (");
-
- /* No need to check the connection now; we'll handle any failure in prepare_and_execute */
- if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) {
-- ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str);
-+ ast_log(LOG_WARNING, "cdr_adaptive_odbc: Unable to retrieve database handle for '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
- continue;
- }
-
- AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) {
-+ int datefield = 0;
-+ if (strcasecmp(entry->cdrname, "start") == 0) {
-+ datefield = 1;
-+ } else if (strcasecmp(entry->cdrname, "answer") == 0) {
-+ datefield = 2;
-+ } else if (strcasecmp(entry->cdrname, "end") == 0) {
-+ datefield = 3;
-+ }
-+
- /* Check if we have a similarly named variable */
-- ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0,
-- (strcasecmp(entry->cdrname, "start") == 0 ||
-- strcasecmp(entry->cdrname, "answer") == 0 ||
-- strcasecmp(entry->cdrname, "end") == 0) ? 0 : 1);
-+ if (entry->staticvalue) {
-+ colptr = ast_strdupa(entry->staticvalue);
-+ } else if (datefield && tableptr->usegmtime) {
-+ struct timeval date_tv = (datefield == 1) ? cdr->start : (datefield == 2) ? cdr->answer : cdr->end;
-+ struct ast_tm tm = { 0, };
-+ ast_localtime(&date_tv, &tm, "UTC");
-+ ast_strftime(colbuf, sizeof(colbuf), "%Y-%m-%d %H:%M:%S", &tm);
-+ colptr = colbuf;
-+ } else {
-+ ast_cdr_getvar(cdr, entry->cdrname, &colptr, colbuf, sizeof(colbuf), 0, datefield ? 0 : 1);
-+ }
-
- if (colptr) {
- /* Check first if the column filters this entry. Note that this
-@@ -389,22 +429,24 @@
- /* For these two field names, get the rendered form, instead of the raw
- * form (but only when we're dealing with a character-based field).
- */
-- if (strcasecmp(entry->name, "disposition") == 0)
-+ if (strcasecmp(entry->name, "disposition") == 0) {
- ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
-- else if (strcasecmp(entry->name, "amaflags") == 0)
-+ } else if (strcasecmp(entry->name, "amaflags") == 0) {
- ast_cdr_getvar(cdr, entry->name, &colptr, colbuf, sizeof(colbuf), 0, 0);
-+ }
-
- /* Truncate too-long fields */
- if (entry->type != SQL_GUID) {
-- if (strlen(colptr) > entry->octetlen)
-+ if (strlen(colptr) > entry->octetlen) {
- colptr[entry->octetlen] = '\0';
-+ }
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(strlen(colptr));
-
- /* Encode value, with escaping */
-- ast_str_append(&sql2, 0, "'");
-+ ast_str_append(&sql2, 0, "%s'", first ? "" : ",");
- for (tmp = colptr; *tmp; tmp++) {
- if (*tmp == '\'') {
- ast_str_append(&sql2, 0, "''");
-@@ -414,7 +456,7 @@
- ast_str_append(&sql2, 0, "%c", *tmp);
- }
- }
-- ast_str_append(&sql2, 0, "',");
-+ ast_str_append(&sql2, 0, "'");
- break;
- case SQL_TYPE_DATE:
- {
-@@ -427,15 +469,16 @@
- (month == 2 && year % 4 == 0 && day > 29) ||
- (month == 2 && year % 4 != 0 && day > 28)) {
- ast_log(LOG_WARNING, "CDR variable %s is not a valid date ('%s').\n", entry->name, colptr);
-- break;
-+ continue;
- }
-
-- if (year > 0 && year < 100)
-+ if (year > 0 && year < 100) {
- year += 2000;
-+ }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(17);
-- ast_str_append(&sql2, 0, "{ d '%04d-%02d-%02d' },", year, month, day);
-+ ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", first ? "" : ",", year, month, day);
- }
- break;
- case SQL_TYPE_TIME:
-@@ -445,12 +488,12 @@
-
- if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
- ast_log(LOG_WARNING, "CDR variable %s is not a valid time ('%s').\n", entry->name, colptr);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(15);
-- ast_str_append(&sql2, 0, "{ t '%02d:%02d:%02d' },", hour, minute, second);
-+ ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", first ? "" : ",", hour, minute, second);
- }
- break;
- case SQL_TYPE_TIMESTAMP:
-@@ -468,15 +511,16 @@
- (month == 2 && year % 4 != 0 && day > 28) ||
- hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
- ast_log(LOG_WARNING, "CDR variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
-- break;
-+ continue;
- }
-
-- if (year > 0 && year < 100)
-+ if (year > 0 && year < 100) {
- year += 2000;
-+ }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(26);
-- ast_str_append(&sql2, 0, "{ ts '%04d-%02d-%02d %02d:%02d:%02d' },", year, month, day, hour, minute, second);
-+ ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", first ? "" : ",", year, month, day, hour, minute, second);
- }
- break;
- case SQL_INTEGER:
-@@ -484,12 +528,12 @@
- int integer = 0;
- if (sscanf(colptr, "%d", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(12);
-- ast_str_append(&sql2, 0, "%d,", integer);
-+ ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
- }
- break;
- case SQL_BIGINT:
-@@ -497,12 +541,12 @@
- long long integer = 0;
- if (sscanf(colptr, "%lld", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(24);
-- ast_str_append(&sql2, 0, "%lld,", integer);
-+ ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", integer);
- }
- break;
- case SQL_SMALLINT:
-@@ -510,12 +554,12 @@
- short integer = 0;
- if (sscanf(colptr, "%hd", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(6);
-- ast_str_append(&sql2, 0, "%d,", integer);
-+ ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
- }
- break;
- case SQL_TINYINT:
-@@ -523,12 +567,12 @@
- char integer = 0;
- if (sscanf(colptr, "%hhd", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(4);
-- ast_str_append(&sql2, 0, "%d,", integer);
-+ ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
- }
- break;
- case SQL_BIT:
-@@ -536,14 +580,14 @@
- char integer = 0;
- if (sscanf(colptr, "%hhd", &integer) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an integer.\n", entry->name);
-- break;
-+ continue;
- }
- if (integer != 0)
- integer = 1;
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(2);
-- ast_str_append(&sql2, 0, "%d,", integer);
-+ ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
- }
- break;
- case SQL_NUMERIC:
-@@ -552,12 +596,12 @@
- double number = 0.0;
- if (sscanf(colptr, "%lf", &number) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(entry->decimals);
-- ast_str_append(&sql2, 0, "%*.*lf,", entry->decimals, entry->radix, number);
-+ ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number);
- }
- break;
- case SQL_FLOAT:
-@@ -567,35 +611,37 @@
- double number = 0.0;
- if (sscanf(colptr, "%lf", &number) != 1) {
- ast_log(LOG_WARNING, "CDR variable %s is not an numeric type.\n", entry->name);
-- break;
-+ continue;
- }
-
-- ast_str_append(&sql, 0, "%s,", entry->name);
-+ ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
- LENGTHEN_BUF2(entry->decimals);
-- ast_str_append(&sql2, 0, "%lf,", number);
-+ ast_str_append(&sql2, 0, "%s%lf", first ? "" : ",", number);
- }
- break;
- default:
- ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
-+ continue;
- }
-+ first = 0;
- }
- }
-
- /* Concatenate the two constructed buffers */
-- LENGTHEN_BUF1(sql2->used);
-- sql->str[sql->used - 1] = ')';
-- sql2->str[sql2->used - 1] = ')';
-- ast_str_append(&sql, 0, "%s", sql2->str);
-+ LENGTHEN_BUF1(ast_str_strlen(sql2));
-+ ast_str_append(&sql, 0, ")");
-+ ast_str_append(&sql2, 0, ")");
-+ ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2));
-
-- ast_verb(11, "[%s]\n", sql->str);
-+ ast_verb(11, "[%s]\n", ast_str_buffer(sql));
-
-- stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql->str);
-+ stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql));
- if (stmt) {
- SQLRowCount(stmt, &rows);
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- }
- if (rows == 0) {
-- ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, sql->str);
-+ ast_log(LOG_WARNING, "cdr_adaptive_odbc: Insert failed on '%s:%s'. CDR failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
- }
- early_release:
- ast_odbc_release_obj(obj);
-@@ -603,10 +649,12 @@
- AST_RWLIST_UNLOCK(&odbc_tables);
-
- /* Next time, just allocate buffers that are that big to start with. */
-- if (sql->used > maxsize)
-- maxsize = sql->used;
-- if (sql2->used > maxsize2)
-- maxsize2 = sql2->used;
-+ if (ast_str_strlen(sql) > maxsize) {
-+ maxsize = ast_str_strlen(sql);
-+ }
-+ if (ast_str_strlen(sql2) > maxsize2) {
-+ maxsize2 = ast_str_strlen(sql2);
-+ }
-
- ast_free(sql);
- ast_free(sql2);
-Index: formats/format_siren7.c
-===================================================================
---- a/formats/format_siren7.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/formats/format_siren7.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,138 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 1999 - 2008, Anthony Minessale and Digium, Inc.
-+ * Anthony Minessale (anthmct@yahoo.com)
-+ * Kevin P. Fleming <kpfleming@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief ITU G.722.1 (Siren7, licensed from Polycom) format, 32kbps bitrate only
-+ * \arg File name extensions: siren7
-+ * \ingroup formats
-+ */
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/mod_format.h"
-+#include "asterisk/module.h"
-+#include "asterisk/endian.h"
-+
-+#define BUF_SIZE 80 /* 20 milliseconds == 80 bytes, 320 samples */
-+#define SAMPLES_TO_BYTES(x) x / (320 / 80)
-+#define BYTES_TO_SAMPLES(x) x * (320 / 80)
-+
-+static struct ast_frame *siren7read(struct ast_filestream *s, int *whennext)
-+{
-+ int res;
-+ /* Send a frame from the file to the appropriate channel */
-+
-+ s->fr.frametype = AST_FRAME_VOICE;
-+ s->fr.subclass = AST_FORMAT_SIREN7;
-+ s->fr.mallocd = 0;
-+ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
-+ if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
-+ if (res)
-+ ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
-+ return NULL;
-+ }
-+ *whennext = s->fr.samples = BYTES_TO_SAMPLES(res);
-+ return &s->fr;
-+}
-+
-+static int siren7write(struct ast_filestream *fs, struct ast_frame *f)
-+{
-+ int res;
-+
-+ if (f->frametype != AST_FRAME_VOICE) {
-+ ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
-+ return -1;
-+ }
-+ if (f->subclass != AST_FORMAT_SIREN7) {
-+ ast_log(LOG_WARNING, "Asked to write non-Siren7 frame (%d)!\n", f->subclass);
-+ return -1;
-+ }
-+ if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
-+ ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static int siren7seek(struct ast_filestream *fs, off_t sample_offset, int whence)
-+{
-+ off_t offset = 0, min = 0, cur, max;
-+
-+ sample_offset = SAMPLES_TO_BYTES(sample_offset);
-+
-+ cur = ftello(fs->f);
-+
-+ fseeko(fs->f, 0, SEEK_END);
-+
-+ max = ftello(fs->f);
-+
-+ if (whence == SEEK_SET)
-+ offset = sample_offset;
-+ else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
-+ offset = sample_offset + cur;
-+ else if (whence == SEEK_END)
-+ offset = max - sample_offset;
-+
-+ if (whence != SEEK_FORCECUR)
-+ offset = (offset > max) ? max : offset;
-+
-+ /* always protect against seeking past begining. */
-+ offset = (offset < min) ? min : offset;
-+
-+ return fseeko(fs->f, offset, SEEK_SET);
-+}
-+
-+static int siren7trunc(struct ast_filestream *fs)
-+{
-+ return ftruncate(fileno(fs->f), ftello(fs->f));
-+}
-+
-+static off_t siren7tell(struct ast_filestream *fs)
-+{
-+ return BYTES_TO_SAMPLES(ftello(fs->f));
-+}
-+
-+static const struct ast_format siren7_f = {
-+ .name = "siren7",
-+ .exts = "siren7",
-+ .format = AST_FORMAT_SIREN7,
-+ .write = siren7write,
-+ .seek = siren7seek,
-+ .trunc = siren7trunc,
-+ .tell = siren7tell,
-+ .read = siren7read,
-+ .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
-+};
-+
-+static int load_module(void)
-+{
-+ if (ast_format_register(&siren7_f))
-+ return AST_MODULE_LOAD_DECLINE;
-+
-+ return AST_MODULE_LOAD_SUCCESS;
-+}
-+
-+static int unload_module(void)
-+{
-+ return ast_format_unregister(siren7_f.name);
-+}
-+
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ITU G.722.1 (Siren7, licensed from Polycom)");
-
-Property changes on: formats/format_siren7.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-Index: formats/format_ilbc.c
-===================================================================
---- a/formats/format_ilbc.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/formats/format_ilbc.c (.../team/group/issue14292) (revision 178988)
-@@ -24,7 +24,7 @@
- * \arg File name extension: ilbc
- * \ingroup formats
- */
--
-+
- #include "asterisk.h"
-
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-Index: formats/format_pcm.c
-===================================================================
---- a/formats/format_pcm.c (.../tags/1.6.1-rc1) (revision 178988)
-+++ b/formats/format_pcm.c (.../team/group/issue14292) (revision 178988)
-@@ -415,7 +415,7 @@
-
- static const struct ast_format alaw_f = {
- .name = "alaw",
-- .exts = "alaw|al",
-+ .exts = "alaw|al|alw",
- .format = AST_FORMAT_ALAW,
- .write = pcm_write,
- .seek = pcm_seek,
-@@ -432,7 +432,7 @@
-
- static const struct ast_format pcm_f = {
- .name = "pcm",
-- .exts = "pcm|ulaw|ul|mu",
-+ .exts = "pcm|ulaw|ul|mu|ulw",
- .format = AST_FORMAT_ULAW,
- .write = pcm_write,
- .seek = pcm_seek,
-Index: formats/format_siren14.c
-===================================================================
---- a/formats/format_siren14.c (.../tags/1.6.1-rc1) (revision 0)
-+++ b/formats/format_siren14.c (.../team/group/issue14292) (revision 178988)
-@@ -0,0 +1,139 @@
-+/*
-+ * Asterisk -- An open source telephony toolkit.
-+ *
-+ * Copyright (C) 1999 - 2008, Anthony Minessale and Digium, Inc.
-+ * Anthony Minessale (anthmct@yahoo.com)
-+ * Kevin P. Fleming <kpfleming@digium.com>
-+ *
-+ * See http://www.asterisk.org for more information about
-+ * the Asterisk project. Please do not directly contact
-+ * any of the maintainers of this project for assistance;
-+ * the project provides a web site, mailing lists and IRC
-+ * channels for your use.
-+ *
-+ * This program is free software, distributed under the terms of
-+ * the GNU General Public License Version 2. See the LICENSE file
-+ * at the top of the source tree.
-+ */
-+
-+/*! \file
-+ *
-+ * \brief ITU G.722.1 Annex C (Siren14, licensed from Polycom) format, 48kbps bitrate only
-+ * \arg File name extensions: siren14
-+ * \ingroup formats
-+ */
-+
-+#include "asterisk.h"
-+
-+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-+
-+#include "asterisk/mod_format.h"
-+#include "asterisk/module.h"
-+#include "asterisk/endian.h"
-+
-+#define BUF_SIZE 120 /* 20 milliseconds == 120 bytes, 640 samples */
-+#define SAMPLES_TO_BYTES(x) ((typeof(x)) x / ((float) 640 / 120))
-+#define BYTES_TO_SAMPLES(x) ((typeof(x)) x * ((float) 640 / 120))
-+
-+static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext)
-+{
-+ int res;
-+ /* Send a frame from the file to the appropriate channel */
-+
-+ s->fr.frametype = AST_FRAME_VOICE;
-+ s->fr.subclass = AST_FORMAT_SIREN14;
-+ s->fr.mallocd = 0;
-+ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
-+ if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
-+ if (res)
-+ ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
-+ return NULL;
-+ }
-+ *whennext = s->fr.samples = BYTES_TO_SAMPLES(res);
-+ ast_log(LOG_DEBUG, "Read frame of %d bytes and %d samples\n", res, s->fr.samples);
-+ return &s->fr;
-+}
-+
-+static int siren14write(struct ast_filestream *fs, struct ast_frame *f)
-+{
-+ int res;
-+
-+ if (f->frametype != AST_FRAME_VOICE) {
-+ ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
-+ return -1;
-+ }
-+ if (f->subclass != AST_FORMAT_SIREN14) {
-+ ast_log(LOG_WARNING, "Asked to write non-Siren14 frame (%d)!\n", f->subclass);
-+ return -1;
-+ }
-+ if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
-+ ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static int siren14seek(struct ast_filestream *fs, off_t sample_offset, int whence)
-+{
-+ off_t offset = 0, min = 0, cur, max;
-+
-+ sample_offset = SAMPLES_TO_BYTES(sample_offset);
-+
-+ cur = ftello(fs->f);
-+
-+ fseeko(fs->f, 0, SEEK_END);
-+
-+ max = ftello(fs->f);
-+
-+ if (whence == SEEK_SET)
-+ offset = sample_offset;
-+ else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
-+ offset = sample_offset + cur;
-+ else if (whence == SEEK_END)
-+ offset = max - sample_offset;
-+
-+ if (whence != SEEK_FORCECUR)
-+ offset = (offset > max) ? max : offset;
-+
-+ /* always protect against seeking past begining. */
-+ offset = (offset < min) ? min : offset;
-+
-+ return fseeko(fs->f, offset, SEEK_SET);
-+}
-+
-+static int siren14trunc(struct ast_filestream *fs)
-+{
-+ return ftruncate(fileno(fs->f), ftello(fs->f));
-+}
-+
-+static off_t siren14tell(struct ast_filestream *fs)
-+{
-+ return BYTES_TO_SAMPLES(ftello(fs->f));
-+}
-+
-+static const struct ast_format siren14_f = {
-+ .name = "siren14",
-+ .exts = "siren14",
-+ .format = AST_FORMAT_SIREN14,
-+ .write = siren14write,
-+ .seek = siren14seek,
-+ .trunc = siren14trunc,
-+ .tell = siren14tell,
-+ .read = siren14read,
-+ .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
-+};
-+
-+static int load_module(void)
-+{
-+ if (ast_format_register(&siren14_f))
-+ return AST_MODULE_LOAD_DECLINE;
-+
-+ return AST_MODULE_LOAD_SUCCESS;
-+}
-+
-+static int unload_module(void)
-+{
-+ return ast_format_unregister(siren14_f.name);
-+}
-+
-+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ITU G.722.1 Annex C (Siren14, licensed from Polycom)");
-
-Property changes on: formats/format_siren14.c
-___________________________________________________________________
-Added: svn:eol-style
- + native
-Added: svn:mime-type
- + text/plain
-Added: svn:keywords
- + Author Date Id Revision
-
-
-Property changes on: .
-___________________________________________________________________
-Deleted: trunk-blocked
- - /trunk:137901,138851,139020,139525,139704,139771,139775,139832,139981,140057,140167,140201,140355,140559,140821,140938,141218,141271,141328,141425,141464,141507,141626,141906,142000,142146,142536,142635,142992,143034,143799,144199,144759,145027,145226,145381,145649,145842,145846,145915,146081,146245,146359,146597,146640,146738,146925,147262,148325,148329,148988,148991,150253,150255,150307,150309,150311,150384,150729,151554-151555,152174,152727,152807,152875,152879,152990,153057,153124,153223,153296,153403,153435,153437,153468,153470,153472,153507,153541,153543,153578,153580,153582,153617-153618,153747,153803,153852,153947,154149,154151,154186-154187,154191,154225,154260,154329,154429,154467,154469,154507,154542,154578,154615,154617,154647,154732,154796,154798,154801,154837,154839,154915,154922-154923,154926,154967,155066,155079-155080,155175,155204,155206,155282,155284,155401,155590,155637,155711,155967,156017-156018,156051,156087,156120,156125,156162,156355,156535,156541,156575,156647,156916,156918,157073,157167,157460-157461,157463,157564,157739,157818,157870,157893,158061,158307,158686,158690,158723,158754,158756,158808,158959,159054,159250,159629,159631,159734,159774,160062,160344,160346,160447,160562,160585,160896,160938,161077,161115,161218,161536,161571,161604,161637,161869,161947,162418,162542,162660,162672,162687,162923,163037,163166,163198,163582,163716,163951-163952,164083,164137,164205,164208,164309,164344,164415,164417,164428,164485,164565,164733,164809,164814,164821,165326,165397,165433,165502,165538,165798,165883,165886,165954,166158,166731,166823,167021,167057,167125,167792,167837,167888,167973,168265,168575,168579,168585,168591,168599,168601,168626,168719,168732,168734,168898,169438,169798,170307,170460,170498,170902,171043,171081,171757,171797
-Deleted: trunk-merged
- - /trunk:1-137647,137680,137732,137780,137812,137848,137933,137987,138024,138028,138086,138124,138148,138155,138207,138260,138311,138361,138409,138412,138442,138473,138476,138479,138482,138518,138631,138687,138694,138775,138778-138780,138815,138845,138887,138943,139016,139083,139210,139215,139391,139457,139469,139554,139558,139563,139622,139624,139627,139662,139707,139770,139870,139915,139928,140053,140061,140169,140205,140301,140418,140422,140433,140489,140491,140563,140566,140606,140691-140692,140749,140752,140817,140824,140860,140887,140975,141039,141115,141157,141367,141504,141566,141682,141745,141807,141810,141868,141949,141995,141998,142064,142080,142219,142355,142359,142417,142475,142576,142676,142741,142745,142748,142866,142929,143031,143082,143141,143340,143405,143559,143609,143737,143837,143840,143843,143904,144025,144067,144149,144482,144523,144563,144569,144635,144678,144681,144829,144879,144949-144951,145076,145249,145428,145487,145553,145579,145606,145692,145752,145771,145959,145962,146198,146242,146312,146449,146555,146644,146713,146802,146807,146875,146877,146883,146920,146923,146928,146970,147011,147050,147146,147194,147518,147592,147689,147807,147896,147899,147952,148000,148010,148112,148120,148144,148160,148200,148268,148373,148376,148471,148519,148612,148695,148738,148754,148868,148913,148917,148985,149040,149062,149131,149199,149201,149205,149208,149271,149279,149384,149487,149588,149637,149640,149687,149756,149918,149920,149981,150125,150207,150210,150257,150302,150305,150580,150635,150817,151101,151242-151243,151327,151371,151420,151428,151439,151464,151512,151600-151601,151906,152020,152060,152132,152134,152216,152287,152369,152442,152467,152536,152569,152605,152646,152689,152765,152812,152877,152887,152915,152920,152923,152969,152993,153122,153181,153362,153616,153650,153652,154023,154061,154072,154264,154268,154366,154428,154687,154919,155012,155121,155241,155244,155264,155324,155360,155395,155399,155467,155513,155516,155554,155671,155763,155804,155862-155863,156127,156166,156169,156228,156243,156290,156295,156299,156388,156612,156649,156690,156756,156817,156911,156962,157039,157041,157105,157164,157253,157302,157306,157366,157427,157496,157512,157562,157592,157600,157632,157639,157706,157743,157784,158062,158066,158072,158082,158133,158188,158230,158262,158265-158266,158374,158414,158449,158484,158540,158602,158606,158688,158694,158851,158857,158876,158924-158925,158992,159050,159093,159247,159276,159360,159402,159437,159475,159534,159554,159774,159818,159853,159898,159911,160004,160097,160170-160172,160208,160308,160319,160333,160481,160552,160555,160559,160626,160663,160699-160700,160760,160791,160854,160856,160945,161014,161147,161181,161252,161288,161349-161350,161427,161493,161721,161726,161787,161790,161830,161951,162016,162079,162140,162197,162205,162266,162271,162275,162291,162342,162355,162414,162466,162488,162583,162619,162656,162664,162667,162739,162805,162891,162922,162924-162930,162997,163081,163085,163089,163094,163168,163171,163213,163241,163254,163317,163384,163449,163512,163579,163612,163629,163642,163667,163670,163675,163762,163829,163873,163912,164203,164257,164268,164270,164272,164312,164349,164351,164419,164423,164519,164522,164525,164602,164606,164623,164648,164659,164675,164737,164798,164801,164807,164877,164882,164942,164978,165071,165142-165143,165216,165219,165254,165318,165325,165330,165541,165599,165658,165662,165723-165724,165792,165797,165801,165890,166092-166095,166162,166258,166267-166268,166273,166282,166317,166342,166377,166382,166436,166470,166533,166569,166665,166696,166773,166861,166908,166954,167176,167180,167265,167301,167373,167442,167477-167478,167542,167546,167555,167569,167662,167700,167720,167835,167894,167935,168014,168090,168142,168192-168193,168200,168270,168334,168481,168486,168497,168508,168517,168523,168526,168547,168562,168578,168588,168594,168604,168610,168613,168615,168623,168629,168705,168711-168712,168722,168725,168737,168746,168832,168941,168976,169044,169080,169211,169365,169486,169510,169557,169574,169611,169620,169625,169673,169723,169791,169793-169794,169869,169944,170047,170051,170148,170165,170240,170393,170501,170505,170569,170608,170652,170677,170720,170790,170794,170837,170943,170980,171188,171326,171528,171618,171622,171691,171964,172063,172131
-Added: automerge
- + *
-Added: branch-1.4-blocked
- + /branches/1.4:43484,43510,43582,43626,43703,43756,44023,44080,44109,44407,44409,44567,44650,44660-44662,44665,44746,44760,44776-44777,44805,44992,45246,45313-45314,45381,45464,46114-46117,46165,46214,46253,46255,46401,46431,46583,46716,46883,47107-47108,47323,47329,47344,47348,47369,47444,47542,47553,47558,47564,47573,47576,47613,47736,47762,47856,47892,48046,48147,48162,48195,48234,48270,48281,48561,48583,48931,49022,49024,49032,49035,49070,49096,49189,49212,49282,49388,49710,50186,50921,51245,51755,51895,52000,52158,52373,52535,52809,52856,53077,53086,53099,53818,53878,54026,56006,56922,57591,58939,58955,59042,59069-59070,59230,60709,61220,62095,62299,62739,62913,63283,63656,64280,64565,64605,65394,65452,66068,66160,66244,66312,66602,66637,67018,67372,72453,72462,72493,72554,72597,72599,72665,73143,74262,74628,74839,75437,75439,75447,75712,75980,76054,76176,76178,76227,76891,77871,78146,78416,78620,78826,78860,80086,80088,80167,80497,80689,80747,81375,81492,82198,82276,82398,83400,83653,84163,84437,84544,85397,85536,85548,85687,85717,85852,86028,86371-86372,86406,87067,87340,87534,88471,89111,89191,89254,89339,89616,89727,89999,90147,90546,90798,91032,91501,92200,92510,93000,93183,93420,93764,94466,94543,94765,94769,94831,96020,96022,96024,97206,98025,98082,98265,98734,98849,98972-98973,98982,99127,99878,100418,100673,100934,101820,102653,103503,103556,103607,103698,103701,103703,103709,103713,103768,103807,104026-104027,104111,104332,104591,105591,107472,107582,109057,109171,109393,110880,112689,112709,113507,114032,114072,114167,114173,114180,114211,114248,114297,114299,114522,114542,114545,114550,114649,115257,115517,117523,117809,118055,119076,120061,120371,120671,120731,121992,122208,122314,122613,122663,124743,124908,125530,125893,126395,126680,127069,127501,127754,128029,128637,129158,129208,129505,130042,130298,130317,130373,131480,132042,132784,132787,132974,133237,133709,134652,134704,134976,136238,136304,136348,136404,136458,136560,137348,137527,137529,137580,137677,137850,138309,138516,138569,138938,138949,139145,139521,139769,140050,140115,141217,141267,141678,143204,143270,143475,143674,143964,144420,144758,145839,146129,146244,147941,148990,149840,150557,150816,151100,151167,151763,154724,158306,158629,159158,159571,160570,160764,162071,162670-162671,163785,164082,164204,164343,165537,165991,166157,166262,166592,168598,169581,169797,171120,171122,171452,172639,173248,173770,173900,174644,174885,175407,175698,177160,177450,177696,178640,178838
-Added: branch-1.4-merged
- + /branches/1.4:1-43376,43383,43386,43388,43392,43396,43405,43410,43422,43441,43445,43450,43454,43456,43464,43466,43469,43477,43482,43486,43489,43492,43518,43524,43553,43564,43616,43635-43702,43704-43755,43757-43800,43802-43846,43852,43861-43862,43864,43873,43877,43893,43898-43899,43913,43915,43918-43919,43933,43944,43952,43978,43993,43996-44012,44022,44034-44043,44053,44055,44057,44068,44078,44090,44111,44125,44135,44166-44167,44169,44186,44199,44215,44283-44286,44298,44312,44322,44378,44390,44393,44433,44436,44450,44476,44486,44502,44559,44561-44563,44581,44605,44628,44631,44684,44759,44764,44786,44788,44806,44808-44809,44819,44888,44911,44921,44942,44945,44956,44971,44982,44994,45026-45027,45031,45040,45049,45051,45066,45079,45088,45104,45106,45125,45196,45213,45262,45280,45327,45378,45408,45410,45439,45441,45452,45517,45595,45622,45646,45678,45692,45694,45741,45775,45817-45818,45916,45928,45999,46065,46067,46078,46080,46082-46113,46118-46141,46143-46154,46200,46216,46237,46249,46252,46276,46298,46329,46347,46351-46353,46358,46363,46367,46370,46377,46382,46389,46398,46403,46407,46433,46474,46506,46511,46526,46554,46558,46561,46563,46606,46628,46631,46714,46744,46775,46778,46780,46822,46845,46847,46857,46901,46930,46937,46965,46992,47015,47051,47053,47192,47195-47196,47199,47239,47250,47268,47279,47284,47287,47309,47327,47331,47333,47352,47366,47372,47375,47377,47380,47391,47398,47405,47414,47418,47432-47433,47436,47454,47457,47463,47466,47474,47476,47492,47494,47497,47507,47509,47511,47513,47523,47526-47527,47540,47551,47572,47581,47584,47597,47617,47621,47625,47628,47632,47635,47639,47641,47645,47656,47684,47690,47693,47698,47701,47707,47709,47712,47733,47744,47748,47751,47755,47758,47764,47777,47782,47823,47843,47845,47850,47852,47860,47864-47865,47897,47944,47959,47989,47992,48002,48015,48017,48031,48038,48049,48054,48088,48095,48101,48105,48107,48113,48115,48129,48135,48143,48152,48155,48158,48166,48168,48177,48179,48186,48190,48193,48199,48219,48223,48228,48230,48248,48252,48254,48264,48279,48317,48323,48326,48349,48357,48363,48372,48375,48377,48379,48381-48382,48391,48396,48399,48401,48427,48461,48472,48478,48481,48487,48502,48504,48506,48513,48521,48525,48528,48548,48554,48564,48571,48577,48586,48592,48596,48637,48783,48870,48888,48906,48944,48948,48956,48960,48964,48966,48975,48977,48980,48982,48985,48987-48988,48993,48995,48997,49006,49009,49024,49028,49046,49061,49063,49066,49073,49098-49099,49102,49145,49165,49237,49259,49313,49355,49413,49457-49461,49465,49523,49536,49551,49553,49581,49600,49636,49680,49705,49712,49714-49715,49742,49831,49834,49866,49890,49925,49945,49983,50006,50032,50073,50098,50124,50151,50228,50266,50298,50346,50377,50405,50433,50466,50468,50562,50602,50647,50674,50727,50754,50782,50820,50867,50895,50957,50994,51030,51057,51087,51146,51148,51150,51159,51162,51165,51167,51170,51172,51176,51182,51186,51195,51198,51204-51205,51211,51213,51233,51236,51241,51243,51251,51256,51262,51265,51272,51274,51311,51326,51328,51331,51339,51341,51343,51348,51350,51407,51409,51513,51558,51615,51683,51716,51750,51781,51788,51829,51848,51931,51989,52016,52049,52052,52107,52160,52163,52208,52210,52265,52335,52370,52416,52462,52494-52506,52523,52572,52611,52645,52647,52679,52688,52695,52717,52763,52807-52808,52904,52952,52997,52999,53001,53035,53037,53040,53042,53046,53050,53052,53057,53062,53064,53070,53072,53075,53079,53081,53085,53088,53093,53097,53104,53109,53114,53118,53120,53131,53136,53138,53143,53150,53152,53246,53294,53324,53355,53358,53399,53429,53434,53464,53497,53530,53532,53601,53715,53749,53779-53781,53783,53810,53850,53879-53881,54002,54066,54103,54204,54218,54235,54290,54375,54481,54623,54714,54772,54787,54884,54886,54888,54898,54924,54969,55002,55006,55050,55052,55086,55129,55154,55217,55219,55278,55397,55435,55483,55553,55555,55590,55634,55670,55688,55717,55741,55758,55799,55834,55869,55914,55947,55949,55951,55954,55957,56008,56011,56055,56094,56125,56231,56277,56341,56372,56407,56457,56505,56569,56685,56740,56783,56785,56805,56839,56847,56856,56888,56975,57049,57053,57055,57089,57093,57139,57144,57146,57203,57207,57318,57364,57396,57426,57473,57477,57556,57649,57768,57770,57798,57826,57870,57872,57914,58023,58053,58119,58121,58165,58240,58243,58320,58351-58352,58354,58389,58436,58474,58479,58510,58512,58584,58604,58638,58669,58705,58779,58783,58825-58826,58843,58845,58848,58902,58906,58923,58931,58933,58935,58937,58941,58946-58947,58953,58957,58992,59035,59037,59040,59049,59064,59076,59078,59081,59087,59089,59145,59180,59182,59188,59195,59200,59202,59206,59213,59215,59217,59223,59225,59228,59254,59256,59259,59261-59262,59273,59275,59278,59281,59284,59289,59302,59304,59341,59358,59361,59363,59452,59486,59522,59573,59654,59688,59724,59774,59804,59853,59887,59936,59939,59963,60069,60088,60112,60137,60214,60265,60268,60323,60325,60361,60399,60459,60485,60521,60565,60603,60661,60712-60713,60762,60798,60847,60850,60936,60984,60989,61183,61342-61443,61477,61641,61644-61645,61648,61651,61656,61658,61674,61676,61678,61681,61683,61686,61690,61694,61697,61705,61707,61763,61765,61772,61774,61779,61787,61799,61805,61863,61870,61914,61959,61961,62005,62038,62137,62171,62174,62218,62331,62369,62371,62414,62419,62497,62545,62548,62624,62689,62692,62738,62789,62797-62807,62842,62883,62912,62942,62986,62989,63047,63099,63152,63254,63286,63329,63360,63403,63445,63448,63478,63532,63534-63535,63566,63608,63611-63612,63698,63749,63804,63830,63872,63886,63905,63982,64044,64086,64114,64157,64193,64240,64276,64278,64306,64324,64353,64426,64515-64516,64543,64578,64602,64686,64720,64754,64756,64759,64761,64820,64868,64904,64974,65039,65076,65123,65200-65201,65250,65342,65408,65501,65541,65589,65677,65679-65680,65683,65685,65768,65836,65839,65841-65842,65853,65863,65866,65965-65967,65978,66026,66029-66030,66070,66074,66076,66157,66159,66363,66398,66404,66414,66437,66474,66503,66538,66671,66768,66770,66775,66821,66879,66881,66897,66916,66919,67020-67021,67026,67061,67064,67066,67068,67071,67073,67119,67121,67156,67158,67162,67210,67270,67304,67308,67329,67334,67360,67420,67457,67492,67526,67558,67594,67597,67626,67631,67650,67716,67804,67862,67872,67924,67941,67993,68027-68028,68030,68071,68157,68192,68198,68211,68249,68280,68313,68326,68354,68370,68401,68450,68527,68595,68644,68683,68733,68781,68814,68922,69010,69012,69014,69016,69069,69071,69128,69144,69181,69183-69184,69221,69259,69358,69392,69434,69470,69518,69558,69579,69625,69660-69661,69668,69689,69702,69708,69744,69775,69794,69796,69805,69847,69895,69944,69987,70003,70062,70084,70164,70198,70360,70397,70445,70494,70552,70554,70560,70612,70656,70677,70726-70727,70808,70841,70866,70883,70899,70949,71003,71063,71096,71106,71118,71120-71123,71214,71230,71289,71291,71362,71371,71412,71422,71430,71519,71522,71576,71657,71751,71796,71877,71915,71953,72006,72042,72112,72125,72148,72257,72260,72272,72328,72331,72335,72381,72383,72556,72705,72766,72806,72850-72852,72888,72926,72933,73005,73053,73208,73253,73316,73319,73355,73398,73400,73467,73512,73548,73551,73555,73598,73629,73675,73679,73696,73727,73769,73849,73930,73980,73985,74043,74045,74047,74082,74120,74122,74159,74162,74211,74265,74314,74317,74323,74374,74379,74388,74428,74476,74515,74572,74642,74722,74767,74815,74864,74866,74888,74922,74955,74997,75053,75067,75078,75108,75253,75306,75401,75403,75405,75441,75445,75450,75529,75583,75619,75621,75623,75658,75707,75711,75732,75749,75759,75807,75928,75969,75978,76067,76087,76132,76139,76174,76211,76485,76519,76561,76618,76620,76654,76656,76708,76801,76803,76937,76983,77071,77154,77176,77191,77318,77348,77350,77380,77410,77424-77429,77460,77490,77536,77540,77571,77768,77771,77778,77780,77783,77785,77788,77794-77795,77824,77827,77831,77844,77852,77854,77863,77865,77867,77869,77883,77886-77887,77890,77894,77939,77943,77945,77947,77949,77993,77996,78028,78063,78095,78101,78103,78242,78275,78371,78375,78415,78437,78450,78488,78569,78575,78646,78717,78749,78778,78859,78891,78907,78936,78951,78955,78995,79044,79049,79142,79174,79207,79214,79255,79397,79436,79470,79523,79527,79553,79642,79665,79690,79748,79756,79778,79792,79833,79857,79902,79904,79906,79912,79947,79998,80044,80047,80049,80130,80132,80166,80183,80255,80257,80302,80304,80330,80360,80362,80390,80424,80426,80469,80499,80501,80539,80547,80573,80661,80717,80722,80750,80789,80820,80849,80895,80932,80974,81010,81012,81042,81065,81074,81120,81158,81189,81226,81291,81331,81340,81342,81346,81349,81367,81369,81373,81379,81381,81383,81392,81395,81397,81401,81403,81405-81406,81410,81412,81415-81416,81418,81426,81433,81435,81437,81439,81442,81448,81453,81455,81520,81523,81525,81569,81599,81650,81682,81713,81743,81776,81778,81826,81832,81886,81923,81952,81997,82028,82091,82155,82236,82238,82240,82243,82245,82250,82252,82261,82263,82265,82267,82274,82278,82280,82285-82286,82291,82296,82309,82326,82335,82337,82339,82344,82346,82358,82376,82385,82394,82396,82435,82444,82514,82590-82592,82594,82644,82676,82751,82802,82834,82865,82867,82929,82961,82992,83023-83024,83070,83074,83121,83175,83177,83179,83230,83232,83246,83316,83348,83432,83558,83589,83637,83695,83773,83879,83910,83941,83943,83974,83976,84018,84049,84078,84133,84146,84158,84160,84166,84170,84206,84236,84239,84271,84274,84291,84370,84410,84474,84511,84581,84637,84690,84692,84742,84783,84818,84851,84890,84902,84957,84990,85023,85057,85093,85158,85195,85242,85276,85280,85316,85356,85515,85517,85523,85532-85533,85540,85543,85545,85552,85556,85559,85561,85571,85604,85647,85649,85684,85686,85720,85818,85850,85896,85921,85958,85994,85997,86032,86063,86066,86117,86149,86202,86237,86296,86328,86330,86405,86469,86471,86502,86598,86630,86661,86663,86694,86726,86750,86754,86756,86787,86836,86880-86881,86902,86936,86982,87069,87120,87168,87262,87294,87342,87373,87396,87460,87567,87571,87650,87686,87739,87775,87849,87852,87906,87908,87970,88026,88078,88116,88210,88283,88328,88366,88539,88585,88624,88671,88709,88719,88765,88768,88805,88826,88862,88931,88994,89032,89036-89037,89042,89045-89046,89053,89079,89088,89090,89093,89095,89097,89099,89101,89103,89105,89115,89119,89125,89169-89173,89184,89194,89205,89239,89241,89246,89248,89260,89275,89280-89281,89286,89288,89296,89298,89301-89302,89323,89325,89416,89419,89450,89457,89491,89493,89495,89527,89534,89536,89540,89545,89559,89571,89577,89580,89586-89587,89592,89594,89599,89610,89618,89622,89624,89630-89631,89634,89701,89709,89790,89837,89839,89844,89886,89893,90059,90098,90101,90142,90145,90154-90155,90160,90163,90166-90545,90547-90753,90876,90967,91070,91074,91192,91237,91273,91292,91366,91439,91450,91637,91675,91677,91693,91737,91777,91780,91783,91826,91828,91830,91890,92158,92202,92204,92323,92363,92443,92463,92617,92696,92803,92807,92809,92815,92875,92933-92934,92937,93180,93182,93250,93291,93336,93377,93381,93625,93668,93949,93955,94077,94122,94251,94256,94418,94420,94464,94468,94538,94540,94660,94763,94767,94789-94790,94793,94797,94801,94808,94824,94828-94829,94905,94924,94977,95024,95095,95191,95470,95577,95890,95946,96102,96198-96199,96318,96394,96449,96525,96573,96575,96644,96884,96932,97077,97093,97152,97192,97194-97195,97304,97308,97350,97410,97448,97450,97489,97491,97529,97575,97618,97622,97640,97645,97697,97734,97753,97847,97849,97889,97925,97973,97976,98164,98219,98315,98317,98325,98372,98390,98467,98733,98774,98894,98934,98943,98946,98951,98955,98958,98960,98964,98966,98991,99004,99079,99081,99187,99301,99341,99426,99540,99592,99594,99643,99652,99718,99775,99777,99923,99975,99977-99978,100138,100164,100264,100378,100465,100581,100624,100626,100629,100672,100675,100740,100793,100835,100882,100922,100930,100932,100973,101035,101080,101152,101216,101219,101222,101413-101414,101433,101480,101482,101531,101601,101649,101693,101772,101818,101822,101894,101942,101989,102090,102142,102214,102323,102378,102450,102453,102576,102651,102725,102807,102858,102968,103070,103120,103197,103315,103324,103385,103683,103688,103690,103722,103726,103728,103741,103763,103770,103780,103786,103790,103795,103801,103812,103821,103823,103845,103904,103953,103956,104015,104037,104082,104084,104086,104092,104094-104095,104102,104106,104119,104132,104135,104139,104141,104334,104536,104593,104596,104598,104625,104665,104704,104783,104787,104841,105059,105113,105116,105261,105326,105409,105557,105560,105563,105565,105568,105570,105572,105674,105676,105932,106015,106038,106235,106237,106328,106437,106552,106606,106635,106704,106788,106842,106895,106945,107016,107099,107102,107158,107161,107173,107230,107290,107352,107405,107408,107461,107464,107637,107646,107713-107714,107826,107877,108031,108083,108086,108135,108227,108288,108469,108530,108583,108682,108737,108792,108796,108961,109012,109107,109226,109309,109386,109575,109648,109713,109763,109838,109908,109973,110019,110035,110083,110163,110336,110395,110474,110614,110628,110635,110779,110962,111014,111020,111024,111049,111121,111126,111129,111245,111280,111341,111391,111442,111605,111658,111720,111856,112068,112125,112138,112204,112209,112393,112468,112599,112711,112766,112820,113012,113065,113117-113118,113296,113348,113399,113402,113454,113504,113596,113681,113784,113874,113927,114021,114029,114035,114045,114051,114063,114083,114100,114103,114106,114112,114117,114120,114133,114138,114148,114184,114191,114195,114198,114204,114207,114226,114230,114242,114257,114275,114278,114284,114322,114537,114558,114571,114579,114584,114587,114591,114594,114597,114600,114603,114608,114621,114624,114628,114632,114662,114673,114689,114695,114708,114823,114829,114848,114875,114880,114890-114891,115017,115102,115196,115276,115279,115282,115285,115304,115308,115312,115320,115327,115333,115341,115415,115418,115422,115512,115545,115551,115554,115557,115561,115565,115568,115579,115884,115944,115990,116038,116088,116230,116296,116352,116409,116463,116466,116799,116978,117081,117086,117135,117462,117479,117507,117514,117519,117574,117582,117899,118048,118052,118163,118251,118358,118365,118465,118509,118551,118558,118646,118858,118953-118954,118956,118961,119009,119012,119071,119156,119238,119301,119354,119404,119478,119530,119533,119585,119636,119687,119742,119838,119926,119929,120001,120168,120173,120226,120282,120285,120425,120513,120675,120863-120885,120908,120959,121078,121229,121280,121442,121495,121596,121751,121804,121861,122046,122127,122130,122137,122259,122311,122713,122869,122919,123110,123113,123271,123274,123333,123391,123485,123710,123769,123869,123883,123909,123930,124112,124182,124315,124372,124395,124450,124540,124910,124965,125132,125218,125276,125327,125384,125585,125587,125740,125793,126056,126516,126573,126735,126789,126844,126899,126902,126999,127068,127133,127244,127560,127663,127892-127895,127973,128639,128737,128795,128812,128856,128912,128950,129047,129149,129343,129436,129567,129741,129803,129907,129966-129967,129970,130039,130102,130169,130173,130236,130514,130573,130634,130735,130792,130889,130959,131012,131242,131299,131357,131369,131421,131491,131790,131915,131921,131970,131985,131988,132107,132112,132311,132571,132641-132642,132645,132704,132712-132713,132826,132872,133038,133101,133104,133169,133295,133488,133572,133578,133649,134161,134254,134352,134475,134480,134536,134540,134595,134649,134758,134883,134915,134983,135055,135058,135473,135479,135482,135536,135597,135747,135799,135841-135850,135899,135915,135949,136062,136190,136241,136484,136488,136726,136946,137138,137405,137530,137679,137731,137847,138023,138027,138119-138238,138258,138360,138886,138942,139015,139074,139213,139347,139387,139456,139466,139553,139621,139635,139764,139869,139909,139927,140051,140056,140060,140421,140488,140605,140670,140690,140747,140751,140816,140850,141028,141094,141156,141366,141503,141565,141741,141806,141809,142063,142079,142218,142354,142358,142416,142474,142575,142675,142740,142744,142807,142865,142927,143140,143337,143404,143534,143736,143903,144066,144238,144356,144677,144924-144925,145479,145751,146026,146448,146643,146711,146799,147193,147517,147681,147997,148257,148611,148736,148912,148916,148987,149061,149130,149200,149204,149207,149266,149452,149683,150124,150304,151240-151241,151905,152059,152215,152286,152368,152463,152535,152538-152539,152811,152922,152958,152992,153114,153337,153651,154060,154066,154263,154266,154365,154685,155011,155398,155553,155803,155861,156164,156167,156178,156229,156289,156294,156297,156386,156688,156755,156816,157104,157162-157163,157305,157365,157859,158053,158071,158126,158483,158539,158600,158603,159025,159246,159269,159316,159476,159808,159897,159900,159976,160003,160207,160297,160480,160551,160558,160703,160770,160943,161013,161287,161426,161725,161948,162013-162014,162136,162188,162204,162264-162265,162273,162286,162341,162348,162413,162463,162653,162659,162663,162738,162804,162874,162926,163080,163084,163088,163092,163253,163316,163383,163448,163511,163761,164201,164350,164416,164422,164605,164634,164672,164736,164806,164876,164881,164977,165317,165591,165661,165767,165796,165889,166093,166297,166380,166509,166568,166772,166953,167095,167179,167260,167299,167432,167541,167545,167554,167566,167714,167840,168128,168191,168198,168267,168480,168507,168516,168546,168551,168561,168593,168603,168608,168614,168622,168628,168716,168721,168745,168828,168975,169210,169364,169485,169722,169867,169943,170050,170147,170158,170239,170392,170504,170568,170588,170648,170671,170719,170836,170979,171187,171264,171527,171621,171837,171963,172030,172169,172438,172962,173066,173070,173211,173392,173396,173559,173592,173692,173696,173917,173967-173968,174082,174148,174218,174282,174369,174583,175029,175124,175187,175294,175311,175590,175777,175792,175825,175921,176029,176216,176249-176252,176254,176354,176426,176661,176701,177096,177225,177383,177536,177540,177701,177786,178141,178205,178373,178445,178508,178804
-Modified: svn:externals
- - menuselect http://svn.digium.com/svn/menuselect/tags/autotag_for_asterisk/1.6.1-rc1
-
- + menuselect http://svn.digium.com/svn/menuselect/trunk
-
-Added: automerge-propname
- + issue14292-integrated
-Added: svnmerge-integrated
- + /trunk:1-178930
-Added: automerge-email
- + rmudgett@digium.com
-Added: issue14292-integrated
- + /team/group/issue14068:1-178954
-Added: issue14068-integrated
- + /team/group/issue8824:1-178953
-Added: reviewboard:url
- + http://reviewboard.digium.com
-
---- a/res/res_indications.c 2009-01-13 19:35:59 +0000
-+++ b//dev/null 2007-04-29 12:33:55 +0000
-@@ -1,441 +0,0 @@
--/*
-- * Asterisk -- An open source telephony toolkit.
-- *
-- * Copyright (C) 2002, Pauline Middelink
-- *
-- *
-- * 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 res_indications.c
-- *
-- * \brief Load the indications
-- *
-- * \author Pauline Middelink <middelink@polyware.nl>
-- *
-- * Load the country specific dialtones into the asterisk PBX.
-- */
--
--#include "asterisk.h"
--
--ASTERISK_FILE_VERSION(__FILE__, "$Revision: 168565 $")
--
--#include <ctype.h>
--#include <sys/stat.h>
--
--#include "asterisk/lock.h"
--#include "asterisk/file.h"
--#include "asterisk/cli.h"
--#include "asterisk/config.h"
--#include "asterisk/channel.h"
--#include "asterisk/pbx.h"
--#include "asterisk/module.h"
--#include "asterisk/translate.h"
--#include "asterisk/indications.h"
--#include "asterisk/utils.h"
--
--/* Globals */
--static const char config[] = "indications.conf";
--
--char *playtones_desc=
--" PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n"
--"while the tones continue to play.\n"
--"Arg is either the tone name defined in the indications.conf configuration file, or a directly\n"
--"specified list of frequencies and durations.\n"
--"See the sample indications.conf for a description of the specification of a tonelist.\n\n"
--"Use the StopPlayTones application to stop the tones playing. \n";
--
--/*
-- * Implementation of functions provided by this module
-- */
--
--/*!
-- * \brief Add a country to indication
-- * \param e the ast_cli_entry for this CLI command
-- * \param cmd the reason we are being called
-- * \param a the arguments being passed to us
-- */
--static char *handle_cli_indication_add(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- struct tone_zone *tz;
-- int created_country = 0;
--
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "indication add";
-- e->usage =
-- "Usage: indication add <country> <indication> \"<tonelist>\"\n"
-- " Add the given indication to the country.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc != 5)
-- return CLI_SHOWUSAGE;
--
-- tz = ast_get_indication_zone(a->argv[2]);
-- if (!tz) {
-- /* country does not exist, create it */
-- ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n", a->argv[2]);
--
-- if (!(tz = ast_calloc(1, sizeof(*tz)))) {
-- return CLI_FAILURE;
-- }
-- ast_copy_string(tz->country, a->argv[2], sizeof(tz->country));
-- if (ast_register_indication_country(tz)) {
-- ast_log(LOG_WARNING, "Unable to register new country\n");
-- ast_free(tz);
-- return CLI_FAILURE;
-- }
-- created_country = 1;
-- }
-- if (ast_register_indication(tz, a->argv[3], a->argv[4])) {
-- ast_log(LOG_WARNING, "Unable to register indication %s/%s\n", a->argv[2], a->argv[3]);
-- if (created_country)
-- ast_unregister_indication_country(a->argv[2]);
-- return CLI_FAILURE;
-- }
-- return CLI_SUCCESS;
--}
--
--/*!
-- * \brief Remove a country from indication
-- * \param e the ast_cli_entry for this CLI command
-- * \param cmd the reason we are being called
-- * \param a the arguments being passed to us
-- */
--static char *handle_cli_indication_remove(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- struct tone_zone *tz;
--
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "indication remove";
-- e->usage =
-- "Usage: indication remove <country> <indication>\n"
-- " Remove the given indication from the country.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc != 3 && a->argc != 4)
-- return CLI_SHOWUSAGE;
--
-- if (a->argc == 3) {
-- /* remove entiry country */
-- if (ast_unregister_indication_country(a->argv[2])) {
-- ast_log(LOG_WARNING, "Unable to unregister indication country %s\n", a->argv[2]);
-- return CLI_FAILURE;
-- }
-- return CLI_SUCCESS;
-- }
--
-- tz = ast_get_indication_zone(a->argv[2]);
-- if (!tz) {
-- ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n", a->argv[2], a->argv[3]);
-- return CLI_FAILURE;
-- }
-- if (ast_unregister_indication(tz, a->argv[3])) {
-- ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n", a->argv[2], a->argv[3]);
-- return CLI_FAILURE;
-- }
-- return CLI_SUCCESS;
--}
--
--/*!
-- * \brief Show the current indications
-- * \param e the ast_cli_entry for this CLI command
-- * \param cmd the reason we are being called
-- * \param a the arguments being passed to us
-- */
--static char *handle_cli_indication_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
--{
-- struct tone_zone *tz = NULL;
-- char buf[256];
-- int found_country = 0;
--
-- switch (cmd) {
-- case CLI_INIT:
-- e->command = "indication show";
-- e->usage =
-- "Usage: indication show [<country> ...]\n"
-- " Display either a condensed for of all country/indications, or the\n"
-- " indications for the specified countries.\n";
-- return NULL;
-- case CLI_GENERATE:
-- return NULL;
-- }
--
-- if (a->argc == 2) {
-- /* no arguments, show a list of countries */
-- ast_cli(a->fd, "Country Alias Description\n");
-- ast_cli(a->fd, "===========================\n");
-- while ((tz = ast_walk_indications(tz)))
-- ast_cli(a->fd, "%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description);
-- return CLI_SUCCESS;
-- }
-- /* there was a request for specific country(ies), lets humor them */
-- while ((tz = ast_walk_indications(tz))) {
-- int i, j;
-- for (i = 2; i < a->argc; i++) {
-- if (strcasecmp(tz->country, a->argv[i]) == 0 && !tz->alias[0]) {
-- struct tone_zone_sound* ts;
-- if (!found_country) {
-- found_country = 1;
-- ast_cli(a->fd, "Country Indication PlayList\n");
-- ast_cli(a->fd, "=====================================\n");
-- }
-- j = snprintf(buf, sizeof(buf), "%-7.7s %-15.15s ", tz->country, "<ringcadence>");
-- for (i = 0; i < tz->nrringcadence; i++) {
-- j += snprintf(buf + j, sizeof(buf) - j, "%d,", tz->ringcadence[i]);
-- }
-- if (tz->nrringcadence)
-- j--;
-- ast_copy_string(buf + j, "\n", sizeof(buf) - j);
-- ast_cli(a->fd, "%s", buf);
-- for (ts = tz->tones; ts; ts = ts->next)
-- ast_cli(a->fd, "%-7.7s %-15.15s %s\n", tz->country, ts->name, ts->data);
-- break;
-- }
-- }
-- }
-- if (!found_country)
-- ast_cli(a->fd, "No countries matched your criteria.\n");
-- return CLI_SUCCESS;
--}
--
--/*!
-- * \brief play tone for indication country
-- * \param chan ast_channel to play the sounds back to
-- * \param data contains tone to play
-- */
--static int handle_playtones(struct ast_channel *chan, void *data)
--{
-- struct tone_zone_sound *ts;
-- int res;
--
-- if (!data || !((char*)data)[0]) {
-- ast_log(LOG_NOTICE,"Nothing to play\n");
-- return -1;
-- }
-- ts = ast_get_indication_tone(chan->zone, (const char*)data);
-- if (ts && ts->data[0])
-- res = ast_playtones_start(chan, 0, ts->data, 0);
-- else
-- res = ast_playtones_start(chan, 0, (const char*)data, 0);
-- if (res)
-- ast_log(LOG_NOTICE,"Unable to start playtones\n");
-- return res;
--}
--
--/*!
-- * \brief Stop tones playing
-- * \param chan
-- * \param data
-- */
--static int handle_stopplaytones(struct ast_channel *chan, void *data)
--{
-- ast_playtones_stop(chan);
-- return 0;
--}
--
--/* helper function to delete a tone_zone in its entirety */
--static inline void free_zone(struct tone_zone* zone)
--{
-- while (zone->tones) {
-- struct tone_zone_sound *tmp = zone->tones->next;
-- ast_free((void *)zone->tones->name);
-- ast_free((void *)zone->tones->data);
-- ast_free(zone->tones);
-- zone->tones = tmp;
-- }
--
-- if (zone->ringcadence)
-- ast_free(zone->ringcadence);
--
-- ast_free(zone);
--}
--
--/*! \brief load indications module */
--static int ind_load_module(int reload)
--{
-- struct ast_config *cfg;
-- struct ast_variable *v;
-- char *cxt;
-- char *c;
-- struct tone_zone *tones;
-- const char *country = NULL;
-- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
--
-- /* that the following cast is needed, is yuk! */
-- /* yup, checked it out. It is NOT written to. */
-- cfg = ast_config_load((char *)config, config_flags);
-- if (!cfg)
-- return -1;
-- else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
-- return 0;
--
-- if (reload)
-- ast_unregister_indication_country(NULL);
--
-- /* Use existing config to populate the Indication table */
-- cxt = ast_category_browse(cfg, NULL);
-- while(cxt) {
-- /* All categories but "general" are considered countries */
-- if (!strcasecmp(cxt, "general")) {
-- cxt = ast_category_browse(cfg, cxt);
-- continue;
-- }
-- if (!(tones = ast_calloc(1, sizeof(*tones)))) {
-- ast_config_destroy(cfg);
-- return -1;
-- }
-- ast_copy_string(tones->country,cxt,sizeof(tones->country));
--
-- v = ast_variable_browse(cfg, cxt);
-- while(v) {
-- if (!strcasecmp(v->name, "description")) {
-- ast_copy_string(tones->description, v->value, sizeof(tones->description));
-- } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) {
-- char *ring,*rings = ast_strdupa(v->value);
-- c = rings;
-- ring = strsep(&c,",");
-- while (ring) {
-- int *tmp, val;
-- if (!isdigit(ring[0]) || (val=atoi(ring))==-1) {
-- ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno);
-- ring = strsep(&c,",");
-- continue;
-- }
-- if (!(tmp = ast_realloc(tones->ringcadence, (tones->nrringcadence + 1) * sizeof(int)))) {
-- ast_config_destroy(cfg);
-- free_zone(tones);
-- return -1;
-- }
-- tones->ringcadence = tmp;
-- tmp[tones->nrringcadence] = val;
-- tones->nrringcadence++;
-- /* next item */
-- ring = strsep(&c,",");
-- }
-- } else if (!strcasecmp(v->name,"alias")) {
-- char *countries = ast_strdupa(v->value);
-- c = countries;
-- country = strsep(&c,",");
-- while (country) {
-- struct tone_zone* azone;
-- if (!(azone = ast_calloc(1, sizeof(*azone)))) {
-- ast_config_destroy(cfg);
-- free_zone(tones);
-- return -1;
-- }
-- ast_copy_string(azone->country, country, sizeof(azone->country));
-- ast_copy_string(azone->alias, cxt, sizeof(azone->alias));
-- if (ast_register_indication_country(azone)) {
-- ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno);
-- free_zone(tones);
-- }
-- /* next item */
-- country = strsep(&c,",");
-- }
-- } else {
-- /* add tone to country */
-- struct tone_zone_sound *ps,*ts;
-- for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) {
-- if (strcasecmp(v->name,ts->name)==0) {
-- /* already there */
-- ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name);
-- goto out;
-- }
-- }
-- /* not there, add it to the back */
-- if (!(ts = ast_malloc(sizeof(*ts)))) {
-- ast_config_destroy(cfg);
-- return -1;
-- }
-- ts->next = NULL;
-- ts->name = ast_strdup(v->name);
-- ts->data = ast_strdup(v->value);
-- if (ps)
-- ps->next = ts;
-- else
-- tones->tones = ts;
-- }
--out: v = v->next;
-- }
-- if (tones->description[0] || tones->alias[0] || tones->tones) {
-- if (ast_register_indication_country(tones)) {
-- ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno);
-- free_zone(tones);
-- }
-- } else {
-- free_zone(tones);
-- }
--
-- cxt = ast_category_browse(cfg, cxt);
-- }
--
-- /* determine which country is the default */
-- country = ast_variable_retrieve(cfg,"general","country");
-- if (ast_strlen_zero(country) || ast_set_indication_country(country)) {
-- ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n");
-- }
--
-- ast_config_destroy(cfg);
-- return 0;
--}
--
--/*! \brief CLI entries for commands provided by this module */
--static struct ast_cli_entry cli_indications[] = {
-- AST_CLI_DEFINE(handle_cli_indication_add, "Add the given indication to the country"),
-- AST_CLI_DEFINE(handle_cli_indication_remove, "Remove the given indication from the country"),
-- AST_CLI_DEFINE(handle_cli_indication_show, "Display a list of all countries/indications")
--};
--
--/*! \brief Unload indicators module */
--static int unload_module(void)
--{
-- /* remove the registed indications... */
-- ast_unregister_indication_country(NULL);
--
-- /* and the functions */
-- ast_cli_unregister_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
-- ast_unregister_application("PlayTones");
-- ast_unregister_application("StopPlayTones");
-- return 0;
--}
--
--
--/*! \brief Load indications module */
--static int load_module(void)
--{
-- if (ind_load_module(0))
-- return AST_MODULE_LOAD_DECLINE;
-- ast_cli_register_multiple(cli_indications, sizeof(cli_indications) / sizeof(struct ast_cli_entry));
-- ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc);
-- ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list"," StopPlayTones(): Stop playing a tone list");
--
-- return AST_MODULE_LOAD_SUCCESS;
--}
--
--/*! \brief Reload indications module */
--static int reload(void)
--{
-- return ind_load_module(1);
--}
--
--AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Region-specific tones",
-- .load = load_module,
-- .unload = unload_module,
-- .reload = reload,
-- );
diff --git a/testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch b/testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch
new file mode 100644
index 00000000..21ff8236
--- /dev/null
+++ b/testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch
@@ -0,0 +1,41697 @@
+Index: .version
+===================================================================
+--- a/.version (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/.version (.../trunk) (revision 186562)
+@@ -1 +1 @@
+-1.6.2.0-beta1
++1.6.2.0-beta1-r186562
+Index: build_tools/strip_nonapi
+===================================================================
+--- a/build_tools/strip_nonapi (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/build_tools/strip_nonapi (.../trunk) (revision 186562)
+@@ -1,38 +0,0 @@
+-#!/bin/sh -e
+-
+-# This script is designed to remove all non-API global symbols from an object
+-# file. The only global symbols that should be retained are those that belong
+-# to the official namespace. Unfortunately doing this is platform-specific, as
+-# the object file manipulation tools are not consistent across platforms.
+-#
+-# On platforms where this script does not know what to do, the object file
+-# will retain non-API global symbols, and this may have unpleasant side effects.
+-#
+-# Prefixes that belong to the official namespace are:
+-# ast_
+-# _ast_
+-# __ast_
+-# astman_
+-# pbx_
+-# resample_
+-
+-FILTER="${GREP} -v -e ^ast_ -e ^_ast_ -e ^__ast_ -e ^astman_ -e ^pbx_ -e ^resample_"
+-
+-case "${PROC}" in
+- powerpc64)
+- TEXTSYM=" D "
+- ;;
+- *)
+- TEXTSYM=" T "
+- ;;
+-esac
+-
+-case "${OSARCH}" in
+- linux-gnu|FreeBSD)
+- nm ${1} | ${GREP} -e "$TEXTSYM" | cut -d" " -f3 | ${FILTER} > striplist
+- sed -e "s/^/-N /" striplist | xargs -n 40 ${STRIP} ${1}
+- rm -f striplist
+- ;;
+- *)
+- ;;
+-esac
+Index: bridges/bridge_softmix.c
+===================================================================
+--- a/bridges/bridge_softmix.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/bridges/bridge_softmix.c (.../trunk) (revision 186562)
+@@ -85,17 +85,25 @@
+ /*! \brief Function called when a bridge is created */
+ static int softmix_bridge_create(struct ast_bridge *bridge)
+ {
+- int timingfd;
++ struct ast_timer *timer;
+
+- if ((timingfd = ast_timer_open()) < 0) {
++ if (!(timer = ast_timer_open())) {
+ return -1;
+ }
+
+- ast_timer_close(timingfd);
++ bridge->bridge_pvt = timer;
+
+ return 0;
+ }
+
++/*! \brief Function called when a bridge is destroyed */
++static int softmix_bridge_destroy(struct ast_bridge *bridge)
++{
++ ast_timer_close((struct ast_timer *) bridge->bridge_pvt);
++
++ return 0;
++}
++
+ /*! \brief Function called when a channel is joined into the bridge */
+ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+ {
+@@ -199,14 +207,11 @@
+ /*! \brief Function which acts as the mixing thread */
+ static int softmix_bridge_thread(struct ast_bridge *bridge)
+ {
+- int timingfd;
++ struct ast_timer *timer = (struct ast_timer *) bridge->bridge_pvt;
++ int timingfd = ast_timer_fd(timer);
+
+- if ((timingfd = ast_timer_open()) < 0) {
+- return -1;
+- }
++ ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
+
+- ast_timer_set_rate(timingfd, (1000 / SOFTMIX_INTERVAL));
+-
+ while (!bridge->stop && !bridge->refresh && bridge->array_num) {
+ struct ast_bridge_channel *bridge_channel = NULL;
+ short buf[SOFTMIX_DATALEN] = {0, };
+@@ -262,14 +267,11 @@
+ /* Wait for the timing source to tell us to wake up and get things done */
+ ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
+
+- ast_timer_ack(timingfd, 1);
++ ast_timer_ack(timer, 1);
+
+ ao2_lock(bridge);
+ }
+
+- ast_timer_set_rate(timingfd, 0);
+- ast_timer_close(timingfd);
+-
+ return 0;
+ }
+
+@@ -283,6 +285,7 @@
+ .formats = AST_FORMAT_SLINEAR,
+ #endif
+ .create = softmix_bridge_create,
++ .destroy = softmix_bridge_destroy,
+ .join = softmix_bridge_join,
+ .leave = softmix_bridge_leave,
+ .write = softmix_bridge_write,
+Index: configure
+===================================================================
+--- a/configure (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/configure (.../trunk) (revision 186562)
+@@ -1,5 +1,5 @@
+ #! /bin/sh
+-# From configure.ac Revision: 182355 .
++# From configure.ac Revision: 182847 .
+ # Guess values for system-dependent variables and create Makefiles.
+ # Generated by GNU Autoconf 2.61 for asterisk 1.6.
+ #
+@@ -992,7 +992,6 @@
+ AST_FORTIFY_SOURCE
+ AST_NO_STRICT_OVERFLOW
+ AST_SHADOW_WARNINGS
+-PBX_RTLD_NOLOAD
+ PBX_IP_MTU_DISCOVER
+ PBX_DAHDI_HALF_FULL
+ GSM_INTERNAL
+@@ -1631,7 +1630,7 @@
+ --with-crypto=PATH use OpenSSL Cryptography support files in PATH
+ --with-dahdi=PATH use DAHDI files in PATH
+ --with-avcodec=PATH use Ffmpeg and avcodec library files in PATH
+- --with-gsm=PATH use External GSM library files in PATH , use
++ --with-gsm=PATH use External GSM library files in PATH, use
+ 'internal' GSM otherwise
+ --with-gtk=PATH use gtk libraries files in PATH
+ --with-gtk2=PATH use gtk2 libraries files in PATH
+@@ -19141,83 +19140,6 @@
+ conftest$ac_exeext conftest.$ac_ext
+
+
+- if test "x${PBX_RTLD_NOLOAD}" != "x1"; then
+- { echo "$as_me:$LINENO: checking for RTLD_NOLOAD in dlfcn.h" >&5
+-echo $ECHO_N "checking for RTLD_NOLOAD in dlfcn.h... $ECHO_C" >&6; }
+- saved_cppflags="${CPPFLAGS}"
+- if test "x${RTLD_NOLOAD_DIR}" != "x"; then
+- RTLD_NOLOAD_INCLUDE="-I${RTLD_NOLOAD_DIR}/include"
+- fi
+- CPPFLAGS="${CPPFLAGS} ${RTLD_NOLOAD_INCLUDE}"
+-
+- cat >conftest.$ac_ext <<_ACEOF
+- /* confdefs.h. */
+-_ACEOF
+-cat confdefs.h >>conftest.$ac_ext
+-cat >>conftest.$ac_ext <<_ACEOF
+-/* end confdefs.h. */
+-#include <dlfcn.h>
+-int
+-main ()
+-{
+-#if defined(RTLD_NOLOAD)
+- 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_RTLD_NOLOAD=1
+-
+-cat >>confdefs.h <<\_ACEOF
+-#define HAVE_RTLD_NOLOAD 1
+-_ACEOF
+-
+-
+-cat >>confdefs.h <<\_ACEOF
+-#define HAVE_RTLD_NOLOAD_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_IP_MTU_DISCOVER}" != "x1"; then
+ { echo "$as_me:$LINENO: checking for IP_MTU_DISCOVER in netinet/in.h" >&5
+ echo $ECHO_N "checking for IP_MTU_DISCOVER in netinet/in.h... $ECHO_C" >&6; }
+@@ -54451,7 +54373,6 @@
+ AST_FORTIFY_SOURCE!$AST_FORTIFY_SOURCE$ac_delim
+ AST_NO_STRICT_OVERFLOW!$AST_NO_STRICT_OVERFLOW$ac_delim
+ 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
+@@ -54466,6 +54387,7 @@
+ PWLIB_LIBDIR!$PWLIB_LIBDIR$ac_delim
+ PWLIB_PLATFORM!$PWLIB_PLATFORM$ac_delim
+ OPENH323DIR!$OPENH323DIR$ac_delim
++OPENH323_INCDIR!$OPENH323_INCDIR$ac_delim
+ _ACEOF
+
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
+@@ -54507,7 +54429,6 @@
+ ac_delim='%!_!# '
+ for ac_last_try in false false false false false :; do
+ cat >conf$$subs.sed <<_ACEOF
+-OPENH323_INCDIR!$OPENH323_INCDIR$ac_delim
+ OPENH323_LIBDIR!$OPENH323_LIBDIR$ac_delim
+ OPENH323_SUFFIX!$OPENH323_SUFFIX$ac_delim
+ OPENH323_BUILD!$OPENH323_BUILD$ac_delim
+@@ -54528,7 +54449,7 @@
+ LTLIBOBJS!$LTLIBOBJS$ac_delim
+ _ACEOF
+
+- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 19; then
++ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 18; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+Index: default.exports
+===================================================================
+--- a/default.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/default.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,4 @@
++{
++ local:
++ *;
++};
+
+Property changes on: default.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: pbx/pbx_dundi.c
+===================================================================
+--- a/pbx/pbx_dundi.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/pbx/pbx_dundi.c (.../trunk) (revision 186562)
+@@ -4614,7 +4614,7 @@
+ ast_log(LOG_WARNING, "Unable to get host name!\n");
+ AST_LIST_LOCK(&peers);
+
+- memcpy(&global_eid, &g_eid, sizeof(global_eid));
++ memcpy(&global_eid, &ast_eid_default, sizeof(global_eid));
+
+ global_storehistory = 0;
+ ast_copy_string(secretpath, "dundi", sizeof(secretpath));
+Index: channels/h323/Makefile.in
+===================================================================
+--- a/channels/h323/Makefile.in (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/h323/Makefile.in (.../trunk) (revision 186562)
+@@ -24,7 +24,9 @@
+ OPENH323DIR=@OPENH323DIR@
+ endif
+
++ifneq ($(wildcard $(OPENH323DIR)/openh323u.mak),)
+ include $(OPENH323DIR)/openh323u.mak
++endif
+
+ notrace::
+ $(MAKE) NOTRACE=1 opt
+Index: channels/misdn_config.c
+===================================================================
+--- a/channels/misdn_config.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn_config.c (.../trunk) (revision 186562)
+@@ -1,6 +1,6 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+- *
++ *
+ * Copyright (C) 2005, Christian Richter
+ *
+ * Christian Richter <crich@beronet.com>
+@@ -132,69 +132,79 @@
+ { "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." },
++ "Set the method to use for channel selection:\n"
++ "\t standard - Use the first free channel starting from the lowest number.\n"
++ "\t standard_dec - Use the first free channel starting from the highest 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"
+@@ -211,6 +221,22 @@
+ "\n"
+ "\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 +245,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 +282,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 +336,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"
+@@ -364,8 +390,8 @@
+ { "crypt_keys", MISDN_GEN_CRYPT_KEYS, MISDN_CTYPE_STR, NO_DEFAULT, NONE,
+ "Keys for cryption, you reference them in the dialplan\n"
+ "\tLater also in dynamic encr." },
+- { "ntkeepcalls", MISDN_GEN_NTKEEPCALLS, MISDN_CTYPE_BOOL, "no", NONE,
+- "avoid dropping calls if the L2 goes down. some Nortel pbx\n"
++ { "ntkeepcalls", MISDN_GEN_NTKEEPCALLS, MISDN_CTYPE_BOOL, "no", NONE,
++ "avoid dropping calls if the L2 goes down. some Nortel pbx\n"
+ "do put down the L2/L1 for some milliseconds even if there\n"
+ "are running calls. with this option you can avoid dropping them" },
+ { "ntdebugflags", MISDN_GEN_NTDEBUGFLAGS, MISDN_CTYPE_INT, "0", NONE,
+@@ -386,7 +412,7 @@
+ /* maps enum config elements to array positions */
+ static int *map;
+
+-static ast_mutex_t config_mutex;
++static ast_mutex_t config_mutex;
+
+ #define CLI_ERROR(name, value, section) ({ \
+ ast_log(LOG_WARNING, "misdn.conf: \"%s=%s\" (section: %s) invalid or out of range. " \
+@@ -475,7 +501,7 @@
+ int i, j;
+ int gn = map[MISDN_CFG_GROUPNAME];
+ union misdn_cfg_pt* free_list[max_ports + 2];
+-
++
+ memset(free_list, 0, sizeof(free_list));
+ free_list[0] = port_cfg[0];
+ for (i = 1; i <= max_ports; ++i) {
+@@ -507,7 +533,7 @@
+ {
+ int i;
+
+- for (i = 0; i < NUM_GEN_ELEMENTS; i++)
++ for (i = 0; i < NUM_GEN_ELEMENTS; i++)
+ if (general_cfg[i].any)
+ ast_free(general_cfg[i].any);
+ }
+@@ -579,11 +605,11 @@
+ pos = get_cfg_position(name, PORT_CFG);
+ if (pos >= 0)
+ return port_spec[pos].elem;
+-
++
+ pos = get_cfg_position(name, GEN_CFG);
+ if (pos >= 0)
+ return gen_spec[pos].elem;
+-
++
+ return MISDN_CFG_FIRST;
+ }
+
+@@ -597,7 +623,7 @@
+ memset(buf, 0, 1);
+ return;
+ }
+-
++
+ /* here comes a hack to replace the (not existing) "name" element with the "ports" element */
+ if (elem == MISDN_CFG_GROUPNAME) {
+ if (!snprintf(buf, bufsize, "ports"))
+@@ -630,7 +656,7 @@
+ spec = (struct misdn_cfg_spec *)port_spec;
+ else if ((elem > MISDN_GEN_FIRST) && (elem < MISDN_GEN_LAST))
+ spec = (struct misdn_cfg_spec *)gen_spec;
+-
++
+ if (!spec || !spec[place].desc)
+ memset(buf, 0, 1);
+ else {
+@@ -659,7 +685,7 @@
+ iter = port_cfg[port][map[MISDN_CFG_MSNS]].ml;
+ else
+ iter = port_cfg[0][map[MISDN_CFG_MSNS]].ml;
+- for (; iter; iter = iter->next)
++ for (; iter; iter = iter->next)
+ if (*(iter->msn) == '*' || ast_extension_match(iter->msn, msn)) {
+ re = 1;
+ break;
+@@ -688,7 +714,7 @@
+ for (i = 1; i <= max_ports; i++) {
+ if (port_cfg[i] && port_cfg[i][map[MISDN_CFG_GROUPNAME]].str) {
+ if (!strcasecmp(port_cfg[i][map[MISDN_CFG_GROUPNAME]].str, group))
+- method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ?
++ method = (port_cfg[i][map[MISDN_CFG_METHOD]].str ?
+ port_cfg[i][map[MISDN_CFG_METHOD]].str : port_cfg[0][map[MISDN_CFG_METHOD]].str);
+ }
+ }
+@@ -708,7 +734,7 @@
+ return re;
+ }
+
+-/*!
++/*!
+ * \brief Generate a comma separated list of all active ports
+ */
+ void misdn_cfg_get_ports_string (char *ports)
+@@ -776,10 +802,10 @@
+ break;
+ case MISDN_CTYPE_ASTGROUP:
+ if (port_cfg[port][place].grp)
+- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
++ snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
+ ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[port][place].grp));
+ else if (port_cfg[0][place].grp)
+- snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
++ snprintf(buf, bufsize, " -> %s: %s", port_spec[place].name,
+ ast_print_group(tempbuf, sizeof(tempbuf), *port_cfg[0][place].grp));
+ else
+ snprintf(buf, bufsize, " -> %s:", port_spec[place].name);
+@@ -844,7 +870,7 @@
+ {
+ int p = -1;
+ int gn = map[MISDN_CFG_GROUPNAME];
+-
++
+ misdn_cfg_lock();
+ for (port++; port <= max_ports; port++) {
+ if (port_cfg[port][gn].str) {
+@@ -936,7 +962,7 @@
+ for (; v; v = v->next) {
+ if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
+ continue;
+- if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) ||
++ if (((pos = get_cfg_position(v->name, GEN_CFG)) < 0) ||
+ (_parse(&general_cfg[pos], v->value, gen_spec[pos].type, gen_spec[pos].boolint_def) < 0))
+ CLI_ERROR(v->name, v->value, "general");
+ }
+@@ -958,7 +984,7 @@
+ cfg_for_ports[0] = 1;
+ }
+
+- if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
++ if (((pos = get_cfg_position("name", PORT_CFG)) < 0) ||
+ (_parse(&cfg_tmp[pos], cat, port_spec[pos].type, port_spec[pos].boolint_def) < 0)) {
+ CLI_ERROR(v->name, v->value, cat);
+ return;
+@@ -969,7 +995,7 @@
+ char *token, *tmp = ast_strdupa(v->value);
+ char ptpbuf[BUFFERSIZE] = "";
+ int start, end;
+- for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) {
++ for (token = strsep(&tmp, ","); token; token = strsep(&tmp, ","), *ptpbuf = 0) {
+ if (!*token)
+ continue;
+ if (sscanf(token, "%d-%d%s", &start, &end, ptpbuf) >= 2) {
+@@ -992,7 +1018,7 @@
+ }
+ }
+ } else {
+- if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
++ if (((pos = get_cfg_position(v->name, PORT_CFG)) < 0) ||
+ (_parse(&cfg_tmp[pos], v->value, port_spec[pos].type, port_spec[pos].boolint_def) < 0))
+ CLI_ERROR(v->name, v->value, cat);
+ }
+Index: channels/chan_jingle.c
+===================================================================
+--- a/channels/chan_jingle.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_jingle.c (.../trunk) (revision 186562)
+@@ -53,7 +53,7 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/file.h"
+@@ -112,9 +112,9 @@
+ char exten[80]; /*!< Called extension */
+ struct ast_channel *owner; /*!< Master Channel */
+ char audio_content_name[100]; /*!< name attribute of content tag */
+- struct ast_rtp *rtp; /*!< RTP audio session */
++ struct ast_rtp_instance *rtp; /*!< RTP audio session */
+ char video_content_name[100]; /*!< name attribute of content tag */
+- struct ast_rtp *vrtp; /*!< RTP video session */
++ struct ast_rtp_instance *vrtp; /*!< RTP video session */
+ int jointcapability; /*!< Supported capability at both ends (codecs ) */
+ int peercapability;
+ struct jingle_pvt *next; /* Next entity */
+@@ -183,11 +183,6 @@
+ static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid);
+ static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+-/*----- RTP interface functions */
+-static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
+- struct ast_rtp *vrtp, struct ast_rtp *tpeer, int codecs, int nat_active);
+-static enum ast_rtp_get_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+-static int jingle_get_codec(struct ast_channel *chan);
+
+ /*! \brief PBX interface structure for channel registration */
+ static const struct ast_channel_tech jingle_tech = {
+@@ -197,7 +192,7 @@
+ .requester = jingle_request,
+ .send_digit_begin = jingle_digit_begin,
+ .send_digit_end = jingle_digit_end,
+- .bridge = ast_rtp_bridge,
++ .bridge = ast_rtp_instance_bridge,
+ .call = jingle_call,
+ .hangup = jingle_hangup,
+ .answer = jingle_answer,
+@@ -216,15 +211,6 @@
+ static struct io_context *io; /*!< The IO context */
+ static struct in_addr __ourip;
+
+-
+-/*! \brief RTP driver interface */
+-static struct ast_rtp_protocol jingle_rtp = {
+- type: "Jingle",
+- get_rtp_info: jingle_get_rtp_peer,
+- set_rtp_peer: jingle_set_rtp_peer,
+- get_codec: jingle_get_codec,
+-};
+-
+ static struct ast_cli_entry jingle_cli[] = {
+ AST_CLI_DEFINE(jingle_do_reload, "Reload Jingle configuration"),
+ AST_CLI_DEFINE(jingle_show_channels, "Show Jingle channels"),
+@@ -304,7 +290,6 @@
+ iks_insert_attrib(payload_g723, "name", "G723");
+ iks_insert_node(dcodecs, payload_g723);
+ }
+- ast_rtp_lookup_code(p->rtp, 1, codec);
+ }
+
+ static int jingle_accept_call(struct jingle *client, struct jingle_pvt *p)
+@@ -398,18 +383,19 @@
+ return res;
+ }
+
+-static enum ast_rtp_get_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+ struct jingle_pvt *p = chan->tech_pvt;
+- enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
+ if (!p)
+ return res;
+
+ ast_mutex_lock(&p->lock);
+ if (p->rtp) {
+- *rtp = p->rtp;
+- res = AST_RTP_TRY_PARTIAL;
++ ao2_ref(p->rtp, +1);
++ *instance = p->rtp;
++ res = AST_RTP_GLUE_RESULT_LOCAL;
+ }
+ ast_mutex_unlock(&p->lock);
+
+@@ -422,7 +408,7 @@
+ return p->peercapability;
+ }
+
+-static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *tpeer, int codecs, int nat_active)
++static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, int codecs, int nat_active)
+ {
+ struct jingle_pvt *p;
+
+@@ -442,6 +428,13 @@
+ return 0;
+ }
+
++static struct ast_rtp_glue jingle_rtp_glue = {
++ .type = "Jingle",
++ .get_rtp_info = jingle_get_rtp_peer,
++ .get_codec = jingle_get_codec,
++ .update_peer = jingle_set_rtp_peer,
++};
++
+ static int jingle_response(struct jingle *client, ikspak *pak, const char *reasonstr, const char *reasonstr2)
+ {
+ iks *response = NULL, *error = NULL, *reason = NULL;
+@@ -621,7 +614,7 @@
+ goto safeout;
+ }
+
+- ast_rtp_get_us(p->rtp, &sin);
++ ast_rtp_instance_get_local_address(p->rtp, &sin);
+ ast_find_ourip(&us, bindaddr);
+
+ /* Setup our first jingle candidate */
+@@ -779,7 +772,7 @@
+ ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
+ tmp->initiator = 1;
+ }
+- tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
++ tmp->rtp = ast_rtp_instance_new(NULL, sched, &bindaddr, NULL);
+ tmp->parent = client;
+ if (!tmp->rtp) {
+ ast_log(LOG_WARNING, "Out of RTP sessions?\n");
+@@ -825,18 +818,18 @@
+
+ /* Set Frame packetization */
+ if (i->rtp)
+- ast_rtp_codec_setpref(i->rtp, &i->prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
+
+ tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
+ fmt = ast_best_codec(tmp->nativeformats);
+
+ if (i->rtp) {
+- ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
+- ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
++ ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
++ ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
+ }
+ if (i->vrtp) {
+- ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
+- ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
++ ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
++ ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
+ }
+ if (state == AST_STATE_RING)
+ tmp->rings = 1;
+@@ -942,9 +935,9 @@
+ if (p->owner)
+ ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
+ if (p->rtp)
+- ast_rtp_destroy(p->rtp);
++ ast_rtp_instance_destroy(p->rtp);
+ if (p->vrtp)
+- ast_rtp_destroy(p->vrtp);
++ ast_rtp_instance_destroy(p->vrtp);
+ jingle_free_candidates(p->theircandidates);
+ ast_free(p);
+ }
+@@ -1009,8 +1002,8 @@
+ ast_copy_string(p->audio_content_name, iks_find_attrib(content, "name"), sizeof(p->audio_content_name));
+
+ while (codec) {
+- ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
+- ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
++ ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+ codec = iks_next(codec);
+ }
+ }
+@@ -1025,8 +1018,8 @@
+ ast_copy_string(p->video_content_name, iks_find_attrib(content, "name"), sizeof(p->video_content_name));
+
+ while (codec) {
+- ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
+- ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
++ ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+ codec = iks_next(codec);
+ }
+ }
+@@ -1079,7 +1072,7 @@
+ sin.sin_port = htons(tmp->port);
+ snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag);
+
+- ast_rtp_stun_request(p->rtp, &sin, username);
++ ast_rtp_instance_stun_request(p->rtp, &sin, username);
+ tmp = tmp->next;
+ }
+ return 1;
+@@ -1169,7 +1162,7 @@
+
+ if (!p->rtp)
+ return &ast_null_frame;
+- f = ast_rtp_read(p->rtp);
++ f = ast_rtp_instance_read(p->rtp, 0);
+ jingle_update_stun(p->parent, p);
+ if (p->owner) {
+ /* We already hold the channel lock */
+@@ -1220,7 +1213,7 @@
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (p->rtp) {
+- res = ast_rtp_write(p->rtp, frame);
++ res = ast_rtp_instance_write(p->rtp, frame);
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+@@ -1229,7 +1222,7 @@
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (p->vrtp) {
+- res = ast_rtp_write(p->vrtp, frame);
++ res = ast_rtp_instance_write(p->vrtp, frame);
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+@@ -1879,7 +1872,7 @@
+ return 0;
+ }
+
+- ast_rtp_proto_register(&jingle_rtp);
++ ast_rtp_glue_register(&jingle_rtp_glue);
+ ast_cli_register_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
+ /* Make sure we can register our channel type */
+ if (ast_channel_register(&jingle_tech)) {
+@@ -1902,7 +1895,7 @@
+ ast_cli_unregister_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
+ /* First, take us out of the channel loop */
+ ast_channel_unregister(&jingle_tech);
+- ast_rtp_proto_unregister(&jingle_rtp);
++ ast_rtp_glue_unregister(&jingle_rtp_glue);
+
+ if (!ast_mutex_lock(&jinglelock)) {
+ /* Hangup all interfaces if they have an owner */
+Index: channels/chan_dahdi.c
+===================================================================
+--- a/channels/chan_dahdi.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_dahdi.c (.../trunk) (revision 186562)
+@@ -153,9 +153,6 @@
+ <description>
+ <para>This application will Accept the R2 call either with charge or no charge.</para>
+ </description>
+- <description>
+- <para>This application will Accept the R2 call either with charge or no charge.</para>
+- </description>
+ </application>
+ ***/
+
+@@ -2535,9 +2532,6 @@
+ /* Don't delete if we don't think it's conferenced at all (implied) */
+ ) return 0;
+ memset(&zi, 0, sizeof(zi));
+- zi.chan = 0;
+- zi.confno = 0;
+- zi.confmode = 0;
+ if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
+ ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
+ return -1;
+@@ -2593,11 +2587,12 @@
+
+ static int reset_conf(struct dahdi_pvt *p)
+ {
+- struct dahdi_confinfo zi;
+- memset(&zi, 0, sizeof(zi));
+ p->confno = -1;
+ memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
+ if (p->subs[SUB_REAL].dfd > -1) {
++ struct dahdi_confinfo zi;
++
++ memset(&zi, 0, sizeof(zi));
+ if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
+ ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
+ }
+@@ -2911,8 +2906,7 @@
+ p->saveconf.confmode = 0;
+ return -1;
+ }
+- c.chan = 0;
+- c.confno = 0;
++ memset(&c, 0, sizeof(c));
+ c.confmode = DAHDI_CONF_NORMAL;
+ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
+ if (res) {
+@@ -2962,10 +2956,7 @@
+ 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);
++ ast_event_queue_and_cache(event);
+
+ if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
+ snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
+@@ -3019,7 +3010,6 @@
+ event = ast_event_get_cached(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_EXISTS,
+ AST_EVENT_IE_END);
+
+ if (event) {
+@@ -3166,7 +3156,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);
+ }
+@@ -3207,12 +3197,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 */
+@@ -3224,8 +3214,8 @@
+ 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
+@@ -3291,14 +3281,14 @@
+
+ switch (mysig) {
+ case SIG_FEATD:
+- l = ast->cid.cid_num;
++ 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;
++ l = ast->connected.id.number;
+ if (l)
+ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
+ else
+@@ -3394,6 +3384,7 @@
+ case SIG_MFCR2:
+ /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
+ p->dialdest[0] = '\0';
++ p->dialing = 1;
+ break;
+ default:
+ ast_debug(1, "not yet implemented\n");
+@@ -3432,7 +3423,7 @@
+ }
+
+ if (!p->hidecallerid) {
+- l = ast->cid.cid_num;
++ l = ast->connected.id.number;
+ } else {
+ l = NULL;
+ }
+@@ -3481,10 +3472,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);
+@@ -3596,9 +3587,9 @@
+ 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;
+ }
+ }
+
+@@ -3812,7 +3803,7 @@
+ }
+ }
+ 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));
++ p->use_callingpres ? ast->connected.id.number_presentation : (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;
+@@ -4468,6 +4459,7 @@
+ p->onhooktime = time(NULL);
+ #if defined(HAVE_PRI) || defined(HAVE_SS7)
+ p->proceeding = 0;
++ p->dialing = 0;
+ p->progress = 0;
+ p->alerting = 0;
+ p->setup_ack = 0;
+@@ -4604,6 +4596,7 @@
+ case SIG_FXOGS:
+ case SIG_FXOLS:
+ case SIG_FXOKS:
++ memset(&par, 0, sizeof(par));
+ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
+ if (!res) {
+ #if 0
+@@ -4769,6 +4762,7 @@
+ /* Send a pri acknowledge */
+ if (!pri_grab(p, p->pri)) {
+ p->proceeding = 1;
++ p->dialing = 0;
+ res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
+ pri_rel(p->pri);
+ } else {
+@@ -5580,6 +5574,7 @@
+ }
+
+ /* No alarms on the span. Check for channel alarms. */
++ memset(&params, 0, sizeof(params));
+ if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
+ return params.chan_alarms;
+
+@@ -6206,6 +6201,7 @@
+ {
+ struct dahdi_params par;
+
++ memset(&par, 0, sizeof(par));
+ if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
+ {
+ if (!par.rxisoffhook)
+@@ -6698,6 +6694,7 @@
+ {
+ struct dahdi_params ps;
+
++ memset(&ps, 0, sizeof(ps));
+ ps.channo = p->channel;
+ if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
+ ast_mutex_unlock(&p->lock);
+@@ -7209,6 +7206,7 @@
+ ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
+ }
+ p->proceeding = 1;
++ p->dialing = 0;
+ }
+ #endif
+ #ifdef HAVE_SS7
+@@ -7390,6 +7388,7 @@
+ if (!tmp)
+ return NULL;
+ tmp->tech = &dahdi_tech;
++ memset(&ps, 0, sizeof(ps));
+ ps.channo = i->channel;
+ res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
+ if (res) {
+@@ -7407,7 +7406,7 @@
+ deflaw = AST_FORMAT_ULAW;
+ }
+ ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
+- tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
++ tmp->nativeformats = deflaw;
+ /* Start out assuming ulaw since it's smaller :) */
+ tmp->rawreadformat = deflaw;
+ tmp->readformat = deflaw;
+@@ -9017,8 +9016,8 @@
+ #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->cidlen = ast_callerid_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
+ }
+@@ -10219,9 +10218,10 @@
+ #endif
+ } else {
+ chan_sig = tmp->sig;
+- memset(&p, 0, sizeof(p));
+- if (tmp->subs[SUB_REAL].dfd > -1)
++ if (tmp->subs[SUB_REAL].dfd > -1) {
++ memset(&p, 0, sizeof(p));
+ res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
++ }
+ }
+ /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
+ switch (chan_sig) {
+@@ -10602,9 +10602,10 @@
+ if (!p->sig || (p->sig == SIG_FXSLS))
+ return 1;
+ /* Check hook state */
+- if (p->subs[SUB_REAL].dfd > -1)
++ if (p->subs[SUB_REAL].dfd > -1) {
++ memset(&par, 0, sizeof(par));
+ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
+- else {
++ } else {
+ /* Assume not off hook on CVRS */
+ res = 0;
+ par.rxisoffhook = 0;
+@@ -11940,6 +11941,7 @@
+
+ if (!explicit) {
+ spanfd = pri_active_dchan_fd(pri);
++ memset(&param, 0, sizeof(param));
+ if (ioctl(spanfd, DAHDI_GET_PARAMS, &param))
+ return -1;
+ span = pris[param.spanno - 1].prilogicalspan;
+@@ -12991,8 +12993,12 @@
+ ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
+ pri->pvts[chanpos]->dsp_features = 0;
+ }
++ /* Bring voice path up */
++ f.subclass = AST_CONTROL_PROGRESS;
++ dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
+ }
+ pri->pvts[chanpos]->progress = 1;
++ pri->pvts[chanpos]->dialing = 0;
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ }
+ }
+@@ -13024,6 +13030,7 @@
+ dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
+ }
+ pri->pvts[chanpos]->proceeding = 1;
++ pri->pvts[chanpos]->dialing = 0;
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ }
+ }
+@@ -13400,6 +13407,7 @@
+ ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
+ return -1;
+ }
++ memset(&p, 0, sizeof(p));
+ res = ioctl(pri->fds[i], DAHDI_GET_PARAMS, &p);
+ if (res) {
+ dahdi_close_pri_fd(pri, i);
+@@ -13421,6 +13429,7 @@
+ pri->dchanavail[i] |= DCHAN_NOTINALARM;
+ else
+ pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
++ memset(&bi, 0, sizeof(bi));
+ bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+ bi.numbufs = 32;
+@@ -14632,12 +14641,14 @@
+ memset(&ci, 0, sizeof(ci));
+ ps.channo = tmp->channel;
+ if (tmp->subs[SUB_REAL].dfd > -1) {
++ memset(&ci, 0, sizeof(ci));
+ if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
+ ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, ci.confmode);
+ }
+ if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
+ ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
+ }
++ memset(&ps, 0, sizeof(ps));
+ if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
+ ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
+ } else {
+@@ -15017,7 +15028,7 @@
+ AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
+ AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
+ AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
+- AST_CLI_DEFINE(dahdi_set_dnd, "Set software gain on a channel"),
++ AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
+ };
+
+ #define TRANSFER 0
+@@ -15297,6 +15308,7 @@
+ ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan, strerror(errno));
+ return -1;
+ }
++ memset(&p, 0, sizeof(p));
+ res = ioctl(link->fds[curfd], DAHDI_GET_PARAMS, &p);
+ if (res) {
+ dahdi_close_ss7_fd(link, curfd);
+@@ -15309,6 +15321,7 @@
+ return -1;
+ }
+
++ memset(&bi, 0, sizeof(bi));
+ bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+ bi.numbufs = 32;
+Index: channels/chan_phone.c
+===================================================================
+--- a/channels/chan_phone.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_phone.c (.../trunk) (revision 186562)
+@@ -303,13 +303,13 @@
+ snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
+ }
+ /* the standard format of ast->callerid is: "name" <number>, 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;
+
+Index: channels/chan_h323.c
+===================================================================
+--- a/channels/chan_h323.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_h323.c (.../trunk) (revision 186562)
+@@ -76,7 +76,7 @@
+ #include "asterisk/utils.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/cli.h"
+@@ -161,7 +161,7 @@
+ char accountcode[256]; /*!< Account code */
+ char rdnis[80]; /*!< Referring DNIS, if available */
+ int amaflags; /*!< AMA Flags */
+- struct ast_rtp *rtp; /*!< RTP Session */
++ struct ast_rtp_instance *rtp; /*!< RTP Session */
+ struct ast_dsp *vad; /*!< Used for in-band DTMF detection */
+ int nativeformats; /*!< Codec formats supported by a channel */
+ int needhangup; /*!< Send hangup when Asterisk is ready */
+@@ -254,7 +254,7 @@
+ .write = oh323_write,
+ .indicate = oh323_indicate,
+ .fixup = oh323_fixup,
+- .bridge = ast_rtp_bridge,
++ .bridge = ast_rtp_instance_bridge,
+ };
+
+ static const char* redirectingreason2str(int redirectingreason)
+@@ -381,8 +381,8 @@
+ if (pvt->update_rtp_info > 0) {
+ if (pvt->rtp) {
+ ast_jb_configure(c, &global_jbconf);
+- ast_channel_set_fd(c, 0, ast_rtp_fd(pvt->rtp));
+- ast_channel_set_fd(c, 1, ast_rtcp_fd(pvt->rtp));
++ ast_channel_set_fd(c, 0, ast_rtp_instance_fd(pvt->rtp, 0));
++ ast_channel_set_fd(c, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+ ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
+ }
+ pvt->update_rtp_info = -1;
+@@ -444,7 +444,7 @@
+ AST_SCHED_DEL(sched, pvt->DTMFsched);
+
+ if (pvt->rtp) {
+- ast_rtp_destroy(pvt->rtp);
++ ast_rtp_instance_destroy(pvt->rtp);
+ }
+
+ /* Free dsp used for in-band DTMF detection */
+@@ -510,7 +510,7 @@
+ if (h323debug) {
+ ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, c->name);
+ }
+- ast_rtp_senddigit_begin(pvt->rtp, digit);
++ ast_rtp_instance_dtmf_begin(pvt->rtp, digit);
+ ast_mutex_unlock(&pvt->lock);
+ } else if (pvt->txDtmfDigit != digit) {
+ /* in-band DTMF */
+@@ -549,7 +549,7 @@
+ if (h323debug) {
+ ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s, duration %d\n", digit, c->name, duration);
+ }
+- ast_rtp_senddigit_end(pvt->rtp, digit);
++ ast_rtp_instance_dtmf_end(pvt->rtp, digit);
+ ast_mutex_unlock(&pvt->lock);
+ } else {
+ /* in-band DTMF */
+@@ -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"))
+@@ -747,11 +747,11 @@
+
+ /* Only apply it for the first packet, we just need the correct ip/port */
+ if (pvt->options.nat) {
+- ast_rtp_setnat(pvt->rtp, pvt->options.nat);
++ ast_rtp_instance_set_prop(pvt->rtp, AST_RTP_PROPERTY_NAT, pvt->options.nat);
+ pvt->options.nat = 0;
+ }
+
+- f = ast_rtp_read(pvt->rtp);
++ f = ast_rtp_instance_read(pvt->rtp, 0);
+ /* Don't send RFC2833 if we're not supposed to */
+ if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & (H323_DTMF_RFC2833 | H323_DTMF_CISCO))) {
+ return &ast_null_frame;
+@@ -808,7 +808,7 @@
+ break;
+ case 1:
+ if (pvt->rtp)
+- fr = ast_rtcp_read(pvt->rtp);
++ fr = ast_rtp_instance_read(pvt->rtp, 1);
+ else
+ fr = &ast_null_frame;
+ break;
+@@ -842,7 +842,7 @@
+ if (pvt) {
+ ast_mutex_lock(&pvt->lock);
+ if (pvt->rtp && !pvt->recvonly)
+- res = ast_rtp_write(pvt->rtp, frame);
++ res = ast_rtp_instance_write(pvt->rtp, frame);
+ __oh323_update_info(c, pvt);
+ ast_mutex_unlock(&pvt->lock);
+ }
+@@ -910,7 +910,7 @@
+ res = 0;
+ break;
+ case AST_CONTROL_SRCUPDATE:
+- ast_rtp_new_source(pvt->rtp);
++ ast_rtp_instance_new_source(pvt->rtp);
+ res = 0;
+ break;
+ case AST_CONTROL_PROCEEDING:
+@@ -946,17 +946,17 @@
+
+ static int __oh323_rtp_create(struct oh323_pvt *pvt)
+ {
+- struct in_addr our_addr;
++ struct sockaddr_in our_addr;
+
+ if (pvt->rtp)
+ return 0;
+
+- if (ast_find_ourip(&our_addr, bindaddr)) {
++ if (ast_find_ourip(&our_addr.sin_addr, bindaddr)) {
+ ast_mutex_unlock(&pvt->lock);
+ ast_log(LOG_ERROR, "Unable to locate local IP address for RTP stream\n");
+ return -1;
+ }
+- pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, our_addr);
++ pvt->rtp = ast_rtp_instance_new(NULL, sched, &our_addr, NULL);
+ if (!pvt->rtp) {
+ ast_mutex_unlock(&pvt->lock);
+ ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
+@@ -965,24 +965,24 @@
+ if (h323debug)
+ ast_debug(1, "Created RTP channel\n");
+
+- ast_rtp_setqos(pvt->rtp, tos, cos, "H323 RTP");
++ ast_rtp_instance_set_qos(pvt->rtp, tos, cos, "H323 RTP");
+
+ if (h323debug)
+ ast_debug(1, "Setting NAT on RTP to %d\n", pvt->options.nat);
+- ast_rtp_setnat(pvt->rtp, pvt->options.nat);
++ ast_rtp_instance_set_prop(pvt->rtp, AST_RTP_PROPERTY_NAT, pvt->options.nat);
+
+ if (pvt->dtmf_pt[0] > 0)
+- ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt[0], "audio", "telephone-event", 0);
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pvt->dtmf_pt[0], "audio", "telephone-event", 0);
+ if (pvt->dtmf_pt[1] > 0)
+- ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt[1], "audio", "cisco-telephone-event", 0);
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pvt->dtmf_pt[1], "audio", "cisco-telephone-event", 0);
+
+ if (pvt->peercapability)
+- ast_rtp_codec_setpref(pvt->rtp, &pvt->peer_prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->peer_prefs);
+
+ if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+ ast_jb_configure(pvt->owner, &global_jbconf);
+- ast_channel_set_fd(pvt->owner, 0, ast_rtp_fd(pvt->rtp));
+- ast_channel_set_fd(pvt->owner, 1, ast_rtcp_fd(pvt->rtp));
++ ast_channel_set_fd(pvt->owner, 0, ast_rtp_instance_fd(pvt->rtp, 0));
++ ast_channel_set_fd(pvt->owner, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+ ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */
+ ast_channel_unlock(pvt->owner);
+ } else
+@@ -1028,13 +1028,13 @@
+ if (!pvt->rtp)
+ __oh323_rtp_create(pvt);
+ #if 0
+- ast_channel_set_fd(ch, 0, ast_rtp_fd(pvt->rtp));
+- ast_channel_set_fd(ch, 1, ast_rtcp_fd(pvt->rtp));
++ ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(pvt->rtp, 0));
++ ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(pvt->rtp, 1));
+ #endif
+ #ifdef VIDEO_SUPPORT
+ if (pvt->vrtp) {
+- ast_channel_set_fd(ch, 2, ast_rtp_fd(pvt->vrtp));
+- ast_channel_set_fd(ch, 3, ast_rtcp_fd(pvt->vrtp));
++ ast_channel_set_fd(ch, 2, ast_rtp_instance_fd(pvt->vrtp, 0));
++ ast_channel_set_fd(ch, 3, ast_rtp_instance_fd(pvt->vrtp, 1));
+ }
+ #endif
+ #ifdef T38_SUPPORT
+@@ -1112,7 +1112,7 @@
+ }
+ if (!pvt->cd.call_token) {
+ ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
+- ast_rtp_destroy(pvt->rtp);
++ ast_rtp_instance_destroy(pvt->rtp);
+ ast_free(pvt);
+ return NULL;
+ }
+@@ -1912,7 +1912,7 @@
+ return NULL;
+ }
+ /* figure out our local RTP port and tell the H.323 stack about it */
+- ast_rtp_get_us(pvt->rtp, &us);
++ ast_rtp_instance_get_local_address(pvt->rtp, &us);
+ ast_mutex_unlock(&pvt->lock);
+
+ ast_copy_string(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr));
+@@ -1931,7 +1931,6 @@
+ {
+ struct oh323_pvt *pvt;
+ struct sockaddr_in them;
+- struct rtpPayloadType rtptype;
+ int nativeformats_changed;
+ enum { NEED_NONE, NEED_HOLD, NEED_UNHOLD } rtp_change = NEED_NONE;
+
+@@ -1953,7 +1952,7 @@
+ __oh323_rtp_create(pvt);
+
+ if ((pt == 2) && (pvt->jointcapability & AST_FORMAT_G726_AAL2)) {
+- ast_rtp_set_rtpmap_type(pvt->rtp, pt, "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD);
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, pt, "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD);
+ }
+
+ them.sin_family = AF_INET;
+@@ -1962,13 +1961,13 @@
+ them.sin_port = htons(remotePort);
+
+ if (them.sin_addr.s_addr) {
+- ast_rtp_set_peer(pvt->rtp, &them);
++ ast_rtp_instance_set_remote_address(pvt->rtp, &them);
+ if (pvt->recvonly) {
+ pvt->recvonly = 0;
+ rtp_change = NEED_UNHOLD;
+ }
+ } else {
+- ast_rtp_stop(pvt->rtp);
++ ast_rtp_instance_stop(pvt->rtp);
+ if (!pvt->recvonly) {
+ pvt->recvonly = 1;
+ rtp_change = NEED_HOLD;
+@@ -1978,7 +1977,7 @@
+ /* Change native format to reflect information taken from OLC/OLCAck */
+ nativeformats_changed = 0;
+ if (pt != 128 && pvt->rtp) { /* Payload type is invalid, so try to use previously decided */
+- rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
++ struct ast_rtp_payload_type rtptype = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(pvt->rtp), pt);
+ if (h323debug)
+ ast_debug(1, "Native format is set to %d from %d by RTP payload type %d\n", rtptype.code, pvt->nativeformats, pt);
+ if (pvt->nativeformats != rtptype.code) {
+@@ -2359,7 +2358,7 @@
+ }
+ if (pvt->rtp) {
+ /* Immediately stop RTP */
+- ast_rtp_destroy(pvt->rtp);
++ ast_rtp_instance_destroy(pvt->rtp);
+ pvt->rtp = NULL;
+ }
+ /* Free dsp used for in-band DTMF detection */
+@@ -2421,7 +2420,7 @@
+ return;
+ }
+ if (pvt->rtp) {
+- ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", (is_cisco ? "cisco-telephone-event" : "telephone-event"), 0);
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, payload, "audio", (is_cisco ? "cisco-telephone-event" : "telephone-event"), 0);
+ }
+ pvt->dtmf_pt[is_cisco ? 1 : 0] = payload;
+ ast_mutex_unlock(&pvt->lock);
+@@ -2452,7 +2451,7 @@
+ }
+ }
+ if (pvt->rtp)
+- ast_rtp_codec_setpref(pvt->rtp, &pvt->peer_prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->peer_prefs);
+ }
+ ast_mutex_unlock(&pvt->lock);
+ }
+@@ -3113,19 +3112,19 @@
+ static struct ast_cli_entry cli_h323_reload =
+ AST_CLI_DEFINE(handle_cli_h323_reload, "Reload H.323 configuration");
+
+-static enum ast_rtp_get_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+ struct oh323_pvt *pvt;
+- enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
+
+ if (!(pvt = (struct oh323_pvt *)chan->tech_pvt))
+- return AST_RTP_GET_FAILED;
++ return AST_RTP_GLUE_RESULT_FORBID;
+
+ ast_mutex_lock(&pvt->lock);
+- *rtp = pvt->rtp;
++ *instance = pvt->rtp ? ao2_ref(pvt->rtp, +1), pvt->rtp : NULL;
+ #if 0
+ if (pvt->options.bridge) {
+- res = AST_RTP_TRY_NATIVE;
++ res = AST_RTP_GLUE_RESULT_REMOTE;
+ }
+ #endif
+ ast_mutex_unlock(&pvt->lock);
+@@ -3133,11 +3132,6 @@
+ return res;
+ }
+
+-static enum ast_rtp_get_result oh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+-{
+- return AST_RTP_GET_FAILED;
+-}
+-
+ static char *convertcap(int cap)
+ {
+ switch (cap) {
+@@ -3165,7 +3159,7 @@
+ }
+ }
+
+-static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
++static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active)
+ {
+ /* XXX Deal with Video */
+ struct oh323_pvt *pvt;
+@@ -3183,19 +3177,18 @@
+ ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
+ return -1;
+ }
+- ast_rtp_get_peer(rtp, &them);
+- ast_rtp_get_us(rtp, &us);
++ ast_rtp_instance_get_remote_address(rtp, &them);
++ ast_rtp_instance_get_local_address(rtp, &us);
+ #if 0 /* Native bridge still isn't ready */
+ h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode);
+ #endif
+ return 0;
+ }
+
+-static struct ast_rtp_protocol oh323_rtp = {
++static struct ast_rtp_glue oh323_rtp_glue = {
+ .type = "H323",
+ .get_rtp_info = oh323_get_rtp_peer,
+- .get_vrtp_info = oh323_get_vrtp_peer,
+- .set_rtp_peer = oh323_set_rtp_peer,
++ .update_peer = oh323_set_rtp_peer,
+ };
+
+ static enum ast_module_load_result load_module(void)
+@@ -3250,7 +3243,7 @@
+ }
+ ast_cli_register_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+
+- ast_rtp_proto_register(&oh323_rtp);
++ ast_rtp_glue_register(&oh323_rtp_glue);
+
+ /* Register our callback functions */
+ h323_callback_register(setup_incoming_call,
+@@ -3271,7 +3264,7 @@
+ /* start the h.323 listener */
+ if (h323_start_listener(h323_signalling_port, bindaddr)) {
+ ast_log(LOG_ERROR, "Unable to create H323 listener.\n");
+- ast_rtp_proto_unregister(&oh323_rtp);
++ ast_rtp_glue_unregister(&oh323_rtp_glue);
+ ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+ ast_cli_unregister(&cli_h323_reload);
+ h323_end_process();
+@@ -3310,7 +3303,7 @@
+ ast_cli_unregister(&cli_h323_reload);
+
+ ast_channel_unregister(&oh323_tech);
+- ast_rtp_proto_unregister(&oh323_rtp);
++ ast_rtp_glue_unregister(&oh323_rtp_glue);
+
+ if (!ast_mutex_lock(&iflock)) {
+ /* hangup all interfaces if they have an owner */
+Index: channels/chan_sip.c
+===================================================================
+--- a/channels/chan_sip.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_sip.c (.../trunk) (revision 186562)
+@@ -229,7 +229,7 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/udptl.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/manager.h"
+@@ -271,6 +271,7 @@
+ #include "asterisk/ast_version.h"
+ #include "asterisk/event.h"
+ #include "asterisk/tcptls.h"
++#include "asterisk/stun.h"
+
+ /*** DOCUMENTATION
+ <application name="SIPDtmfMode" language="en_US">
+@@ -691,6 +692,7 @@
+ AUTH_PEER_NOT_DYNAMIC = -6,
+ AUTH_ACL_FAILED = -7,
+ AUTH_BAD_TRANSPORT = -8,
++ AUTH_RTP_FAILED = 9,
+ };
+
+ /*! \brief States for outbound registrations (with register= lines in sip.conf */
+@@ -940,7 +942,55 @@
+ { 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 if we have
+ allowsubscribe and allowrefer on in sip.conf.
+@@ -1011,6 +1061,7 @@
+ #define DEFAULT_USERAGENT "Asterisk PBX" /*!< Default Useragent: header unless re-defined in sip.conf */
+ #define DEFAULT_SDPSESSION "Asterisk PBX" /*!< Default SDP session name, (s=) header unless re-defined in sip.conf */
+ #define DEFAULT_SDPOWNER "root" /*!< Default SDP username field in (o=) header unless re-defined in sip.conf */
++#define DEFAULT_ENGINE "asterisk" /*!< Default RTP engine to use for sessions */
+ #endif
+ /*@}*/
+
+@@ -1029,6 +1080,7 @@
+ static char default_mohsuggest[MAX_MUSICCLASS]; /*!< Global setting for moh class to suggest when putting
+ * a bridged channel on hold */
+ static char default_parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */
++static char default_engine[256]; /*!< Default RTP engine */
+ 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 */
+@@ -1350,7 +1402,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 */
+@@ -1369,6 +1424,10 @@
+ /* 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_PREFERRED_CODEC (1 << 13) /*!< GDP: Only respond with single most preferred joint codec */
+ #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? */
+@@ -1398,7 +1457,8 @@
+ (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_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \
++ SIP_PAGE2_RPID_IMMEDIATE)
+
+ /*@}*/
+
+@@ -1455,7 +1515,6 @@
+ /*! \brief T38 States for a call */
+ enum t38state {
+ T38_DISABLED = 0, /*!< Not enabled */
+- T38_LOCAL_DIRECT, /*!< Offered from local */
+ T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
+ T38_PEER_DIRECT, /*!< Offered from peer */
+ T38_PEER_REINVITE, /*!< Offered from peer - REINVITE */
+@@ -1469,6 +1528,7 @@
+ int peercapability; /*!< Peers T38 capability */
+ int jointcapability; /*!< Supported T38 capability at both ends */
+ enum t38state state; /*!< T.38 state */
++ unsigned int direct:1; /*!< Whether the T38 came from the initial invite or not */
+ };
+
+ /*! \brief Parameters to know status of transfer */
+@@ -1606,10 +1666,9 @@
+ AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */
+ /* we only store the part in <brackets> 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 */
++ AST_STRING_FIELD(engine); /*!< RTP engine to use */
+ );
+ char via[128]; /*!< Via: header */
+ struct sip_socket socket; /*!< The socket used for this dialog */
+@@ -1669,17 +1728,19 @@
+ struct ast_channel *owner; /*!< Who owns us (if we have an owner) */
+ struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */
+ int route_persistant; /*!< Is this the "real" route? */
+- struct ast_variable *notify_headers; /*!< Custom notify type */
++ struct ast_variable *notify_headers; /*!< Custom notify type */
+ struct sip_auth *peerauth; /*!< Realm authentication */
+ int noncecount; /*!< Nonce-count */
+ char lastmsg[256]; /*!< Last Message sent/received */
+ int amaflags; /*!< AMA Flags */
+ int pendinginvite; /*!< Any pending INVITE or state NOTIFY (in subscribe pvt's) ? (seqno of this) */
++ int glareinvite; /*!< A invite received while a pending invite is already present is stored here. Its seqno is the
++ value. Since this glare invite's seqno is not the same as the pending invite's, it must be
++ held in order to properly process acknowledgements for our 491 response. */
+ struct sip_request initreq; /*!< Latest request that opened a new transaction
+ within this dialog.
+- NOT the request that opened the dialog
+- */
+-
++ NOT the request that opened the dialog */
++
+ int initid; /*!< Auto-congest ID if appropriate (scheduler) */
+ int waitid; /*!< Wait ID for scheduler after 491 or other delays */
+ int autokillid; /*!< Auto-kill ID (scheduler) */
+@@ -1690,15 +1751,15 @@
+ int stateid; /*!< SUBSCRIBE: ID for devicestate subscriptions */
+ int laststate; /*!< SUBSCRIBE: Last known extension state */
+ int dialogver; /*!< SUBSCRIBE: Version for subscription dialog-info */
+-
++
+ struct ast_dsp *vad; /*!< Inband DTMF Detection dsp */
+-
++
+ struct sip_peer *relatedpeer; /*!< If this dialog is related to a peer, which one
+ Used in peerpoke, mwi subscriptions */
+ struct sip_registry *registry; /*!< If this is a REGISTER dialog, to which registry */
+- struct ast_rtp *rtp; /*!< RTP Session */
+- struct ast_rtp *vrtp; /*!< Video RTP session */
+- struct ast_rtp *trtp; /*!< Text RTP session */
++ struct ast_rtp_instance *rtp; /*!< RTP Session */
++ struct ast_rtp_instance *vrtp; /*!< Video RTP session */
++ struct ast_rtp_instance *trtp; /*!< Text RTP session */
+ struct sip_pkt *packets; /*!< Packets scheduled for re-transmission */
+ struct sip_history_head *history; /*!< History of this SIP dialog */
+ size_t history_entries; /*!< Number of entires in the history */
+@@ -1841,6 +1902,7 @@
+ 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) */
++ AST_STRING_FIELD(engine); /*!< RTP Engine to use */
+ );
+ struct sip_socket socket; /*!< Socket used for this peer */
+ unsigned int transports:3; /*!< Transports (enum sip_transport) that are acceptable for this peer */
+@@ -2228,11 +2290,11 @@
+ 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);
+-static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable);
++static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable);
+ static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
+ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
+ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
+@@ -2249,7 +2311,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 */
+@@ -2293,7 +2355,7 @@
+ 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);
++static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38);
+ static void do_setnat(struct sip_pvt *p, int natflags);
+ static void stop_media_flows(struct sip_pvt *p);
+
+@@ -2497,11 +2559,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);
+@@ -2528,6 +2593,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);
+@@ -2536,7 +2602,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);
+@@ -2561,14 +2626,6 @@
+ 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);
+
+-/*----- RTP interface functions */
+-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
+-static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+-static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+-static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+-static int sip_get_codec(struct ast_channel *chan);
+-static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
+-
+ /*------ T38 Support --------- */
+ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
+ static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
+@@ -2589,6 +2646,9 @@
+ static enum st_mode st_get_mode(struct sip_pvt *);
+ static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p);
+
++/*------- RTP Glue functions -------- */
++static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, int codecs, int nat_active);
++
+ /*!--- 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);
+@@ -2617,8 +2677,8 @@
+ .fixup = sip_fixup, /* called with chan locked */
+ .send_digit_begin = sip_senddigit_begin, /* called with chan unlocked */
+ .send_digit_end = sip_senddigit_end,
+- .bridge = ast_rtp_bridge, /* XXX chan unlocked ? */
+- .early_bridge = ast_rtp_early_bridge,
++ .bridge = ast_rtp_instance_bridge, /* XXX chan unlocked ? */
++ .early_bridge = ast_rtp_instance_early_bridge,
+ .send_text = sip_sendtext, /* called with chan locked */
+ .func_channel_read = acf_channel_read,
+ .queryoption = sip_queryoption,
+@@ -2691,17 +2751,6 @@
+ return errorvalue;
+ }
+
+-
+-/*! \brief Interface structure with callbacks used to connect to RTP module */
+-static struct ast_rtp_protocol sip_rtp = {
+- .type = "SIP",
+- .get_rtp_info = sip_get_rtp_peer,
+- .get_vrtp_info = sip_get_vrtp_peer,
+- .get_trtp_info = sip_get_trtp_peer,
+- .set_rtp_peer = sip_set_rtp_peer,
+- .get_codec = sip_get_codec,
+-};
+-
+ /*!
+ * duplicate a list of channel variables, \return the copy.
+ */
+@@ -3896,7 +3945,6 @@
+ /* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
+ if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT)) {
+ switch (p->t38.state) {
+- case T38_LOCAL_DIRECT:
+ case T38_LOCAL_REINVITE:
+ case T38_PEER_DIRECT:
+ case T38_PEER_REINVITE:
+@@ -4591,11 +4639,11 @@
+
+ if (p->rtp) {
+ ast_debug(1, "Setting NAT on RTP to %s\n", mode);
+- ast_rtp_setnat(p->rtp, natflags);
++ ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_NAT, natflags);
+ }
+ if (p->vrtp) {
+ ast_debug(1, "Setting NAT on VRTP to %s\n", mode);
+- ast_rtp_setnat(p->vrtp, natflags);
++ ast_rtp_instance_set_prop(p->vrtp, AST_RTP_PROPERTY_NAT, natflags);
+ }
+ if (p->udptl) {
+ ast_debug(1, "Setting NAT on UDPTL to %s\n", mode);
+@@ -4603,7 +4651,7 @@
+ }
+ if (p->trtp) {
+ ast_debug(1, "Setting NAT on TRTP to %s\n", mode);
+- ast_rtp_setnat(p->trtp, natflags);
++ ast_rtp_instance_set_prop(p->trtp, AST_RTP_PROPERTY_NAT, natflags);
+ }
+ }
+
+@@ -4618,6 +4666,10 @@
+ if (old == state)
+ return;
+
++ if (state == T38_PEER_DIRECT) {
++ p->t38.direct = 1;
++ }
++
+ p->t38.state = state;
+ ast_debug(2, "T38 state changed to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
+
+@@ -4691,6 +4743,51 @@
+ *to_sock = *from_sock;
+ }
+
++/*! \brief Initialize RTP portion of a dialog
++ * \returns -1 on failure, 0 on success
++ */
++static int dialog_initialize_rtp(struct sip_pvt *dialog)
++{
++ if (!sip_methods[dialog->method].need_rtp) {
++ return 0;
++ }
++
++ if (!(dialog->rtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr, NULL))) {
++ return -1;
++ }
++
++ if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (dialog->capability & AST_FORMAT_VIDEO_MASK)) {
++ if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr, NULL))) {
++ return -1;
++ }
++ ast_rtp_instance_set_timeout(dialog->vrtp, global_rtptimeout);
++ ast_rtp_instance_set_hold_timeout(dialog->vrtp, global_rtpholdtimeout);
++
++ ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1);
++ }
++
++ if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_TEXTSUPPORT)) {
++ if (!(dialog->trtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr, NULL))) {
++ return -1;
++ }
++ ast_rtp_instance_set_timeout(dialog->trtp, global_rtptimeout);
++ ast_rtp_instance_set_hold_timeout(dialog->trtp, global_rtpholdtimeout);
++
++ ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1);
++ }
++
++ ast_rtp_instance_set_timeout(dialog->rtp, global_rtptimeout);
++ ast_rtp_instance_set_hold_timeout(dialog->rtp, global_rtpholdtimeout);
++
++ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, 1);
++ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
++ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
++
++ ast_rtp_instance_set_qos(dialog->rtp, global_tos_audio, 0, "SIP RTP");
++
++ return 0;
++}
++
+ /*! \brief Create address structure from peer reference.
+ * This function copies data from peer to the dialog, so we don't have to look up the peer
+ * again from memory or database during the life time of the dialog.
+@@ -4718,17 +4815,6 @@
+ ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
+ ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+ dialog->capability = peer->capability;
+- if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) &&
+- (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) ||
+- !(dialog->capability & AST_FORMAT_VIDEO_MASK)) &&
+- dialog->vrtp) {
+- ast_rtp_destroy(dialog->vrtp);
+- dialog->vrtp = NULL;
+- }
+- if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_TEXTSUPPORT) && dialog->trtp) {
+- ast_rtp_destroy(dialog->trtp);
+- dialog->trtp = NULL;
+- }
+ dialog->prefs = peer->prefs;
+ if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
+ if (!dialog->udptl) {
+@@ -4744,29 +4830,28 @@
+ }
+ do_setnat(dialog, ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
+
++ ast_string_field_set(dialog, engine, peer->engine);
++
++ if (dialog_initialize_rtp(dialog)) {
++ return -1;
++ }
++
+ if (dialog->rtp) { /* Audio */
+- ast_rtp_setdtmf(dialog->rtp, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
+- ast_rtp_setdtmfcompensate(dialog->rtp, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
+- ast_rtp_set_rtptimeout(dialog->rtp, peer->rtptimeout);
+- ast_rtp_set_rtpholdtimeout(dialog->rtp, peer->rtpholdtimeout);
+- ast_rtp_set_rtpkeepalive(dialog->rtp, peer->rtpkeepalive);
++ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
++ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
++ ast_rtp_instance_set_timeout(dialog->rtp, peer->rtptimeout);
++ ast_rtp_instance_set_hold_timeout(dialog->rtp, peer->rtpholdtimeout);
+ /* Set Frame packetization */
+- ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs);
+ dialog->autoframing = peer->autoframing;
+ }
+ if (dialog->vrtp) { /* Video */
+- ast_rtp_setdtmf(dialog->vrtp, 0);
+- ast_rtp_setdtmfcompensate(dialog->vrtp, 0);
+- ast_rtp_set_rtptimeout(dialog->vrtp, peer->rtptimeout);
+- ast_rtp_set_rtpholdtimeout(dialog->vrtp, peer->rtpholdtimeout);
+- ast_rtp_set_rtpkeepalive(dialog->vrtp, peer->rtpkeepalive);
++ ast_rtp_instance_set_timeout(dialog->vrtp, peer->rtptimeout);
++ ast_rtp_instance_set_hold_timeout(dialog->vrtp, peer->rtpholdtimeout);
+ }
+ if (dialog->trtp) { /* Realtime text */
+- ast_rtp_setdtmf(dialog->trtp, 0);
+- ast_rtp_setdtmfcompensate(dialog->trtp, 0);
+- ast_rtp_set_rtptimeout(dialog->trtp, peer->rtptimeout);
+- ast_rtp_set_rtpholdtimeout(dialog->trtp, peer->rtpholdtimeout);
+- ast_rtp_set_rtpkeepalive(dialog->trtp, peer->rtpkeepalive);
++ ast_rtp_instance_set_timeout(dialog->trtp, peer->rtptimeout);
++ ast_rtp_instance_set_hold_timeout(dialog->trtp, peer->rtpholdtimeout);
+ }
+
+ ast_string_field_set(dialog, peername, peer->name);
+@@ -4779,7 +4864,10 @@
+ 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);
++ ast_string_field_set(dialog, engine, peer->engine);
+ ref_proxy(dialog, obproxy_get(dialog, peer));
+ dialog->callgroup = peer->callgroup;
+ dialog->pickupgroup = peer->pickupgroup;
+@@ -4875,6 +4963,12 @@
+ return res;
+ }
+
++ if (dialog_initialize_rtp(dialog)) {
++ return -1;
++ }
++
++ do_setnat(dialog, ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
++
+ ast_string_field_set(dialog, tohost, peername);
+
+ /* Get the outbound proxy information */
+@@ -4995,9 +5089,6 @@
+ } else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REPLACES")) {
+ /* We're replacing a call. */
+ p->options->replaces = ast_var_value(current);
+- } else if (!strcasecmp(ast_var_name(current), "T38CALL")) {
+- p->t38.state = T38_LOCAL_DIRECT;
+- ast_debug(1, "T38State change to %d on channel %s\n", p->t38.state, ast->name);
+ }
+ }
+
+@@ -5039,11 +5130,13 @@
+ p->t38.jointcapability = p->t38.capability;
+ ast_debug(2, "Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
+
++ sip_pvt_lock(p);
+ xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
++ sip_pvt_unlock(p);
+ if (xmitres == XMIT_ERROR)
+ return -1;
+ p->invitestate = INV_CALLING;
+-
++
+ /* Initialize auto-congest time */
+ AST_SCHED_REPLACE_UNREF(p->initid, sched, p->timer_b, auto_congest, p,
+ dialog_unref(_data, "dialog ptr dec when SCHED_REPLACE del op succeeded"),
+@@ -5150,15 +5243,13 @@
+ p->notify_headers = NULL;
+ }
+ if (p->rtp) {
+- ast_rtp_destroy(p->rtp);
++ ast_rtp_instance_destroy(p->rtp);
+ }
+ if (p->vrtp) {
+- ast_rtp_destroy(p->vrtp);
++ ast_rtp_instance_destroy(p->vrtp);
+ }
+ if (p->trtp) {
+- while (ast_rtp_get_bridged(p->trtp))
+- usleep(1);
+- ast_rtp_destroy(p->trtp);
++ ast_rtp_instance_destroy(p->trtp);
+ }
+ if (p->udptl)
+ ast_udptl_destroy(p->udptl);
+@@ -5677,42 +5768,50 @@
+
+ if (!p->pendinginvite) {
+ struct ast_channel *bridge = ast_bridged_channel(oldowner);
+- char *audioqos = "";
+- char *videoqos = "";
+- char *textqos = "";
++ char quality_buf[AST_MAX_USER_FIELD], *quality;
+
+- if (p->rtp)
+- ast_rtp_set_vars(oldowner, p->rtp);
++ if (p->rtp) {
++ ast_rtp_instance_set_stats_vars(oldowner, p->rtp);
++ }
+
+ if (bridge) {
+ struct sip_pvt *q = bridge->tech_pvt;
+
+- if (IS_SIP_TECH(bridge->tech) && q)
+- ast_rtp_set_vars(bridge, q->rtp);
++ if (IS_SIP_TECH(bridge->tech) && q) {
++ ast_rtp_instance_set_stats_vars(bridge, q->rtp);
++ }
+ }
+
+- if (p->vrtp)
+- videoqos = ast_rtp_get_quality(p->vrtp, NULL, RTPQOS_SUMMARY);
+- if (p->trtp)
+- textqos = ast_rtp_get_quality(p->trtp, NULL, RTPQOS_SUMMARY);
++ if (p->do_history || oldowner) {
++ if (p->rtp && (quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ if (p->do_history) {
++ append_history(p, "RTCPaudio", "Quality:%s", quality);
++ }
++ if (oldowner) {
++ pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", quality);
++ }
++ }
++ if (p->vrtp && (quality = ast_rtp_instance_get_quality(p->vrtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ if (p->do_history) {
++ append_history(p, "RTCPvideo", "Quality:%s", quality);
++ }
++ if (oldowner) {
++ pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", quality);
++ }
++ }
++ if (p->trtp && (quality = ast_rtp_instance_get_quality(p->trtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ if (p->do_history) {
++ append_history(p, "RTCPtext", "Quality:%s", quality);
++ }
++ if (oldowner) {
++ pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", quality);
++ }
++ }
++ }
++
+ /* Send a hangup */
+ transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
+
+- /* Get RTCP quality before end of call */
+- if (p->do_history) {
+- if (p->rtp)
+- append_history(p, "RTCPaudio", "Quality:%s", audioqos);
+- if (p->vrtp)
+- append_history(p, "RTCPvideo", "Quality:%s", videoqos);
+- if (p->trtp)
+- append_history(p, "RTCPtext", "Quality:%s", textqos);
+- }
+- if (p->rtp && oldowner)
+- pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", audioqos);
+- if (p->vrtp && oldowner)
+- pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", videoqos);
+- if (p->trtp && oldowner)
+- pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", textqos);
+ } else {
+ /* Note we will need a BYE when this all settles out
+ but we can't send one while we have "INVITE" outstanding. */
+@@ -5769,13 +5868,10 @@
+ ast_debug(1, "SIP answering channel: %s\n", ast->name);
+ if (p->t38.state == T38_PEER_DIRECT) {
+ change_t38_state(p, T38_ENABLED);
+- res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+- 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);
+- ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
+ }
++ ast_rtp_instance_new_source(p->rtp);
++ res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE, TRUE);
++ ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
+ }
+ sip_pvt_unlock(p);
+ return res;
+@@ -5808,13 +5904,17 @@
+ if ((ast->_state != AST_STATE_UP) &&
+ !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
+ !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+- ast_rtp_new_source(p->rtp);
++ ast_rtp_instance_new_source(p->rtp);
+ p->invitestate = INV_EARLY_MEDIA;
+- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
+- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
++ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
++ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
++ } else if (p->t38.state == T38_ENABLED && !p->t38.direct) {
++ change_t38_state(p, T38_DISABLED);
++ transmit_reinvite_with_sdp(p, FALSE, FALSE);
++ } else {
++ p->lastrtptx = time(NULL);
++ res = ast_rtp_instance_write(p->rtp, frame);
+ }
+- p->lastrtptx = time(NULL);
+- res = ast_rtp_write(p->rtp, frame);
+ }
+ sip_pvt_unlock(p);
+ }
+@@ -5828,11 +5928,11 @@
+ !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);
+- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
++ 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);
+- res = ast_rtp_write(p->vrtp, frame);
++ res = ast_rtp_instance_write(p->vrtp, frame);
+ }
+ sip_pvt_unlock(p);
+ }
+@@ -5841,7 +5941,7 @@
+ if (p) {
+ sip_pvt_lock(p);
+ if (p->red) {
+- red_buffer_t140(p->trtp, frame);
++ ast_rtp_red_buffer(p->trtp, frame);
+ } else {
+ if (p->trtp) {
+ /* Activate text early media */
+@@ -5849,11 +5949,11 @@
+ !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);
+- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
++ 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);
+- res = ast_rtp_write(p->trtp, frame);
++ res = ast_rtp_instance_write(p->trtp, frame);
+ }
+ }
+ sip_pvt_unlock(p);
+@@ -5869,8 +5969,16 @@
+ we simply forget the frames if we get modem frames before the bridge is up.
+ Fax will re-transmit.
+ */
+- if (p->udptl && ast->_state == AST_STATE_UP)
+- res = ast_udptl_write(p->udptl, frame);
++ if (ast->_state == AST_STATE_UP) {
++ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state == T38_DISABLED) {
++ if (!p->pendinginvite) {
++ change_t38_state(p, T38_LOCAL_REINVITE);
++ transmit_reinvite_with_sdp(p, TRUE, FALSE);
++ }
++ } else if (p->udptl && p->t38.state == T38_ENABLED) {
++ res = ast_udptl_write(p->udptl, frame);
++ }
++ }
+ sip_pvt_unlock(p);
+ }
+ break;
+@@ -5933,11 +6041,15 @@
+ sip_pvt_lock(p);
+ switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
+ case SIP_DTMF_INBAND:
+- res = -1; /* Tell Asterisk to generate inband indications */
++ if (p->rtp && ast_rtp_instance_dtmf_mode_get(p->rtp) == AST_RTP_DTMF_MODE_INBAND) {
++ ast_rtp_instance_dtmf_begin(p->rtp, digit);
++ } else {
++ res = -1; /* Tell Asterisk to generate inband indications */
++ }
+ break;
+ case SIP_DTMF_RFC2833:
+ if (p->rtp)
+- ast_rtp_senddigit_begin(p->rtp, digit);
++ ast_rtp_instance_dtmf_begin(p->rtp, digit);
+ break;
+ default:
+ break;
+@@ -5962,10 +6074,14 @@
+ break;
+ case SIP_DTMF_RFC2833:
+ if (p->rtp)
+- ast_rtp_senddigit_end(p->rtp, digit);
++ ast_rtp_instance_dtmf_end(p->rtp, digit);
+ break;
+ case SIP_DTMF_INBAND:
+- res = -1; /* Tell Asterisk to stop inband indications */
++ if (p->rtp && ast_rtp_instance_dtmf_mode_get(p->rtp) == AST_RTP_DTMF_MODE_INBAND) {
++ ast_rtp_instance_dtmf_end(p->rtp, digit);
++ } else {
++ res = -1; /* Tell Asterisk to stop inband indications */
++ }
+ break;
+ }
+ sip_pvt_unlock(p);
+@@ -6053,18 +6169,18 @@
+ !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);
+- ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
++ transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE, FALSE);
++ ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+ break;
+ }
+ res = -1;
+ break;
+ case AST_CONTROL_HOLD:
+- ast_rtp_new_source(p->rtp);
++ ast_rtp_instance_new_source(p->rtp);
+ ast_moh_start(ast, data, p->mohinterpret);
+ break;
+ case AST_CONTROL_UNHOLD:
+- ast_rtp_new_source(p->rtp);
++ ast_rtp_instance_new_source(p->rtp);
+ ast_moh_stop(ast);
+ break;
+ case AST_CONTROL_VIDUPDATE: /* Request a video frame update */
+@@ -6085,7 +6201,7 @@
+ AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+ change_t38_state(p, T38_ENABLED);
+ transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+- } else if (p->t38.state != T38_ENABLED) {
++ } else if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
+ change_t38_state(p, T38_LOCAL_REINVITE);
+ if (!p->pendinginvite) {
+ transmit_reinvite_with_sdp(p, TRUE, FALSE);
+@@ -6110,8 +6226,14 @@
+ }
+ break;
+ case AST_CONTROL_SRCUPDATE:
+- ast_rtp_new_source(p->rtp);
++ ast_rtp_instance_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;
+@@ -6224,23 +6346,29 @@
+ ast_debug(3, "This channel will not be able to handle video.\n");
+
+ if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
+- i->vad = ast_dsp_new();
+- ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
+- if (global_relaxdtmf)
+- ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
++ if (!i->rtp || ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_INBAND)) {
++ i->vad = ast_dsp_new();
++ ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
++ if (global_relaxdtmf)
++ ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
++ }
++ } else if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) {
++ if (i->rtp) {
++ ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_RFC2833);
++ }
+ }
+
+ /* Set file descriptors for audio, video, realtime text and UDPTL as needed */
+ if (i->rtp) {
+- ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
+- ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
++ ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
++ ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
+ }
+ if (needvideo && i->vrtp) {
+- ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
+- ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
++ ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
++ ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
+ }
+ if (needtext && i->trtp)
+- ast_channel_set_fd(tmp, 4, ast_rtp_fd(i->trtp));
++ ast_channel_set_fd(tmp, 4, ast_rtp_instance_fd(i->trtp, 0));
+ if (i->udptl)
+ ast_channel_set_fd(tmp, 5, ast_udptl_fd(i->udptl));
+
+@@ -6292,10 +6420,6 @@
+ if (i->rtp)
+ ast_jb_configure(tmp, &global_jbconf);
+
+- /* If the INVITE contains T.38 SDP information set the proper channel variable so a created outgoing call will also have T.38 */
+- if (i->udptl && i->t38.state == T38_PEER_DIRECT)
+- pbx_builtin_setvar_helper(tmp, "_T38CALL", "1");
+-
+ /* Set channel variables for this call from configuration */
+ for (v = i->chanvars ; v ; v = v->next) {
+ char valuebuf[1024];
+@@ -6468,19 +6592,19 @@
+
+ switch(ast->fdno) {
+ case 0:
+- f = ast_rtp_read(p->rtp); /* RTP Audio */
++ f = ast_rtp_instance_read(p->rtp, 0); /* RTP Audio */
+ break;
+ case 1:
+- f = ast_rtcp_read(p->rtp); /* RTCP Control Channel */
++ f = ast_rtp_instance_read(p->rtp, 1); /* RTCP Control Channel */
+ break;
+ case 2:
+- f = ast_rtp_read(p->vrtp); /* RTP Video */
++ f = ast_rtp_instance_read(p->vrtp, 0); /* RTP Video */
+ break;
+ case 3:
+- f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */
++ f = ast_rtp_instance_read(p->vrtp, 1); /* RTCP Control Channel for video */
+ break;
+ case 4:
+- f = ast_rtp_read(p->trtp); /* RTP Text */
++ f = ast_rtp_instance_read(p->trtp, 0); /* RTP Text */
+ if (sipdebug_text) {
+ int i;
+ unsigned char* arr = f->data.ptr;
+@@ -6687,50 +6811,11 @@
+ p->ocseq = INITIAL_CSEQ;
+
+ if (sip_methods[intended_method].need_rtp) {
+- p->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+- /* If the global videosupport flag is on, we always create a RTP interface for video */
+- if (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT))
+- p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+- if (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT))
+- p->trtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+- if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT))
+- p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
+- if (!p->rtp|| (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)
+- || (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) && !p->trtp)) {
+- ast_log(LOG_WARNING, "Unable to create RTP audio %s%ssession: %s\n",
+- ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video " : "",
+- ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) ? "and text " : "", strerror(errno));
+- if (p->chanvars) {
+- ast_variables_destroy(p->chanvars);
+- p->chanvars = NULL;
+- }
+- ao2_t_ref(p, -1, "failed to create RTP audio session, drop p");
+- return NULL;
++ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && (p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) {
++ ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio);
+ }
+- ast_rtp_setqos(p->rtp, global_tos_audio, global_cos_audio, "SIP RTP");
+- ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
+- ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
+- ast_rtp_set_rtptimeout(p->rtp, global_rtptimeout);
+- ast_rtp_set_rtpholdtimeout(p->rtp, global_rtpholdtimeout);
+- ast_rtp_set_rtpkeepalive(p->rtp, global_rtpkeepalive);
+- if (p->vrtp) {
+- ast_rtp_setqos(p->vrtp, global_tos_video, global_cos_video, "SIP VRTP");
+- ast_rtp_setdtmf(p->vrtp, 0);
+- ast_rtp_setdtmfcompensate(p->vrtp, 0);
+- ast_rtp_set_rtptimeout(p->vrtp, global_rtptimeout);
+- ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout);
+- ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive);
+- }
+- if (p->trtp) {
+- ast_rtp_setqos(p->trtp, global_tos_text, global_cos_text, "SIP TRTP");
+- ast_rtp_setdtmf(p->trtp, 0);
+- ast_rtp_setdtmfcompensate(p->trtp, 0);
+- }
+- if (p->udptl)
+- ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio);
+ p->maxcallbitrate = default_maxcallbitrate;
+ p->autoframing = global_autoframing;
+- ast_rtp_codec_setpref(p->rtp, &p->prefs);
+ }
+
+ if (useglobal_nat && sin) {
+@@ -6762,6 +6847,7 @@
+ }
+ ast_string_field_set(p, context, sip_cfg.default_context);
+ ast_string_field_set(p, parkinglot, default_parkinglot);
++ ast_string_field_set(p, engine, default_engine);
+
+ AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue);
+
+@@ -7396,7 +7482,7 @@
+ int iterator;
+ int sendonly = -1;
+ int numberofports;
+- struct ast_rtp *newaudiortp, *newvideortp, *newtextrtp; /* Buffers for codec handling */
++ struct ast_rtp_codecs newaudiortp, newvideortp, newtextrtp;
+ int newjointcapability; /* Negotiated capability */
+ int newpeercapability;
+ int newnoncodeccapability;
+@@ -7421,34 +7507,11 @@
+ return -1;
+ }
+
+- /* Initialize the temporary RTP structures we use to evaluate the offer from the peer */
+-#ifdef LOW_MEMORY
+- newaudiortp = ast_threadstorage_get(&ts_audio_rtp, ast_rtp_alloc_size());
+-#else
+- newaudiortp = alloca(ast_rtp_alloc_size());
+-#endif
+- memset(newaudiortp, 0, ast_rtp_alloc_size());
+- ast_rtp_new_init(newaudiortp);
+- ast_rtp_pt_clear(newaudiortp);
++ /* Make sure that the codec structures are all cleared out */
++ ast_rtp_codecs_payloads_clear(&newaudiortp, NULL);
++ ast_rtp_codecs_payloads_clear(&newvideortp, NULL);
++ ast_rtp_codecs_payloads_clear(&newtextrtp, NULL);
+
+-#ifdef LOW_MEMORY
+- newvideortp = ast_threadstorage_get(&ts_video_rtp, ast_rtp_alloc_size());
+-#else
+- newvideortp = alloca(ast_rtp_alloc_size());
+-#endif
+- memset(newvideortp, 0, ast_rtp_alloc_size());
+- ast_rtp_new_init(newvideortp);
+- ast_rtp_pt_clear(newvideortp);
+-
+-#ifdef LOW_MEMORY
+- newtextrtp = ast_threadstorage_get(&ts_text_rtp, ast_rtp_alloc_size());
+-#else
+- newtextrtp = alloca(ast_rtp_alloc_size());
+-#endif
+- memset(newtextrtp, 0, ast_rtp_alloc_size());
+- ast_rtp_new_init(newtextrtp);
+- ast_rtp_pt_clear(newtextrtp);
+-
+ /* Update our last rtprx when we receive an SDP, too */
+ p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
+
+@@ -7529,12 +7592,14 @@
+ p->novideo = TRUE;
+ p->notext = TRUE;
+
+- if (p->vrtp)
+- ast_rtp_pt_clear(newvideortp); /* Must be cleared in case no m=video line exists */
+-
+- if (p->trtp)
+- ast_rtp_pt_clear(newtextrtp); /* Must be cleared in case no m=text line exists */
++ if (p->vrtp) {
++ ast_rtp_codecs_payloads_clear(&newvideortp, NULL);
++ }
+
++ if (p->trtp) {
++ ast_rtp_codecs_payloads_clear(&newtextrtp, NULL);
++ }
++
+ /* Find media streams in this SDP offer */
+ while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
+ int x;
+@@ -7558,7 +7623,8 @@
+ }
+ if (debug)
+ ast_verbose("Found RTP audio format %d\n", codec);
+- ast_rtp_set_m_type(newaudiortp, codec);
++
++ ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec);
+ }
+ } else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+ (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1 && len >= 0)) {
+@@ -7574,7 +7640,7 @@
+ }
+ if (debug)
+ ast_verbose("Found RTP video format %d\n", codec);
+- ast_rtp_set_m_type(newvideortp, codec);
++ ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec);
+ }
+ } else if ((sscanf(m, "text %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+ (sscanf(m, "text %d RTP/AVP %n", &x, &len) == 1 && len > 0)) {
+@@ -7590,7 +7656,7 @@
+ }
+ if (debug)
+ ast_verbose("Found RTP text format %d\n", codec);
+- ast_rtp_set_m_type(newtextrtp, codec);
++ ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
+ }
+ } else if (p->udptl && ( (sscanf(m, "image %d udptl t38%n", &x, &len) == 1 && len > 0) ||
+ (sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1 && len > 0) )) {
+@@ -7655,10 +7721,10 @@
+ if (udptlportno > 0) {
+ sin.sin_port = htons(udptlportno);
+ if (ast_test_flag(&p->flags[0], SIP_NAT) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) {
+- struct sockaddr_in peer;
+- ast_rtp_get_peer(p->rtp, &peer);
+- if (peer.sin_addr.s_addr) {
+- memcpy(&sin.sin_addr, &peer.sin_addr, sizeof(sin.sin_addr));
++ struct sockaddr_in remote_address;
++ ast_rtp_instance_get_remote_address(p->rtp, &remote_address);
++ if (remote_address.sin_addr.s_addr) {
++ memcpy(&sin, &remote_address, sizeof(sin));
+ if (debug) {
+ ast_log(LOG_DEBUG, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_inet_ntoa(sin.sin_addr));
+ }
+@@ -7678,7 +7744,7 @@
+ if (p->rtp) {
+ if (portno > 0) {
+ sin.sin_port = htons(portno);
+- ast_rtp_set_peer(p->rtp, &sin);
++ ast_rtp_instance_set_remote_address(p->rtp, &sin);
+ if (debug)
+ ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ } else {
+@@ -7686,7 +7752,7 @@
+ if (debug)
+ ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session. Callid %s\n", p->callid);
+ } else {
+- ast_rtp_stop(p->rtp);
++ ast_rtp_instance_stop(p->rtp);
+ if (debug)
+ ast_verbose("Peer doesn't provide audio. Callid %s\n", p->callid);
+ }
+@@ -7769,18 +7835,17 @@
+ }
+ }
+ if (framing && p->autoframing) {
+- struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp);
++ struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
+ int codec_n;
+- int format = 0;
+- for (codec_n = 0; codec_n < MAX_RTP_PT; codec_n++) {
+- format = ast_rtp_codec_getformat(codec_n);
+- if (!format) /* non-codec or not found */
++ for (codec_n = 0; codec_n < AST_RTP_MAX_PT; codec_n++) {
++ struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n);
++ if (!format.asterisk_format || !format.code) /* non-codec or not found */
+ continue;
+ if (option_debug)
+- ast_log(LOG_DEBUG, "Setting framing for %d to %ld\n", format, framing);
+- ast_codec_pref_setsize(pref, format, framing);
++ ast_log(LOG_DEBUG, "Setting framing for %d to %ld\n", format.code, framing);
++ ast_codec_pref_setsize(pref, format.code, framing);
+ }
+- ast_rtp_codec_setpref(p->rtp, pref);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref);
+ }
+ continue;
+ }
+@@ -7792,7 +7857,7 @@
+
+ sscanf(red_cp, "%u", &red_data_pt[red_num_gen]);
+ red_cp = strtok(red_cp, "/");
+- while (red_cp && red_num_gen++ < RED_MAX_GENERATION) {
++ while (red_cp && red_num_gen++ < AST_RED_MAX_GENERATION) {
+ sscanf(red_cp, "%u", &red_data_pt[red_num_gen]);
+ red_cp = strtok(NULL, "/");
+ }
+@@ -7801,15 +7866,15 @@
+ }
+
+ if (sscanf(a, "fmtp: %u %63s", &codec, fmtp_string) == 2) {
+- struct rtpPayloadType payload;
++ struct ast_rtp_payload_type payload;
+ unsigned int handled = 0;
+
+- payload = ast_rtp_lookup_pt(newaudiortp, codec);
++ payload = ast_rtp_codecs_payload_lookup(&newaudiortp, codec);
+ if (!payload.code) {
+ /* it wasn't found, try the video rtp */
+- payload = ast_rtp_lookup_pt(newvideortp, codec);
++ payload = ast_rtp_codecs_payload_lookup(&newvideortp, codec);
+ }
+- if (payload.code && payload.isAstFormat) {
++ if (payload.code && payload.asterisk_format) {
+ unsigned int bit_rate;
+
+ switch (payload.code) {
+@@ -7817,7 +7882,7 @@
+ 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);
++ ast_rtp_codecs_payloads_unset(&newaudiortp, NULL, codec);
+ } else {
+ handled = 1;
+ }
+@@ -7827,7 +7892,7 @@
+ 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);
++ ast_rtp_codecs_payloads_unset(&newaudiortp, NULL, codec);
+ } else {
+ handled = 1;
+ }
+@@ -7849,24 +7914,24 @@
+ /* 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_rate(newvideortp, codec, "video", mimeSubtype, 0, sample_rate) != -1) {
++ if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newvideortp, NULL, 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;
+ last_rtpmap_codec++;
+ } else {
+- ast_rtp_unset_m_type(newvideortp, codec);
++ ast_rtp_codecs_payloads_unset(&newvideortp, NULL, codec);
+ if (debug)
+ ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
+ }
+ } else if (!strncasecmp(mimeSubtype, "T140", 4)) { /* Text */
+ if (p->trtp) {
+ /* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
+- ast_rtp_set_rtpmap_type(newtextrtp, codec, "text", mimeSubtype, 0);
++ ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
+ }
+ } else if (!strncasecmp(mimeSubtype, "RED", 3)) { /* Text with Redudancy */
+ if (p->trtp) {
+- ast_rtp_set_rtpmap_type(newtextrtp, codec, "text", mimeSubtype, 0);
++ ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
+ red_pt = codec;
+ sprintf(red_fmtp, "fmtp:%d ", red_pt);
+
+@@ -7874,15 +7939,14 @@
+ ast_verbose("RED submimetype has payload type: %d\n", red_pt);
+ }
+ } else { /* Must be audio?? */
+- 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 (ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newaudiortp, NULL, 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;
+ last_rtpmap_codec++;
+ } else {
+- ast_rtp_unset_m_type(newaudiortp, codec);
++ ast_rtp_codecs_payloads_unset(&newaudiortp, NULL, codec);
+ if (debug)
+ ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
+ }
+@@ -8007,7 +8071,7 @@
+
+ /* Remote party offers T38, we need to update state */
+ if (t38action == SDP_T38_ACCEPT) {
+- if (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)
++ if (p->t38.state == T38_LOCAL_REINVITE)
+ change_t38_state(p, T38_ENABLED);
+ } else if (t38action == SDP_T38_INITIATE) {
+ if (p->owner && p->lastinvite) {
+@@ -8021,15 +8085,14 @@
+ }
+
+ /* Now gather all of the codecs that we are asked for: */
+- ast_rtp_get_current_formats(newaudiortp, &peercapability, &peernoncodeccapability);
+- ast_rtp_get_current_formats(newvideortp, &vpeercapability, &vpeernoncodeccapability);
+- ast_rtp_get_current_formats(newtextrtp, &tpeercapability, &tpeernoncodeccapability);
++ ast_rtp_codecs_payload_formats(&newaudiortp, &peercapability, &peernoncodeccapability);
++ ast_rtp_codecs_payload_formats(&newvideortp, &vpeercapability, &vpeernoncodeccapability);
++ ast_rtp_codecs_payload_formats(&newtextrtp, &tpeercapability, &tpeernoncodeccapability);
+
+ newjointcapability = p->capability & (peercapability | vpeercapability | tpeercapability);
+ newpeercapability = (peercapability | vpeercapability | tpeercapability);
+ newnoncodeccapability = p->noncodeccapability & peernoncodeccapability;
+-
+-
++
+ if (debug) {
+ /* shame on whoever coded this.... */
+ char s1[SIPBUFSIZE], s2[SIPBUFSIZE], s3[SIPBUFSIZE], s4[SIPBUFSIZE], s5[SIPBUFSIZE];
+@@ -8040,11 +8103,17 @@
+ ast_getformatname_multiple(s3, SIPBUFSIZE, vpeercapability),
+ ast_getformatname_multiple(s4, SIPBUFSIZE, tpeercapability),
+ ast_getformatname_multiple(s5, SIPBUFSIZE, newjointcapability));
++ }
+
++ if (debug) {
++ struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE);
++ struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE);
++ struct ast_str *s3 = ast_str_alloca(SIPBUFSIZE);
++
+ ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
+- ast_rtp_lookup_mime_multiple(s1, SIPBUFSIZE, p->noncodeccapability, 0, 0),
+- ast_rtp_lookup_mime_multiple(s2, SIPBUFSIZE, peernoncodeccapability, 0, 0),
+- ast_rtp_lookup_mime_multiple(s3, SIPBUFSIZE, newnoncodeccapability, 0, 0));
++ ast_rtp_lookup_mime_multiple2(s1, p->noncodeccapability, 0, 0),
++ ast_rtp_lookup_mime_multiple2(s2, peernoncodeccapability, 0, 0),
++ ast_rtp_lookup_mime_multiple2(s3, newnoncodeccapability, 0, 0));
+ }
+ if (!newjointcapability) {
+ /* If T.38 was not negotiated either, totally bail out... */
+@@ -8064,18 +8133,24 @@
+ p->peercapability = newpeercapability; /* The other sides capability in latest offer */
+ p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */
+
++ if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) { /* respond with single most preferred joint codec, limiting the other side's choice */
++ p->jointcapability = ast_codec_choose(&p->prefs, p->jointcapability, 1);
++ }
++
+ if (p->jointcapability & AST_FORMAT_T140RED) {
+- p->red = 1;
+- rtp_red_init(p->trtp, 300, red_data_pt, 2);
++ p->red = 1;
++ ast_rtp_red_init(p->trtp, 300, red_data_pt, 2);
+ } else {
+- p->red = 0;
++ p->red = 0;
+ }
+
+- ast_rtp_pt_copy(p->rtp, newaudiortp);
+- if (p->vrtp)
+- ast_rtp_pt_copy(p->vrtp, newvideortp);
+- if (p->trtp)
+- ast_rtp_pt_copy(p->trtp, newtextrtp);
++ ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
++ if (p->vrtp) {
++ ast_rtp_codecs_payloads_copy(&newvideortp, ast_rtp_instance_get_codecs(p->vrtp), p->vrtp);
++ }
++ if (p->trtp) {
++ ast_rtp_codecs_payloads_copy(&newtextrtp, ast_rtp_instance_get_codecs(p->trtp), p->trtp);
++ }
+
+ if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
+ ast_clear_flag(&p->flags[0], SIP_DTMF);
+@@ -8083,8 +8158,8 @@
+ /* XXX Would it be reasonable to drop the DSP at this point? XXX */
+ ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
+ /* Since RFC2833 is now negotiated we need to change some properties of the RTP stream */
+- ast_rtp_setdtmf(p->rtp, 1);
+- ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
++ ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, 1);
++ ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
+ } else {
+ ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
+ }
+@@ -8092,21 +8167,21 @@
+
+ /* Setup audio port number */
+ if (p->rtp && sin.sin_port) {
+- ast_rtp_set_peer(p->rtp, &sin);
++ ast_rtp_instance_set_remote_address(p->rtp, &sin);
+ if (debug)
+ ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ }
+
+ /* Setup video port number */
+ if (p->vrtp && vsin.sin_port) {
+- ast_rtp_set_peer(p->vrtp, &vsin);
++ ast_rtp_instance_set_remote_address(p->vrtp, &vsin);
+ if (debug)
+ ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
+ }
+
+ /* Setup text port number */
+ if (p->trtp && tsin.sin_port) {
+- ast_rtp_set_peer(p->trtp, &tsin);
++ ast_rtp_instance_set_remote_address(p->trtp, &tsin);
+ if (debug)
+ ast_verbose("Peer text RTP is at port %s:%d\n", ast_inet_ntoa(tsin.sin_addr), ntohs(tsin.sin_port));
+ }
+@@ -8153,7 +8228,7 @@
+ S_OR(p->mohsuggest, NULL),
+ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
+ if (sendonly)
+- ast_rtp_stop(p->rtp);
++ ast_rtp_instance_stop(p->rtp);
+ /* RTCP needs to go ahead, even if we're on hold!!! */
+ /* Activate a re-invite */
+ ast_queue_frame(p->owner, &ast_null_frame);
+@@ -8700,9 +8775,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);
+@@ -8740,6 +8812,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)
++ && (!strncmp(msg, "180", 3) || !strncmp(msg, "183", 3))) {
++ 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 */
+@@ -8959,6 +9039,89 @@
+ return 0;
+ }
+
++/*!
++ * \pre if p->owner exists, it must be locked
++ * \brief Add Remote-Party-ID header to SIP message
++ */
++static int add_rpid(struct sip_request *req, struct sip_pvt *p)
++{
++ struct ast_str *tmp = ast_str_alloca(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\" <anonymous@anonymous.invalid>";
++
++ 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) {
++ ast_str_set(&tmp, -1, "%s", anonymous_string);
++ } else {
++ ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%s>", lid_name, lid_num, fromdomain);
++ }
++ add_header(req, "P-Asserted-Identity", ast_str_buffer(tmp));
++ } else {
++ ast_str_set(&tmp, -1, "\"%s\" <sip:%s@%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)) {
++ ast_str_append(&tmp, -1, ";privacy=%s;screen=%s", privacy, screen);
++ }
++
++ add_header(req, "Remote-Party-ID", ast_str_buffer(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)
+@@ -8990,19 +9153,19 @@
+
+ if (debug)
+ ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
+- if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
++ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->rtp), 1, codec)) == -1)
+ return;
+
+ if (p->rtp) {
+- struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp);
++ struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
+ fmt = ast_codec_pref_getsize(pref, codec);
+ } else /* I dont see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
+ 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_rtp_lookup_mime_subtype2(1, codec,
+ ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0),
+- ast_rtp_lookup_sample_rate(1, codec));
++ ast_rtp_lookup_sample_rate2(1, codec));
+
+ switch (codec) {
+ case AST_FORMAT_G729A:
+@@ -9049,13 +9212,13 @@
+ if (debug)
+ ast_verbose("Adding video codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
+
+- if ((rtp_code = ast_rtp_lookup_code(p->vrtp, 1, codec)) == -1)
++ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->vrtp), 1, codec)) == -1)
+ 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, 0),
+- ast_rtp_lookup_sample_rate(1, codec));
++ ast_rtp_lookup_mime_subtype2(1, codec, 0),
++ ast_rtp_lookup_sample_rate2(1, codec));
+ /* Add fmtp code here */
+ }
+
+@@ -9072,20 +9235,21 @@
+ if (debug)
+ ast_verbose("Adding text codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
+
+- if ((rtp_code = ast_rtp_lookup_code(p->trtp, 1, codec)) == -1)
++ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, codec)) == -1)
+ 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, 0),
+- ast_rtp_lookup_sample_rate(1, codec));
++ ast_rtp_lookup_mime_subtype2(1, codec, 0),
++ ast_rtp_lookup_sample_rate2(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_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));
++ int t140code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->trtp), 1, AST_FORMAT_T140);
++ ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code,
++ t140code,
++ t140code,
++ t140code);
+
+ }
+ }
+@@ -9120,92 +9284,6 @@
+ }
+ }
+
+-/*! \brief Add T.38 Session Description Protocol message */
+-static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
+-{
+- int len = 0;
+- int x = 0;
+- struct sockaddr_in udptlsin;
+- struct ast_str *m_modem = ast_str_alloca(1024);
+- struct ast_str *a_modem = ast_str_alloca(1024);
+- struct sockaddr_in udptldest = { 0, };
+- int debug;
+-
+- debug = sip_debug_test_pvt(p);
+- len = 0;
+- if (!p->udptl) {
+- ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
+- return -1;
+- }
+-
+- if (!p->sessionid) {
+- p->sessionid = (int)ast_random();
+- p->sessionversion = p->sessionid;
+- } else
+- p->sessionversion++;
+-
+- /* Our T.38 end is */
+- ast_udptl_get_us(p->udptl, &udptlsin);
+-
+- /* Determine T.38 UDPTL destination */
+- if (p->udptlredirip.sin_addr.s_addr) {
+- udptldest.sin_port = p->udptlredirip.sin_port;
+- udptldest.sin_addr = p->udptlredirip.sin_addr;
+- } else {
+- udptldest.sin_addr = p->ourip.sin_addr;
+- udptldest.sin_port = udptlsin.sin_port;
+- }
+-
+- if (debug)
+- ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(udptlsin.sin_port));
+-
+- /* We break with the "recommendation" and send our IP, in order that our
+- peer doesn't have to ast_gethostbyname() us */
+-
+- if (debug) {
+- ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
+- p->t38.capability,
+- p->t38.peercapability,
+- p->t38.jointcapability);
+- }
+- ast_str_append(&m_modem, 0, "v=0\r\n");
+- ast_str_append(&m_modem, 0, "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner , p->sessionid, p->sessionversion, ast_inet_ntoa(udptldest.sin_addr));
+- ast_str_append(&m_modem, 0, "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
+- ast_str_append(&m_modem, 0, "c=IN IP4 %s\r\n", ast_inet_ntoa(udptldest.sin_addr));
+- ast_str_append(&m_modem, 0, "t=0 0\r\n");
+- ast_str_append(&m_modem, 0, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
+-
+- if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
+- ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
+- if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
+- ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
+- if ((x = t38_get_rate(p->t38.jointcapability)))
+- ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", x);
+- if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
+- ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval\r\n");
+- if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
+- ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR\r\n");
+- if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
+- ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG\r\n");
+- ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
+- x = ast_udptl_get_local_max_datagram(p->udptl);
+- ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n", x);
+- ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
+- if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
+- ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
+- len = m_modem->used + a_modem->used;
+- add_header(resp, "Content-Type", "application/sdp");
+- add_header_contentLength(resp, len);
+- add_line(resp, m_modem->str);
+- add_line(resp, a_modem->str);
+-
+- /* Update lastrtprx when we send our SDP */
+- p->lastrtprx = p->lastrtptx = time(NULL);
+-
+- return 0;
+-}
+-
+-
+ /*! \brief Add RFC 2833 DTMF offer to SDP */
+ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
+ struct ast_str **m_buf, struct ast_str **a_buf,
+@@ -9214,14 +9292,14 @@
+ int rtp_code;
+
+ if (debug)
+- ast_verbose("Adding non-codec 0x%x (%s) to SDP\n", format, ast_rtp_lookup_mime_subtype(0, format, 0));
+- if ((rtp_code = ast_rtp_lookup_code(p->rtp, 0, format)) == -1)
++ ast_verbose("Adding non-codec 0x%x (%s) to SDP\n", format, ast_rtp_lookup_mime_subtype2(0, format, 0));
++ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(p->rtp), 0, format)) == -1)
+ 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(0, format, 0),
+- ast_rtp_lookup_sample_rate(0, format));
++ ast_rtp_lookup_mime_subtype2(0, format, 0),
++ ast_rtp_lookup_sample_rate2(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);
+ }
+@@ -9234,11 +9312,11 @@
+ struct sockaddr_in *dest, struct sockaddr_in *vdest)
+ {
+ /* First, get our address */
+- ast_rtp_get_us(p->rtp, sin);
++ ast_rtp_instance_get_local_address(p->rtp, sin);
+ if (p->vrtp)
+- ast_rtp_get_us(p->vrtp, vsin);
++ ast_rtp_instance_get_local_address(p->vrtp, vsin);
+ if (p->trtp)
+- ast_rtp_get_us(p->trtp, tsin);
++ ast_rtp_instance_get_local_address(p->trtp, tsin);
+
+ /* Now, try to figure out where we want them to send data */
+ /* Is this a re-invite to move the media out, then use the original offer from caller */
+@@ -9268,7 +9346,7 @@
+ is used in Session-Timers where RE-INVITEs are used for refreshing SIP sessions
+ without modifying the media session in any way.
+ */
+-static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp)
++static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38)
+ {
+ int len = 0;
+ int alreadysent = 0;
+@@ -9277,8 +9355,10 @@
+ struct sockaddr_in vsin;
+ struct sockaddr_in tsin;
+ struct sockaddr_in dest;
++ struct sockaddr_in udptlsin;
+ struct sockaddr_in vdest = { 0, };
+ struct sockaddr_in tdest = { 0, };
++ struct sockaddr_in udptldest = { 0, };
+
+ /* SDP fields */
+ char *version = "v=0\r\n"; /* Protocol version */
+@@ -9287,16 +9367,18 @@
+ char connection[256]; /* Connection data */
+ char *session_time = "t=0 0\r\n"; /* Time the session is active */
+ char bandwidth[256] = ""; /* Max bitrate */
+- char *hold;
++ char *hold = "";
+ struct ast_str *m_audio = ast_str_alloca(256); /* Media declaration line for audio */
+ struct ast_str *m_video = ast_str_alloca(256); /* Media declaration line for video */
+ struct ast_str *m_text = ast_str_alloca(256); /* Media declaration line for text */
++ struct ast_str *m_modem = ast_str_alloca(256); /* Media declaration line for modem */
+ struct ast_str *a_audio = ast_str_alloca(1024); /* Attributes for audio */
+ struct ast_str *a_video = ast_str_alloca(1024); /* Attributes for video */
+ struct ast_str *a_text = ast_str_alloca(1024); /* Attributes for text */
++ struct ast_str *a_modem = ast_str_alloca(1024); /* Attributes for modem */
+
+ int x;
+- int capability;
++ int capability = 0;
+ int needaudio = FALSE;
+ int needvideo = FALSE;
+ int needtext = FALSE;
+@@ -9327,184 +9409,235 @@
+ p->sessionversion++;
+ }
+
+- capability = p->jointcapability;
++ get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
+
+- /* XXX note, Video and Text are negated - 'true' means 'no' */
+- ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability),
+- p->novideo ? "True" : "False", p->notext ? "True" : "False");
+- ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
++ snprintf(owner, sizeof(owner), "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
++ snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
++
++ if (add_audio) {
++ capability = p->jointcapability;
++
++ /* XXX note, Video and Text are negated - 'true' means 'no' */
++ ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability),
++ p->novideo ? "True" : "False", p->notext ? "True" : "False");
++ ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
+
+ #ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
+- if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP)) {
+- ast_str_append(&m_audio, 0, " %d", 191);
+- ast_str_append(&a_audio, 0, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
+- }
++ if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP)) {
++ ast_str_append(&m_audio, 0, " %d", 191);
++ ast_str_append(&a_audio, 0, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
++ }
+ #endif
+
+- /* Check if we need audio */
+- if (capability & AST_FORMAT_AUDIO_MASK)
+- needaudio = TRUE;
++ /* Check if we need audio */
++ if (capability & AST_FORMAT_AUDIO_MASK)
++ needaudio = TRUE;
+
+- /* Check if we need video in this call */
+- if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
+- if (p->vrtp) {
+- needvideo = TRUE;
+- ast_debug(2, "This call needs video offers!\n");
+- } else
+- ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
+- }
++ /* Check if we need video in this call */
++ if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
++ if (p->vrtp) {
++ needvideo = TRUE;
++ ast_debug(2, "This call needs video offers!\n");
++ } else
++ ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
++ }
+
+- /* Get our media addresses */
+- get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
+-
+- if (debug)
+- ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(sin.sin_port));
++ if (debug)
++ ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(sin.sin_port));
+
+- /* Ok, we need video. Let's add what we need for video and set codecs.
+- Video is handled differently than audio since we can not transcode. */
+- if (needvideo) {
+- ast_str_append(&m_video, 0, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
++ /* Ok, we need video. Let's add what we need for video and set codecs.
++ Video is handled differently than audio since we can not transcode. */
++ if (needvideo) {
++ ast_str_append(&m_video, 0, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+
+- /* Build max bitrate string */
+- if (p->maxcallbitrate)
+- snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
+- if (debug)
+- ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));
+- }
++ /* Build max bitrate string */
++ if (p->maxcallbitrate)
++ snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
++ if (debug)
++ ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));
++ }
+
+- /* Check if we need text in this call */
+- if((capability & AST_FORMAT_TEXT_MASK) && !p->notext) {
+- if (sipdebug_text)
+- ast_verbose("We think we can do text\n");
+- if (p->trtp) {
++ /* Check if we need text in this call */
++ if((capability & AST_FORMAT_TEXT_MASK) && !p->notext) {
+ if (sipdebug_text)
+- ast_verbose("And we have a text rtp object\n");
+- needtext = TRUE;
+- ast_debug(2, "This call needs text offers! \n");
+- } else
+- ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n");
+- }
++ ast_verbose("We think we can do text\n");
++ if (p->trtp) {
++ if (sipdebug_text)
++ ast_verbose("And we have a text rtp object\n");
++ needtext = TRUE;
++ ast_debug(2, "This call needs text offers! \n");
++ } else
++ ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n");
++ }
+
+- /* Ok, we need text. Let's add what we need for text and set codecs.
+- Text is handled differently than audio since we can not transcode. */
+- if (needtext) {
+- if (sipdebug_text)
+- ast_verbose("Lets set up the text sdp\n");
+- /* Determine text destination */
+- if (p->tredirip.sin_addr.s_addr) {
+- tdest.sin_addr = p->tredirip.sin_addr;
+- tdest.sin_port = p->tredirip.sin_port;
+- } else {
+- tdest.sin_addr = p->ourip.sin_addr;
+- tdest.sin_port = tsin.sin_port;
++ /* Ok, we need text. Let's add what we need for text and set codecs.
++ Text is handled differently than audio since we can not transcode. */
++ if (needtext) {
++ if (sipdebug_text)
++ ast_verbose("Lets set up the text sdp\n");
++ /* Determine text destination */
++ if (p->tredirip.sin_addr.s_addr) {
++ tdest.sin_addr = p->tredirip.sin_addr;
++ tdest.sin_port = p->tredirip.sin_port;
++ } else {
++ tdest.sin_addr = p->ourip.sin_addr;
++ tdest.sin_port = tsin.sin_port;
++ }
++ ast_str_append(&m_text, 0, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
++ if (debug) /* XXX should I use tdest below ? */
++ ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port));
++
+ }
+- ast_str_append(&m_text, 0, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
+
+- if (debug) /* XXX should I use tdest below ? */
+- ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port));
++ /* Start building generic SDP headers */
+
+- }
++ /* We break with the "recommendation" and send our IP, in order that our
++ peer doesn't have to ast_gethostbyname() us */
+
+- /* Start building generic SDP headers */
++ ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
+
+- /* We break with the "recommendation" and send our IP, in order that our
+- peer doesn't have to ast_gethostbyname() us */
++ if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
++ hold = "a=recvonly\r\n";
++ else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
++ hold = "a=inactive\r\n";
++ else
++ hold = "a=sendrecv\r\n";
+
+- snprintf(owner, sizeof(owner), "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
+- snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
+- ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
++ /* Now, start adding audio codecs. These are added in this order:
++ - First what was requested by the calling channel
++ - Then preferences in order from sip.conf device config for this peer/user
++ - Then other codecs in capabilities, including video
++ */
+
+- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
+- hold = "a=recvonly\r\n";
+- else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
+- hold = "a=inactive\r\n";
+- else
+- hold = "a=sendrecv\r\n";
++ /* Prefer the audio codec we were requested to use, first, no matter what
++ Note that p->prefcodec can include video codecs, so mask them out
++ */
++ if (capability & p->prefcodec) {
++ int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
+
+- /* Now, start adding audio codecs. These are added in this order:
+- - First what was requested by the calling channel
+- - Then preferences in order from sip.conf device config for this peer/user
+- - Then other codecs in capabilities, including video
+- */
++ add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
++ alreadysent |= codec;
++ }
+
+- /* Prefer the audio codec we were requested to use, first, no matter what
+- Note that p->prefcodec can include video codecs, so mask them out
+- */
+- if (capability & p->prefcodec) {
+- int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
++ /* Start by sending our preferred audio/video codecs */
++ for (x = 0; x < 32; x++) {
++ int codec;
+
+- add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
+- alreadysent |= codec;
+- }
++ if (!(codec = ast_codec_pref_index(&p->prefs, x)))
++ break;
+
+- /* Start by sending our preferred audio/video codecs */
+- for (x = 0; x < 32; x++) {
+- int codec;
++ if (!(capability & codec))
++ continue;
+
+- if (!(codec = ast_codec_pref_index(&p->prefs, x)))
+- break;
++ if (alreadysent & codec)
++ continue;
+
+- if (!(capability & codec))
+- continue;
++ add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
++ alreadysent |= codec;
++ }
+
+- if (alreadysent & codec)
+- continue;
++ /* Now send any other common audio and video codecs, and non-codec formats: */
++ for (x = 1; x <= (needtext ? AST_FORMAT_TEXT_MASK : (needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK)); x <<= 1) {
++ if (!(capability & x)) /* Codec not requested */
++ continue;
+
+- add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
+- alreadysent |= codec;
+- }
++ if (alreadysent & x) /* Already added to SDP */
++ continue;
+
+- /* Now send any other common audio and video codecs, and non-codec formats: */
+- for (x = 1; x <= (needtext ? AST_FORMAT_TEXT_MASK : (needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK)); x <<= 1) {
+- if (!(capability & x)) /* Codec not requested */
+- continue;
++ if (x & AST_FORMAT_AUDIO_MASK)
++ 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, &m_text, &a_text, debug, &min_text_packet_size);
++ }
+
+- if (alreadysent & x) /* Already added to SDP */
+- continue;
++ /* Now add DTMF RFC2833 telephony-event as a codec */
++ for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
++ if (!(p->jointnoncodeccapability & x))
++ continue;
+
+- if (x & AST_FORMAT_AUDIO_MASK)
+- 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, &m_text, &a_text, debug, &min_text_packet_size);
+- }
++ add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug);
++ }
+
+- /* Now add DTMF RFC2833 telephony-event as a codec */
+- for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
+- if (!(p->jointnoncodeccapability & x))
+- continue;
++ ast_debug(3, "-- Done with adding codecs to SDP\n");
+
+- add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug);
++ if (!p->owner || !ast_internal_timing_enabled(p->owner))
++ ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
++
++ if (min_audio_packet_size)
++ ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);
++
++ /* XXX don't think you can have ptime for video */
++ if (min_video_packet_size)
++ ast_str_append(&a_video, 0, "a=ptime:%d\r\n", min_video_packet_size);
++
++ /* XXX don't think you can have ptime for text */
++ if (min_text_packet_size)
++ ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
++
++ if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
++ m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
++ a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)
++ ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
+ }
+
+- ast_debug(3, "-- Done with adding codecs to SDP\n");
++ if (add_t38) {
++ /* Our T.38 end is */
++ ast_udptl_get_us(p->udptl, &udptlsin);
+
+- if (!p->owner || !ast_internal_timing_enabled(p->owner))
+- ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
++ /* Determine T.38 UDPTL destination */
++ if (p->udptlredirip.sin_addr.s_addr) {
++ udptldest.sin_port = p->udptlredirip.sin_port;
++ udptldest.sin_addr = p->udptlredirip.sin_addr;
++ } else {
++ udptldest.sin_addr = p->ourip.sin_addr;
++ udptldest.sin_port = udptlsin.sin_port;
++ }
+
+- if (min_audio_packet_size)
+- ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);
++ if (debug)
++ ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(udptlsin.sin_port));
+
+- /* XXX don't think you can have ptime for video */
+- if (min_video_packet_size)
+- ast_str_append(&a_video, 0, "a=ptime:%d\r\n", min_video_packet_size);
++ /* We break with the "recommendation" and send our IP, in order that our
++ peer doesn't have to ast_gethostbyname() us */
+
+- /* XXX don't think you can have ptime for text */
+- if (min_text_packet_size)
+- ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
+-
+- if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
+- m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
+- a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)
+- ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
++ if (debug) {
++ ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
++ p->t38.capability,
++ p->t38.peercapability,
++ p->t38.jointcapability);
++ }
+
++ ast_str_append(&m_modem, 0, "m=image %d udptl t38", ntohs(udptldest.sin_port));
++
++ if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
++ ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
++ if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
++ ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
++ if ((x = t38_get_rate(p->t38.jointcapability)))
++ ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", x);
++ if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
++ ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval\r\n");
++ if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
++ ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR\r\n");
++ if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
++ ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG\r\n");
++ ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
++ x = ast_udptl_get_local_max_datagram(p->udptl);
++ ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n", x);
++ ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
++ if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
++ ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
++ }
++
+ if (needaudio)
+ ast_str_append(&m_audio, 0, "\r\n");
+ if (needvideo)
+ ast_str_append(&m_video, 0, "\r\n");
+ if (needtext)
+ ast_str_append(&m_text, 0, "\r\n");
++ if (add_t38)
++ ast_str_append(&m_modem, 0, "\r\n");
+
+ len = strlen(version) + strlen(subject) + strlen(owner) +
+ strlen(connection) + strlen(session_time);
+@@ -9514,6 +9647,8 @@
+ len += m_video->used + a_video->used + strlen(bandwidth) + strlen(hold);
+ if (needtext) /* only if text response is appropriate */
+ len += m_text->used + a_text->used + strlen(hold);
++ if (add_t38)
++ len += m_modem->used + a_modem->used;
+
+ add_header(resp, "Content-Type", "application/sdp");
+ add_header_contentLength(resp, len);
+@@ -9539,6 +9674,10 @@
+ add_line(resp, a_text->str);
+ add_line(resp, hold); /* Repeat hold for the text stream */
+ }
++ if (add_t38) {
++ add_line(resp, m_modem->str);
++ add_line(resp, a_modem->str);
++ }
+
+ /* Update lastrtprx when we send our SDP */
+ p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
+@@ -9561,7 +9700,7 @@
+ respprep(&resp, p, msg, req);
+ if (p->udptl) {
+ ast_udptl_offered_from_local(p->udptl, 0);
+- add_t38_sdp(&resp, p);
++ add_sdp(&resp, p, 0, 0, 1);
+ } else
+ ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
+ if (retrans && !p->pendinginvite)
+@@ -9596,7 +9735,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;
+@@ -9605,13 +9744,20 @@
+ 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");
+- ast_rtp_codec_setpref(p->rtp, &p->prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
+ }
+- try_suggested_sip_codec(p);
+- add_sdp(&resp, p, oldsdp);
++ try_suggested_sip_codec(p);
++ if (p->t38.state == T38_PEER_DIRECT || p->t38.state == T38_ENABLED) {
++ add_sdp(&resp, p, oldsdp, TRUE, TRUE);
++ } else {
++ add_sdp(&resp, p, oldsdp, TRUE, FALSE);
++ }
+ } else
+ ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
+ if (reliable && !p->pendinginvite)
+@@ -9693,9 +9839,9 @@
+ if (p->do_history)
+ append_history(p, "ReInv", "Re-invite sent");
+ if (t38version)
+- add_t38_sdp(&req, p);
++ add_sdp(&req, p, oldsdp, FALSE, TRUE);
+ else
+- add_sdp(&req, p, oldsdp);
++ add_sdp(&req, p, oldsdp, TRUE, FALSE);
+
+ /* Use this as the basis */
+ initialize_initreq(p, &req);
+@@ -9750,85 +9896,6 @@
+ }
+ }
+
+-/*! \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\" <sip:%s@%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\" <sip:%s@%s>;tag=%s", clin,
+- S_OR(p->fromuser, clid),
+- fromdomain, p->tag);
+-}
+-
+ /*! \brief Initiate new SIP request to peer/user */
+ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod)
+ {
+@@ -9864,16 +9931,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))
+@@ -9961,12 +10022,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);
+@@ -9975,10 +10031,46 @@
+ 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 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), "<sip:%s@%s>;reason=%s", diverting_number, ast_inet_ntoa(pvt->ourip.sin_addr), reason);
++ } else {
++ snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%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
+@@ -10097,13 +10189,18 @@
+
+ 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)) {
++ if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
+ ast_udptl_offered_from_local(p->udptl, 1);
+ ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+- add_t38_sdp(&req, p);
++ add_sdp(&req, p, FALSE, FALSE, TRUE);
+ } else if (p->rtp)
+- add_sdp(&req, p, FALSE);
++ add_sdp(&req, p, FALSE, TRUE, FALSE);
+ } else {
+ if (!p->notify_headers) {
+ add_header_contentLength(&req, 0);
+@@ -10579,6 +10676,80 @@
+ " *Variable: <name>=<value> At least one variable pair must be specified.\n"
+ " ActionID: <id> 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, TRUE, 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"},
+@@ -10606,7 +10777,7 @@
+ static int sip_reregister(const void *data)
+ {
+ /* if we are here, we know that we need to reregister. */
+- struct sip_registry *r= (struct sip_registry *) data;
++ struct sip_registry *r = (struct sip_registry *) data;
+
+ /* if we couldn't get a reference to the registry object, punt */
+ if (!r)
+@@ -11916,10 +12087,96 @@
+ /*! \brief Send a fake 401 Unauthorized response when the administrator
+ wants to hide the names of local devices from fishers
+ */
+-static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable)
++static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable)
+ {
+- ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
+- transmit_response_with_auth(p, "401 Unauthorized", req, p->randdata, reliable, "WWW-Authenticate", 0);
++ /* We have to emulate EXACTLY what we'd get with a good peer
++ * and a bad password, or else we leak information. */
++ const char *response = "407 Proxy Authentication Required";
++ const char *reqheader = "Proxy-Authorization";
++ const char *respheader = "Proxy-Authenticate";
++ const char *authtoken;
++ struct ast_str *buf;
++ char *c;
++
++ /* table of recognised keywords, and their value in the digest */
++ enum keys { K_NONCE, K_LAST };
++ struct x {
++ const char *key;
++ const char *s;
++ } *i, keys[] = {
++ [K_NONCE] = { "nonce=", "" },
++ [K_LAST] = { NULL, NULL}
++ };
++
++ if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) {
++ response = "401 Unauthorized";
++ reqheader = "Authorization";
++ respheader = "WWW-Authenticate";
++ }
++ authtoken = get_header(req, reqheader);
++ if (req->ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
++ /* This is a retransmitted invite/register/etc, don't reconstruct authentication
++ * information */
++ transmit_response_with_auth(p, response, req, p->randdata, 0, respheader, 0);
++ /* Schedule auto destroy in 32 seconds (according to RFC 3261) */
++ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
++ return;
++ } else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
++ /* We have no auth, so issue challenge and request authentication */
++ ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
++ transmit_response_with_auth(p, response, req, p->randdata, 0, respheader, 0);
++ /* Schedule auto destroy in 32 seconds */
++ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
++ return;
++ }
++
++ if (!(buf = ast_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN))) {
++ transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ return;
++ }
++
++ /* Make a copy of the response and parse it */
++ if (ast_str_set(&buf, 0, "%s", authtoken) == AST_DYNSTR_BUILD_FAILED) {
++ transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ return;
++ }
++
++ c = buf->str;
++
++ while (c && *(c = ast_skip_blanks(c))) { /* lookup for keys */
++ for (i = keys; i->key != NULL; i++) {
++ const char *separator = ","; /* default */
++
++ if (strncasecmp(c, i->key, strlen(i->key)) != 0) {
++ continue;
++ }
++ /* Found. Skip keyword, take text in quotes or up to the separator. */
++ c += strlen(i->key);
++ if (*c == '"') { /* in quotes. Skip first and look for last */
++ c++;
++ separator = "\"";
++ }
++ i->s = c;
++ strsep(&c, separator);
++ break;
++ }
++ if (i->key == NULL) { /* not found, jump after space or comma */
++ strsep(&c, " ,");
++ }
++ }
++
++ /* Verify nonce from request matches our nonce. If not, send 401 with new nonce */
++ if (strcasecmp(p->randdata, keys[K_NONCE].s)) {
++ if (!req->ignore) {
++ ast_string_field_build(p, randdata, "%08lx", ast_random());
++ }
++ transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, FALSE);
++
++ /* Schedule auto destroy in 32 seconds */
++ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
++ } else {
++ transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq);
++ }
+ }
+
+ /*!
+@@ -12011,12 +12268,6 @@
+ }
+
+ 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);
+- p->autoframing = peer->autoframing;
+- }
+ if (!peer->host_dynamic) {
+ ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);
+ res = AUTH_PEER_NOT_DYNAMIC;
+@@ -12095,6 +12346,14 @@
+ }
+ }
+ }
++ if (!peer && sip_cfg.alwaysauthreject) {
++ /* If we found a peer, we transmit a 100 Trying. Therefore, if we're
++ * trying to avoid leaking information, we MUST also transmit the same
++ * response when we DON'T find a peer. */
++ transmit_response(p, "100 Trying", req);
++ /* Insert a fake delay between the 100 and the subsequent failure. */
++ sched_yield();
++ }
+ if (!res) {
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+ }
+@@ -12108,7 +12367,7 @@
+ name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+ break;
+ case AUTH_USERNAME_MISMATCH:
+- /* Username and digest username does not match.
++ /* Username and digest username does not match.
+ Asterisk uses the From: username for authentication. We need the
+ devices to use the same authentication user name until we support
+ proper authentication by digest auth name */
+@@ -12121,7 +12380,12 @@
+ case AUTH_PEER_NOT_DYNAMIC:
+ case AUTH_ACL_FAILED:
+ if (sip_cfg.alwaysauthreject) {
+- transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE);
++ transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE);
++ if (global_authfailureevents) {
++ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Rejected\r\nCause: %s\r\nAddress: %s\r\nPort: %d\r\n",
++ name, res == AUTH_PEER_NOT_DYNAMIC ? "AUTH_PEER_NOT_DYNAMIC" : "URI_NOT_FOUND",
++ ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
++ }
+ } else {
+ /* URI not found */
+ if (res == AUTH_PEER_NOT_DYNAMIC) {
+@@ -12178,23 +12442,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;
+
+- /*! \todo This function does not take user-parameters into consideration.
+- First look for @, then start looking for ; to find uri-parameters.
+- */
+- params = strchr(tmp, ';');
++ if ((params = strchr(tmp, '>'))) {
++ params = strchr(params, ';');
++ }
+
+ exten = get_in_brackets(tmp);
+ if (!strncasecmp(exten, "sip:", 4)) {
+@@ -12213,16 +12653,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);
+ }
+ }
+ }
+@@ -12230,14 +12670,33 @@
+
+ rdomain = exten;
+ rexten = strsep(&rdomain, "@"); /* trim anything after @ */
+- if (p->owner)
++ if (p->owner)
+ 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;
+ }
+
+@@ -12849,58 +13308,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;
+-}
+-
+-
+-/*! \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);
+@@ -12935,7 +13348,7 @@
+ /* XXX what about p->prefs = peer->prefs; ? */
+ /* Set Frame packetization */
+ if (p->rtp) {
+- ast_rtp_codec_setpref(p->rtp, &peer->prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs);
+ p->autoframing = peer->autoframing;
+ }
+
+@@ -12948,7 +13361,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);
+@@ -12957,6 +13369,7 @@
+ ast_string_field_set(p, mohinterpret, peer->mohinterpret);
+ ast_string_field_set(p, mohsuggest, peer->mohsuggest);
+ ast_string_field_set(p, parkinglot, peer->parkinglot);
++ ast_string_field_set(p, engine, peer->engine);
+ if (peer->callingpres) /* Peer calling pres setting will override RPID */
+ p->callingpres = peer->callingpres;
+ if (peer->maxms && peer->lastms)
+@@ -13000,14 +13413,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);
+@@ -13024,17 +13441,6 @@
+ if (p->peercapability)
+ p->jointcapability &= p->peercapability;
+ p->maxcallbitrate = peer->maxcallbitrate;
+- if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) &&
+- (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ||
+- !(p->capability & AST_FORMAT_VIDEO_MASK)) &&
+- p->vrtp) {
+- ast_rtp_destroy(p->vrtp);
+- p->vrtp = NULL;
+- }
+- if ((!ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) || !(p->capability & AST_FORMAT_TEXT_MASK)) && p->trtp) {
+- ast_rtp_destroy(p->trtp);
+- p->trtp = NULL;
+- }
+ 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;
+@@ -13043,6 +13449,12 @@
+ p->jointnoncodeccapability = p->noncodeccapability;
+ if (p->t38.peercapability)
+ p->t38.jointcapability &= p->t38.peercapability;
++ if (!dialog_initialize_rtp(p)) {
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs);
++ p->autoframing = peer->autoframing;
++ } else {
++ res = AUTH_RTP_FAILED;
++ }
+ }
+ unref_peer(peer, "check_peer_ok: unref_peer: tossing temp ptr to peer from find_peer");
+ return res;
+@@ -13062,8 +13474,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);
+@@ -13079,11 +13489,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;
+@@ -13157,14 +13562,18 @@
+ }
+
+ 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 (sip_cfg.allowguest) {
+- replace_cid(p, rpid_num, calleridname);
+- res = AUTH_SUCCESSFUL;
++ get_rpid(p, req);
++ if (!dialog_initialize_rtp(p)) {
++ res = AUTH_SUCCESSFUL;
++ } else {
++ res = AUTH_RTP_FAILED;
++ }
+ } else if (sip_cfg.alwaysauthreject)
+ res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
+ else
+@@ -13961,7 +14370,20 @@
+ */
+ return 0;
+ }
+-
++
++ /* We absolutely cannot destroy the rtp struct while a bridge is active or we WILL crash */
++ if (dialog->rtp && ast_rtp_instance_get_bridged(dialog->rtp)) {
++ ast_debug(2, "Bridge still active. Delaying destroy of SIP dialog '%s' Method: %s\n", dialog->callid, sip_methods[dialog->method].text);
++ sip_pvt_unlock(dialog);
++ return 0;
++ }
++
++ if (dialog->vrtp && ast_rtp_instance_get_bridged(dialog->vrtp)) {
++ ast_debug(2, "Bridge still active. Delaying destroy of SIP dialog '%s' Method: %s\n", dialog->callid, sip_methods[dialog->method].text);
++ sip_pvt_unlock(dialog);
++ return 0;
++ }
++
+ /* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */
+ check_rtp_timeout(dialog, *t);
+
+@@ -13970,13 +14392,13 @@
+ - if that's the case, wait with destruction */
+ if (dialog->needdestroy && !dialog->packets && !dialog->owner) {
+ /* We absolutely cannot destroy the rtp struct while a bridge is active or we WILL crash */
+- if (dialog->rtp && ast_rtp_get_bridged(dialog->rtp)) {
++ if (dialog->rtp && ast_rtp_instance_get_bridged(dialog->rtp)) {
+ ast_debug(2, "Bridge still active. Delaying destruction of SIP dialog '%s' Method: %s\n", dialog->callid, sip_methods[dialog->method].text);
+ sip_pvt_unlock(dialog);
+ return 0;
+ }
+
+- if (dialog->vrtp && ast_rtp_get_bridged(dialog->vrtp)) {
++ if (dialog->vrtp && ast_rtp_instance_get_bridged(dialog->vrtp)) {
+ ast_debug(2, "Bridge still active. Delaying destroy of SIP dialog '%s' Method: %s\n", dialog->callid, sip_methods[dialog->method].text);
+ sip_pvt_unlock(dialog);
+ return 0;
+@@ -14466,6 +14888,7 @@
+ ast_cli(fd, " Sess-Refresh : %s\n", strefresher2str(peer->stimer.st_ref));
+ ast_cli(fd, " Sess-Expires : %d secs\n", peer->stimer.st_max_se);
+ ast_cli(fd, " Min-Sess : %d secs\n", peer->stimer.st_min_se);
++ ast_cli(fd, " RTP Engine : %s\n", peer->engine);
+ ast_cli(fd, "\n");
+ peer = unref_peer(peer, "sip_show_peer: unref_peer: done with peer ptr");
+ } else if (peer && type == 1) { /* manager listing */
+@@ -14513,6 +14936,7 @@
+ astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresher2str(peer->stimer.st_ref));
+ astman_append(s, "SIP-Sess-Expires: %d\r\n", peer->stimer.st_max_se);
+ astman_append(s, "SIP-Sess-Min: %d\r\n", peer->stimer.st_min_se);
++ astman_append(s, "SIP-RTP-Engine: %s\r\n", peer->engine);
+
+ /* - is enumerated */
+ astman_append(s, "SIP-DTMFmode: %s\r\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF)));
+@@ -14645,6 +15069,7 @@
+ ast_cli(a->fd, " Sess-Refresh : %s\n", strefresher2str(user->stimer.st_ref));
+ ast_cli(a->fd, " Sess-Expires : %d secs\n", user->stimer.st_max_se);
+ ast_cli(a->fd, " Sess-Min-SE : %d secs\n", user->stimer.st_min_se);
++ ast_cli(a->fd, " RTP Engine : %s\n", user->engine);
+
+ ast_cli(a->fd, " Codec Order : (");
+ print_codec_to_cli(a->fd, &user->prefs);
+@@ -14799,11 +15224,10 @@
+ #define FORMAT2 "%-15.15s %-11.11s %-8.8s %-10.10s %-10.10s (%-2.2s) %-6.6s %-10.10s %-10.10s ( %%) %-6.6s\n"
+ #define FORMAT "%-15.15s %-11.11s %-8.8s %-10.10u%-1.1s %-10.10u (%-2.2u%%) %-6.6u %-10.10u%-1.1s %-10.10u (%-2.2u%%) %-6.6u\n"
+ struct sip_pvt *cur = __cur;
+- unsigned int rxcount;
+- unsigned int txcount;
++ struct ast_rtp_instance_stats stats;
+ char durbuf[10];
+- int duration;
+- int durh, durm, durs;
++ int duration;
++ int durh, durm, durs;
+ struct ast_channel *c = cur->owner;
+ struct __show_chan_arg *arg = __arg;
+ int fd = arg->fd;
+@@ -14817,10 +15241,9 @@
+ ast_cli(fd, "%-15.15s %-11.11s (inv state: %s) -- %s\n", ast_inet_ntoa(cur->sa.sin_addr), cur->callid, invitestate2string[cur->invitestate].desc, "-- No RTP active");
+ return 0; /* don't care, we scan all channels */
+ }
+- rxcount = ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXCOUNT);
+- txcount = ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXCOUNT);
+
+- /* Find the duration of this channel */
++ ast_rtp_instance_get_stats(cur->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL);
++
+ if (c && c->cdr && !ast_tvzero(c->cdr->start)) {
+ duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
+ durh = duration / 3600;
+@@ -14830,21 +15253,21 @@
+ } else {
+ durbuf[0] = '\0';
+ }
+- /* Print stats for every call with RTP */
++
+ ast_cli(fd, FORMAT,
+ ast_inet_ntoa(cur->sa.sin_addr),
+ cur->callid,
+ durbuf,
+- rxcount > (unsigned int) 100000 ? (unsigned int) (rxcount)/(unsigned int) 1000 : rxcount,
+- rxcount > (unsigned int) 100000 ? "K":" ",
+- ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS),
+- rxcount > ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS) ? (unsigned int) (ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS) / rxcount * 100) : 0,
+- ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXJITTER),
+- txcount > (unsigned int) 100000 ? (unsigned int) (txcount)/(unsigned int) 1000 : txcount,
+- txcount > (unsigned int) 100000 ? "K":" ",
+- ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS),
+- txcount > ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS) ? (unsigned int) (ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS)/ txcount * 100) : 0,
+- ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXJITTER)
++ stats.rxcount > (unsigned int) 100000 ? (unsigned int) (stats.rxcount)/(unsigned int) 1000 : stats.rxcount,
++ stats.rxcount > (unsigned int) 100000 ? "K":" ",
++ stats.rxploss,
++ stats.rxcount > stats.rxploss ? (stats.rxploss / stats.rxcount * 100) : 0,
++ stats.rxjitter,
++ stats.txcount > (unsigned int) 100000 ? (unsigned int) (stats.txcount)/(unsigned int) 1000 : stats.txcount,
++ stats.txcount > (unsigned int) 100000 ? "K":" ",
++ stats.txploss,
++ stats.txcount > stats.txploss ? (stats.txploss / stats.txcount * 100) : 0,
++ stats.txjitter
+ );
+ arg->numchans++;
+
+@@ -16387,29 +16810,150 @@
+ .read = function_sipchaninfo_read,
+ };
+
++static int read_to_parts(struct sip_pvt *p, struct sip_request *req, char **name, char **number)
++{
++
++ 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)
++static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward)
+ {
+- char tmp[SIPBUFSIZE];
+- char *s, *e, *t, *trans;
++ 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;
+@@ -16417,12 +16961,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);
+@@ -16432,51 +16976,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 */
+@@ -16516,12 +17079,15 @@
+ to avoid race conditions between asterisk servers.
+ Called from the scheduler.
+ */
+-static int sip_reinvite_retry(const void *data)
++static int sip_reinvite_retry(const void *data)
+ {
+ struct sip_pvt *p = (struct sip_pvt *) data;
+
+- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
++ sip_pvt_lock(p); /* called from schedule thread which requires a lock */
++ ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+ p->waitid = -1;
++ check_pendings(p);
++ sip_pvt_unlock(p);
+ dialog_unref(p, "unref the dialog ptr from sip_reinvite_retry, because it held a dialog ptr");
+ return 0;
+ }
+@@ -16536,7 +17102,8 @@
+ int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
+ 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
+@@ -16554,7 +17121,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 */
+@@ -16582,6 +17149,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_channel_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);
+@@ -16599,10 +17174,32 @@
+ 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_channel_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_channel_queue_connected_line_update(p->owner, &connected);
++ }
++ }
+ if (find_sdp(req)) {
+ if (p->invitestate != INV_CANCELLED)
+ p->invitestate = INV_EARLY_MEDIA;
+@@ -16624,9 +17221,19 @@
+ if (!reinvite)
+ /* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
+ /* For re-invites, we try to recover */
+- ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
++ 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_channel_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 */
+ /* This is important when we have a SIP proxy between us and the phone */
+@@ -16648,6 +17255,9 @@
+
+ if (!req->ignore && p->owner) {
+ if (!reinvite) {
++ struct ast_party_connected_line connected;
++ ast_party_connected_line_collect_caller(&connected, &p->owner->cid);
++ ast_channel_queue_connected_line_update(p->owner, &connected);
+ ast_queue_control(p->owner, AST_CONTROL_ANSWER);
+ if (sip_cfg.callevents)
+ manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
+@@ -16788,24 +17398,10 @@
+ if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
+ change_t38_state(p, T38_DISABLED);
+ /* Try to reset RTP timers */
+- ast_rtp_set_rtptimers_onhold(p->rtp);
++ //ast_rtp_set_rtptimers_onhold(p->rtp);
+
+ /* Trigger a reinvite back to audio */
+ transmit_reinvite_with_sdp(p, FALSE, FALSE);
+- } else if (p->udptl && p->t38.state == T38_LOCAL_DIRECT) {
+- /* We tried to send T.38 out in an initial INVITE and the remote side rejected it,
+- right now we can't fall back to audio so totally abort.
+- */
+- /* Try to reset RTP timers */
+- ast_rtp_set_rtptimers_onhold(p->rtp);
+- ast_log(LOG_ERROR, "Got error on T.38 initial invite. Bailing out.\n");
+-
+- change_t38_state(p, T38_DISABLED);
+- /* The dialog is now terminated */
+- if (p->owner && !req->ignore)
+- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+- 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)
+@@ -16826,8 +17422,15 @@
+ /* This is a re-invite that failed. */
+ /* Reset the flag after a while
+ */
+- int wait = 3 + ast_random() % 5;
+- p->waitid = ast_sched_add(sched, wait, sip_reinvite_retry, dialog_ref(p, "passing dialog ptr into sched structure based on waitid for sip_reinvite_retry."));
++ int wait;
++ /* RFC 3261, if owner of call, wait between 2.1 to 4 seconds,
++ * if not owner of call, wait 0 to 2 seconds */
++ if (p->outgoing_call) {
++ wait = 2100 + ast_random() % 2000;
++ } else {
++ wait = ast_random() % 2000;
++ }
++ p->waitid = ast_sched_add(sched, wait, sip_reinvite_retry, dialog_ref(p, "passing dialog ptr into sched structure based on waitid for sip_reinvite_retry."));
+ ast_log(LOG_WARNING, "just did sched_add waitid(%d) for sip_reinvite_retry for dialog %s in handle_response_invite\n", p->waitid, p->callid);
+ ast_debug(2, "Reinvite race. Waiting %d secs before retry\n", wait);
+ }
+@@ -16953,6 +17556,8 @@
+ */
+ static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
+ {
++ enum ast_control_transfer message = AST_TRANSFER_FAILED;
++
+ /* If no refer structure exists, then do nothing */
+ if (!p->refer)
+ return;
+@@ -16972,12 +17577,18 @@
+ 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));
++ if (p->owner) {
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
+ 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;
+- pvt_set_needdestroy(p, "failed to authenticat REFER");
++ if (p->owner) {
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
++ pvt_set_needdestroy(p, "failed to authenticate REFER");
+ }
+ break;
+ case 481: /* Call leg does not exist */
+@@ -16998,11 +17609,17 @@
+ ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to);
+ pvt_set_needdestroy(p, "received 500/501 response");
+ p->refer->status = REFER_FAILED;
++ if (p->owner) {
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
+ 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;
+ pvt_set_needdestroy(p, "received 603 response");
++ if (p->owner) {
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
+ break;
+ }
+ }
+@@ -17215,11 +17832,11 @@
+ {
+ /* Immediately stop RTP, VRTP and UDPTL as applicable */
+ if (p->rtp)
+- ast_rtp_stop(p->rtp);
++ ast_rtp_instance_stop(p->rtp);
+ if (p->vrtp)
+- ast_rtp_stop(p->vrtp);
++ ast_rtp_instance_stop(p->vrtp);
+ if (p->trtp)
+- ast_rtp_stop(p->trtp);
++ ast_rtp_instance_stop(p->trtp);
+ if (p->udptl)
+ ast_udptl_stop(p->udptl);
+ }
+@@ -17296,6 +17913,7 @@
+ case 183: /* 183 Session Progress */
+ case 180: /* 180 Ringing */
+ case 182: /* 182 Queued */
++ case 181: /* 181 Call Is Being Forwarded */
+ if (sipmethod == SIP_INVITE)
+ handle_response_invite(p, resp, rest, req, seqno);
+ break;
+@@ -17463,7 +18081,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_channel_set_redirecting(p->owner, &redirecting);
++ }
+ /* Fall through */
+ case 486: /* Busy here */
+ case 600: /* Busy everywhere */
+@@ -18037,7 +18659,11 @@
+ if (!success) {
+ ast_log(LOG_NOTICE, "Transfer failed. Sorry. Nothing further to do with this call\n");
+ }
+-
++
++ if (p->owner) {
++ enum ast_control_transfer message = success ? AST_TRANSFER_SUCCESS : AST_TRANSFER_FAILED;
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
+ /* Confirm that we received this packet */
+ transmit_response(p, "200 OK", req);
+ } else if (p->mwi && !strcmp(event, "message-summary")) {
+@@ -18054,10 +18680,7 @@
+ 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);
++ ast_event_queue_and_cache(event);
+ }
+ }
+
+@@ -18158,7 +18781,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);
+@@ -18192,7 +18815,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);
+
+@@ -18592,10 +19215,11 @@
+ return 0;
+ }
+
+-/*! \brief Handle incoming INVITE request
+-\note If the INVITE has a Replaces header, it is part of an
++/*!
++ * \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)
+@@ -18704,9 +19328,10 @@
+ return transmit_invite(p, SIP_INVITE, 1, 3);
+ }
+ }
+-
++
+ if (!req->ignore && p->pendinginvite) {
+ /* We already have a pending invite. Sorry. You are on hold. */
++ p->glareinvite = seqno; /* must hold on to this seqno to process ack and retransmit correctly */
+ transmit_response_reliable(p, "491 Request Pending", req);
+ ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid);
+ /* Don't destroy dialog here */
+@@ -18865,6 +19490,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_channel_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)) {
+@@ -18887,6 +19522,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 */
+@@ -18895,7 +19531,7 @@
+ if (res < 0) { /* Something failed in authentication */
+ if (res == AUTH_FAKE_AUTH) {
+ ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+- transmit_fake_auth_response(p, req, XMIT_RELIABLE);
++ transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
+ } else {
+ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+ transmit_response_reliable(p, "403 Forbidden", req);
+@@ -18944,13 +19580,13 @@
+ 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 */
+
+ if (p->rtp) {
+- ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
+- ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
++ ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
++ ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
+ }
+
+ if (!replace_id && gotdest) { /* No matching extension found */
+@@ -18988,9 +19624,11 @@
+ if (c) {
+ /* Pre-lock the call */
+ ast_channel_lock(c);
++ ast_channel_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);
+@@ -19000,6 +19638,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_channel_set_redirecting(c, &redirecting);
++ }
+ }
+
+ /* Session-Timers */
+@@ -19210,7 +19852,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;
+@@ -19240,7 +19881,7 @@
+ } else if (p->t38.state == T38_DISABLED) {
+ /* 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;
+@@ -19358,6 +19999,8 @@
+ 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");
+
+@@ -19372,6 +20015,45 @@
+ ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name);
+ ast_channel_unlock(targetcall_pvt->owner);
+ }
++
++ if (target.chan2) {
++ if (current->chan2) {
++ /* Tell each of the other channels to whom they are now connected */
++ ast_channel_lock(current->chan2);
++ ast_connected_line_copy_from_caller(&connected_caller, &current->chan2->cid);
++ ast_channel_unlock(current->chan2);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(target.chan2, &connected_caller);
++ ast_channel_lock(target.chan2);
++ ast_connected_line_copy_from_caller(&connected_caller, &target.chan2->cid);
++ ast_channel_unlock(target.chan2);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(current->chan2, &connected_caller);
++ ast_party_connected_line_free(&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) {
++ ast_channel_lock(target.chan1);
++ ast_party_connected_line_copy(&connected_caller, &target.chan1->connected);
++ ast_channel_unlock(target.chan1);
++ connected_caller = target.chan1->connected;
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(current->chan2, &connected_caller);
++ ast_party_connected_line_free(&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_channel_queue_connected_line_update(target.chan1, &connected_caller);
++ }
+ }
+ if (targetcall_pvt)
+ ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
+@@ -19769,7 +20451,7 @@
+ static int acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen)
+ {
+ struct sip_pvt *p = chan->tech_pvt;
+- char *all = "", *parse = ast_strdupa(preparse);
++ char *parse = ast_strdupa(preparse);
+ int res = 0;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(param);
+@@ -19807,61 +20489,70 @@
+ args.type = "audio";
+
+ if (!strcasecmp(args.type, "audio"))
+- ast_rtp_get_peer(p->rtp, &sin);
++ ast_rtp_instance_get_remote_address(p->rtp, &sin);
+ else if (!strcasecmp(args.type, "video"))
+- ast_rtp_get_peer(p->vrtp, &sin);
++ ast_rtp_instance_get_remote_address(p->vrtp, &sin);
+ else if (!strcasecmp(args.type, "text"))
+- ast_rtp_get_peer(p->trtp, &sin);
++ ast_rtp_instance_get_remote_address(p->trtp, &sin);
+ else
+ return -1;
+
+ snprintf(buf, buflen, "%s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ } else if (!strcasecmp(args.param, "rtpqos")) {
+- struct ast_rtp_quality qos;
+- struct ast_rtp *rtp = p->rtp;
+-
+- memset(&qos, 0, sizeof(qos));
++ struct ast_rtp_instance *rtp = NULL;
+
+- if (ast_strlen_zero(args.type))
++ if (ast_strlen_zero(args.type)) {
+ args.type = "audio";
+- if (ast_strlen_zero(args.field))
+- args.field = "all";
+-
+- if (!strcasecmp(args.type, "AUDIO")) {
+- all = ast_rtp_get_quality(rtp = p->rtp, &qos, RTPQOS_SUMMARY);
+- } else if (!strcasecmp(args.type, "VIDEO")) {
+- all = ast_rtp_get_quality(rtp = p->vrtp, &qos, RTPQOS_SUMMARY);
+- } else if (!strcasecmp(args.type, "TEXT")) {
+- all = ast_rtp_get_quality(rtp = p->trtp, &qos, RTPQOS_SUMMARY);
++ }
++
++ if (!strcasecmp(args.type, "audio")) {
++ rtp = p->rtp;
++ } else if (!strcasecmp(args.type, "video")) {
++ rtp = p->vrtp;
++ } else if (!strcasecmp(args.type, "text")) {
++ rtp = p->trtp;
+ } else {
+- return -1;
++ return -1;
+ }
+-
+- if (!strcasecmp(args.field, "local_ssrc"))
+- snprintf(buf, buflen, "%u", qos.local_ssrc);
+- else if (!strcasecmp(args.field, "local_lostpackets"))
+- snprintf(buf, buflen, "%u", qos.local_lostpackets);
+- else if (!strcasecmp(args.field, "local_jitter"))
+- snprintf(buf, buflen, "%.0f", qos.local_jitter * 1000.0);
+- else if (!strcasecmp(args.field, "local_count"))
+- snprintf(buf, buflen, "%u", qos.local_count);
+- else if (!strcasecmp(args.field, "remote_ssrc"))
+- snprintf(buf, buflen, "%u", qos.remote_ssrc);
+- else if (!strcasecmp(args.field, "remote_lostpackets"))
+- snprintf(buf, buflen, "%u", qos.remote_lostpackets);
+- else if (!strcasecmp(args.field, "remote_jitter"))
+- snprintf(buf, buflen, "%.0f", qos.remote_jitter * 1000.0);
+- else if (!strcasecmp(args.field, "remote_count"))
+- snprintf(buf, buflen, "%u", qos.remote_count);
+- else if (!strcasecmp(args.field, "rtt"))
+- snprintf(buf, buflen, "%.0f", qos.rtt * 1000.0);
+- else if (!strcasecmp(args.field, "all"))
+- ast_copy_string(buf, all, buflen);
+- else if (!ast_rtp_get_qos(rtp, args.field, buf, buflen))
+- ;
+- else {
+- ast_log(LOG_WARNING, "Unrecognized argument '%s' to %s\n", preparse, funcname);
+- return -1;
++
++ if (ast_strlen_zero(args.field) || !strcasecmp(args.field, "all")) {
++ char quality_buf[AST_MAX_USER_FIELD], *quality;
++
++ if (!(quality = ast_rtp_instance_get_quality(rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ return -1;
++ }
++
++ ast_copy_string(buf, quality_buf, buflen);
++ return res;
++ } else {
++ struct ast_rtp_instance_stats stats;
++
++ if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
++ return -1;
++ }
++
++ if (!strcasecmp(args.field, "local_ssrc")) {
++ snprintf(buf, buflen, "%u", stats.local_ssrc);
++ } else if (!strcasecmp(args.field, "local_lostpackets")) {
++ snprintf(buf, buflen, "%u", stats.rxploss);
++ } else if (!strcasecmp(args.field, "local_jitter")) {
++ snprintf(buf, buflen, "%u", stats.rxjitter);
++ } else if (!strcasecmp(args.field, "local_count")) {
++ snprintf(buf, buflen, "%u", stats.rxcount);
++ } else if (!strcasecmp(args.field, "remote_ssrc")) {
++ snprintf(buf, buflen, "%u", stats.remote_ssrc);
++ } else if (!strcasecmp(args.field, "remote_lostpackets")) {
++ snprintf(buf, buflen, "%u", stats.txploss);
++ } else if (!strcasecmp(args.field, "remote_jitter")) {
++ snprintf(buf, buflen, "%u", stats.txjitter);
++ } else if (!strcasecmp(args.field, "remote_count")) {
++ snprintf(buf, buflen, "%u", stats.txcount);
++ } else if (!strcasecmp(args.field, "rtt")) {
++ snprintf(buf, buflen, "%u", stats.rtt);
++ } else {
++ ast_log(LOG_WARNING, "Unrecognized argument '%s' to %s\n", preparse, funcname);
++ return -1;
++ }
+ }
+ } else {
+ res = -1;
+@@ -19893,53 +20584,53 @@
+
+ /* Get RTCP quality before end of call */
+ if (p->do_history || p->owner) {
++ char quality_buf[AST_MAX_USER_FIELD], *quality;
+ struct ast_channel *bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
+- char *videoqos, *textqos;
+
+- if (p->rtp) {
++ if (p->rtp && (quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
+ if (p->do_history) {
+- char *audioqos,
+- *audioqos_jitter,
+- *audioqos_loss,
+- *audioqos_rtt;
++ append_history(p, "RTCPaudio", "Quality:%s", quality);
+
+- audioqos = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_SUMMARY);
+- audioqos_jitter = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_JITTER);
+- audioqos_loss = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_LOSS);
+- audioqos_rtt = ast_rtp_get_quality(p->rtp, NULL, RTPQOS_RTT);
++ if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)))) {
++ append_history(p, "RTCPaudioJitter", "Quality:%s", quality);
++ }
++ if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)))) {
++ append_history(p, "RTCPaudioLoss", "Quality:%s", quality);
++ }
++ if ((quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)))) {
++ append_history(p, "RTCPaudioRTT", "Quality:%s", quality);
++ }
++ }
+
+- append_history(p, "RTCPaudio", "Quality:%s", audioqos);
+- append_history(p, "RTCPaudioJitter", "Quality:%s", audioqos_jitter);
+- append_history(p, "RTCPaudioLoss", "Quality:%s", audioqos_loss);
+- append_history(p, "RTCPaudioRTT", "Quality:%s", audioqos_rtt);
+- }
+-
+ if (p->owner) {
+- ast_rtp_set_vars(p->owner, p->rtp);
++ ast_rtp_instance_set_stats_vars(p->owner, p->rtp);
+ }
++
+ }
+
+ if (bridge) {
+ struct sip_pvt *q = bridge->tech_pvt;
+
+- if (IS_SIP_TECH(bridge->tech) && q->rtp)
+- ast_rtp_set_vars(bridge, q->rtp);
++ if (IS_SIP_TECH(bridge->tech) && q->rtp) {
++ ast_rtp_instance_set_stats_vars(bridge, q->rtp);
++ }
+ }
+
+- if (p->vrtp) {
+- videoqos = ast_rtp_get_quality(p->vrtp, NULL, RTPQOS_SUMMARY);
+- if (p->do_history)
+- append_history(p, "RTCPvideo", "Quality:%s", videoqos);
+- if (p->owner)
+- pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", videoqos);
++ if (p->vrtp && (quality = ast_rtp_instance_get_quality(p->vrtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ if (p->do_history) {
++ append_history(p, "RTCPvideo", "Quality:%s", quality);
++ }
++ if (p->owner) {
++ pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", quality);
++ }
+ }
+-
+- if (p->trtp) {
+- textqos = ast_rtp_get_quality(p->trtp, NULL, RTPQOS_SUMMARY);
+- if (p->do_history)
+- append_history(p, "RTCPtext", "Quality:%s", textqos);
+- if (p->owner)
+- pbx_builtin_setvar_helper(p->owner, "RTPTEXTQOS", textqos);
++ if (p->trtp && (quality = ast_rtp_instance_get_quality(p->trtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ if (p->do_history) {
++ append_history(p, "RTCPtext", "Quality:%s", quality);
++ }
++ if (p->owner) {
++ pbx_builtin_setvar_helper(p->owner, "RTPTEXTQOS", quality);
++ }
+ }
+ }
+
+@@ -20092,7 +20783,7 @@
+ if (res < 0) {
+ if (res == AUTH_FAKE_AUTH) {
+ ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+- transmit_fake_auth_response(p, req, XMIT_UNRELIABLE);
++ transmit_fake_auth_response(p, SIP_SUBSCRIBE, req, XMIT_UNRELIABLE);
+ } else {
+ ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", get_header(req, "From"));
+ transmit_response_reliable(p, "403 Forbidden", req);
+@@ -20436,10 +21127,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
+@@ -20580,8 +21271,12 @@
+ if (find_sdp(req)) {
+ if (process_sdp(p, req, SDP_T38_NONE))
+ return -1;
+- }
++ }
+ check_pendings(p);
++ } else if (p->glareinvite == seqno) {
++ /* handle ack for the 491 pending sent for glareinvite */
++ p->glareinvite = 0;
++ __sip_ack(p, seqno, 1, 0);
+ }
+ /* Got an ACK that we did not match. Ignore silently */
+ if (!p->lastinvite && ast_strlen_zero(p->randdata)) {
+@@ -21033,8 +21728,6 @@
+ event = ast_event_get_cached(AST_EVENT_MWI,
+ AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox->mailbox,
+ AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, S_OR(mailbox->context, "default"),
+- AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+- AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+ AST_EVENT_IE_END);
+ if (!event)
+ continue;
+@@ -21126,15 +21819,8 @@
+ return;
+
+ /* If we have no timers set, return now */
+- if ((ast_rtp_get_rtpkeepalive(dialog->rtp) == 0) && (ast_rtp_get_rtptimeout(dialog->rtp) == 0) && (ast_rtp_get_rtpholdtimeout(dialog->rtp) == 0))
++ if (!ast_rtp_instance_get_timeout(dialog->rtp) && !ast_rtp_instance_get_hold_timeout(dialog->rtp)) {
+ return;
+-
+- /* Check AUDIO RTP keepalives */
+- if (dialog->lastrtptx && ast_rtp_get_rtpkeepalive(dialog->rtp) &&
+- (t > dialog->lastrtptx + ast_rtp_get_rtpkeepalive(dialog->rtp))) {
+- /* Need to send an empty RTP packet */
+- dialog->lastrtptx = time(NULL);
+- ast_rtp_sendcng(dialog->rtp, 0);
+ }
+
+ /*! \todo Check video RTP keepalives
+@@ -21144,16 +21830,10 @@
+ */
+
+ /* Check AUDIO RTP timers */
+- if (dialog->lastrtprx && (ast_rtp_get_rtptimeout(dialog->rtp) || ast_rtp_get_rtpholdtimeout(dialog->rtp)) &&
+- (t > dialog->lastrtprx + ast_rtp_get_rtptimeout(dialog->rtp))) {
+-
+- /* Might be a timeout now -- see if we're on hold */
+- struct sockaddr_in sin;
+- ast_rtp_get_peer(dialog->rtp, &sin);
+- if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD) || (ast_rtp_get_rtpholdtimeout(dialog->rtp) &&
+- (t > dialog->lastrtprx + ast_rtp_get_rtpholdtimeout(dialog->rtp)))) {
++ if (dialog->lastrtprx && (ast_rtp_instance_get_timeout(dialog->rtp) || ast_rtp_instance_get_hold_timeout(dialog->rtp)) && (t > dialog->lastrtprx + ast_rtp_instance_get_timeout(dialog->rtp))) {
++ if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD) || (ast_rtp_instance_get_hold_timeout(dialog->rtp) && (t > dialog->lastrtprx + ast_rtp_instance_get_hold_timeout(dialog->rtp)))) {
+ /* Needs a hangup */
+- if (ast_rtp_get_rtptimeout(dialog->rtp)) {
++ if (ast_rtp_instance_get_timeout(dialog->rtp)) {
+ while (dialog->owner && ast_channel_trylock(dialog->owner)) {
+ sip_pvt_unlock(dialog);
+ usleep(1);
+@@ -21168,11 +21848,11 @@
+ has already been requested and we don't want to
+ repeatedly request hangups
+ */
+- ast_rtp_set_rtptimeout(dialog->rtp, 0);
+- ast_rtp_set_rtpholdtimeout(dialog->rtp, 0);
++ ast_rtp_instance_set_timeout(dialog->rtp, 0);
++ ast_rtp_instance_set_hold_timeout(dialog->rtp, 0);
+ if (dialog->vrtp) {
+- ast_rtp_set_rtptimeout(dialog->vrtp, 0);
+- ast_rtp_set_rtpholdtimeout(dialog->vrtp, 0);
++ ast_rtp_instance_set_timeout(dialog->vrtp, 0);
++ ast_rtp_instance_set_hold_timeout(dialog->vrtp, 0);
+ }
+ }
+ }
+@@ -22024,7 +22704,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);
+@@ -22332,6 +23021,7 @@
+ ast_string_field_set(peer, language, default_language);
+ ast_string_field_set(peer, mohinterpret, default_mohinterpret);
+ ast_string_field_set(peer, mohsuggest, default_mohsuggest);
++ ast_string_field_set(peer, engine, default_engine);
+ peer->addr.sin_family = AF_INET;
+ peer->defaddr.sin_family = AF_INET;
+ peer->capability = global_capability;
+@@ -22671,6 +23361,8 @@
+ ast_string_field_set(peer, mohsuggest, v->value);
+ } else if (!strcasecmp(v->name, "parkinglot")) {
+ ast_string_field_set(peer, parkinglot, v->value);
++ } else if (!strcasecmp(v->name, "rtp_engine")) {
++ ast_string_field_set(peer, engine, v->value);
+ } else if (!strcasecmp(v->name, "mailbox")) {
+ add_peer_mailboxes(peer, v->value);
+ } else if (!strcasecmp(v->name, "hasvoicemail")) {
+@@ -22697,6 +23389,8 @@
+ int error = ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, FALSE);
+ if (error)
+ ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value);
++ } else if (!strcasecmp(v->name, "preferred_codec_only")) {
++ ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_PREFERRED_CODEC);
+ } else if (!strcasecmp(v->name, "registertrying")) {
+ ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_REGISTERTRYING);
+ } else if (!strcasecmp(v->name, "autoframing")) {
+@@ -23118,6 +23812,7 @@
+ ast_set_flag(&global_flags[0], SIP_DTMF_RFC2833); /*!< Default DTMF setting: RFC2833 */
+ ast_set_flag(&global_flags[0], SIP_NAT_RFC3581); /*!< NAT support if requested by device with rport */
+ ast_set_flag(&global_flags[0], SIP_CAN_REINVITE); /*!< Allow re-invites */
++ ast_copy_string(default_engine, DEFAULT_ENGINE, sizeof(default_engine));
+
+ /* Debugging settings, always default to off */
+ dumphistory = FALSE;
+@@ -23432,6 +24127,8 @@
+ int error = ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, FALSE);
+ if (error)
+ ast_log(LOG_WARNING, "Codec configuration errors found in line %d : %s = %s\n", v->lineno, v->name, v->value);
++ } else if (!strcasecmp(v->name, "preferred_codec_only")) {
++ ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_PREFERRED_CODEC);
+ } else if (!strcasecmp(v->name, "autoframing")) {
+ global_autoframing = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "allowexternaldomains")) {
+@@ -23856,156 +24553,176 @@
+ return 0;
+ }
+
+-/*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
+-static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+- struct sip_pvt *p = NULL;
+- enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
++ struct sip_pvt *p = NULL;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
+
+- if (!(p = chan->tech_pvt))
+- return AST_RTP_GET_FAILED;
+-
+- sip_pvt_lock(p);
+- if (!(p->rtp)) {
+- sip_pvt_unlock(p);
+- return AST_RTP_GET_FAILED;
++ if (!(p = chan->tech_pvt)) {
++ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+
+- *rtp = p->rtp;
++ sip_pvt_lock(p);
++ if (!(p->rtp)) {
++ sip_pvt_unlock(p);
++ return AST_RTP_GLUE_RESULT_FORBID;
++ }
+
+- if (ast_rtp_getnat(*rtp) && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT))
+- res = AST_RTP_TRY_PARTIAL;
+- else if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
+- res = AST_RTP_TRY_NATIVE;
+- else if (ast_test_flag(&global_jbconf, AST_JB_FORCED))
+- res = AST_RTP_GET_FAILED;
++ ao2_ref(p->rtp, +1);
++ *instance = p->rtp;
+
+- sip_pvt_unlock(p);
++ if (!ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT)) {
++ res = AST_RTP_GLUE_RESULT_LOCAL;
++ } else if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE)) {
++ res = AST_RTP_GLUE_RESULT_REMOTE;
++ } else if (ast_test_flag(&global_jbconf, AST_JB_FORCED)) {
++ res = AST_RTP_GLUE_RESULT_FORBID;
++ }
+
+- return res;
++ sip_pvt_unlock(p);
++
++ return res;
+ }
+
+-/*! \brief Returns null if we can't reinvite video (part of RTP interface) */
+-static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+ struct sip_pvt *p = NULL;
+- enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+-
+- if (!(p = chan->tech_pvt))
+- return AST_RTP_GET_FAILED;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
++ if (!(p = chan->tech_pvt)) {
++ return AST_RTP_GLUE_RESULT_FORBID;
++ }
++
+ sip_pvt_lock(p);
+ if (!(p->vrtp)) {
+ sip_pvt_unlock(p);
+- return AST_RTP_GET_FAILED;
++ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+
+- *rtp = p->vrtp;
++ ao2_ref(p->vrtp, +1);
++ *instance = p->vrtp;
+
+- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
+- res = AST_RTP_TRY_NATIVE;
++ if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE)) {
++ res = AST_RTP_GLUE_RESULT_REMOTE;
++ }
+
+ sip_pvt_unlock(p);
+
+ return res;
+ }
+
+-/*! \brief Returns null if we can't reinvite text (part of RTP interface) */
+-static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+- struct sip_pvt *p = NULL;
+- enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+-
+- if (!(p = chan->tech_pvt))
+- return AST_RTP_GET_FAILED;
++ struct sip_pvt *p = NULL;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
+- sip_pvt_lock(p);
+- if (!(p->trtp)) {
+- sip_pvt_unlock(p);
+- return AST_RTP_GET_FAILED;
+- }
++ if (!(p = chan->tech_pvt)) {
++ return AST_RTP_GLUE_RESULT_FORBID;
++ }
+
+- *rtp = p->trtp;
++ sip_pvt_lock(p);
++ if (!(p->trtp)) {
++ sip_pvt_unlock(p);
++ return AST_RTP_GLUE_RESULT_FORBID;
++ }
+
+- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
+- res = AST_RTP_TRY_NATIVE;
++ ao2_ref(p->trtp, +1);
++ *instance = p->trtp;
+
+- sip_pvt_unlock(p);
++ if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE)) {
++ res = AST_RTP_GLUE_RESULT_REMOTE;
++ }
+
+- return res;
++ sip_pvt_unlock(p);
++
++ return res;
+ }
+
+-/*! \brief Set the RTP peer for this call */
+-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
++static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, int codecs, int nat_active)
+ {
+- struct sip_pvt *p;
+- int changed = 0;
++ struct sip_pvt *p;
++ int changed = 0;
+
+- p = chan->tech_pvt;
+- if (!p)
+- return -1;
++ p = chan->tech_pvt;
++ if (!p)
++ return -1;
+
+ /* Disable early RTP bridge */
+ if (chan->_state != AST_STATE_UP && !sip_cfg.directrtpsetup) /* We are in early state */
+ return 0;
+
+- sip_pvt_lock(p);
+- if (p->alreadygone) {
+- /* If we're destroyed, don't bother */
+- sip_pvt_unlock(p);
+- return 0;
+- }
++ sip_pvt_lock(p);
++ if (p->alreadygone) {
++ /* If we're destroyed, don't bother */
++ sip_pvt_unlock(p);
++ return 0;
++ }
+
+- /* if this peer cannot handle reinvites of the media stream to devices
+- that are known to be behind a NAT, then stop the process now
++ /* if this peer cannot handle reinvites of the media stream to devices
++ that are known to be behind a NAT, then stop the process now
+ */
+- if (nat_active && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT)) {
+- sip_pvt_unlock(p);
+- return 0;
+- }
++ if (nat_active && !ast_test_flag(&p->flags[0], SIP_CAN_REINVITE_NAT)) {
++ sip_pvt_unlock(p);
++ return 0;
++ }
+
+- if (rtp) {
+- changed |= ast_rtp_get_peer(rtp, &p->redirip);
+- } else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) {
+- memset(&p->redirip, 0, sizeof(p->redirip));
+- changed = 1;
+- }
+- if (vrtp) {
+- changed |= ast_rtp_get_peer(vrtp, &p->vredirip);
+- } else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) {
+- memset(&p->vredirip, 0, sizeof(p->vredirip));
+- changed = 1;
+- }
+- if (trtp) {
+- changed |= ast_rtp_get_peer(trtp, &p->tredirip);
+- } else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) {
+- memset(&p->tredirip, 0, sizeof(p->tredirip));
+- changed = 1;
+- }
+- if (codecs && (p->redircodecs != codecs)) {
+- p->redircodecs = codecs;
+- changed = 1;
+- }
+- if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER) && !ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
+- if (chan->_state != AST_STATE_UP) { /* We are in early state */
+- if (p->do_history)
+- append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
+- ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip.sin_addr));
+- } else if (!p->pendinginvite) { /* We are up, and have no outstanding invite */
+- ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip.sin_addr));
+- transmit_reinvite_with_sdp(p, FALSE, FALSE);
+- } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+- ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(rtp ? p->redirip.sin_addr : p->ourip.sin_addr));
+- /* We have a pending Invite. Send re-invite when we're done with the invite */
+- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+- }
+- }
+- /* Reset lastrtprx timer */
+- p->lastrtprx = p->lastrtptx = time(NULL);
+- sip_pvt_unlock(p);
+- return 0;
++ if (instance) {
++ changed |= ast_rtp_instance_get_remote_address(instance, &p->redirip);
++ } else if (p->redirip.sin_addr.s_addr || ntohs(p->redirip.sin_port) != 0) {
++ memset(&p->redirip, 0, sizeof(p->redirip));
++ changed = 1;
++ }
++ if (vinstance) {
++ changed |= ast_rtp_instance_get_remote_address(vinstance, &p->vredirip);
++ } else if (p->vredirip.sin_addr.s_addr || ntohs(p->vredirip.sin_port) != 0) {
++ memset(&p->vredirip, 0, sizeof(p->vredirip));
++ changed = 1;
++ }
++ if (tinstance) {
++ changed |= ast_rtp_instance_get_remote_address(tinstance, &p->tredirip);
++ } else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) {
++ memset(&p->tredirip, 0, sizeof(p->tredirip));
++ changed = 1;
++ }
++ if (codecs && (p->redircodecs != codecs)) {
++ p->redircodecs = codecs;
++ changed = 1;
++ }
++ if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER) && !ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
++ if (chan->_state != AST_STATE_UP) { /* We are in early state */
++ if (p->do_history)
++ append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
++ ast_debug(1, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
++ } else if (!p->pendinginvite) { /* We are up, and have no outstanding invite */
++ ast_debug(3, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
++ transmit_reinvite_with_sdp(p, FALSE, FALSE);
++ } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
++ ast_debug(3, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(instance ? p->redirip.sin_addr : p->ourip.sin_addr));
++ /* We have a pending Invite. Send re-invite when we're done with the invite */
++ ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
++ }
++ }
++ /* Reset lastrtprx timer */
++ p->lastrtprx = p->lastrtptx = time(NULL);
++ sip_pvt_unlock(p);
++ return 0;
+ }
+
++static int sip_get_codec(struct ast_channel *chan)
++{
++ struct sip_pvt *p = chan->tech_pvt;
++ return p->peercapability ? p->peercapability : p->capability;
++}
++
++static struct ast_rtp_glue sip_rtp_glue = {
++ .type = "SIP",
++ .get_rtp_info = sip_get_rtp_peer,
++ .get_vrtp_info = sip_get_vrtp_peer,
++ .get_trtp_info = sip_get_trtp_peer,
++ .update_peer = sip_set_rtp_peer,
++ .get_codec = sip_get_codec,
++};
++
+ static char *app_dtmfmode = "SIPDtmfMode";
+ static char *app_sipaddheader = "SIPAddHeader";
+ static char *app_sipremoveheader = "SIPRemoveHeader";
+@@ -24051,7 +24768,7 @@
+ } else
+ ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n", mode);
+ if (p->rtp)
+- ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
++ ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
+ if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
+ if (!p->vad) {
+ p->vad = ast_dsp_new();
+@@ -24195,17 +24912,15 @@
+
+ sip_scheddestroy(p, SIP_TRANS_TIMEOUT); /* Make sure we stop send this reply. */
+ sip_alreadygone(p);
++
++ if (p->owner) {
++ enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
+ /* hangup here */
+ return 0;
+ }
+
+-/*! \brief Return SIP UA's codec (part of the RTP interface) */
+-static int sip_get_codec(struct ast_channel *chan)
+-{
+- struct sip_pvt *p = chan->tech_pvt;
+- return p->jointcapability ? p->jointcapability : p->capability;
+-}
+-
+ /*! \brief Send a poke to all known peers */
+ static void sip_poke_all_peers(void)
+ {
+@@ -24413,12 +25128,12 @@
+ /* Register all CLI functions for SIP */
+ ast_cli_register_multiple(cli_sip, ARRAY_LEN(cli_sip));
+
+- /* Tell the RTP subdriver that we're here */
+- ast_rtp_proto_register(&sip_rtp);
+-
+ /* Tell the UDPTL subdriver that we're here */
+ ast_udptl_proto_register(&sip_udptl);
+
++ /* Tell the RTP engine about our RTP glue */
++ ast_rtp_glue_register(&sip_rtp_glue);
++
+ /* Register dialplan applications */
+ ast_register_application_xml(app_dtmfmode, sip_dtmfmode);
+ ast_register_application_xml(app_sipaddheader, sip_addheader);
+@@ -24489,12 +25204,12 @@
+ /* Unregister CLI commands */
+ ast_cli_unregister_multiple(cli_sip, ARRAY_LEN(cli_sip));
+
+- /* Disconnect from the RTP subsystem */
+- ast_rtp_proto_unregister(&sip_rtp);
+-
+ /* Disconnect from UDPTL */
+ ast_udptl_proto_unregister(&sip_udptl);
+
++ /* Disconnect from RTP engine */
++ ast_rtp_glue_unregister(&sip_rtp_glue);
++
+ /* Unregister AMI actions */
+ ast_manager_unregister("SIPpeers");
+ ast_manager_unregister("SIPshowpeer");
+Index: channels/chan_agent.c
+===================================================================
+--- a/channels/chan_agent.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_agent.c (.../trunk) (revision 186562)
+@@ -52,7 +52,6 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/file.h"
+@@ -758,8 +757,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_channel_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);
+Index: channels/Makefile
+===================================================================
+--- a/channels/Makefile (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/Makefile (.../trunk) (revision 186562)
+@@ -57,25 +57,14 @@
+ LIBS+= -lres_monitor.so -lres_features.so
+ endif
+
+-clean::
+- $(MAKE) -C misdn clean
+-
+ ifneq ($(wildcard h323/Makefile.ast),)
+- include h323/Makefile.ast
++include h323/Makefile.ast
++endif
+ H323LDFLAGS+=-Wl,--version-script=h323/noexport.map
++
+ clean::
++ $(MAKE) -C misdn clean
+ if [ -f h323/Makefile ]; then $(MAKE) -C h323 clean; fi
+-else
+-h323/libchanh323.a h323/Makefile.ast:
+- $(CMD_PREFIX) $(MAKE) -C h323
+- $(CMD_PREFIX) rm -f ../main/asterisk
+- $(CMD_PREFIX) echo "***************************************************************"
+- $(CMD_PREFIX) echo
+- $(CMD_PREFIX) echo "********** Re-run 'make' to pick up H.323 parameters **********"
+- $(CMD_PREFIX) echo
+- $(CMD_PREFIX) echo "***************************************************************"
+- $(CMD_PREFIX) exit 1
+-endif
+
+ dist-clean::
+ rm -f h323/Makefile
+@@ -107,4 +96,10 @@
+ chan_usbradio.so: LIBS+=-lusb -lasound
+ chan_usbradio.so: ASTCFLAGS+=-DNDEBUG
+
++h323/Makefile.ast:
++ $(CMD_PREFIX) $(MAKE) -C h323 Makefile.ast
+
++h323/libchanh323.a:
++ $(CMD_PREFIX) $(MAKE) -C h323 libchanh323.a
++
++
+Index: channels/chan_iax2.c
+===================================================================
+--- a/channels/chan_iax2.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_iax2.c (.../trunk) (revision 186562)
+@@ -88,6 +88,7 @@
+ #include "asterisk/event.h"
+ #include "asterisk/astobj2.h"
+ #include "asterisk/timing.h"
++#include "asterisk/taskprocessor.h"
+
+ #include "iax2.h"
+ #include "iax2-parser.h"
+@@ -257,7 +258,7 @@
+
+ static int srvlookup = 0;
+
+-static int timingfd = -1; /* Timing file descriptor */
++static struct ast_timer *timer; /* Timer for trunking */
+
+ static struct ast_netsock_list *netsock;
+ static struct ast_netsock_list *outsock; /*!< used if sourceaddress specified and bindaddr == INADDR_ANY */
+@@ -270,6 +271,9 @@
+ /* T1, maybe ISDN */
+ #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
+ ~AST_FORMAT_SLINEAR & \
++ ~AST_FORMAT_SLINEAR16 & \
++ ~AST_FORMAT_SIREN7 & \
++ ~AST_FORMAT_SIREN14 & \
+ ~AST_FORMAT_ULAW & \
+ ~AST_FORMAT_ALAW & \
+ ~AST_FORMAT_G722)
+@@ -376,7 +380,9 @@
+ them before sending voice or anything else*/
+ IAX_ALLOWFWDOWNLOAD = (1 << 26), /*!< Allow the FWDOWNL command? */
+ IAX_IMMEDIATE = (1 << 27), /*!< Allow immediate off-hook to extension s */
+- IAX_FORCE_ENCRYPT = (1 << 28), /*!< Forces call encryption, if encryption not possible hangup */
++ 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;
+@@ -755,9 +761,13 @@
+ * \note The contents of this list do not need to be explicitly destroyed
+ * on module unload. This is because all active calls are destroyed, and
+ * all frames in this queue will get destroyed as a part of that process.
++ *
++ * \note Contents protected by the iaxsl[] locks
+ */
+-static AST_LIST_HEAD_STATIC(frame_queue, iax_frame);
++static AST_LIST_HEAD_NOLOCK(, iax_frame) frame_queue[IAX_MAX_CALLS];
+
++static struct ast_taskprocessor *transmit_processor;
++
+ /*!
+ * This module will get much higher performance when doing a lot of
+ * user and peer lookups if the number of buckets is increased from 1.
+@@ -1585,21 +1595,19 @@
+ struct iax_frame *cur = NULL;
+
+ ast_mutex_lock(&iaxsl[pvt->callno]);
++
+ iax2_destroy_helper(pvt);
+- ast_mutex_unlock(&iaxsl[pvt->callno]);
+
+ /* Already gone */
+- ast_set_flag(pvt, IAX_ALREADYGONE);
++ ast_set_flag(pvt, IAX_ALREADYGONE);
+
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_TRAVERSE(&frame_queue, cur, list) {
++ AST_LIST_TRAVERSE(&frame_queue[pvt->callno], cur, list) {
+ /* Cancel any pending transmissions */
+- if (cur->callno == pvt->callno) {
+- cur->retries = -1;
+- }
++ cur->retries = -1;
+ }
+- AST_LIST_UNLOCK(&frame_queue);
+
++ ast_mutex_unlock(&iaxsl[pvt->callno]);
++
+ if (pvt->reg) {
+ pvt->reg->callno = 0;
+ }
+@@ -1970,7 +1978,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_FORCE_ENCRYPT);
++ 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);
+@@ -2620,17 +2628,16 @@
+ f->retries = -1;
+ freeme = 1;
+ }
+- if (callno)
+- ast_mutex_unlock(&iaxsl[callno]);
+- /* Do not try again */
++
+ if (freeme) {
+ /* Don't attempt delivery, just remove it from the queue */
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_REMOVE(&frame_queue, f, list);
+- AST_LIST_UNLOCK(&frame_queue);
++ AST_LIST_REMOVE(&frame_queue[callno], f, list);
++ ast_mutex_unlock(&iaxsl[callno]);
+ f->retrans = -1;
+ /* Free the IAX frame */
+ iax2_frame_free(f);
++ } else if (callno) {
++ ast_mutex_unlock(&iaxsl[callno]);
+ }
+ }
+
+@@ -2920,7 +2927,7 @@
+ static char *handle_cli_iax2_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ struct iax_frame *cur;
+- int cnt = 0, dead = 0, final = 0;
++ int cnt = 0, dead = 0, final = 0, i = 0;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -2936,15 +2943,17 @@
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_TRAVERSE(&frame_queue, cur, list) {
+- if (cur->retries < 0)
+- dead++;
+- if (cur->final)
+- final++;
+- cnt++;
++ for (i = 0; i < ARRAY_LEN(frame_queue); i++) {
++ ast_mutex_lock(&iaxsl[i]);
++ AST_LIST_TRAVERSE(&frame_queue[i], cur, list) {
++ if (cur->retries < 0)
++ dead++;
++ if (cur->final)
++ final++;
++ cnt++;
++ }
++ ast_mutex_unlock(&iaxsl[i]);
+ }
+- AST_LIST_UNLOCK(&frame_queue);
+
+ ast_cli(a->fd, " IAX Statistics\n");
+ ast_cli(a->fd, "---------------------\n");
+@@ -3301,23 +3310,39 @@
+ return 0;
+ }
+
+-static int iax2_transmit(struct iax_frame *fr)
++static int transmit_frame(void *data)
+ {
+- /* Lock the queue and place this packet at the end */
+- /* By setting this to 0, the network thread will send it for us, and
+- queue retransmission if necessary */
+- fr->sentyet = 0;
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_INSERT_TAIL(&frame_queue, fr, list);
+- AST_LIST_UNLOCK(&frame_queue);
+- /* Wake up the network and scheduler thread */
+- if (netthreadid != AST_PTHREADT_NULL)
+- pthread_kill(netthreadid, SIGURG);
+- ast_sched_thread_poke(sched);
++ struct iax_frame *fr = data;
++
++ ast_mutex_lock(&iaxsl[fr->callno]);
++
++ fr->sentyet = 1;
++
++ if (iaxs[fr->callno]) {
++ send_packet(fr);
++ }
++
++ if (fr->retries < 0) {
++ ast_mutex_unlock(&iaxsl[fr->callno]);
++ /* No retransmit requested */
++ iax_frame_free(fr);
++ } else {
++ /* We need reliable delivery. Schedule a retransmission */
++ AST_LIST_INSERT_TAIL(&frame_queue[fr->callno], fr, list);
++ ast_mutex_unlock(&iaxsl[fr->callno]);
++ fr->retries++;
++ fr->retrans = iax2_sched_add(sched, fr->retrytime, attempt_transmit, fr);
++ }
++
+ return 0;
+ }
+
++static int iax2_transmit(struct iax_frame *fr)
++{
++ fr->sentyet = 0;
+
++ return ast_taskprocessor_push(transmit_processor, transmit_frame, fr);
++}
+
+ static int iax2_digit_begin(struct ast_channel *c, char digit)
+ {
+@@ -3578,6 +3603,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];
+@@ -3621,7 +3648,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_FORCE_ENCRYPT);
++ 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;
+@@ -3639,6 +3666,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)) {
+@@ -3847,8 +3876,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));
+@@ -3865,21 +3894,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);
+@@ -4375,6 +4404,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);
+@@ -4390,6 +4424,7 @@
+ unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
+ struct iax_ie_data ied = { "", };
+ char tmp[256], *context;
++ enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
+ ast_copy_string(tmp, dest, sizeof(tmp));
+ context = strchr(tmp, '@');
+ if (context) {
+@@ -4400,6 +4435,7 @@
+ if (context)
+ iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, context);
+ ast_debug(1, "Transferring '%s' to '%s'\n", c->name, dest);
++ ast_queue_control_data(c, AST_CONTROL_TRANSFER, &message, sizeof(message));
+ return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
+ }
+
+@@ -6356,7 +6392,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;
+@@ -6682,15 +6718,20 @@
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+
+ return_unref:
+- ast_string_field_set(iaxs[callno], peer, peer);
+- /* Choose lowest expiry number */
+- if (expire && (expire < iaxs[callno]->expiry))
+- iaxs[callno]->expiry = expire;
++ if (iaxs[callno]) {
++ ast_string_field_set(iaxs[callno], peer, peer);
+
++ /* Choose lowest expiry number */
++ if (expire && (expire < iaxs[callno]->expiry)) {
++ iaxs[callno]->expiry = expire;
++ }
++ }
++
+ res = 0;
+
+- if (p)
++ if (p) {
+ peer_unref(p);
++ }
+
+ return res;
+ }
+@@ -7007,16 +7048,13 @@
+ pvt->lastsent = 0;
+ pvt->nextpred = 0;
+ pvt->pingtime = DEFAULT_RETRY_TIME;
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_TRAVERSE(&frame_queue, cur, list) {
++ AST_LIST_TRAVERSE(&frame_queue[callno], cur, list) {
+ /* We must cancel any packets that would have been transmitted
+ because now we're talking to someone new. It's okay, they
+ were transmitted to someone that didn't care anyway. */
+- if (callno == cur->callno)
+- cur->retries = -1;
++ cur->retries = -1;
+ }
+- AST_LIST_UNLOCK(&frame_queue);
+- return 0;
++ return 0;
+ }
+
+ /*! \brief Acknowledgment received for OUR registration */
+@@ -7386,8 +7424,6 @@
+ event = ast_event_get_cached(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_EXISTS,
+- AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+ AST_EVENT_IE_END);
+ if (event) {
+ new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
+@@ -7621,16 +7657,13 @@
+ {
+ struct iax_frame *f;
+
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_TRAVERSE(&frame_queue, f, list) {
++ AST_LIST_TRAVERSE(&frame_queue[callno], f, list) {
+ /* Send a copy immediately */
+- if ((f->callno == callno) && iaxs[f->callno] &&
+- ((unsigned char ) (f->oseqno - last) < 128) &&
+- (f->retries >= 0)) {
++ if (((unsigned char) (f->oseqno - last) < 128) &&
++ (f->retries >= 0)) {
+ send_packet(f);
+ }
+ }
+- AST_LIST_UNLOCK(&frame_queue);
+ }
+
+ static void __iax2_poke_peer_s(const void *data)
+@@ -7711,8 +7744,8 @@
+ if (iaxtrunkdebug)
+ ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
+
+- if (timingfd > -1) {
+- ast_timer_ack(timingfd, 1);
++ if (timer) {
++ ast_timer_ack(timer, 1);
+ }
+
+ /* For each peer that supports trunking... */
+@@ -8647,17 +8680,15 @@
+ if (iaxdebug)
+ ast_debug(1, "Cancelling transmission of packet %d\n", x);
+ call_to_destroy = 0;
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_TRAVERSE(&frame_queue, cur, list) {
++ AST_LIST_TRAVERSE(&frame_queue[fr->callno], cur, list) {
+ /* If it's our call, and our timestamp, mark -1 retries */
+- if ((fr->callno == cur->callno) && (x == cur->oseqno)) {
++ if (x == cur->oseqno) {
+ cur->retries = -1;
+ /* Destroy call if this is the end */
+ if (cur->final)
+ call_to_destroy = fr->callno;
+ }
+ }
+- AST_LIST_UNLOCK(&frame_queue);
+ if (call_to_destroy) {
+ if (iaxdebug)
+ ast_debug(1, "Really destroying %d, having been acked on final message\n", call_to_destroy);
+@@ -8899,13 +8930,12 @@
+ case IAX_COMMAND_TXACC:
+ 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) {
++ AST_LIST_TRAVERSE(&frame_queue[fr->callno], cur, list) {
+ /* Cancel any outstanding txcnt's */
+- if ((fr->callno == cur->callno) && (cur->transfer))
++ if (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);
+ send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
+@@ -9804,13 +9834,12 @@
+ break;
+ case IAX_COMMAND_TXMEDIA:
+ if (iaxs[fr->callno]->transferring == TRANSFER_READY) {
+- AST_LIST_LOCK(&frame_queue);
+- AST_LIST_TRAVERSE(&frame_queue, cur, list) {
++ AST_LIST_TRAVERSE(&frame_queue[fr->callno], cur, list) {
+ /* Cancel any outstanding frames and start anew */
+- if ((fr->callno == cur->callno) && (cur->transfer))
++ if (cur->transfer) {
+ cur->retries = -1;
++ }
+ }
+- AST_LIST_UNLOCK(&frame_queue);
+ /* Start sending our media to the transfer address, but otherwise leave the call as-is */
+ iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS;
+ }
+@@ -9936,6 +9965,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_connected_line_parse_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;
+@@ -10431,7 +10485,7 @@
+ memset(&cai, 0, sizeof(cai));
+ cai.capability = iax2_capability;
+
+- ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
++ 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)) {
+@@ -10450,7 +10504,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);
++ 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)
+@@ -10489,66 +10543,18 @@
+
+ static void *network_thread(void *ignore)
+ {
+- /* Our job is simple: Send queued messages, retrying if necessary. Read frames
+- from the network, and queue them for delivery to the channels */
+- int res, count, wakeup;
+- struct iax_frame *f;
++ if (timer) {
++ ast_io_add(io, ast_timer_fd(timer), timing_read, AST_IO_IN | AST_IO_PRI, NULL);
++ }
+
+- if (timingfd > -1)
+- ast_io_add(io, timingfd, timing_read, AST_IO_IN | AST_IO_PRI, NULL);
+-
+- for(;;) {
++ for (;;) {
+ pthread_testcancel();
++ /* Wake up once a second just in case SIGURG was sent while
++ * we weren't in poll(), to make sure we don't hang when trying
++ * to unload. */
++ ast_io_wait(io, 1000);
++ }
+
+- /* Go through the queue, sending messages which have not yet been
+- sent, and scheduling retransmissions if appropriate */
+- AST_LIST_LOCK(&frame_queue);
+- count = 0;
+- wakeup = -1;
+- AST_LIST_TRAVERSE_SAFE_BEGIN(&frame_queue, f, list) {
+- if (f->sentyet)
+- continue;
+-
+- /* Try to lock the pvt, if we can't... don't fret - defer it till later */
+- if (ast_mutex_trylock(&iaxsl[f->callno])) {
+- wakeup = 1;
+- continue;
+- }
+-
+- f->sentyet = 1;
+-
+- if (iaxs[f->callno]) {
+- send_packet(f);
+- count++;
+- }
+-
+- ast_mutex_unlock(&iaxsl[f->callno]);
+-
+- if (f->retries < 0) {
+- /* This is not supposed to be retransmitted */
+- AST_LIST_REMOVE_CURRENT(list);
+- /* Free the iax frame */
+- iax_frame_free(f);
+- } else {
+- /* We need reliable delivery. Schedule a retransmission */
+- f->retries++;
+- f->retrans = iax2_sched_add(sched, f->retrytime, attempt_transmit, f);
+- }
+- }
+- AST_LIST_TRAVERSE_SAFE_END;
+- AST_LIST_UNLOCK(&frame_queue);
+-
+- pthread_testcancel();
+- if (count >= 20)
+- ast_debug(1, "chan_iax2: Sent %d queued outbound frames all at once\n", count);
+-
+- /* Now do the IO, and run scheduled tasks */
+- res = ast_io_wait(io, wakeup);
+- if (res >= 0) {
+- if (res >= 20)
+- ast_debug(1, "chan_iax2: ast_io_wait ran %d I/Os all at once\n", res);
+- }
+- }
+ return NULL;
+ }
+
+@@ -10761,7 +10767,7 @@
+
+ if (peer) {
+ if (firstpass) {
+- ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
++ 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,"");
+@@ -10803,7 +10809,7 @@
+ ast_string_field_set(peer, dbsecret, v->value);
+ } else if (!strcasecmp(v->name, "trunk")) {
+ ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK);
+- if (ast_test_flag(peer, IAX_TRUNK) && (timingfd < 0)) {
++ if (ast_test_flag(peer, IAX_TRUNK) && !timer) {
+ ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without a timing interface\n", peer->name);
+ ast_clear_flag(peer, IAX_TRUNK);
+ }
+@@ -10934,6 +10940,18 @@
+ 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 | 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 | IAX_RECVCONNECTEDLINE);
++ }
+ }/* else if (strcasecmp(v->name,"type")) */
+ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
+ v = v->next;
+@@ -11032,7 +11050,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_FORCE_ENCRYPT);
++ 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, "");
+@@ -11070,7 +11088,7 @@
+ ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
+ } 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)) {
++ if (ast_test_flag(user, IAX_TRUNK) && !timer) {
+ ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without a timing interface\n", user->name);
+ ast_clear_flag(user, IAX_TRUNK);
+ }
+@@ -11177,6 +11195,18 @@
+ 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 | 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 | IAX_RECVCONNECTEDLINE);
++ }
+ }/* else if (strcasecmp(v->name,"type")) */
+ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
+ v = v->next;
+@@ -11292,10 +11322,8 @@
+ trunkmaxsize = MAX_TRUNKDATA;
+ amaflags = 0;
+ delayreject = 0;
+- ast_clear_flag((&globalflags), IAX_NOTRANSFER);
+- ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA);
+- ast_clear_flag((&globalflags), IAX_USEJITTERBUF);
+- ast_clear_flag((&globalflags), IAX_FORCEJITTERBUF);
++ ast_clear_flag((&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF |
++ IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ delete_users();
+ }
+
+@@ -11599,6 +11627,18 @@
+ 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 | 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 | IAX_RECVCONNECTEDLINE);
++ }
+ } /*else if (strcasecmp(v->name,"type")) */
+ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
+ v = v->next;
+@@ -12420,19 +12460,14 @@
+ struct ast_context *con;
+ int x;
+
+- /* Make sure threads do not hold shared resources when they are canceled */
+-
+- /* Grab the sched lock resource to keep it away from threads about to die */
+- /* Cancel the network thread, close the net socket */
+ if (netthreadid != AST_PTHREADT_NULL) {
+- AST_LIST_LOCK(&frame_queue);
+ pthread_cancel(netthreadid);
+- AST_LIST_UNLOCK(&frame_queue);
++ pthread_kill(netthreadid, SIGURG);
+ pthread_join(netthreadid, 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)))
+@@ -12480,9 +12515,10 @@
+ ao2_ref(users, -1);
+ ao2_ref(iax_peercallno_pvts, -1);
+ ao2_ref(iax_transfercallno_pvts, -1);
+- if (timingfd > -1) {
+- ast_timer_close(timingfd);
++ if (timer) {
++ ast_timer_close(timer);
+ }
++ transmit_processor = ast_taskprocessor_unreference(transmit_processor);
+
+ con = ast_context_find(regcontext);
+ if (con)
+@@ -12551,19 +12587,23 @@
+ struct iax2_registry *reg = NULL;
+
+ peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb);
+- if (!peers)
++ if (!peers) {
+ return AST_MODULE_LOAD_FAILURE;
++ }
++
+ users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_cb, user_cmp_cb);
+ if (!users) {
+ ao2_ref(peers, -1);
+ return AST_MODULE_LOAD_FAILURE;
+ }
++
+ iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb);
+ if (!iax_peercallno_pvts) {
+ ao2_ref(peers, -1);
+ 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);
+@@ -12571,6 +12611,16 @@
+ ao2_ref(iax_peercallno_pvts, -1);
+ return AST_MODULE_LOAD_FAILURE;
+ }
++
++ transmit_processor = ast_taskprocessor_get("iax2_transmit", TPS_REF_DEFAULT);
++ if (!transmit_processor) {
++ ao2_ref(peers, -1);
++ ao2_ref(users, -1);
++ ao2_ref(iax_peercallno_pvts, -1);
++ ao2_ref(iax_transfercallno_pvts, -1);
++ return AST_MODULE_LOAD_FAILURE;
++ }
++
+ ast_custom_function_register(&iaxpeer_function);
+ ast_custom_function_register(&iaxvar_function);
+
+@@ -12621,9 +12671,8 @@
+ 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) {
+- ast_timer_set_rate(timingfd, trunkfreq);
++ if ((timer = ast_timer_open())) {
++ ast_timer_set_rate(timer, trunkfreq);
+ }
+
+ if (set_config(config, 0) == -1) {
+Index: channels/chan_misdn.c
+===================================================================
+--- a/channels/chan_misdn.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_misdn.c (.../trunk) (revision 186562)
+@@ -1,6 +1,6 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+- *
++ *
+ * Copyright (C) 2004 - 2006, Christian Richter
+ *
+ * Christian Richter <crich@beronet.com>
+@@ -47,6 +47,7 @@
+ #include <signal.h>
+ #include <sys/file.h>
+ #include <semaphore.h>
++#include <ctype.h>
+
+ #include "asterisk/channel.h"
+ #include "asterisk/config.h"
+@@ -88,8 +89,6 @@
+ ast_mutex_t mutexjb;
+ };
+
+-
+-
+ /*! \brief allocates the jb-structure and initialize the elements */
+ struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
+
+@@ -135,7 +134,6 @@
+ 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
+@@ -143,13 +141,13 @@
+
+ struct hold_info {
+ /*!
+- * \brief Logical port the channel call record is HOLDED on
+- * because the B channel is no longer associated.
++ * \brief Logical port the channel call record is HOLDED on
++ * because the B channel is no longer associated.
+ */
+ int port;
+
+ /*!
+- * \brief Original B channel number the HOLDED call was using.
++ * \brief Original B channel number the HOLDED call was using.
+ * \note Used only for debug display messages.
+ */
+ int channel;
+@@ -159,18 +157,18 @@
+ * \brief Channel call record structure
+ */
+ struct chan_list {
+- /*!
++ /*!
+ * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
+ */
+ char allowed_bearers[BUFFERSIZE + 1];
+-
+- /*!
++
++ /*!
+ * \brief State of the channel
+ */
+ enum misdn_chan_state state;
+
+- /*!
+- * \brief TRUE if a hangup needs to be queued
++ /*!
++ * \brief TRUE if a hangup needs to be queued
+ * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
+ */
+ int need_queue_hangup;
+@@ -184,30 +182,30 @@
+ * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
+ */
+ int need_busy;
+-
++
+ /*!
+ * \brief Who originally created this channel. ORG_AST or ORG_MISDN
+ */
+ int originator;
+
+- /*!
++ /*!
+ * \brief TRUE of we are not to respond immediately to a SETUP message. Check the dialplan first.
+ * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
+ */
+ int noautorespond_on_setup;
+-
++
+ int norxtone; /*!< Boolean assigned values but the value is not used. */
+
+ /*!
+ * \brief TRUE if we are not to generate tones (Playtones)
+ */
+- int notxtone;
++ int notxtone;
+
+ /*!
+ * \brief TRUE if echo canceller is enabled. Value is toggled.
+ */
+ int toggle_ec;
+-
++
+ /*!
+ * \brief TRUE if you want to send Tone Indications to an incoming
+ * ISDN channel on a TE Port.
+@@ -222,8 +220,8 @@
+ int ignore_dtmf;
+
+ /*!
+- * \brief Pipe file descriptor handles array.
+- * Read from pipe[0], write to pipe[1]
++ * \brief Pipe file descriptor handles array.
++ * Read from pipe[0], write to pipe[1]
+ */
+ int pipe[2];
+
+@@ -282,31 +280,31 @@
+ /*!
+ * \brief Allocated jitterbuffer controller
+ * \note misdn_jb_init() creates the jitterbuffer.
+- * \note Must use misdn_jb_destroy() to clean up.
++ * \note Must use misdn_jb_destroy() to clean up.
+ */
+ struct misdn_jb *jb;
+-
++
+ /*!
+ * \brief Allocated DSP controller
+ * \note ast_dsp_new() creates the DSP controller.
+- * \note Must use ast_dsp_free() to clean up.
++ * \note Must use ast_dsp_free() to clean up.
+ */
+ struct ast_dsp *dsp;
+
+ /*!
+ * \brief Allocated audio frame sample translator
+ * \note ast_translator_build_path() creates the translator path.
+- * \note Must use ast_translator_free_path() to clean up.
++ * \note Must use ast_translator_free_path() to clean up.
+ */
+ struct ast_trans_pvt *trans;
+-
++
+ /*!
+ * \brief Associated Asterisk channel structure.
+ */
+ struct ast_channel * ast;
+
+ //int dummy; /* Not used */
+-
++
+ /*!
+ * \brief Associated B channel structure.
+ */
+@@ -317,13 +315,13 @@
+ */
+ struct hold_info hold_info;
+
+- /*!
+- * \brief From associated B channel: Layer 3 process ID
+- * \note Used to find the HOLDED channel call record when retrieving a call.
++ /*!
++ * \brief From associated B channel: Layer 3 process ID
++ * \note Used to find the HOLDED channel call record when retrieving a call.
+ */
+ unsigned int l3id;
+
+- /*!
++ /*!
+ * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
+ * \note Used only for debug display messages.
+ */
+@@ -341,10 +339,6 @@
+ */
+ char mohinterpret[MAX_MUSICCLASS];
+
+-#if 0
+- int zero_read_cnt; /* Not used */
+-#endif
+-
+ /*!
+ * \brief Number of outgoing audio frames dropped since last debug gripe message.
+ */
+@@ -363,24 +357,24 @@
+ int nttimeout;
+
+ /*!
+- * \brief Other channel call record PID
+- * \note Value imported from Asterisk environment variable MISDN_PID
++ * \brief Other channel call record PID
++ * \note Value imported from Asterisk environment variable MISDN_PID
+ */
+ int other_pid;
+
+ /*!
+ * \brief Bridged other channel call record
+- * \note Pointer set when other_pid imported from Asterisk environment
++ * \note Pointer set when other_pid imported from Asterisk environment
+ * variable MISDN_PID by either side.
+ */
+ struct chan_list *other_ch;
+
+ /*!
+ * \brief Tone zone sound used for dialtone generation.
+- * \note Used as a boolean. Non-NULL to prod generation if enabled.
++ * \note Used as a boolean. Non-NULL to prod generation if enabled.
+ */
+ struct ast_tone_zone_sound *ts;
+-
++
+ /*!
+ * \brief Enables overlap dialing for the set amount of seconds. (0 = Disabled)
+ * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
+@@ -402,18 +396,10 @@
+ */
+ struct timeval overlap_tv;
+
+-#if 0
+- struct chan_list *peer; /* Not used */
+-#endif
+-
+ /*!
+ * \brief Next channel call record in the list.
+ */
+ struct chan_list *next;
+-#if 0
+- struct chan_list *prev; /* Not used */
+- struct chan_list *first; /* Not used */
+-#endif
+ };
+
+
+@@ -424,13 +410,14 @@
+ 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);
+
+-static struct robin_list {
++struct robin_list {
+ char *group;
+ int port;
+ int channel;
+ struct robin_list *next;
+ struct robin_list *prev;
+-} *robin = NULL;
++};
++static struct robin_list *robin = NULL;
+
+
+ static inline void free_robin_list_r(struct robin_list *r)
+@@ -450,7 +437,7 @@
+ 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;
+@@ -539,7 +526,7 @@
+
+ int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
+
+-void debug_numplan(int port, int numplan, char *type);
++void debug_numtype(int port, int numtype, char *type);
+
+ int add_out_calls(int port);
+ int add_in_calls(int port);
+@@ -558,31 +545,559 @@
+ static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
+ {
+ struct chan_list *tmp;
+-
++
+ for (tmp = cl_te; tmp; tmp = tmp->next) {
+ if (tmp->ast == ast) {
+ return tmp;
+ }
+ }
+-
++
+ return NULL;
+ }
+
+ static struct chan_list * get_chan_by_ast_name(char *name)
+ {
+ struct chan_list *tmp;
+-
++
+ for (tmp = cl_te; tmp; tmp = tmp->next) {
+ if (tmp->ast && strcmp(tmp->ast->name, name) == 0) {
+ return tmp;
+ }
+ }
+-
++
+ return NULL;
+ }
+
++/*!
++ * \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;
+
++ 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;
++ }
++
++ return str;
++}
++
++/*!
++ * \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;
++ }
++
++ return ast_number_type;
++}
++
++/*!
++ * \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;
++ }
++
++ return number_type;
++}
++
++/*!
++ * \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;
++ }
++
++ return str;
++}
++
++/*!
++ * \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;
++ }
++
++ return ast_number_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;
++ }
++
++ return number_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;
++
++ default:
++ str = "Unknown";
++ break;
++ }
++
++ return str;
++}
++
++/*!
++ * \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 1:
++ presentation = AST_PRES_RESTRICTED;
++ break;
++
++ case 2:
++ presentation = AST_PRES_UNAVAILABLE;
++ break;
++ }
++
++ return presentation;
++}
++
++/*!
++ * \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;
++ }
++
++ return presentation;
++}
++
++/*!
++ * \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:
++ str = "Unknown";
++ break;
++ }
++
++ return str;
++}
++
++/*!
++ * \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;
++ }
++
++ return screening;
++}
++
++/*!
++ * \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;
++ }
++
++ return screening;
++}
++
++/*!
++ * \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;
++ }
++ }
++ return mISDN_REDIRECTING_REASON_UNKNOWN;
++}
++
++/*!
++ * \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;
++ }
++
++ return ast;
++}
++
++
++
+ struct allowed_bearers {
+ char *name; /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
+ char *display; /*!< Bearer capability displayable name */
+@@ -591,7 +1106,7 @@
+ };
+
+ /* *INDENT-OFF* */
+-static const struct allowed_bearers allowed_bearers_array[]= {
++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 },
+@@ -610,7 +1125,7 @@
+ if (allowed_bearers_array[index].cap == cap) {
+ return allowed_bearers_array[index].display;
+ }
+- } /* end for */
++ }
+
+ return "Unknown Bearer";
+ }
+@@ -669,10 +1184,10 @@
+ }
+ }
+
+-static void print_bearer(struct misdn_bchannel *bc)
++static void print_bearer(struct misdn_bchannel *bc)
+ {
+ 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");
+@@ -683,6 +1198,95 @@
+ }
+ }
+
++/*!
++ * \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';
++}
++
++/*!
++ * \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;
++ }
++ misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
++
++ misdn_prefix_string(num_prefix, number, size);
++}
++
+ static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
+ {
+ char buf[128];
+@@ -692,7 +1296,8 @@
+ }
+
+ if (originator == ORG_AST) {
+- if (!(ast = ast_bridged_channel(ast))) {
++ ast = ast_bridged_channel(ast);
++ if (!ast) {
+ return;
+ }
+ }
+@@ -739,14 +1344,15 @@
+ default:
+ break;
+ }
+-
++
+ bc->AOCD_need_export = 0;
+ }
+
+ /*************** Helpers END *************/
+
+ static void sighandler(int sig)
+-{}
++{
++}
+
+ static void *misdn_tasks_thread_func(void *data)
+ {
+@@ -758,7 +1364,7 @@
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGUSR1);
+ sigaction(SIGUSR1, &sa, NULL);
+-
++
+ sem_post((sem_t *)data);
+
+ while (1) {
+@@ -785,7 +1391,7 @@
+ }
+
+ chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
+-
++
+ misdn_tasks = sched_context_create();
+ pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
+
+@@ -841,6 +1447,7 @@
+ static int misdn_l1_task(const void *vdata)
+ {
+ const int *data = vdata;
++
+ misdn_lib_isdn_l1watcher(*data);
+ chan_misdn_log(5, *data, "L1watcher timeout\n");
+ return 1;
+@@ -867,21 +1474,22 @@
+ tv_end.tv_sec += ch->overlap_dial;
+ tv_now = ast_tvnow();
+
+- if ((diff = ast_tvdiff_ms(tv_end, tv_now)) > 100) {
++ diff = ast_tvdiff_ms(tv_end, tv_now);
++ if (100 < diff) {
+ return diff;
+ }
+
+ /* if we are 100ms near the timeout, we are satisfied.. */
+ stop_indicate(ch);
+
+- if (ast_strlen_zero(ch->bc->dad)) {
++ if (ast_strlen_zero(ch->bc->dialed.number)) {
+ dad = "s";
+- ast_copy_string(ch->ast->exten, "s", sizeof(ch->ast->exten));
++ strcpy(ch->ast->exten, dad);
+ } else {
+- dad = ch->bc->dad;
++ dad = ch->bc->dialed.number;
+ }
+
+- if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
++ 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");
+@@ -918,8 +1526,8 @@
+ "!941+1209/100,!0/100", /* * */
+ "!941+1477/100,!0/100", /* # */
+ };
+- struct ast_channel *chan = cl->ast;
+-
++ 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') {
+@@ -958,8 +1566,10 @@
+ level = 1;
+ } else if (!strcasecmp(a->argv[3], "off")) {
+ level = 0;
++ } else if (isdigit(a->argv[3][0])) {
++ level = atoi(a->argv[3]);
+ } else {
+- level = atoi(a->argv[3]);
++ return CLI_SHOWUSAGE;
+ }
+
+ switch (a->argc) {
+@@ -975,7 +1585,7 @@
+ only = 1;
+ }
+ }
+-
++
+ for (i = 0; i <= max_ports; i++) {
+ misdn_debug[i] = level;
+ misdn_debug_only[i] = only;
+@@ -1267,18 +1877,18 @@
+ for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
+ misdn_cfg_get_config_string(port, elem, buffer, sizeof(buffer));
+ ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
+- }
++ }
+ ast_cli(a->fd, "\n");
+ }
+ }
+-
++
+ if (onlyport > 0) {
+ if (misdn_cfg_is_port_valid(onlyport)) {
+ ast_cli(a->fd, "[PORT %d]\n", onlyport);
+ for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
+ misdn_cfg_get_config_string(onlyport, elem, buffer, sizeof(buffer));
+ ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
+- }
++ }
+ ast_cli(a->fd, "\n");
+ } else {
+ ast_cli(a->fd, "Port %d is not active!\n", onlyport);
+@@ -1294,38 +1904,40 @@
+ };
+
+ static struct state_struct state_array[] = {
++/* *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_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_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)
++static const char *misdn_get_ch_state(struct chan_list *p)
+ {
+ int i;
+ static char state[8];
+-
++
+ if (!p) {
+ return NULL;
+ }
+-
++
+ for (i = 0; i < ARRAY_LEN(state_array); i++) {
+ if (state_array[i].state == p->state) {
+ return state_array[i].txt;
+@@ -1346,7 +1958,7 @@
+ ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
+ return ;
+ }
+-
++
+ free_robin_list();
+ misdn_cfg_reload();
+ misdn_cfg_update_ptp();
+@@ -1385,18 +1997,24 @@
+ 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)
+- );
++ 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"
+@@ -1419,21 +2037,18 @@
+ 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);
+ }
+ }
+
+@@ -1457,11 +2072,11 @@
+ }
+
+ help = cl_te;
+-
++
+ ast_cli(a->fd, "Channel List: %p\n", cl_te);
+
+ for (; help; help = help->next) {
+- struct misdn_bchannel *bc = help->bc;
++ struct misdn_bchannel *bc = help->bc;
+ struct ast_channel *ast = help->ast;
+ if (!ast) {
+ if (!bc) {
+@@ -1481,15 +2096,17 @@
+ 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);
+ }
+@@ -1523,13 +2140,13 @@
+ help = cl_te;
+
+ for (; help; help = help->next) {
+- struct misdn_bchannel *bc = help->bc;
++ struct misdn_bchannel *bc = help->bc;
+ struct ast_channel *ast = help->ast;
+-
++
+ if (bc && ast) {
+ if (!strcasecmp(ast->name, a->argv[3])) {
+ print_bc_info(a->fd, help, bc);
+- break;
++ break;
+ }
+ }
+ }
+@@ -1639,7 +2256,7 @@
+ }
+
+ port = atoi(a->argv[3]);
+-
++
+ ast_cli(a->fd, "BEGIN STACK_LIST:\n");
+ get_show_stack_details(port, buf);
+ ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
+@@ -1649,13 +2266,13 @@
+
+ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *channame;
++ char *channame;
+ char *nr;
+ struct chan_list *tmp;
+- int port;
++ int port;
+ char *served_nr;
+ struct misdn_bchannel dummy, *bc=&dummy;
+-
++
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "misdn send facility";
+@@ -1673,7 +2290,7 @@
+ if (a->argc < 5) {
+ return CLI_SHOWUSAGE;
+ }
+-
++
+ if (strstr(a->argv[3], "calldeflect")) {
+ if (a->argc < 6) {
+ ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
+@@ -1686,15 +2303,15 @@
+ 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);
+- return 0;
++ 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);
+- return 0;
++ 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")) {
+ if (a->argc < 7) {
+@@ -1719,20 +2336,20 @@
+ } 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]);
+ served_nr = a->argv[5];
+-
++
+ misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
+ 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);
+ }
+
+@@ -1773,8 +2390,8 @@
+
+ static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *channame;
+- char *msg;
++ char *channame;
++ char *msg;
+ struct chan_list *tmp;
+ int i, msglen;
+
+@@ -1803,7 +2420,7 @@
+ tmp = get_chan_by_ast_name(channame);
+ if (!tmp) {
+ ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
+- return CLI_SUCCESS;
++ return CLI_SUCCESS;
+ }
+ #if 1
+ for (i = 0; i < msglen; i++) {
+@@ -1841,9 +2458,9 @@
+ }
+
+ channame = a->argv[3];
+-
++
+ ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
+-
++
+ tmp = get_chan_by_ast_name(channame);
+ if (!tmp) {
+ ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
+@@ -1893,7 +2510,7 @@
+
+ ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
+ tmp = get_chan_by_ast_name(channame);
+-
++
+ if (tmp && tmp->bc) {
+ ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
+ misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
+@@ -2010,23 +2627,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;
+@@ -2034,7 +2653,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:
+@@ -2049,50 +2667,19 @@
+ misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
+ misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
+ chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
+-
++
+ if (pres < 0 || screen < 0) {
+- chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres);
+-
+- switch (ast->cid.cid_pres & 0x60) {
+- case AST_PRES_RESTRICTED:
+- bc->pres = 1;
+- chan_misdn_log(2, port, " --> PRES: Restricted (1)\n");
+- break;
+- case AST_PRES_UNAVAILABLE:
+- bc->pres = 2;
+- chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n");
+- break;
+- default:
+- bc->pres = 0;
+- chan_misdn_log(2, port, " --> PRES: Allowed (0)\n");
+- break;
+- }
++ chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number_presentation);
+
+- switch (ast->cid.cid_pres & 0x3) {
+- default:
+- case AST_PRES_USER_NUMBER_UNSCREENED:
+- bc->screen = 0;
+- chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n");
+- break;
+- case AST_PRES_USER_NUMBER_PASSED_SCREEN:
+- bc->screen = 1;
+- chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n");
+- break;
+- case AST_PRES_USER_NUMBER_FAILED_SCREEN:
+- bc->screen = 2;
+- chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n");
+- break;
+- case AST_PRES_NETWORK_NUMBER:
+- bc->screen = 3;
+- chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n");
+- break;
+- }
++ 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);
++
++ 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;
+ }
+
+
+@@ -2100,9 +2687,9 @@
+ {
+ struct misdn_bchannel *bc = ch->bc;
+ int len = ch->jb_len, threshold = ch->jb_upper_threshold;
+-
++
+ chan_misdn_log(5, bc->port, "config_jb: Called\n");
+-
++
+ if (! len) {
+ chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
+ bc->nojitter=1;
+@@ -2131,20 +2718,26 @@
+ }
+
+
+-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:
+@@ -2194,7 +2787,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;
+@@ -2218,7 +2811,7 @@
+ ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
+ return -1;
+ }
+-
++
+ port = bc->port;
+ chan_misdn_log(1, port, "read_config: Getting Config\n");
+
+@@ -2233,9 +2826,8 @@
+ misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(ch->incoming_early_audio));
+
+ 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));
+-
+ if (ch->ast_dsp) {
+ ch->ignore_dtmf = 1;
+ }
+@@ -2252,7 +2844,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:
+@@ -2261,7 +2852,7 @@
+ bc->hdlc = 1;
+ break;
+ }
+-
++
+ }
+ /*Initialize new Jitterbuffer*/
+ misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
+@@ -2281,14 +2872,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) */
+@@ -2301,87 +2894,53 @@
+
+ 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));
++ 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")) {
+ 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));
+- }
++ ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten));
+
+- 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);
+- }
+-
+ misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
+ ast_mutex_init(&ch->overlap_tv_lock);
+ } /* ORIG MISDN END */
+
+ ch->overlap_dial_task = -1;
+-
++
+ if (ch->faxdetect || ch->ast_dsp) {
+ misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
+ if (!ch->dsp) {
+@@ -2401,7 +2960,80 @@
+ return 0;
+ }
+
++/*!
++ * \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");
++ }
++}
++
++/*!
++ * \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);
++}
++
++
+ /*****************************/
+ /*** AST Indications Start ***/
+ /*****************************/
+@@ -2412,22 +3044,17 @@
+ 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 *dest_cp = ast_strdupa(dest);
++ char *dest_cp;
++
+ AST_DECLARE_APP_ARGS(args,
+- AST_APP_ARG(type);
+- AST_APP_ARG(ext);
+- AST_APP_ARG(opts);
++ AST_APP_ARG(intf); /* The interface token is discarded. */
++ AST_APP_ARG(ext); /* extension token */
++ AST_APP_ARG(opts); /* options token */
+ );
+
+- AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
+-
+- if (ast_strlen_zero(args.ext)) {
+- 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;
+@@ -2440,58 +3067,85 @@
+ 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(3, port, " --> * adding2newbc ext %s\n", ast->exten);
+- if (ast->exten) {
+- ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
+- ast_copy_string(newbc->dad, args.ext, sizeof(newbc->dad));
+- }
+
+- ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));
++ chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context);
+
+- 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));
++ 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);
++ }
+
++ 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));
+ if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
+ 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 */
+@@ -2500,7 +3154,12 @@
+ } 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) {
+@@ -2520,7 +3179,7 @@
+ /** 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;
+@@ -2538,8 +3197,8 @@
+ }
+
+ ch->state = MISDN_CALLING;
+-
+- return 0;
++
++ return 0;
+ }
+
+
+@@ -2551,9 +3210,9 @@
+ 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) {
+ ast_log(LOG_WARNING, " --> Channel not connected ??\n");
+ ast_queue_hangup_with_cause(ast, AST_CAUSE_NETWORK_OUT_OF_ORDER);
+@@ -2586,9 +3245,19 @@
+ 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);
+@@ -2615,12 +3284,12 @@
+
+ bc = p->bc;
+ chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
+-
++
+ if (!bc) {
+ ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
+ return -1;
+ }
+-
++
+ switch (p->state ) {
+ case MISDN_CALLING:
+ if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) {
+@@ -2629,15 +3298,15 @@
+ 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);
++ 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->dad, sizeof(p->ast->exten));
++ 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. */
++ * the other side is also mISDN. */
+ if (p->other_ch) {
+ return 0;
+ }
+@@ -2677,18 +3346,18 @@
+ ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
+ return -1;
+ }
+-
++
+ if (!p->bc ) {
+ chan_misdn_log(1, 0, "* IND : Indication from %s\n", ast->exten);
+ ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
+ return -1;
+ }
+-
++
+ chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] from %s\n", cond, ast->exten);
+-
++
+ 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;
+@@ -2700,20 +3369,20 @@
+ }
+ 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) {
+@@ -2728,7 +3397,7 @@
+ }
+ }
+
+- 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) {
+@@ -2739,28 +3408,28 @@
+ }
+ 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);
+@@ -2771,7 +3440,7 @@
+ }
+ 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);
+
+@@ -2780,17 +3449,26 @@
+ }
+ 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);
++ ast_moh_start(ast, data, p->mohinterpret);
++ 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;
+ }
+
+@@ -2815,8 +3493,10 @@
+
+ if (bc) {
+ const char *tmp;
++
+ ast_channel_lock(ast);
+- if ((tmp = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER"))) {
++ 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);
+@@ -2827,16 +3507,16 @@
+ MISDN_ASTERISK_TECH_PVT(ast) = NULL;
+ p->ast = NULL;
+
+- if (ast->_state == AST_STATE_RESERVED ||
+- p->state == MISDN_NOTHING ||
+- p->state == MISDN_HOLDED ||
++ if (ast->_state == AST_STATE_RESERVED ||
++ p->state == MISDN_NOTHING ||
++ p->state == MISDN_HOLDED ||
+ p->state == MISDN_HOLD_DISCONNECT ) {
+
+ CLEAN_CH:
+ /* between request and call */
+ ast_debug(1, "State Reserved (or nothing) => chanIsAvail\n");
+ MISDN_ASTERISK_TECH_PVT(ast) = NULL;
+-
++
+ ast_mutex_lock(&release_lock);
+ cl_dequeue_chan(&cl_te, p);
+ close(p->pipe[0]);
+@@ -2876,17 +3556,23 @@
+ }
+ ast_channel_unlock(ast);
+
+- 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));
++ 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:
+ case MISDN_CALLING:
+ p->state = MISDN_CLEANING;
+- /* This is the only place in misdn_hangup, where we
++ /* This is the only place in misdn_hangup, where we
+ * can call release_chan, else it might create lot's of trouble
+ * */
+ ast_log(LOG_NOTICE, "release channel, in CALLING/INCOMING_SETUP state.. no other events happened\n");
+@@ -2970,7 +3656,7 @@
+ if (bc->need_release) {
+ misdn_lib_send_event(bc, EVENT_RELEASE);
+ }
+- p->state = MISDN_CLEANING;
++ p->state = MISDN_CLEANING;
+ } else {
+ if (bc->need_disconnect) {
+ misdn_lib_send_event(bc, EVENT_DISCONNECT);
+@@ -2989,7 +3675,7 @@
+ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
+ {
+ struct ast_frame *f,*f2;
+-
++
+ if (tmp->trans) {
+ f2 = ast_translate(tmp->trans, frame, 0);
+ f = ast_dsp_process(tmp->ast, tmp->dsp, f2);
+@@ -3000,9 +3686,9 @@
+
+ if (!f || (f->frametype != AST_FRAME_DTMF))
+ return frame;
+-
++
+ ast_debug(1, "Detected inband DTMF digit: %c\n", f->subclass);
+-
++
+ if (tmp->faxdetect && (f->subclass == 'f')) {
+ /* Fax tone -- Handle and return NULL */
+ if (!tmp->faxhandled) {
+@@ -3035,7 +3721,7 @@
+ 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);
++ 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");
+@@ -3049,7 +3735,7 @@
+ ast_debug(1, "Fax already handled\n");
+ }
+ }
+-
++
+ if (tmp->ast_dsp && (f->subclass != 'f')) {
+ chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass);
+ }
+@@ -3082,7 +3768,8 @@
+ FD_ZERO(&rrfs);
+ FD_SET(tmp->pipe[0], &rrfs);
+
+- if (!(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;
+ }
+@@ -3151,7 +3838,7 @@
+ {
+ struct chan_list *ch;
+ int i = 0;
+-
++
+ if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) {
+ return -1;
+ }
+@@ -3160,12 +3847,12 @@
+ chan_misdn_log(7, 0, "misdn_write: Returning because holded\n");
+ return 0;
+ }
+-
++
+ if (!ch->bc ) {
+ ast_log(LOG_WARNING, "private but no bc\n");
+ return -1;
+ }
+-
++
+ if (ch->notxtone) {
+ chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
+ return 0;
+@@ -3176,16 +3863,16 @@
+ chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
+ return 0;
+ }
+-
++
+ if (!(frame->subclass & prefformat)) {
+ chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass);
+ return 0;
+ }
+-
+
++
+ if (!frame->samples ) {
+ chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
+-
++
+ if (!strcmp(frame->src,"ast_prod")) {
+ chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));
+
+@@ -3203,7 +3890,7 @@
+ chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
+ return 0;
+ }
+-
++
+ #ifdef MISDN_DEBUG
+ {
+ int i, max = 5 > frame->samples ? frame->samples : 5;
+@@ -3224,7 +3911,7 @@
+ 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);
+ }
+-
++
+ 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);
+@@ -3241,7 +3928,7 @@
+ 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);
+@@ -3250,15 +3937,11 @@
+ return 0;
+ }
+
+-
+-
+-
+-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;
+@@ -3266,13 +3949,13 @@
+ struct ast_frame *f;
+ int p1_b, p2_b;
+ int bridging;
+-
++
+ ch1 = get_chan_by_ast(c0);
+ ch2 = get_chan_by_ast(c1);
+
+ carr[0] = c0;
+ carr[1] = c1;
+-
++
+ if (!(ch1 && ch2)) {
+ return -1;
+ }
+@@ -3294,8 +3977,12 @@
+
+ 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) ) {
+ ch1->ignore_dtmf = 1;
+ }
+@@ -3317,7 +4004,7 @@
+ if (!f || f->frametype == AST_FRAME_CONTROL) {
+ /* got hangup .. */
+
+- if (!f)
++ if (!f)
+ chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
+ else
+ chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass);
+@@ -3326,7 +4013,7 @@
+ *rc = who;
+ break;
+ }
+-
++
+ if ( f->frametype == AST_FRAME_DTMF ) {
+ chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass, who->exten);
+
+@@ -3334,16 +4021,16 @@
+ *rc = who;
+ break;
+ }
+-
++
+ #if 0
+ if (f->frametype == AST_FRAME_VOICE) {
+ chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
+-
++
+ continue;
+ }
+ #endif
+
+- ast_write(who == c0 ? c1 : 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);
+@@ -3371,11 +4058,11 @@
+ chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
+ return 0;
+ }
+-
++
+ chan_misdn_log(3, cl->bc->port, " --> Dial\n");
+
+ cl->ts = ast_get_indication_tone(ast->zone, "dial");
+-
++
+ if (cl->ts) {
+ cl->notxtone = 0;
+ cl->norxtone = 0;
+@@ -3429,7 +4116,7 @@
+
+ cl->notxtone = 1;
+ cl->norxtone = 1;
+-
++
+ return 0;
+ }
+
+@@ -3438,11 +4125,12 @@
+ {
+ struct chan_list *cl;
+
+- if (!(cl = ast_calloc(1, sizeof(*cl)))) {
++ cl = ast_calloc(1, sizeof(*cl));
++ if (!cl) {
+ chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
+ return NULL;
+ }
+-
++
+ cl->originator = orig;
+ cl->need_queue_hangup = 1;
+ cl->need_hangup = 1;
+@@ -3456,38 +4144,54 @@
+ {
+ 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;
+ }
+
+@@ -3524,7 +4228,7 @@
+ if (port >= port_start) {
+ next_chan = 1;
+ }
+-
++
+ if (port <= port_start && next_chan) {
+ int maxbchans=misdn_lib_get_maxchans(port);
+ if (++robin_channel >= maxbchans) {
+@@ -3544,7 +4248,7 @@
+ 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);
+ }
+@@ -3564,7 +4268,7 @@
+ }
+ }
+ } while (!newbc && robin_channel != rr->channel);
+- } else {
++ } else {
+ for (port = misdn_cfg_get_next_port(0); port > 0;
+ port = misdn_cfg_get_next_port(port)) {
+
+@@ -3580,17 +4284,18 @@
+ chan_misdn_log(4, port, "portup:%d\n", port_up);
+
+ if (port_up > 0) {
+- if ((newbc = misdn_lib_get_free_bc(port, 0, 0, dec))) {
++ newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
++ if (newbc) {
+ break;
+ }
+ }
+ }
+ }
+ }
+-
++
+ /* Group dial failed ?*/
+ if (!newbc) {
+- ast_log(LOG_WARNING,
++ ast_log(LOG_WARNING,
+ "Could not Dial out on group '%s'.\n"
+ "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
+ "\tOr there was no free channel on none of the ports\n\n"
+@@ -3603,34 +4308,38 @@
+ 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");
+ return NULL;
+ }
+
+ cl->ast = tmp;
+-
++
+ /* register chan in local list */
+ 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;
+-
++
+ return tmp;
+ }
+
+@@ -3638,7 +4347,7 @@
+ static int misdn_send_text(struct ast_channel *chan, const char *text)
+ {
+ struct chan_list *tmp = chan->tech_pvt;
+-
++
+ if (tmp && tmp->bc) {
+ ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
+ misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
+@@ -3646,7 +4355,7 @@
+ ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
+ return -1;
+ }
+-
++
+ return 0;
+ }
+
+@@ -3658,7 +4367,7 @@
+ .send_digit_begin = misdn_digit_begin,
+ .send_digit_end = misdn_digit_end,
+ .call = misdn_call,
+- .bridge = misdn_bridge,
++ .bridge = misdn_bridge,
+ .hangup = misdn_hangup,
+ .answer = misdn_answer,
+ .read = misdn_read,
+@@ -3690,7 +4399,7 @@
+
+ static int glob_channel = 0;
+
+-static void update_name(struct ast_channel *tmp, int port, int c)
++static void update_name(struct ast_channel *tmp, int port, int c)
+ {
+ int chan_offset = 0;
+ int tmp_port = misdn_cfg_get_next_port(0);
+@@ -3699,7 +4408,7 @@
+ if (tmp_port == port) {
+ break;
+ }
+- chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
++ chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
+ }
+ if (c < 0) {
+ c = 0;
+@@ -3737,7 +4446,7 @@
+
+ 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;
+
+@@ -3745,7 +4454,7 @@
+ tmp->rawreadformat = format;
+ tmp->writeformat = format;
+ tmp->rawwriteformat = format;
+-
++
+ tmp->tech_pvt = chlist;
+
+ misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
+@@ -3779,7 +4488,7 @@
+ } else {
+ chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
+ }
+-
++
+ return tmp;
+ }
+
+@@ -3792,7 +4501,11 @@
+ }
+ }
+
+- 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;
+ }
+@@ -3806,7 +4519,7 @@
+ }
+ }
+
+- 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;
+ }
+@@ -3819,21 +4532,29 @@
+ return NULL;
+ }
+
+- chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
++ 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) &&
++ 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;
+ }
+
+
+-static struct chan_list *find_holded_l3(struct chan_list *list, unsigned long l3_id, int w)
++static struct chan_list *find_holded_l3(struct chan_list *list, unsigned long l3_id, int w)
+ {
+ struct chan_list *help = list;
+
+@@ -3850,20 +4571,20 @@
+ static void cl_queue_chan(struct chan_list **list, struct chan_list *chan)
+ {
+ chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
+-
++
+ ast_mutex_lock(&cl_te_lock);
+ if (!*list) {
+ *list = chan;
+ } else {
+ struct chan_list *help = *list;
+- for (; help->next; help = help->next);
++ for (; help->next; help = help->next);
+ help->next = chan;
+ }
+ chan->next = NULL;
+ ast_mutex_unlock(&cl_te_lock);
+ }
+
+-static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan)
++static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan)
+ {
+ struct chan_list *help;
+
+@@ -3879,13 +4600,13 @@
+ ast_mutex_unlock(&cl_te_lock);
+ return;
+ }
+-
++
+ if (*list == chan) {
+ *list = (*list)->next;
+ ast_mutex_unlock(&cl_te_lock);
+ return;
+ }
+-
++
+ for (help = *list; help->next; help = help->next) {
+ if (help->next == chan) {
+ help->next = help->next->next;
+@@ -3893,7 +4614,7 @@
+ return;
+ }
+ }
+-
++
+ ast_mutex_unlock(&cl_te_lock);
+ }
+
+@@ -3902,7 +4623,7 @@
+
+ static int pbx_start_chan(struct chan_list *ch)
+ {
+- int ret = ast_pbx_start(ch->ast);
++ int ret = ast_pbx_start(ch->ast);
+
+ ch->need_hangup = (ret >= 0) ? 0 : 1;
+
+@@ -3948,12 +4669,14 @@
+ }
+
+ /** Isdn asks us to release channel, pendant to misdn_hangup **/
+-static void release_chan(struct misdn_bchannel *bc) {
++static void release_chan(struct misdn_bchannel *bc)
++{
+ struct ast_channel *ast = NULL;
+ struct chan_list *ch;
+
+ ast_mutex_lock(&release_lock);
+- if (!(ch = find_chan_by_bc(cl_te, bc))) {
++ 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;
+@@ -3961,12 +4684,12 @@
+
+ if (ch->ast) {
+ ast = ch->ast;
+- }
++ }
+
+ chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id);
+
+ /* releasing jitterbuffer */
+- if (ch->jb ) {
++ if (ch->jb) {
+ misdn_jb_destroy(ch->jb);
+ ch->jb = NULL;
+ } else {
+@@ -3994,7 +4717,14 @@
+ 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(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;
+
+@@ -4040,7 +4770,7 @@
+
+ if (!ch->noautorespond_on_setup) {
+ if (bc->nt) {
+- int ret;
++ int ret;
+ ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
+ } else {
+ int ret;
+@@ -4054,10 +4784,15 @@
+ 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);
+-
+- strncpy(ast->exten, "s", 2);
+-
++ 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 : "");
++
++ strcpy(ast->exten, "s");
++
+ if (pbx_start_chan(ch) < 0) {
+ ast = NULL;
+ hangup_chan(ch);
+@@ -4065,8 +4800,8 @@
+
+ misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT);
+ }
+-
+-
++
++
+ while (!ast_strlen_zero(predial) ) {
+ fr.frametype = AST_FRAME_DTMF;
+ fr.subclass = *predial;
+@@ -4118,7 +4853,7 @@
+ *
+ chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Congestion pid:%d\n", bc ? bc->pid : -1);
+ ch->state = MISDN_BUSY;
+-
++
+ ast_queue_control(ast, AST_CONTROL_CONGESTION);
+ */
+ break;
+@@ -4133,11 +4868,11 @@
+ }
+
+ chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
+-
++
+ ast_queue_control(ast, AST_CONTROL_BUSY);
+-
++
+ ch->need_busy = 0;
+-
++
+ break;
+ }
+ }
+@@ -4184,6 +4919,7 @@
+ 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);
+@@ -4210,7 +4946,7 @@
+ int add_in_calls(int port)
+ {
+ int max_in_calls;
+-
++
+ misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
+ misdn_in_calls[port]++;
+
+@@ -4218,14 +4954,14 @@
+ ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
+ return misdn_in_calls[port] - max_in_calls;
+ }
+-
++
+ return 0;
+ }
+
+ int add_out_calls(int port)
+ {
+ int max_out_calls;
+-
++
+ misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));
+
+ if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
+@@ -4234,11 +4970,12 @@
+ }
+
+ misdn_out_calls[port]++;
+-
++
+ 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");
+@@ -4251,10 +4988,11 @@
+ }
+ }
+
+-static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
++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);
+ }
+ }
+@@ -4267,20 +5005,27 @@
+ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
+ {
+ struct chan_list *ch = find_chan_by_bc(cl_te, bc);
+-
++
+ if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */
+ int debuglevel = 1;
+ 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));
+ }
+ }
+-
++
+ if (!ch) {
+ switch(event) {
+ case EVENT_SETUP:
+@@ -4302,7 +5047,7 @@
+ return -1;
+ }
+ }
+-
++
+ if (ch) {
+ switch (event) {
+ case EVENT_TONE_GENERATE:
+@@ -4325,8 +5070,8 @@
+ }
+ }
+ }
+-
+-
++
++
+ switch (event) {
+ case EVENT_PORT_ALARM:
+ {
+@@ -4334,17 +5079,17 @@
+ misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(boa));
+ if (boa) {
+ cb_log(1, bc->port, " --> blocking\n");
+- misdn_lib_port_block(bc->port);
++ misdn_lib_port_block(bc->port);
+ }
+ }
+ break;
+ case EVENT_BCHAN_ACTIVATED:
+ break;
+-
++
+ case EVENT_NEW_CHANNEL:
+ update_name(ch->ast,bc->port,bc->channel);
+ break;
+-
++
+ case EVENT_NEW_L3ID:
+ ch->l3id=bc->l3_id;
+ ch->addr=bc->addr;
+@@ -4354,7 +5099,7 @@
+ if (!ch) {
+ ch = find_holded(cl_te,bc);
+ }
+-
++
+ if (!ch) {
+ ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
+ break;
+@@ -4364,7 +5109,7 @@
+ ch->bc = (struct misdn_bchannel *)user_data;
+ }
+ break;
+-
++
+ case EVENT_DTMF_TONE:
+ {
+ /* sending INFOS as DTMF-Frames :) */
+@@ -4380,7 +5125,7 @@
+ fr.mallocd = 0;
+ fr.offset = 0;
+ fr.delivery = ast_tv(0,0);
+-
++
+ if (!ch->ignore_dtmf) {
+ chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
+ ast_queue_frame(ch->ast, &fr);
+@@ -4391,12 +5136,12 @@
+ break;
+ case EVENT_STATUS:
+ break;
+-
++
+ case EVENT_INFORMATION:
+ if (ch->state != MISDN_CONNECTED) {
+ stop_indicate(ch);
+ }
+-
++
+ if (!ch->ast) {
+ break;
+ }
+@@ -4408,25 +5153,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");
+
+@@ -4454,13 +5197,13 @@
+ ch->overlap_tv = ast_tvnow();
+ ast_mutex_unlock(&ch->overlap_tv_lock);
+ if (ch->overlap_dial_task == -1) {
+- ch->overlap_dial_task =
++ ch->overlap_dial_task =
+ misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
+ }
+ 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);
+ }
+@@ -4483,11 +5226,11 @@
+ 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);
+ }
+ }
+@@ -4495,10 +5238,9 @@
+ 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;
+
+@@ -4538,13 +5280,11 @@
+ 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");
++ ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
+ return 0;
+ }
+
+@@ -4556,50 +5296,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: Unavailable (2)\n");
+- break;
+- default:
+- pres = AST_PRES_ALLOWED;
+- chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres);
+- break;
+- }
++ /* 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) {
+- default:
+- case 0:
+- screen = AST_PRES_USER_NUMBER_UNSCREENED;
+- chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen);
+- 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;
++ 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_channel_set_redirecting(chan, &redirecting);
+ }
+
+- chan->cid.cid_pres = pres | screen;
+-
+ pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
+ chan->transfercapability = bc->capability;
+
+@@ -4628,7 +5363,7 @@
+ break;
+ }
+ }
+- } /* end for */
++ }
+ if (i == ARRAY_LEN(allowed_bearers_array)) {
+ /* We did not find the bearer capability */
+ chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
+@@ -4653,7 +5388,6 @@
+ hangup_chan(ch);
+ } else {
+ ch->state = MISDN_CALLING_ACKNOWLEDGE;
+- ast_setstate(chan, AST_STATE_DOWN);
+ hangup_chan(ch);
+ ch->ast = NULL;
+ break;
+@@ -4670,16 +5404,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);
+@@ -4703,8 +5437,8 @@
+ break;
+ }
+
+- /* Whatever happens, when sending_complete is set or we are PTMP TE, we will definitely
+- * jump into the dialplan, when the dialed extension does not exist, the 's' extension
++ /* Whatever happens, when sending_complete is set or we are PTMP TE, we will definitely
++ * jump into the dialplan, when the dialed extension does not exist, the 's' extension
+ * will be used by Asterisk automatically. */
+ if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
+ if (!ch->noautorespond_on_setup) {
+@@ -4719,17 +5453,17 @@
+
+
+ /*
+- * When we are NT and overlapdial is set and if
++ * When we are NT and overlapdial is set and if
+ * 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;
+ }
+
+- /*
+- * If overlapdial we will definitely send a SETUP_ACKNOWLEDGE and wait for more
++ /*
++ * If overlapdial we will definitely send a SETUP_ACKNOWLEDGE and wait for more
+ * Infos with a Interdigit Timeout.
+ * */
+ if (ch->overlap_dial) {
+@@ -4739,16 +5473,16 @@
+
+ wait_for_digits(ch, bc, chan);
+ if (ch->overlap_dial_task == -1) {
+- ch->overlap_dial_task =
++ 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
++ /* 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;
+ }
+@@ -4756,29 +5490,30 @@
+ /*
+ * If the extension exists let's just jump into it.
+ * */
+- 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)) {
+ 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) {
+ 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));
+
+@@ -4792,7 +5527,7 @@
+ }
+
+ ch->state = MISDN_PROCEEDING;
+-
++
+ if (!ch->ast) {
+ break;
+ }
+@@ -4809,7 +5544,7 @@
+ misdn_inband_avail(bc)) {
+ start_bc_tones(ch);
+ }
+-
++
+ ch->state = MISDN_PROGRESS;
+
+ if (!ch->ast) {
+@@ -4820,16 +5555,16 @@
+ break;
+ case EVENT_ALERTING:
+ ch->state = MISDN_ALERTING;
+-
++
+ if (!ch->ast) {
+ break;
+ }
+
+ ast_queue_control(ch->ast, AST_CONTROL_RINGING);
+ ast_setstate(ch->ast, AST_STATE_RINGING);
+-
++
+ cb_log(7, bc->port, " --> Set State Ringing\n");
+-
++
+ if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
+ cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
+ start_bc_tones(ch);
+@@ -4843,38 +5578,41 @@
+ }
+ 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 */
+- misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
++ /* 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) {
+- break;
+- }
++ if (!ch->ast) {
++ break;
++ }
+
+- bridged = ast_bridged_channel(ch->ast);
+- stop_indicate(ch);
++ 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_channel_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;
++ }
+ case EVENT_CONNECT_ACKNOWLEDGE:
+ ch->l3id = bc->l3_id;
+ ch->addr = bc->addr;
+@@ -4896,7 +5634,7 @@
+ alternative number, then play it instead of
+ immediately releasing the call */
+ chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
+-
++
+ ch->state = MISDN_DISCONNECTED;
+ start_bc_tones(ch);
+
+@@ -4948,15 +5686,16 @@
+ stop_bc_tones(ch);
+ hangup_chan(ch);
+
+- if (ch)
++ if (ch) {
+ ch->state = MISDN_CLEANING;
++ }
+
+ release_chan(bc);
+ break;
+ case EVENT_BCHAN_ERROR:
+ case EVENT_CLEANUP:
+ stop_bc_tones(ch);
+-
++
+ switch (ch->state) {
+ case MISDN_CALLING:
+ bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
+@@ -4964,7 +5703,7 @@
+ default:
+ break;
+ }
+-
++
+ hangup_chan(ch);
+ release_chan(bc);
+ break;
+@@ -4997,23 +5736,23 @@
+
+ res = generate(ast, tmp, tone_len, tone_len);
+ ast->generatordata = tmp;
+-
++
+ if (res) {
+ ast_log(LOG_WARNING, "Auto-deactivating generator\n");
+ ast_deactivate_generator(ast);
+ } else {
+ bc->tone_cnt = 0;
+ }
++ break;
+ }
+- break;
+-
+ case EVENT_BCHAN_DATA:
+ if (ch->bc->AOCD_need_export) {
+ export_aoc_vars(ch->originator, ch->ast, ch->bc);
+ }
+ if (!misdn_cap_is_speech(ch->bc->capability)) {
+ struct ast_frame frame;
+- /*In Data Modes we queue frames*/
++
++ /* 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;
+@@ -5024,8 +5763,9 @@
+ 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 };
+@@ -5040,12 +5780,12 @@
+ chan_misdn_log(9, bc->port, "Select Timed out\n");
+ break;
+ }
+-
++
+ if (t < 0) {
+ chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
+ break;
+ }
+-
++
+ if (FD_ISSET(ch->pipe[1], &wrfs)) {
+ 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) {
+@@ -5095,11 +5835,12 @@
+ misdn_lib_send_event(bc, EVENT_RELEASE);
+ }
+ break;
+- case MISDN_CLEANING:
++ case MISDN_CLEANING:
+ 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);
++ break;
+ }
+ break;
+
+@@ -5133,13 +5874,13 @@
+ if (hold_ast) {
+ ast_moh_stop(hold_ast);
+ }
+-
++
+ if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
+ 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;
+@@ -5157,7 +5898,7 @@
+ chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
+ ch->state = MISDN_HOLDED;
+ ch->l3id = bc->l3_id;
+-
++
+ misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
+
+ /* XXX This should queue an AST_CONTROL_HOLD frame on this channel
+@@ -5172,11 +5913,11 @@
+ misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
+ chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
+ }
+- }
+ break;
++ }
+ case EVENT_FACILITY:
+ print_facility(&(bc->fac_in), bc);
+-
++
+ switch (bc->fac_in.Function) {
+ #ifdef HAVE_MISDN_FAC_RESULT
+ case Fac_RESULT:
+@@ -5190,7 +5931,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");
+@@ -5199,7 +5940,7 @@
+ }
+ }
+ misdn_lib_send_event(bc, EVENT_DISCONNECT);
+- }
++ }
+ break;
+ case Fac_AOCDCurrency:
+ if (ch) {
+@@ -5225,7 +5966,7 @@
+ 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) {
+@@ -5237,7 +5978,7 @@
+ chan_misdn_log(1, 0, "Got Unknown Event\n");
+ break;
+ }
+-
++
+ return RESPONSE_OK;
+ }
+
+@@ -5258,11 +5999,11 @@
+ ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
+
+ misdn_tasks_destroy();
+-
++
+ 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"); */
+@@ -5275,7 +6016,7 @@
+ free_robin_list();
+ misdn_cfg_destroy();
+ misdn_lib_destroy();
+-
++
+ if (misdn_debug) {
+ ast_free(misdn_debug);
+ }
+@@ -5283,7 +6024,7 @@
+ ast_free(misdn_debug_only);
+ }
+ ast_free(misdn_ports);
+-
++
+ return 0;
+ }
+
+@@ -5301,18 +6042,18 @@
+ };
+
+ max_ports = misdn_lib_maxports_get();
+-
++
+ if (max_ports <= 0) {
+ ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
+-
++
+ if (misdn_cfg_init(max_ports, 0)) {
+ ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
+ return AST_MODULE_LOAD_DECLINE;
+ }
+ g_config_initialized = 1;
+-
++
+ misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
+ if (!misdn_debug) {
+ ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
+@@ -5369,7 +6110,7 @@
+ unload_module();
+ return AST_MODULE_LOAD_DECLINE;
+ }
+-
++
+ ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
+
+ ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
+@@ -5400,7 +6141,7 @@
+ " vt - Tx gain control, optarg is gain\n"
+ );
+
+-
++
+ ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
+ "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
+ "Sends the Facility Message FACILITY_TYPE with \n"
+@@ -5432,13 +6173,13 @@
+ misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
+
+ /* start the l1 watchers */
+-
++
+ for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
+ int l1timeout;
+ misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
+ if (l1timeout) {
+ chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
+- misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
++ misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
+ }
+ }
+
+@@ -5462,19 +6203,20 @@
+ {
+ struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
+ 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")) {
+ ast_log(LOG_WARNING, "misdn_facility makes only sense with chan_misdn channels!\n");
+ return -1;
+ }
+-
+- if (ast_strlen_zero((char *)data)) {
++
++ if (ast_strlen_zero((char *) data)) {
+ ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
+ return -1;
+ }
+@@ -5493,7 +6235,9 @@
+ }
+
+ 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));
++ 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;
+@@ -5517,11 +6261,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;
+ }
+@@ -5544,7 +6288,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];
+@@ -5555,7 +6299,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);
+@@ -5595,7 +6338,7 @@
+ ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n");
+ return -1;
+ }
+-
++
+ if (ast_strlen_zero((char *)data)) {
+ ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
+ return -1;
+@@ -5611,14 +6354,14 @@
+ neglect = 1;
+ tok++;
+ }
+-
++
+ switch(tok[0]) {
+-
++
+ case 'd' :
+ ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
+ chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
+ break;
+-
++
+ case 'n':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
+ ch->bc->nodsp = 1;
+@@ -5677,7 +6420,7 @@
+ break;
+ }
+ break;
+-
++
+ case 'c':
+ keyidx = atoi(++tok);
+ {
+@@ -5699,7 +6442,7 @@
+ }
+ case 'e':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
+-
++
+ if (neglect) {
+ chan_misdn_log(1, ch->bc->port, " --> disabled\n");
+ #ifdef MISDN_1_2
+@@ -5719,11 +6462,11 @@
+ }
+ #endif
+ }
+-
++
+ break;
+ case 'h':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
+-
++
+ if (strlen(tok) > 1 && tok[1] == '1') {
+ chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
+ if (!ch->bc->hdlc) {
+@@ -5732,12 +6475,12 @@
+ }
+ ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
+ break;
+-
++
+ case 's':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
+ ch->bc->send_dtmf = 1;
+ break;
+-
++
+ case 'f':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
+ ch->faxdetect = 1;
+@@ -5753,12 +6496,15 @@
+ chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
+ /* CRICH: callingpres!!! */
+ if (strstr(tok, "allowed")) {
+- ch->bc->pres = 0;
++ ch->bc->presentation = 0;
++ ch->bc->set_presentation = 1;
+ } else if (strstr(tok, "restricted")) {
+- ch->bc->pres = 1;
++ ch->bc->presentation = 1;
++ ch->bc->set_presentation = 1;
+ } else if (strstr(tok, "not_screened")) {
+ chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
+- ch->bc->pres = 1;
++ ch->bc->presentation = 1;
++ ch->bc->set_presentation = 1;
+ }
+ break;
+ case 'i' :
+@@ -5791,19 +6537,19 @@
+ ch->bc->nodsp = 1;
+ ch->bc->nojitter = 1;
+ }
+-
++
+ return 0;
+ }
+
+
+-int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len)
++int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len)
+ {
+ struct chan_list *ch = find_chan_by_bc(cl_te, bc);
+-
++
+ if (ch && ch->jb) {
+ return misdn_jb_empty(ch->jb, buf, len);
+ }
+-
++
+ return -1;
+ }
+
+@@ -5860,7 +6606,7 @@
+ void misdn_jb_destroy(struct misdn_jb *jb)
+ {
+ ast_mutex_destroy(&jb->mutexjb);
+-
++
+ ast_free(jb->ok);
+ ast_free(jb->samples);
+ ast_free(jb);
+@@ -5877,10 +6623,10 @@
+ }
+
+ ast_mutex_lock(&jb->mutexjb);
+-
++
+ wp = jb->wp;
+ rp = jb->rp;
+-
++
+ for (i = 0; i < len; i++) {
+ jb->samples[wp] = data[i];
+ jb->ok[wp] = 1;
+@@ -5924,7 +6670,7 @@
+ jb->wp = wp;
+
+ ast_mutex_unlock(&jb->mutexjb);
+-
++
+ return 0;
+ }
+
+@@ -5940,7 +6686,7 @@
+ rp = jb->rp;
+ wp = jb->wp;
+
+- if (jb->state_empty) {
++ if (jb->state_empty) {
+ for (i = 0; i < len; i++) {
+ if (wp == rp) {
+ jb->rp = rp;
+@@ -5976,16 +6722,10 @@
+ return read;
+ }
+
+-
+-
+-
+ /*******************************************************/
+ /*************** JITTERBUFFER END *********************/
+ /*******************************************************/
+
+-
+-
+-
+ static void chan_misdn_log(int level, int port, char *tmpl, ...)
+ {
+ va_list ap;
+@@ -6006,15 +6746,14 @@
+
+ if (level == -1) {
+ ast_log(LOG_WARNING, "%s", buf);
++ } else if (misdn_debug_only[port] ?
++ (level == 1 && misdn_debug[port]) || (level == misdn_debug[port])
++ : level <= misdn_debug[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);
+ }
+-
++
+ if ((level <= misdn_debug[0]) && !ast_strlen_zero(global_tracefile) ) {
+ char ctimebuf[30];
+ time_t tm = time(NULL);
+@@ -6022,20 +6761,21 @@
+
+ FILE *fp = fopen(global_tracefile, "a+");
+
+- if ((p = strchr(tmp, '\n'))) {
++ p = strchr(tmp, '\n');
++ if (p) {
+ *p = ':';
+ }
+-
++
+ if (!fp) {
+ ast_console_puts("Error opening Tracefile: [ ");
+ ast_console_puts(global_tracefile);
+ ast_console_puts(" ] ");
+-
++
+ ast_console_puts(strerror(errno));
+ ast_console_puts("\n");
+ return ;
+ }
+-
++
+ fputs(tmp, fp);
+ fputs(" ", fp);
+ fputs(port_buf, fp);
+Index: channels/chan_skinny.c
+===================================================================
+--- a/channels/chan_skinny.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_skinny.c (.../trunk) (revision 186562)
+@@ -49,7 +49,7 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/netsock.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+@@ -1111,8 +1111,8 @@
+ struct skinny_subchannel {
+ ast_mutex_t lock;
+ struct ast_channel *owner;
+- struct ast_rtp *rtp;
+- struct ast_rtp *vrtp;
++ struct ast_rtp_instance *rtp;
++ struct ast_rtp_instance *vrtp;
+ unsigned int callid;
+ /* time_t lastouttime; */ /* Unused */
+ int progress;
+@@ -1347,7 +1347,7 @@
+ .fixup = skinny_fixup,
+ .send_digit_begin = skinny_senddigit_begin,
+ .send_digit_end = skinny_senddigit_end,
+- .bridge = ast_rtp_bridge,
++ .bridge = ast_rtp_instance_bridge,
+ };
+
+ static int skinny_extensionstate_cb(char *context, char* exten, int state, void *data);
+@@ -2516,6 +2516,43 @@
+ return 0;
+ }
+
++static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
++{
++ struct ast_channel *c = sub->owner;
++ struct skinny_line *l = sub->parent;
++ struct skinny_device *d = l->device;
++
++ if (ast_strlen_zero(c->cid.cid_num) || ast_strlen_zero(c->connected.id.number))
++ return;
++
++ 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;
++ }
++
++ transmit_callinfo(d, l->cid_name, l->cid_num, c->connected.id.name, c->connected.id.number, l->instance, sub->callid, 2);
++ }
++ }
++}
++
+ static void mwi_event_cb(const struct ast_event *event, void *userdata)
+ {
+ struct skinny_line *l = userdata;
+@@ -2557,46 +2594,48 @@
+ /* I do not believe skinny can deal with video.
+ Anyone know differently? */
+ /* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
+-static enum ast_rtp_get_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
+ {
+ struct skinny_subchannel *sub = NULL;
+
+ if (!(sub = c->tech_pvt) || !(sub->vrtp))
+- return AST_RTP_GET_FAILED;
++ return AST_RTP_GLUE_RESULT_FORBID;
+
+- *rtp = sub->vrtp;
++ ao2_ref(sub->vrtp, +1);
++ *instance = sub->vrtp;
+
+- return AST_RTP_TRY_NATIVE;
++ return AST_RTP_GLUE_RESULT_REMOTE;
+ }
+
+-static enum ast_rtp_get_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
+ {
+ struct skinny_subchannel *sub = NULL;
+ struct skinny_line *l;
+- enum ast_rtp_get_result res = AST_RTP_TRY_NATIVE;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_REMOTE;
+
+ if (skinnydebug)
+ ast_verb(1, "skinny_get_rtp_peer() Channel = %s\n", c->name);
+
+
+ if (!(sub = c->tech_pvt))
+- return AST_RTP_GET_FAILED;
++ return AST_RTP_GLUE_RESULT_FORBID;
+
+ ast_mutex_lock(&sub->lock);
+
+ if (!(sub->rtp)){
+ ast_mutex_unlock(&sub->lock);
+- return AST_RTP_GET_FAILED;
++ return AST_RTP_GLUE_RESULT_FORBID;
+ }
+-
+- *rtp = sub->rtp;
+
++ ao2_ref(sub->rtp, +1);
++ *instance = sub->rtp;
++
+ l = sub->parent;
+
+ if (!l->canreinvite || l->nat){
+- res = AST_RTP_TRY_PARTIAL;
++ res = AST_RTP_GLUE_RESULT_LOCAL;
+ if (skinnydebug)
+- ast_verb(1, "skinny_get_rtp_peer() Using AST_RTP_TRY_PARTIAL \n");
++ ast_verb(1, "skinny_get_rtp_peer() Using AST_RTP_GLUE_RESULT_LOCAL \n");
+ }
+
+ ast_mutex_unlock(&sub->lock);
+@@ -2605,7 +2644,7 @@
+
+ }
+
+-static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
++static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active)
+ {
+ struct skinny_subchannel *sub;
+ struct skinny_line *l;
+@@ -2630,7 +2669,7 @@
+ s = d->session;
+
+ if (rtp){
+- ast_rtp_get_peer(rtp, &them);
++ ast_rtp_instance_get_remote_address(rtp, &them);
+
+ /* Shutdown any early-media or previous media on re-invite */
+ if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
+@@ -2654,7 +2693,7 @@
+ req->data.startmedia.conferenceId = htolel(sub->callid);
+ req->data.startmedia.passThruPartyId = htolel(sub->callid);
+ if (!(l->canreinvite) || (l->nat)){
+- ast_rtp_get_us(rtp, &us);
++ ast_rtp_instance_get_local_address(rtp, &us);
+ req->data.startmedia.remoteIp = htolel(d->ourip.s_addr);
+ req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
+ } else {
+@@ -2675,11 +2714,11 @@
+ return 0;
+ }
+
+-static struct ast_rtp_protocol skinny_rtp = {
++static struct ast_rtp_glue skinny_rtp_glue = {
+ .type = "Skinny",
+ .get_rtp_info = skinny_get_rtp_peer,
+ .get_vrtp_info = skinny_get_vrtp_peer,
+- .set_rtp_peer = skinny_set_rtp_peer,
++ .update_peer = skinny_set_rtp_peer,
+ };
+
+ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+@@ -3559,29 +3598,36 @@
+
+ ast_mutex_lock(&sub->lock);
+ /* Allocate the RTP */
+- sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
++ sub->rtp = ast_rtp_instance_new(NULL, sched, &bindaddr, NULL);
+ if (hasvideo)
+- sub->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+-
++ sub->vrtp = ast_rtp_instance_new(NULL, sched, &bindaddr, NULL);
++
++ if (sub->rtp) {
++ ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
++ }
++ if (sub->vrtp) {
++ ast_rtp_instance_set_prop(sub->vrtp, AST_RTP_PROPERTY_RTCP, 1);
++ }
++
+ if (sub->rtp && sub->owner) {
+- ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
+- ast_channel_set_fd(sub->owner, 1, ast_rtcp_fd(sub->rtp));
++ ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
++ ast_channel_set_fd(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
+ }
+ if (hasvideo && sub->vrtp && sub->owner) {
+- ast_channel_set_fd(sub->owner, 2, ast_rtp_fd(sub->vrtp));
+- ast_channel_set_fd(sub->owner, 3, ast_rtcp_fd(sub->vrtp));
++ ast_channel_set_fd(sub->owner, 2, ast_rtp_instance_fd(sub->vrtp, 0));
++ ast_channel_set_fd(sub->owner, 3, ast_rtp_instance_fd(sub->vrtp, 1));
+ }
+ if (sub->rtp) {
+- ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
+- ast_rtp_setnat(sub->rtp, l->nat);
++ ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
++ ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, l->nat);
+ }
+ if (sub->vrtp) {
+- ast_rtp_setqos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
+- ast_rtp_setnat(sub->vrtp, l->nat);
++ ast_rtp_instance_set_qos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
++ ast_rtp_instance_set_prop(sub->vrtp, AST_RTP_PROPERTY_NAT, l->nat);
+ }
+ /* Set Frame packetization */
+ if (sub->rtp)
+- ast_rtp_codec_setpref(sub->rtp, &l->prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, &l->prefs);
+
+ /* Create the RTP connection */
+ transmit_connect(d, sub);
+@@ -3601,6 +3647,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);
+@@ -3764,7 +3812,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);
+
+@@ -3852,7 +3900,7 @@
+ sub->alreadygone = 0;
+ sub->outgoing = 0;
+ if (sub->rtp) {
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+ ast_mutex_unlock(&sub->lock);
+@@ -3891,7 +3939,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);
+@@ -3913,16 +3961,16 @@
+
+ switch(ast->fdno) {
+ case 0:
+- f = ast_rtp_read(sub->rtp); /* RTP Audio */
++ f = ast_rtp_instance_read(sub->rtp, 0); /* RTP Audio */
+ break;
+ case 1:
+- f = ast_rtcp_read(sub->rtp); /* RTCP Control Channel */
++ f = ast_rtp_instance_read(sub->rtp, 1); /* RTCP Control Channel */
+ break;
+ case 2:
+- f = ast_rtp_read(sub->vrtp); /* RTP Video */
++ f = ast_rtp_instance_read(sub->vrtp, 0); /* RTP Video */
+ break;
+ case 3:
+- f = ast_rtcp_read(sub->vrtp); /* RTCP Control Channel for video */
++ f = ast_rtp_instance_read(sub->vrtp, 1); /* RTCP Control Channel for video */
+ break;
+ #if 0
+ case 5:
+@@ -3979,7 +4027,7 @@
+ if (sub) {
+ ast_mutex_lock(&sub->lock);
+ if (sub->rtp) {
+- res = ast_rtp_write(sub->rtp, frame);
++ res = ast_rtp_instance_write(sub->rtp, frame);
+ }
+ ast_mutex_unlock(&sub->lock);
+ }
+@@ -4086,6 +4134,10 @@
+ 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:
+@@ -4193,7 +4245,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;
+@@ -4234,7 +4286,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;
+@@ -4253,8 +4305,11 @@
+ case AST_CONTROL_PROCEEDING:
+ break;
+ case AST_CONTROL_SRCUPDATE:
+- ast_rtp_new_source(sub->rtp);
++ ast_rtp_instance_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 */
+@@ -4312,7 +4367,7 @@
+ if (skinnydebug)
+ ast_verb(1, "skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
+ if (sub->rtp) {
+- ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
++ ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
+ }
+ if (state == AST_STATE_RING) {
+ tmp->rings = 1;
+@@ -5537,8 +5592,8 @@
+ l = sub->parent;
+
+ if (sub->rtp) {
+- ast_rtp_set_peer(sub->rtp, &sin);
+- ast_rtp_get_us(sub->rtp, &us);
++ ast_rtp_instance_set_remote_address(sub->rtp, &sin);
++ ast_rtp_instance_get_local_address(sub->rtp, &us);
+ } else {
+ ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
+ return 0;
+@@ -7289,7 +7344,7 @@
+ return -1;
+ }
+
+- ast_rtp_proto_register(&skinny_rtp);
++ ast_rtp_glue_register(&skinny_rtp_glue);
+ ast_cli_register_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
+
+ ast_manager_register2("SKINNYdevices", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_devices,
+@@ -7323,7 +7378,7 @@
+ struct skinny_subchannel *sub;
+ struct ast_context *con;
+
+- ast_rtp_proto_unregister(&skinny_rtp);
++ ast_rtp_glue_unregister(&skinny_rtp_glue);
+ ast_channel_unregister(&skinny_tech);
+ ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
+
+Index: channels/chan_mgcp.c
+===================================================================
+--- a/channels/chan_mgcp.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_mgcp.c (.../trunk) (revision 186562)
+@@ -52,7 +52,7 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/cli.h"
+@@ -282,7 +282,7 @@
+ int id;
+ struct ast_channel *owner;
+ struct mgcp_endpoint *parent;
+- struct ast_rtp *rtp;
++ struct ast_rtp_instance *rtp;
+ struct sockaddr_in tmpdest;
+ char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint.
+ This should be obsoleted */
+@@ -408,7 +408,7 @@
+ static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
+ static int transmit_modify_request(struct mgcp_subchannel *sub);
+ static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);
+-static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);
++static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_instance *rtp, int codecs);
+ static int transmit_connection_del(struct mgcp_subchannel *sub);
+ static int transmit_audit_endpoint(struct mgcp_endpoint *p);
+ static void start_rtp(struct mgcp_subchannel *sub);
+@@ -447,7 +447,7 @@
+ .fixup = mgcp_fixup,
+ .send_digit_begin = mgcp_senddigit_begin,
+ .send_digit_end = mgcp_senddigit_end,
+- .bridge = ast_rtp_bridge,
++ .bridge = ast_rtp_instance_bridge,
+ };
+
+ static void mwi_event_cb(const struct ast_event *event, void *userdata)
+@@ -472,7 +472,6 @@
+ 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, cntx,
+- AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
+ AST_EVENT_IE_END);
+
+ if (event) {
+@@ -504,7 +503,7 @@
+ sub->alreadygone = 0;
+ memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
+ if (sub->rtp) {
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+ dump_cmd_queues(NULL, sub); /* SC */
+@@ -916,7 +915,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)) {
+@@ -1004,7 +1003,7 @@
+ /* Reset temporary destination */
+ memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
+ if (sub->rtp) {
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+
+@@ -1204,7 +1203,7 @@
+ /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
+ struct ast_frame *f;
+
+- f = ast_rtp_read(sub->rtp);
++ f = ast_rtp_instance_read(sub->rtp, 0);
+ /* Don't send RFC2833 if we're not supposed to */
+ if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
+ return &ast_null_frame;
+@@ -1262,7 +1261,7 @@
+ ast_mutex_lock(&sub->lock);
+ if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
+ if (sub->rtp) {
+- res = ast_rtp_write(sub->rtp, frame);
++ res = ast_rtp_instance_write(sub->rtp, frame);
+ }
+ }
+ ast_mutex_unlock(&sub->lock);
+@@ -1298,7 +1297,7 @@
+ res = -1; /* Let asterisk play inband indications */
+ } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
+ ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
+- ast_rtp_senddigit_begin(sub->rtp, digit);
++ ast_rtp_instance_dtmf_begin(sub->rtp, digit);
+ } else {
+ ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
+ }
+@@ -1325,7 +1324,7 @@
+ tmp[2] = digit;
+ tmp[3] = '\0';
+ transmit_notify_request(sub, tmp);
+- ast_rtp_senddigit_end(sub->rtp, digit);
++ ast_rtp_instance_dtmf_end(sub->rtp, digit);
+ } else {
+ ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
+ }
+@@ -1454,7 +1453,7 @@
+ ast_moh_stop(ast);
+ break;
+ case AST_CONTROL_SRCUPDATE:
+- ast_rtp_new_source(sub->rtp);
++ ast_rtp_instance_new_source(sub->rtp);
+ break;
+ case -1:
+ transmit_notify_request(sub, "");
+@@ -1482,7 +1481,7 @@
+ fmt = ast_best_codec(tmp->nativeformats);
+ ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
+ if (sub->rtp)
+- ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
++ ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
+ if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
+ i->dsp = ast_dsp_new();
+ ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
+@@ -1875,12 +1874,12 @@
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+ sin.sin_port = htons(portno);
+- ast_rtp_set_peer(sub->rtp, &sin);
++ ast_rtp_instance_set_remote_address(sub->rtp, &sin);
+ #if 0
+ printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ #endif
+ /* Scan through the RTP payload types specified in a "m=" line: */
+- ast_rtp_pt_clear(sub->rtp);
++ ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp);
+ codecs = ast_strdupa(m + len);
+ while (!ast_strlen_zero(codecs)) {
+ if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
+@@ -1889,7 +1888,7 @@
+ ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
+ return -1;
+ }
+- ast_rtp_set_m_type(sub->rtp, codec);
++ ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec);
+ codec_count++;
+ codecs += len;
+ }
+@@ -1902,11 +1901,11 @@
+ if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2)
+ continue;
+ /* Note: should really look at the 'freq' and '#chans' params too */
+- ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0);
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec, "audio", mimeSubtype, 0);
+ }
+
+ /* Now gather all of the codecs that were asked for: */
+- ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
++ ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(sub->rtp), &peercapability, &peerNonCodecCapability);
+ p->capability = capability & peercapability;
+ if (mgcpdebug) {
+ ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
+@@ -2044,7 +2043,7 @@
+ }
+
+
+-static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp)
++static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp_instance *rtp)
+ {
+ int len;
+ int codec;
+@@ -2067,9 +2066,9 @@
+ ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
+ return -1;
+ }
+- ast_rtp_get_us(sub->rtp, &sin);
++ ast_rtp_instance_get_local_address(sub->rtp, &sin);
+ if (rtp) {
+- ast_rtp_get_peer(rtp, &dest);
++ ast_rtp_instance_get_remote_address(sub->rtp, &dest);
+ } else {
+ if (sub->tmpdest.sin_addr.s_addr) {
+ dest.sin_addr = sub->tmpdest.sin_addr;
+@@ -2095,11 +2094,11 @@
+ if (mgcpdebug) {
+ ast_verbose("Answering with capability %d\n", x);
+ }
+- codec = ast_rtp_lookup_code(sub->rtp, 1, x);
++ codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, x);
+ if (codec > -1) {
+ snprintf(costr, sizeof(costr), " %d", codec);
+ strncat(m, costr, sizeof(m) - strlen(m) - 1);
+- snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0));
++ snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, x, 0));
+ strncat(a, costr, sizeof(a) - strlen(a) - 1);
+ }
+ }
+@@ -2109,11 +2108,11 @@
+ if (mgcpdebug) {
+ ast_verbose("Answering with non-codec capability %d\n", x);
+ }
+- codec = ast_rtp_lookup_code(sub->rtp, 0, x);
++ codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 0, x);
+ if (codec > -1) {
+ snprintf(costr, sizeof(costr), " %d", codec);
+ strncat(m, costr, sizeof(m) - strlen(m) - 1);
+- snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0));
++ snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(0, x, 0));
+ strncat(a, costr, sizeof(a) - strlen(a) - 1);
+ if (x == AST_RTP_DTMF) {
+ /* Indicate we support DTMF... Not sure about 16,
+@@ -2137,7 +2136,7 @@
+ return 0;
+ }
+
+-static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs)
++static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_instance *rtp, int codecs)
+ {
+ struct mgcp_request resp;
+ char local[256];
+@@ -2148,13 +2147,13 @@
+ if (ast_strlen_zero(sub->cxident) && rtp) {
+ /* We don't have a CXident yet, store the destination and
+ wait a bit */
+- ast_rtp_get_peer(rtp, &sub->tmpdest);
++ ast_rtp_instance_get_remote_address(rtp, &sub->tmpdest);
+ return 0;
+ }
+ ast_copy_string(local, "p:20", sizeof(local));
+ for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
+ if (p->capability & x) {
+- snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
++ snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, x, 0));
+ strncat(local, tmp, sizeof(local) - strlen(local) - 1);
+ }
+ }
+@@ -2173,7 +2172,7 @@
+ return send_request(p, sub, &resp, oseq); /* SC */
+ }
+
+-static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp)
++static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_instance *rtp)
+ {
+ struct mgcp_request resp;
+ char local[256];
+@@ -2184,7 +2183,7 @@
+ ast_copy_string(local, "p:20", sizeof(local));
+ for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
+ if (p->capability & x) {
+- snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
++ snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, x, 0));
+ strncat(local, tmp, sizeof(local) - strlen(local) - 1);
+ }
+ }
+@@ -2612,21 +2611,17 @@
+ ast_mutex_lock(&sub->lock);
+ /* check again to be on the safe side */
+ if (sub->rtp) {
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+ /* Allocate the RTP now */
+- sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
++ sub->rtp = ast_rtp_instance_new(NULL, sched, &bindaddr, NULL);
+ if (sub->rtp && sub->owner)
+- ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
++ ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
+ if (sub->rtp) {
+- ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
+- ast_rtp_setnat(sub->rtp, sub->nat);
++ ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
++ ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->nat);
+ }
+-#if 0
+- ast_rtp_set_callback(p->rtp, rtpready);
+- ast_rtp_set_data(p->rtp, p);
+-#endif
+ /* Make a call*ID */
+ snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
+ /* Transmit the connection create */
+@@ -3941,22 +3936,22 @@
+ return (gw_reload ? NULL : gw);
+ }
+
+-static enum ast_rtp_get_result mgcp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result mgcp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+ struct mgcp_subchannel *sub = NULL;
+
+ if (!(sub = chan->tech_pvt) || !(sub->rtp))
+- return AST_RTP_GET_FAILED;
++ return AST_RTP_GLUE_RESULT_FORBID;
+
+- *rtp = sub->rtp;
++ *instance = sub->rtp ? ao2_ref(sub->rtp, +1), sub->rtp : NULL;
+
+ if (sub->parent->canreinvite)
+- return AST_RTP_TRY_NATIVE;
++ return AST_RTP_GLUE_RESULT_REMOTE;
+ else
+- return AST_RTP_TRY_PARTIAL;
++ return AST_RTP_GLUE_RESULT_LOCAL;
+ }
+
+-static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
++static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active)
+ {
+ /* XXX Is there such thing as video support with MGCP? XXX */
+ struct mgcp_subchannel *sub;
+@@ -3968,10 +3963,10 @@
+ return -1;
+ }
+
+-static struct ast_rtp_protocol mgcp_rtp = {
++static struct ast_rtp_glue mgcp_rtp_glue = {
+ .type = "MGCP",
+ .get_rtp_info = mgcp_get_rtp_peer,
+- .set_rtp_peer = mgcp_set_rtp_peer,
++ .update_peer = mgcp_set_rtp_peer,
+ };
+
+ static void destroy_endpoint(struct mgcp_endpoint *e)
+@@ -3985,7 +3980,7 @@
+ transmit_connection_del(sub);
+ }
+ if (sub->rtp) {
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+ memset(sub->magic, 0, sizeof(sub->magic));
+@@ -4277,7 +4272,7 @@
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+- ast_rtp_proto_register(&mgcp_rtp);
++ ast_rtp_glue_register(&mgcp_rtp_glue);
+ ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
+
+ /* And start the monitor for the first time */
+@@ -4380,7 +4375,7 @@
+ }
+
+ close(mgcpsock);
+- ast_rtp_proto_unregister(&mgcp_rtp);
++ ast_rtp_glue_unregister(&mgcp_rtp_glue);
+ ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
+ sched_context_destroy(sched);
+
+Index: channels/chan_unistim.c
+===================================================================
+--- a/channels/chan_unistim.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_unistim.c (.../trunk) (revision 186562)
+@@ -60,7 +60,7 @@
+ #include "asterisk/module.h"
+ #include "asterisk/pbx.h"
+ #include "asterisk/event.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/netsock.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+@@ -365,7 +365,7 @@
+ /*! Unistim line */
+ struct unistim_line *parent;
+ /*! RTP handle */
+- struct ast_rtp *rtp;
++ struct ast_rtp_instance *rtp;
+ int alreadygone;
+ char ringvolume;
+ char ringstyle;
+@@ -711,7 +711,7 @@
+ .send_digit_begin = unistim_senddigit_begin,
+ .send_digit_end = unistim_senddigit_end,
+ .send_text = unistim_sendtext,
+-/* .bridge = ast_rtp_bridge, */
++ .bridge = ast_rtp_instance_bridge,
+ };
+
+ static void display_last_error(const char *sz_msg)
+@@ -1854,7 +1854,7 @@
+ static void swap_subs(struct unistim_line *p, int a, int b)
+ {
+ /* struct ast_channel *towner; */
+- struct ast_rtp *rtp;
++ struct ast_rtp_instance *rtp;
+ int fds;
+
+ if (unistimdebug)
+@@ -2056,30 +2056,29 @@
+ /* Allocate the RTP */
+ if (unistimdebug)
+ ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr));
+- sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, sout.sin_addr);
++ sub->rtp = ast_rtp_instance_new(NULL, sched, &sout, NULL);
+ if (!sub->rtp) {
+ ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n",
+ strerror(errno), ast_inet_ntoa(sout.sin_addr));
+ ast_mutex_unlock(&sub->lock);
+ return;
+ }
+- if (sub->rtp && sub->owner) {
+- sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
+- sub->owner->fds[1] = ast_rtcp_fd(sub->rtp);
++ ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
++ if (sub->owner) {
++ sub->owner->fds[0] = ast_rtp_instance_fd(sub->rtp, 0);
++ sub->owner->fds[1] = ast_rtp_instance_fd(sub->rtp, 1);
+ }
+- if (sub->rtp) {
+- ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
+- ast_rtp_setnat(sub->rtp, sub->parent->parent->nat);
+- }
++ ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
++ ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->parent->parent->nat);
+
+ /* Create the RTP connection */
+- ast_rtp_get_us(sub->rtp, &us);
++ ast_rtp_instance_get_local_address(sub->rtp, &us);
+ sin.sin_family = AF_INET;
+ /* Setting up RTP for our side */
+ memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr,
+ sizeof(sin.sin_addr));
+ sin.sin_port = htons(sub->parent->parent->rtp_port);
+- ast_rtp_set_peer(sub->rtp, &sin);
++ ast_rtp_instance_set_remote_address(sub->rtp, &sin);
+ if (!(sub->owner->nativeformats & sub->owner->readformat)) {
+ int fmt;
+ fmt = ast_best_codec(sub->owner->nativeformats);
+@@ -2091,7 +2090,7 @@
+ sub->owner->readformat = fmt;
+ sub->owner->writeformat = fmt;
+ }
+- codec = ast_rtp_lookup_code(sub->rtp, 1, sub->owner->readformat);
++ codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, sub->owner->readformat);
+ /* Setting up RTP of the phone */
+ if (public_ip.sin_family == 0) /* NAT IP override ? */
+ memcpy(&public, &us, sizeof(public)); /* No defined, using IP from recvmsg */
+@@ -3672,16 +3671,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);
+@@ -3724,7 +3723,7 @@
+ if (sub->rtp) {
+ if (unistimdebug)
+ ast_verb(0, "Destroying RTP session\n");
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+ return 0;
+@@ -3769,7 +3768,7 @@
+ if (sub->rtp) {
+ if (unistimdebug)
+ ast_verb(0, "Destroying RTP session\n");
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ }
+ return 0;
+@@ -3794,7 +3793,7 @@
+ if (sub->rtp) {
+ if (unistimdebug)
+ ast_verb(0, "Destroying RTP session\n");
+- ast_rtp_destroy(sub->rtp);
++ ast_rtp_instance_destroy(sub->rtp);
+ sub->rtp = NULL;
+ } else if (unistimdebug)
+ ast_verb(0, "No RTP session to destroy\n");
+@@ -3921,10 +3920,10 @@
+
+ switch (ast->fdno) {
+ case 0:
+- f = ast_rtp_read(sub->rtp); /* RTP Audio */
++ f = ast_rtp_instance_read(sub->rtp, 0); /* RTP Audio */
+ break;
+ case 1:
+- f = ast_rtcp_read(sub->rtp); /* RTCP Control Channel */
++ f = ast_rtp_instance_read(sub->rtp, 1); /* RTCP Control Channel */
+ break;
+ default:
+ f = &ast_null_frame;
+@@ -3990,7 +3989,7 @@
+ if (sub) {
+ ast_mutex_lock(&sub->lock);
+ if (sub->rtp) {
+- res = ast_rtp_write(sub->rtp, frame);
++ res = ast_rtp_instance_write(sub->rtp, frame);
+ }
+ ast_mutex_unlock(&sub->lock);
+ }
+@@ -4391,7 +4390,6 @@
+ event = ast_event_get_cached(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_EXISTS,
+ AST_EVENT_IE_END);
+
+ if (event) {
+@@ -4456,8 +4454,8 @@
+ if ((sub->rtp) && (sub->subtype == 0)) {
+ if (unistimdebug)
+ ast_verb(0, "New unistim channel with a previous rtp handle ?\n");
+- tmp->fds[0] = ast_rtp_fd(sub->rtp);
+- tmp->fds[1] = ast_rtcp_fd(sub->rtp);
++ tmp->fds[0] = ast_rtp_instance_fd(sub->rtp, 0);
++ tmp->fds[1] = ast_rtp_instance_fd(sub->rtp, 1);
+ }
+ if (sub->rtp)
+ ast_jb_configure(tmp, &global_jbconf);
+@@ -5527,51 +5525,19 @@
+ return 0;
+ }
+
+-static enum ast_rtp_get_result unistim_get_vrtp_peer(struct ast_channel *chan,
+- struct ast_rtp **rtp)
++static enum ast_rtp_glue_result unistim_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+- return AST_RTP_TRY_NATIVE;
+-}
++ struct unistim_subchannel *sub = chan->tech_pvt;
+
+-static enum ast_rtp_get_result unistim_get_rtp_peer(struct ast_channel *chan,
+- struct ast_rtp **rtp)
+-{
+- struct unistim_subchannel *sub;
+- enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
++ ao2_ref(sub->rtp, +1);
++ *instance = sub->rtp;
+
+- if (unistimdebug)
+- ast_verb(0, "unistim_get_rtp_peer called\n");
+-
+- sub = chan->tech_pvt;
+- if (sub && sub->rtp) {
+- *rtp = sub->rtp;
+- res = AST_RTP_TRY_NATIVE;
+- }
+-
+- return res;
++ return AST_RTP_GLUE_RESULT_LOCAL;
+ }
+
+-static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
+- struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
+-{
+- struct unistim_subchannel *sub;
+-
+- if (unistimdebug)
+- ast_verb(0, "unistim_set_rtp_peer called\n");
+-
+- sub = chan->tech_pvt;
+-
+- if (sub)
+- return 0;
+-
+- return -1;
+-}
+-
+-static struct ast_rtp_protocol unistim_rtp = {
++static struct ast_rtp_glue unistim_rtp_glue = {
+ .type = channel_type,
+ .get_rtp_info = unistim_get_rtp_peer,
+- .get_vrtp_info = unistim_get_vrtp_peer,
+- .set_rtp_peer = unistim_set_rtp_peer,
+ };
+
+ /*--- load_module: PBX load module - initialization ---*/
+@@ -5604,7 +5570,7 @@
+ goto chanreg_failed;
+ }
+
+- ast_rtp_proto_register(&unistim_rtp);
++ ast_rtp_glue_register(&unistim_rtp_glue);
+
+ ast_cli_register_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
+
+@@ -5635,7 +5601,7 @@
+ ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
+
+ ast_channel_unregister(&unistim_tech);
+- ast_rtp_proto_unregister(&unistim_rtp);
++ ast_rtp_glue_unregister(&unistim_rtp_glue);
+
+ ast_mutex_lock(&monlock);
+ if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
+Index: channels/chan_local.c
+===================================================================
+--- a/channels/chan_local.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_local.c (.../trunk) (revision 186562)
+@@ -39,7 +39,6 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/file.h"
+@@ -407,6 +406,37 @@
+ 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) {
++ unsigned char frame_data[1024];
++ if (condition == AST_CONTROL_CONNECTED_LINE) {
++ f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected);
++ } else {
++ f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting);
++ }
++ f.subclass = condition;
++ f.data.ptr = frame_data;
++ if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) {
++ ast_mutex_unlock(&p->lock);
++ }
++ }
+ } else {
+ /* Queue up a frame representing the indication as a control frame */
+ ast_mutex_lock(&p->lock);
+@@ -510,22 +540,45 @@
+
+ if (!p)
+ return -1;
+-
+- ast_mutex_lock(&p->lock);
+
++ /* If you value your sanity, please don't look at this code */
++start_over:
++ while (ast_channel_trylock(p->chan)) {
++ ast_channel_unlock(p->owner);
++ usleep(1);
++ ast_channel_lock(p->owner);
++ }
++
++ /* p->owner and p->chan are locked now. Let's get p locked */
++ if (ast_mutex_trylock(&p->lock)) {
++ /* @#$&$@ */
++ ast_channel_unlock(p->chan);
++ ast_channel_unlock(p->owner);
++ usleep(1);
++ ast_channel_lock(p->owner);
++ goto start_over;
++ }
++
+ /*
+ * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
+ * call, so it's done here instead.
++ *
++ * All these failure points just return -1. The individual strings will
++ * be cleared when we destroy the channel.
+ */
+- 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;
++ if (!(p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis))) {
++ return -1;
++ }
++ ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
++
++ if (!(p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid))) {
++ return -1;
++ }
+ p->chan->cid.cid_tns = p->owner->cid.cid_tns;
++
++ ast_connected_line_copy_to_caller(&p->chan->cid, &p->owner->connected);
++ ast_connected_line_copy_from_caller(&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);
+@@ -561,6 +614,7 @@
+ ast_set_flag(p, LOCAL_LAUNCHED_PBX);
+
+ ast_mutex_unlock(&p->lock);
++ ast_channel_unlock(p->chan);
+ return res;
+ }
+
+Index: channels/chan_bridge.c
+===================================================================
+--- a/channels/chan_bridge.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_bridge.c (.../trunk) (revision 186562)
+@@ -39,7 +39,6 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/file.h"
+Index: channels/misdn/isdn_msg_parser.c
+===================================================================
+--- a/channels/misdn/isdn_msg_parser.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/isdn_msg_parser.c (.../trunk) (revision 186562)
+@@ -11,7 +11,7 @@
+ * the GNU General Public License
+ */
+
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN - message parser
+ * \author Christian Richter <crich@beronet.com>
+ */
+@@ -25,21 +25,57 @@
+
+ #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;
++ }
++}
++
++
+ static void set_channel(struct misdn_bchannel *bc, int channel)
+ {
+
+ cb_log(3,bc->port,"set_channel: bc->channel:%d channel:%d\n", bc->channel, channel);
+-
+-
++
++
+ if (channel==0xff) {
+ /* any channel */
+ channel=-1;
+ }
+-
++
+ /* ALERT: is that everytime true ? */
+ if (channel > 0 && bc->nt ) {
+-
++
+ if (bc->channel && ( bc->channel != 0xff) ) {
+ cb_log(0,bc->port,"We already have a channel (%d)\n", bc->channel);
+ } else {
+@@ -47,179 +83,191 @@
+ cb_event(EVENT_NEW_CHANNEL,bc,NULL);
+ }
+ }
+-
++
+ if (channel > 0 && !bc->nt ) {
+ bc->channel = channel;
+ cb_event(EVENT_NEW_CHANNEL,bc,NULL);
+ }
+ }
+
+-static void parse_proceeding (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_proceeding (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ CALL_PROCEEDING_t *proceeding=(CALL_PROCEEDING_t*)((unsigned long)msg->data+ HEADER_LEN);
+ //struct misdn_stack *stack=get_stack_by_bc(bc);
+-
++
+ {
+ int exclusive, channel;
+ dec_ie_channel_id(proceeding->CHANNEL_ID, (Q931_info_t *)proceeding, &exclusive, &channel, nt,bc);
+
+ set_channel(bc,channel);
+-
++
+ }
+-
++
+ dec_ie_progress(proceeding->PROGRESS, (Q931_info_t *)proceeding, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
+-
+-
+-#ifdef DEBUG
+- printf("Parsing PROCEEDING Msg\n");
++
++
++#ifdef DEBUG
++ printf("Parsing PROCEEDING Msg\n");
+ #endif
+ }
+ static msg_t *build_proceeding (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ CALL_PROCEEDING_t *proceeding;
+- msg_t *msg =(msg_t*)create_l3msg(CC_PROCEEDING | REQUEST, MT_CALL_PROCEEDING, bc?bc->l3_id:-1, sizeof(CALL_PROCEEDING_t) ,nt);
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_PROCEEDING | REQUEST, MT_CALL_PROCEEDING, bc?bc->l3_id:-1, sizeof(CALL_PROCEEDING_t) ,nt);
++
+ proceeding=(CALL_PROCEEDING_t*)((msg->data+HEADER_LEN));
+
+ enc_ie_channel_id(&proceeding->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
+-
+- if (nt)
++
++ if (nt)
+ enc_ie_progress(&proceeding->PROGRESS, msg, 0, nt?1:5, 8, nt,bc);
+-
+
+-#ifdef DEBUG
+- printf("Building PROCEEDING Msg\n");
++
++#ifdef DEBUG
++ printf("Building PROCEEDING Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_alerting (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_alerting (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+- int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
++ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ ALERTING_t *alerting=(ALERTING_t*)((unsigned long)(msg->data+HEADER_LEN));
+ //Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
+-
++
+ dec_ie_progress(alerting->PROGRESS, (Q931_info_t *)alerting, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
+-
+-#ifdef DEBUG
+- printf("Parsing ALERTING Msg\n");
++
++#ifdef DEBUG
++ printf("Parsing ALERTING Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_alerting (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_alerting (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ ALERTING_t *alerting;
+- msg_t *msg =(msg_t*)create_l3msg(CC_ALERTING | REQUEST, MT_ALERTING, bc?bc->l3_id:-1, sizeof(ALERTING_t) ,nt);
+-
+- alerting=(ALERTING_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_ALERTING | REQUEST, MT_ALERTING, bc?bc->l3_id:-1, sizeof(ALERTING_t) ,nt);
++
++ alerting=(ALERTING_t*)((msg->data+HEADER_LEN));
++
+ enc_ie_channel_id(&alerting->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
+-
+- if (nt)
++
++ if (nt)
+ enc_ie_progress(&alerting->PROGRESS, msg, 0, nt?1:5, 8, nt,bc);
+-#ifdef DEBUG
+- printf("Building ALERTING Msg\n");
++#ifdef DEBUG
++ printf("Building ALERTING Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+
+-static void parse_progress (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_progress (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+- PROGRESS_t *progress=(PROGRESS_t*)((unsigned long)(msg->data+HEADER_LEN));
+- //Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
+-
++ PROGRESS_t *progress=(PROGRESS_t*)((unsigned long)(msg->data+HEADER_LEN));
++ //Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
++
+ dec_ie_progress(progress->PROGRESS, (Q931_info_t *)progress, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
+-
+-#ifdef DEBUG
+- printf("Parsing PROGRESS Msg\n");
++
++#ifdef DEBUG
++ printf("Parsing PROGRESS Msg\n");
+ #endif
+ }
+
+-static msg_t *build_progress (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_progress (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ PROGRESS_t *progress;
+- msg_t *msg =(msg_t*)create_l3msg(CC_PROGRESS | REQUEST, MT_PROGRESS, bc?bc->l3_id:-1, sizeof(PROGRESS_t) ,nt);
+-
+- progress=(PROGRESS_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_PROGRESS | REQUEST, MT_PROGRESS, bc?bc->l3_id:-1, sizeof(PROGRESS_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building PROGRESS Msg\n");
++ progress=(PROGRESS_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building PROGRESS Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+-{
++static void parse_setup (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++{
+ 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");
++#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);
++
++ 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;
+ }
+-
+- {
+- 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;
++ 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;
++ case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
+ break;
+ case 0: bc->capability=INFO_CAPABILITY_SPEECH;
+ break;
+@@ -228,7 +276,7 @@
+ case 8: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
+ bc->user1 = user;
+ bc->urate = urate;
+-
++
+ bc->rate = rate;
+ bc->mode = mode;
+ break;
+@@ -237,7 +285,7 @@
+ default:
+ break;
+ }
+-
++
+ switch(user) {
+ case 2:
+ bc->law=INFO_CODEC_ULAW;
+@@ -247,15 +295,15 @@
+ break;
+ default:
+ bc->law=INFO_CODEC_ALAW;
+-
++
+ }
+-
+- bc->capability=capability;
++
++ bc->capability=capability;
+ }
+ {
+ int exclusive, channel;
+ dec_ie_channel_id(setup->CHANNEL_ID, (Q931_info_t *)setup, &exclusive, &channel, nt,bc);
+-
++
+ set_channel(bc,channel);
+ }
+
+@@ -266,55 +314,63 @@
+ else
+ cb_log(1,bc->port,"NO USERUESRINFO\n");
+ }
+-
++
+ dec_ie_progress(setup->PROGRESS, (Q931_info_t *)setup, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
+-
++
+ }
+
+-#define ANY_CHANNEL 0xff /* IE attribut for 'any channel' */
+-static msg_t *build_setup (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++#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;
+ SETUP_t *setup;
+- msg_t *msg =(msg_t*)create_l3msg(CC_SETUP | REQUEST, MT_SETUP, bc?bc->l3_id:-1, sizeof(SETUP_t) ,nt);
+-
+- setup=(SETUP_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_SETUP | REQUEST, MT_SETUP, bc?bc->l3_id:-1, sizeof(SETUP_t) ,nt);
++
++ setup=(SETUP_t*)((msg->data+HEADER_LEN));
++
+ if (bc->channel == 0 || bc->channel == ANY_CHANNEL || bc->channel==-1)
+ enc_ie_channel_id(&setup->CHANNEL_ID, msg, 0, bc->channel, nt,bc);
+- else
++ else
+ 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->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->dad[0])
+- enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, 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->rad[0])
+- enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, 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;
+@@ -324,7 +380,7 @@
+ default:
+ user=3;
+ }
+-
++
+ switch (bc->capability) {
+ case INFO_CAPABILITY_SPEECH: capability = 0;
+ break;
+@@ -337,81 +393,108 @@
+ user=-1;
+ break;
+ default:
+- capability=bc->capability;
++ capability=bc->capability;
+ }
+-
+-
+-
++
+ enc_ie_bearer(&setup->BEARER, msg, coding, capability, mode, rate, -1, user, nt,bc);
+ }
+
+ if (bc->sending_complete) {
+ enc_ie_complete(&setup->COMPLETE,msg, bc->sending_complete, nt, bc);
+ }
+-
++
+ if (bc->uulen) {
+ int protocol=4;
+ enc_ie_useruser(&setup->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
+ cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
+ }
+
+-#ifdef DEBUG
+- printf("Building SETUP Msg\n");
++#ifdef DEBUG
++ printf("Building SETUP Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_connect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_connect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ 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);
+ */
+-
+-#ifdef DEBUG
+- printf("Parsing CONNECT Msg\n");
++
++#ifdef DEBUG
++ printf("Parsing CONNECT Msg\n");
+ #endif
+ }
+
+-static msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_connect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ CONNECT_t *connect;
+- msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | REQUEST, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_t) ,nt);
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | REQUEST, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_t) ,nt);
++
+ cb_log(6,bc->port,"BUILD_CONNECT: bc:%p bc->l3id:%d, nt:%d\n",bc,bc->l3_id,nt);
+
+- connect=(CONNECT_t*)((msg->data+HEADER_LEN));
++ connect=(CONNECT_t*)((msg->data+HEADER_LEN));
+
+ if (nt) {
+ time_t now;
+ time(&now);
+ 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
+- printf("Building CONNECT Msg\n");
++#ifdef DEBUG
++ printf("Building CONNECT Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_setup_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_setup_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ SETUP_ACKNOWLEDGE_t *setup_acknowledge=(SETUP_ACKNOWLEDGE_t*)((unsigned long)(msg->data+HEADER_LEN));
+@@ -423,384 +506,384 @@
+
+ set_channel(bc, channel);
+ }
+-
++
+ dec_ie_progress(setup_acknowledge->PROGRESS, (Q931_info_t *)setup_acknowledge, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
+-#ifdef DEBUG
+- printf("Parsing SETUP_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Parsing SETUP_ACKNOWLEDGE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_setup_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_setup_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ SETUP_ACKNOWLEDGE_t *setup_acknowledge;
+- msg_t *msg =(msg_t*)create_l3msg(CC_SETUP_ACKNOWLEDGE | REQUEST, MT_SETUP_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(SETUP_ACKNOWLEDGE_t) ,nt);
+-
+- setup_acknowledge=(SETUP_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_SETUP_ACKNOWLEDGE | REQUEST, MT_SETUP_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(SETUP_ACKNOWLEDGE_t) ,nt);
++
++ setup_acknowledge=(SETUP_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++
+ enc_ie_channel_id(&setup_acknowledge->CHANNEL_ID, msg, 1,bc->channel, nt,bc);
+-
+- if (nt)
++
++ if (nt)
+ enc_ie_progress(&setup_acknowledge->PROGRESS, msg, 0, nt?1:5, 8, nt,bc);
+-
+-#ifdef DEBUG
+- printf("Building SETUP_ACKNOWLEDGE Msg\n");
++
++#ifdef DEBUG
++ printf("Building SETUP_ACKNOWLEDGE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_connect_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_connect_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing CONNECT_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Parsing CONNECT_ACKNOWLEDGE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_connect_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_connect_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ CONNECT_ACKNOWLEDGE_t *connect_acknowledge;
+- msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | RESPONSE, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_ACKNOWLEDGE_t) ,nt);
+-
+- connect_acknowledge=(CONNECT_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_CONNECT | RESPONSE, MT_CONNECT, bc?bc->l3_id:-1, sizeof(CONNECT_ACKNOWLEDGE_t) ,nt);
++
++ connect_acknowledge=(CONNECT_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++
+ enc_ie_channel_id(&connect_acknowledge->CHANNEL_ID, msg, 1, bc->channel, nt,bc);
+-
+-#ifdef DEBUG
+- printf("Building CONNECT_ACKNOWLEDGE Msg\n");
++
++#ifdef DEBUG
++ printf("Building CONNECT_ACKNOWLEDGE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_user_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_user_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing USER_INFORMATION Msg\n");
++#ifdef DEBUG
++ printf("Parsing USER_INFORMATION Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_user_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_user_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ USER_INFORMATION_t *user_information;
+- msg_t *msg =(msg_t*)create_l3msg(CC_USER_INFORMATION | REQUEST, MT_USER_INFORMATION, bc?bc->l3_id:-1, sizeof(USER_INFORMATION_t) ,nt);
+-
+- user_information=(USER_INFORMATION_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_USER_INFORMATION | REQUEST, MT_USER_INFORMATION, bc?bc->l3_id:-1, sizeof(USER_INFORMATION_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building USER_INFORMATION Msg\n");
++ user_information=(USER_INFORMATION_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building USER_INFORMATION Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_suspend_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_suspend_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing SUSPEND_REJECT Msg\n");
++#ifdef DEBUG
++ printf("Parsing SUSPEND_REJECT Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_suspend_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_suspend_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ SUSPEND_REJECT_t *suspend_reject;
+- msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND_REJECT | REQUEST, MT_SUSPEND_REJECT, bc?bc->l3_id:-1, sizeof(SUSPEND_REJECT_t) ,nt);
+-
+- suspend_reject=(SUSPEND_REJECT_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND_REJECT | REQUEST, MT_SUSPEND_REJECT, bc?bc->l3_id:-1, sizeof(SUSPEND_REJECT_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building SUSPEND_REJECT Msg\n");
++ suspend_reject=(SUSPEND_REJECT_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building SUSPEND_REJECT Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_resume_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_resume_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing RESUME_REJECT Msg\n");
++#ifdef DEBUG
++ printf("Parsing RESUME_REJECT Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_resume_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_resume_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RESUME_REJECT_t *resume_reject;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RESUME_REJECT | REQUEST, MT_RESUME_REJECT, bc?bc->l3_id:-1, sizeof(RESUME_REJECT_t) ,nt);
+-
+- resume_reject=(RESUME_REJECT_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RESUME_REJECT | REQUEST, MT_RESUME_REJECT, bc?bc->l3_id:-1, sizeof(RESUME_REJECT_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building RESUME_REJECT Msg\n");
++ resume_reject=(RESUME_REJECT_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building RESUME_REJECT Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_hold (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_hold (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing HOLD Msg\n");
++#ifdef DEBUG
++ printf("Parsing HOLD Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_hold (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_hold (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ HOLD_t *hold;
+- msg_t *msg =(msg_t*)create_l3msg(CC_HOLD | REQUEST, MT_HOLD, bc?bc->l3_id:-1, sizeof(HOLD_t) ,nt);
+-
+- hold=(HOLD_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_HOLD | REQUEST, MT_HOLD, bc?bc->l3_id:-1, sizeof(HOLD_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building HOLD Msg\n");
++ hold=(HOLD_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building HOLD Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_suspend (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_suspend (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing SUSPEND Msg\n");
++#ifdef DEBUG
++ printf("Parsing SUSPEND Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_suspend (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_suspend (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ SUSPEND_t *suspend;
+- msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND | REQUEST, MT_SUSPEND, bc?bc->l3_id:-1, sizeof(SUSPEND_t) ,nt);
+-
+- suspend=(SUSPEND_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND | REQUEST, MT_SUSPEND, bc?bc->l3_id:-1, sizeof(SUSPEND_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building SUSPEND Msg\n");
++ suspend=(SUSPEND_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building SUSPEND Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_resume (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_resume (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing RESUME Msg\n");
++#ifdef DEBUG
++ printf("Parsing RESUME Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_resume (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_resume (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RESUME_t *resume;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RESUME | REQUEST, MT_RESUME, bc?bc->l3_id:-1, sizeof(RESUME_t) ,nt);
+-
+- resume=(RESUME_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RESUME | REQUEST, MT_RESUME, bc?bc->l3_id:-1, sizeof(RESUME_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building RESUME Msg\n");
++ resume=(RESUME_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building RESUME Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_hold_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_hold_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing HOLD_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Parsing HOLD_ACKNOWLEDGE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_hold_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_hold_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ HOLD_ACKNOWLEDGE_t *hold_acknowledge;
+- msg_t *msg =(msg_t*)create_l3msg(CC_HOLD_ACKNOWLEDGE | REQUEST, MT_HOLD_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(HOLD_ACKNOWLEDGE_t) ,nt);
+-
+- hold_acknowledge=(HOLD_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_HOLD_ACKNOWLEDGE | REQUEST, MT_HOLD_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(HOLD_ACKNOWLEDGE_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building HOLD_ACKNOWLEDGE Msg\n");
++ hold_acknowledge=(HOLD_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building HOLD_ACKNOWLEDGE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_suspend_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_suspend_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing SUSPEND_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Parsing SUSPEND_ACKNOWLEDGE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_suspend_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_suspend_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ SUSPEND_ACKNOWLEDGE_t *suspend_acknowledge;
+- msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND_ACKNOWLEDGE | REQUEST, MT_SUSPEND_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(SUSPEND_ACKNOWLEDGE_t) ,nt);
+-
+- suspend_acknowledge=(SUSPEND_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_SUSPEND_ACKNOWLEDGE | REQUEST, MT_SUSPEND_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(SUSPEND_ACKNOWLEDGE_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building SUSPEND_ACKNOWLEDGE Msg\n");
++ suspend_acknowledge=(SUSPEND_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building SUSPEND_ACKNOWLEDGE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_resume_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_resume_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing RESUME_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Parsing RESUME_ACKNOWLEDGE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_resume_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_resume_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RESUME_ACKNOWLEDGE_t *resume_acknowledge;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RESUME_ACKNOWLEDGE | REQUEST, MT_RESUME_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(RESUME_ACKNOWLEDGE_t) ,nt);
+-
+- resume_acknowledge=(RESUME_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RESUME_ACKNOWLEDGE | REQUEST, MT_RESUME_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(RESUME_ACKNOWLEDGE_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building RESUME_ACKNOWLEDGE Msg\n");
++ resume_acknowledge=(RESUME_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building RESUME_ACKNOWLEDGE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_hold_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_hold_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing HOLD_REJECT Msg\n");
++#ifdef DEBUG
++ printf("Parsing HOLD_REJECT Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_hold_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_hold_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ HOLD_REJECT_t *hold_reject;
+- msg_t *msg =(msg_t*)create_l3msg(CC_HOLD_REJECT | REQUEST, MT_HOLD_REJECT, bc?bc->l3_id:-1, sizeof(HOLD_REJECT_t) ,nt);
+-
+- hold_reject=(HOLD_REJECT_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_HOLD_REJECT | REQUEST, MT_HOLD_REJECT, bc?bc->l3_id:-1, sizeof(HOLD_REJECT_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building HOLD_REJECT Msg\n");
++ hold_reject=(HOLD_REJECT_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building HOLD_REJECT Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_retrieve (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_retrieve (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing RETRIEVE Msg\n");
++#ifdef DEBUG
++ printf("Parsing RETRIEVE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_retrieve (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_retrieve (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RETRIEVE_t *retrieve;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE | REQUEST, MT_RETRIEVE, bc?bc->l3_id:-1, sizeof(RETRIEVE_t) ,nt);
+-
+- retrieve=(RETRIEVE_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE | REQUEST, MT_RETRIEVE, bc?bc->l3_id:-1, sizeof(RETRIEVE_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building RETRIEVE Msg\n");
++ retrieve=(RETRIEVE_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building RETRIEVE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_retrieve_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_retrieve_acknowledge (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing RETRIEVE_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Parsing RETRIEVE_ACKNOWLEDGE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_retrieve_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_retrieve_acknowledge (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RETRIEVE_ACKNOWLEDGE_t *retrieve_acknowledge;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE_ACKNOWLEDGE | REQUEST, MT_RETRIEVE_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(RETRIEVE_ACKNOWLEDGE_t) ,nt);
+-
+- retrieve_acknowledge=(RETRIEVE_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE_ACKNOWLEDGE | REQUEST, MT_RETRIEVE_ACKNOWLEDGE, bc?bc->l3_id:-1, sizeof(RETRIEVE_ACKNOWLEDGE_t) ,nt);
+
++ retrieve_acknowledge=(RETRIEVE_ACKNOWLEDGE_t*)((msg->data+HEADER_LEN));
++
+ enc_ie_channel_id(&retrieve_acknowledge->CHANNEL_ID, msg, 1, bc->channel, nt,bc);
+-#ifdef DEBUG
+- printf("Building RETRIEVE_ACKNOWLEDGE Msg\n");
++#ifdef DEBUG
++ printf("Building RETRIEVE_ACKNOWLEDGE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_retrieve_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_retrieve_reject (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing RETRIEVE_REJECT Msg\n");
++#ifdef DEBUG
++ printf("Parsing RETRIEVE_REJECT Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_retrieve_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_retrieve_reject (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RETRIEVE_REJECT_t *retrieve_reject;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE_REJECT | REQUEST, MT_RETRIEVE_REJECT, bc?bc->l3_id:-1, sizeof(RETRIEVE_REJECT_t) ,nt);
+-
+- retrieve_reject=(RETRIEVE_REJECT_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RETRIEVE_REJECT | REQUEST, MT_RETRIEVE_REJECT, bc?bc->l3_id:-1, sizeof(RETRIEVE_REJECT_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building RETRIEVE_REJECT Msg\n");
++ retrieve_reject=(RETRIEVE_REJECT_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building RETRIEVE_REJECT Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_disconnect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_disconnect (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ DISCONNECT_t *disconnect=(DISCONNECT_t*)((unsigned long)(msg->data+HEADER_LEN));
+ int location;
+- int cause;
++ int cause;
+ dec_ie_cause(disconnect->CAUSE, (Q931_info_t *)(disconnect), &location, &cause, nt,bc);
+ if (cause>0) bc->cause=cause;
+
+ dec_ie_progress(disconnect->PROGRESS, (Q931_info_t *)disconnect, &bc->progress_coding, &bc->progress_location, &bc->progress_indicator, nt, bc);
+-#ifdef DEBUG
+- printf("Parsing DISCONNECT Msg\n");
++#ifdef DEBUG
++ printf("Parsing DISCONNECT Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_disconnect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_disconnect (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ DISCONNECT_t *disconnect;
+- msg_t *msg =(msg_t*)create_l3msg(CC_DISCONNECT | REQUEST, MT_DISCONNECT, bc?bc->l3_id:-1, sizeof(DISCONNECT_t) ,nt);
+-
+- disconnect=(DISCONNECT_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_DISCONNECT | REQUEST, MT_DISCONNECT, bc?bc->l3_id:-1, sizeof(DISCONNECT_t) ,nt);
++
++ disconnect=(DISCONNECT_t*)((msg->data+HEADER_LEN));
++
+ enc_ie_cause(&disconnect->CAUSE, msg, (nt)?1:0, bc->out_cause,nt,bc);
+ if (nt) enc_ie_progress(&disconnect->PROGRESS, msg, 0, nt?1:5, 8 ,nt,bc);
+
+@@ -809,42 +892,42 @@
+ enc_ie_useruser(&disconnect->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
+ cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
+ }
+-
+-#ifdef DEBUG
+- printf("Building DISCONNECT Msg\n");
++
++#ifdef DEBUG
++ printf("Building DISCONNECT Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_restart (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_restart (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RESTART_t *restart=(RESTART_t*)((unsigned long)(msg->data+HEADER_LEN));
+
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+-
+-#ifdef DEBUG
++
++#ifdef DEBUG
+ printf("Parsing RESTART Msg\n");
+ #endif
+-
++
+ {
+ int exclusive;
+ dec_ie_channel_id(restart->CHANNEL_ID, (Q931_info_t *)restart, &exclusive, &bc->restart_channel, nt,bc);
+ cb_log(3, stack->port, "CC_RESTART Request on channel:%d on this port.\n", bc->restart_channel);
+ }
+-
++
+ }
+
+-static msg_t *build_restart (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_restart (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RESTART_t *restart;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RESTART | REQUEST, MT_RESTART, bc?bc->l3_id:-1, sizeof(RESTART_t) ,nt);
+-
+- restart=(RESTART_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_RESTART | REQUEST, MT_RESTART, bc?bc->l3_id:-1, sizeof(RESTART_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building RESTART Msg\n");
++ restart=(RESTART_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building RESTART Msg\n");
+ #endif
+
+ if (bc->channel > 0) {
+@@ -855,33 +938,33 @@
+ }
+
+ cb_log(0,bc->port, "Restarting channel %d\n", bc->channel);
+- return msg;
++ return msg;
+ }
+
+-static void parse_release (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_release (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RELEASE_t *release=(RELEASE_t*)((unsigned long)(msg->data+HEADER_LEN));
+ int location;
+ int cause;
+-
++
+ dec_ie_cause(release->CAUSE, (Q931_info_t *)(release), &location, &cause, nt,bc);
+ if (cause>0) bc->cause=cause;
+-#ifdef DEBUG
+- printf("Parsing RELEASE Msg\n");
++#ifdef DEBUG
++ printf("Parsing RELEASE Msg\n");
+ #endif
+
+-
++
+ }
+
+-static msg_t *build_release (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_release (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RELEASE_t *release;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RELEASE | REQUEST, MT_RELEASE, bc?bc->l3_id:-1, sizeof(RELEASE_t) ,nt);
+-
+- release=(RELEASE_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_RELEASE | REQUEST, MT_RELEASE, bc?bc->l3_id:-1, sizeof(RELEASE_t) ,nt);
++
++ release=(RELEASE_t*)((msg->data+HEADER_LEN));
++
+ if (bc->out_cause>= 0)
+ enc_ie_cause(&release->CAUSE, msg, nt?1:0, bc->out_cause, nt,bc);
+
+@@ -890,14 +973,14 @@
+ enc_ie_useruser(&release->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
+ cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
+ }
+-
+-#ifdef DEBUG
+- printf("Building RELEASE Msg\n");
++
++#ifdef DEBUG
++ printf("Building RELEASE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_release_complete (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_release_complete (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RELEASE_COMPLETE_t *release_complete=(RELEASE_COMPLETE_t*)((unsigned long)(msg->data+HEADER_LEN));
+@@ -926,19 +1009,19 @@
+ dec_ie_cause(release_complete->CAUSE, (Q931_info_t *)(release_complete), &location, &cause, nt,bc);
+ if (cause>0) bc->cause=cause;
+
+-#ifdef DEBUG
+- printf("Parsing RELEASE_COMPLETE Msg\n");
++#ifdef DEBUG
++ printf("Parsing RELEASE_COMPLETE Msg\n");
+ #endif
+ }
+
+-static msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ RELEASE_COMPLETE_t *release_complete;
+- msg_t *msg =(msg_t*)create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, bc?bc->l3_id:-1, sizeof(RELEASE_COMPLETE_t) ,nt);
+-
+- release_complete=(RELEASE_COMPLETE_t*)((msg->data+HEADER_LEN));
+-
++ msg_t *msg =(msg_t*)create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, bc?bc->l3_id:-1, sizeof(RELEASE_COMPLETE_t) ,nt);
++
++ release_complete=(RELEASE_COMPLETE_t*)((msg->data+HEADER_LEN));
++
+ enc_ie_cause(&release_complete->CAUSE, msg, nt?1:0, bc->out_cause, nt,bc);
+
+ if (bc->uulen) {
+@@ -946,23 +1029,23 @@
+ enc_ie_useruser(&release_complete->USER_USER, msg, protocol, bc->uu, bc->uulen, nt,bc);
+ cb_log(1,bc->port,"ENCODING USERUESRINFO:%s\n",bc->uu);
+ }
+-
+-#ifdef DEBUG
+- printf("Building RELEASE_COMPLETE Msg\n");
++
++#ifdef DEBUG
++ printf("Building RELEASE_COMPLETE Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
+- FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN);
+- Q931_info_t *qi = (Q931_info_t*)(msg->data+HEADER_LEN);
++ FACILITY_t *facility = (FACILITY_t*)(msg->data+HEADER_LEN);
++ Q931_info_t *qi = (Q931_info_t*)(msg->data+HEADER_LEN);
+ unsigned char *p = NULL;
+ int err;
+
+-#ifdef DEBUG
+- printf("Parsing FACILITY Msg\n");
++#ifdef DEBUG
++ printf("Parsing FACILITY Msg\n");
+ #endif
+
+ if (!bc->nt) {
+@@ -973,31 +1056,37 @@
+ }
+ if (!p)
+ return;
+-
++
+ err = decodeFac(p, &(bc->fac_in));
+ if (err) {
+ cb_log(5, bc->port, "Decoding FACILITY failed! (%d)\n", err);
+ }
+ }
+
+-static msg_t *build_facility (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++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
+- printf("Building FACILITY Msg\n");
++#ifdef DEBUG
++ printf("Building FACILITY Msg\n");
+ #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,147 +1098,144 @@
+ 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);
+ }
+
+- return msg;
++ return msg;
+ }
+
+-static void parse_notify (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_notify (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing NOTIFY Msg\n");
++#ifdef DEBUG
++ printf("Parsing NOTIFY Msg\n");
+ #endif
+ }
+
+-static msg_t *build_notify (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_notify (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ NOTIFY_t *notify;
+- msg_t *msg =(msg_t*)create_l3msg(CC_NOTIFY | REQUEST, MT_NOTIFY, bc?bc->l3_id:-1, sizeof(NOTIFY_t) ,nt);
+-
+- notify=(NOTIFY_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_NOTIFY | REQUEST, MT_NOTIFY, bc?bc->l3_id:-1, sizeof(NOTIFY_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building NOTIFY Msg\n");
++ notify=(NOTIFY_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building NOTIFY Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_status_enquiry (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_status_enquiry (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing STATUS_ENQUIRY Msg\n");
++#ifdef DEBUG
++ printf("Parsing STATUS_ENQUIRY Msg\n");
+ #endif
+ }
+
+-static msg_t *build_status_enquiry (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_status_enquiry (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ STATUS_ENQUIRY_t *status_enquiry;
+- msg_t *msg =(msg_t*)create_l3msg(CC_STATUS_ENQUIRY | REQUEST, MT_STATUS_ENQUIRY, bc?bc->l3_id:-1, sizeof(STATUS_ENQUIRY_t) ,nt);
+-
+- status_enquiry=(STATUS_ENQUIRY_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_STATUS_ENQUIRY | REQUEST, MT_STATUS_ENQUIRY, bc?bc->l3_id:-1, sizeof(STATUS_ENQUIRY_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building STATUS_ENQUIRY Msg\n");
++ status_enquiry=(STATUS_ENQUIRY_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building STATUS_ENQUIRY Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_information (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ 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);
+- }
+-#ifdef DEBUG
+- printf("Parsing INFORMATION Msg\n");
++ 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
+ }
+
+-static msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_information (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ INFORMATION_t *information;
+- msg_t *msg =(msg_t*)create_l3msg(CC_INFORMATION | REQUEST, MT_INFORMATION, bc?bc->l3_id:-1, sizeof(INFORMATION_t) ,nt);
+-
+- information=(INFORMATION_t*)((msg->data+HEADER_LEN));
+-
+- {
+- enc_ie_called_pn(&information->CALLED_PN, msg, 0, 1, bc->info_dad, nt,bc);
+- }
++ msg_t *msg =(msg_t*)create_l3msg(CC_INFORMATION | REQUEST, MT_INFORMATION, bc?bc->l3_id:-1, sizeof(INFORMATION_t) ,nt);
+
++ information=(INFORMATION_t*)((msg->data+HEADER_LEN));
++
++ 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);
+ }
+ }
+-
+-#ifdef DEBUG
+- printf("Building INFORMATION Msg\n");
++
++#ifdef DEBUG
++ printf("Building INFORMATION Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_status (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ STATUS_t *status=(STATUS_t*)((unsigned long)(msg->data+HEADER_LEN));
+ int location;
+ int cause;
+-
++
+ 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");
++#ifdef DEBUG
++ printf("Parsing STATUS Msg\n");
+ #endif
+ }
+
+-static msg_t *build_status (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_status (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ STATUS_t *status;
+- msg_t *msg =(msg_t*)create_l3msg(CC_STATUS | REQUEST, MT_STATUS, bc?bc->l3_id:-1, sizeof(STATUS_t) ,nt);
+-
+- status=(STATUS_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_STATUS | REQUEST, MT_STATUS, bc?bc->l3_id:-1, sizeof(STATUS_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building STATUS Msg\n");
++ status=(STATUS_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building STATUS Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+-static void parse_timeout (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++static void parse_timeout (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing STATUS Msg\n");
+-#endif
++#ifdef DEBUG
++ printf("Parsing STATUS Msg\n");
++#endif
+ }
+
+-static msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++static msg_t *build_timeout (struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
+ {
+ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
+ STATUS_t *status;
+- msg_t *msg =(msg_t*)create_l3msg(CC_STATUS | REQUEST, MT_STATUS, bc?bc->l3_id:-1, sizeof(STATUS_t) ,nt);
+-
+- status=(STATUS_t*)((msg->data+HEADER_LEN));
++ msg_t *msg =(msg_t*)create_l3msg(CC_STATUS | REQUEST, MT_STATUS, bc?bc->l3_id:-1, sizeof(STATUS_t) ,nt);
+
+-#ifdef DEBUG
+- printf("Building STATUS Msg\n");
++ status=(STATUS_t*)((msg->data+HEADER_LEN));
++
++#ifdef DEBUG
++ printf("Building STATUS Msg\n");
+ #endif
+- return msg;
++ return msg;
+ }
+
+
+@@ -1161,97 +1247,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))
+@@ -1263,15 +1292,15 @@
+
+ if (nt){
+ mISDNuser_head_t *hh = (mISDNuser_head_t*)msg->data;
+-
++
+ for (i=0; i< msgs_max -1; i++) {
+ if ( (hh->prim&COMMAND_MASK)==(msgs[i].misdn_msg&COMMAND_MASK)) return i;
+ }
+-
++
+ } else {
+ iframe_t *frm = (iframe_t*)msg->data;
+-
+- for (i=0; i< msgs_max -1; i++)
++
++ for (i=0; i< msgs_max -1; i++)
+ if ( (frm->prim&COMMAND_MASK)==(msgs[i].misdn_msg&COMMAND_MASK)) return i;
+ }
+
+@@ -1281,11 +1310,11 @@
+ int isdn_msg_get_index_by_event(struct isdn_msg msgs[], enum event_e event, int nt)
+ {
+ int i;
+- for (i=0; i< msgs_max; i++)
++ for (i=0; i< msgs_max; i++)
+ if ( event == msgs[i].event) return i;
+
+ cb_log(10,0, "get_index: event not found!\n");
+-
++
+ return -1;
+ }
+
+@@ -1318,9 +1347,9 @@
+ char * isdn_get_info(struct isdn_msg msgs[], enum event_e event, int nt)
+ {
+ int i=isdn_msg_get_index_by_event(msgs, event, nt);
+-
++
+ if(i>=0) return msgs[i].info;
+-
++
+ if (event == EVENT_CLEANUP) return EVENT_CLEAN_INFO;
+ if (event == EVENT_DTMF_TONE) return EVENT_DTMF_TONE_INFO;
+ if (event == EVENT_NEW_L3ID) return EVENT_NEW_L3ID_INFO;
+@@ -1331,7 +1360,7 @@
+ if (event == EVENT_TONE_GENERATE) return EVENT_TONE_GENERATE_INFO;
+ if (event == EVENT_PORT_ALARM) return EVENT_PORT_ALARM_INFO;
+ if (event == EVENT_BCHAN_ERROR) return EVENT_BCHAN_ERROR_INFO;
+-
++
+ return NULL;
+ }
+
+@@ -1348,6 +1377,6 @@
+ {
+ int i=isdn_msg_get_index_by_event(msgs, event, nt);
+ if(i<0) return NULL;
+-
++
+ return msgs[i].msg_builder(msgs, bc, nt);
+ }
+Index: channels/misdn/portinfo.c
+===================================================================
+--- a/channels/misdn/portinfo.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/portinfo.c (.../trunk) (revision 186562)
+@@ -1,4 +1,4 @@
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN - port info
+ * \author Christian Richter <crich@beronet.com>
+ */
+Index: channels/misdn/isdn_lib.c
+===================================================================
+--- a/channels/misdn/isdn_lib.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/isdn_lib.c (.../trunk) (revision 186562)
+@@ -11,7 +11,7 @@
+ * the GNU General Public License
+ */
+
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN
+ * \author Christian Richter <crich@beronet.com>
+ */
+@@ -33,7 +33,7 @@
+ int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len);
+
+
+-/*
++/*
+ * Define ARRAY_LEN() because I cannot
+ * #include "asterisk/utils.h"
+ */
+@@ -62,7 +62,7 @@
+ return stack->pri;
+ }
+ }
+-
++
+ return -1;
+ }
+
+@@ -74,15 +74,15 @@
+ return stack->nt;
+ }
+ }
+-
++
+ return -1;
+ }
+
+-void misdn_make_dummy(struct misdn_bchannel *dummybc, int port, int l3id, int nt, int channel)
++void misdn_make_dummy(struct misdn_bchannel *dummybc, int port, int l3id, int nt, int channel)
+ {
+ memset (dummybc,0,sizeof(struct misdn_bchannel));
+ dummybc->port=port;
+- if (l3id==0)
++ if (l3id==0)
+ dummybc->l3_id = MISDN_ID_DUMMY;
+ else
+ dummybc->l3_id=l3id;
+@@ -119,7 +119,7 @@
+ }
+
+ int misdn_lib_is_port_blocked(int port)
+-{
++{
+ struct misdn_stack *stack=get_misdn_stack();
+ for ( ; stack; stack=stack->next) {
+ if (stack->port == port) {
+@@ -138,12 +138,12 @@
+ return -1;
+ }
+
+-int misdn_lib_get_maxchans(int port)
++int misdn_lib_get_maxchans(int port)
+ {
+ struct misdn_stack *stack=get_misdn_stack();
+ for ( ; stack; stack=stack->next) {
+ if (stack->port == port) {
+- if (stack->pri)
++ if (stack->pri)
+ return 30;
+ else
+ return 2;
+@@ -159,7 +159,7 @@
+
+ if (!bc)
+ return NULL;
+-
++
+ for ( ; stack; stack = stack->next) {
+ if (bc->port == stack->port)
+ return stack;
+@@ -171,19 +171,24 @@
+
+ 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",
++ 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;
+ }
+ }
+
+@@ -219,10 +224,10 @@
+ void *user_data;
+
+ msg_queue_t upqueue;
+- msg_queue_t activatequeue;
+-
++ msg_queue_t activatequeue;
++
+ sem_t new_msg;
+-
++
+ struct misdn_stack *stack_list;
+ } ;
+
+@@ -248,7 +253,7 @@
+ int misdn_lib_port_restart(int port);
+ int misdn_lib_pid_restart(int pid);
+
+-extern struct isdn_msg msgs_g[];
++extern struct isdn_msg msgs_g[];
+
+ #define ISDN_PID_L3_B_USER 0x430000ff
+ #define ISDN_PID_L4_B_USER 0x440000ff
+@@ -304,7 +309,7 @@
+ "Res Digital",
+ "Unknown Bearer"
+ };
+-
++
+ switch (cap) {
+ case INFO_CAPABILITY_SPEECH:
+ return bearers[0];
+@@ -330,7 +335,7 @@
+ static void init_flip_bits(void)
+ {
+ int i,k;
+-
++
+ for (i = 0 ; i < 256 ; i++) {
+ unsigned char sample = 0 ;
+ for (k = 0; k<8; k++) {
+@@ -344,11 +349,11 @@
+ {
+ int i;
+ char * start = buf;
+-
++
+ for (i = 0 ; i < len; i++) {
+ buf[i] = flip_table[(unsigned char)buf[i]];
+ }
+-
++
+ return start;
+ }
+
+@@ -359,13 +364,13 @@
+ {
+ int i = 0;
+ msg_t *dmsg;
+-
++
+ while(i < 10)
+ {
+ dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
+ if (dmsg)
+ return(dmsg);
+-
++
+ if (!i)
+ printf("cannot allocate memory, trying again...\n");
+ i++;
+@@ -383,10 +388,10 @@
+ msg_t *dmsg;
+ Q931_info_t *qi;
+ iframe_t *frm;
+-
++
+ if (!ntmode)
+ size = sizeof(Q931_info_t)+2;
+-
++
+ while(i < 10) {
+ if (ntmode) {
+ dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
+@@ -406,7 +411,7 @@
+ return(dmsg);
+ }
+ }
+-
++
+ if (!i) printf("cannot allocate memory, trying again...\n");
+ i++;
+ usleep(300000);
+@@ -425,11 +430,11 @@
+ cb_log(0,bc->port,"send_msg: IEK!! no stack\n ");
+ return -1;
+ }
+-
++
+ frm->addr = (stack->upper_id | FLG_MSG_DOWN);
+ frm->dinfo = bc->l3_id;
+ frm->len = (dmsg->len) - mISDN_HEADER_LEN;
+-
++
+ cb_log(4,stack->port,"Sending msg, prim:%x addr:%x dinfo:%x\n",frm->prim,frm->addr,frm->dinfo);
+
+ mISDN_write(midev, dmsg->data, dmsg->len, TIMEOUT_1SEC);
+@@ -457,7 +462,7 @@
+ /* We have opted to never receive any available inband recorded messages */
+ return 0;
+ }
+-
++
+ switch (bc->progress_indicator) {
+ case INFO_PI_INBAND_AVAILABLE:
+ case INFO_PI_CALL_NOT_E2E_ISDN:
+@@ -505,7 +510,7 @@
+ cb_log(0,stack->port,"couldn't set channel %d in\n", channel );
+ return -1;
+ }
+-
++
+ return 0;
+ }
+
+@@ -517,9 +522,9 @@
+ int chan=0;
+ int bnums = stack->pri ? stack->b_num : stack->b_num - 1;
+
+- if (bc->channel_found)
++ if (bc->channel_found)
+ return 0;
+-
++
+ bc->channel_found=1;
+
+ cb_log(5,stack->port,"find_free_chan: req_chan:%d\n",channel);
+@@ -528,7 +533,7 @@
+ cb_log(0, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel);
+ return 0;
+ }
+-
++
+ channel--;
+
+ if (dec) {
+@@ -558,7 +563,7 @@
+ dump_chan_list(stack);
+ 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);
+@@ -576,8 +581,8 @@
+ cb_log(0,stack?stack->port:0, "empty_chan_in_stack: cannot empty channel %d\n",channel);
+ return -1;
+ }
+-
+- cb_log (4, stack?stack->port:0, "empty_chan_in_stack: %d\n",channel);
++
++ cb_log (4, stack?stack->port:0, "empty_chan_in_stack: %d\n",channel);
+ stack->channels[channel-1] = 0;
+ dump_chan_list(stack);
+ return 0;
+@@ -585,7 +590,7 @@
+
+ char *bc_state2str(enum bchannel_state state) {
+ int i;
+-
++
+ struct bchan_state_s {
+ char *n;
+ enum bchannel_state s;
+@@ -604,7 +609,7 @@
+ {"BCHAN_CLEAN_REQUEST", BCHAN_CLEAN_REQUEST},
+ {"BCHAN_ERROR", BCHAN_ERROR}
+ };
+-
++
+ for (i=0; i< sizeof(states)/sizeof(struct bchan_state_s); i++)
+ if ( states[i].s == state)
+ return states[i].n;
+@@ -618,7 +623,7 @@
+ bc->l3_id,
+ bc_state2str(bc->bc_state),
+ bc_state2str(state) );
+-
++
+ switch (state) {
+ case BCHAN_ACTIVATED:
+ if (bc->next_bc_state == BCHAN_BRIDGED) {
+@@ -644,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;
+@@ -656,38 +684,32 @@
+ bc->sending_complete = 0;
+
+ bc->restart_channel=0;
+-
++
+ bc->conf_id = 0;
+
+ bc->need_more_infos = 0;
+-
++
+ bc->send_dtmf=0;
+ bc->nodsp=0;
+ bc->nojitter=0;
+
+ bc->time_usec=0;
+-
++
+ bc->rxgain=0;
+ bc->txgain=0;
+
+ bc->crypt=0;
+ bc->curptx=0; bc->curprx=0;
+-
++
+ bc->crypt_key[0] = 0;
+-
++
+ 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;
+-
++
+ #ifdef MISDN_1_2
+ *bc->pipeline = 0;
+ #else
+@@ -698,17 +720,22 @@
+ bc->AOCD_need_export = 0;
+
+ bc->orig=0;
+-
++
+ bc->cause = AST_CAUSE_NORMAL_CLEARING;
+ bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
+- bc->pres = 0; /* allowed */
+-
++
++ 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;
+ bc->progress_location=0;
+ bc->progress_indicator=0;
+-
++
+ /** Set Default Bearer Caps **/
+ bc->capability=INFO_CAPABILITY_SPEECH;
+ bc->law=INFO_CODEC_ALAW;
+@@ -716,24 +743,23 @@
+ bc->rate=0x10;
+ bc->user1=0;
+ bc->urate=0;
+-
++
+ 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;
+-
++
+ bc->fac_in.Function = Fac_None;
+ bc->fac_out.Function = Fac_None;
+-
++
+ bc->te_choose_channel = 0;
+ bc->channel_found= 0;
+
+@@ -748,32 +774,32 @@
+ struct misdn_stack * stack;
+
+ cb_log(3, bc?bc->port:0, "$$$ CLEANUP CALLED pid:%d\n", bc?bc->pid:-1);
+-
++
+ if (!bc ) return -1;
+ stack=get_stack_by_bc(bc);
+-
++
+ if (!stack) return -1;
+-
++
+ switch (bc->bc_state ) {
+ case BCHAN_CLEANED:
+ cb_log(5, stack->port, "$$$ Already cleaned up bc with stid :%x\n", bc->b_stid);
+ return -1;
+-
++
+ default:
+ break;
+ }
+-
++
+ cb_log(2, stack->port, "$$$ Cleaning up bc with stid :%x pid:%d\n", bc->b_stid, bc->pid);
+-
++
+ manager_ec_disable(bc);
+
+ manager_bchannel_deactivate(bc);
+
+ mISDN_write_frame(stack->midev, buff, bc->layer_id|FLG_MSG_TARGET|FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+-
++
+ bc->b_stid = 0;
+ bc_state_change(bc, BCHAN_CLEANED);
+-
++
+ return ret;
+ }
+
+@@ -785,14 +811,14 @@
+
+ for (i=0; i<=stack->b_num; i++) {
+ if (global_state == MISDN_INITIALIZED) {
+- cb_event(EVENT_CLEANUP, &stack->bc[i], NULL);
++ cb_event(EVENT_CLEANUP, &stack->bc[i], NULL);
+ empty_chan_in_stack(stack,i+1);
+ empty_bc(&stack->bc[i]);
+ clean_up_bc(&stack->bc[i]);
+ stack->bc[i].in_use = 0;
+ }
+-
+- }
++
++ }
+ }
+
+ static int new_te_id = 0;
+@@ -801,9 +827,9 @@
+
+ static int misdn_lib_get_l1_down(struct misdn_stack *stack)
+ {
+- /* Pull Up L1 */
++ /* Pull Up L1 */
+ iframe_t act;
+- act.prim = PH_DEACTIVATE | REQUEST;
++ act.prim = PH_DEACTIVATE | REQUEST;
+ act.addr = stack->lower_id|FLG_MSG_DOWN;
+ act.dinfo = 0;
+ act.len = 0;
+@@ -815,38 +841,38 @@
+
+ static int misdn_lib_get_l2_down(struct misdn_stack *stack)
+ {
+-
++
+ if (stack->ptp && (stack->nt) ) {
+ msg_t *dmsg;
+ /* L2 */
+ dmsg = create_l2msg(DL_RELEASE| REQUEST, 0, 0);
+-
++
+ if (stack->nst.manager_l3(&stack->nst, dmsg))
+ free_msg(dmsg);
+-
++
+ } else {
+ iframe_t act;
+-
++
+ act.prim = DL_RELEASE| REQUEST;
+ act.addr = (stack->upper_id |FLG_MSG_DOWN) ;
+-
++
+ act.dinfo = 0;
+ act.len = 0;
+ return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+ }
+-
++
+ return 0;
+ }
+
+
+ static int misdn_lib_get_l1_up(struct misdn_stack *stack)
+ {
+- /* Pull Up L1 */
++ /* Pull Up L1 */
+ iframe_t act;
+- act.prim = PH_ACTIVATE | REQUEST;
++ act.prim = PH_ACTIVATE | REQUEST;
+ act.addr = (stack->upper_id | FLG_MSG_DOWN) ;
+
+-
++
+ act.dinfo = 0;
+ act.len = 0;
+
+@@ -856,26 +882,26 @@
+
+ int misdn_lib_get_l2_up(struct misdn_stack *stack)
+ {
+-
++
+ if (stack->ptp && (stack->nt) ) {
+ msg_t *dmsg;
+ /* L2 */
+ dmsg = create_l2msg(DL_ESTABLISH | REQUEST, 0, 0);
+-
++
+ if (stack->nst.manager_l3(&stack->nst, dmsg))
+ free_msg(dmsg);
+-
++
+ } else {
+ iframe_t act;
+-
++
+ act.prim = DL_ESTABLISH | REQUEST;
+ act.addr = (stack->upper_id |FLG_MSG_DOWN) ;
+-
++
+ act.dinfo = 0;
+ act.len = 0;
+ return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+ }
+-
++
+ return 0;
+ }
+
+@@ -883,10 +909,10 @@
+ static int misdn_lib_get_l2_te_ptp_up(struct misdn_stack *stack)
+ {
+ iframe_t act;
+-
++
+ act.prim = DL_ESTABLISH | REQUEST;
+ act.addr = (stack->upper_id & ~LAYER_ID_MASK) | 3 | FLG_MSG_DOWN;
+-
++
+ act.dinfo = 0;
+ act.len = 0;
+ return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+@@ -897,14 +923,14 @@
+ static int misdn_lib_get_short_status(struct misdn_stack *stack)
+ {
+ iframe_t act;
+-
+-
+- act.prim = MGR_SHORTSTATUS | REQUEST;
+-
++
++
++ act.prim = MGR_SHORTSTATUS | REQUEST;
++
+ act.addr = (stack->upper_id | MSG_BROADCAST) ;
+
+ act.dinfo = SSTATUS_BROADCAST_BIT | SSTATUS_ALL;
+-
++
+ act.len = 0;
+ return mISDN_write(stack->midev, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+ }
+@@ -929,7 +955,7 @@
+ if (stack->procids[proc_id] == 0) {
+ break;
+ }
+- } /* end for */
++ }
+ if (proc_id == MAXPROCS) {
+ cb_log(0, stack->port, "Couldn't Create New ProcId.\n");
+ return -1;
+@@ -941,7 +967,7 @@
+ bc->l3_id = l3_id;
+ cb_log(3, stack->port, " --> new_l3id %x\n", l3_id);
+ } else {
+- if (stack->ptp || bc->te_choose_channel) {
++ if ((stack->pri && stack->ptp) || bc->te_choose_channel) {
+ /* we know exactly which channels are in use */
+ if (find_free_chan_in_stack(stack, bc, bc->channel_preselected ? bc->channel : 0, bc->dec) < 0) {
+ return -1;
+@@ -996,7 +1022,7 @@
+ cb_log(0, bc->port, "setup_bc: NO STACK FOUND!!\n");
+ return -1;
+ }
+-
++
+ midev = stack->midev;
+ channel = bc->channel - 1 - (bc->channel > 16);
+ b_stid = stack->b_stids[channel >= 0 ? channel : 0];
+@@ -1008,9 +1034,9 @@
+ 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 already initialized*/
+ for (i=0; i <= stack->b_num; i++) {
+ if (stack->bc[i].b_stid == b_stid) {
+@@ -1018,10 +1044,10 @@
+ return -1;
+ }
+ }
+-
++
+ if (b_stid <= 0) {
+ cb_log(0, stack->port," -- Stid <=0 at the moment in channel:%d\n",channel);
+-
++
+ bc_state_change(bc,BCHAN_ERROR);
+ return 1;
+ }
+@@ -1031,10 +1057,10 @@
+ {
+ layer_info_t li;
+ memset(&li, 0, sizeof(li));
+-
++
+ li.object_id = -1;
+ li.extentions = 0;
+-
++
+ li.st = bc->b_stid; /* given idx */
+
+
+@@ -1044,18 +1070,18 @@
+ #endif
+ if ( bc->hdlc || bc->nodsp) {
+ cb_log(4, stack->port,"setup_bc: without dsp\n");
+- {
++ {
+ int l = sizeof(li.name);
+ strncpy(li.name, "B L3", l);
+ li.name[l-1] = 0;
+ }
+ li.pid.layermask = ISDN_LAYER((3));
+ li.pid.protocol[3] = ISDN_PID_L3_B_USER;
+-
++
+ bc->layer=3;
+ } else {
+ cb_log(4, stack->port,"setup_bc: with dsp\n");
+- {
++ {
+ int l = sizeof(li.name);
+ strncpy(li.name, "B L4", l);
+ li.name[l-1] = 0;
+@@ -1064,8 +1090,8 @@
+ li.pid.protocol[4] = ISDN_PID_L4_B_USER;
+
+ bc->layer=4;
+- }
+-
++ }
++
+ ret = mISDN_new_layer(midev, &li);
+ if (ret ) {
+ cb_log(0, stack->port,"New Layer Err: %d %s\n",ret,strerror(errno));
+@@ -1073,23 +1099,23 @@
+ bc_state_change(bc,BCHAN_ERROR);
+ return(-EINVAL);
+ }
+-
++
+ bc->layer_id = li.id;
+ }
+-
++
+ memset(&pid, 0, sizeof(pid));
+-
+-
+-
++
++
++
+ cb_log(4, stack->port," --> Channel is %d\n", bc->channel);
+-
++
+ if (bc->nodsp) {
+ cb_log(2, stack->port," --> TRANSPARENT Mode (no DSP, no HDLC)\n");
+ pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
+ pid.protocol[2] = ISDN_PID_L2_B_TRANS;
+ pid.protocol[3] = ISDN_PID_L3_B_USER;
+ pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3));
+-
++
+ } else if ( bc->hdlc ) {
+ cb_log(2, stack->port," --> HDLC Mode\n");
+ pid.protocol[1] = ISDN_PID_L1_B_64HDLC ;
+@@ -1103,16 +1129,16 @@
+ pid.protocol[3] = ISDN_PID_L3_B_DSP;
+ pid.protocol[4] = ISDN_PID_L4_B_USER;
+ pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4));
+-
+- }
+
++ }
++
+ ret = mISDN_set_stack(midev, bc->b_stid, &pid);
+
+ if (ret){
+ cb_log(0, stack->port,"$$$ Set Stack Err: %d %s\n",ret,strerror(errno));
+-
++
+ mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+-
++
+ bc_state_change(bc,BCHAN_ERROR);
+ cb_event(EVENT_BCHAN_ERROR, bc, glob_mgr->user_data);
+ return(-EINVAL);
+@@ -1123,7 +1149,7 @@
+ if (ret) {
+ cb_log(0, stack->port,"$$$ Set StackIND Err: %d %s\n",ret,strerror(errno));
+ mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+-
++
+ bc_state_change(bc,BCHAN_ERROR);
+ cb_event(EVENT_BCHAN_ERROR, bc, glob_mgr->user_data);
+ return(-EINVAL);
+@@ -1136,14 +1162,14 @@
+ if (!bc->addr) {
+ cb_log(0, stack->port,"$$$ Get Layerid Err: %d %s\n",ret,strerror(errno));
+ mISDN_write_frame(midev, buff, bc->layer_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+-
++
+ bc_state_change(bc,BCHAN_ERROR);
+ cb_event(EVENT_BCHAN_ERROR, bc, glob_mgr->user_data);
+ return (-EINVAL);
+ }
+
+ manager_bchannel_activate(bc);
+-
++
+ bc_state_change(bc,BCHAN_ACTIVATED);
+
+ return 0;
+@@ -1157,11 +1183,11 @@
+ unsigned char buff[1025] = "";
+ iframe_t *frm = (iframe_t *)buff;
+ int ret;
+-
++
+ if (!bc) return -1;
+-
++
+ cb_log(8, port, "Init.BC %d.\n",bidx);
+-
++
+ memset(bc, 0,sizeof(struct misdn_bchannel));
+
+ bc->send_lock=malloc(sizeof(struct send_lock));
+@@ -1169,40 +1195,40 @@
+ return -1;
+ }
+ pthread_mutex_init(&bc->send_lock->lock, NULL);
+-
++
+ if (msn) {
+ int l = sizeof(bc->msn);
+ strncpy(bc->msn,msn, l);
+ bc->msn[l-1] = 0;
+ }
+-
+-
++
++
+ empty_bc(bc);
+ bc_state_change(bc, BCHAN_CLEANED);
+-
++
+ bc->port=stack->port;
+ bc->nt=stack->nt?1:0;
+ bc->pri=stack->pri;
+-
++
+ {
+ ibuffer_t* ibuf= init_ibuffer(MISDN_IBUF_SIZE);
+
+ if (!ibuf) return -1;
+-
++
+ clear_ibuffer( ibuf);
+-
++
+ ibuf->rsem=malloc(sizeof(sem_t));
+ if (!ibuf->rsem) {
+ return -1;
+ }
+-
++
+ bc->astbuf=ibuf;
+
+ if (sem_init(ibuf->rsem,1,0)<0)
+ sem_init(ibuf->rsem,0,0);
+-
++
+ }
+-
++
+ {
+ stack_info_t *stinf;
+ ret = mISDN_get_stack_info(midev, stack->port, buff, sizeof(buff));
+@@ -1210,12 +1236,12 @@
+ cb_log(0, port, "%s: Cannot get stack info for this port. (ret=%d)\n", __FUNCTION__, ret);
+ return -1;
+ }
+-
++
+ stinf = (stack_info_t *)&frm->data.p;
+-
++
+ cb_log(8, port, " --> Child %x\n",stinf->child[bidx]);
+ }
+-
++
+ return 0;
+ }
+
+@@ -1227,7 +1253,7 @@
+ unsigned char buff[1025];
+ iframe_t *frm = (iframe_t *)buff;
+ stack_info_t *stinf;
+- int i;
++ int i;
+ layer_info_t li;
+
+ struct misdn_stack *stack = malloc(sizeof(struct misdn_stack));
+@@ -1235,28 +1261,28 @@
+
+
+ cb_log(8, port, "Init. Stack.\n");
+-
++
+ memset(stack,0,sizeof(struct misdn_stack));
+-
++
+ for (i=0; i<MAX_BCHANS + 1; i++ ) stack->channels[i]=0;
+-
++
+ stack->port=port;
+ stack->midev=midev;
+ stack->ptp=ptp;
+-
++
+ stack->holding=NULL;
+ stack->pri=0;
+-
++
+ msg_queue_init(&stack->downqueue);
+ msg_queue_init(&stack->upqueue);
+-
++
+ /* query port's requirements */
+ ret = mISDN_get_stack_info(midev, port, buff, sizeof(buff));
+ if (ret < 0) {
+ cb_log(0, port, "%s: Cannot get stack info for this port. (ret=%d)\n", __FUNCTION__, ret);
+ return(NULL);
+ }
+-
++
+ stinf = (stack_info_t *)&frm->data.p;
+
+ stack->d_stid = stinf->id;
+@@ -1264,7 +1290,7 @@
+
+ for (i=0; i<=stinf->childcnt; i++)
+ stack->b_stids[i] = stinf->child[i];
+-
++
+ switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) {
+ case ISDN_PID_L0_TE_S0:
+ stack->nt=0;
+@@ -1283,7 +1309,7 @@
+ cb_log(8, port, "TE S2M Stack\n");
+ stack->nt=1;
+ stack->pri=1;
+-
++
+ break;
+ default:
+ cb_log(0, port, "this is a unknown port type 0x%08x\n", stinf->pid.protocol[0]);
+@@ -1291,19 +1317,19 @@
+ }
+
+ if (!stack->nt) {
+- if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP ) {
++ if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP ) {
+ stack->ptp = 1;
+ } else {
+ stack->ptp = 0;
+ }
+ }
+-
++
+ {
+ int ret;
+ int nt=stack->nt;
+
+ cb_log(8, port, "Init. Stack.\n");
+-
++
+ memset(&li, 0, sizeof(li));
+ {
+ int l = sizeof(li.name);
+@@ -1315,15 +1341,15 @@
+ li.pid.protocol[nt?2:4] = nt?ISDN_PID_L2_LAPD_NET:ISDN_PID_L4_CAPI20;
+ li.pid.layermask = ISDN_LAYER((nt?2:4));
+ li.st = stack->d_stid;
+-
+-
++
++
+ ret = mISDN_new_layer(midev, &li);
+ if (ret) {
+ cb_log(0, port, "%s: Cannot add layer %d to this port.\n", __FUNCTION__, nt?2:4);
+ return(NULL);
+ }
+-
+-
++
++
+ stack->upper_id = li.id;
+ ret = mISDN_register_layer(midev, stack->d_stid, stack->upper_id);
+ if (ret)
+@@ -1331,52 +1357,52 @@
+ cb_log(0,port,"Cannot register layer %d of this port.\n", nt?2:4);
+ return(NULL);
+ }
+-
+- stack->lower_id = mISDN_get_layerid(midev, stack->d_stid, nt?1:3);
++
++ stack->lower_id = mISDN_get_layerid(midev, stack->d_stid, nt?1:3);
+ if (stack->lower_id < 0) {
+ cb_log(0, port, "%s: Cannot get layer(%d) id of this port.\n", __FUNCTION__, nt?1:3);
+ return(NULL);
+ }
+-
++
+ stack->upper_id = mISDN_get_layerid(midev, stack->d_stid, nt?2:4);
+ if (stack->upper_id < 0) {
+ cb_log(0, port, "%s: Cannot get layer(%d) id of this port.\n", __FUNCTION__, 2);
+ return(NULL);
+ }
+-
++
+ cb_log(8, port, "NT Stacks upper_id %x\n",stack->upper_id);
+-
+-
++
++
+ /* create nst (nt-mode only) */
+ if (nt) {
+-
++
+ memset(&stack->nst, 0, sizeof(net_stack_t));
+ memset(&stack->mgr, 0, sizeof(manager_t));
+-
++
+ stack->mgr.nst = &stack->nst;
+ stack->nst.manager = &stack->mgr;
+-
++
+ stack->nst.l3_manager = handle_event_nt;
+ stack->nst.device = midev;
+ stack->nst.cardnr = port;
+ stack->nst.d_stid = stack->d_stid;
+-
++
+ stack->nst.feature = FEATURE_NET_HOLD;
+ if (stack->ptp)
+ stack->nst.feature |= FEATURE_NET_PTP;
+ if (stack->pri)
+ stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID;
+-
++
+ stack->nst.l1_id = stack->lower_id;
+ stack->nst.l2_id = stack->upper_id;
+-
++
+ msg_queue_init(&stack->nst.down_queue);
+-
++
+ Isdnl2Init(&stack->nst);
+ Isdnl3Init(&stack->nst);
+-
+- }
+-
++
++ }
++
+ if (!stack->nt) {
+ /*assume L1 is up, we'll get DEACTIVATES soon, for non
+ * up L1s*/
+@@ -1384,7 +1410,7 @@
+ }
+ stack->l1link=0;
+ stack->l2link=0;
+-#if 0
++#if 0
+ if (!stack->nt) {
+ misdn_lib_get_short_status(stack);
+ } else {
+@@ -1396,12 +1422,12 @@
+
+ misdn_lib_get_short_status(stack);
+ misdn_lib_get_l1_up(stack);
+- misdn_lib_get_l2_up(stack);
+-
++ misdn_lib_get_l2_up(stack);
++
+ }
+
+ cb_log(8,0,"stack_init: port:%d lowerId:%x upperId:%x\n",stack->port,stack->lower_id, stack->upper_id);
+-
++
+ return stack;
+ }
+
+@@ -1415,11 +1441,11 @@
+ cleanup_Isdnl2(&stack->nst);
+ cleanup_Isdnl3(&stack->nst);
+ }
+-
+- if (stack->lower_id)
++
++ if (stack->lower_id)
+ mISDN_write_frame(stack->midev, buf, stack->lower_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+
+- if (stack->upper_id)
++ if (stack->upper_id)
+ mISDN_write_frame(stack->midev, buf, stack->upper_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+ }
+
+@@ -1427,14 +1453,14 @@
+ static struct misdn_stack * find_stack_by_addr(int addr)
+ {
+ struct misdn_stack *stack;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+ if ( (stack->upper_id&STACK_ID_MASK) == (addr&STACK_ID_MASK)) return stack;
+
+ }
+-
++
+ return NULL;
+ }
+
+@@ -1442,24 +1468,24 @@
+ static struct misdn_stack * find_stack_by_port(int port)
+ {
+ struct misdn_stack *stack;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+- stack=stack->next)
++ stack=stack->next)
+ if (stack->port == port) return stack;
+-
++
+ return NULL;
+ }
+
+ static struct misdn_stack * find_stack_by_mgr(manager_t* mgr_nt)
+ {
+ struct misdn_stack *stack;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+- stack=stack->next)
++ stack=stack->next)
+ if ( &stack->mgr == mgr_nt) return stack;
+-
++
+ return NULL;
+ }
+
+@@ -1506,7 +1532,7 @@
+ }
+ }
+ }
+-
++
+ return NULL;
+ }
+
+@@ -1514,7 +1540,7 @@
+ {
+ struct misdn_stack* stack;
+ int i;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+@@ -1533,14 +1559,14 @@
+ struct misdn_stack* stack=find_stack_by_port(port);
+ int i;
+
+- if (!stack) return NULL;
+-
++ if (!stack) return NULL;
++
+ for (i=0; i<=stack->b_num; i++) {
+ if ( stack->bc[i].channel== channel ) {
+ return &stack->bc[i];
+ }
+ }
+-
++
+ return NULL;
+ }
+
+@@ -1551,16 +1577,23 @@
+ static int handle_event ( struct misdn_bchannel *bc, enum event_e event, iframe_t *frm)
+ {
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+-
++
+ if (!stack->nt) {
+-
++
+ switch (event) {
+
+ case EVENT_CONNECT_ACKNOWLEDGE:
+ 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) );
+ }
+
+@@ -1582,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:
+@@ -1602,12 +1642,12 @@
+
+ if (!bc->channel)
+ cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n");
+- else
++ else
+ cb_log(0, stack->port, "Requested Channel Already in Use releasing this call with cause 34!!!!\n");
+
+ /* when the channel is already in use, we can't
+- * simply clear it, we need to make sure that
+- * it will still be marked as in_use in the
++ * simply clear it, we need to make sure that
++ * it will still be marked as in_use in the
+ * available channels list.*/
+ bc->channel=0;
+
+@@ -1626,7 +1666,7 @@
+ break;
+ }
+ } else { /** NT MODE **/
+-
++
+ }
+ return 0;
+ }
+@@ -1636,7 +1676,7 @@
+ struct misdn_bchannel *bc;
+
+ if (!stack) return -1;
+-
++
+ switch (frm->prim) {
+ case CC_NEW_CR|INDICATION:
+ cb_log(7, stack->port, " --> lib: NEW_CR Ind with l3id:%x on this port.\n",frm->dinfo);
+@@ -1646,7 +1686,7 @@
+ cb_log(0, stack->port, " --> !! lib: No free channel!\n");
+ return -1;
+ }
+-
++
+ cb_log(7, stack->port, " --> new_process: New L3Id: %x\n",frm->dinfo);
+ bc->l3_id=frm->dinfo;
+ return 1;
+@@ -1663,14 +1703,14 @@
+ {
+ struct misdn_bchannel *bc=find_bc_by_l3id(stack, frm->dinfo);
+ struct misdn_bchannel dummybc;
+-
++
+ if (!bc) {
+ 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;
++
++ bc=&dummybc;
+ }
+-
++
+ if (bc) {
+ int channel = bc->channel;
+ cb_log(4, stack->port, " --> lib: CLEANING UP l3id: %x\n",frm->dinfo);
+@@ -1698,15 +1738,15 @@
+ }
+ }
+ else {
+- if (stack->nt)
++ if (stack->nt)
+ cb_log(4, stack->port, "BC with dinfo: %x not found.. (prim was %x and addr %x)\n",frm->dinfo, frm->prim, frm->addr);
+ }
+-
++
+ return 1;
+ }
+ break;
+ }
+-
++
+ return 0;
+ }
+
+@@ -1720,10 +1760,10 @@
+ cb_log(1,0,"misdn_release: No Stack found\n");
+ return;
+ }
+-
+- if (bc->channel>0)
++
++ if (bc->channel>0)
+ empty_chan_in_stack(stack,bc->channel);
+-
++
+ empty_bc(bc);
+ clean_up_bc(bc);
+ bc->in_use=0;
+@@ -1732,21 +1772,21 @@
+
+
+
+-int misdn_lib_get_port_up (int port)
+-{ /* Pull Up L1 */
++int misdn_lib_get_port_up (int port)
++{ /* Pull Up L1 */
+ struct misdn_stack *stack;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+-
++
+ if (stack->port == port) {
+
+ if (!stack->l1link)
+ misdn_lib_get_l1_up(stack);
+ if (!stack->l2link)
+ misdn_lib_get_l2_up(stack);
+-
++
+ return 0;
+ }
+ }
+@@ -1754,8 +1794,8 @@
+ }
+
+
+-int misdn_lib_get_port_down (int port)
+-{ /* Pull Down L1 */
++int misdn_lib_get_port_down (int port)
++{ /* Pull Down L1 */
+ struct misdn_stack *stack;
+ for (stack=glob_mgr->stack_list;
+ stack;
+@@ -1778,7 +1818,7 @@
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+-
++
+ if (stack->port == port) {
+
+ if (stack->blocked) {
+@@ -1805,7 +1845,7 @@
+ }
+ }
+ }
+-
++
+ return -1;
+ }
+
+@@ -1825,7 +1865,7 @@
+ if (!bc) {
+ 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;
++ bc=&dummybc;
+ }
+
+ if (bc) {
+@@ -1858,7 +1898,7 @@
+
+ hh=(mISDNuser_head_t*)msg->data;
+ port=stack->port;
+-
++
+ cb_log(5, stack->port, " --> lib: prim %x dinfo %x\n",hh->prim, hh->dinfo);
+ {
+ switch(hh->prim){
+@@ -1873,7 +1913,7 @@
+ frm.addr=stack->upper_id | FLG_MSG_DOWN;
+
+ frm.prim = CC_NEW_CR|INDICATION;
+-
++
+ if (handle_cr( stack, &frm)< 0) {
+ msg_t *dmsg;
+ cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo);
+@@ -1882,7 +1922,7 @@
+ free_msg(msg);
+ return 0;
+ }
+-
++
+ bc = find_bc_by_l3id(stack, hh->dinfo);
+ hold_bc = stack_holder_find(stack, bc->l3_id);
+ cb_log(4, stack->port, "bc_l3id:%x holded_bc_l3id:%x\n",bc->l3_id, hold_bc->l3_id);
+@@ -1898,17 +1938,17 @@
+ bc->holded=0;
+ bc->b_stid=0;
+ }
+-
++
+ }
+-
++
+ break;
+-
++
+ case CC_SETUP|CONFIRM:
+ {
+ struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
+ int l3id = *((int *)(((u_char *)msg->data)+ mISDNUSER_HEAD_SIZE));
+ cb_log(4, stack->port, " --> lib: Event_ind:SETUP CONFIRM [NT] : new L3ID is %x\n",l3id );
+-
++
+ if (!bc) { cb_log(4, stack->port, "Bc Not found (after SETUP CONFIRM)\n"); return 0; }
+ cb_log (2,bc->port,"I IND :CC_SETUP|CONFIRM: old l3id:%x new l3id:%x\n", bc->l3_id, l3id);
+ bc->l3_id=l3id;
+@@ -1916,11 +1956,11 @@
+ }
+ free_msg(msg);
+ return 0;
+-
++
+ case CC_SETUP|INDICATION:
+ {
+ struct misdn_bchannel* bc=misdn_lib_get_free_bc(stack->port, 0, 1, 0);
+- if (!bc)
++ if (!bc)
+ ERR_NO_CHANNEL:
+ {
+ msg_t *dmsg;
+@@ -1930,7 +1970,7 @@
+ free_msg(msg);
+ return 0;
+ }
+-
++
+ cb_log(4, stack->port, " --> new_process: New L3Id: %x\n",hh->dinfo);
+ bc->l3_id=hh->dinfo;
+ }
+@@ -1938,11 +1978,11 @@
+
+ case CC_CONNECT_ACKNOWLEDGE|INDICATION:
+ break;
+-
++
+ case CC_ALERTING|INDICATION:
+ case CC_PROCEEDING|INDICATION:
+ case CC_SETUP_ACKNOWLEDGE|INDICATION:
+- if(!stack->ptp) break;
++ if(!stack->ptp) break;
+ case CC_CONNECT|INDICATION:
+ break;
+ case CC_DISCONNECT|INDICATION:
+@@ -1950,22 +1990,22 @@
+ struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
+ if (!bc) {
+ bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000);
+- if (bc) {
++ if (bc) {
+ int myprocid=bc->l3_id&0x0000ffff;
+ hh->dinfo=(hh->dinfo&0xffff0000)|myprocid;
+ cb_log(3,stack->port,"Reject dinfo: %x cause:%d\n",hh->dinfo,bc->cause);
+- reject=1;
++ reject=1;
+ }
+ }
+ }
+ break;
+-
++
+ case CC_FACILITY|INDICATION:
+ {
+ struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
+ if (!bc) {
+ bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000);
+- if (bc) {
++ if (bc) {
+ int myprocid=bc->l3_id&0x0000ffff;
+ hh->dinfo=(hh->dinfo&0xffff0000)|myprocid;
+ cb_log(4,bc->port,"Repaired reject Bug, new dinfo: %x\n",hh->dinfo);
+@@ -1973,7 +2013,7 @@
+ }
+ }
+ break;
+-
++
+ case CC_RELEASE_COMPLETE|INDICATION:
+ break;
+
+@@ -1994,13 +2034,13 @@
+ {
+ struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
+
+- if (bc) {
++ if (bc) {
+ cb_log(1, stack->port, "CC_RELEASE|CONFIRM (l3id:%x), sending RELEASE_COMPLETE\n", hh->dinfo);
+ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+ }
+ }
+ break;
+-
++
+ case CC_RELEASE|INDICATION:
+ break;
+
+@@ -2009,7 +2049,7 @@
+ free_msg(msg);
+ return 0 ;
+ break;
+-
++
+ case CC_NEW_CR|INDICATION:
+ /* Got New CR for bchan, for now I handle this one in */
+ /* connect_ack, Need to be changed */
+@@ -2022,36 +2062,36 @@
+ stack->procids[bc->l3_id&0xff] = 0 ;
+ }
+ cb_log(4, stack->port, "lib: Event_ind:CC_NEW_CR : very new L3ID is %x\n",l3id );
+-
++
+ bc->l3_id =l3id;
+ cb_event(EVENT_NEW_L3ID, bc, glob_mgr->user_data);
+-
++
+ free_msg(msg);
+ return 0;
+ }
+-
++
+ case DL_ESTABLISH | INDICATION:
+ case DL_ESTABLISH | CONFIRM:
+ {
+ cb_log(3, stack->port, "%% GOT L2 Activate Info.\n");
+-
++
+ if (stack->ptp && stack->l2link) {
+ cb_log(0, stack->port, "%% GOT L2 Activate Info. but we're activated already.. this l2 is faulty, blocking port\n");
+ cb_event(EVENT_PORT_ALARM, &stack->bc[0], glob_mgr->user_data);
+ }
+
+ if (stack->ptp && !stack->restart_sent) {
+- /* make sure we restart the interface of the
++ /* make sure we restart the interface of the
+ * other side */
+ stack->restart_sent=1;
+ misdn_lib_send_restart(stack->port, -1);
+
+ }
+-
++
+ /* when we get the L2 UP, the L1 is UP definitely too*/
+ stack->l2link = 1;
+ stack->l2upcnt=0;
+-
++
+ free_msg(msg);
+ return 0;
+ }
+@@ -2075,10 +2115,10 @@
+ stack->l2upcnt++;
+ }
+ }
+-
+- } else
++
++ } else
+ cb_log(3, stack->port, "%% GOT L2 DeActivate Info.\n");
+-
++
+ stack->l2link = 0;
+ free_msg(msg);
+ return 0;
+@@ -2086,37 +2126,37 @@
+ break;
+ }
+ }
+-
++
+ {
+ /* Parse Events and fire_up to App. */
+ struct misdn_bchannel *bc;
+ struct misdn_bchannel dummybc;
+-
++
+ enum event_e event = isdn_msg_get_event(msgs_g, msg, 1);
+-
++
+ bc=find_bc_by_l3id(stack, hh->dinfo);
+-
++
+ if (!bc) {
+ 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;
++ bc=&dummybc;
+ }
+ if (bc ) {
+ isdn_msg_parse_event(msgs_g,msg,bc, 1);
+
+ switch (event) {
+ case EVENT_SETUP:
+- if (bc->channel<=0 || bc->channel==0xff)
++ if (bc->channel<=0 || bc->channel==0xff)
+ bc->channel=0;
+-
+- if (find_free_chan_in_stack(stack,bc, bc->channel,0)<0)
++
++ if (find_free_chan_in_stack(stack,bc, bc->channel,0)<0)
+ goto ERR_NO_CHANNEL;
+ break;
+ case EVENT_RELEASE:
+ case EVENT_RELEASE_COMPLETE:
+ {
+ int channel=bc->channel;
+- int tmpcause=bc->cause;
++ int tmpcause=bc->cause;
+ empty_bc(bc);
+ bc->cause=tmpcause;
+ clean_up_bc(bc);
+@@ -2130,7 +2170,7 @@
+ default:
+ break;
+ }
+-
++
+ if(!isdn_get_info(msgs_g,event,1)) {
+ cb_log(4, stack->port, "Unknown Event Ind: prim %x dinfo %x\n",hh->prim, hh->dinfo);
+ } else {
+@@ -2161,8 +2201,8 @@
+ static int handle_timers(msg_t* msg)
+ {
+ iframe_t *frm= (iframe_t*)msg->data;
+- struct misdn_stack *stack;
+-
++ struct misdn_stack *stack;
++
+ /* Timer Stuff */
+ switch (frm->prim) {
+ case MGR_INITTIMER | CONFIRM:
+@@ -2172,17 +2212,17 @@
+ free_msg(msg);
+ return(1);
+ }
+-
+-
+-
++
++
++
+ if (frm->prim==(MGR_TIMER | INDICATION) ) {
+ for (stack = glob_mgr->stack_list;
+ stack;
+ stack = stack->next) {
+ itimer_t *it;
+-
++
+ if (!stack->nt) continue;
+-
++
+ it = stack->nst.tlist;
+ /* find timer */
+ for(it=stack->nst.tlist;
+@@ -2201,12 +2241,12 @@
+ return 1;
+ }
+ }
+-
++
+ cb_log(0, 0, "Timer Msg without Timer ??\n");
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ return 0;
+ }
+
+@@ -2226,23 +2266,23 @@
+ static int do_tone(struct misdn_bchannel *bc, int len)
+ {
+ bc->tone_cnt=len;
+-
++
+ if (bc->generate_tone) {
+ cb_event(EVENT_TONE_GENERATE, bc, glob_mgr->user_data);
+-
++
+ if ( !bc->nojitter ) {
+ misdn_tx_jitter(bc,len);
+ }
+-
++
+ return 1;
+ }
+-
++
+ return 0;
+ }
+
+
+ #ifdef MISDN_SAVE_DATA
+-static void misdn_save_data(int id, char *p1, int l1, char *p2, int l2)
++static void misdn_save_data(int id, char *p1, int l1, char *p2, int l2)
+ {
+ char n1[32],n2[32];
+ FILE *rx, *tx;
+@@ -2250,17 +2290,17 @@
+ sprintf(n1,"/tmp/misdn-rx-%d.raw",id);
+ sprintf(n2,"/tmp/misdn-tx-%d.raw",id);
+
+- rx = fopen(n1,"a+");
++ rx = fopen(n1,"a+");
+ tx = fopen(n2,"a+");
+
+ if (!rx || !tx) {
+ cb_log(0,0,"Couldn't open files: %s\n",strerror(errno));
+ return ;
+ }
+-
++
+ fwrite(p1,1,l1,rx);
+ fwrite(p2,1,l2,tx);
+-
++
+ fclose(rx);
+ fclose(tx);
+
+@@ -2273,25 +2313,25 @@
+ char *data=&buf[mISDN_HEADER_LEN];
+ iframe_t *txfrm= (iframe_t*)buf;
+ int jlen, r;
+-
++
+ jlen=cb_jb_empty(bc,data,len);
+-
++
+ if (jlen) {
+ #ifdef MISDN_SAVE_DATA
+ misdn_save_data((bc->port*100+bc->channel), data, jlen, bc->bframe, bc->bframe_len);
+ #endif
+ flip_buf_bits( data, jlen);
+-
++
+ if (jlen < len) {
+ cb_log(7,bc->port,"Jitterbuffer Underrun.\n");
+ }
+-
++
+ txfrm->prim = DL_DATA|REQUEST;
+-
++
+ txfrm->dinfo = 0;
+-
++
+ txfrm->addr = bc->addr|FLG_MSG_DOWN; /* | IF_DOWN; */
+-
++
+ txfrm->len =jlen;
+ cb_log(9, bc->port, "Transmitting %d samples 2 misdn\n", txfrm->len);
+
+@@ -2332,25 +2372,25 @@
+ iframe_t *frm= (iframe_t*)msg->data;
+ struct misdn_bchannel *bc=find_bc_by_addr(frm->addr);
+ struct misdn_stack *stack;
+-
++
+ if (!bc) {
+ cb_log(1,0,"handle_bchan: BC not found for prim:%x with addr:%x dinfo:%x\n", frm->prim, frm->addr, frm->dinfo);
+ return 0 ;
+ }
+-
++
+ stack = get_stack_by_bc(bc);
+-
++
+ if (!stack) {
+ cb_log(0, bc->port,"handle_bchan: STACK not found for prim:%x with addr:%x dinfo:%x\n", frm->prim, frm->addr, frm->dinfo);
+ return 0;
+ }
+-
++
+ switch (frm->prim) {
+
+ case MGR_SETSTACK| CONFIRM:
+ cb_log(3, stack->port, "BCHAN: MGR_SETSTACK|CONFIRM pid:%d\n",bc->pid);
+ break;
+-
++
+ case MGR_SETSTACK| INDICATION:
+ cb_log(3, stack->port, "BCHAN: MGR_SETSTACK|IND pid:%d\n",bc->pid);
+ break;
+@@ -2363,9 +2403,9 @@
+ usleep(1000);
+ goto AGAIN;
+ }
+-
++
+ cb_log(0,stack->port,"$$$ Get Layer (%d) Id Error: %s\n",bc->layer,strerror(errno));
+-
++
+ /* we kill the channel later, when we received some
+ data. */
+ bc->addr= frm->addr;
+@@ -2373,12 +2413,12 @@
+ cb_log(0, stack->port,"$$$ bc->addr <0 Error:%s\n",strerror(errno));
+ bc->addr=0;
+ }
+-
++
+ cb_log(4, stack->port," --> Got Adr %x\n", bc->addr);
+
+ free_msg(msg);
+-
+-
++
++
+ switch(bc->bc_state) {
+ case BCHAN_SETUP:
+ bc_state_change(bc,BCHAN_SETUPED);
+@@ -2395,31 +2435,31 @@
+ case MGR_DELLAYER| INDICATION:
+ cb_log(3, stack->port, "BCHAN: MGR_DELLAYER|IND pid:%d\n",bc->pid);
+ break;
+-
++
+ case MGR_DELLAYER| CONFIRM:
+ cb_log(3, stack->port, "BCHAN: MGR_DELLAYER|CNF pid:%d\n",bc->pid);
+-
++
+ bc->pid=0;
+ bc->addr=0;
+-
++
+ free_msg(msg);
+ return 1;
+-
++
+ case PH_ACTIVATE | INDICATION:
+ case DL_ESTABLISH | INDICATION:
+ cb_log(3, stack->port, "BCHAN: ACT Ind pid:%d\n", bc->pid);
+
+ free_msg(msg);
+- return 1;
++ return 1;
+
+ case PH_ACTIVATE | CONFIRM:
+ case DL_ESTABLISH | CONFIRM:
+-
++
+ cb_log(3, stack->port, "BCHAN: bchan ACT Confirm pid:%d\n",bc->pid);
+ free_msg(msg);
+-
+- return 1;
+
++ return 1;
++
+ case DL_ESTABLISH | REQUEST:
+ {
+ char buf[128];
+@@ -2435,33 +2475,40 @@
+ }
+ free_msg(msg);
+ return 1;
+-
++
+ case PH_DEACTIVATE | INDICATION:
+ case DL_RELEASE | INDICATION:
+ cb_log (3, stack->port, "BCHAN: DeACT Ind pid:%d\n",bc->pid);
+-
++
+ free_msg(msg);
+ return 1;
+-
++
+ case PH_DEACTIVATE | CONFIRM:
+ case DL_RELEASE | CONFIRM:
+ cb_log(3, stack->port, "BCHAN: DeACT Conf pid:%d\n",bc->pid);
+-
++
+ free_msg(msg);
+ return 1;
+-
++
+ case PH_CONTROL|INDICATION:
+ {
+ 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;
+ cb_log(4, stack->port, " --> DTMF TONE: %c\n",dtmf);
+ bc->dtmf=dtmf;
+ cb_event(EVENT_DTMF_TONE, bc, glob_mgr->user_data);
+-
++
+ free_msg(msg);
+ return 1;
+ }
+@@ -2482,11 +2529,11 @@
+ case DL_DATA|REQUEST:
+ cb_log(0, stack->port, "DL_DATA REQUEST \n");
+ do_tone(bc, 64);
+-
++
+ free_msg(msg);
+ return 1;
+-
+-
++
++
+ case PH_DATA|INDICATION:
+ case DL_DATA|INDICATION:
+ {
+@@ -2494,10 +2541,10 @@
+ bc->bframe_len = frm->len;
+
+ /** Anyway flip the bufbits **/
+- if ( misdn_cap_is_speech(bc->capability) )
++ if ( misdn_cap_is_speech(bc->capability) )
+ flip_buf_bits(bc->bframe, bc->bframe_len);
+-
+
++
+ if (!bc->bframe_len) {
+ cb_log(2, stack->port, "DL_DATA INDICATION bc->addr:%x frm->addr:%x\n", bc->addr, frm->addr);
+ free_msg(msg);
+@@ -2509,12 +2556,12 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ #if MISDN_DEBUG
+ cb_log(0, stack->port, "DL_DATA INDICATION Len %d\n", frm->len);
+
+ #endif
+-
++
+ if ( (bc->bc_state == BCHAN_ACTIVATED) && frm->len > 0) {
+ int t;
+
+@@ -2528,7 +2575,7 @@
+ #endif
+ if ( !t ) {
+ int i;
+-
++
+ if ( misdn_cap_is_speech(bc->capability)) {
+ if ( !bc->nojitter ) {
+ #ifdef MISDN_B_DEBUG
+@@ -2541,15 +2588,15 @@
+ }
+ }
+
+-#ifdef MISDN_B_DEBUG
++#ifdef MISDN_B_DEBUG
+ cb_log(0,bc->port,"EVENT_B_DATA START\n");
+ #endif
+-
++
+ i = cb_event(EVENT_BCHAN_DATA, bc, glob_mgr->user_data);
+-#ifdef MISDN_B_DEBUG
++#ifdef MISDN_B_DEBUG
+ cb_log(0,bc->port,"EVENT_B_DATA STOP\n");
+ #endif
+-
++
+ if (i<0) {
+ cb_log(10,stack->port,"cb_event returned <0\n");
+ /*clean_up_bc(bc);*/
+@@ -2582,7 +2629,7 @@
+ #endif
+ break;
+ }
+-
++
+ return 0;
+ }
+
+@@ -2596,29 +2643,29 @@
+
+ stack=find_stack_by_addr( frm->addr );
+
+-
+-
++
++
+ if (!stack || !stack->nt) {
+ return 0;
+ }
+
+-
++
+ if ((err=stack->nst.l1_l2(&stack->nst,msg))) {
+-
++
+ if (nt_err_cnt > 0 ) {
+ if (nt_err_cnt < 100) {
+- nt_err_cnt++;
++ nt_err_cnt++;
+ cb_log(0, stack->port, "NT Stack sends us error: %d \n", err);
+ } else if (nt_err_cnt < 105){
+ cb_log(0, stack->port, "NT Stack sends us error: %d over 100 times, so I'll stop this message\n", err);
+- nt_err_cnt = - 1;
++ nt_err_cnt = - 1;
+ }
+ }
+ free_msg(msg);
+ return 1;
+-
++
+ }
+-
++
+ return 1;
+ }
+
+@@ -2626,13 +2673,13 @@
+ static int handle_frm(msg_t *msg)
+ {
+ iframe_t *frm = (iframe_t*) msg->data;
+-
++
+ struct misdn_stack *stack=find_stack_by_addr(frm->addr);
+
+ if (!stack || stack->nt) {
+ return 0;
+ }
+-
++
+ cb_log(4,stack?stack->port:0,"handle_frm: frm->addr:%x frm->prim:%x\n",frm->addr,frm->prim);
+
+ {
+@@ -2650,7 +2697,7 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ bc=find_bc_by_l3id(stack, frm->dinfo);
+
+ if (!bc && (frm->prim==(CC_RESTART|CONFIRM)) ) {
+@@ -2670,15 +2717,15 @@
+ return 1;
+ }
+
+-
++
+ handle_frm_bc:
+ if (bc ) {
+ enum event_e event = isdn_msg_get_event(msgs_g, msg, 0);
+ enum event_response_e response=RESPONSE_OK;
+ int ret;
+-
++
+ isdn_msg_parse_event(msgs_g,msg,bc, 0);
+-
++
+ /** Preprocess some Events **/
+ ret = handle_event(bc, event, frm);
+ if (ret<0) {
+@@ -2688,8 +2735,8 @@
+ }
+ /* shoot up event to App: */
+ cb_log(5, stack->port, "lib Got Prim: Addr %x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo);
+-
+- if(!isdn_get_info(msgs_g,event,0))
++
++ if(!isdn_get_info(msgs_g,event,0))
+ cb_log(0, stack->port, "Unknown Event Ind: Addr:%x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo);
+ else
+ response=cb_event(event, bc, glob_mgr->user_data);
+@@ -2698,13 +2745,13 @@
+ switch (response) {
+ case RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE:
+
+- cb_log(0, stack->port, "TOTALLY 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 = AST_CAUSE_NORMAL_CLEARING;
+-
++
+ case RESPONSE_RELEASE_SETUP:
+ misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
+ if (bc->channel>0)
+@@ -2718,7 +2765,7 @@
+ case RESPONSE_OK:
+ cb_log(4, stack->port, "GOT SETUP OK\n");
+
+-
++
+ break;
+ default:
+ break;
+@@ -2728,13 +2775,13 @@
+ if (event == EVENT_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;
++ int tmpcause=bc->cause;
++ int tmp_out_cause=bc->out_cause;
+ empty_bc(bc);
+ bc->cause=tmpcause;
+ bc->out_cause=tmp_out_cause;
+ clean_up_bc(bc);
+-
++
+ 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 <port> <channel>'\n");
+@@ -2755,11 +2802,11 @@
+
+ cb_log(5, stack->port, "Freeing Msg on prim:%x \n",frm->prim);
+
+-
++
+ free_msg(msg);
+ return 1;
+ #endif
+-
++
+ } else {
+ struct misdn_bchannel dummybc;
+ if (frm->prim!=(CC_FACILITY|INDICATION))
+@@ -2770,7 +2817,7 @@
+ memset (&dummybc,0,sizeof(dummybc));
+ dummybc.port=stack->port;
+ dummybc.l3_id=frm->dinfo;
+- bc=&dummybc;
++ bc=&dummybc;
+ goto handle_frm_bc;
+ }
+ }
+@@ -2785,7 +2832,7 @@
+ iframe_t *frm = (iframe_t*) msg->data;
+ struct misdn_stack *stack = find_stack_by_addr(frm->addr);
+ int i ;
+-
++
+ if (!stack) return 0 ;
+
+ switch (frm->prim) {
+@@ -2793,9 +2840,9 @@
+ case PH_ACTIVATE | INDICATION:
+ cb_log (3, stack->port, "L1: PH L1Link Up!\n");
+ stack->l1link=1;
+-
++
+ if (stack->nt) {
+-
++
+ if (stack->nst.l1_l2(&stack->nst, msg))
+ free_msg(msg);
+
+@@ -2804,14 +2851,14 @@
+ } else {
+ free_msg(msg);
+ }
+-
++
+ for (i=0;i<=stack->b_num; i++) {
+ if (stack->bc[i].evq != EVENT_NOTHING) {
+ 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;
+ }
+-
++
+ }
+ return 1;
+
+@@ -2819,16 +2866,16 @@
+ free_msg(msg);
+ cb_log(3,stack->port,"L1: PH_ACTIVATE|REQUEST \n");
+ return 1;
+-
++
+ case PH_DEACTIVATE | REQUEST:
+ free_msg(msg);
+ cb_log(3,stack->port,"L1: PH_DEACTIVATE|REQUEST \n");
+ return 1;
+-
++
+ case PH_DEACTIVATE | CONFIRM:
+ case PH_DEACTIVATE | INDICATION:
+ cb_log (3, stack->port, "L1: PH L1Link Down! \n");
+-
++
+ #if 0
+ for (i=0; i<=stack->b_num; i++) {
+ if (global_state == MISDN_INITIALIZED) {
+@@ -2836,19 +2883,19 @@
+ }
+ }
+ #endif
+-
++
+ if (stack->nt) {
+ if (stack->nst.l1_l2(&stack->nst, msg))
+ free_msg(msg);
+ } else {
+ free_msg(msg);
+ }
+-
++
+ stack->l1link=0;
+ stack->l2link=0;
+ return 1;
+ }
+-
++
+ return 0;
+ }
+
+@@ -2857,11 +2904,11 @@
+ iframe_t *frm = (iframe_t*) msg->data;
+
+ struct misdn_stack *stack = find_stack_by_addr(frm->addr);
+-
++
+ if (!stack) {
+ return 0 ;
+ }
+-
++
+ switch(frm->prim) {
+
+ case DL_ESTABLISH | REQUEST:
+@@ -2870,13 +2917,13 @@
+ case DL_RELEASE | REQUEST:
+ cb_log(1,stack->port,"DL_RELEASE|REQUEST \n");
+ return 1;
+-
++
+ case DL_ESTABLISH | INDICATION:
+ case DL_ESTABLISH | CONFIRM:
+ {
+ cb_log (3, stack->port, "L2: L2Link Up! \n");
+ if (stack->ptp && stack->l2link) {
+- cb_log (-1, stack->port, "L2: L2Link Up! but it's already UP.. must be faulty, blocking port\n");
++ cb_log (-1, stack->port, "L2: L2Link Up! but it's already UP.. must be faulty, blocking port\n");
+ cb_event(EVENT_PORT_ALARM, &stack->bc[0], glob_mgr->user_data);
+ }
+ stack->l2link=1;
+@@ -2884,13 +2931,13 @@
+ return 1;
+ }
+ break;
+-
++
+ case DL_RELEASE | INDICATION:
+ case DL_RELEASE | CONFIRM:
+ {
+ cb_log (3, stack->port, "L2: L2Link Down! \n");
+ stack->l2link=0;
+-
++
+ free_msg(msg);
+ return 1;
+ }
+@@ -2909,9 +2956,9 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ stack = find_stack_by_addr(frm->addr);
+-
++
+ if (!stack) {
+ if (frm->prim == (MGR_DELLAYER|CONFIRM)) {
+ cb_log(2, 0, "MGMT: DELLAYER|CONFIRM Addr: %x !\n",
+@@ -2919,20 +2966,20 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ return 0;
+ }
+-
++
+ switch(frm->prim) {
+ case MGR_SHORTSTATUS | INDICATION:
+ case MGR_SHORTSTATUS | CONFIRM:
+ cb_log(5, 0, "MGMT: Short status dinfo %x\n",frm->dinfo);
+-
++
+ switch (frm->dinfo) {
+ case SSTATUS_L1_ACTIVATED:
+ cb_log(3, 0, "MGMT: SSTATUS: L1_ACTIVATED \n");
+ stack->l1link=1;
+-
++
+ break;
+ case SSTATUS_L1_DEACTIVATED:
+ cb_log(3, 0, "MGMT: SSTATUS: L1_DEACTIVATED \n");
+@@ -2946,16 +2993,16 @@
+ cb_log(3, stack->port, "MGMT: SSTATUS: L2_ESTABLISH \n");
+ stack->l2link=1;
+ break;
+-
++
+ case SSTATUS_L2_RELEASED:
+ cb_log(3, stack->port, "MGMT: SSTATUS: L2_RELEASED \n");
+ stack->l2link=0;
+ break;
+ }
+-
++
+ free_msg(msg);
+ return 1;
+-
++
+ case MGR_SETSTACK | INDICATION:
+ cb_log(4, stack->port, "MGMT: SETSTACK|IND dinfo %x\n",frm->dinfo);
+ free_msg(msg);
+@@ -2964,21 +3011,21 @@
+ cb_log(4, stack->port, "MGMT: DELLAYER|CNF dinfo %x\n",frm->dinfo) ;
+ free_msg(msg);
+ return 1;
+-
++
+ }
+-
++
+ /*
+ if ( (frm->prim & 0x0f0000) == 0x0f0000) {
+ cb_log(5, 0, "$$$ MGMT FRAME: prim %x addr %x dinfo %x\n",frm->prim, frm->addr, frm->dinfo) ;
+ free_msg(msg);
+ return 1;
+ } */
+-
++
+ return 0;
+ }
+
+
+-static msg_t *fetch_msg(int midev)
++static msg_t *fetch_msg(int midev)
+ {
+ msg_t *msg=alloc_msg(MAX_MSG_SIZE);
+ int r;
+@@ -2991,7 +3038,7 @@
+ AGAIN:
+ r=mISDN_read(midev,msg->data,MAX_MSG_SIZE, TIMEOUT_10SEC);
+ msg->len=r;
+-
++
+ if (r==0) {
+ free_msg(msg); /* danger, cause usually freeing in main_loop */
+ cb_log(6,0,"Got empty Msg..\n");
+@@ -3005,8 +3052,8 @@
+ usleep(5000);
+ goto AGAIN;
+ }
+-
+- cb_log(0,0,"mISDN_read returned :%d error:%s (%d)\n",r,strerror(errno),errno);
++
++ cb_log(0,0,"mISDN_read returned :%d error:%s (%d)\n",r,strerror(errno),errno);
+ }
+
+ #if 0
+@@ -3024,12 +3071,12 @@
+ ;
+
+ if (stack) {
+- cb_log(4, port, "Checking L1 State\n");
++ cb_log(4, port, "Checking L1 State\n");
+ if (!stack->l1link) {
+- cb_log(4, port, "L1 State Down, trying to get it up again\n");
++ cb_log(4, port, "L1 State Down, trying to get it up again\n");
+ misdn_lib_get_short_status(stack);
+- misdn_lib_get_l1_up(stack);
+- misdn_lib_get_l2_up(stack);
++ misdn_lib_get_l1_up(stack);
++ misdn_lib_get_l2_up(stack);
+ }
+ }
+ }
+@@ -3041,19 +3088,19 @@
+ int zero_frm=0 , fff_frm=0 ;
+ int midev= mgr->midev;
+ int port=0;
+-
++
+ while (1) {
+- msg_t *msg = fetch_msg(midev);
++ msg_t *msg = fetch_msg(midev);
+ iframe_t *frm;
+-
+-
++
++
+ if (!msg) continue;
+-
++
+ frm = (iframe_t*) msg->data;
+-
++
+ /** 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++;
++ zero_frm++;
+ free_msg(msg);
+ continue;
+ } else {
+@@ -3062,10 +3109,10 @@
+ zero_frm = 0 ;
+ }
+ }
+-
++
+ /** I get this sometimes after setup_bc **/
+ if (frm->len == 0 && frm->dinfo == 0 && frm->prim == 0xffffffff ) {
+- fff_frm++;
++ fff_frm++;
+ free_msg(msg);
+ continue;
+ } else {
+@@ -3074,7 +3121,7 @@
+ fff_frm = 0 ;
+ }
+ }
+-
++
+ manager_isdn_handler(frm, msg);
+ }
+
+@@ -3090,24 +3137,24 @@
+ int ret;
+
+ if (midev<=0) return midev;
+-
++
+ /* create entity for layer 3 TE-mode */
+ mISDN_write_frame(midev, buff, 0, MGR_NEWENTITY | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+ ret = mISDN_read_frame(midev, frm, sizeof(iframe_t), 0, MGR_NEWENTITY | CONFIRM, TIMEOUT_1SEC);
+-
++
+ if (ret < mISDN_HEADER_LEN) {
+ noentity:
+ fprintf(stderr, "cannot request MGR_NEWENTITY from mISDN: %s\n",strerror(errno));
+ exit(-1);
+ }
+-
++
+ entity = frm->dinfo & 0xffff ;
+-
++
+ if (!entity)
+ goto noentity;
+
+ return midev;
+-
++
+ }
+
+ void te_lib_destroy(int midev)
+@@ -3131,14 +3178,14 @@
+ {
+ struct misdn_stack *stack;
+ int i;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+ for (i=0; i<=stack->b_num; i++)
+ if (stack->bc[i].pid == pid) return &stack->bc[i];
+ }
+-
++
+ return NULL;
+ }
+
+@@ -3159,12 +3206,12 @@
+ cb_log(2,bc->port, "channel with stid:%x for one second still in use! (n:%d lu:%d)\n", bc->b_stid, (int) now.tv_sec, (int) bc->last_used.tv_sec);
+ return 1;
+ }
+-
+
++
+ cb_log(3,bc->port, "channel with stid:%x not in use!\n", bc->b_stid);
+ return 0;
+ }
+-
++
+ cb_log(2,bc->port, "channel with stid:%x in use!\n", bc->b_stid);
+ return 1;
+ }
+@@ -3194,7 +3241,7 @@
+ {
+ struct misdn_stack *stack;
+ int i;
+-
++
+ if (channel < 0 || channel > MAX_BCHANS) {
+ cb_log(0,port,"Requested channel out of bounds (%d)\n",channel);
+ return NULL;
+@@ -3203,7 +3250,7 @@
+ usleep(1000);
+
+ for (stack=glob_mgr->stack_list; stack; stack=stack->next) {
+-
++
+ if (stack->port == port) {
+ int maxnum;
+
+@@ -3211,12 +3258,12 @@
+ cb_log(0,port,"Port is blocked\n");
+ return NULL;
+ }
+-
++
+ if (channel > 0) {
+ if (channel <= stack->b_num) {
+ for (i = 0; i < stack->b_num; i++) {
+ if ( stack->bc[i].channel == channel) {
+- if (test_inuse(&stack->bc[i])) {
++ if (test_inuse(&stack->bc[i])) {
+ cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port);
+ return NULL;
+
+@@ -3240,7 +3287,7 @@
+ /* 3. channel on bri means CW*/
+ if (!stack->pri && i==stack->b_num)
+ stack->bc[i].cw=1;
+-
++
+ prepare_bc(&stack->bc[i], channel);
+ stack->bc[i].dec=1;
+ return &stack->bc[i];
+@@ -3268,10 +3315,6 @@
+ return NULL;
+ }
+
+-
+-
+-
+-/* ******************************************************************* */
+ /*!
+ * \internal
+ * \brief Convert the facility function enum value into a string.
+@@ -3280,36 +3323,30 @@
+ */
+ static const char *fac2str(enum FacFunction facility)
+ {
+- static const struct {
+- enum FacFunction facility;
++ static const struct {
++ enum FacFunction facility;
+ char *name;
+ } arr[] = {
+ /* *INDENT-OFF* */
+ { Fac_None, "Fac_None" },
+- { Fac_GetSupportedServices, "Fac_GetSupportedServices" },
+- { Fac_Listen, "Fac_Listen" },
+- { Fac_Suspend, "Fac_Suspend" },
+- { Fac_Resume, "Fac_Resume" },
+ { Fac_CFActivate, "Fac_CFActivate" },
+ { Fac_CFDeactivate, "Fac_CFDeactivate" },
+- { Fac_CFInterrogateParameters, "Fac_CFInterrogateParameters" },
+- { Fac_CFInterrogateNumbers, "Fac_CFInterrogateNumbers" },
+ { Fac_CD, "Fac_CD" },
+ { Fac_AOCDCurrency, "Fac_AOCDCurrency" },
+ { Fac_AOCDChargingUnit, "Fac_AOCDChargingUnit" },
+ /* *INDENT-ON* */
+ };
+-
++
+ unsigned index;
+-
++
+ 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)
+ {
+@@ -3321,27 +3358,57 @@
+
+ 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,
+- " --> 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:' '
+- );
+-
++ " --> 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 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));
+
+ cb_log(5, stack->port, " --> urate:%d rate:%d mode:%d user1:%d\n", bc->urate, bc->rate, bc->mode,bc->user1);
+-
++
+ cb_log(5, stack->port, " --> bc:%p h:%d sh:%d\n", bc, bc->holded, bc->stack_holder);
+ }
+
+@@ -3364,19 +3431,24 @@
+
+ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
+ {
+- msg_t *msg;
++ msg_t *msg;
+ int retval=0;
+ struct misdn_stack *stack;
+-
++
+ if (!bc) RETURN(-1,OUT_POST_UNLOCK);
+-
++
+ 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);
+
+
+@@ -3389,11 +3461,17 @@
+ misdn_lib_get_l1_up(stack);
+ 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);
+-
++
+ switch (event) {
+ case EVENT_SETUP:
+ if (create_process(glob_mgr->midev, bc)<0) {
+@@ -3431,19 +3509,26 @@
+ 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) );
+ }
+-
++
+ if (!bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0);
+ manager_ec_enable(bc);
+-
++
+ if (bc->txgain != 0) {
+ cb_log(4, stack->port, "--> Changing txgain to %d\n", bc->txgain);
+ manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain);
+ }
+-
++
+ if ( bc->rxgain != 0 ) {
+ cb_log(4, stack->port, "--> Changing rxgain to %d\n", bc->rxgain);
+ manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain);
+@@ -3466,7 +3551,7 @@
+ bc_state_change(holded_bc,BCHAN_CLEANED);
+
+ stack_holder_add(stack,holded_bc);
+-
++
+ /*kill the bridge and clean the bchannel*/
+ if (stack->nt) {
+ int channel;
+@@ -3481,7 +3566,7 @@
+ misdn_split_conf(bc2,bc->conf_id);
+ }
+ }
+-
++
+ channel = bc->channel;
+
+ empty_bc(bc);
+@@ -3490,9 +3575,9 @@
+ if (channel>0)
+ empty_chan_in_stack(stack,channel);
+
+- bc->in_use=0;
++ bc->in_use=0;
+ }
+-
++
+ }
+ break;
+
+@@ -3502,7 +3587,7 @@
+ cb_log(0,bc->port," --> we have already send Disconnect\n");
+ RETURN(-1,OUT);
+ }
+-
++
+ bc->need_disconnect=0;
+ break;
+ case EVENT_RELEASE:
+@@ -3526,30 +3611,30 @@
+ /*create cleanup in TE*/
+ int channel=bc->channel;
+
+- int tmpcause=bc->cause;
+- int tmp_out_cause=bc->out_cause;
++ int tmpcause=bc->cause;
++ int tmp_out_cause=bc->out_cause;
+ empty_bc(bc);
+ bc->cause=tmpcause;
+ bc->out_cause=tmp_out_cause;
+ clean_up_bc(bc);
+-
++
+ if (channel>0)
+ empty_chan_in_stack(stack,channel);
+-
++
+ bc->in_use=0;
+ }
+ break;
+-
++
+ case EVENT_CONNECT_ACKNOWLEDGE:
+
+ if ( bc->nt || misdn_cap_is_speech(bc->capability)) {
+ int retval=setup_bc(bc);
+ if (retval == -EINVAL){
+ cb_log(0,bc->port,"send_event: setup_bc failed\n");
+-
++
+ }
+ }
+-
++
+ if (misdn_cap_is_speech(bc->capability)) {
+ if ( !bc->nodsp) manager_ph_control(bc, DTMF_TONE_START, 0);
+ manager_ec_enable(bc);
+@@ -3564,21 +3649,32 @@
+ }
+ }
+ break;
+-
++
+ default:
+ break;
+ }
+-
++
+ /* 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);
+
+ OUT_POST_UNLOCK:
+- return retval;
++ return retval;
+ }
+
+
+@@ -3596,12 +3692,12 @@
+ cb_log(0,0,"mISDN Msg without Address pr:%x dinfo:%x (already more than 100 of them)\n",frm->prim,frm->dinfo);
+ cnt=0;
+ }
+-
++
+ free_msg(msg);
+ return 1;
+-
++
+ }
+-
++
+ switch (frm->prim) {
+ case MGR_SETSTACK|INDICATION:
+ return handle_bchan(msg);
+@@ -3609,7 +3705,7 @@
+
+ case MGR_SETSTACK|CONFIRM:
+ case MGR_CLEARSTACK|CONFIRM:
+- free_msg(msg) ;
++ free_msg(msg) ;
+ return 1;
+ break;
+
+@@ -3630,13 +3726,13 @@
+ struct misdn_bchannel *bc;
+
+ /*we flush the read buffer here*/
+-
++
+ cb_log(9,0,"BCHAN DATA without BC: addr:%x port:%d channel:%d\n",frm->addr, port,channel);
+-
+- free_msg(msg);
++
++ free_msg(msg);
+ return 1;
+-
+-
++
++
+ bc = find_bc_by_channel(port, channel);
+
+ if (!bc) {
+@@ -3647,7 +3743,7 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ cb_log(0,0," --> bc not found by channel\n");
+ if (stack->l2link)
+ misdn_lib_get_l2_down(stack);
+@@ -3658,7 +3754,7 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ cb_log(3,port," --> BC in state:%s\n", bc_state2str(bc->bc_state));
+ }
+ }
+@@ -3673,7 +3769,7 @@
+ struct misdn_stack *stack;
+ stack=find_stack_by_addr( frm->addr );
+
+-
++
+ if (!stack) {
+ return 0;
+ }
+@@ -3685,7 +3781,7 @@
+ #endif
+
+ int manager_isdn_handler(iframe_t *frm ,msg_t *msg)
+-{
++{
+
+ if (frm->dinfo==0xffffffff && frm->prim==(PH_DATA|CONFIRM)) {
+ cb_log(0,0,"SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n");
+@@ -3696,35 +3792,35 @@
+ if (handle_bchan(msg)) {
+ return 0 ;
+ }
+-
++
+ if (unhandled_bmsg_count==1000) {
+- cb_log(0, 0, "received 1k Unhandled Bchannel Messages: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo);
++ cb_log(0, 0, "received 1k Unhandled Bchannel Messages: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo);
+ unhandled_bmsg_count=0;
+ }
+
+ unhandled_bmsg_count++;
+ free_msg(msg);
+ return 0;
+- }
++ }
+
+ #ifdef RECV_FRM_SYSLOG_DEBUG
+ syslog(LOG_NOTICE,"mISDN recv: P(%02d): ADDR:%x PRIM:%x DINFO:%x\n",stack->port, frm->addr, frm->prim, frm->dinfo);
+ #endif
+
+- if (handle_timers(msg))
++ if (handle_timers(msg))
+ return 0 ;
+
+-
+- if (handle_mgmt(msg))
+- return 0 ;
+-
+- if (handle_l2(msg))
++
++ if (handle_mgmt(msg))
+ return 0 ;
+
++ if (handle_l2(msg))
++ return 0 ;
++
+ /* Its important to handle l1 AFTER l2 */
+- if (handle_l1(msg))
++ if (handle_l1(msg))
+ return 0 ;
+-
++
+ if (handle_frm_nt(msg)) {
+ return 0;
+ }
+@@ -3737,10 +3833,10 @@
+ return 0 ;
+ }
+
+- cb_log(0, 0, "Unhandled Message: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo);
++ cb_log(0, 0, "Unhandled Message: prim %x len %d from addr %x, dinfo %x on this port.\n",frm->prim, frm->len, frm->addr, frm->dinfo);
+ free_msg(msg);
+-
+
++
+ return 0;
+ }
+
+@@ -3768,16 +3864,16 @@
+
+ frm->dinfo = 0;
+ frm->len = 0;
+-
++
+ msg_queue_tail(&glob_mgr->activatequeue, msg);
+ sem_post(&glob_mgr->new_msg);
+
+-
+- return 0;
++
++ return 0;
+ }
+
+
+-int queue_cleanup_bc(struct misdn_bchannel *bc)
++int queue_cleanup_bc(struct misdn_bchannel *bc)
+ {
+ msg_t *msg=alloc_msg(MAX_MSG_SIZE);
+ iframe_t *frm;
+@@ -3794,15 +3890,15 @@
+
+ frm->dinfo = bc->port;
+ frm->len = 0;
+-
++
+ msg_queue_tail(&glob_mgr->activatequeue, msg);
+ sem_post(&glob_mgr->new_msg);
+
+- return 0;
++ return 0;
+
+ }
+
+-int misdn_lib_pid_restart(int pid)
++int misdn_lib_pid_restart(int pid)
+ {
+ struct misdn_bchannel *bc=manager_find_bc_by_pid(pid);
+
+@@ -3819,7 +3915,7 @@
+ struct misdn_bchannel dummybc;
+ /*default is all channels*/
+ cb_log(0, port, "Sending Restarts on this port.\n");
+-
++
+ misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
+
+ /*default is all channels*/
+@@ -3855,11 +3951,11 @@
+ int misdn_lib_port_restart(int port)
+ {
+ struct misdn_stack *stack=find_stack_by_port(port);
+-
++
+ cb_log(0, port, "Restarting this port.\n");
+ if (stack) {
+ cb_log(0, port, "Stack:%p\n",stack);
+-
++
+ clear_l3(stack);
+ {
+ msg_t *msg=alloc_msg(MAX_MSG_SIZE);
+@@ -3869,7 +3965,7 @@
+ cb_log(0, port, "port_restart: alloc_msg failed\n");
+ return -1;
+ }
+-
++
+ frm=(iframe_t*)msg->data;
+ /* we must activate if we are deactivated */
+ /* activate bchannel */
+@@ -3884,7 +3980,7 @@
+
+ if (stack->nt)
+ misdn_lib_reinit_nt_stack(stack->port);
+-
++
+ }
+
+ return 0;
+@@ -3892,25 +3988,25 @@
+
+
+
+-static sem_t handler_started;
++static sem_t handler_started;
+
+ /* This is a thread */
+ static void manager_event_handler(void *arg)
+ {
+- sem_post(&handler_started);
++ sem_post(&handler_started);
+ while (1) {
+ struct misdn_stack *stack;
+ msg_t *msg;
+-
++
+ /** wait for events **/
+ sem_wait(&glob_mgr->new_msg);
+-
++
+ for (msg=msg_dequeue(&glob_mgr->activatequeue);
+ msg;
+ msg=msg_dequeue(&glob_mgr->activatequeue)
+ )
+ {
+-
++
+ iframe_t *frm = (iframe_t*) msg->data ;
+
+ switch ( frm->prim) {
+@@ -3925,7 +4021,7 @@
+ free_msg(msg);
+ break;
+ }
+-
++
+ bc = find_bc_by_l3id(stack, frm->addr);
+ if (bc) {
+ cb_log(1,bc->port,"CLEARSTACK queued, cleaning up\n");
+@@ -3934,7 +4030,7 @@
+ cb_log(0,stack->port,"bc could not be cleaned correctly !! addr [%x]\n",frm->addr);
+ }
+ }
+- free_msg(msg);
++ free_msg(msg);
+ break;
+ case MGR_SETSTACK | REQUEST :
+ /* Warning: memory leak here if we get this message */
+@@ -3947,10 +4043,10 @@
+
+ for (stack=glob_mgr->stack_list;
+ stack;
+- stack=stack->next ) {
++ stack=stack->next ) {
+
+ while ( (msg=msg_dequeue(&stack->upqueue)) ) {
+- /** Handle L2/3 Signalling after bchans **/
++ /** Handle L2/3 Signalling after bchans **/
+ if (!handle_frm_nt(msg)) {
+ /* Maybe it's TE */
+ if (!handle_frm(msg)) {
+@@ -3960,16 +4056,16 @@
+ }
+ }
+
+- /* Here we should check if we really want to
+- send all the messages we've queued, lets
+- assume we've queued a Disconnect, but
++ /* Here we should check if we really want to
++ send all the messages we've queued, lets
++ assume we've queued a Disconnect, but
+ received it already from the other side!*/
+-
++
+ while ( (msg=msg_dequeue(&stack->downqueue)) ) {
+ if (stack->nt ) {
+ if (stack->nst.manager_l3(&stack->nst, msg))
+ cb_log(0, stack->port, "Error@ Sending Message in NT-Stack.\n");
+-
++
+ } else {
+ iframe_t *frm = (iframe_t *)msg->data;
+ struct misdn_bchannel *bc = find_bc_by_l3id(stack, frm->dinfo);
+@@ -3998,14 +4094,14 @@
+
+ int i = mISDN_open();
+ int max=0;
+-
++
+ if (i<0)
+ return -1;
+
+ max = mISDN_get_stack_count(i);
+-
++
+ mISDN_close(i);
+-
++
+ return max;
+ }
+
+@@ -4022,12 +4118,12 @@
+ #endif
+ }
+
+-void misdn_lib_nt_debug_init( int flags, char *file )
++void misdn_lib_nt_debug_init( int flags, char *file )
+ {
+ static int init=0;
+ char *f;
+-
+- if (!flags)
++
++ if (!flags)
+ f=NULL;
+ else
+ f=file;
+@@ -4048,50 +4144,50 @@
+ char plist[1024];
+ int midev;
+ int port_count=0;
+-
++
+ cb_log = iface->cb_log;
+ cb_event = iface->cb_event;
+ cb_jb_empty = iface->cb_jb_empty;
+-
++
+ glob_mgr = mgr;
+-
++
+ msg_init();
+
+ misdn_lib_nt_debug_init(0,NULL);
+-
++
+ if (!portlist || (*portlist == 0) ) return 1;
+-
++
+ init_flip_bits();
+-
++
+ {
+ strncpy(plist,portlist, 1024);
+ plist[1023] = 0;
+ }
+-
++
+ memcpy(tone_425_flip,tone_425,TONE_425_SIZE);
+ flip_buf_bits(tone_425_flip,TONE_425_SIZE);
+
+ memcpy(tone_silence_flip,tone_SILENCE,TONE_SILENCE_SIZE);
+ flip_buf_bits(tone_silence_flip,TONE_SILENCE_SIZE);
+-
++
+ midev=te_lib_init();
+ mgr->midev=midev;
+
+ port_count=mISDN_get_stack_count(midev);
+-
++
+ msg_queue_init(&mgr->activatequeue);
+-
++
+ if (sem_init(&mgr->new_msg, 1, 0)<0)
+ sem_init(&mgr->new_msg, 0, 0);
+-
++
+ for (tok=strtok_r(plist," ,",&tokb );
+- tok;
++ tok;
+ tok=strtok_r(NULL," ,",&tokb)) {
+ int port = atoi(tok);
+ struct misdn_stack *stack;
+ static int first=1;
+ int ptp=0;
+-
++
+ if (strstr(tok, "ptp"))
+ ptp=1;
+
+@@ -4100,12 +4196,12 @@
+ exit(1);
+ }
+ stack=stack_init(midev, port, ptp);
+-
++
+ if (!stack) {
+ perror("stack_init");
+ exit(1);
+ }
+-
++
+ {
+ int i;
+ for(i=0;i<=stack->b_num; i++) {
+@@ -4122,30 +4218,30 @@
+ first=0;
+ continue;
+ }
+-
++
+ if (stack) {
+ struct misdn_stack * help;
+- for ( help=mgr->stack_list; help; help=help->next )
++ for ( help=mgr->stack_list; help; help=help->next )
+ if (help->next == NULL) break;
+ help->next=stack;
+ }
+-
++
+ }
+-
++
+ if (sem_init(&handler_started, 1, 0)<0)
+ sem_init(&handler_started, 0, 0);
+-
++
+ cb_log(8, 0, "Starting Event Handler\n");
+ pthread_create( &mgr->event_handler_thread, NULL,(void*)manager_event_handler, mgr);
+-
++
+ sem_wait(&handler_started) ;
+ cb_log(8, 0, "Starting Event Catcher\n");
+ pthread_create( &mgr->event_thread, NULL, (void*)misdn_lib_isdn_event_catcher, mgr);
+-
++
+ cb_log(8, 0, "Event Catcher started\n");
+
+- global_state= MISDN_INITIALIZED;
+-
++ global_state= MISDN_INITIALIZED;
++
+ return (mgr == NULL);
+ }
+
+@@ -4153,7 +4249,7 @@
+ {
+ struct misdn_stack *help;
+ int i;
+-
++
+ for ( help=glob_mgr->stack_list; help; help=help->next ) {
+ for(i=0;i<=help->b_num; i++) {
+ char buf[1024];
+@@ -4163,21 +4259,21 @@
+ cb_log (1, help->port, "Destroying this port.\n");
+ stack_destroy(help);
+ }
+-
++
+ if (global_state == MISDN_INITIALIZED) {
+ cb_log(4, 0, "Killing Handler Thread\n");
+ if ( pthread_cancel(glob_mgr->event_handler_thread) == 0 ) {
+ cb_log(4, 0, "Joining Handler Thread\n");
+ pthread_join(glob_mgr->event_handler_thread, NULL);
+ }
+-
++
+ cb_log(4, 0, "Killing Main Thread\n");
+ if ( pthread_cancel(glob_mgr->event_thread) == 0 ) {
+ cb_log(4, 0, "Joining Main Thread\n");
+ pthread_join(glob_mgr->event_thread, NULL);
+ }
+ }
+-
++
+ cb_log(1, 0, "Closing mISDN device\n");
+ te_lib_destroy(glob_mgr->midev);
+ }
+@@ -4197,12 +4293,12 @@
+ cb_log(0, bc->port, "bchannel_activate: Stack not found !");
+ return ;
+ }
+-
++
+ /* we must activate if we are deactivated */
+ clear_ibuffer(bc->astbuf);
+-
++
+ cb_log(5, stack->port, "$$$ Bchan Activated addr %x\n", bc->addr);
+-
++
+ mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_DOWN, DL_ESTABLISH | REQUEST, 0,0, NULL, TIMEOUT_1SEC);
+
+ return ;
+@@ -4213,7 +4309,7 @@
+ {
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+ iframe_t dact;
+- char buf[128];
++ char buf[128];
+
+ switch (bc->bc_state) {
+ case BCHAN_ACTIVATED:
+@@ -4226,11 +4322,11 @@
+ return ;
+
+ }
+-
++
+ cb_log(5, stack->port, "$$$ Bchan deActivated addr %x\n", bc->addr);
+-
++
+ bc->generate_tone=0;
+-
++
+ dact.prim = DL_RELEASE | REQUEST;
+ dact.addr = bc->addr | FLG_MSG_DOWN;
+ dact.dinfo = 0;
+@@ -4238,9 +4334,9 @@
+ mISDN_write_frame(stack->midev, buf, bc->addr | FLG_MSG_DOWN, DL_RELEASE|REQUEST,0,0,NULL, TIMEOUT_1SEC);
+
+ clear_ibuffer(bc->astbuf);
+-
++
+ bc_state_change(bc,BCHAN_RELEASE);
+-
++
+ return;
+ }
+
+@@ -4260,19 +4356,19 @@
+ cb_log(3, bc->port, "BC not yet activated (state:%s)\n",bc_state2str(bc->bc_state));
+ return -1;
+ }
+-
++
+ frm->prim = DL_DATA|REQUEST;
+ frm->dinfo = 0;
+ frm->addr = bc->addr | FLG_MSG_DOWN ;
+-
++
+ frm->len = len;
+ memcpy(&buf[mISDN_HEADER_LEN], data,len);
+-
+- if ( misdn_cap_is_speech(bc->capability) )
++
++ if ( misdn_cap_is_speech(bc->capability) )
+ flip_buf_bits( &buf[mISDN_HEADER_LEN], len);
+ else
+ cb_log(6, stack->port, "Writing %d data bytes\n",len);
+-
++
+ cb_log(9, stack->port, "Writing %d bytes 2 mISDN\n",len);
+ r=mISDN_write(stack->midev, buf, frm->len + mISDN_HEADER_LEN, TIMEOUT_INFINIT);
+ return 0;
+@@ -4289,9 +4385,9 @@
+ iframe_t *ctrl = (iframe_t *)buffer; /* preload data */
+ unsigned int *d = (unsigned int*)&ctrl->data.p;
+ /*struct misdn_stack *stack=get_stack_by_bc(bc);*/
+-
++
+ cb_log(4,bc->port,"ph_control: c1:%x c2:%x\n",c1,c2);
+-
++
+ ctrl->prim = PH_CONTROL | REQUEST;
+ ctrl->addr = bc->addr | FLG_MSG_DOWN;
+ ctrl->dinfo = 0;
+@@ -4340,7 +4436,7 @@
+ iframe_t *ctrl = (iframe_t *)buffer;
+ unsigned int *d = (unsigned int *)&ctrl->data.p;
+ /*struct misdn_stack *stack=get_stack_by_bc(bc);*/
+-
++
+ ctrl->prim = PH_CONTROL | REQUEST;
+ ctrl->addr = bc->addr | FLG_MSG_DOWN;
+ ctrl->dinfo = 0;
+@@ -4356,13 +4452,13 @@
+ void manager_clean_bc(struct misdn_bchannel *bc )
+ {
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+-
++
+ if (bc->channel>0)
+ empty_chan_in_stack(stack, bc->channel);
+ empty_bc(bc);
+ bc->in_use=0;
+
+- cb_event(EVENT_CLEANUP, bc, NULL);
++ cb_event(EVENT_CLEANUP, bc, NULL);
+ }
+
+
+@@ -4370,15 +4466,15 @@
+ {
+ struct misdn_bchannel *help;
+ cb_log(4,stack->port, "*HOLDER: add %x\n",holder->l3_id);
+-
++
+ holder->stack_holder=1;
+ holder->next=NULL;
+-
++
+ if (!stack->holding) {
+ stack->holding = holder;
+ return;
+ }
+-
++
+ for (help=stack->holding;
+ help;
+ help=help->next) {
+@@ -4387,7 +4483,7 @@
+ break;
+ }
+ }
+-
++
+ }
+
+ void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holder)
+@@ -4395,17 +4491,17 @@
+ struct misdn_bchannel *h1;
+
+ if (!holder->stack_holder) return;
+-
++
+ holder->stack_holder=0;
+-
++
+ cb_log(4,stack->port, "*HOLDER: remove %x\n",holder->l3_id);
+ if (!stack || ! stack->holding) return;
+-
++
+ if (holder == stack->holding) {
+ stack->holding = stack->holding->next;
+ return;
+ }
+-
++
+ for (h1=stack->holding;
+ h1;
+ h1=h1->next) {
+@@ -4421,9 +4517,9 @@
+ struct misdn_bchannel *help;
+
+ cb_log(4,stack?stack->port:0, "*HOLDER: find_bychan %c\n", chan);
+-
++
+ if (!stack) return NULL;
+-
++
+ for (help=stack->holding;
+ help;
+ help=help->next) {
+@@ -4443,9 +4539,9 @@
+ struct misdn_bchannel *help;
+
+ cb_log(4,stack?stack->port:0, "*HOLDER: find %lx\n",l3id);
+-
++
+ if (!stack) return NULL;
+-
++
+ for (help=stack->holding;
+ help;
+ help=help->next) {
+@@ -4461,34 +4557,34 @@
+
+
+
+-void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone)
++void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone)
+ {
+ char buf[mISDN_HEADER_LEN + 128] = "";
+ iframe_t *frm = (iframe_t*)buf;
+
+ switch(tone) {
+ case TONE_DIAL:
+- manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_DIALTONE);
++ manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_DIALTONE);
+ break;
+-
++
+ case TONE_ALERTING:
+- manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_RINGING);
++ manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_RINGING);
+ break;
+-
++
+ case TONE_HANGUP:
+- manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_HANGUP);
++ manager_ph_control(bc, TONE_PATT_ON, TONE_GERMAN_HANGUP);
+ break;
+
+ case TONE_NONE:
+ default:
+- manager_ph_control(bc, TONE_PATT_OFF, TONE_GERMAN_HANGUP);
++ manager_ph_control(bc, TONE_PATT_OFF, TONE_GERMAN_HANGUP);
+ }
+
+ frm->prim=DL_DATA|REQUEST;
+ frm->addr=bc->addr|FLG_MSG_DOWN;
+ frm->dinfo=0;
+ frm->len=128;
+-
++
+ mISDN_write(glob_mgr->midev, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+ }
+
+@@ -4496,7 +4592,7 @@
+ void manager_ec_enable(struct misdn_bchannel *bc)
+ {
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+-
++
+ cb_log(4, stack?stack->port:0,"ec_enable\n");
+
+ if (!misdn_cap_is_speech(bc->capability)) {
+@@ -4513,7 +4609,7 @@
+
+ if (bc->ec_enable) {
+ cb_log(3, stack?stack->port:0,"Sending Control ECHOCAN_ON taps:%d\n",bc->ec_deftaps);
+-
++
+ switch (bc->ec_deftaps) {
+ case 4:
+ case 8:
+@@ -4530,10 +4626,10 @@
+ cb_log(0, stack->port, "Taps should be power of 2\n");
+ bc->ec_deftaps=128;
+ }
+-
++
+ ec_arr[0]=bc->ec_deftaps;
+ ec_arr[1]=0;
+-
++
+ manager_ph_control_block(bc, ECHOCAN_ON, ec_arr, sizeof(ec_arr));
+ }
+ #endif
+@@ -4545,7 +4641,7 @@
+ void manager_ec_disable(struct misdn_bchannel *bc)
+ {
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+-
++
+ cb_log(4, stack?stack->port:0," --> ec_disable\n");
+
+ if (!misdn_cap_is_speech(bc->capability)) {
+@@ -4600,10 +4696,10 @@
+
+ cb_log(4, bc1->port, "I Send: BRIDGE from:%d to:%d\n",bc1->port,bc2->port);
+
+- for (bc=bc_list; *bc; bc++) {
++ for (bc=bc_list; *bc; bc++) {
+ (*bc)->conf_id=conf_id;
+ cb_log(4, (*bc)->port, " --> bc_addr:%x\n",(*bc)->addr);
+-
++
+ switch((*bc)->bc_state) {
+ case BCHAN_ACTIVATED:
+ misdn_join_conf(*bc,conf_id);
+@@ -4622,15 +4718,15 @@
+ bc1,bc2,NULL
+ };
+ struct misdn_bchannel **bc;
+-
+- for (bc=bc_list; *bc; bc++) {
++
++ for (bc=bc_list; *bc; bc++) {
+ if ( (*bc)->bc_state == BCHAN_BRIDGED){
+ misdn_split_conf( *bc, (*bc)->conf_id);
+ } else {
+ cb_log( 2, (*bc)->port, "BC not bridged (state:%s) so not splitting it\n",bc_state2str((*bc)->bc_state));
+ }
+ }
+-
++
+ }
+
+
+@@ -4646,37 +4742,37 @@
+ void misdn_lib_reinit_nt_stack(int port)
+ {
+ struct misdn_stack *stack=find_stack_by_port(port);
+-
++
+ if (stack) {
+ stack->l2link=0;
+ stack->blocked=0;
+-
++
+ cleanup_Isdnl3(&stack->nst);
+ cleanup_Isdnl2(&stack->nst);
+
+
+ memset(&stack->nst, 0, sizeof(net_stack_t));
+ memset(&stack->mgr, 0, sizeof(manager_t));
+-
++
+ stack->mgr.nst = &stack->nst;
+ stack->nst.manager = &stack->mgr;
+-
++
+ stack->nst.l3_manager = handle_event_nt;
+ stack->nst.device = glob_mgr->midev;
+ stack->nst.cardnr = port;
+ stack->nst.d_stid = stack->d_stid;
+-
++
+ stack->nst.feature = FEATURE_NET_HOLD;
+ if (stack->ptp)
+ stack->nst.feature |= FEATURE_NET_PTP;
+ if (stack->pri)
+ stack->nst.feature |= FEATURE_NET_CRLEN2 | FEATURE_NET_EXTCID;
+-
++
+ stack->nst.l1_id = stack->lower_id;
+ stack->nst.l2_id = stack->upper_id;
+-
++
+ msg_queue_init(&stack->nst.down_queue);
+-
++
+ Isdnl2Init(&stack->nst);
+ Isdnl3Init(&stack->nst);
+
+Index: channels/misdn/isdn_lib_intern.h
+===================================================================
+--- a/channels/misdn/isdn_lib_intern.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/isdn_lib_intern.h (.../trunk) (revision 186562)
+@@ -41,7 +41,6 @@
+ 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);
+Index: channels/misdn/isdn_lib.h
+===================================================================
+--- a/channels/misdn/isdn_lib.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/isdn_lib.h (.../trunk) (revision 186562)
+@@ -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,
+@@ -189,6 +197,19 @@
+ 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
+@@ -202,12 +223,81 @@
+ 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;
+
+@@ -326,26 +416,6 @@
+ /*! \brief TRUE if we will not use the jitter buffer system */
+ int nojitter;
+
+- /*! \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_PLAN dnumplan;
+-
+- /*! \brief Type-of-number in ISDN terms for the redirecting number which a call diversion or transfer was invoked.
+- * \note Collected from the incoming SETUP message but not used.
+- */
+- enum mISDN_NUMBER_PLAN rnumplan;
+-
+- /*! \brief Type-of-number in ISDN terms for the originating/calling number (Caller-ID)
+- * \note This value is set to "localdialplan" in /etc/asterisk/misdn.conf for outgoing calls
+- */
+- enum mISDN_NUMBER_PLAN onumplan;
+-
+- /*! \brief Type-of-number in ISDN terms for the connected party number
+- * \note This value is set to "cpndialplan" in /etc/asterisk/misdn.conf for outgoing calls
+- */
+- enum mISDN_NUMBER_PLAN cpnnumplan;
+-
+ /*! \brief Progress Indicator IE coding standard field.
+ * \note Collected from the incoming messages but not used.
+ */
+@@ -421,16 +491,38 @@
+ */
+ int stack_holder;
+
+- /*! \brief Caller ID presentation restriction code
++ /*!
++ * \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 pres;
++ int presentation;
+
+- /*! \brief Caller ID screening code
+- * 0=Unscreened, 1=Passed Screen, 2=Failed Screen, 3=Network Number
+- */
+- int screen;
++ /*! \brief TRUE if the user set the presentation restriction code */
++ int set_presentation;
+
+ /*! \brief SETUP message bearer capability field code value */
+ int capability;
+@@ -462,6 +554,23 @@
+ 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.
+@@ -469,39 +578,20 @@
+ char display[84];
+
+ /*! \brief Not used. Contents are setup but not used. */
+- char msn[32];
++ char msn[MISDN_MAX_NUMBER_LEN];
+
+- /*! \brief Originating/Calling Phone Number (Address)
+- * \note This value can be set to "callerid" in /etc/asterisk/misdn.conf for outgoing calls
+- */
+- char oad[32];
+-
+- /*! \brief Redirecting Phone Number (Address) where a call diversion or transfer was invoked */
+- char rad[32];
+-
+- /*! \brief Dialed/Called Phone Number (Address) */
+- char dad[32];
+-
+- /*! \brief Connected Party/Line Phone Number (Address) */
+- char cad[32];
+-
+- /*! \brief Original Dialed/Called Phone Number (Address) before national/international dialing prefix added.
+- * \note Not used. Contents are setup but not used.
+- */
+- char orig_dad[32];
+-
+ /*! \brief Q.931 Keypad Facility IE contents
+ * \note Contents exported and imported to Asterisk variable MISDN_KEYPAD
+ */
+- char keypad[32];
++ char keypad[MISDN_MAX_KEYPAD_LEN];
+
+ /*! \brief Current overlap dialing digits to/from INFORMATION messages */
+- char info_dad[64];
++ 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[64];
++ char infos_pending[MISDN_MAX_NUMBER_LEN];
+
+-/* unsigned char info_keypad[32]; */
++/* unsigned char info_keypad[MISDN_MAX_KEYPAD_LEN]; */
+ /* unsigned char clisub[24]; */
+ /* unsigned char cldsub[24]; */
+
+Index: channels/misdn/Makefile
+===================================================================
+--- a/channels/misdn/Makefile (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/Makefile (.../trunk) (revision 186562)
+@@ -13,5 +13,5 @@
+ portinfo: portinfo.o
+ $(CC) -o $@ $^ -lisdnnet -lmISDN -lpthread
+
+-clean:
++clean:
+ rm -rf *.a *.o *.so portinfo *.i
+Index: channels/misdn/chan_misdn_config.h
+===================================================================
+--- a/channels/misdn/chan_misdn_config.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/chan_misdn_config.h (.../trunk) (revision 186562)
+@@ -11,7 +11,7 @@
+ * the GNU General Public License
+ */
+
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN - Config
+ * \author Christian Richter <crich@beronet.com>
+ */
+@@ -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) */
+@@ -89,7 +95,7 @@
+ MISDN_CFG_FAXDETECT_TIMEOUT, /* int */
+ MISDN_CFG_PTP, /* int (bool) */
+ MISDN_CFG_LAST,
+-
++
+ /* general config items */
+ MISDN_GEN_FIRST,
+ #ifndef MISDN_1_2
+@@ -116,14 +122,14 @@
+ };
+
+ /* you must call misdn_cfg_init before any other function of this header file */
+-int misdn_cfg_init(int max_ports, int reload);
++int misdn_cfg_init(int max_ports, int reload);
+ void misdn_cfg_reload(void);
+ void misdn_cfg_destroy(void);
+
+ void misdn_cfg_update_ptp( void );
+
+-/* if you requst a general config element, the port value is ignored. if the requested
+- * value is not available, or the buffer is too small, the buffer will be nulled (in
++/* if you requst a general config element, the port value is ignored. if the requested
++ * value is not available, or the buffer is too small, the buffer will be nulled (in
+ * case of a char* only its first byte will be nulled). */
+ void misdn_cfg_get(int port, enum misdn_cfg_elements elem, void* buf, int bufsize);
+
+Index: channels/misdn/ie.c
+===================================================================
+--- a/channels/misdn/ie.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/misdn/ie.c (.../trunk) (revision 186562)
+@@ -15,7 +15,7 @@
+ * the GNU General Public License
+ */
+
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN
+ * \author Christian Richter <crich@beronet.com>
+ */
+@@ -153,7 +153,7 @@
+ p[4+(multi>=0)] = 0xa0 + user;
+ }
+
+-static void dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capability, int *mode, int *rate, int *multi, int *user,
++static void dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capability, int *mode, int *rate, int *multi, int *user,
+ int *async, int *urate, int *stopbits, int *dbits, int *parity, int nt, struct misdn_bchannel *bc)
+ {
+ int octet;
+@@ -168,13 +168,13 @@
+ *stopbits = -1;
+ *dbits = -1;
+ *parity = -1;
+-
++
+ if (!nt)
+ {
+ p = NULL;
+ #ifdef LLC_SUPPORT
+ if (qi->QI_ELEMENT(llc)) {
+-
++
+ p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(llc) + 1;
+ }
+ #endif
+@@ -189,7 +189,7 @@
+ printf("%s: ERROR: IE too short (%d).\n", __FUNCTION__, p[0]);
+ return;
+ }
+-
++
+ *coding = (p[1]&0x60) >> 5;
+ *capability = p[1] & 0x1f;
+ octet = 2;
+@@ -221,7 +221,7 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (p[octet++] & 0x80)
+ goto l2;
+
+@@ -231,7 +231,7 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (p[octet++] & 0x80)
+ goto l2;
+
+@@ -239,7 +239,7 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (p[octet++] & 0x80)
+ goto l2;
+
+@@ -247,20 +247,20 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (!p[octet++] & 0x80)
+ goto l2;
+
+ /* Wheee. V.110 speed information */
+
+ *stopbits = (p[octet] & 0x60) >> 5;
+- *dbits = (p[octet] & 0x18) >> 3;
++ *dbits = (p[octet] & 0x18) >> 3;
+ *parity = p[octet] & 7;
+
+ octet++;
+ }
+ l2: /* Nobody seems to want the rest so we don't bother (yet) */
+- done:
++ done:
+ if (MISDN_IE_DEBG) printf(" coding=%d capability=%d mode=%d rate=%d multi=%d user=%d async=%d urate=%d stopbits=%d dbits=%d parity=%d\n", *coding, *capability, *mode, *rate, *multi, *user, *async, *urate, *stopbits, *dbits, *parity);
+ }
+
+@@ -292,7 +292,7 @@
+ if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
+ i++;
+ }
+-
++
+ if (MISDN_IE_DEBG) printf(" callid%s\n", debug);
+
+ l = callid_len;
+@@ -338,7 +338,7 @@
+ if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
+ i++;
+ }
+-
++
+ if (MISDN_IE_DEBG) printf(" callid%s\n", debug);
+ }
+ #endif
+@@ -501,7 +501,7 @@
+ } else
+ {
+ strnncpy(number, (char *)p+2, p[0]-1, number_len);
+- /* SPECIAL workarround for IBT software bug */
++ /* SPECIAL workarround for IBT software bug */
+ /* if (number[0]==0x80) */
+ /* strcpy((char *)number, (char *)number+1); */
+ }
+@@ -691,7 +691,7 @@
+ int l;
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+ int pri = stack->pri;
+-
++
+ if (exclusive<0 || exclusive>1)
+ {
+ printf("%s: ERROR: exclusive(%d) is out of range.\n", __FUNCTION__, exclusive);
+@@ -707,8 +707,8 @@
+ }
+
+ /* if (MISDN_IE_DEBG) printf(" exclusive=%d channel=%d\n", exclusive, channel); */
+-
+
++
+ if (!pri)
+ {
+ /* BRI */
+@@ -1086,7 +1086,7 @@
+ *location = -1;
+ //*progress = -1;
+ *progress = 0;
+-
++
+ if (!nt)
+ {
+ p = NULL;
+@@ -1350,7 +1350,7 @@
+ if (MISDN_IE_DEBG) sprintf(debug+(i*3), " %02x", user[i]);
+ i++;
+ }
+-
++
+ if (MISDN_IE_DEBG) printf(" protocol=%d user-user%s\n", protocol, debug);
+
+ l = user_len+1;
+@@ -1397,7 +1397,7 @@
+ i++;
+ }
+ debug[i*3] = '\0';
+-
++
+ if (MISDN_IE_DEBG) printf(" protocol=%d user-user%s\n", *protocol, debug);
+ }
+ #endif
+Index: channels/chan_gtalk.c
+===================================================================
+--- a/channels/chan_gtalk.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/channels/chan_gtalk.c (.../trunk) (revision 186562)
+@@ -52,7 +52,8 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/sched.h"
+ #include "asterisk/io.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
++#include "asterisk/stun.h"
+ #include "asterisk/acl.h"
+ #include "asterisk/callerid.h"
+ #include "asterisk/file.h"
+@@ -112,8 +113,8 @@
+ char cid_name[80]; /*!< Caller ID name */
+ char exten[80]; /*!< Called extension */
+ struct ast_channel *owner; /*!< Master Channel */
+- struct ast_rtp *rtp; /*!< RTP audio session */
+- struct ast_rtp *vrtp; /*!< RTP video session */
++ struct ast_rtp_instance *rtp; /*!< RTP audio session */
++ struct ast_rtp_instance *vrtp; /*!< RTP video session */
+ int jointcapability; /*!< Supported capability at both ends (codecs ) */
+ int peercapability;
+ struct gtalk_pvt *next; /* Next entity */
+@@ -183,11 +184,6 @@
+ static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid);
+ static char *gtalk_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static char *gtalk_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+-/*----- RTP interface functions */
+-static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
+- struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
+-static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+-static int gtalk_get_codec(struct ast_channel *chan);
+
+ /*! \brief PBX interface structure for channel registration */
+ static const struct ast_channel_tech gtalk_tech = {
+@@ -197,7 +193,7 @@
+ .requester = gtalk_request,
+ .send_digit_begin = gtalk_digit_begin,
+ .send_digit_end = gtalk_digit_end,
+- .bridge = ast_rtp_bridge,
++ .bridge = ast_rtp_instance_bridge,
+ .call = gtalk_call,
+ .hangup = gtalk_hangup,
+ .answer = gtalk_answer,
+@@ -216,14 +212,6 @@
+ static struct io_context *io; /*!< The IO context */
+ static struct in_addr __ourip;
+
+-/*! \brief RTP driver interface */
+-static struct ast_rtp_protocol gtalk_rtp = {
+- type: "Gtalk",
+- get_rtp_info: gtalk_get_rtp_peer,
+- set_rtp_peer: gtalk_set_rtp_peer,
+- get_codec: gtalk_get_codec,
+-};
+-
+ static struct ast_cli_entry gtalk_cli[] = {
+ AST_CLI_DEFINE(gtalk_do_reload, "Reload GoogleTalk configuration"),
+ AST_CLI_DEFINE(gtalk_show_channels, "Show GoogleTalk channels"),
+@@ -371,7 +359,7 @@
+ iks_insert_node(dcodecs, payload_gsm);
+ res++;
+ }
+- ast_rtp_lookup_code(p->rtp, 1, codec);
++
+ return res;
+ }
+
+@@ -523,18 +511,19 @@
+ return res;
+ }
+
+-static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
++static enum ast_rtp_glue_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
+ {
+ struct gtalk_pvt *p = chan->tech_pvt;
+- enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
++ enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
+
+ if (!p)
+ return res;
+
+ ast_mutex_lock(&p->lock);
+ if (p->rtp){
+- *rtp = p->rtp;
+- res = AST_RTP_TRY_PARTIAL;
++ ao2_ref(p->rtp, +1);
++ *instance = p->rtp;
++ res = AST_RTP_GLUE_RESULT_LOCAL;
+ }
+ ast_mutex_unlock(&p->lock);
+
+@@ -547,7 +536,7 @@
+ return p->peercapability;
+ }
+
+-static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
++static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active)
+ {
+ struct gtalk_pvt *p;
+
+@@ -567,6 +556,13 @@
+ return 0;
+ }
+
++static struct ast_rtp_glue gtalk_rtp_glue = {
++ .type = "Gtalk",
++ .get_rtp_info = gtalk_get_rtp_peer,
++ .get_codec = gtalk_get_codec,
++ .update_peer = gtalk_set_rtp_peer,
++};
++
+ static int gtalk_response(struct gtalk *client, char *from, ikspak *pak, const char *reasonstr, const char *reasonstr2)
+ {
+ iks *response = NULL, *error = NULL, *reason = NULL;
+@@ -615,15 +611,15 @@
+ }
+
+ /* codec points to the first <payload-type/> tag */
+- codec = iks_child(iks_child(iks_child(pak->x)));
++ codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
+ while (codec) {
+- ast_rtp_set_m_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")));
+- ast_rtp_set_rtpmap_type(tmp->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+- codec = iks_next(codec);
++ ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp, atoi(iks_find_attrib(codec, "id")));
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
++ codec = iks_next_tag(codec);
+ }
+
+ /* Now gather all of the codecs that we are asked for */
+- ast_rtp_get_current_formats(tmp->rtp, &tmp->peercapability, &peernoncodeccapability);
++ ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(tmp->rtp), &tmp->peercapability, &peernoncodeccapability);
+
+ /* at this point, we received an awser from the remote Gtalk client,
+ which allows us to compare capabilities */
+@@ -810,7 +806,7 @@
+ goto safeout;
+ }
+
+- ast_rtp_get_us(p->rtp, &sin);
++ ast_rtp_instance_get_local_address(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.");
+@@ -951,8 +947,9 @@
+ tmp->initiator = 1;
+ }
+ /* clear codecs */
+- tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+- ast_rtp_pt_clear(tmp->rtp);
++ tmp->rtp = ast_rtp_instance_new(NULL, sched, &bindaddr, NULL);
++ ast_rtp_instance_set_prop(tmp->rtp, AST_RTP_PROPERTY_RTCP, 1);
++ ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(tmp->rtp), tmp->rtp);
+
+ /* add user configured codec capabilites */
+ if (client->capability)
+@@ -1014,20 +1011,20 @@
+
+ /* Set Frame packetization */
+ if (i->rtp)
+- ast_rtp_codec_setpref(i->rtp, &i->prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
+
+ tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
+ fmt = ast_best_codec(tmp->nativeformats);
+
+ if (i->rtp) {
+- ast_rtp_setstun(i->rtp, 1);
+- ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
+- ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
++ ast_rtp_instance_set_prop(i->rtp, AST_RTP_PROPERTY_STUN, 1);
++ ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
++ ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
+ }
+ if (i->vrtp) {
+- ast_rtp_setstun(i->rtp, 1);
+- ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
+- ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
++ ast_rtp_instance_set_prop(i->vrtp, AST_RTP_PROPERTY_STUN, 1);
++ ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
++ ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
+ }
+ if (state == AST_STATE_RING)
+ tmp->rings = 1;
+@@ -1142,9 +1139,9 @@
+ if (p->owner)
+ ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
+ if (p->rtp)
+- ast_rtp_destroy(p->rtp);
++ ast_rtp_instance_destroy(p->rtp);
+ if (p->vrtp)
+- ast_rtp_destroy(p->vrtp);
++ ast_rtp_instance_destroy(p->vrtp);
+ gtalk_free_candidates(p->theircandidates);
+ ast_free(p);
+ }
+@@ -1204,16 +1201,16 @@
+ }
+
+ /* codec points to the first <payload-type/> tag */
+- codec = iks_child(iks_child(iks_child(pak->x)));
++ codec = iks_first_tag(iks_first_tag(iks_first_tag(pak->x)));
+
+ while (codec) {
+- ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id")));
+- ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
+- codec = iks_next(codec);
++ ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
++ ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
++ codec = iks_next_tag(codec);
+ }
+
+ /* Now gather all of the codecs that we are asked for */
+- ast_rtp_get_current_formats(p->rtp, &p->peercapability, &peernoncodeccapability);
++ ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(p->rtp), &p->peercapability, &peernoncodeccapability);
+ p->jointcapability = p->capability & p->peercapability;
+ ast_mutex_unlock(&p->lock);
+
+@@ -1277,16 +1274,16 @@
+ p->ourcandidates->username);
+
+ /* Find out the result of the STUN */
+- ast_rtp_get_peer(p->rtp, &aux);
++ ast_rtp_instance_get_remote_address(p->rtp, &aux);
+
+ /* If the STUN result is different from the IP of the hostname,
+ lock on the stun IP of the hostname advertised by the
+ remote client */
+ if (aux.sin_addr.s_addr &&
+ aux.sin_addr.s_addr != sin.sin_addr.s_addr)
+- ast_rtp_stun_request(p->rtp, &aux, username);
++ ast_rtp_instance_stun_request(p->rtp, &aux, username);
+ else
+- ast_rtp_stun_request(p->rtp, &sin, username);
++ ast_rtp_instance_stun_request(p->rtp, &sin, username);
+
+ if (aux.sin_addr.s_addr) {
+ ast_debug(4, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip);
+@@ -1323,11 +1320,11 @@
+ traversenodes = pak->query;
+ while(traversenodes) {
+ if(!strcasecmp(iks_name(traversenodes), "session")) {
+- traversenodes = iks_child(traversenodes);
++ traversenodes = iks_first_tag(traversenodes);
+ continue;
+ }
+ if(!strcasecmp(iks_name(traversenodes), "transport")) {
+- traversenodes = iks_child(traversenodes);
++ traversenodes = iks_first_tag(traversenodes);
+ continue;
+ }
+ if(!strcasecmp(iks_name(traversenodes), "candidate")) {
+@@ -1366,7 +1363,7 @@
+ gtalk_update_stun(p->parent, p);
+ newcandidate = NULL;
+ }
+- traversenodes = iks_next(traversenodes);
++ traversenodes = iks_next_tag(traversenodes);
+ }
+
+ receipt = iks_new("iq");
+@@ -1387,7 +1384,7 @@
+
+ if (!p->rtp)
+ return &ast_null_frame;
+- f = ast_rtp_read(p->rtp);
++ f = ast_rtp_instance_read(p->rtp, 0);
+ gtalk_update_stun(p->parent, p);
+ if (p->owner) {
+ /* We already hold the channel lock */
+@@ -1438,7 +1435,7 @@
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (p->rtp) {
+- res = ast_rtp_write(p->rtp, frame);
++ res = ast_rtp_instance_write(p->rtp, frame);
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+@@ -1447,7 +1444,7 @@
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (p->vrtp) {
+- res = ast_rtp_write(p->vrtp, frame);
++ res = ast_rtp_instance_write(p->vrtp, frame);
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+@@ -2062,7 +2059,7 @@
+ return 0;
+ }
+
+- ast_rtp_proto_register(&gtalk_rtp);
++ ast_rtp_glue_register(&gtalk_rtp_glue);
+ ast_cli_register_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
+
+ /* Make sure we can register our channel type */
+@@ -2086,7 +2083,7 @@
+ ast_cli_unregister_multiple(gtalk_cli, ARRAY_LEN(gtalk_cli));
+ /* First, take us out of the channel loop */
+ ast_channel_unregister(&gtalk_tech);
+- ast_rtp_proto_unregister(&gtalk_rtp);
++ ast_rtp_glue_unregister(&gtalk_rtp_glue);
+
+ if (!ast_mutex_lock(&gtalklock)) {
+ /* Hangup all interfaces if they have an owner */
+Index: configure.ac
+===================================================================
+--- a/configure.ac (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/configure.ac (.../trunk) (revision 186562)
+@@ -609,8 +609,6 @@
+ AC_MSG_RESULT(no)
+ )
+
+-AST_C_DEFINE_CHECK([RTLD_NOLOAD], [RTLD_NOLOAD], [dlfcn.h])
+-
+ AST_C_DEFINE_CHECK([IP_MTU_DISCOVER], [IP_MTU_DISCOVER], [netinet/in.h])
+
+ AC_CHECK_HEADER([libkern/OSAtomic.h],
+Index: apps/app_senddtmf.c
+===================================================================
+--- a/apps/app_senddtmf.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_senddtmf.c (.../trunk) (revision 186562)
+@@ -106,7 +106,7 @@
+ astman_send_error(s, m, "Channel not specified");
+ return 0;
+ }
+- if (!digit) {
++ if (ast_strlen_zero(digit)) {
+ astman_send_error(s, m, "No digit specified");
+ ast_channel_unlock(chan);
+ return 0;
+Index: apps/app_test.c
+===================================================================
+--- a/apps/app_test.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_test.c (.../trunk) (revision 186562)
+@@ -132,7 +132,7 @@
+ return (noise / samples);
+ }
+
+-static int sendnoise(struct ast_channel *chan, int ms)
++static int sendnoise(struct ast_channel *chan, int ms)
+ {
+ int res;
+ res = ast_tonepair_start(chan, 1537, 2195, ms, 8192);
+@@ -140,7 +140,7 @@
+ res = ast_waitfordigit(chan, ms);
+ ast_tonepair_stop(chan);
+ }
+- return res;
++ return res;
+ }
+
+ static int testclient_exec(struct ast_channel *chan, void *data)
+@@ -150,41 +150,41 @@
+ char fn[80];
+ char serverver[80];
+ FILE *f;
+-
++
+ /* Check for test id */
+ if (ast_strlen_zero(testid)) {
+ ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n");
+ return -1;
+ }
+-
++
+ if (chan->_state != AST_STATE_UP)
+ res = ast_answer(chan);
+-
++
+ /* Wait a few just to be sure things get started */
+ res = ast_safe_sleep(chan, 3000);
+ /* Transmit client version */
+ if (!res)
+ res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
+ ast_debug(1, "Transmit client version\n");
+-
++
+ /* Read server version */
+ ast_debug(1, "Read server version\n");
+- if (!res)
++ if (!res)
+ res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0);
+ if (res > 0)
+ res = 0;
+ ast_debug(1, "server version: %s\n", serverver);
+-
++
+ if (res > 0)
+ res = 0;
+
+ if (!res)
+ res = ast_safe_sleep(chan, 1000);
+ /* Send test id */
+- if (!res)
+- res = ast_dtmf_stream(chan, NULL, testid, 0, 0);
+- if (!res)
+- res = ast_dtmf_stream(chan, NULL, "#", 0, 0);
++ if (!res)
++ res = ast_dtmf_stream(chan, NULL, testid, 0, 0);
++ if (!res)
++ res = ast_dtmf_stream(chan, NULL, "#", 0, 0);
+ ast_debug(1, "send test identifier: %s\n", testid);
+
+ if ((res >=0) && (!ast_strlen_zero(testid))) {
+@@ -198,7 +198,7 @@
+ fprintf(f, "CLIENTTEST ID: %s\n", testid);
+ fprintf(f, "ANSWER: PASS\n");
+ res = 0;
+-
++
+ if (!res) {
+ /* Step 1: Wait for "1" */
+ ast_debug(1, "TestClient: 2. Wait DTMF 1\n");
+@@ -209,8 +209,9 @@
+ else
+ res = -1;
+ }
+- if (!res)
++ if (!res) {
+ res = ast_safe_sleep(chan, 1000);
++ }
+ if (!res) {
+ /* Step 2: Send "2" */
+ ast_debug(1, "TestClient: 2. Send DTMF 2\n");
+@@ -226,7 +227,7 @@
+ fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
+ if (res > 0)
+ res = 0;
+- }
++ }
+ if (!res) {
+ /* Step 4: Measure noise */
+ ast_debug(1, "TestClient: 4. Measure noise\n");
+@@ -272,7 +273,7 @@
+ }
+ if (!res) {
+ /* Step 9: Measure noise */
+- ast_debug(1, "TestClient: 6. Measure tone\n");
++ ast_debug(1, "TestClient: 9. Measure tone\n");
+ res = measurenoise(chan, 4000, "TestClient");
+ fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
+ if (res > 0)
+@@ -280,7 +281,7 @@
+ }
+ if (!res) {
+ /* Step 10: Send "7" */
+- ast_debug(1, "TestClient: 7. Send DTMF 7\n");
++ ast_debug(1, "TestClient: 10. Send DTMF 7\n");
+ res = ast_dtmf_stream(chan, NULL, "7", 0, 0);
+ fprintf(f, "SEND DTMF 7: %s\n", (res < 0) ? "FAIL" : "PASS");
+ if (res > 0)
+@@ -297,6 +298,9 @@
+ res = -1;
+ }
+ if (!res) {
++ res = ast_safe_sleep(chan, 1000);
++ }
++ if (!res) {
+ /* Step 12: Hangup! */
+ ast_debug(1, "TestClient: 12. Hangup\n");
+ }
+@@ -324,7 +328,7 @@
+ res = ast_answer(chan);
+ /* Read version */
+ ast_debug(1, "Read client version\n");
+- if (!res)
++ if (!res)
+ res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
+ if (res > 0)
+ res = 0;
+@@ -338,8 +342,8 @@
+ if (res > 0)
+ res = 0;
+
+- if (!res)
+- res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
++ if (!res)
++ res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
+ ast_debug(1, "read test identifier: %s\n", testid);
+ /* Check for sneakyness */
+ if (strchr(testid, '/'))
+@@ -391,7 +395,6 @@
+ if (res > 0)
+ res = 0;
+ }
+-
+ if (!res) {
+ /* Step 5: Wait one second */
+ ast_debug(1, "TestServer: 5. Wait one second\n");
+@@ -400,7 +403,6 @@
+ if (res > 0)
+ res = 0;
+ }
+-
+ if (!res) {
+ /* Step 6: Measure noise */
+ ast_debug(1, "TestServer: 6. Measure tone\n");
+@@ -409,7 +411,6 @@
+ if (res > 0)
+ res = 0;
+ }
+-
+ if (!res) {
+ /* Step 7: Send "5" */
+ ast_debug(1, "TestServer: 7. Send DTMF 5\n");
+@@ -418,14 +419,13 @@
+ if (res > 0)
+ res = 0;
+ }
+-
+ if (!res) {
+ /* Step 8: Transmit tone noise */
+ ast_debug(1, "TestServer: 8. Transmit tone\n");
+ res = sendnoise(chan, 6000);
+ fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS");
+ }
+-
++
+ if (!res || (res == '7')) {
+ /* Step 9: Wait for "7" */
+ ast_debug(1, "TestServer: 9. Wait DTMF 7\n");
+@@ -437,8 +437,9 @@
+ else
+ res = -1;
+ }
+- if (!res)
++ if (!res) {
+ res = ast_safe_sleep(chan, 1000);
++ }
+ if (!res) {
+ /* Step 10: Send "8" */
+ ast_debug(1, "TestServer: 10. Send DTMF 8\n");
+@@ -474,7 +475,7 @@
+ res = ast_unregister_application(testc_app);
+ res |= ast_unregister_application(tests_app);
+
+- return res;
++ return res;
+ }
+
+ static int load_module(void)
+Index: apps/app_ices.c
+===================================================================
+--- a/apps/app_ices.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_ices.c (.../trunk) (revision 186562)
+@@ -58,7 +58,7 @@
+ <description>
+ <para>Streams to an icecast server using ices (available separately).
+ A configuration file must be supplied for ices (see contrib/asterisk-ices.xml).</para>
+- <note><para>ICES version 2 cient and server required.</para></note>
++ <note><para>ICES version 2 client and server required.</para></note>
+ </description>
+ </application>
+
+Index: apps/app_directed_pickup.c
+===================================================================
+--- a/apps/app_directed_pickup.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_directed_pickup.c (.../trunk) (revision 186562)
+@@ -40,6 +40,7 @@
+ #include "asterisk/lock.h"
+ #include "asterisk/app.h"
+ #include "asterisk/features.h"
++#include "asterisk/callerid.h"
+
+ #define PICKUPMARK "PICKUPMARK"
+
+@@ -91,9 +92,21 @@
+ 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_channel_update_connected_line(chan, &connected_caller);
++
++ ast_channel_lock(chan);
++ ast_connected_line_copy_from_caller(&connected_caller, &chan->cid);
++ ast_channel_unlock(chan);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_queue_connected_line_update(chan, &connected_caller);
++ ast_party_connected_line_free(&connected_caller);
++
+ if ((res = ast_answer(chan))) {
+ ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
+ return -1;
+Index: apps/app_minivm.c
+===================================================================
+--- a/apps/app_minivm.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_minivm.c (.../trunk) (revision 186562)
+@@ -1177,7 +1177,7 @@
+ }
+ ast_debug(4, "Fromstring now: %s\n", ast_strlen_zero(passdata) ? "-default-" : passdata);
+
+- fprintf(p, "Message-ID: <Asterisk-%d-%s-%d-%s>\n", (unsigned int)rand(), vmu->username, (int)getpid(), who);
++ fprintf(p, "Message-ID: <Asterisk-%d-%s-%d-%s>\n", (unsigned int)ast_random(), vmu->username, (int)getpid(), who);
+ len_passdata = strlen(vmu->fullname) * 2 + 3;
+ passdata2 = alloca(len_passdata);
+ if (!ast_strlen_zero(vmu->email))
+@@ -1210,7 +1210,7 @@
+ fprintf(p, "MIME-Version: 1.0\n");
+
+ /* Something unique. */
+- snprintf(bound, sizeof(bound), "voicemail_%s%d%d", vmu->username, (int)getpid(), (unsigned int)rand());
++ snprintf(bound, sizeof(bound), "voicemail_%s%d%d", vmu->username, (int)getpid(), (unsigned int)ast_random());
+
+ fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
+
+@@ -1785,13 +1785,10 @@
+ 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;
++ 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);
++ ast_event_queue_and_cache(event);
+ }
+
+ /*! \brief Send MWI using interal Asterisk event subsystem */
+Index: apps/app_dumpchan.c
+===================================================================
+--- a/apps/app_dumpchan.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_dumpchan.c (.../trunk) (revision 186562)
+@@ -149,7 +149,7 @@
+
+ static int dumpchan_exec(struct ast_channel *chan, void *data)
+ {
+- struct ast_str *vars = ast_str_thread_get(&global_app_buf, 16);
++ struct ast_str *vars = ast_str_thread_get(&ast_str_thread_global_buf, 16);
+ char info[1024];
+ int level = 0;
+ static char *line = "================================================================================";
+Index: apps/app_voicemail.c
+===================================================================
+--- a/apps/app_voicemail.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_voicemail.c (.../trunk) (revision 186562)
+@@ -325,7 +325,7 @@
+ static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
+ static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu);
+ static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
+-static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
++static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
+ static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
+ static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
+ static void vmstate_insert(struct vm_state *vms);
+@@ -518,11 +518,6 @@
+ Spanish also uses:
+ \arg \b vm-youhaveno
+
+-Ukrainian requires the following additional soundfile:
+-\arg \b vm-nove 'nove'
+-\arg \b vm-stare 'stare'
+-\arg \b digits/ua/1e 'odne'
+-
+ Italian requires the following additional soundfile:
+
+ For vm_intro_it:
+@@ -809,7 +804,7 @@
+ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
+ static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
+ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
+-static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
++static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
+ static void apply_options(struct ast_vm_user *vmu, const char *options);
+ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
+ static int is_valid_dtmf(const char *key);
+@@ -1916,9 +1911,9 @@
+ }
+ imap_delete_old_greeting(fn, vms);
+ }
+-
+- make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
+- /* read mail file to memory */
++
++ make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX", S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
++ /* read mail file to memory */
+ len = ftell(p);
+ rewind(p);
+ if (!(buf = ast_malloc(len + 1))) {
+@@ -2299,22 +2294,14 @@
+
+ static void update_messages_by_imapuser(const char *user, unsigned long number)
+ {
+- struct vmstate *vlist = NULL;
++ struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
+
+- AST_LIST_LOCK(&vmstates);
+- AST_LIST_TRAVERSE(&vmstates, vlist, list) {
+- if (!vlist->vms) {
+- ast_debug(3, "error: vms is NULL for %s\n", user);
+- continue;
+- }
+- if (!vlist->vms->imapuser) {
+- ast_debug(3, "error: imapuser is NULL for %s\n", user);
+- continue;
+- }
+- ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vlist->vms->vmArrayIndex, vlist->vms->interactive);
+- vlist->vms->msgArray[vlist->vms->vmArrayIndex++] = number;
++ if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
++ return;
+ }
+- AST_LIST_UNLOCK(&vmstates);
++
++ ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
++ vms->msgArray[vms->vmArrayIndex++] = number;
+ }
+
+ void mm_searched(MAILSTREAM *stream, unsigned long number)
+@@ -2605,7 +2592,7 @@
+ return vms_p;
+ }
+
+-static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
++static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
+ {
+ struct vmstate *vlist = NULL;
+
+@@ -3856,9 +3843,16 @@
+ return 1;
+ }
+
+-static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category, const char *flag)
++static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category, const char *flag)
+ {
+ char callerid[256];
++ char fromdir[256], fromfile[256];
++ struct ast_config *msg_cfg;
++ const char *origcallerid, *origtime;
++ char origcidname[80], origcidnum[80], origdate[80];
++ int inttime;
++ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
++
+ /* Prepare variables for substitution in email body and subject */
+ pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
+ pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
+@@ -3873,6 +3867,35 @@
+ pbx_builtin_setvar_helper(ast, "VM_DATE", date);
+ pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
+ pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
++
++ /* Retrieve info from VM attribute file */
++ make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
++ make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
++ if (strlen(fromfile) < sizeof(fromfile) - 5) {
++ strcat(fromfile, ".txt");
++ }
++ if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
++ if (option_debug > 0) {
++ ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
++ }
++ return;
++ }
++
++ if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
++ pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
++ ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
++ pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
++ pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
++ }
++
++ if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%d", &inttime) == 1) {
++ struct timeval tv = { inttime, };
++ struct ast_tm tm;
++ ast_localtime(&tv, &tm, NULL);
++ ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
++ pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
++ }
++ ast_config_destroy(msg_cfg);
+ }
+
+ /*!
+@@ -4006,7 +4029,7 @@
+ *
+ * The email body, and base 64 encoded attachement (if any) are stored to the file identified by *p. This method does not actually send the email. That is done by invoking the configure 'mailcmd' and piping this generated file into it, or with the sendemail() function.
+ */
+-static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
++static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
+ {
+ char date[256];
+ char host[MAXHOSTNAMELEN] = "";
+@@ -4066,7 +4089,7 @@
+ if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
+ char *ptr;
+ memset(passdata2, 0, len_passdata2);
+- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category, flag);
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category, flag);
+ pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
+ len_passdata = strlen(passdata2) * 3 + 300;
+ passdata = alloca(len_passdata);
+@@ -4117,7 +4140,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);
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category, flag);
+ pbx_substitute_variables_helper(ast, e_subj, passdata, len_passdata);
+ if (check_mime(passdata)) {
+ int first_line = 1;
+@@ -4203,17 +4226,57 @@
+ 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);
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
+ pbx_substitute_variables_helper(ast, e_body, passdata, vmlen);
+ fprintf(p, "%s" ENDL, passdata);
+ ast_channel_free(ast);
+ } else
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+- } else if (msgnum > -1){
+- fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a %s long %s message (number %d)" ENDL
+- "in mailbox %s from %s, on %s so you might" ENDL
+- "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname,
+- dur, flag, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
++ } else if (msgnum > -1) {
++ if (strcmp(vmu->mailbox, mailbox)) {
++ /* Forwarded type */
++ struct ast_config *msg_cfg;
++ const char *v;
++ int inttime;
++ char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
++ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
++ /* Retrieve info from VM attribute file */
++ make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
++ make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
++ if (strlen(fromfile) < sizeof(fromfile) - 5) {
++ strcat(fromfile, ".txt");
++ }
++ if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
++ if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
++ ast_copy_string(origcallerid, v, sizeof(origcallerid));
++ }
++
++ /* You might be tempted to do origdate, except that a) it's in the wrong
++ * format, and b) it's missing for IMAP recordings. */
++ if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%d", &inttime) == 1) {
++ struct timeval tv = { inttime, };
++ struct ast_tm tm;
++ ast_localtime(&tv, &tm, NULL);
++ ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
++ }
++ fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
++ " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
++ "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
++ " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
++ msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
++ date, origcallerid, origdate);
++ ast_config_destroy(msg_cfg);
++ } else {
++ goto plain_message;
++ }
++ } else {
++plain_message:
++ fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
++ "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
++ "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
++ ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
++ (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
++ }
+ } else {
+ fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
+ "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
+@@ -4288,7 +4351,7 @@
+ }
+ #undef ENDL
+
+-static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
++static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
+ {
+ FILE *p=NULL;
+ char tmp[80] = "/tmp/astmail-XXXXXX";
+@@ -4307,7 +4370,7 @@
+ ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
+ return -1;
+ } else {
+- make_email_file(p, srcemail, vmu, msgnum, context, mailbox, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
++ make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
+ fclose(p);
+ snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
+ ast_safe_system(tmp2);
+@@ -4316,7 +4379,7 @@
+ return 0;
+ }
+
+-static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
++static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
+ {
+ char date[256];
+ char host[MAXHOSTNAMELEN] = "";
+@@ -4347,7 +4410,7 @@
+ int vmlen = strlen(fromstring)*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);
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
+ pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
+ fprintf(p, "From: %s <%s>\n", passdata, who);
+ ast_channel_free(ast);
+@@ -4363,7 +4426,7 @@
+ int vmlen = strlen(pagersubject) * 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);
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
+ pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
+ fprintf(p, "Subject: %s\n\n", passdata);
+ ast_channel_free(ast);
+@@ -4385,7 +4448,7 @@
+ int vmlen = strlen(pagerbody) * 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);
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
+ pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
+ fprintf(p, "%s\n", passdata);
+ ast_channel_free(ast);
+@@ -6215,10 +6278,7 @@
+ 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);
++ ast_event_queue_and_cache(event);
+ }
+
+ /*!
+@@ -6275,14 +6335,15 @@
+ RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
+
+ /* XXX possible imap issue, should category be NULL XXX */
+- sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
++ sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
+
+ if (attach_user_voicemail)
+ DISPOSE(todir, msgnum);
+ }
+
+- if (!ast_strlen_zero(vmu->pager))
+- sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category, flag);
++ if (!ast_strlen_zero(vmu->pager)) {
++ sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category, flag);
++ }
+
+ if (ast_test_flag(vmu, VM_DELETE))
+ DELETE(todir, msgnum, fn, vmu);
+@@ -6462,6 +6523,7 @@
+ while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
+ free_user(receiver);
+ }
++ ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
+ valid_extensions = 0;
+ break;
+ }
+@@ -6535,7 +6597,7 @@
+ myserveremail = vmtmp->serveremail;
+ attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
+ /* NULL category for IMAP storage */
+- sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan, NULL, urgent_str);
++ sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan, NULL, urgent_str);
+ #else
+ copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
+ #endif
+@@ -7323,7 +7385,8 @@
+ if (!res) {
+ if (lastnum == 0) {
+ res = ast_play_and_wait(chan, "vm-no");
+- } else {
++ }
++ if (!res) {
+ res = ast_say_counted_noun(chan, lastnum, "vm-message");
+ }
+ }
+@@ -10270,7 +10333,7 @@
+ char *current;
+
+ /* Add 16 for fudge factor */
+- struct ast_str *str = ast_str_thread_get(&global_app_buf, strlen(value) + 16);
++ struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
+
+ ast_str_reset(str);
+
+Index: apps/app_dial.c
+===================================================================
+--- a/apps/app_dial.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_dial.c (.../trunk) (revision 186562)
+@@ -54,7 +54,7 @@
+ #include "asterisk/utils.h"
+ #include "asterisk/app.h"
+ #include "asterisk/causes.h"
+-#include "asterisk/rtp.h"
++#include "asterisk/rtp_engine.h"
+ #include "asterisk/cdr.h"
+ #include "asterisk/manager.h"
+ #include "asterisk/privacy.h"
+@@ -109,11 +109,13 @@
+ <option name="D" argsep=":">
+ <argument name="called" />
+ <argument name="calling" />
++ <argument name="progress" />
+ <para>Send the specified DTMF strings <emphasis>after</emphasis> the called
+ party has answered, but before the call gets bridged. The
+ <replaceable>called</replaceable> DTMF string is sent to the called party, and the
+ <replaceable>calling</replaceable> DTMF string is sent to the calling party. Both arguments
+- can be used alone.</para>
++ can be used alone. If <replaceable>progress</replaceable> is specified, its DTMF is sent
++ immediately after receiving a PROGRESS message.</para>
+ </option>
+ <option name="e">
+ <para>Execute the <literal>h</literal> extension for peer after the call ends</para>
+@@ -155,6 +157,10 @@
+ <option name="i">
+ <para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
+ </option>
++ <option name="I">
++ <para>Asterisk will ignore any connected line update requests or redirecting party update
++ requests it may receiveon this dial attempt.</para>
++ </option>
+ <option name="k">
+ <para>Allow the called party to enable parking of the call by sending
+ the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
+@@ -380,7 +386,6 @@
+ 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.</para>
+-
+ <para>If the <variable>OUTBOUND_GROUP</variable> variable is set, all peer channels created by this
+ application will be put into that group (as in Set(GROUP()=...).
+ If the <variable>OUTBOUND_GROUP_ONCE</variable> variable is set, all peer channels created by this
+@@ -462,12 +467,13 @@
+ OPT_GO_ON = (1 << 5),
+ OPT_CALLEE_HANGUP = (1 << 6),
+ OPT_CALLER_HANGUP = (1 << 7),
++ OPT_ORIGINAL_CLID = (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),
+@@ -488,9 +494,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,
+@@ -522,13 +529,14 @@
+ 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_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
+ 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('N', OPT_SCREEN_NOCALLERID),
+ AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
+ AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
+ AST_APP_OPTION('p', OPT_SCREENING),
+@@ -556,8 +564,10 @@
+ struct chanlist *next;
+ struct ast_channel *chan;
+ uint64_t flags;
++ struct ast_party_connected_line connected;
+ };
+
++static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode);
+
+ static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
+ {
+@@ -651,7 +661,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);
+@@ -699,6 +708,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;
+@@ -739,28 +750,38 @@
+ handle_cause(cause, num);
+ ast_hangup(original);
+ } else {
+- char *new_cid_num, *new_cid_name;
+- struct ast_channel *src;
++ if (single) {
++ ast_rtp_instance_early_bridge_make_compatible(c, in);
++ }
+
+- ast_rtp_make_compatible(c, in, single);
++ c->cdrflags = in->cdrflags;
++
++ ast_channel_set_redirecting(c, apr);
++ ast_channel_lock(c);
++ while (ast_channel_trylock(in)) {
++ CHANNEL_DEADLOCK_AVOIDANCE(c);
++ }
++ 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;
++
+ 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 */
++ S_REPLACE(c->cid.cid_num, ast_strdupa(S_OR(in->macroexten, in->exten)));
++ S_REPLACE(c->cid.cid_name, NULL);
++ ast_string_field_set(c, accountcode, c->accountcode);
+ } else {
+- new_cid_num = ast_strdup(in->cid.cid_num);
+- new_cid_name = ast_strdup(in->cid.cid_name);
+- src = in;
++ ast_party_caller_copy(&c->cid, &in->cid);
++ ast_string_field_set(c, accountcode, in->accountcode);
+ }
+- 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);
++ ast_party_connected_line_copy(&c->connected, apc);
+
+- 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)));
++ S_REPLACE(in->cid.cid_rdnis, ast_strdup(c->cid.cid_rdnis));
++ ast_channel_unlock(in);
++ ast_channel_unlock(c);
++ ast_channel_update_redirecting(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);
+@@ -770,7 +791,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);
+@@ -796,23 +816,35 @@
+ static struct ast_channel *wait_for_answer(struct ast_channel *in,
+ struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags,
+ struct privacy_args *pa,
+- const struct cause_args *num_in, int *result)
++ const struct cause_args *num_in, int *result, char *dtmf_progress)
+ {
+ struct cause_args num = *num_in;
+ int prestart = num.busy + num.congestion + num.nochan;
+ 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;
++ struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
+ 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_channel_lock(outgoing->chan);
++ ast_connected_line_copy_from_caller(&connected_caller, &outgoing->chan->cid);
++ ast_channel_unlock(outgoing->chan);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_update_connected_line(in, &connected_caller);
++ ast_party_connected_line_free(&connected_caller);
++ }
+ }
+
+ #ifdef HAVE_EPOLL
+@@ -859,6 +891,18 @@
+ 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_channel_update_connected_line(in, &o->connected);
++ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) {
++ ast_channel_lock(c);
++ ast_connected_line_copy_from_caller(&connected_caller, &c->cid);
++ ast_channel_unlock(c);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_update_connected_line(in, &connected_caller);
++ ast_party_connected_line_free(&connected_caller);
++ }
++ }
+ peer = c;
+ ast_copy_flags64(peerflags, o,
+ OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
+@@ -897,6 +941,18 @@
+ /* 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_channel_update_connected_line(in, &o->connected);
++ } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) {
++ ast_channel_lock(c);
++ ast_connected_line_copy_from_caller(&connected_caller, &c->cid);
++ ast_channel_unlock(c);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_update_connected_line(in, &connected_caller);
++ ast_party_connected_line_free(&connected_caller);
++ }
++ }
+ peer = c;
+ if (peer->cdr) {
+ peer->cdr->answer = ast_tvnow();
+@@ -952,6 +1008,10 @@
+ ast_channel_early_bridge(in, c);
+ if (!ast_test_flag64(outgoing, OPT_RINGBACK))
+ ast_indicate(in, AST_CONTROL_PROGRESS);
++ if(!ast_strlen_zero(dtmf_progress)) {
++ ast_verb(3, "Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n", dtmf_progress);
++ ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
++ }
+ break;
+ case AST_CONTROL_VIDUPDATE:
+ ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name);
+@@ -961,6 +1021,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_connected_line_parse_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))
+@@ -1052,8 +1135,8 @@
+ }
+
+ if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
+- (f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */
+- ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
++ detect_disconnect(in, f->subclass, featurecode)) {
++ ast_verb(3, "User requested call disconnect.\n");
+ *to = 0;
+ strcpy(pa->status, "CANCEL");
+ ast_cdr_noanswer(in->cdr);
+@@ -1075,7 +1158,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);
+ }
+@@ -1097,6 +1182,26 @@
+ return peer;
+ }
+
++static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode)
++{
++ struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
++ struct ast_call_feature feature = { 0, };
++ int res;
++
++ ast_str_append(&featurecode, 1, "%c", code);
++
++ res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature);
++
++ if (res != AST_FEATURE_RETURN_STOREDIGITS) {
++ ast_str_reset(featurecode);
++ }
++ if (feature.feature_mask & AST_FEATURE_DISCONNECT) {
++ return 1;
++ }
++
++ return 0;
++}
++
+ static void replace_macro_delimiter(char *s)
+ {
+ for (; *s; s++)
+@@ -1394,11 +1499,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);
+ }
+
+@@ -1502,7 +1607,7 @@
+
+ struct ast_bridge_config config = { { 0, } };
+ struct timeval calldurationlimit = { 0, };
+- char *dtmfcalled = NULL, *dtmfcalling = NULL;
++ char *dtmfcalled = NULL, *dtmfcalling = NULL, *dtmf_progress=NULL;
+ struct privacy_args pa = {
+ .sentringing = 0,
+ .privdb_val = 0,
+@@ -1553,12 +1658,11 @@
+ 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);
+ }
+-
++
+ if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
+ calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]);
+ if (!calldurationlimit.tv_sec) {
+@@ -1570,8 +1674,9 @@
+ }
+
+ if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
+- dtmfcalling = opt_args[OPT_ARG_SENDDTMF];
+- dtmfcalled = strsep(&dtmfcalling, ":");
++ dtmf_progress = opt_args[OPT_ARG_SENDDTMF];
++ dtmfcalled = strsep(&dtmf_progress, ":");
++ dtmfcalling = strsep(&dtmf_progress, ":");
+ }
+
+ if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
+@@ -1591,7 +1696,7 @@
+ res = -1; /* reset default */
+ }
+
+- if (ast_test_flag64(&opts, OPT_DTMF_EXIT)) {
++ if (ast_test_flag64(&opts, OPT_DTMF_EXIT) || ast_test_flag64(&opts, OPT_CALLER_HANGUP)) {
+ __ast_answer(chan, 0, 0);
+ }
+
+@@ -1608,7 +1713,7 @@
+ 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_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE);
+
+ /* loop through the list of dial destinations */
+ rest = args.peers;
+@@ -1645,6 +1750,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)
+@@ -1717,8 +1830,14 @@
+ }
+ pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
+
++ ast_channel_lock(tc);
++ while (ast_channel_trylock(chan)) {
++ CHANNEL_DEADLOCK_AVOIDANCE(tc);
++ }
+ /* Setup outgoing SDP to match incoming one */
+- ast_rtp_make_compatible(tc, chan, !outgoing && !rest);
++ if (!outgoing && !rest) {
++ ast_rtp_instance_early_bridge_make_compatible(tc, chan);
++ }
+
+ /* Inherit specially named variables from parent channel */
+ ast_channel_inherit_variables(chan, tc);
+@@ -1728,20 +1847,31 @@
+ 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);
++ }
++
++ ast_connected_line_copy_from_caller(&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;
+
+@@ -1778,6 +1908,8 @@
+ if (tc->hangupcause) {
+ chan->hangupcause = tc->hangupcause;
+ }
++ ast_channel_unlock(chan);
++ ast_channel_unlock(tc);
+ ast_hangup(tc);
+ tc = NULL;
+ ast_free(tmp);
+@@ -1785,8 +1917,11 @@
+ } else {
+ senddialevent(chan, tc, numsubst);
+ ast_verb(3, "Called %s\n", numsubst);
+- if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID))
++ 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);
++ }
++ ast_channel_unlock(chan);
++ ast_channel_unlock(tc);
+ }
+ /* Put them in the list of outgoing thingies... We're ready now.
+ XXX If we're forcibly removed, these outgoing calls won't get
+@@ -1838,7 +1973,7 @@
+ }
+ }
+
+- peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result);
++ peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result, dtmf_progress);
+
+ /* The ast_channel_datastore_remove() function could fail here if the
+ * datastore was moved to another channel during a masquerade. If this is
+Index: apps/app_queue.c
+===================================================================
+--- a/apps/app_queue.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_queue.c (.../trunk) (revision 186562)
+@@ -94,6 +94,7 @@
+ #include "asterisk/strings.h"
+ #include "asterisk/global_datastores.h"
+ #include "asterisk/taskprocessor.h"
++#include "asterisk/callerid.h"
+
+ /*!
+ * \par Please read before modifying this file.
+@@ -141,6 +142,10 @@
+ <para>Ignore call forward requests from queue members and do nothing
+ when they are requested.</para>
+ </option>
++ <option name="I">
++ <para>Asterisk will ignore any connected line update requests or any redirecting party
++ update requests it may receive on this dial attempt.</para>
++ </option>
+ <option name="r">
+ <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
+ </option>
+@@ -625,6 +630,8 @@
+ time_t lastcall;
+ struct call_queue *lastqueue;
+ struct member *member;
++ unsigned int update_connectedline:1;
++ struct ast_party_connected_line connected;
+ };
+
+
+@@ -1630,7 +1637,7 @@
+
+ if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
+ if (ast_string_field_init(q, 64)) {
+- free(q);
++ ao2_ref(q, -1);
+ return NULL;
+ }
+ ast_string_field_set(q, name, queuename);
+@@ -2268,11 +2275,56 @@
+ }
+ }
+
+-/*!
+- * \brief traverse all defined queues which have calls waiting and contain this member
+- * \retval 0 if no other queue has precedence (higher weight)
+- * \retval 1 if found
+-*/
++/*!
++ * \brief Get the number of members available to accept a call.
++ *
++ * \note The queue passed in should be locked prior to this function call
++ *
++ * \param[in] q The queue for which we are couting the number of available members
++ * \return Return the number of available members in queue q
++ */
++static int num_available_members(struct call_queue *q)
++{
++ struct member *mem;
++ int avl = 0;
++ struct ao2_iterator mem_iter;
++
++ mem_iter = ao2_iterator_init(q->members, 0);
++ while ((mem = ao2_iterator_next(&mem_iter))) {
++ switch (mem->status) {
++ case AST_DEVICE_INUSE:
++ if (!q->ringinuse)
++ break;
++ /* else fall through */
++ case AST_DEVICE_NOT_INUSE:
++ case AST_DEVICE_UNKNOWN:
++ if (!mem->paused) {
++ avl++;
++ }
++ break;
++ }
++ ao2_ref(mem, -1);
++
++ /* If autofill is not enabled or if the queue's strategy is ringall, then
++ * we really don't care about the number of available members so much as we
++ * do that there is at least one available.
++ *
++ * In fact, we purposely will return from this function stating that only
++ * one member is available if either of those conditions hold. That way,
++ * functions which determine what action to take based on the number of available
++ * members will operate properly. The reasoning is that even if multiple
++ * members are available, only the head caller can actually be serviced.
++ */
++ if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
++ break;
++ }
++ }
++
++ return avl;
++}
++
++/* traverse all defined queues which have calls waiting and contain this member
++ return 0 if no other queue has precedence (higher weight) or 1 if found */
+ static int compare_weight(struct call_queue *rq, struct member *member)
+ {
+ struct call_queue *q;
+@@ -2292,7 +2344,7 @@
+ if (q->count && q->members) {
+ if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
+ ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
+- if (q->weight > rq->weight) {
++ if (q->weight > rq->weight && q->count >= num_available_members(q)) {
+ ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
+ found = 1;
+ }
+@@ -2319,7 +2371,7 @@
+ /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
+ static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
+ {
+- struct ast_str *buf = ast_str_thread_get(&global_app_buf, len + 1);
++ struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
+ char *tmp;
+
+ if (pbx_builtin_serialize_variables(chan, &buf)) {
+@@ -2434,23 +2486,41 @@
+ (*busies)++;
+ return 0;
+ }
+-
++
++ ast_channel_lock(tmp->chan);
++ while (ast_channel_trylock(qe->chan)) {
++ CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
++ }
++
+ if (qe->cancel_answered_elsewhere) {
+ ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
+ }
+ tmp->chan->appl = "AppQueue";
+ tmp->chan->data = "(Outgoing Line)";
+ memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
+- if (tmp->chan->cid.cid_num)
+- ast_free(tmp->chan->cid.cid_num);
+- tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
+- if (tmp->chan->cid.cid_name)
+- ast_free(tmp->chan->cid.cid_name);
+- tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
+- if (tmp->chan->cid.cid_ani)
+- ast_free(tmp->chan->cid.cid_ani);
+- tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
+
++ /* If the new channel has no callerid, try to guess what it should be */
++ if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
++ if (!ast_strlen_zero(qe->chan->connected.id.number)) {
++ ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
++ tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
++ } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
++ ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
++ } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
++ ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
++ }
++ tmp->update_connectedline = 0;
++ }
++
++ if (tmp->chan->cid.cid_rdnis)
++ ast_free(tmp->chan->cid.cid_rdnis);
++ tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
++ ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
++
++ tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
++
++ ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
++
+ /* Inherit specially named variables from parent channel */
+ ast_channel_inherit_variables(qe->chan, tmp->chan);
+
+@@ -2458,7 +2528,6 @@
+ tmp->chan->adsicpe = qe->chan->adsicpe;
+
+ /* Inherit context and extension */
+- ast_channel_lock(qe->chan);
+ macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
+ ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
+ macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
+@@ -2466,13 +2535,14 @@
+ ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
+ else
+ ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
+- ast_channel_unlock(qe->chan);
+
+ /* Place the call, but don't wait on the answer */
+ if ((res = ast_call(tmp->chan, location, 0))) {
+ /* Again, keep going even if there's an error */
+ ast_debug(1, "ast call on peer returned %d\n", res);
+ ast_verb(3, "Couldn't call %s\n", tmp->interface);
++ ast_channel_unlock(tmp->chan);
++ ast_channel_unlock(qe->chan);
+ do_hang(tmp);
+ (*busies)++;
+ update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
+@@ -2500,6 +2570,8 @@
+ qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+ ast_verb(3, "Called %s\n", tmp->interface);
+ }
++ ast_channel_unlock(tmp->chan);
++ ast_channel_unlock(qe->chan);
+
+ update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
+ return 1;
+@@ -2730,7 +2802,7 @@
+ * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
+ * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
+ */
+-static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
++static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
+ {
+ const char *queue = qe->parent->name;
+ struct callattempt *o, *start = NULL, *prev = NULL;
+@@ -2750,7 +2822,13 @@
+ #ifdef HAVE_EPOLL
+ struct callattempt *epollo;
+ #endif
++ struct ast_party_connected_line connected_caller;
++ char *inchan_name;
+
++ ast_channel_lock(qe->chan);
++ inchan_name = ast_strdupa(qe->chan->name);
++ ast_channel_unlock(qe->chan);
++
+ starttime = (long) time(NULL);
+ #ifdef HAVE_EPOLL
+ for (epollo = outgoing; epollo; epollo = epollo->q_next) {
+@@ -2800,9 +2878,28 @@
+ }
+ winner = ast_waitfor_n(watchers, pos, to);
+ for (o = start; o; o = o->call_next) {
++ /* We go with a static buffer here instead of using ast_strdupa. Using
++ * ast_strdupa in a loop like this one can cause a stack overflow
++ */
++ char ochan_name[AST_CHANNEL_NAME];
++ ast_channel_lock(o->chan);
++ ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
++ ast_channel_unlock(o->chan);
+ if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
+ if (!peer) {
+- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
++ ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
++ if (update_connectedline) {
++ if (o->connected.id.number) {
++ ast_channel_update_connected_line(in, &o->connected);
++ } else if (o->update_connectedline) {
++ ast_channel_lock(o->chan);
++ ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
++ ast_channel_unlock(o->chan);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_update_connected_line(in, &connected_caller);
++ ast_party_connected_line_free(&connected_caller);
++ }
++ }
+ peer = o;
+ }
+ } else if (o->chan && (o->chan == winner)) {
+@@ -2811,12 +2908,15 @@
+ ast_copy_string(membername, o->member->membername, sizeof(membername));
+
+ if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
+- ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
++ ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
+ numnochan++;
+ do_hang(o);
+ winner = NULL;
+ continue;
+ } else if (!ast_strlen_zero(o->chan->call_forward)) {
++ struct ast_party_redirecting *apr = &o->chan->redirecting;
++ struct ast_party_connected_line *apc = &o->chan->connected;
++ struct ast_channel *original = o->chan;
+ char tmpchan[256];
+ char *stuff;
+ char *tech;
+@@ -2831,7 +2931,7 @@
+ tech = "Local";
+ }
+ /* Before processing channel, go ahead and check for forwarding */
+- ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
++ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
+ /* Setup parameters */
+ o->chan = ast_request(tech, in->nativeformats, stuff, &status);
+ if (!o->chan) {
+@@ -2839,32 +2939,42 @@
+ o->stillgoing = 0;
+ numnochan++;
+ } else {
++ ast_channel_lock(o->chan);
++ while (ast_channel_trylock(in)) {
++ CHANNEL_DEADLOCK_AVOIDANCE(o->chan);
++ }
+ ast_channel_inherit_variables(in, o->chan);
+ ast_channel_datastore_inherit(in, o->chan);
+- if (o->chan->cid.cid_num)
+- ast_free(o->chan->cid.cid_num);
+- o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
+
+- if (o->chan->cid.cid_name)
+- ast_free(o->chan->cid.cid_name);
+- o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
+-
+ ast_string_field_set(o->chan, accountcode, in->accountcode);
+ o->chan->cdrflags = in->cdrflags;
+
+- if (in->cid.cid_ani) {
+- if (o->chan->cid.cid_ani)
+- ast_free(o->chan->cid.cid_ani);
+- o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
+- }
++ ast_channel_set_redirecting(o->chan, apr);
++
+ if (o->chan->cid.cid_rdnis)
+ ast_free(o->chan->cid.cid_rdnis);
+- o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
++ o->chan->cid.cid_rdnis = ast_strdup(S_OR(original->cid.cid_rdnis,S_OR(in->macroexten, in->exten)));
++
++ o->chan->cid.cid_tns = in->cid.cid_tns;
++
++ ast_party_caller_copy(&o->chan->cid, &in->cid);
++ ast_party_connected_line_copy(&o->chan->connected, apc);
++
++ ast_channel_update_redirecting(in, apr);
++ if (in->cid.cid_rdnis) {
++ ast_free(in->cid.cid_rdnis);
++ }
++ in->cid.cid_rdnis = ast_strdup(o->chan->cid.cid_rdnis);
++
++ update_connectedline = 1;
++
+ if (ast_call(o->chan, tmpchan, 0)) {
+ ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
+ do_hang(o);
+ numnochan++;
+ }
++ ast_channel_unlock(in);
++ ast_channel_unlock(o->chan);
+ }
+ /* Hangup the original channel now, in case we needed it */
+ ast_hangup(winner);
+@@ -2877,12 +2987,24 @@
+ case AST_CONTROL_ANSWER:
+ /* This is our guy if someone answered. */
+ if (!peer) {
+- ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
++ ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
++ if (update_connectedline) {
++ if (o->connected.id.number) {
++ ast_channel_update_connected_line(in, &o->connected);
++ } else if (o->update_connectedline) {
++ ast_channel_lock(o->chan);
++ ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
++ ast_channel_unlock(o->chan);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_update_connected_line(in, &connected_caller);
++ ast_party_connected_line_free(&connected_caller);
++ }
++ }
+ peer = o;
+ }
+ break;
+ case AST_CONTROL_BUSY:
+- ast_verb(3, "%s is busy\n", o->chan->name);
++ ast_verb(3, "%s is busy\n", ochan_name);
+ if (in->cdr)
+ ast_cdr_busy(in->cdr);
+ do_hang(o);
+@@ -2897,7 +3019,7 @@
+ numbusies++;
+ break;
+ case AST_CONTROL_CONGESTION:
+- ast_verb(3, "%s is circuit-busy\n", o->chan->name);
++ ast_verb(3, "%s is circuit-busy\n", ochan_name);
+ if (in->cdr)
+ ast_cdr_busy(in->cdr);
+ endtime = (long) time(NULL);
+@@ -2912,13 +3034,37 @@
+ numbusies++;
+ break;
+ case AST_CONTROL_RINGING:
+- ast_verb(3, "%s is ringing\n", o->chan->name);
++ ast_verb(3, "%s is ringing\n", ochan_name);
+ break;
+ case AST_CONTROL_OFFHOOK:
+ /* Ignore going off hook */
+ break;
++ case AST_CONTROL_CONNECTED_LINE:
++ if (!update_connectedline) {
++ ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
++ } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
++ struct ast_party_connected_line connected;
++ ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
++ ast_party_connected_line_set_init(&connected, &o->connected);
++ ast_connected_line_parse_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", ochan_name, inchan_name);
++ ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
++ }
++ break;
++ case AST_CONTROL_REDIRECTING:
++ if (!update_connectedline) {
++ ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
++ } else {
++ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
++ ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
++ }
++ break;
+ default:
+ ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
++ break;
+ }
+ }
+ ast_frfree(f);
+@@ -2981,80 +3127,46 @@
+ /*!
+ * \brief Check if we should start attempting to call queue members.
+ *
+- * The behavior of this function is dependent first on whether autofill is enabled
+- * and second on whether the ring strategy is ringall. If autofill is not enabled,
+- * then return true if we're the head of the queue. If autofill is enabled, then
+- * we count the available members and see if the number of available members is enough
+- * that given our position in the queue, we would theoretically be able to connect to
+- * one of those available members
++ * A simple process, really. Count the number of members who are available
++ * to take our call and then see if we are in a position in the queue at
++ * which a member could accept our call.
++ *
++ * \param[in] qe The caller who wants to know if it is his turn
++ * \retval 0 It is not our turn
++ * \retval 1 It is our turn
+ */
+ static int is_our_turn(struct queue_ent *qe)
+ {
+ struct queue_ent *ch;
+- struct member *cur;
+- int avl = 0;
++ int res;
++ int avl;
+ int idx = 0;
+- int res;
++ /* This needs a lock. How many members are available to be served? */
++ ao2_lock(qe->parent);
+
+- if (!qe->parent->autofill) {
+- /* Atomically read the parent head -- does not need a lock */
+- ch = qe->parent->head;
+- /* If we are now at the top of the head, break out */
+- if (ch == qe) {
+- ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
+- res = 1;
+- } else {
+- ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
+- res = 0;
+- }
++ avl = num_available_members(qe->parent);
+
+- } else {
+- /* This needs a lock. How many members are available to be served? */
+- ao2_lock(qe->parent);
+-
+- ch = qe->parent->head;
+-
+- if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
+- ast_debug(1, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
+- avl = 1;
+- } else {
+- struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
+- while ((cur = ao2_iterator_next(&mem_iter))) {
+- switch (cur->status) {
+- case AST_DEVICE_INUSE:
+- if (!qe->parent->ringinuse)
+- break;
+- /* else fall through */
+- case AST_DEVICE_NOT_INUSE:
+- case AST_DEVICE_UNKNOWN:
+- if (!cur->paused)
+- avl++;
+- break;
+- }
+- ao2_ref(cur, -1);
+- }
+- }
++ ch = qe->parent->head;
+
+- ast_debug(1, "There are %d available members.\n", avl);
+-
+- while ((idx < avl) && (ch) && (ch != qe)) {
+- if (!ch->pending)
+- idx++;
+- ch = ch->next;
+- }
+-
+- /* If the queue entry is within avl [the number of available members] calls from the top ... */
+- if (ch && idx < avl) {
+- ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
+- res = 1;
+- } else {
+- ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
+- res = 0;
+- }
+-
+- ao2_unlock(qe->parent);
++ ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
++
++ while ((idx < avl) && (ch) && (ch != qe)) {
++ if (!ch->pending)
++ idx++;
++ ch = ch->next;
+ }
+
++ ao2_unlock(qe->parent);
++
++ /* If the queue entry is within avl [the number of available members] calls from the top ... */
++ if (ch && idx < avl) {
++ ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
++ res = 1;
++ } else {
++ ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
++ res = 0;
++ }
++
+ return res;
+ }
+
+@@ -3506,6 +3618,7 @@
+ char *p;
+ char vars[2048];
+ int forwardsallowed = 1;
++ int update_connectedline = 1;
+ int callcompletedinsl;
+ struct ao2_iterator memi;
+ struct ast_datastore *datastore, *transfer_ds;
+@@ -3571,6 +3684,9 @@
+ case 'i':
+ forwardsallowed = 0;
+ break;
++ case 'I':
++ update_connectedline = 0;
++ break;
+ case 'x':
+ ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
+ break;
+@@ -3580,22 +3696,8 @@
+ case 'C':
+ qe->cancel_answered_elsewhere = 1;
+ break;
+-
+ }
+
+- if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
+- queue_end_bridge->q = qe->parent;
+- queue_end_bridge->chan = qe->chan;
+- bridge_config.end_bridge_callback = end_bridge_callback;
+- bridge_config.end_bridge_callback_data = queue_end_bridge;
+- bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
+- /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
+- * to make sure to increase the refcount of this queue so it cannot be freed until we
+- * are done with it. We remove this reference in end_bridge_callback.
+- */
+- queue_ref(qe->parent);
+- }
+-
+ /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited.
+ (this is mainly to support chan_local)
+ */
+@@ -3663,6 +3765,17 @@
+ }
+ }
+ AST_LIST_UNLOCK(dialed_interfaces);
++
++ ast_channel_lock(qe->chan);
++ /* If any pre-existing connected line information exists on this
++ * channel, like from the CONNECTED_LINE dialplan function, use this
++ * to seed the connected line information. It may, of course, be updated
++ * during the call
++ */
++ if (qe->chan->connected.id.number) {
++ ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
++ }
++ ast_channel_unlock(qe->chan);
+
+ if (di) {
+ free(tmp);
+@@ -3694,6 +3807,7 @@
+ tmp->oldstatus = cur->status;
+ tmp->lastcall = cur->lastcall;
+ tmp->lastqueue = cur->lastqueue;
++ tmp->update_connectedline = 1;
+ ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
+ /* Special case: If we ring everyone, go ahead and ring them, otherwise
+ just calculate their metric for the appropriate strategy */
+@@ -3734,7 +3848,7 @@
+ ring_one(qe, outgoing, &numbusies);
+ if (use_weight)
+ ao2_unlock(queues);
+- lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
++ lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
+ /* The ast_channel_datastore_remove() function could fail here if the
+ * datastore was moved to another channel during a masquerade. If this is
+ * the case, don't free the datastore here because later, when the channel
+@@ -4147,6 +4261,20 @@
+ qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
+ ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
+ ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
++
++ if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
++ queue_end_bridge->q = qe->parent;
++ queue_end_bridge->chan = qe->chan;
++ bridge_config.end_bridge_callback = end_bridge_callback;
++ bridge_config.end_bridge_callback_data = queue_end_bridge;
++ bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
++ /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
++ * to make sure to increase the refcount of this queue so it cannot be freed until we
++ * are done with it. We remove this reference in end_bridge_callback.
++ */
++ queue_ref(qe->parent);
++ }
++
+ time(&callstart);
+ transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
+ bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
+@@ -5591,6 +5719,11 @@
+ AST_APP_ARG(state_interface);
+ );
+
++ if (ast_strlen_zero(memberdata)) {
++ ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
++ return;
++ }
++
+ /* Add a new member */
+ parse = ast_strdupa(memberdata);
+
+Index: apps/app_followme.c
+===================================================================
+--- a/apps/app_followme.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/apps/app_followme.c (.../trunk) (revision 186562)
+@@ -998,7 +998,7 @@
+
+ static int app_exec(struct ast_channel *chan, void *data)
+ {
+- struct fm_args targs;
++ struct fm_args targs = { 0, };
+ struct ast_bridge_config config;
+ struct call_followme *f;
+ struct number *nm, *newnm;
+Index: UPGRADE.txt
+===================================================================
+--- a/UPGRADE.txt (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/UPGRADE.txt (.../trunk) (revision 186562)
+@@ -18,6 +18,14 @@
+ ===
+ ===========================================================
+
++From 1.6.2 to 1.6.3:
++
++* The usage of RTP inside of Asterisk has now become modularized. This means
++ the Asterisk RTP stack now exists as a loadable module, res_rtp_asterisk.
++ If you are not using autoload=yes in modules.conf you will need to ensure
++ it is set to load. If not, then any module which uses RTP (such as chan_sip)
++ will not be able to send or receive calls.
++
+ From 1.6.1 to 1.6.2:
+
+ * The res_indications module has been removed. Its functionality was important
+Index: CHANGES
+===================================================================
+--- a/CHANGES (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/CHANGES (.../trunk) (revision 186562)
+@@ -7,7 +7,67 @@
+ === and the other UPGRADE files for older releases.
+ ===
+ ======================================================================
++------------------------------------------------------------------------------
++--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.6.3 -------------
++------------------------------------------------------------------------------
+
++SIP Changes
++-----------
++ * Added preferred_codec_only option in sip.conf. This feature limits the joint
++ codecs sent in response to an INVITE to the single most preferred codec.
++
++Applications
++------------
++ * Added progress option to the app_dial D() option. When progress DTMF is
++ present, those values are sent immediatly upon receiving a PROGRESS message
++ regardless if the call has been answered or not.
++
++Dialplan Functions
++------------------
++ * Added new dialplan functions CONNECTEDLINE and REDIRECTING which permits
++ setting various connected line and redirecting party information.
++ * The CHANNEL() function now supports the "name" option.
++
++Queue changes
++-------------
++ * A new option, 'I' has been added to both app_queue and app_dial.
++ By setting this option, Asterisk will not update the caller with
++ connected line changes or redirecting party changes when they occur.
++
++mISDN channel driver (chan_misdn) changes
++----------------------------------------
++ * Added display_connected parameter to misdn.conf to put a display string
++ in the CONNECT message containing the connected name and/or number if
++ the presentation setting permits it.
++ * Added display_setup parameter to misdn.conf to put a display string
++ in the SETUP message containing the caller name and/or number if the
++ presentation setting permits it.
++ * Made misdn.conf parameters localdialplan and cpndialplan take a -1 to
++ indicate the dialplan settings are to be obtained from the asterisk
++ channel.
++ * Made misdn.conf parameter callerid accept the "name" <number> format
++ used by the rest of the system.
++ * Made use the nationalprefix and internationalprefix misdn.conf
++ parameters to prefix any received number from the ISDN link if that
++ number has the corresponding Type-Of-Number.
++ * Added the following new parameters: unknownprefix, netspecificprefix,
++ subscriberprefix, and abbreviatedprefix in misdn.conf to prefix any
++ received number from the ISDN link if that number has the corresponding
++ Type-Of-Number.
++
++
++SIP channel driver (chan_sip) changes
++-------------------------------------------
++ * The sendrpid parameter has been expanded to include the options
++ 'rpid' and 'pai'. Setting sendrpid to 'rpid' will cause Remote-Party-ID
++ header to be sent (equivalent to setting sendrpid=yes) and setting
++ sendrpid to 'pai' will cause P-Asserted-Identity header to be sent.
++
++Asterisk Manager Interface
++--------------------------
++ * The Hangup action now accepts a Cause header which may be used to
++ set the channel's hangup cause.
++
+ ------------------------------------------------------------------------------
+ --- Functionality changes from Asterisk 1.6.1 to Asterisk 1.6.2 -------------
+ ------------------------------------------------------------------------------
+Index: sounds/Makefile
+===================================================================
+--- a/sounds/Makefile (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/sounds/Makefile (.../trunk) (revision 186562)
+@@ -17,8 +17,8 @@
+
+ SOUNDS_DIR:=$(DESTDIR)$(ASTDATADIR)/sounds
+ MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh
+-CORE_SOUNDS_VERSION:=1.4.14
+-EXTRA_SOUNDS_VERSION:=1.4.8
++CORE_SOUNDS_VERSION:=1.4.15
++EXTRA_SOUNDS_VERSION:=1.4.9
+ SOUNDS_URL:=http://downloads.digium.com/pub/telephony/sounds/releases
+ MCS:=$(subst -EN-,-en-,$(MENUSELECT_CORE_SOUNDS))
+ MCS:=$(subst -FR-,-fr-,$(MCS))
+Index: autoconf/ast_ext_lib.m4
+===================================================================
+--- a/autoconf/ast_ext_lib.m4 (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/autoconf/ast_ext_lib.m4 (.../trunk) (revision 186562)
+@@ -11,7 +11,7 @@
+ $1_DESCRIP="$2"
+ $1_OPTION="$3"
+ PBX_$1=0
+- AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH $4]),
++ AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH$4]),
+ [
+ case ${withval} in
+ n|no)
+Index: funcs/func_channel.c
+===================================================================
+--- a/funcs/func_channel.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/funcs/func_channel.c (.../trunk) (revision 186562)
+@@ -83,6 +83,9 @@
+ <enum name="musicclass">
+ <para>R/W class (from musiconhold.conf) for hold music.</para>
+ </enum>
++ <enum name="name">
++ <para>The name of the channel</para>
++ </enum>
+ <enum name="parkinglot">
+ <para>R/W parkinglot for parking.</para>
+ </enum>
+@@ -249,7 +252,9 @@
+ locked_copy_string(chan, buf, chan->language, len);
+ else if (!strcasecmp(data, "musicclass"))
+ locked_copy_string(chan, buf, chan->musicclass, len);
+- else if (!strcasecmp(data, "parkinglot"))
++ else if (!strcasecmp(data, "name")) {
++ locked_copy_string(chan, buf, chan->name, len);
++ } else if (!strcasecmp(data, "parkinglot"))
+ locked_copy_string(chan, buf, chan->parkinglot, len);
+ else if (!strcasecmp(data, "state"))
+ locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
+Index: include/asterisk/rtp.h
+===================================================================
+--- a/include/asterisk/rtp.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/rtp.h (.../trunk) (revision 186562)
+@@ -1,416 +0,0 @@
+-/*
+- * Asterisk -- An open source telephony toolkit.
+- *
+- * Copyright (C) 1999 - 2006, Digium, Inc.
+- *
+- * Mark Spencer <markster@digium.com>
+- *
+- * See http://www.asterisk.org for more information about
+- * the Asterisk project. Please do not directly contact
+- * any of the maintainers of this project for assistance;
+- * the project provides a web site, mailing lists and IRC
+- * channels for your use.
+- *
+- * This program is free software, distributed under the terms of
+- * the GNU General Public License Version 2. See the LICENSE file
+- * at the top of the source tree.
+- */
+-
+-/*!
+- * \file rtp.h
+- * \brief Supports RTP and RTCP with Symmetric RTP support for NAT traversal.
+- *
+- * RTP is defined in RFC 3550.
+- */
+-
+-#ifndef _ASTERISK_RTP_H
+-#define _ASTERISK_RTP_H
+-
+-#include "asterisk/network.h"
+-
+-#include "asterisk/frame.h"
+-#include "asterisk/io.h"
+-#include "asterisk/sched.h"
+-#include "asterisk/channel.h"
+-#include "asterisk/linkedlists.h"
+-
+-#if defined(__cplusplus) || defined(c_plusplus)
+-extern "C" {
+-#endif
+-
+-/* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
+-/*! DTMF (RFC2833) */
+-#define AST_RTP_DTMF (1 << 0)
+-/*! 'Comfort Noise' (RFC3389) */
+-#define AST_RTP_CN (1 << 1)
+-/*! DTMF (Cisco Proprietary) */
+-#define AST_RTP_CISCO_DTMF (1 << 2)
+-/*! Maximum RTP-specific code */
+-#define AST_RTP_MAX AST_RTP_CISCO_DTMF
+-
+-/*! Maxmum number of payload defintions for a RTP session */
+-#define MAX_RTP_PT 256
+-
+-/*! T.140 Redundancy Maxium number of generations */
+-#define RED_MAX_GENERATION 5
+-
+-#define FLAG_3389_WARNING (1 << 0)
+-
+-enum ast_rtp_options {
+- AST_RTP_OPT_G726_NONSTANDARD = (1 << 0),
+-};
+-
+-enum ast_rtp_get_result {
+- /*! Failed to find the RTP structure */
+- AST_RTP_GET_FAILED = 0,
+- /*! RTP structure exists but true native bridge can not occur so try partial */
+- AST_RTP_TRY_PARTIAL,
+- /*! RTP structure exists and native bridge can occur */
+- AST_RTP_TRY_NATIVE,
+-};
+-
+-/*! \brief Variables used in ast_rtcp_get function */
+-enum ast_rtp_qos_vars {
+- AST_RTP_TXCOUNT,
+- AST_RTP_RXCOUNT,
+- AST_RTP_TXJITTER,
+- AST_RTP_RXJITTER,
+- AST_RTP_RXPLOSS,
+- AST_RTP_TXPLOSS,
+- AST_RTP_RTT
+-};
+-
+-struct ast_rtp;
+-/*! T.140 Redundancy structure*/
+-struct rtp_red;
+-
+-/*! \brief The value of each payload format mapping: */
+-struct rtpPayloadType {
+- int isAstFormat; /*!< whether the following code is an AST_FORMAT */
+- int code;
+-};
+-
+-/*! \brief This is the structure that binds a channel (SIP/Jingle/H.323) to the RTP subsystem
+-*/
+-struct ast_rtp_protocol {
+- /*! Get RTP struct, or NULL if unwilling to transfer */
+- enum ast_rtp_get_result (* const get_rtp_info)(struct ast_channel *chan, struct ast_rtp **rtp);
+- /*! Get RTP struct, or NULL if unwilling to transfer */
+- enum ast_rtp_get_result (* const get_vrtp_info)(struct ast_channel *chan, struct ast_rtp **rtp);
+- /*! Get RTP struct, or NULL if unwilling to transfer */
+- enum ast_rtp_get_result (* const get_trtp_info)(struct ast_channel *chan, struct ast_rtp **rtp);
+- /*! Set RTP peer */
+- int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, struct ast_rtp *tpeer, int codecs, int nat_active);
+- int (* const get_codec)(struct ast_channel *chan);
+- const char * const type;
+- AST_LIST_ENTRY(ast_rtp_protocol) list;
+-};
+-
+-enum ast_rtp_quality_type {
+- RTPQOS_SUMMARY = 0,
+- RTPQOS_JITTER,
+- RTPQOS_LOSS,
+- RTPQOS_RTT
+-};
+-
+-/*! \brief RTCP quality report storage */
+-struct ast_rtp_quality {
+- unsigned int local_ssrc; /*!< Our SSRC */
+- unsigned int local_lostpackets; /*!< Our lost packets */
+- double local_jitter; /*!< Our calculated jitter */
+- unsigned int local_count; /*!< Number of received packets */
+- unsigned int remote_ssrc; /*!< Their SSRC */
+- unsigned int remote_lostpackets; /*!< Their lost packets */
+- double remote_jitter; /*!< Their reported jitter */
+- unsigned int remote_count; /*!< Number of transmitted packets */
+- double rtt; /*!< Round trip time */
+-};
+-
+-/*! RTP callback structure */
+-typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
+-
+-/*!
+- * \brief Get the amount of space required to hold an RTP session
+- * \return number of bytes required
+- */
+-size_t ast_rtp_alloc_size(void);
+-
+-/*!
+- * \brief Initializate a RTP session.
+- *
+- * \param sched
+- * \param io
+- * \param rtcpenable
+- * \param callbackmode
+- * \return A representation (structure) of an RTP session.
+- */
+-struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode);
+-
+-/*!
+- * \brief Initializate a RTP session using an in_addr structure.
+- *
+- * This fuction gets called by ast_rtp_new().
+- *
+- * \param sched
+- * \param io
+- * \param rtcpenable
+- * \param callbackmode
+- * \param in
+- * \return A representation (structure) of an RTP session.
+- */
+-struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode, struct in_addr in);
+-
+-void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
+-
+-/* Copies from rtp to them and returns 1 if there was a change or 0 if it was already the same */
+-int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them);
+-
+-void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us);
+-
+-struct ast_rtp *ast_rtp_get_bridged(struct ast_rtp *rtp);
+-
+-/*! Destroy RTP session */
+-void ast_rtp_destroy(struct ast_rtp *rtp);
+-
+-void ast_rtp_reset(struct ast_rtp *rtp);
+-
+-/*! Stop RTP session, do not destroy structure */
+-void ast_rtp_stop(struct ast_rtp *rtp);
+-
+-void ast_rtp_set_callback(struct ast_rtp *rtp, ast_rtp_callback callback);
+-
+-void ast_rtp_set_data(struct ast_rtp *rtp, void *data);
+-
+-int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *f);
+-
+-struct ast_frame *ast_rtp_read(struct ast_rtp *rtp);
+-
+-struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp);
+-
+-int ast_rtp_fd(struct ast_rtp *rtp);
+-
+-int ast_rtcp_fd(struct ast_rtp *rtp);
+-
+-int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit);
+-
+-int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
+-
+-int ast_rtp_sendcng(struct ast_rtp *rtp, int level);
+-
+-int ast_rtp_setqos(struct ast_rtp *rtp, int tos, int cos, char *desc);
+-
+-void ast_rtp_new_source(struct ast_rtp *rtp);
+-
+-/*! \brief Setting RTP payload types from lines in a SDP description: */
+-void ast_rtp_pt_clear(struct ast_rtp* rtp);
+-/*! \brief Set payload types to defaults */
+-void ast_rtp_pt_default(struct ast_rtp* rtp);
+-
+-/*! \brief Copy payload types between RTP structures */
+-void ast_rtp_pt_copy(struct ast_rtp *dest, struct ast_rtp *src);
+-
+-/*! \brief Activate payload type */
+-void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt);
+-
+-/*! \brief clear payload type */
+-void ast_rtp_unset_m_type(struct ast_rtp* rtp, int pt);
+-
+-/*! \brief Set payload type to a known MIME media type for a codec
+- *
+- * \param rtp RTP structure to modify
+- * \param pt Payload type entry to modify
+- * \param mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
+- * \param mimeSubtype MIME subtype of media stream (typically a codec name)
+- * \param options Zero or more flags from the ast_rtp_options enum
+- *
+- * This function 'fills in' an entry in the list of possible formats for
+- * a media stream associated with an RTP structure.
+- *
+- * \retval 0 on success
+- * \retval -1 if the payload type is out of range
+- * \retval -2 if the mimeType/mimeSubtype combination was not found
+- */
+-int ast_rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
+- char *mimeType, char *mimeSubtype,
+- enum ast_rtp_options options);
+-
+-/*! \brief Set payload type to a known MIME media type for a codec with a specific sample rate
+- *
+- * \param rtp RTP structure to modify
+- * \param pt Payload type entry to modify
+- * \param mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
+- * \param mimeSubtype MIME subtype of media stream (typically a codec name)
+- * \param options Zero or more flags from the ast_rtp_options enum
+- * \param sample_rate The sample rate of the media stream
+- *
+- * This function 'fills in' an entry in the list of possible formats for
+- * a media stream associated with an RTP structure.
+- *
+- * \retval 0 on success
+- * \retval -1 if the payload type is out of range
+- * \retval -2 if the mimeType/mimeSubtype combination was not found
+- */
+-int ast_rtp_set_rtpmap_type_rate(struct ast_rtp* rtp, int pt,
+- char *mimeType, char *mimeSubtype,
+- enum ast_rtp_options options,
+- unsigned int sample_rate);
+-
+-/*! \brief Mapping between RTP payload format codes and Asterisk codes: */
+-struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt);
+-int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code);
+-
+-void ast_rtp_get_current_formats(struct ast_rtp* rtp,
+- int* astFormats, int* nonAstFormats);
+-
+-/*! \brief Mapping an Asterisk code into a MIME subtype (string): */
+-const char *ast_rtp_lookup_mime_subtype(int isAstFormat, int code,
+- enum ast_rtp_options options);
+-
+-/*! \brief Get the sample rate associated with known RTP payload types
+- *
+- * \param isAstFormat True if the value in the 'code' parameter is an AST_FORMAT value
+- * \param code Format code, either from AST_FORMAT list or from AST_RTP list
+- *
+- * \return the sample rate if the format was found, zero if it was not found
+- */
+-unsigned int ast_rtp_lookup_sample_rate(int isAstFormat, int code);
+-
+-/*! \brief Build a string of MIME subtype names from a capability list */
+-char *ast_rtp_lookup_mime_multiple(char *buf, size_t size, const int capability,
+- const int isAstFormat, enum ast_rtp_options options);
+-
+-void ast_rtp_setnat(struct ast_rtp *rtp, int nat);
+-
+-int ast_rtp_getnat(struct ast_rtp *rtp);
+-
+-/*! \brief Indicate whether this RTP session is carrying DTMF or not */
+-void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf);
+-
+-/*! \brief Compensate for devices that send RFC2833 packets all at once */
+-void ast_rtp_setdtmfcompensate(struct ast_rtp *rtp, int compensate);
+-
+-/*! \brief Enable STUN capability */
+-void ast_rtp_setstun(struct ast_rtp *rtp, int stun_enable);
+-
+-/*! \brief Generic STUN request
+- * send a generic stun request to the server specified.
+- * \param s the socket used to send the request
+- * \param dst the address of the STUN server
+- * \param username if non null, add the username in the request
+- * \param answer if non null, the function waits for a response and
+- * puts here the externally visible address.
+- * \return 0 on success, other values on error.
+- * The interface it may change in the future.
+- */
+-int ast_stun_request(int s, struct sockaddr_in *dst,
+- const char *username, struct sockaddr_in *answer);
+-
+-/*! \brief Send STUN request for an RTP socket
+- * Deprecated, this is just a wrapper for ast_rtp_stun_request()
+- */
+-void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username);
+-
+-/*! \brief The RTP bridge.
+- \arg \ref AstRTPbridge
+-*/
+-int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
+-
+-/*! \brief Register an RTP channel client */
+-int ast_rtp_proto_register(struct ast_rtp_protocol *proto);
+-
+-/*! \brief Unregister an RTP channel client */
+-void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto);
+-
+-int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, int media);
+-
+-/*! \brief If possible, create an early bridge directly between the devices without
+- having to send a re-invite later */
+-int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
+-
+-/*! \brief Get QOS stats on a RTP channel
+- * \since 1.6.1
+- */
+-int ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, char *buf, unsigned int buflen);
+-
+-/*! \brief Return RTP and RTCP QoS values
+- * \since 1.6.1
+- */
+-unsigned int ast_rtp_get_qosvalue(struct ast_rtp *rtp, enum ast_rtp_qos_vars value);
+-
+-/*! \brief Set RTPAUDIOQOS(...) variables on a channel when it is being hung up
+- * \since 1.6.1
+- */
+-void ast_rtp_set_vars(struct ast_channel *chan, struct ast_rtp *rtp);
+-
+-/*! \brief Return RTCP quality string
+- *
+- * \param rtp An rtp structure to get qos information about.
+- *
+- * \param qual An (optional) rtp quality structure that will be
+- * filled with the quality information described in
+- * the ast_rtp_quality structure. This structure is
+- * not dependent on any qtype, so a call for any
+- * type of information would yield the same results
+- * because ast_rtp_quality is not a data type
+- * specific to any qos type.
+- *
+- * \param qtype The quality type you'd like, default should be
+- * RTPQOS_SUMMARY which returns basic information
+- * about the call. The return from RTPQOS_SUMMARY
+- * is basically ast_rtp_quality in a string. The
+- * other types are RTPQOS_JITTER, RTPQOS_LOSS and
+- * RTPQOS_RTT which will return more specific
+- * statistics.
+- * \version 1.6.1 added qtype parameter
+- */
+-char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual, enum ast_rtp_quality_type qtype);
+-/*! \brief Send an H.261 fast update request. Some devices need this rather than the XML message in SIP */
+-int ast_rtcp_send_h261fur(void *data);
+-
+-void ast_rtp_init(void); /*! Initialize RTP subsystem */
+-int ast_rtp_reload(void); /*! reload rtp configuration */
+-void ast_rtp_new_init(struct ast_rtp *rtp);
+-
+-/*! \brief Set codec preference */
+-void ast_rtp_codec_setpref(struct ast_rtp *rtp, struct ast_codec_pref *prefs);
+-
+-/*! \brief Get codec preference */
+-struct ast_codec_pref *ast_rtp_codec_getpref(struct ast_rtp *rtp);
+-
+-/*! \brief get format from predefined dynamic payload format */
+-int ast_rtp_codec_getformat(int pt);
+-
+-/*! \brief Set rtp timeout */
+-void ast_rtp_set_rtptimeout(struct ast_rtp *rtp, int timeout);
+-/*! \brief Set rtp hold timeout */
+-void ast_rtp_set_rtpholdtimeout(struct ast_rtp *rtp, int timeout);
+-/*! \brief set RTP keepalive interval */
+-void ast_rtp_set_rtpkeepalive(struct ast_rtp *rtp, int period);
+-/*! \brief Get RTP keepalive interval */
+-int ast_rtp_get_rtpkeepalive(struct ast_rtp *rtp);
+-/*! \brief Get rtp hold timeout */
+-int ast_rtp_get_rtpholdtimeout(struct ast_rtp *rtp);
+-/*! \brief Get rtp timeout */
+-int ast_rtp_get_rtptimeout(struct ast_rtp *rtp);
+-/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
+-void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp);
+-
+-/*! \brief Initalize t.140 redudancy
+- * \param ti time between each t140red frame is sent
+- * \param red_pt payloadtype for RTP packet
+- * \param pt payloadtype numbers for each generation including primary data
+- * \param num_gen number of redundant generations, primary data excluded
+- * \since 1.6.1
+- */
+-int rtp_red_init(struct ast_rtp *rtp, int ti, int *pt, int num_gen);
+-
+-/*! \brief Buffer t.140 data */
+-void red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f);
+-
+-
+-
+-#if defined(__cplusplus) || defined(c_plusplus)
+-}
+-#endif
+-
+-#endif /* _ASTERISK_RTP_H */
+Index: include/asterisk/rtp_engine.h
+===================================================================
+--- a/include/asterisk/rtp_engine.h (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/include/asterisk/rtp_engine.h (.../trunk) (revision 186562)
+@@ -0,0 +1,1594 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2009, Digium, Inc.
++ *
++ * Mark Spencer <markster@digium.com>
++ * Joshua Colp <jcolp@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*! \file
++ * \brief Pluggable RTP Architecture
++ * \author Joshua Colp <jcolp@digium.com>
++ * \ref AstRTPEngine
++ */
++
++/*!
++ * \page AstRTPEngine Asterisk RTP Engine API
++ *
++ * The purpose of this API is to provide a way for multiple RTP stacks to be used inside
++ * of Asterisk without any module that uses RTP knowing any different. To the module each RTP
++ * stack behaves the same.
++ *
++ * An RTP session is called an instance and is made up of a combination of codec information,
++ * RTP engine, RTP properties, and address information. An engine name may be passed in to explicitly
++ * choose an RTP stack to be used but a default one will be used if none is provided. An address to use
++ * for RTP may also be provided but the underlying RTP engine may choose a different address depending on
++ * it's configuration.
++ *
++ * An RTP engine is the layer between the RTP engine core and the RTP stack itself. The RTP engine core provides
++ * a set of callbacks to do various things (such as write audio out) that the RTP engine has to have implemented.
++ *
++ * Glue is what binds an RTP instance to a channel. It is used to retrieve RTP instance information when
++ * performing remote or local bridging and is used to have the channel driver tell the remote side to change
++ * destination of the RTP stream.
++ *
++ * Statistics from an RTP instance can be retrieved using the ast_rtp_instance_get_stats API call. This essentially
++ * asks the RTP engine in use to fill in a structure with the requested values. It is not required for an RTP engine
++ * to support all statistic values.
++ *
++ * Properties allow behavior of the RTP engine and RTP engine core to be changed. For example, there is a property named
++ * AST_RTP_PROPERTY_NAT which is used to tell the RTP engine to enable symmetric RTP if it supports it. It is not required
++ * for an RTP engine to support all properties.
++ *
++ * Codec information is stored using a separate data structure which has it's own set of API calls to add/remove/retrieve
++ * information. They are used by the module after an RTP instance is created so that payload information is available for
++ * the RTP engine.
++ */
++
++#ifndef _ASTERISK_RTP_ENGINE_H
++#define _ASTERISK_RTP_ENGINE_H
++
++#if defined(__cplusplus) || defined(c_plusplus)
++extern "C" {
++#endif
++
++#include "asterisk/astobj2.h"
++
++/* Maximum number of payloads supported */
++#define AST_RTP_MAX_PT 256
++
++/* Maximum number of generations */
++#define AST_RED_MAX_GENERATION 5
++
++struct ast_rtp_instance;
++struct ast_rtp_glue;
++
++/*! RTP Properties that can be set on an RTP instance */
++enum ast_rtp_property {
++ /*! Enable symmetric RTP support */
++ AST_RTP_PROPERTY_NAT = 0,
++ /*! RTP instance will be carrying DTMF (using RFC2833) */
++ AST_RTP_PROPERTY_DTMF,
++ /*! Expect unreliable DTMF from remote party */
++ AST_RTP_PROPERTY_DTMF_COMPENSATE,
++ /*! Enable STUN support */
++ AST_RTP_PROPERTY_STUN,
++ /*! Enable RTCP support */
++ AST_RTP_PROPERTY_RTCP,
++ /*! Maximum number of RTP properties supported */
++ AST_RTP_PROPERTY_MAX,
++};
++
++/*! Additional RTP options */
++enum ast_rtp_options {
++ /*! Remote side is using non-standard G.726 */
++ AST_RTP_OPT_G726_NONSTANDARD = (1 << 0),
++};
++
++/*! RTP DTMF Modes */
++enum ast_rtp_dtmf_mode {
++ /*! No DTMF is being carried over the RTP stream */
++ AST_RTP_DTMF_MODE_NONE = 0,
++ /*! DTMF is being carried out of band using RFC2833 */
++ AST_RTP_DTMF_MODE_RFC2833,
++ /*! DTMF is being carried inband over the RTP stream */
++ AST_RTP_DTMF_MODE_INBAND,
++};
++
++/*! Result codes when RTP glue is queried for information */
++enum ast_rtp_glue_result {
++ /*! No remote or local bridging is permitted */
++ AST_RTP_GLUE_RESULT_FORBID = 0,
++ /*! Move RTP stream to be remote between devices directly */
++ AST_RTP_GLUE_RESULT_REMOTE,
++ /*! Perform RTP engine level bridging if possible */
++ AST_RTP_GLUE_RESULT_LOCAL,
++};
++
++/*! Field statistics that can be retrieved from an RTP instance */
++enum ast_rtp_instance_stat_field {
++ /*! Retrieve quality information */
++ AST_RTP_INSTANCE_STAT_FIELD_QUALITY = 0,
++ /*! Retrieve quality information about jitter */
++ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER,
++ /*! Retrieve quality information about packet loss */
++ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS,
++ /*! Retrieve quality information about round trip time */
++ AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT,
++};
++
++/*! Statistics that can be retrieved from an RTP instance */
++enum ast_rtp_instance_stat {
++ /*! Retrieve all statistics */
++ AST_RTP_INSTANCE_STAT_ALL = 0,
++ /*! Retrieve number of packets transmitted */
++ AST_RTP_INSTANCE_STAT_TXCOUNT,
++ /*! Retrieve number of packets received */
++ AST_RTP_INSTANCE_STAT_RXCOUNT,
++ /*! Retrieve ALL statistics relating to packet loss */
++ AST_RTP_INSTANCE_STAT_COMBINED_LOSS,
++ /*! Retrieve number of packets lost for transmitting */
++ AST_RTP_INSTANCE_STAT_TXPLOSS,
++ /*! Retrieve number of packets lost for receiving */
++ AST_RTP_INSTANCE_STAT_RXPLOSS,
++ /*! Retrieve maximum number of packets lost on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_MAXRXPLOSS,
++ /*! Retrieve minimum number of packets lost on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_MINRXPLOSS,
++ /*! Retrieve average number of packets lost on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVRXPLOSS,
++ /*! Retrieve standard deviation of packets lost on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_STDEVRXPLOSS,
++ /*! Retrieve maximum number of packets lost on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_MAXRXPLOSS,
++ /*! Retrieve minimum number of packets lost on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_MINRXPLOSS,
++ /*! Retrieve average number of packets lost on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVRXPLOSS,
++ /*! Retrieve standard deviation of packets lost on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_STDEVRXPLOSS,
++ /*! Retrieve ALL statistics relating to jitter */
++ AST_RTP_INSTANCE_STAT_COMBINED_JITTER,
++ /*! Retrieve jitter on transmitted packets */
++ AST_RTP_INSTANCE_STAT_TXJITTER,
++ /*! Retrieve jitter on received packets */
++ AST_RTP_INSTANCE_STAT_RXJITTER,
++ /*! Retrieve maximum jitter on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_MAXJITTER,
++ /*! Retrieve minimum jitter on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_MINJITTER,
++ /*! Retrieve average jitter on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVJITTER,
++ /*! Retrieve standard deviation jitter on remote side */
++ AST_RTP_INSTANCE_STAT_REMOTE_STDEVJITTER,
++ /*! Retrieve maximum jitter on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_MAXJITTER,
++ /*! Retrieve minimum jitter on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_MINJITTER,
++ /*! Retrieve average jitter on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVJITTER,
++ /*! Retrieve standard deviation jitter on local side */
++ AST_RTP_INSTANCE_STAT_LOCAL_STDEVJITTER,
++ /*! Retrieve ALL statistics relating to round trip time */
++ AST_RTP_INSTANCE_STAT_COMBINED_RTT,
++ /*! Retrieve round trip time */
++ AST_RTP_INSTANCE_STAT_RTT,
++ /*! Retrieve maximum round trip time */
++ AST_RTP_INSTANCE_STAT_MAX_RTT,
++ /*! Retrieve minimum round trip time */
++ AST_RTP_INSTANCE_STAT_MIN_RTT,
++ /*! Retrieve average round trip time */
++ AST_RTP_INSTANCE_STAT_NORMDEVRTT,
++ /*! Retrieve standard deviation round trip time */
++ AST_RTP_INSTANCE_STAT_STDEVRTT,
++ /*! Retrieve local SSRC */
++ AST_RTP_INSTANCE_STAT_LOCAL_SSRC,
++ /*! Retrieve remote SSRC */
++ AST_RTP_INSTANCE_STAT_REMOTE_SSRC,
++};
++
++/* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
++/*! DTMF (RFC2833) */
++#define AST_RTP_DTMF (1 << 0)
++/*! 'Comfort Noise' (RFC3389) */
++#define AST_RTP_CN (1 << 1)
++/*! DTMF (Cisco Proprietary) */
++#define AST_RTP_CISCO_DTMF (1 << 2)
++/*! Maximum RTP-specific code */
++#define AST_RTP_MAX AST_RTP_CISCO_DTMF
++
++/*! Structure that represents a payload */
++struct ast_rtp_payload_type {
++ /*! Is this an Asterisk value */
++ int asterisk_format;
++ /*! Actual internal value of the payload */
++ int code;
++};
++
++/*! Structure that represents statistics from an RTP instance */
++struct ast_rtp_instance_stats {
++ /*! Number of packets transmitted */
++ unsigned int txcount;
++ /*! Number of packets received */
++ unsigned int rxcount;
++ /*! Jitter on transmitted packets */
++ unsigned int txjitter;
++ /*! Jitter on received packets */
++ unsigned int rxjitter;
++ /*! Maximum jitter on remote side */
++ double remote_maxjitter;
++ /*! Minimum jitter on remote side */
++ double remote_minjitter;
++ /*! Average jitter on remote side */
++ double remote_normdevjitter;
++ /*! Standard deviation jitter on remote side */
++ double remote_stdevjitter;
++ /*! Maximum jitter on local side */
++ double local_maxjitter;
++ /*! Minimum jitter on local side */
++ double local_minjitter;
++ /*! Average jitter on local side */
++ double local_normdevjitter;
++ /*! Standard deviation jitter on local side */
++ double local_stdevjitter;
++ /*! Number of transmitted packets lost */
++ unsigned int txploss;
++ /*! Number of received packets lost */
++ unsigned int rxploss;
++ /*! Maximum number of packets lost on remote side */
++ double remote_maxrxploss;
++ /*! Minimum number of packets lost on remote side */
++ double remote_minrxploss;
++ /*! Average number of packets lost on remote side */
++ double remote_normdevrxploss;
++ /*! Standard deviation packets lost on remote side */
++ double remote_stdevrxploss;
++ /*! Maximum number of packets lost on local side */
++ double local_maxrxploss;
++ /*! Minimum number of packets lost on local side */
++ double local_minrxploss;
++ /*! Average number of packets lost on local side */
++ double local_normdevrxploss;
++ /*! Standard deviation packets lost on local side */
++ double local_stdevrxploss;
++ /*! Total round trip time */
++ unsigned int rtt;
++ /*! Maximum round trip time */
++ double maxrtt;
++ /*! Minimum round trip time */
++ double minrtt;
++ /*! Average round trip time */
++ double normdevrtt;
++ /*! Standard deviation round trip time */
++ double stdevrtt;
++ /*! Our SSRC */
++ unsigned int local_ssrc;
++ /*! Their SSRC */
++ unsigned int remote_ssrc;
++};
++
++#define AST_RTP_STAT_SET(current_stat, combined, placement, value) \
++if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \
++placement = value; \
++if (stat == current_stat) { \
++return 0; \
++} \
++}
++
++#define AST_RTP_STAT_TERMINATOR(combined) \
++if (stat == combined) { \
++return 0; \
++}
++
++/*! Structure that represents an RTP stack (engine) */
++struct ast_rtp_engine {
++ /*! Name of the RTP engine, used when explicitly requested */
++ const char *name;
++ /*! Module this RTP engine came from, used for reference counting */
++ struct ast_module *mod;
++ /*! Callback for setting up a new RTP instance */
++ int (*new)(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data);
++ /*! Callback for destroying an RTP instance */
++ int (*destroy)(struct ast_rtp_instance *instance);
++ /*! Callback for writing out a frame */
++ int (*write)(struct ast_rtp_instance *instance, struct ast_frame *frame);
++ /*! Callback for stopping the RTP instance */
++ void (*stop)(struct ast_rtp_instance *instance);
++ /*! Callback for starting RFC2833 DTMF transmission */
++ int (*dtmf_begin)(struct ast_rtp_instance *instance, char digit);
++ /*! Callback for stopping RFC2833 DTMF transmission */
++ int (*dtmf_end)(struct ast_rtp_instance *instance, char digit);
++ /*! Callback to indicate that a new source of media has come in */
++ void (*new_source)(struct ast_rtp_instance *instance);
++ /*! Callback for setting an extended RTP property */
++ int (*extended_prop_set)(struct ast_rtp_instance *instance, int property, void *value);
++ /*! Callback for getting an extended RTP property */
++ void *(*extended_prop_get)(struct ast_rtp_instance *instance, int property);
++ /*! Callback for setting an RTP property */
++ void (*prop_set)(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
++ /*! Callback for setting a payload */
++ void (*payload_set)(struct ast_rtp_instance *instance, int payload, int astformat, int format);
++ /*! Callback for setting packetization preferences */
++ void (*packetization_set)(struct ast_rtp_instance *instance, struct ast_codec_pref *pref);
++ /*! Callback for setting the remote address that RTP is to be sent to */
++ void (*remote_address_set)(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
++ /*! Callback for changing DTMF mode */
++ int (*dtmf_mode_set)(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode);
++ /*! Callback for retrieving statistics */
++ int (*get_stat)(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat);
++ /*! Callback for setting QoS values */
++ int (*qos)(struct ast_rtp_instance *instance, int tos, int cos, const char *desc);
++ /*! Callback for retrieving a file descriptor to poll on, not always required */
++ int (*fd)(struct ast_rtp_instance *instance, int rtcp);
++ /*! Callback for initializing RED support */
++ int (*red_init)(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
++ /*! Callback for buffering a frame using RED */
++ int (*red_buffer)(struct ast_rtp_instance *instance, struct ast_frame *frame);
++ /*! Callback for reading a frame from the RTP engine */
++ struct ast_frame *(*read)(struct ast_rtp_instance *instance, int rtcp);
++ /*! Callback to locally bridge two RTP instances */
++ int (*local_bridge)(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1);
++ /*! Callback to set the read format */
++ int (*set_read_format)(struct ast_rtp_instance *instance, int format);
++ /*! Callback to set the write format */
++ int (*set_write_format)(struct ast_rtp_instance *instance, int format);
++ /*! Callback to make two instances compatible */
++ int (*make_compatible)(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1);
++ /*! Callback to see if two instances are compatible with DTMF */
++ int (*dtmf_compatible)(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1);
++ /*! Callback to indicate that packets will now flow */
++ int (*activate)(struct ast_rtp_instance *instance);
++ /*! Callback to request that the RTP engine send a STUN BIND request */
++ void (*stun_request)(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username);
++ /*! Linked list information */
++ AST_RWLIST_ENTRY(ast_rtp_engine) entry;
++};
++
++/*! Structure that represents codec and packetization information */
++struct ast_rtp_codecs {
++ /*! Codec packetization preferences */
++ struct ast_codec_pref pref;
++ /*! Payloads present */
++ struct ast_rtp_payload_type payloads[AST_RTP_MAX_PT];
++};
++
++/*! Structure that represents the glue that binds an RTP instance to a channel */
++struct ast_rtp_glue {
++ /*! Name of the channel driver that this glue is responsible for */
++ const char *type;
++ /*! Module that the RTP glue came from */
++ struct ast_module *mod;
++ /*!
++ * \brief Callback for retrieving the RTP instance carrying audio
++ * \note This function increases the reference count on the returned RTP instance.
++ */
++ enum ast_rtp_glue_result (*get_rtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance);
++ /*!
++ * \brief Callback for retrieving the RTP instance carrying video
++ * \note This function increases the reference count on the returned RTP instance.
++ */
++ enum ast_rtp_glue_result (*get_vrtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance);
++ /*!
++ * \brief Callback for retrieving the RTP instance carrying text
++ * \note This function increases the reference count on the returned RTP instance.
++ */
++ enum ast_rtp_glue_result (*get_trtp_info)(struct ast_channel *chan, struct ast_rtp_instance **instance);
++ /*! Callback for updating the destination that the remote side should send RTP to */
++ int (*update_peer)(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, int codecs, int nat_active);
++ /*! Callback for retrieving codecs that the channel can do */
++ int (*get_codec)(struct ast_channel *chan);
++ /*! Linked list information */
++ AST_RWLIST_ENTRY(ast_rtp_glue) entry;
++};
++
++#define ast_rtp_engine_register(engine) ast_rtp_engine_register2(engine, ast_module_info->self)
++
++/*!
++ * \brief Register an RTP engine
++ *
++ * \param engine Structure of the RTP engine to register
++ * \param module Module that the RTP engine is part of
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_engine_register2(&example_rtp_engine, NULL);
++ * \endcode
++ *
++ * This registers the RTP engine declared as example_rtp_engine with the RTP engine core, but does not
++ * associate a module with it.
++ *
++ * \note It is recommended that you use the ast_rtp_engine_register macro so that the module is
++ * associated with the RTP engine and use counting is performed.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module);
++
++/*!
++ * \brief Unregister an RTP engine
++ *
++ * \param engine Structure of the RTP engine to unregister
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_engine_unregister(&example_rtp_engine);
++ * \endcode
++ *
++ * This unregisters the RTP engine declared as example_rtp_engine from the RTP engine core. If a module
++ * reference was provided when it was registered then this will only be called once the RTP engine is no longer in use.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_engine_unregister(struct ast_rtp_engine *engine);
++
++#define ast_rtp_glue_register(glue) ast_rtp_glue_register2(glue, ast_module_info->self)
++
++/*!
++ * \brief Register RTP glue
++ *
++ * \param glue The glue to register
++ * \param module Module that the RTP glue is part of
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_glue_register2(&example_rtp_glue, NULL);
++ * \endcode
++ *
++ * This registers the RTP glue declared as example_rtp_glue with the RTP engine core, but does not
++ * associate a module with it.
++ *
++ * \note It is recommended that you use the ast_rtp_glue_register macro so that the module is
++ * associated with the RTP glue and use counting is performed.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_glue_register2(struct ast_rtp_glue *glue, struct ast_module *module);
++
++/*!
++ * \brief Unregister RTP glue
++ *
++ * \param glue The glue to unregister
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_glue_unregister(&example_rtp_glue);
++ * \endcode
++ *
++ * This unregisters the RTP glue declared as example_rtp_gkue from the RTP engine core. If a module
++ * reference was provided when it was registered then this will only be called once the RTP engine is no longer in use.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_glue_unregister(struct ast_rtp_glue *glue);
++
++/*!
++ * \brief Create a new RTP instance
++ *
++ * \param engine_name Name of the engine to use for the RTP instance
++ * \param sched Scheduler context that the RTP engine may want to use
++ * \param sin Address we want to bind to
++ * \param data Unique data for the engine
++ *
++ * \retval non-NULL success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_instance *instance = NULL;
++ * instance = ast_rtp_instance_new(NULL, sched, &sin, NULL);
++ * \endcode
++ *
++ * This creates a new RTP instance using the default engine and asks the RTP engine to bind to the address given
++ * in the sin structure.
++ *
++ * \note The RTP engine does not have to use the address provided when creating an RTP instance. It may choose to use
++ * another depending on it's own configuration.
++ *
++ * \since 1.6.3
++ */
++struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, struct sockaddr_in *sin, void *data);
++
++/*!
++ * \brief Destroy an RTP instance
++ *
++ * \param instance The RTP instance to destroy
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_destroy(instance);
++ * \endcode
++ *
++ * This destroys the RTP instance pointed to by instance. Once this function returns instance no longer points to valid
++ * memory and may not be used again.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_destroy(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Set the data portion of an RTP instance
++ *
++ * \param instance The RTP instance to manipulate
++ * \param data Pointer to data
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_data(instance, blob);
++ * \endcode
++ *
++ * This sets the data pointer on the RTP instance pointed to by 'instance' to
++ * blob.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_set_data(struct ast_rtp_instance *instance, void *data);
++
++/*!
++ * \brief Get the data portion of an RTP instance
++ *
++ * \param instance The RTP instance we want the data portion from
++ *
++ * Example usage:
++ *
++ * \code
++ * struct *blob = ast_rtp_instance_get_data(instance);
++ ( \endcode
++ *
++ * This gets the data pointer on the RTP instance pointed to by 'instance'.
++ *
++ * \since 1.6.3
++ */
++void *ast_rtp_instance_get_data(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Send a frame out over RTP
++ *
++ * \param instance The RTP instance to send frame out on
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_write(instance, frame);
++ * \endcode
++ *
++ * This gives the frame pointed to by frame to the RTP engine being used for the instance
++ * and asks that it be transmitted to the current remote address set on the RTP instance.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame);
++
++/*!
++ * \brief Receive a frame over RTP
++ *
++ * \param instance The RTP instance to receive frame on
++ * \param rtcp Whether to read in RTCP or not
++ *
++ * \retval non-NULL success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_frame *frame;
++ * frame = ast_rtp_instance_read(instance, 0);
++ * \endcode
++ *
++ * This asks the RTP engine to read in RTP from the instance and return it as an Asterisk frame.
++ *
++ * \since 1.6.3
++ */
++struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp);
++
++/*!
++ * \brief Set the address of the remote endpoint that we are sending RTP to
++ *
++ * \param instance The RTP instance to change the address on
++ * \param address Address to set it to
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_remote_address(instance, &sin);
++ * \endcode
++ *
++ * This changes the remote address that RTP will be sent to on instance to the address given in the sin
++ * structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address);
++
++/*!
++ * \brief Set the address that we are expecting to receive RTP on
++ *
++ * \param instance The RTP instance to change the address on
++ * \param address Address to set it to
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_local_address(instance, &sin);
++ * \endcode
++ *
++ * This changes the local address that RTP is expected on to the address given in the sin
++ * structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address);
++
++/*!
++ * \brief Get the local address that we are expecting RTP on
++ *
++ * \param instance The RTP instance to get the address from
++ * \param address The variable to store the address in
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct sockaddr_in sin;
++ * ast_rtp_instance_get_local_address(instance, &sin);
++ * \endcode
++ *
++ * This gets the local address that we are expecting RTP on and stores it in the 'sin' structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address);
++
++/*!
++ * \brief Get the address of the remote endpoint that we are sending RTP to
++ *
++ * \param instance The instance that we want to get the remote address for
++ * \param address A structure to put the address into
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct sockaddr_in sin;
++ * ast_rtp_instance_get_remote_address(instance, &sin);
++ * \endcode
++ *
++ * This retrieves the current remote address set on the instance pointed to by instance and puts the value
++ * into the sin structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address);
++
++/*!
++ * \brief Set the value of an RTP instance extended property
++ *
++ * \param instance The RTP instance to set the extended property on
++ * \param property The extended property to set
++ * \param value The value to set the extended property to
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_set_extended_prop(struct ast_rtp_instance *instance, int property, void *value);
++
++/*!
++ * \brief Get the value of an RTP instance extended property
++ *
++ * \param instance The RTP instance to get the extended property on
++ * \param property The extended property to get
++ *
++ * \since 1.6.3
++ */
++void *ast_rtp_instance_get_extended_prop(struct ast_rtp_instance *instance, int property);
++
++/*!
++ * \brief Set the value of an RTP instance property
++ *
++ * \param instance The RTP instance to set the property on
++ * \param property The property to modify
++ * \param value The value to set the property to
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_prop(instance, AST_RTP_PROPERTY_NAT, 1);
++ * \endcode
++ *
++ * This enables the AST_RTP_PROPERTY_NAT property on the instance pointed to by instance.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
++
++/*!
++ * \brief Get the value of an RTP instance property
++ *
++ * \param instance The RTP instance to get the property from
++ * \param property The property to get
++ *
++ * \retval Current value of the property
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT);
++ * \endcode
++ *
++ * This returns the current value of the NAT property on the instance pointed to by instance.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_get_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property);
++
++/*!
++ * \brief Get the codecs structure of an RTP instance
++ *
++ * \param instance The RTP instance to get the codecs structure from
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_codecs *codecs = ast_rtp_instance_get_codecs(instance);
++ * \endcode
++ *
++ * This gets the codecs structure on the RTP instance pointed to by 'instance'.
++ *
++ * \since 1.6.3
++ */
++struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Clear payload information from an RTP instance
++ *
++ * \param codecs The codecs structure that payloads will be cleared from
++ * \param instance Optionally the instance that the codecs structure belongs to
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_codecs codecs;
++ * ast_rtp_codecs_payloads_clear(&codecs, NULL);
++ * \endcode
++ *
++ * This clears the codecs structure and puts it into a pristine state.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Set payload information on an RTP instance to the default
++ *
++ * \param codecs The codecs structure to set defaults on
++ * \param instance Optionally the instance that the codecs structure belongs to
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_codecs codecs;
++ * ast_rtp_codecs_payloads_default(&codecs, NULL);
++ * \endcode
++ *
++ * This sets the default payloads on the codecs structure.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Copy payload information from one RTP instance to another
++ *
++ * \param src The source codecs structure
++ * \param dst The destination codecs structure that the values from src will be copied to
++ * \param instance Optionally the instance that the dst codecs structure belongs to
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_codecs_payloads_copy(&codecs0, &codecs1, NULL);
++ * \endcode
++ *
++ * This copies the payloads from the codecs0 structure to the codecs1 structure, overwriting any current values.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Record payload information that was seen in an m= SDP line
++ *
++ * \param codecs The codecs structure to muck with
++ * \param instance Optionally the instance that the codecs structure belongs to
++ * \param payload Numerical payload that was seen in the m= SDP line
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, 0);
++ * \endcode
++ *
++ * This records that the numerical payload '0' was seen in the codecs structure.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload);
++
++/*!
++ * \brief Record payload information that was seen in an a=rtpmap: SDP line
++ *
++ * \param codecs The codecs structure to muck with
++ * \param instance Optionally the instance that the codecs structure belongs to
++ * \param payload Numerical payload that was seen in the a=rtpmap: SDP line
++ * \param mimetype The string mime type that was seen
++ * \param mimesubtype The strin mime sub type that was seen
++ * \param options Optional options that may change the behavior of this specific payload
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, 0, "audio", "PCMU", 0);
++ * \endcode
++ *
++ * This records that the numerical payload '0' was seen with mime type 'audio' and sub mime type 'PCMU' in the codecs structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options);
++
++/*!
++ * \brief Set payload type to a known MIME media type for a codec with a specific sample rate
++ *
++ * \param rtp RTP structure to modify
++ * \param instance Optionally the instance that the codecs structure belongs to
++ * \param pt Payload type entry to modify
++ * \param mimetype top-level MIME type of media stream (typically "audio", "video", "text", etc.)
++ * \param mimesubtype MIME subtype of media stream (typically a codec name)
++ * \param options Zero or more flags from the ast_rtp_options enum
++ * \param sample_rate The sample rate of the media stream
++ *
++ * This function 'fills in' an entry in the list of possible formats for
++ * a media stream associated with an RTP structure.
++ *
++ * \retval 0 on success
++ * \retval -1 if the payload type is out of range
++ * \retval -2 if the mimeType/mimeSubtype combination was not found
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int pt,
++ char *mimetype, char *mimesubtype,
++ enum ast_rtp_options options,
++ unsigned int sample_rate);
++
++/*!
++ * \brief Remove payload information
++ *
++ * \param codecs The codecs structure to muck with
++ * \param instance Optionally the instance that the codecs structure belongs to
++ * \param payload Numerical payload to unset
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_codecs_payloads_unset(&codecs, NULL, 0);
++ * \endcode
++ *
++ * This clears the payload '0' from the codecs structure. It will be as if it was never set.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload);
++
++/*!
++ * \brief Retrieve payload information by payload
++ *
++ * \param codecs Codecs structure to look in
++ * \param payload Numerical payload to look up
++ *
++ * \retval Payload information
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_payload_type payload_type;
++ * payload_type = ast_rtp_codecs_payload_lookup(&codecs, 0);
++ * \endcode
++ *
++ * This looks up the information for payload '0' from the codecs structure.
++ *
++ * \since 1.6.3
++ */
++struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload);
++
++/*!
++ * \brief Get the sample rate associated with known RTP payload types
++ *
++ * \param asterisk_format True if the value in the 'code' parameter is an AST_FORMAT value
++ * \param code Format code, either from AST_FORMAT list or from AST_RTP list
++ *
++ * \return the sample rate if the format was found, zero if it was not found
++ *
++ * \since 1.6.3
++ */
++unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, int code);
++
++/*!
++ * \brief Retrieve all formats that were found
++ *
++ * \param codecs Codecs structure to look in
++ * \param astFormats An integer to put the Asterisk formats in
++ * \param nonastformats An integer to put the non-Asterisk formats in
++ *
++ * Example usage:
++ *
++ * \code
++ * int astformats, nonastformats;
++ * ast_rtp_codecs_payload_Formats(&codecs, &astformats, &nonastformats);
++ * \endcode
++ *
++ * This retrieves all the formats known about in the codecs structure and puts the Asterisk ones in the integer
++ * pointed to by astformats and the non-Asterisk ones in the integer pointed to by nonastformats.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, int *astformats, int *nonastformats);
++
++/*!
++ * \brief Retrieve a payload based on whether it is an Asterisk format and the code
++ *
++ * \param codecs Codecs structure to look in
++ * \param asterisk_format Non-zero if the given code is an Asterisk format value
++ * \param code The format to look for
++ *
++ * \retval Numerical payload
++ *
++ * Example usage:
++ *
++ * \code
++ * int payload = ast_rtp_codecs_payload_code(&codecs, 1, AST_FORMAT_ULAW);
++ * \endcode
++ *
++ * This looks for the numerical payload for ULAW in the codecs structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, const int asterisk_format, const int code);
++
++/*!
++ * \brief Retrieve mime subtype information on a payload
++ *
++ * \param asterisk_format Non-zero if the given code is an Asterisk format value
++ * \param code Format to look up
++ * \param options Additional options that may change the result
++ *
++ * \retval Mime subtype success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * const char *subtype = ast_rtp_lookup_mime_subtype2(1, AST_FORMAT_ULAW, 0);
++ * \endcode
++ *
++ * This looks up the mime subtype for the ULAW format.
++ *
++ * \since 1.6.3
++ */
++const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, const int code, enum ast_rtp_options options);
++
++/*!
++ * \brief Convert formats into a string and put them into a buffer
++ *
++ * \param buf Buffer to put the mime output into
++ * \param capability Formats that we are looking up
++ * \param asterisk_format Non-zero if the given capability are Asterisk format capabilities
++ * \param options Additional options that may change the result
++ *
++ * \retval non-NULL success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * char buf[256] = "";
++ * char *mime = ast_rtp_lookup_mime_multiple2(&buf, sizeof(buf), AST_FORMAT_ULAW | AST_FORMAT_ALAW, 1, 0);
++ * \endcode
++ *
++ * This returns the mime values for ULAW and ALAW in the buffer pointed to by buf.
++ *
++ * \since 1.6.3
++ */
++char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, const int capability, const int asterisk_format, enum ast_rtp_options options);
++
++/*!
++ * \brief Set codec packetization preferences
++ *
++ * \param codecs Codecs structure to muck with
++ * \param instance Optionally the instance that the codecs structure belongs to
++ * \param prefs Codec packetization preferences
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_codecs_packetization_set(&codecs, NULL, &prefs);
++ * \endcode
++ *
++ * This sets the packetization preferences pointed to by prefs on the codecs structure pointed to by codecs.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs);
++
++/*!
++ * \brief Begin sending a DTMF digit
++ *
++ * \param instance The RTP instance to send the DTMF on
++ * \param digit What DTMF digit to send
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_dtmf_begin(instance, '1');
++ * \endcode
++ *
++ * This starts sending the DTMF '1' on the RTP instance pointed to by instance. It will
++ * continue being sent until it is ended.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit);
++
++/*!
++ * \brief Stop sending a DTMF digit
++ *
++ * \param instance The RTP instance to stop the DTMF on
++ * \param digit What DTMF digit to stop
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_dtmf_end(instance, '1');
++ * \endcode
++ *
++ * This stops sending the DTMF '1' on the RTP instance pointed to by instance.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_dtmf_end(struct ast_rtp_instance *instance, char digit);
++
++/*!
++ * \brief Set the DTMF mode that should be used
++ *
++ * \param instance the RTP instance to set DTMF mode on
++ * \param dtmf_mode The DTMF mode that is in use
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_dtmf_mode_set(instance, AST_RTP_DTMF_MODE_RFC2833);
++ * \endcode
++ *
++ * This sets the RTP instance to use RFC2833 for DTMF transmission and receiving.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode);
++
++/*!
++ * \brief Get the DTMF mode of an RTP instance
++ *
++ * \param instance The RTP instance to get the DTMF mode of
++ *
++ * \retval DTMF mode
++ *
++ * Example usage:
++ *
++ * \code
++ * enum ast_rtp_dtmf_mode dtmf_mode = ast_rtp_instance_dtmf_mode_get(instance);
++ * \endcode
++ *
++ * This gets the DTMF mode set on the RTP instance pointed to by 'instance'.
++ *
++ * \since 1.6.3
++ */
++enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Indicate a new source of audio has dropped in
++ *
++ * \param instance Instance that the new media source is feeding into
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_new_source(instance);
++ * \endcode
++ *
++ * This indicates that a new source of media is feeding the instance pointed to by
++ * instance.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_new_source(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Set QoS parameters on an RTP session
++ *
++ * \param instance Instance to set the QoS parameters on
++ * \param tos Terms of service value
++ * \param cos Class of service value
++ * \param desc What is setting the QoS values
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_qos(instance, 0, 0, "Example");
++ * \endcode
++ *
++ * This sets the TOS and COS values to 0 on the instance pointed to by instance.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc);
++
++/*!
++ * \brief Stop an RTP instance
++ *
++ * \param instance Instance that media is no longer going to at this time
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_stop(instance);
++ * \endcode
++ *
++ * This tells the RTP engine being used for the instance pointed to by instance
++ * that media is no longer going to it at this time, but may in the future.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_stop(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Get the file descriptor for an RTP session (or RTCP)
++ *
++ * \param instance Instance to get the file descriptor for
++ * \param rtcp Whether to retrieve the file descriptor for RTCP or not
++ *
++ * \retval fd success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * int rtp_fd = ast_rtp_instance_fd(instance, 0);
++ * \endcode
++ *
++ * This retrieves the file descriptor for the socket carrying media on the instance
++ * pointed to by instance.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp);
++
++/*!
++ * \brief Get the RTP glue that binds a channel to the RTP engine
++ *
++ * \param type Name of the glue we want
++ *
++ * \retval non-NULL success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_glue *glue = ast_rtp_instance_get_glue("Example");
++ * \endcode
++ *
++ * This retrieves the RTP glue that has the name 'Example'.
++ *
++ * \since 1.6.3
++ */
++struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type);
++
++/*!
++ * \brief Bridge two channels that use RTP instances
++ *
++ * \param c0 First channel part of the bridge
++ * \param c1 Second channel part of the bridge
++ * \param flags Bridging flags
++ * \param fo If a frame needs to be passed up it is stored here
++ * \param rc Channel that passed the above frame up
++ * \param timeoutms How long the channels should be bridged for
++ *
++ * \retval Bridge result
++ *
++ * \note This should only be used by channel drivers in their technology declaration.
++ *
++ * \since 1.6.3
++ */
++enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
++
++/*!
++ * \brief Get the other RTP instance that an instance is bridged to
++ *
++ * \param instance The RTP instance that we want
++ *
++ * \retval non-NULL success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_instance *bridged = ast_rtp_instance_get_bridged(instance0);
++ * \endcode
++ *
++ * This gets the RTP instance that instance0 is bridged to.
++ *
++ * \since 1.6.3
++ */
++struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Make two channels compatible for early bridging
++ *
++ * \param c0 First channel part of the bridge
++ * \param c1 Second channel part of the bridge
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
++
++/*!
++ * \brief Early bridge two channels that use RTP instances
++ *
++ * \param c0 First channel part of the bridge
++ * \param c1 Second channel part of the bridge
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * \note This should only be used by channel drivers in their technology declaration.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
++
++/*!
++ * \brief Initialize RED support on an RTP instance
++ *
++ * \param instance The instance to initialize RED support on
++ * \param buffer_time How long to buffer before sending
++ * \param payloads Payload values
++ * \param generations Number of generations
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
++
++/*!
++ * \brief Buffer a frame in an RTP instance for RED
++ *
++ * \param instance The instance to buffer the frame on
++ * \param frame Frame that we want to buffer
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame);
++
++/*!
++ * \brief Retrieve statistics about an RTP instance
++ *
++ * \param instance Instance to get statistics on
++ * \param stats Structure to put results into
++ * \param stat What statistic(s) to retrieve
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * struct ast_rtp_instance_stats stats;
++ * ast_rtp_instance_get_stats(instance, &stats, AST_RTP_INSTANCE_STAT_ALL);
++ * \endcode
++ *
++ * This retrieves all statistics the underlying RTP engine supports and puts the values into the
++ * stats structure.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat);
++
++/*!
++ * \brief Set standard statistics from an RTP instance on a channel
++ *
++ * \param chan Channel to set the statistics on
++ * \param instance The RTP instance that statistics will be retrieved from
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_stats_vars(chan, rtp);
++ * \endcode
++ *
++ * This retrieves standard statistics from the RTP instance rtp and sets it on the channel pointed to
++ * by chan.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Retrieve quality statistics about an RTP instance
++ *
++ * \param instance Instance to get statistics on
++ * \param field What quality statistic to retrieve
++ * \param buf What buffer to put the result into
++ * \param size Size of the above buffer
++ *
++ * \retval non-NULL success
++ * \retval NULL failure
++ *
++ * Example usage:
++ *
++ * \code
++ * char quality[AST_MAX_USER_FIELD];
++ * ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, &buf, sizeof(buf));
++ * \endcode
++ *
++ * This retrieves general quality statistics and places a text representation into the buf pointed to by buf.
++ *
++ * \since 1.6.3
++ */
++char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size);
++
++/*!
++ * \brief Request that the underlying RTP engine provide audio frames in a specific format
++ *
++ * \param instance The RTP instance to change read format on
++ * \param format Format that frames are wanted in
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_read_format(instance, AST_FORMAT_ULAW);
++ * \endcode
++ *
++ * This requests that the RTP engine provide audio frames in the ULAW format.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, int format);
++
++/*!
++ * \brief Tell underlying RTP engine that audio frames will be provided in a specific format
++ *
++ * \param instance The RTP instance to change write format on
++ * \param format Format that frames will be provided in
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_write_format(instance, AST_FORMAT_ULAW);
++ * \endcode
++ *
++ * This tells the underlying RTP engine that audio frames will be provided to it in ULAW format.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, int format);
++
++/*!
++ * \brief Request that the underlying RTP engine make two RTP instances compatible with eachother
++ *
++ * \param chan Our own Asterisk channel
++ * \param instance The first RTP instance
++ * \param peer The peer Asterisk channel
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_make_compatible(instance, peer);
++ * \endcode
++ *
++ * This makes the RTP instance for 'peer' compatible with 'instance' and vice versa.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_channel *peer);
++
++/*!
++ * \brief Indicate to the RTP engine that packets are now expected to be sent/received on the RTP instance
++ *
++ * \param instance The RTP instance
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_activate(instance);
++ * \endcode
++ *
++ * This tells the underlying RTP engine of instance that packets will now flow.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_activate(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Request that the underlying RTP engine send a STUN BIND request
++ *
++ * \param instance The RTP instance
++ * \param suggestion The suggested destination
++ * \param username Optionally a username for the request
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_stun_request(instance, NULL, NULL);
++ * \endcode
++ *
++ * This requests that the RTP engine send a STUN BIND request on the session pointed to by
++ * 'instance'.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username);
++
++/*!
++ * \brief Set the RTP timeout value
++ *
++ * \param instance The RTP instance
++ * \param timeout Value to set the timeout to
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_timeout(instance, 5000);
++ * \endcode
++ *
++ * This sets the RTP timeout value on 'instance' to be 5000.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_set_timeout(struct ast_rtp_instance *instance, int timeout);
++
++/*!
++ * \brief Set the RTP timeout value for when the instance is on hold
++ *
++ * \param instance The RTP instance
++ * \param timeout Value to set the timeout to
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_set_hold_timeout(instance, 5000);
++ * \endcode
++ *
++ * This sets the RTP hold timeout value on 'instance' to be 5000.
++ *
++ * \since 1.6.3
++ */
++void ast_rtp_instance_set_hold_timeout(struct ast_rtp_instance *instance, int timeout);
++
++/*!
++ * \brief Get the RTP timeout value
++ *
++ * \param instance The RTP instance
++ *
++ * \retval timeout value
++ *
++ * Example usage:
++ *
++ * \code
++ * int timeout = ast_rtp_instance_get_timeout(instance);
++ * \endcode
++ *
++ * This gets the RTP timeout value for the RTP instance pointed to by 'instance'.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_get_timeout(struct ast_rtp_instance *instance);
++
++/*!
++ * \brief Get the RTP timeout value for when an RTP instance is on hold
++ *
++ * \param instance The RTP instance
++ *
++ * \retval timeout value
++ *
++ * Example usage:
++ *
++ * \code
++ * int timeout = ast_rtp_instance_get_hold_timeout(instance);
++ * \endcode
++ *
++ * This gets the RTP hold timeout value for the RTP instance pointed to by 'instance'.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_get_hold_timeout(struct ast_rtp_instance *instance);
++
++#if defined(__cplusplus) || defined(c_plusplus)
++}
++#endif
++
++#endif /* _ASTERISK_RTP_ENGINE_H */
+
+Property changes on: include/asterisk/rtp_engine.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: include/asterisk/utils.h
+===================================================================
+--- a/include/asterisk/utils.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/utils.h (.../trunk) (revision 186562)
+@@ -688,7 +688,7 @@
+ * This is set in asterisk.conf, or determined automatically by taking the mac
+ * address of an Ethernet interface on the system.
+ */
+-extern struct ast_eid g_eid;
++extern struct ast_eid ast_eid_default;
+
+ /*!
+ * \brief Fill in an ast_eid with the default eid of this machine
+Index: include/asterisk/channel.h
+===================================================================
+--- a/include/asterisk/channel.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/channel.h (.../trunk) (revision 186562)
+@@ -102,7 +102,7 @@
+ can create a native bridge without sending media through the
+ core.
+
+- Native briding can be disabled by a number of reasons,
++ Native bridging can be disabled by a number of reasons,
+ like DTMF being needed by the core or codecs being incompatible
+ so a transcoding module is needed.
+
+@@ -183,45 +183,173 @@
+ void (*digit)(struct ast_channel *chan, char digit);
+ };
+
+-/*! \brief Structure for all kinds of caller ID identifications.
++/*!
++ * \brief Structure for all kinds of caller ID identifications.
+ * \note All string fields here are malloc'ed, so they need to be
+ * freed when the structure is deleted.
+ * Also, NULL and "" must be considered equivalent.
+ *
+- * SIP and IAX2 has utf8 encoded Unicode caller ID names.
++ * \note SIP and IAX2 has utf8 encoded Unicode caller ID names.
+ * In some cases, we also have an alternative (RPID) E.164 number that can be used
+- * as caller ID on numeric E.164 phone networks (DAHDI or SIP/IAX2 to pstn gateway).
++ * as caller ID on numeric E.164 phone networks (DAHDI or SIP/IAX2 to PSTN gateway).
+ *
+ * \todo Implement settings for transliteration between UTF8 caller ID names in
+ * to Ascii Caller ID's (DAHDI). Östen Åsklund might be transliterated into
+- * Osten Asklund or Oesten Aasklund depending upon language and person...
+- * We need automatic routines for incoming calls and static settings for
+- * our own accounts.
++ * Osten Asklund or Oesten Aasklund depending upon language and person...
++ * We need automatic routines for incoming calls and static settings for
++ * our own accounts.
+ */
+ struct ast_callerid {
+- char *cid_dnid; /*!< Malloc'd Dialed Number Identifier */
+- char *cid_num; /*!< Malloc'd Caller Number */
+- char *cid_name; /*!< Malloc'd Caller Name (ASCII) */
+- char *cid_ani; /*!< Malloc'd ANI */
+- char *cid_rdnis; /*!< Malloc'd RDNIS */
+- int cid_pres; /*!< Callerid presentation/screening */
+- int cid_ani2; /*!< Callerid ANI 2 (Info digits) */
+- int cid_ton; /*!< Callerid Type of Number */
+- int cid_tns; /*!< Callerid Transit Network Select */
++ /*!
++ * \brief Malloc'd Dialed Number Identifier
++ * (Field will eventually move to struct ast_channel.dialed.number)
++ */
++ char *cid_dnid;
++
++ /*!
++ * \brief Malloc'd Caller Number
++ * (Field will eventually move to struct ast_channel.caller.id.number)
++ */
++ char *cid_num;
++
++ /*!
++ * \brief Malloc'd Caller Name (ASCII)
++ * (Field will eventually move to struct ast_channel.caller.id.name)
++ */
++ char *cid_name;
++
++ /*!
++ * \brief Malloc'd Automatic Number Identification (ANI)
++ * (Field will eventually move to struct ast_channel.caller.ani)
++ */
++ char *cid_ani;
++
++ /*!
++ * \brief Malloc'd Redirecting Directory Number Information Service (RDNIS)
++ * (Field will eventually move to struct ast_channel.redirecting.from.number)
++ */
++ char *cid_rdnis;
++
++ /*!
++ * \brief Callerid Q.931 encoded number presentation/screening fields
++ * (Field will eventually move to struct ast_channel.caller.id.number_presentation)
++ */
++ int cid_pres;
++
++ /*!
++ * \brief Callerid ANI 2 (Info digits)
++ * (Field will eventually move to struct ast_channel.caller.ani2)
++ */
++ int cid_ani2;
++
++ /*!
++ * \brief Callerid Q.931 encoded type-of-number/numbering-plan fields
++ * \note Currently this value is mostly just passed around the system.
++ * The H.323 interfaces set the value from received messages and uses the value for sent messages.
++ * The DAHDI PRI interfaces set the value from received messages but does not use it for sent messages.
++ * You can read it and set it but only H.323 uses it.
++ * (Field will eventually move to struct ast_channel.caller.id.number_type)
++ */
++ int cid_ton;
++
++ /*!
++ * \brief Callerid Transit Network Select
++ * \note Currently this value is just passed around the system.
++ * You can read it and set it but it is never used for anything.
++ * (Field will eventually move to struct ast_channel.dialed.transit_network_select)
++ */
++ int cid_tns;
+ };
+
+-/*! \brief
+- Structure to describe a channel "technology", ie a channel driver
+- See for examples:
+- \arg chan_iax2.c - The Inter-Asterisk exchange protocol
+- \arg chan_sip.c - The SIP channel driver
+- \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
++/*!
++ * \since 1.6.3
++ * \brief Information needed to identify an endpoint in a call.
++ * \note All string fields here are malloc'ed, so they need to be
++ * freed when the structure is deleted.
++ * \note NULL and "" must be considered equivalent.
++ */
++struct ast_party_id {
++ /*! \brief Subscriber phone number (Malloced) */
++ char *number;
+
+- If you develop your own channel driver, this is where you
+- tell the PBX at registration of your driver what properties
+- this driver supports and where different callbacks are
+- implemented.
+-*/
++ /*! \brief Subscriber name (Malloced) */
++ char *name;
++
++ /*! \brief Q.931 encoded type-of-number/numbering-plan fields */
++ int number_type;
++
++ /*! \brief Q.931 encoded number presentation/screening fields */
++ int number_presentation;
++};
++
++/*!
++ * \since 1.6.3
++ * \brief Connected Line/Party information.
++ * \note All string fields here are malloc'ed, so they need to be
++ * freed when the structure is deleted.
++ * \note NULL and "" must be considered equivalent.
++ */
++struct ast_party_connected_line {
++ struct ast_party_id id; /*! \brief Connected party ID */
++
++ /*!
++ * \brief Automatic Number Identification (ANI) (Malloced)
++ * \note Not really part of connected line data but needed to
++ * save the corresponding caller id value.
++ */
++ char *ani;
++
++ /*!
++ * \brief Automatic Number Identification 2 (Info Digits)
++ * \note Not really part of connected line data but needed to
++ * save the corresponding caller id value.
++ */
++ int ani2;
++
++ /*! \brief Information about the source of an update (Q.SIG/ISDN requirement).
++ * \note enum AST_CONNECTED_LINE_UPDATE_SOURCE values
++ * for Normal-Answer, Call-transfer, Call-diversion
++ */
++ int source;
++};
++
++/*!
++ * \since 1.6.3
++ * \brief Redirecting Line information.
++ * RDNIS (Redirecting Directory Number Information Service)
++ * Where a call diversion or transfer was invoked.
++ * \note All string fields here are malloc'ed, so they need to be
++ * freed when the structure is deleted.
++ * \note NULL and "" must be considered equivalent.
++ */
++struct ast_party_redirecting {
++ /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */
++ struct ast_party_id from;
++
++ /*! \brief Call is redirecting to a new party (Sent to the caller) */
++ struct ast_party_id to;
++
++ /*! \brief Number of times the call was redirected */
++ int count;
++
++ /*! \brief enum AST_REDIRECTING_REASON value for redirection */
++ int reason;
++};
++
++/*!
++ * \brief
++ * Structure to describe a channel "technology", ie a channel driver
++ * See for examples:
++ * \arg chan_iax2.c - The Inter-Asterisk exchange protocol
++ * \arg chan_sip.c - The SIP channel driver
++ * \arg chan_dahdi.c - PSTN connectivity (TDM, PRI, T1/E1, FXO, FXS)
++ *
++ * \details
++ * If you develop your own channel driver, this is where you
++ * tell the PBX at registration of your driver what properties
++ * this driver supports and where different callbacks are
++ * implemented.
++ */
+ struct ast_channel_tech {
+ const char * const type;
+ const char * const description;
+@@ -250,7 +378,7 @@
+ int (* const send_digit_end)(struct ast_channel *chan, char digit, unsigned int duration);
+
+ /*! \brief Call a given phone number (address, etc), but don't
+- take longer than timeout seconds to do so. */
++ * take longer than timeout seconds to do so. */
+ int (* const call)(struct ast_channel *chan, char *addr, int timeout);
+
+ /*! \brief Hangup (and possibly destroy) the channel */
+@@ -381,7 +509,8 @@
+ T38_STATE_NEGOTIATED, /*!< T38 established */
+ };
+
+-/*! \brief Main Channel structure associated with a channel.
++/*!
++ * \brief Main Channel structure associated with a channel.
+ * This is the side of it mostly used by the pbx and call management.
+ *
+ * \note XXX It is important to remember to increment .cleancount each time
+@@ -395,7 +524,6 @@
+ * and 8-byte fields causes 4 bytes of padding to be added before many
+ * 8-byte fields.
+ */
+-
+ struct ast_channel {
+ const struct ast_channel_tech *tech; /*!< Technology (point to channel driver) */
+ void *tech_pvt; /*!< Private data used by the technology driver */
+@@ -403,8 +531,8 @@
+ void *generatordata; /*!< Current generator data if there is any */
+ struct ast_generator *generator; /*!< Current active data generator */
+ struct ast_channel *_bridge; /*!< Who are we bridged to, if we're bridged.
+- Who is proxying for us, if we are proxied (i.e. chan_agent).
+- Do not access directly, use ast_bridged_channel(chan) */
++ * Who is proxying for us, if we are proxied (i.e. chan_agent).
++ * Do not access directly, use ast_bridged_channel(chan) */
+ struct ast_channel *masq; /*!< Channel that will masquerade as us */
+ struct ast_channel *masqr; /*!< Who we are masquerading as */
+ const char *blockproc; /*!< Procedure causing blocking */
+@@ -421,7 +549,7 @@
+ struct ast_audiohook_list *audiohooks;
+ struct ast_cdr *cdr; /*!< Call Detail Record */
+ struct ast_tone_zone *zone; /*!< Tone zone as set in indications.conf or
+- in the CHANNEL dialplan function */
++ * in the CHANNEL dialplan function */
+ struct ast_channel_monitor *monitor; /*!< Channel monitoring */
+ #ifdef HAVE_EPOLL
+ struct ast_epoll_data *epfd_data[AST_MAX_FDS];
+@@ -441,7 +569,29 @@
+ struct timeval whentohangup; /*!< Non-zero, set to actual time when channel is to be hung up */
+ pthread_t blocker; /*!< If anyone is blocking, this is them */
+ ast_mutex_t lock_dont_use; /*!< Lock a channel for some operations. See ast_channel_lock() */
+- struct ast_callerid cid; /*!< Caller ID, name, presentation etc */
++
++ /*!
++ * \brief Channel Caller ID information.
++ * \note The caller id information is the caller id of this
++ * channel when it is used to initiate a call.
++ */
++ struct ast_callerid cid;
++
++ /*!
++ * \brief Channel Connected Line ID information.
++ * \note The connected line information identifies the channel
++ * connected/bridged to this channel.
++ */
++ struct ast_party_connected_line connected;
++
++ /*!
++ * \brief Redirecting/Diversion information
++ * \note Until struct ast_channel.cid.cid_rdnis is replaced
++ * with ast_channel.redirecting.from.number, the
++ * ast_channel.redirecting.from.number field is not used.
++ */
++ struct ast_party_redirecting redirecting;
++
+ struct ast_frame dtmff; /*!< DTMF frame */
+ struct varshead varshead; /*!< A linked list for channel variables. See \ref AstChanVar */
+ ast_group_t callgroup; /*!< Call group for call pickups */
+@@ -456,11 +606,11 @@
+ unsigned long outsmpl; /*!< Track the read/written samples for monitor use */
+
+ int fds[AST_MAX_FDS]; /*!< File descriptors for channel -- Drivers will poll on
+- these file descriptors, so at least one must be non -1.
+- See \arg \ref AstFileDesc */
++ * these file descriptors, so at least one must be non -1.
++ * See \arg \ref AstFileDesc */
+ int cdrflags; /*!< Call Detail Record Flags */
+ int _softhangup; /*!< Whether or not we have been hung up... Do not set this value
+- directly, use ast_softhangup() */
++ * directly, use ast_softhangup() */
+ int fdno; /*!< Which fd had an event detected on */
+ int streamid; /*!< For streaming playback, the schedule ID */
+ int vstreamid; /*!< For streaming video playback, the schedule ID */
+@@ -473,9 +623,9 @@
+ int amaflags; /*!< Set BEFORE PBX is started to determine AMA flags */
+ enum ast_channel_adsicpe adsicpe; /*!< Whether or not ADSI is detected on CPE */
+ unsigned int fin; /*!< Frames in counters. The high bit is a debug mask, so
+- the counter is only in the remaining bits */
++ * the counter is only in the remaining bits */
+ unsigned int fout; /*!< Frames out counters. The high bit is a debug mask, so
+- the counter is only in the remaining bits */
++ * the counter is only in the remaining bits */
+ int hangupcause; /*!< Why is the channel hanged up. See causes.h */
+ unsigned int flags; /*!< channel flags of AST_FLAG_ type */
+ int alertpipe[2];
+@@ -490,12 +640,13 @@
+ #endif
+ int visible_indication; /*!< Indication currently playing on the channel */
+
+- unsigned short transfercapability; /*!< ISDN Transfer Capbility - AST_FLAG_DIGITAL is not enough */
++ unsigned short transfercapability; /*!< ISDN Transfer Capability - AST_FLAG_DIGITAL is not enough */
+
+ union {
+ char unused_old_dtmfq[AST_MAX_EXTENSION]; /*!< (deprecated, use readq instead) Any/all queued DTMF characters */
+ struct {
+ struct ast_bridge *bridge; /*!< Bridge this channel is participating in */
++ struct ast_timer *timer; /*!< timer object that provided timingfd */
+ };
+ };
+
+@@ -508,17 +659,21 @@
+
+ /*! \brief ast_channel_tech Properties */
+ enum {
+- /*! \brief Channels have this property if they can accept input with jitter;
+- * i.e. most VoIP channels */
++ /*!
++ * \brief Channels have this property if they can accept input with jitter;
++ * i.e. most VoIP channels
++ */
+ AST_CHAN_TP_WANTSJITTER = (1 << 0),
+- /*! \brief Channels have this property if they can create jitter;
+- * i.e. most VoIP channels */
++ /*!
++ * \brief Channels have this property if they can create jitter;
++ * i.e. most VoIP channels
++ */
+ AST_CHAN_TP_CREATESJITTER = (1 << 1),
+ };
+
+ /*! \brief ast_channel flags */
+ enum {
+- /*! Queue incoming dtmf, to be released when this flag is turned off */
++ /*! Queue incoming DTMF, to be released when this flag is turned off */
+ AST_FLAG_DEFER_DTMF = (1 << 1),
+ /*! write should be interrupt generator */
+ AST_FLAG_WRITE_INT = (1 << 2),
+@@ -549,7 +704,7 @@
+ * to instead only generate END frames. */
+ AST_FLAG_END_DTMF_ONLY = (1 << 14),
+ /*! Flag to show channels that this call is hangup due to the fact that the call
+- was indeed anwered, but in another channel */
++ was indeed answered, but in another channel */
+ AST_FLAG_ANSWERED_ELSEWHERE = (1 << 15),
+ /*! This flag indicates that on a masquerade, an active stream should not
+ * be carried over */
+@@ -674,7 +829,6 @@
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+-
+ int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore);
+
+ /*!
+@@ -777,6 +931,7 @@
+ * \retval 0 success
+ * \retval non-zero failure
+ *
++ * \details
+ * The supplied payload data is copied into the frame, so the caller's copy
+ * is not modified nor freed, and the resulting frame will retain a copy of
+ * the data even if the caller frees their local copy.
+@@ -811,6 +966,7 @@
+ * \param data data to pass to the channel requester
+ * \param status status
+ *
++ * \details
+ * Request a channel of a given type, with data as optional information used
+ * by the low level module
+ *
+@@ -854,54 +1010,63 @@
+ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data,
+ int timeout, int *reason, const char *cid_num, const char *cid_name, struct outgoing_helper *oh);
+
+-/*!\brief Register a channel technology (a new channel driver)
++/*!
++ * \brief Register a channel technology (a new channel driver)
+ * Called by a channel module to register the kind of channels it supports.
+ * \param tech Structure defining channel technology or "type"
+ * \return Returns 0 on success, -1 on failure.
+ */
+ int ast_channel_register(const struct ast_channel_tech *tech);
+
+-/*! \brief Unregister a channel technology
++/*!
++ * \brief Unregister a channel technology
+ * \param tech Structure defining channel technology or "type" that was previously registered
+ * \return No return value.
+ */
+ void ast_channel_unregister(const struct ast_channel_tech *tech);
+
+-/*! \brief Get a channel technology structure by name
++/*!
++ * \brief Get a channel technology structure by name
+ * \param name name of technology to find
+ * \return a pointer to the structure, or NULL if no matching technology found
+ */
+ const struct ast_channel_tech *ast_get_channel_tech(const char *name);
+
+ #ifdef CHANNEL_TRACE
+-/*! \brief Update the context backtrace if tracing is enabled
++/*!
++ * \brief Update the context backtrace if tracing is enabled
+ * \return Returns 0 on success, -1 on failure
+ */
+ int ast_channel_trace_update(struct ast_channel *chan);
+
+-/*! \brief Enable context tracing in the channel
++/*!
++ * \brief Enable context tracing in the channel
+ * \return Returns 0 on success, -1 on failure
+ */
+ int ast_channel_trace_enable(struct ast_channel *chan);
+
+-/*! \brief Disable context tracing in the channel.
++/*!
++ * \brief Disable context tracing in the channel.
+ * \note Does not remove current trace entries
+ * \return Returns 0 on success, -1 on failure
+ */
+ int ast_channel_trace_disable(struct ast_channel *chan);
+
+-/*! \brief Whether or not context tracing is enabled
++/*!
++ * \brief Whether or not context tracing is enabled
+ * \return Returns -1 when the trace is enabled. 0 if not.
+ */
+ int ast_channel_trace_is_enabled(struct ast_channel *chan);
+
+-/*! \brief Put the channel backtrace in a string
++/*!
++ * \brief Put the channel backtrace in a string
+ * \return Returns the amount of lines in the backtrace. -1 on error.
+ */
+ int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out);
+ #endif
+
+-/*! \brief Hang up a channel
++/*!
++ * \brief Hang up a channel
+ * \note This function performs a hard hangup on a channel. Unlike the soft-hangup, this function
+ * performs all stream stopping, etc, on the channel that needs to end.
+ * chan is no longer valid after this call.
+@@ -916,6 +1081,7 @@
+ * \param chan channel to be soft-hung-up
+ * \param cause Ast hangupcause for hangup
+ *
++ * \details
+ * Call the protocol layer, but don't destroy the channel structure
+ * (use this if you are trying to
+ * safely hangup a channel managed by another thread.
+@@ -926,9 +1092,11 @@
+ */
+ int ast_softhangup(struct ast_channel *chan, int cause);
+
+-/*! \brief Softly hangup up a channel (no channel lock)
++/*!
++ * \brief Softly hangup up a channel (no channel lock)
+ * \param chan channel to be soft-hung-up
+- * \param cause Ast hangupcause for hangup (see cause.h) */
++ * \param cause Ast hangupcause for hangup (see cause.h)
++ */
+ int ast_softhangup_nolock(struct ast_channel *chan, int cause);
+
+ /*! \brief Check to see if a channel is needing hang up
+@@ -943,6 +1111,7 @@
+ * \param chan channel on which to check for hang up
+ * \param offset offset in seconds from current time
+ * \return 1, 0, or -1
++ * \details
+ * This function compares a offset from current time with the absolute time
+ * out on a channel (when to hang up). If the absolute time out on a channel
+ * is earlier than current time plus the offset, it returns 1, if the two
+@@ -965,11 +1134,13 @@
+ */
+ int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offset);
+
+-/*! \brief Set when to hang a channel up
++/*!
++ * \brief Set when to hang a channel up
+ *
+ * \param chan channel on which to check for hang up
+ * \param offset offset in seconds relative to the current time of when to hang up
+ *
++ * \details
+ * This function sets the absolute time out on a channel (when to hang up).
+ *
+ * \note This function does not require that the channel is locked before
+@@ -981,7 +1152,8 @@
+ */
+ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) __attribute__((deprecated));
+
+-/*! \brief Set when to hang a channel up
++/*!
++ * \brief Set when to hang a channel up
+ *
+ * \param chan channel on which to check for hang up
+ * \param offset offset in seconds and useconds relative to the current time of when to hang up
+@@ -1001,6 +1173,7 @@
+ *
+ * \param chan channel to answer
+ *
++ * \details
+ * This function answers a channel and handles all necessary call
+ * setup functions.
+ *
+@@ -1061,18 +1234,21 @@
+ */
+ int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer);
+
+-/*! \brief Make a call
++/*!
++ * \brief Make a call
+ * \param chan which channel to make the call on
+ * \param addr destination of the call
+ * \param timeout time to wait on for connect
++ * \details
+ * Place a call, take no longer than timeout ms.
+- \return Returns -1 on failure, 0 on not enough time
+- (does not automatically stop ringing), and
+- the number of seconds the connect took otherwise.
+- */
++ * \return -1 on failure, 0 on not enough time
++ * (does not automatically stop ringing), and
++ * the number of seconds the connect took otherwise.
++ */
+ int ast_call(struct ast_channel *chan, char *addr, int timeout);
+
+-/*! \brief Indicates condition of channel
++/*!
++ * \brief Indicates condition of channel
+ * \note Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel
+ * \param chan channel to change the indication
+ * \param condition which condition to indicate on the channel
+@@ -1080,7 +1256,8 @@
+ */
+ int ast_indicate(struct ast_channel *chan, int condition);
+
+-/*! \brief Indicates condition of channel, with payload
++/*!
++ * \brief Indicates condition of channel, with payload
+ * \note Indicate a condition such as AST_CONTROL_HOLD with payload being music on hold class
+ * \param chan channel to change the indication
+ * \param condition which condition to indicate on the channel
+@@ -1092,33 +1269,43 @@
+
+ /* Misc stuff ------------------------------------------------ */
+
+-/*! \brief Wait for input on a channel
++/*!
++ * \brief Wait for input on a channel
+ * \param chan channel to wait on
+ * \param ms length of time to wait on the channel
++ * \details
+ * Wait for input on a channel for a given # of milliseconds (<0 for indefinite).
+- \return Returns < 0 on failure, 0 if nothing ever arrived, and the # of ms remaining otherwise */
++ * \retval < 0 on failure
++ * \retval 0 if nothing ever arrived
++ * \retval the # of ms remaining otherwise
++ */
+ int ast_waitfor(struct ast_channel *chan, int ms);
+
+-/*! \brief Wait for a specified amount of time, looking for hangups
++/*!
++ * \brief Wait for a specified amount of time, looking for hangups
+ * \param chan channel to wait for
+ * \param ms length of time in milliseconds to sleep
++ * \details
+ * Waits for a specified amount of time, servicing the channel as required.
+ * \return returns -1 on hangup, otherwise 0.
+ */
+ int ast_safe_sleep(struct ast_channel *chan, int ms);
+
+-/*! \brief Wait for a specified amount of time, looking for hangups and a condition argument
++/*!
++ * \brief Wait for a specified amount of time, looking for hangups and a condition argument
+ * \param chan channel to wait for
+ * \param ms length of time in milliseconds to sleep
+ * \param cond a function pointer for testing continue condition
+ * \param data argument to be passed to the condition test function
+ * \return returns -1 on hangup, otherwise 0.
++ * \details
+ * Waits for a specified amount of time, servicing the channel as required. If cond
+ * returns 0, this function returns.
+ */
+ int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data );
+
+-/*! \brief Waits for activity on a group of channels
++/*!
++ * \brief Waits for activity on a group of channels
+ * \param chan an array of pointers to channels
+ * \param n number of channels that are to be waited upon
+ * \param fds an array of fds to wait upon
+@@ -1126,44 +1313,55 @@
+ * \param exception exception flag
+ * \param outfd fd that had activity on it
+ * \param ms how long the wait was
++ * \details
+ * Big momma function here. Wait for activity on any of the n channels, or any of the nfds
+- file descriptors.
+- \return Returns the channel with activity, or NULL on error or if an FD
+- came first. If the FD came first, it will be returned in outfd, otherwise, outfd
+- will be -1 */
++ * file descriptors.
++ * \return Returns the channel with activity, or NULL on error or if an FD
++ * came first. If the FD came first, it will be returned in outfd, otherwise, outfd
++ * will be -1
++ */
+ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **chan, int n,
+ int *fds, int nfds, int *exception, int *outfd, int *ms);
+
+-/*! \brief Waits for input on a group of channels
+- Wait for input on an array of channels for a given # of milliseconds.
+- \return Return channel with activity, or NULL if none has activity.
+- \param chan an array of pointers to channels
+- \param n number of channels that are to be waited upon
+- \param ms time "ms" is modified in-place, if applicable */
++/*!
++ * \brief Waits for input on a group of channels
++ * Wait for input on an array of channels for a given # of milliseconds.
++ * \return Return channel with activity, or NULL if none has activity.
++ * \param chan an array of pointers to channels
++ * \param n number of channels that are to be waited upon
++ * \param ms time "ms" is modified in-place, if applicable
++ */
+ struct ast_channel *ast_waitfor_n(struct ast_channel **chan, int n, int *ms);
+
+-/*! \brief Waits for input on an fd
+- This version works on fd's only. Be careful with it. */
++/*!
++ * \brief Waits for input on an fd
++ * \note This version works on fd's only. Be careful with it.
++ */
+ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception);
+
+
+-/*! \brief Reads a frame
++/*!
++ * \brief Reads a frame
+ * \param chan channel to read a frame from
+ * \return Returns a frame, or NULL on error. If it returns NULL, you
+- best just stop reading frames and assume the channel has been
+- disconnected. */
++ * best just stop reading frames and assume the channel has been
++ * disconnected.
++ */
+ struct ast_frame *ast_read(struct ast_channel *chan);
+
+-/*! \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
+- \param chan channel to read a frame from
+- \return Returns a frame, or NULL on error. If it returns NULL, you
+- best just stop reading frames and assume the channel has been
+- disconnected.
+- \note Audio is replaced with AST_FRAME_NULL to avoid
+- transcode when the resulting audio is not necessary. */
++/*!
++ * \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
++ * \param chan channel to read a frame from
++ * \return Returns a frame, or NULL on error. If it returns NULL, you
++ * best just stop reading frames and assume the channel has been
++ * disconnected.
++ * \note Audio is replaced with AST_FRAME_NULL to avoid
++ * transcode when the resulting audio is not necessary.
++ */
+ struct ast_frame *ast_read_noaudio(struct ast_channel *chan);
+
+-/*! \brief Write a frame to a channel
++/*!
++ * \brief Write a frame to a channel
+ * This function writes the given frame to the indicated channel.
+ * \param chan destination channel of the frame
+ * \param frame frame that will be written
+@@ -1171,7 +1369,8 @@
+ */
+ int ast_write(struct ast_channel *chan, struct ast_frame *frame);
+
+-/*! \brief Write video frame to a channel
++/*!
++ * \brief Write video frame to a channel
+ * This function writes the given frame to the indicated channel.
+ * \param chan destination channel of the frame
+ * \param frame frame that will be written
+@@ -1179,7 +1378,8 @@
+ */
+ int ast_write_video(struct ast_channel *chan, struct ast_frame *frame);
+
+-/*! \brief Write text frame to a channel
++/*!
++ * \brief Write text frame to a channel
+ * This function writes the given frame to the indicated channel.
+ * \param chan destination channel of the frame
+ * \param frame frame that will be written
+@@ -1190,7 +1390,8 @@
+ /*! \brief Send empty audio to prime a channel driver */
+ int ast_prod(struct ast_channel *chan);
+
+-/*! \brief Sets read format on channel chan
++/*!
++ * \brief Sets read format on channel chan
+ * Set read format for channel to whichever component of "format" is best.
+ * \param chan channel to change
+ * \param format format to change to
+@@ -1198,7 +1399,8 @@
+ */
+ int ast_set_read_format(struct ast_channel *chan, int format);
+
+-/*! \brief Sets write format on channel chan
++/*!
++ * \brief Sets write format on channel chan
+ * Set write format for channel to whichever component of "format" is best.
+ * \param chan channel to change
+ * \param format new format for writing
+@@ -1212,6 +1414,7 @@
+ * \param chan channel to act upon
+ * \param text string of text to send on the channel
+ *
++ * \details
+ * Write text to a display on a channel
+ *
+ * \note The channel does not need to be locked before calling this function.
+@@ -1221,34 +1424,35 @@
+ */
+ int ast_sendtext(struct ast_channel *chan, const char *text);
+
+-/*! \brief Receives a text character from a channel
++/*!
++ * \brief Receives a text character from a channel
+ * \param chan channel to act upon
+ * \param timeout timeout in milliseconds (0 for infinite wait)
++ * \details
+ * Read a char of text from a channel
+- * Returns 0 on success, -1 on failure
++ * \return 0 on success, -1 on failure
+ */
+ int ast_recvchar(struct ast_channel *chan, int timeout);
+
+-/*! \brief Send a DTMF digit to a channel
+- * Send a DTMF digit to a channel.
++/*!
++ * \brief Send a DTMF digit to a channel.
+ * \param chan channel to act upon
+ * \param digit the DTMF digit to send, encoded in ASCII
+ * \param duration the duration of the digit ending in ms
+- * \return Returns 0 on success, -1 on failure
++ * \return 0 on success, -1 on failure
+ */
+ int ast_senddigit(struct ast_channel *chan, char digit, unsigned int duration);
+
+-/*! \brief Send a DTMF digit to a channel
+- * Send a DTMF digit to a channel.
++/*!
++ * \brief Send a DTMF digit to a channel.
+ * \param chan channel to act upon
+ * \param digit the DTMF digit to send, encoded in ASCII
+- * \return Returns 0 on success, -1 on failure
++ * \return 0 on success, -1 on failure
+ */
+ int ast_senddigit_begin(struct ast_channel *chan, char digit);
+
+-/*! \brief Send a DTMF digit to a channel
+-
+- * Send a DTMF digit to a channel.
++/*!
++ * \brief Send a DTMF digit to a channel.
+ * \param chan channel to act upon
+ * \param digit the DTMF digit to send, encoded in ASCII
+ * \param duration the duration of the digit ending in ms
+@@ -1256,7 +1460,8 @@
+ */
+ int ast_senddigit_end(struct ast_channel *chan, char digit, unsigned int duration);
+
+-/*! \brief Receives a text string from a channel
++/*!
++ * \brief Receives a text string from a channel
+ * Read a string of text from a channel
+ * \param chan channel to act upon
+ * \param timeout timeout in milliseconds (0 for infinite wait)
+@@ -1264,11 +1469,12 @@
+ */
+ char *ast_recvtext(struct ast_channel *chan, int timeout);
+
+-/*! \brief Browse channels in use
++/*!
++ * \brief Browse channels in use
+ * Browse the channels currently in use
+ * \param prev where you want to start in the channel list
+ * \return Returns the next channel in the list, NULL on end.
+- * If it returns a channel, that channel *has been locked*!
++ * If it returns a channel, that channel *has been locked*!
+ */
+ struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev);
+
+@@ -1288,7 +1494,8 @@
+ struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
+ const char *context);
+
+-/*! \brief Search for a channel based on the passed channel matching callback
++/*!
++ * \brief Search for a channel based on the passed channel matching callback
+ * Search for a channel based on the specified is_match callback, and return the
+ * first channel that we match. When returned, the channel will be locked. Note
+ * that the is_match callback is called with the passed channel locked, and should
+@@ -1300,33 +1507,41 @@
+ */
+ struct ast_channel *ast_channel_search_locked(int (*is_match)(struct ast_channel *, void *), void *data);
+
+-/*! ! \brief Waits for a digit
++/*!
++ * \brief Waits for a digit
+ * \param c channel to wait for a digit on
+ * \param ms how many milliseconds to wait
+- * \return Returns <0 on error, 0 on no entry, and the digit on success. */
++ * \return Returns <0 on error, 0 on no entry, and the digit on success.
++ */
+ int ast_waitfordigit(struct ast_channel *c, int ms);
+
+-/*! \brief Wait for a digit
+- Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
++/*!
++ * \brief Wait for a digit
++ * Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
+ * \param c channel to wait for a digit on
+ * \param ms how many milliseconds to wait
+ * \param audiofd audio file descriptor to write to if audio frames are received
+ * \param ctrlfd control file descriptor to monitor for reading
+- * \return Returns 1 if ctrlfd becomes available */
++ * \return Returns 1 if ctrlfd becomes available
++ */
+ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
+
+-/*! Reads multiple digits
++/*!
++ * \brief Reads multiple digits
+ * \param c channel to read from
+ * \param s string to read in to. Must be at least the size of your length
+ * \param len how many digits to read (maximum)
+ * \param timeout how long to timeout between digits
+ * \param rtimeout timeout to wait on the first digit
+ * \param enders digits to end the string
++ * \details
+ * Read in a digit string "s", max length "len", maximum timeout between
+- digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
+- for the first digit. Returns 0 on normal return, or 1 on a timeout. In the case of
+- a timeout, any digits that were read before the timeout will still be available in s.
+- RETURNS 2 in full version when ctrlfd is available, NOT 1*/
++ * digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
++ * for the first digit.
++ * \return Returns 0 on normal return, or 1 on a timeout. In the case of
++ * a timeout, any digits that were read before the timeout will still be available in s.
++ * RETURNS 2 in full version when ctrlfd is available, NOT 1
++ */
+ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
+ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders, int audiofd, int ctrlfd);
+
+@@ -1342,28 +1557,37 @@
+ #define AST_BRIDGE_IGNORE_SIGS (1 << 4)
+
+
+-/*! \brief Makes two channel formats compatible
++/*!
++ * \brief Makes two channel formats compatible
+ * \param c0 first channel to make compatible
+ * \param c1 other channel to make compatible
+- * Set two channels to compatible formats -- call before ast_channel_bridge in general .
+- * \return Returns 0 on success and -1 if it could not be done */
++ * \details
++ * Set two channels to compatible formats -- call before ast_channel_bridge in general.
++ * \return Returns 0 on success and -1 if it could not be done
++ */
+ int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
+
+-/*! Bridge two channels together (early)
++/*!
++ * \brief Bridge two channels together (early)
+ * \param c0 first channel to bridge
+ * \param c1 second channel to bridge
++ * \details
+ * Bridge two channels (c0 and c1) together early. This implies either side may not be answered yet.
+- * \return Returns 0 on success and -1 if it could not be done */
++ * \return Returns 0 on success and -1 if it could not be done
++ */
+ int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
+
+-/*! Bridge two channels together
++/*!
++ * \brief Bridge two channels together
+ * \param c0 first channel to bridge
+ * \param c1 second channel to bridge
+ * \param config config for the channels
+ * \param fo destination frame(?)
+ * \param rc destination channel(?)
++ * \details
+ * Bridge two channels (c0 and c1) together. If an important frame occurs, we return that frame in
+- *rf (remember, it could be NULL) and which channel (0 or 1) in rc */
++ * *rf (remember, it could be NULL) and which channel (0 or 1) in rc
++ */
+ /* int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); */
+ int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,
+ struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc);
+@@ -1374,6 +1598,7 @@
+ * \param original channel to make a copy of
+ * \param clone copy of the original channel
+ *
++ * \details
+ * This is a very strange and freaky function used primarily for transfer. Suppose that
+ * "original" and "clone" are two channels in random situations. This function takes
+ * the guts out of "clone" and puts them into the "original" channel, then alerts the
+@@ -1385,100 +1610,114 @@
+ */
+ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
+
+-/*! Gives the string form of a given cause code */
+ /*!
++ * \brief Gives the string form of a given cause code.
++ *
+ * \param state cause to get the description of
+- * Give a name to a cause code
+- * Returns the text form of the binary cause code given
++ * \return the text form of the binary cause code given
+ */
+ const char *ast_cause2str(int state) attribute_pure;
+
+-/*! Convert the string form of a cause code to a number */
+ /*!
++ * \brief Convert the string form of a cause code to a number
++ *
+ * \param name string form of the cause
+- * Returns the cause code
++ * \return the cause code
+ */
+ int ast_str2cause(const char *name) attribute_pure;
+
+-/*! Gives the string form of a given channel state */
+ /*!
++ * \brief Gives the string form of a given channel state
++ *
+ * \param ast_channel_state state to get the name of
+- * Give a name to a state
+- * Returns the text form of the binary state given
++ * \return the text form of the binary state given
+ */
+ const char *ast_state2str(enum ast_channel_state);
+
+-/*! Gives the string form of a given transfer capability */
+ /*!
+- * \param transfercapability transfercapabilty to get the name of
+- * Give a name to a transfercapbility
+- * See above
+- * Returns the text form of the binary transfer capability
++ * \brief Gives the string form of a given transfer capability
++ *
++ * \param transfercapability transfer capability to get the name of
++ * \return the text form of the binary transfer capability
+ */
+ char *ast_transfercapability2str(int transfercapability) attribute_const;
+
+-/* Options: Some low-level drivers may implement "options" allowing fine tuning of the
+- low level channel. See frame.h for options. Note that many channel drivers may support
+- none or a subset of those features, and you should not count on this if you want your
+- asterisk application to be portable. They're mainly useful for tweaking performance */
++/*
++ * Options: Some low-level drivers may implement "options" allowing fine tuning of the
++ * low level channel. See frame.h for options. Note that many channel drivers may support
++ * none or a subset of those features, and you should not count on this if you want your
++ * asterisk application to be portable. They're mainly useful for tweaking performance
++ */
+
+-/*! Sets an option on a channel */
+ /*!
++ * \brief Sets an option on a channel
++ *
+ * \param channel channel to set options on
+ * \param option option to change
+ * \param data data specific to option
+ * \param datalen length of the data
+ * \param block blocking or not
++ * \details
+ * Set an option on a channel (see frame.h), optionally blocking awaiting the reply
+- * Returns 0 on success and -1 on failure
++ * \return 0 on success and -1 on failure
+ */
+ int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block);
+
+-/*! Pick the best codec */
+-/* Choose the best codec... Uhhh... Yah. */
++/*! Pick the best codec
++ * Choose the best codec... Uhhh... Yah. */
+ int ast_best_codec(int fmts);
+
+
+-/*! Checks the value of an option */
+ /*!
++ * \brief Checks the value of an option
++ *
+ * Query the value of an option
+ * Works similarly to setoption except only reads the options.
+ */
+ int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
+
+-/*! Checks for HTML support on a channel */
+-/*! Returns 0 if channel does not support HTML or non-zero if it does */
++/*!
++ * \brief Checks for HTML support on a channel
++ * \return 0 if channel does not support HTML or non-zero if it does
++ */
+ int ast_channel_supports_html(struct ast_channel *channel);
+
+-/*! Sends HTML on given channel */
+-/*! Send HTML or URL on link. Returns 0 on success or -1 on failure */
++/*!
++ * \brief Sends HTML on given channel
++ * Send HTML or URL on link.
++ * \return 0 on success or -1 on failure
++ */
+ int ast_channel_sendhtml(struct ast_channel *channel, int subclass, const char *data, int datalen);
+
+-/*! Sends a URL on a given link */
+-/*! Send URL on link. Returns 0 on success or -1 on failure */
++/*!
++ * \brief Sends a URL on a given link
++ * Send URL on link.
++ * \return 0 on success or -1 on failure
++ */
+ int ast_channel_sendurl(struct ast_channel *channel, const char *url);
+
+-/*! Defers DTMF */
+-/*! Defer DTMF so that you only read things like hangups and audio. Returns
+- non-zero if channel was already DTMF-deferred or 0 if channel is just now
+- being DTMF-deferred */
++/*!
++ * \brief Defers DTMF so that you only read things like hangups and audio.
++ * \return non-zero if channel was already DTMF-deferred or
++ * 0 if channel is just now being DTMF-deferred
++ */
+ int ast_channel_defer_dtmf(struct ast_channel *chan);
+
+-/*! Undo defer. ast_read will return any dtmf characters that were queued */
++/*! Undo defer. ast_read will return any DTMF characters that were queued */
+ void ast_channel_undefer_dtmf(struct ast_channel *chan);
+
+ /*! Initiate system shutdown -- prevents new channels from being allocated.
+- If "hangup" is non-zero, all existing channels will receive soft
+- hangups */
++ * \param hangup If "hangup" is non-zero, all existing channels will receive soft
++ * hangups */
+ void ast_begin_shutdown(int hangup);
+
+ /*! Cancels an existing shutdown and returns to normal operation */
+ void ast_cancel_shutdown(void);
+
+-/*! Returns number of active/allocated channels */
++/*! \return number of active/allocated channels */
+ int ast_active_channels(void);
+
+-/*! Returns non-zero if Asterisk is being shut down */
++/*! \return non-zero if Asterisk is being shut down */
+ int ast_shutting_down(void);
+
+ /*! Activate a given generator */
+@@ -1536,105 +1775,119 @@
+ *
+ * \param rate number of timer ticks per second
+ *
++ * \details
+ * If timers are supported, force a scheduled expiration on the
+ * timer fd, at which point we call the callback function / data
+ *
+- * Call this function with a rate of 0 to turn off the timer ticks
++ * \note Call this function with a rate of 0 to turn off the timer ticks
+ *
+ * \version 1.6.1 changed samples parameter to rate, accomodates new timing methods
+ */
+ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data);
+
+-/*! \brief Transfer a channel (if supported). Returns -1 on error, 0 if not supported
+- and 1 if supported and requested
+- \param chan current channel
+- \param dest destination extension for transfer
+-*/
++/*!
++ * \brief Transfer a channel (if supported).
++ * \retval -1 on error
++ * \retval 0 if not supported
++ * \retval 1 if supported and requested
++ * \param chan current channel
++ * \param dest destination extension for transfer
++ */
+ int ast_transfer(struct ast_channel *chan, char *dest);
+
+-/*! \brief Start masquerading a channel
+- XXX This is a seriously whacked out operation. We're essentially putting the guts of
+- the clone channel into the original channel. Start by killing off the original
+- channel's backend. I'm not sure we're going to keep this function, because
+- while the features are nice, the cost is very high in terms of pure nastiness. XXX
+- \param chan Channel to masquerade
+-*/
++/*!
++ * \brief Start masquerading a channel
++ * \details
++ * XXX This is a seriously whacked out operation. We're essentially putting the guts of
++ * the clone channel into the original channel. Start by killing off the original
++ * channel's backend. I'm not sure we're going to keep this function, because
++ * while the features are nice, the cost is very high in terms of pure nastiness. XXX
++ * \param chan Channel to masquerade
++ */
+ int ast_do_masquerade(struct ast_channel *chan);
+
+-/*! \brief Find bridged channel
+- \param chan Current channel
+-*/
++/*!
++ * \brief Find bridged channel
++ * \param chan Current channel
++ */
+ struct ast_channel *ast_bridged_channel(struct ast_channel *chan);
+
+ /*!
+- \brief Inherits channel variable from parent to child channel
+- \param parent Parent channel
+- \param child Child channel
+-
+- Scans all channel variables in the parent channel, looking for those
+- that should be copied into the child channel.
+- Variables whose names begin with a single '_' are copied into the
+- child channel with the prefix removed.
+- Variables whose names begin with '__' are copied into the child
+- channel with their names unchanged.
+-*/
++ * \brief Inherits channel variable from parent to child channel
++ * \param parent Parent channel
++ * \param child Child channel
++ *
++ * \details
++ * Scans all channel variables in the parent channel, looking for those
++ * that should be copied into the child channel.
++ * Variables whose names begin with a single '_' are copied into the
++ * child channel with the prefix removed.
++ * Variables whose names begin with '__' are copied into the child
++ * channel with their names unchanged.
++ */
+ void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child);
+
+ /*!
+- \brief adds a list of channel variables to a channel
+- \param chan the channel
+- \param vars a linked list of variables
+-
+- Variable names can be for a regular channel variable or a dialplan function
+- that has the ability to be written to.
+-*/
++ * \brief adds a list of channel variables to a channel
++ * \param chan the channel
++ * \param vars a linked list of variables
++ *
++ * \details
++ * Variable names can be for a regular channel variable or a dialplan function
++ * that has the ability to be written to.
++ */
+ void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars);
+
+ /*!
+- \brief An opaque 'object' structure use by silence generators on channels.
++ * \brief An opaque 'object' structure use by silence generators on channels.
+ */
+ struct ast_silence_generator;
+
+ /*!
+- \brief Starts a silence generator on the given channel.
+- \param chan The channel to generate silence on
+- \return An ast_silence_generator pointer, or NULL if an error occurs
+-
+- This function will cause SLINEAR silence to be generated on the supplied
+- channel until it is disabled; if the channel cannot be put into SLINEAR
+- mode then the function will fail.
+-
+- The pointer returned by this function must be preserved and passed to
+- ast_channel_stop_silence_generator when you wish to stop the silence
+- generation.
++ * \brief Starts a silence generator on the given channel.
++ * \param chan The channel to generate silence on
++ * \return An ast_silence_generator pointer, or NULL if an error occurs
++ *
++ * \details
++ * This function will cause SLINEAR silence to be generated on the supplied
++ * channel until it is disabled; if the channel cannot be put into SLINEAR
++ * mode then the function will fail.
++ *
++ * \note
++ * The pointer returned by this function must be preserved and passed to
++ * ast_channel_stop_silence_generator when you wish to stop the silence
++ * generation.
+ */
+ struct ast_silence_generator *ast_channel_start_silence_generator(struct ast_channel *chan);
+
+ /*!
+- \brief Stops a previously-started silence generator on the given channel.
+- \param chan The channel to operate on
+- \param state The ast_silence_generator pointer return by a previous call to
+- ast_channel_start_silence_generator.
+- \return nothing
+-
+- This function will stop the operating silence generator and return the channel
+- to its previous write format.
++ * \brief Stops a previously-started silence generator on the given channel.
++ * \param chan The channel to operate on
++ * \param state The ast_silence_generator pointer return by a previous call to
++ * ast_channel_start_silence_generator.
++ * \return nothing
++ *
++ * \details
++ * This function will stop the operating silence generator and return the channel
++ * to its previous write format.
+ */
+ void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state);
+
+ /*!
+- \brief Check if the channel can run in internal timing mode.
+- \param chan The channel to check
+- \return boolean
+-
+- This function will return 1 if internal timing is enabled and the timing
+- device is available.
++ * \brief Check if the channel can run in internal timing mode.
++ * \param chan The channel to check
++ * \return boolean
++ *
++ * \details
++ * This function will return 1 if internal timing is enabled and the timing
++ * device is available.
+ */
+ int ast_internal_timing_enabled(struct ast_channel *chan);
+
+ /* Misc. functions below */
+
+-/*! \brief if fd is a valid descriptor, set *pfd with the descriptor
++/*!
++ * \brief if fd is a valid descriptor, set *pfd with the descriptor
+ * \return Return 1 (not -1!) if added, 0 otherwise (so we can add the
+ * return value to the index into the array)
+ */
+@@ -1677,12 +1930,14 @@
+ }
+ #endif
+
+-/*! \brief Waits for activity on a group of channels
++/*!
++ * \brief Waits for activity on a group of channels
+ * \param nfds the maximum number of file descriptors in the sets
+ * \param rfds file descriptors to check for read availability
+ * \param wfds file descriptors to check for write availability
+ * \param efds file descriptors to check for exceptions (OOB data)
+ * \param tvp timeout while waiting for events
++ * \details
+ * This is the same as a standard select(), except it guarantees the
+ * behaviour where the passed struct timeval is updated with how much
+ * time was not slept while waiting for the specified events
+@@ -1739,23 +1994,23 @@
+ /*! \brief print call- and pickup groups into buffer */
+ char *ast_print_group(char *buf, int buflen, ast_group_t group);
+
+-/*! \brief Convert enum channelreloadreason to text string for manager event
+- \param reason Enum channelreloadreason - reason for reload (manager, cli, start etc)
+-*/
++/*!
++ * \brief Convert enum channelreloadreason to text string for manager event
++ * \param reason The reason for reload (manager, cli, start etc)
++ */
+ const char *channelreloadreason2txt(enum channelreloadreason reason);
+
+ /*! \brief return an ast_variable list of channeltypes */
+ struct ast_variable *ast_channeltype_list(void);
+
+ /*!
+- \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
+- \param reason The integer argument, usually taken from AST_CONTROL_ macros
+- \return char pointer explaining the code
++ * \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
++ * \param reason The integer argument, usually taken from AST_CONTROL_ macros
++ * \return char pointer explaining the code
+ */
+ const char *ast_channel_reason2str(int reason);
+
+-/*! \brief channel group info
+- */
++/*! \brief channel group info */
+ struct ast_group_info {
+ struct ast_channel *chan;
+ char *category;
+@@ -1764,6 +2019,295 @@
+ };
+
+
++/*!
++ * \since 1.6.3
++ * \brief Copy the source caller information to the destination caller.
++ *
++ * \param dest Destination caller
++ * \param src Source caller
++ *
++ * \return Nothing
++ */
++void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src);
++
++/*!
++ * \since 1.6.3
++ * \brief Initialize the given connected line structure.
++ *
++ * \param init Connected line structure to initialize.
++ *
++ * \return Nothing
++ */
++void ast_party_connected_line_init(struct ast_party_connected_line *init);
++
++/*!
++ * \since 1.6.3
++ * \brief Copy the source connected line information to the destination connected line.
++ *
++ * \param dest Destination connected line
++ * \param src Source connected line
++ *
++ * \return Nothing
++ */
++void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src);
++
++/*!
++ * \since 1.6.3
++ * \brief Initialize the given connected line structure using the given
++ * guide for a set update operation.
++ *
++ * \details
++ * The initialization is needed to allow a set operation to know if a
++ * value needs to be updated. Simple integers need the guide's original
++ * value in case the set operation is not trying to set a new value.
++ * String values are simply set to NULL pointers if they are not going
++ * to be updated.
++ *
++ * \param init Connected line structure to initialize.
++ * \param guide Source connected line to use as a guide in initializing.
++ *
++ * \return Nothing
++ */
++void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide);
++
++/*!
++ * \since 1.6.3
++ * \brief Set the connected line information based on another connected line source
++ *
++ * This is similar to ast_party_connected_line_copy, except that NULL values for
++ * strings in the src parameter indicate not to update the corresponding dest values.
++ *
++ * \param src The source connected line to use as a guide to set the dest
++ * \param dest The connected line one wishes to update
++ *
++ * \return Nada
++ */
++void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src);
++
++/*!
++ * \since 1.6.3
++ * \brief Collect the caller party information into a connected line structure.
++ *
++ * \param connected Collected caller information for the connected line
++ * \param cid Caller information.
++ *
++ * \return Nothing
++ *
++ * \warning This is a shallow copy.
++ * \warning DO NOT call ast_party_connected_line_free() on the filled in
++ * connected line structure!
++ */
++void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid);
++
++/*!
++ * \since 1.6.3
++ * \brief Destroy the connected line information contents
++ *
++ * \param doomed The connected line information to destroy.
++ *
++ * \return Nothing
++ */
++void ast_party_connected_line_free(struct ast_party_connected_line *doomed);
++
++/*!
++ * \since 1.6.3
++ * \brief Copy the source redirecting information to the destination redirecting.
++ *
++ * \param dest Destination redirecting
++ * \param src Source redirecting
++ *
++ * \return Nothing
++ */
++void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src);
++
++/*!
++ * \since 1.6.3
++ * \brief Initialize the given redirecting id structure using the given guide
++ * for a set update operation.
++ *
++ * \details
++ * The initialization is needed to allow a set operation to know if a
++ * value needs to be updated. Simple integers need the guide's original
++ * value in case the set operation is not trying to set a new value.
++ * String values are simply set to NULL pointers if they are not going
++ * to be updated.
++ *
++ * \param init Redirecting id structure to initialize.
++ * \param guide Source redirecting id to use as a guide in initializing.
++ *
++ * \return Nothing
++ */
++void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide);
++
++/*!
++ * \since 1.6.3
++ * \brief Destroy the redirecting information contents
++ *
++ * \param doomed The redirecting information to destroy.
++ *
++ * \return Nothing
++ */
++void ast_party_redirecting_free(struct ast_party_redirecting *doomed);
++
++/*!
++ * \since 1.6.3
++ * \brief Copy the caller information to the connected line information.
++ *
++ * \param dest Destination connected line information
++ * \param src Source caller information
++ *
++ * \return Nothing
++ *
++ * \note Assumes locks are already acquired
++ */
++void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_callerid *src);
++
++/*!
++ * \since 1.6.3
++ * \brief Copy the connected line information to the caller information.
++ *
++ * \param dest Destination caller information
++ * \param src Source connected line information
++ *
++ * \return Nothing
++ *
++ * \note Assumes locks are already acquired
++ */
++void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src);
++
++/*!
++ * \since 1.6.3
++ * \brief Set the connected line information in the Asterisk channel
++ *
++ * \param chan Asterisk channel to set connected line information
++ * \param connected Connected line information
++ *
++ * \return Nothing
++ *
++ * \note The channel does not need to be locked before calling this function.
++ */
++void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected);
++
++/*!
++ * \since 1.6.3
++ * \brief Build the connected line information data frame.
++ *
++ * \param data Buffer to fill with the frame data
++ * \param datalen Size of the buffer to fill
++ * \param connected Connected line information
++ *
++ * \retval -1 if error
++ * \retval Amount of data buffer used
++ */
++int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected);
++
++/*!
++ * \since 1.6.3
++ * \brief Parse connected line indication frame data
++ *
++ * \param data Buffer with the frame data to parse
++ * \param datalen Size of the buffer
++ * \param connected Extracted connected line information
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ *
++ * \note The filled in connected line structure needs to be initialized by
++ * ast_party_connected_line_set_init() before calling. If defaults are not
++ * required use ast_party_connected_line_init().
++ * \note The filled in connected line structure needs to be destroyed by
++ * ast_party_connected_line_free() when it is no longer needed.
++ */
++int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected);
++
++/*!
++ * \since 1.6.3
++ * \brief Indicate that the connected line information has changed
++ *
++ * \param chan Asterisk channel to indicate connected line information
++ * \param connected Connected line information
++ *
++ * \return Nothing
++ */
++void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected);
++
++/*!
++ * \since 1.6.3
++ * \brief Queue a connected line update frame on a channel
++ *
++ * \param chan Asterisk channel to indicate connected line information
++ * \param connected Connected line information
++ *
++ * \return Nothing
++ */
++void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected);
++
++/*!
++ * \since 1.6.3
++ * \brief Set the redirecting id information in the Asterisk channel
++ *
++ * \param chan Asterisk channel to set redirecting id information
++ * \param redirecting Redirecting id information
++ *
++ * \return Nothing
++ *
++ * \note The channel does not need to be locked before calling this function.
++ */
++void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
++
++/*!
++ * \since 1.6.3
++ * \brief Build the redirecting id data frame.
++ *
++ * \param data Buffer to fill with the frame data
++ * \param datalen Size of the buffer to fill
++ * \param redirecting Redirecting id information
++ *
++ * \retval -1 if error
++ * \retval Amount of data buffer used
++ */
++int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting);
++
++/*!
++ * \since 1.6.3
++ * \brief Parse redirecting indication frame data
++ *
++ * \param data Buffer with the frame data to parse
++ * \param datalen Size of the buffer
++ * \param redirecting Extracted redirecting id information
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ *
++ * \note The filled in id structure needs to be initialized by
++ * ast_party_redirecting_set_init() before calling.
++ * \note The filled in id structure needs to be destroyed by
++ * ast_party_redirecting_free() when it is no longer needed.
++ */
++int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting);
++
++/*!
++ * \since 1.6.3
++ * \brief Indicate that the redirecting id has changed
++ *
++ * \param chan Asterisk channel to indicate redirecting id information
++ * \param redirecting Redirecting id information
++ *
++ * \return Nothing
++ */
++void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
++
++/*!
++ * \since 1.6.3
++ * \brief Queue a redirecting update frame on a channel
++ *
++ * \param chan Asterisk channel to indicate redirecting id information
++ * \param redirecting Redirecting id information
++ *
++ * \return Nothing
++ */
++void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting);
++
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+ #endif
+Index: include/asterisk/_private.h
+===================================================================
+--- a/include/asterisk/_private.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/_private.h (.../trunk) (revision 186562)
+@@ -29,7 +29,7 @@
+ void dnsmgr_start_refresh(void); /*!< Provided by dnsmgr.c */
+ int dnsmgr_reload(void); /*!< Provided by dnsmgr.c */
+ void threadstorage_init(void); /*!< Provided by threadstorage.c */
+-void ast_event_init(void); /*!< Provided by event.c */
++int ast_event_init(void); /*!< Provided by event.c */
+ int ast_device_state_engine_init(void); /*!< Provided by devicestate.c */
+ int astobj2_init(void); /*!< Provided by astobj2.c */
+ int ast_file_init(void); /*!< Provided by file.c */
+@@ -41,6 +41,7 @@
+ int ast_timing_init(void); /*!< Provided by timing.c */
+ int ast_indications_init(void); /*!< Provided by indications.c */
+ int ast_indications_reload(void);/*!< Provided by indications.c */
++void ast_stun_init(void); /*!< Provided by stun.c */
+
+ /*!
+ * \brief Reload asterisk modules.
+Index: include/asterisk/features.h
+===================================================================
+--- a/include/asterisk/features.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/features.h (.../trunk) (revision 186562)
+@@ -36,6 +36,21 @@
+
+ #define PARK_APP_NAME "Park"
+
++#define AST_FEATURE_RETURN_HANGUP -1
++#define AST_FEATURE_RETURN_SUCCESSBREAK 0
++#define AST_FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
++#define AST_FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
++#define AST_FEATURE_RETURN_PASSDIGITS 21
++#define AST_FEATURE_RETURN_STOREDIGITS 22
++#define AST_FEATURE_RETURN_SUCCESS 23
++#define AST_FEATURE_RETURN_KEEPTRYING 24
++#define AST_FEATURE_RETURN_PARKFAILED 25
++
++#define FEATURE_SENSE_CHAN (1 << 0)
++#define FEATURE_SENSE_PEER (1 << 1)
++
++typedef int (*ast_feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data);
++
+ /*! \brief main call feature structure */
+
+ enum {
+@@ -53,7 +68,7 @@
+ char sname[FEATURE_SNAME_LEN];
+ char exten[FEATURE_MAX_LEN];
+ char default_exten[FEATURE_MAX_LEN];
+- int (*operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data);
++ ast_feature_operation operation;
+ unsigned int flags;
+ char app[FEATURE_APP_LEN];
+ char app_args[FEATURE_APP_ARGS_LEN];
+@@ -61,14 +76,6 @@
+ AST_LIST_ENTRY(ast_call_feature) feature_entry;
+ };
+
+-#define AST_FEATURE_RETURN_HANGUP -1
+-#define AST_FEATURE_RETURN_SUCCESSBREAK 0
+-#define AST_FEATURE_RETURN_PASSDIGITS 21
+-#define AST_FEATURE_RETURN_STOREDIGITS 22
+-#define AST_FEATURE_RETURN_SUCCESS 23
+-#define AST_FEATURE_RETURN_KEEPTRYING 24
+-#define AST_FEATURE_RETURN_PARKFAILED 25
+-
+ /*!
+ * \brief Park a call and read back parked location
+ * \param chan the channel to actually be parked
+@@ -123,6 +130,14 @@
+ \param feature the ast_call_feature object which was registered before*/
+ void ast_unregister_feature(struct ast_call_feature *feature);
+
++/*! \brief detect a feature before bridging
++ \param chan
++ \param ast_flags ptr
++ \param char ptr of input code
++ \retval ast_call_feature ptr to be set if found
++ \return result, was feature found or not */
++int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature);
++
+ /*! \brief look for a call feature entry by its sname
+ \param name a string ptr, should match "automon", "blindxfer", "atxfer", etc. */
+ struct ast_call_feature *ast_find_call_feature(const char *name);
+Index: include/asterisk/app.h
+===================================================================
+--- a/include/asterisk/app.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/app.h (.../trunk) (revision 186562)
+@@ -32,7 +32,7 @@
+ extern "C" {
+ #endif
+
+-AST_THREADSTORAGE_EXTERNAL(global_app_buf);
++AST_THREADSTORAGE_EXTERNAL(ast_str_thread_global_buf);
+
+ /* IVR stuff */
+
+Index: include/asterisk/res_odbc.h
+===================================================================
+--- a/include/asterisk/res_odbc.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/res_odbc.h (.../trunk) (revision 186562)
+@@ -35,7 +35,7 @@
+
+ typedef enum { ODBC_SUCCESS=0, ODBC_FAIL=-1} odbc_status;
+
+-/*! \brief Flags for use with ast_odbc_request_obj2 */
++/*! \brief Flags for use with \see ast_odbc_request_obj2 */
+ enum {
+ RES_ODBC_SANITY_CHECK = (1 << 0),
+ RES_ODBC_INDEPENDENT_CONNECTION = (1 << 1),
+@@ -102,7 +102,7 @@
+ /*!
+ * \brief Retrieves a connected ODBC object
+ * \param name The name of the ODBC class for which a connection is needed.
+- * \param check Whether to ensure that a connection is valid before returning the handle. Usually unnecessary.
++ * \param flags Set of flags used to control which connection is returned.
+ * \retval ODBC object
+ * \retval NULL if there is no connection available with the requested name.
+ *
+@@ -129,7 +129,7 @@
+ * \brief Retrieve a stored ODBC object, if a transaction has been started.
+ * \param chan Channel associated with the transaction.
+ * \param objname Name of the database handle. This name corresponds to the name passed
+- * to ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the
++ * to \see ast_odbc_request_obj2 (or formerly, to ast_odbc_request_obj). Note that the
+ * existence of this parameter name explicitly allows for multiple transactions to be open
+ * at once, albeit to different databases.
+ * \retval A stored ODBC object, if a transaction was already started.
+@@ -180,7 +180,7 @@
+ /*!
+ * \brief Find or create an entry describing the table specified.
+ * \param database Name of an ODBC class on which to query the table
+- * \param table Tablename to describe
++ * \param tablename Tablename to describe
+ * \retval A structure describing the table layout, or NULL, if the table is not found or another error occurs.
+ * When a structure is returned, the contained columns list will be
+ * rdlock'ed, to ensure that it will be retained in memory.
+@@ -200,7 +200,7 @@
+ /*!
+ * \brief Remove a cache entry from memory
+ * \param database Name of an ODBC class (used to ensure like-named tables in different databases are not confused)
+- * \param table Tablename for which a cached record should be removed
++ * \param tablename Tablename for which a cached record should be removed
+ * \retval 0 if the cache entry was removed, or -1 if no matching entry was found.
+ * \since 1.6.1
+ */
+@@ -213,7 +213,7 @@
+
+ /*!\brief Wrapper for SQLGetData to use with dynamic strings
+ * \param buf Address of the pointer to the ast_str structure.
+- * \param maxlen The maximum size of the resulting string, or 0 for no limit.
++ * \param pmaxlen The maximum size of the resulting string, or 0 for no limit.
+ * \param StatementHandle The statement handle from which to retrieve data.
+ * \param ColumnNumber Column number (1-based offset) for which to retrieve data.
+ * \param TargetType The SQL constant indicating what kind of data is to be retrieved (usually SQL_CHAR)
+Index: include/asterisk/event.h
+===================================================================
+--- a/include/asterisk/event.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/event.h (.../trunk) (revision 186562)
+@@ -358,42 +358,18 @@
+ *
+ * \param event the event to be queued and cached
+ *
+- * The rest of the arguments to this function specify information elements to
+- * use for determining which events in the cache that this event should replace.
+- * All events in the cache that match the specified criteria will be removed from
+- * the cache and then this one will be added. The arguments are specified in
+- * the form:
+- *
+- * \code
+- * <enum ast_event_ie_type>, [enum ast_event_ie_pltype]
+- * \endcode
+- * and must end with AST_EVENT_IE_END.
+- *
+- * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+- * by a valid IE payload type. If the payload type given is EXISTS, then all
+- * events that contain that information element will be removed from the cache.
+- * Otherwise, all events in the cache that contain an information element with
+- * the same value as the new event will be removed.
+- *
+- * \note If more than one IE parameter is specified, they *all* must match for
+- * the event to be removed from the cache.
+- *
+- * Example usage:
+- *
+- * \code
+- * ast_event_queue_and_cache(event,
+- * AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR,
+- * AST_EVENT_IE_END);
+- * \endcode
+- *
+- * This example queues and caches an event. Any events in the cache that have
+- * the same MAILBOX information element as this event will be removed.
+- *
++ * \details
+ * The purpose of caching events is so that the core can retain the last known
+ * information for events that represent some sort of state. That way, when
+ * code needs to find out the current state, it can query the cache.
++ *
++ * The event API already knows which events can be cached and how to cache them.
++ *
++ * \retval 0 success
++ * \retval non-zero failure. If failure is returned, the event must be destroyed
++ * by the caller of this function.
+ */
+-int ast_event_queue_and_cache(struct ast_event *event, ...);
++int ast_event_queue_and_cache(struct ast_event *event);
+
+ /*!
+ * \brief Retrieve an event from the cache
+@@ -511,6 +487,18 @@
+ const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+ /*!
++ * \brief Get the hash for the string payload of an IE
++ *
++ * \param event The event to get the IE from
++ * \param ie_type the type of information element to retrieve the hash for
++ *
++ * \return This function returns the hash value as calculated by ast_str_hash()
++ * for the string payload. This is stored in the event to avoid
++ * unnecessary string comparisons.
++ */
++uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type);
++
++/*!
+ * \brief Get the value of an information element that has a raw payload
+ *
+ * \param event The event to get the IE from
+Index: include/asterisk/compat.h
+===================================================================
+--- a/include/asterisk/compat.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/compat.h (.../trunk) (revision 186562)
+@@ -67,7 +67,7 @@
+ #include <string.h>
+ #endif
+
+-#ifdef HAVE_SYS_POLL_H
++#ifndef AST_POLL_COMPAT
+ #include <sys/poll.h>
+ #else
+ #include "asterisk/poll-compat.h"
+Index: include/asterisk/timing.h
+===================================================================
+--- a/include/asterisk/timing.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/timing.h (.../trunk) (revision 186562)
+@@ -45,9 +45,6 @@
+ 4) Multiple 'event types', so that the code using the timer can
+ know whether the wakeup it received was due to a periodic trigger
+ or a continuous trigger.
+-
+- \todo Create an implementation of this API for Linux based on the
+- following API: http://www.kernel.org/doc/man-pages/online/pages/man2/timerfd_create.2.html
+ */
+
+ #ifndef _ASTERISK_TIMING_H
+@@ -96,7 +93,7 @@
+ */
+ #define ast_register_timing_interface(i) _ast_register_timing_interface(i, ast_module_info->self)
+ void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
+- struct ast_module *mod);
++ struct ast_module *mod);
+
+ /*!
+ * \brief Unregister a previously registered timing interface.
+@@ -110,45 +107,57 @@
+ */
+ int ast_unregister_timing_interface(void *handle);
+
++struct ast_timer;
++
+ /*!
+- * \brief Open a timing fd
++ * \brief Open a timer
+ *
+- * \retval -1 error, with errno set
+- * \retval >=0 success
++ * \retval NULL on error, with errno set
++ * \retval non-NULL timer handle on success
+ * \since 1.6.1
+ */
+-int ast_timer_open(void);
++struct ast_timer *ast_timer_open(void);
+
+ /*!
+ * \brief Close an opened timing handle
+ *
+- * \param handle timing fd returned from timer_open()
++ * \param handle timer handle returned from timer_open()
+ *
+ * \return nothing
+ * \since 1.6.1
+ */
+-void ast_timer_close(int handle);
++void ast_timer_close(struct ast_timer *handle);
+
+ /*!
++ * \brief Get a poll()-able file descriptor for a timer
++ *
++ * \param handle timer handle returned from timer_open()
++ *
++ * \return file descriptor which can be used with poll() to wait for events
++ * \since 1.6.1
++ */
++int ast_timer_fd(const struct ast_timer *handle);
++
++/*!
+ * \brief Set the timing tick rate
+ *
+- * \param handle timing fd returned from timer_open()
++ * \param handle timer handle returned from timer_open()
+ * \param rate ticks per second, 0 turns the ticks off if needed
+ *
+- * Use this function if you want the timing fd to show input at a certain
+- * rate. The other alternative use of a timing fd, is using the continuous
++ * Use this function if you want the timer to show input at a certain
++ * rate. The other alternative use of a timer is the continuous
+ * mode.
+ *
+ * \retval -1 error, with errno set
+ * \retval 0 success
+ * \since 1.6.1
+ */
+-int ast_timer_set_rate(int handle, unsigned int rate);
++int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate);
+
+ /*!
+ * \brief Acknowledge a timer event
+ *
+- * \param handle timing fd returned from timer_open()
++ * \param handle timer handle returned from timer_open()
+ * \param quantity number of timer events to acknowledge
+ *
+ * \note This function should only be called if timer_get_event()
+@@ -157,55 +166,55 @@
+ * \return nothing
+ * \since 1.6.1
+ */
+-void ast_timer_ack(int handle, unsigned int quantity);
++void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity);
+
+ /*!
+ * \brief Enable continuous mode
+ *
+- * \param handle timing fd returned from timer_open()
++ * \param handle timer handle returned from timer_open()
+ *
+- * Continuous mode causes poll() on the timing fd to immediately return
++ * Continuous mode causes poll() on the timer's fd to immediately return
+ * always until continuous mode is disabled.
+ *
+ * \retval -1 failure, with errno set
+ * \retval 0 success
+ * \since 1.6.1
+ */
+-int ast_timer_enable_continuous(int handle);
++int ast_timer_enable_continuous(const struct ast_timer *handle);
+
+ /*!
+ * \brief Disable continuous mode
+ *
+- * \param handle timing fd returned from timer_close()
++ * \param handle timer handle returned from timer_close()
+ *
+ * \retval -1 failure, with errno set
+ * \retval 0 success
+ * \since 1.6.1
+ */
+-int ast_timer_disable_continuous(int handle);
++int ast_timer_disable_continuous(const struct ast_timer *handle);
+
+ /*!
+- * \brief Determine timing event
++ * \brief Retrieve timing event
+ *
+- * \param handle timing fd returned by timer_open()
++ * \param handle timer handle returned by timer_open()
+ *
+- * After poll() indicates that there is input on the timing fd, this will
++ * After poll() indicates that there is input on the timer's fd, this will
+ * be called to find out what triggered it.
+ *
+- * \return which event triggered the timing fd
++ * \return which event triggered the timer
+ * \since 1.6.1
+ */
+-enum ast_timer_event ast_timer_get_event(int handle);
++enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle);
+
+ /*!
+- * \brief Get maximum rate supported for a timing handle
++ * \brief Get maximum rate supported for a timer
+ *
+- * \param handle timing fd returned by timer_open()
++ * \param handle timer handle returned by timer_open()
+ *
+- * \return maximum rate supported for timing handle
++ * \return maximum rate supported by timer
+ * \since 1.6.1
+ */
+-unsigned int ast_timer_get_max_rate(int handle);
++unsigned int ast_timer_get_max_rate(const struct ast_timer *handle);
+
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+Index: include/asterisk/frame.h
+===================================================================
+--- a/include/asterisk/frame.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/frame.h (.../trunk) (revision 186562)
+@@ -39,54 +39,56 @@
+ char framing[32];
+ };
+
+-/*! \page Def_Frame AST Multimedia and signalling frames
+- \section Def_AstFrame What is an ast_frame ?
+- A frame of data read used to communicate between
+- between channels and applications.
+- Frames are divided into frame types and subclasses.
++/*!
++ * \page Def_Frame AST Multimedia and signalling frames
++ * \section Def_AstFrame What is an ast_frame ?
++ * A frame of data read used to communicate between
++ * between channels and applications.
++ * Frames are divided into frame types and subclasses.
++ *
++ * \par Frame types
++ * \arg \b VOICE: Voice data, subclass is codec (AST_FORMAT_*)
++ * \arg \b VIDEO: Video data, subclass is codec (AST_FORMAT_*)
++ * \arg \b DTMF: A DTMF digit, subclass is the digit
++ * \arg \b IMAGE: Image transport, mostly used in IAX
++ * \arg \b TEXT: Text messages and character by character (real time text)
++ * \arg \b HTML: URL's and web pages
++ * \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
++ * \arg \b IAX: Private frame type for the IAX protocol
++ * \arg \b CNG: Comfort noice frames
++ * \arg \b CONTROL:A control frame, subclass defined as AST_CONTROL_
++ * \arg \b NULL: Empty, useless frame
++ *
++ * \par Files
++ * \arg frame.h Definitions
++ * \arg frame.c Function library
++ * \arg \ref Def_Channel Asterisk channels
++ * \section Def_ControlFrame Control Frames
++ * Control frames send signalling information between channels
++ * and devices. They are prefixed with AST_CONTROL_, like AST_CONTROL_FRAME_HANGUP
++ * \arg \b HANGUP The other end has hungup
++ * \arg \b RING Local ring
++ * \arg \b RINGING The other end is ringing
++ * \arg \b ANSWER The other end has answered
++ * \arg \b BUSY Remote end is busy
++ * \arg \b TAKEOFFHOOK Make it go off hook (what's "it" ? )
++ * \arg \b OFFHOOK Line is off hook
++ * \arg \b CONGESTION Congestion (circuit is busy, not available)
++ * \arg \b FLASH Other end sends flash hook
++ * \arg \b WINK Other end sends wink
++ * \arg \b OPTION Send low-level option
++ * \arg \b RADIO_KEY Key radio (see app_rpt.c)
++ * \arg \b RADIO_UNKEY Un-key radio (see app_rpt.c)
++ * \arg \b PROGRESS Other end indicates call progress
++ * \arg \b PROCEEDING Indicates proceeding
++ * \arg \b HOLD Call is placed on hold
++ * \arg \b UNHOLD Call is back from hold
++ * \arg \b VIDUPDATE Video update requested
++ * \arg \b SRCUPDATE The source of media has changed
++ * \arg \b CONNECTED_LINE Connected line has changed
++ * \arg \b REDIRECTING Call redirecting information has changed.
++ */
+
+- \par Frame types
+- \arg \b VOICE: Voice data, subclass is codec (AST_FORMAT_*)
+- \arg \b VIDEO: Video data, subclass is codec (AST_FORMAT_*)
+- \arg \b DTMF: A DTMF digit, subclass is the digit
+- \arg \b IMAGE: Image transport, mostly used in IAX
+- \arg \b TEXT: Text messages and character by character (real time text)
+- \arg \b HTML: URL's and web pages
+- \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
+- \arg \b IAX: Private frame type for the IAX protocol
+- \arg \b CNG: Comfort noice frames
+- \arg \b CONTROL: A control frame, subclass defined as AST_CONTROL_
+- \arg \b NULL: Empty, useless frame
+-
+- \par Files
+- \arg frame.h Definitions
+- \arg frame.c Function library
+- \arg \ref Def_Channel Asterisk channels
+- \section Def_ControlFrame Control Frames
+- Control frames send signalling information between channels
+- and devices. They are prefixed with AST_CONTROL_, like AST_CONTROL_FRAME_HANGUP
+- \arg \b HANGUP The other end has hungup
+- \arg \b RING Local ring
+- \arg \b RINGING The other end is ringing
+- \arg \b ANSWER The other end has answered
+- \arg \b BUSY Remote end is busy
+- \arg \b TAKEOFFHOOK Make it go off hook (what's "it" ? )
+- \arg \b OFFHOOK Line is off hook
+- \arg \b CONGESTION Congestion (circuit is busy, not available)
+- \arg \b FLASH Other end sends flash hook
+- \arg \b WINK Other end sends wink
+- \arg \b OPTION Send low-level option
+- \arg \b RADIO_KEY Key radio (see app_rpt.c)
+- \arg \b RADIO_UNKEY Un-key radio (see app_rpt.c)
+- \arg \b PROGRESS Other end indicates call progress
+- \arg \b PROCEEDING Indicates proceeding
+- \arg \b HOLD Call is placed on hold
+- \arg \b UNHOLD Call is back from hold
+- \arg \b VIDUPDATE Video update requested
+- \arg \b SRCUPDATE The source of media has changed
+-
+-*/
+-
+ /*!
+ * \brief Frame types
+ *
+@@ -319,6 +321,9 @@
+ AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */
+ AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */
+ AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */
++ AST_CONTROL_TRANSFER = 21, /*!< Indicate status of a transfer request */
++ AST_CONTROL_CONNECTED_LINE = 22, /*!< Indicate connected line has changed */
++ AST_CONTROL_REDIRECTING = 23 /*!< Indicate redirecting id has changed */
+ };
+
+ enum ast_control_t38 {
+@@ -329,6 +334,11 @@
+ AST_T38_REFUSED /*!< T38 refused for some reason (usually rejected by remote end) */
+ };
+
++enum ast_control_transfer {
++ AST_TRANSFER_SUCCESS = 0, /*!< Transfer request on the channel worked */
++ AST_TRANSFER_FAILED, /*!< Transfer request on the channel failed */
++};
++
+ #define AST_SMOOTHER_FLAG_G729 (1 << 0)
+ #define AST_SMOOTHER_FLAG_BE (1 << 1)
+
+Index: include/asterisk/devicestate.h
+===================================================================
+--- a/include/asterisk/devicestate.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/devicestate.h (.../trunk) (revision 186562)
+@@ -37,6 +37,8 @@
+ #ifndef _ASTERISK_DEVICESTATE_H
+ #define _ASTERISK_DEVICESTATE_H
+
++#include "asterisk/channel.h"
++
+ #if defined(__cplusplus) || defined(c_plusplus)
+ extern "C" {
+ #endif
+@@ -260,6 +262,21 @@
+ unsigned int ring:1;
+ };
+
++/*!
++ * \brief Enable distributed device state processing.
++ *
++ * \details
++ * By default, Asterisk assumes that device state change events will only be
++ * originating from one instance. If a module gets loaded and configured such
++ * that multiple instances of Asterisk will be sharing device state, this
++ * function should be called to enable distributed device state processing.
++ * It is off by default to save on unnecessary processing.
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ */
++int ast_enable_distributed_devstate(void);
++
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+ #endif
+Index: include/asterisk/astobj2.h
+===================================================================
+--- a/include/asterisk/astobj2.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/astobj2.h (.../trunk) (revision 186562)
+@@ -388,6 +388,7 @@
+ *
+ * \param data_size The sizeof() of the user-defined structure.
+ * \param destructor_fn The destructor function (can be NULL)
++ * \param debug_msg
+ * \return A pointer to user-data.
+ *
+ * Allocates a struct astobj2 with sufficient space for the
+@@ -397,24 +398,26 @@
+ * - the refcount of the object just created is 1
+ * - the returned pointer cannot be free()'d or realloc()'ed;
+ * rather, we just call ao2_ref(o, -1);
++ *
++ * @{
+ */
+
+ #ifdef REF_DEBUG
+
+
+-#define ao2_t_alloc(arg1, arg2, arg3) _ao2_alloc_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_alloc(arg1, arg2) _ao2_alloc_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_alloc(data_size, destructor_fn) __ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+ #else
+
+-#define ao2_t_alloc(arg1,arg2,arg3) _ao2_alloc((arg1), (arg2))
+-#define ao2_alloc(arg1,arg2) _ao2_alloc((arg1), (arg2))
++#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc((data_size), (destructor_fn))
++#define ao2_alloc(data_size, destructor_fn) __ao2_alloc((data_size), (destructor_fn))
+
+ #endif
+-void *_ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname);
+-void *_ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
++void *__ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname);
++void *__ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
++/*! @} */
+
+-
+ /*! \brief
+ * Reference/unreference an object and return the old refcount.
+ *
+@@ -434,17 +437,20 @@
+ * have a reference count to it, so the only case when the object
+ * can go away is when we release our reference, and it is
+ * the last one in existence.
++ *
++ * @{
+ */
+
+ #ifdef REF_DEBUG
+-#define ao2_t_ref(arg1,arg2,arg3) _ao2_ref_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_ref(arg1,arg2) _ao2_ref_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_ref(o,delta,tag) __ao2_ref_debug((o), (delta), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_ref(o,delta) __ao2_ref_debug((o), (delta), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_ref(arg1,arg2,arg3) _ao2_ref((arg1), (arg2))
+-#define ao2_ref(arg1,arg2) _ao2_ref((arg1), (arg2))
++#define ao2_t_ref(o,delta,tag) __ao2_ref((o), (delta))
++#define ao2_ref(o,delta) __ao2_ref((o), (delta))
+ #endif
+-int _ao2_ref_debug(void *o, int delta, char *tag, char *file, int line, const char *funcname);
+-int _ao2_ref(void *o, int delta);
++int __ao2_ref_debug(void *o, int delta, char *tag, char *file, int line, const char *funcname);
++int __ao2_ref(void *o, int delta);
++/*! @} */
+
+ /*! \brief
+ * Lock an object.
+@@ -455,8 +461,8 @@
+ #ifndef DEBUG_THREADS
+ int ao2_lock(void *a);
+ #else
+-#define ao2_lock(a) _ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+-int _ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
++#define ao2_lock(a) __ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
++int __ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
+ #endif
+
+ /*! \brief
+@@ -468,8 +474,8 @@
+ #ifndef DEBUG_THREADS
+ int ao2_unlock(void *a);
+ #else
+-#define ao2_unlock(a) _ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+-int _ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
++#define ao2_unlock(a) __ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
++int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
+ #endif
+
+ /*! \brief
+@@ -481,8 +487,8 @@
+ #ifndef DEBUG_THREADS
+ int ao2_trylock(void *a);
+ #else
+-#define ao2_trylock(a) _ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+-int _ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
++#define ao2_trylock(a) __ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
++int __ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
+ #endif
+
+ /*!
+@@ -686,15 +692,15 @@
+ */
+
+ #ifdef REF_DEBUG
+-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_container_alloc(arg1,arg2,arg3) _ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc((arg1), (arg2), (arg3))
+-#define ao2_container_alloc(arg1,arg2,arg3) _ao2_container_alloc((arg1), (arg2), (arg3))
++#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc((arg1), (arg2), (arg3))
++#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc((arg1), (arg2), (arg3))
+ #endif
+-struct ao2_container *_ao2_container_alloc(const unsigned int n_buckets,
++struct ao2_container *__ao2_container_alloc(const unsigned int n_buckets,
+ ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
+-struct ao2_container *_ao2_container_alloc_debug(const unsigned int n_buckets,
++struct ao2_container *__ao2_container_alloc_debug(const unsigned int n_buckets,
+ ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
+ char *tag, char *file, int line, const char *funcname);
+
+@@ -730,14 +736,14 @@
+ */
+ #ifdef REF_DEBUG
+
+-#define ao2_t_link(arg1, arg2, arg3) _ao2_link_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_link(arg1, arg2) _ao2_link_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_link(arg1, arg2, arg3) __ao2_link_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_link(arg1, arg2) __ao2_link_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_link(arg1, arg2, arg3) _ao2_link((arg1), (arg2))
+-#define ao2_link(arg1, arg2) _ao2_link((arg1), (arg2))
++#define ao2_t_link(arg1, arg2, arg3) __ao2_link((arg1), (arg2))
++#define ao2_link(arg1, arg2) __ao2_link((arg1), (arg2))
+ #endif
+-void *_ao2_link_debug(struct ao2_container *c, void *new_obj, char *tag, char *file, int line, const char *funcname);
+-void *_ao2_link(struct ao2_container *c, void *newobj);
++void *__ao2_link_debug(struct ao2_container *c, void *new_obj, char *tag, char *file, int line, const char *funcname);
++void *__ao2_link(struct ao2_container *c, void *newobj);
+
+ /*!
+ * \brief Remove an object from the container
+@@ -756,14 +762,14 @@
+ * refcount will be decremented).
+ */
+ #ifdef REF_DEBUG
+-#define ao2_t_unlink(arg1, arg2, arg3) _ao2_unlink_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_unlink(arg1, arg2) _ao2_unlink_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_unlink(arg1, arg2, arg3) __ao2_unlink_debug((arg1), (arg2), (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_unlink(arg1, arg2) __ao2_unlink_debug((arg1), (arg2), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_unlink(arg1, arg2, arg3) _ao2_unlink((arg1), (arg2))
+-#define ao2_unlink(arg1, arg2) _ao2_unlink((arg1), (arg2))
++#define ao2_t_unlink(arg1, arg2, arg3) __ao2_unlink((arg1), (arg2))
++#define ao2_unlink(arg1, arg2) __ao2_unlink((arg1), (arg2))
+ #endif
+-void *_ao2_unlink_debug(struct ao2_container *c, void *obj, char *tag, char *file, int line, const char *funcname);
+-void *_ao2_unlink(struct ao2_container *c, void *obj);
++void *__ao2_unlink_debug(struct ao2_container *c, void *obj, char *tag, char *file, int line, const char *funcname);
++void *__ao2_unlink(struct ao2_container *c, void *obj);
+
+
+ /*! \brief Used as return value if the flag OBJ_MULTIPLE is set */
+@@ -849,20 +855,23 @@
+ *
+ * \note When the returned object is no longer in use, ao2_ref() should
+ * be used to free the additional reference possibly created by this function.
++ *
++ * @{
+ */
+ #ifdef REF_DEBUG
+-#define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), (arg5), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback_debug((arg1), (arg2), (arg3), (arg4), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_callback(c,flags,cb_fn,arg,tag) __ao2_callback_debug((c), (flags), (cb_fn), (arg), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_callback(c,flags,cb_fn,arg) __ao2_callback_debug((c), (flags), (cb_fn), (arg), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_callback(arg1,arg2,arg3,arg4,arg5) _ao2_callback((arg1), (arg2), (arg3), (arg4))
+-#define ao2_callback(arg1,arg2,arg3,arg4) _ao2_callback((arg1), (arg2), (arg3), (arg4))
++#define ao2_t_callback(c,flags,cb_fn,arg,tag) __ao2_callback((c), (flags), (cb_fn), (arg))
++#define ao2_callback(c,flags,cb_fn,arg) __ao2_callback((c), (flags), (cb_fn), (arg))
+ #endif
+-void *_ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
++void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
+ ao2_callback_fn *cb_fn, void *arg, char *tag,
+ char *file, int line, const char *funcname);
+-void *_ao2_callback(struct ao2_container *c,
++void *__ao2_callback(struct ao2_container *c,
+ enum search_flags flags,
+ ao2_callback_fn *cb_fn, void *arg);
++/*! @} */
+
+ /*! \brief
+ * ao2_callback_data() is a generic function that applies cb_fn() to all objects
+@@ -880,16 +889,16 @@
+ * \see ao2_callback()
+ */
+ #ifdef REF_DEBUG
+-#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) _ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), (arg6), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) _ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) __ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), (arg6), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) __ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) _ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
+-#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) _ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
++#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) __ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
++#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) __ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
+ #endif
+-void *_ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
++void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
+ ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag,
+ char *file, int line, const char *funcname);
+-void *_ao2_callback_data(struct ao2_container *c,
++void *__ao2_callback_data(struct ao2_container *c,
+ enum search_flags flags,
+ ao2_callback_data_fn *cb_fn, void *arg, void *data);
+
+@@ -897,14 +906,14 @@
+ * XXX possibly change order of arguments ?
+ */
+ #ifdef REF_DEBUG
+-#define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_find(arg1,arg2,arg3) _ao2_find_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_find(arg1,arg2,arg3,arg4) __ao2_find_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_find(arg1,arg2,arg3) __ao2_find_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_find(arg1,arg2,arg3,arg4) _ao2_find((arg1), (arg2), (arg3))
+-#define ao2_find(arg1,arg2,arg3) _ao2_find((arg1), (arg2), (arg3))
++#define ao2_t_find(arg1,arg2,arg3,arg4) __ao2_find((arg1), (arg2), (arg3))
++#define ao2_find(arg1,arg2,arg3) __ao2_find((arg1), (arg2), (arg3))
+ #endif
+-void *_ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname);
+-void *_ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
++void *__ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname);
++void *__ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
+
+ /*! \brief
+ *
+@@ -1003,14 +1012,14 @@
+
+ struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags);
+ #ifdef REF_DEBUG
+-#define ao2_t_iterator_next(arg1, arg2) _ao2_iterator_next_debug((arg1), (arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-#define ao2_iterator_next(arg1) _ao2_iterator_next_debug((arg1), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_t_iterator_next(arg1, arg2) __ao2_iterator_next_debug((arg1), (arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
++#define ao2_iterator_next(arg1) __ao2_iterator_next_debug((arg1), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #else
+-#define ao2_t_iterator_next(arg1, arg2) _ao2_iterator_next((arg1))
+-#define ao2_iterator_next(arg1) _ao2_iterator_next((arg1))
++#define ao2_t_iterator_next(arg1, arg2) __ao2_iterator_next((arg1))
++#define ao2_iterator_next(arg1) __ao2_iterator_next((arg1))
+ #endif
+-void *_ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname);
+-void *_ao2_iterator_next(struct ao2_iterator *a);
++void *__ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname);
++void *__ao2_iterator_next(struct ao2_iterator *a);
+
+ /* extra functions */
+ void ao2_bt(void); /* backtrace */
+Index: include/asterisk/heap.h
+===================================================================
+--- a/include/asterisk/heap.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/heap.h (.../trunk) (revision 186562)
+@@ -209,6 +209,8 @@
+ */
+ size_t ast_heap_size(struct ast_heap *h);
+
++#ifndef DEBUG_THREADS
++
+ /*!
+ * \brief Write-Lock a heap
+ *
+@@ -247,6 +249,17 @@
+ */
+ int ast_heap_unlock(struct ast_heap *h);
+
++#else /* DEBUG_THREADS */
++
++#define ast_heap_wrlock(h) __ast_heap_wrlock(h, __FILE__, __PRETTY_FUNCTION__, __LINE__)
++int __ast_heap_wrlock(struct ast_heap *h, const char *file, const char *func, int line);
++#define ast_heap_rdlock(h) __ast_heap_rdlock(h, __FILE__, __PRETTY_FUNCTION__, __LINE__)
++int __ast_heap_rdlock(struct ast_heap *h, const char *file, const char *func, int line);
++#define ast_heap_unlock(h) __ast_heap_unlock(h, __FILE__, __PRETTY_FUNCTION__, __LINE__)
++int __ast_heap_unlock(struct ast_heap *h, const char *file, const char *func, int line);
++
++#endif /* DEBUG_THREADS */
++
+ /*!
+ * \brief Verify that a heap has been properly constructed
+ *
+Index: include/asterisk/lock.h
+===================================================================
+--- a/include/asterisk/lock.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/lock.h (.../trunk) (revision 186562)
+@@ -500,8 +500,10 @@
+ if (t->tracking) {
+ #ifdef HAVE_BKTR
+ ast_reentrancy_lock(lt);
+- ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+- bt = &lt->backtrace[lt->reentrancy];
++ if (lt->reentrancy != AST_MAX_REENTRANCY) {
++ ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
++ bt = &lt->backtrace[lt->reentrancy];
++ }
+ ast_reentrancy_unlock(lt);
+ ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
+ #else
+@@ -622,8 +624,10 @@
+ if (t->tracking) {
+ #ifdef HAVE_BKTR
+ ast_reentrancy_lock(lt);
+- ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+- bt = &lt->backtrace[lt->reentrancy];
++ if (lt->reentrancy != AST_MAX_REENTRANCY) {
++ ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
++ bt = &lt->backtrace[lt->reentrancy];
++ }
+ ast_reentrancy_unlock(lt);
+ ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
+ #else
+@@ -1069,6 +1073,7 @@
+ #ifdef HAVE_BKTR
+ struct ast_bt *bt = NULL;
+ #endif
++ int lock_found = 0;
+
+
+ #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+@@ -1086,44 +1091,35 @@
+
+ ast_reentrancy_lock(lt);
+ if (lt->reentrancy) {
+- int lock_found = 0;
+ int i;
+ pthread_t self = pthread_self();
+- for (i = lt->reentrancy-1; i >= 0; --i) {
++ for (i = lt->reentrancy - 1; i >= 0; --i) {
+ if (lt->thread[i] == self) {
+ lock_found = 1;
+- if (i != lt->reentrancy-1) {
+- lt->file[i] = lt->file[lt->reentrancy-1];
+- lt->lineno[i] = lt->lineno[lt->reentrancy-1];
+- lt->func[i] = lt->func[lt->reentrancy-1];
+- lt->thread[i] = lt->thread[lt->reentrancy-1];
++ if (i != lt->reentrancy - 1) {
++ lt->file[i] = lt->file[lt->reentrancy - 1];
++ lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
++ lt->func[i] = lt->func[lt->reentrancy - 1];
++ lt->thread[i] = lt->thread[lt->reentrancy - 1];
+ }
++#ifdef HAVE_BKTR
++ bt = &lt->backtrace[i];
++#endif
++ lt->file[lt->reentrancy - 1] = NULL;
++ lt->lineno[lt->reentrancy - 1] = 0;
++ lt->func[lt->reentrancy - 1] = NULL;
++ lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
+ break;
+ }
+ }
+- if (!lock_found) {
+- __ast_mutex_logger("%s line %d (%s): attempted unlock rwlock '%s' without owning it!\n",
+- filename, line, func, name);
+- __ast_mutex_logger("%s line %d (%s): '%s' was last locked here.\n",
+- lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1], lt->func[lt->reentrancy-1], name);
+-#ifdef HAVE_BKTR
+- __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
+-#endif
+- DO_THREAD_CRASH;
+- }
+ }
+
+- if (--lt->reentrancy < 0) {
++ if (lock_found && --lt->reentrancy < 0) {
+ __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
+ filename, line, func, name);
+ lt->reentrancy = 0;
+ }
+
+-#ifdef HAVE_BKTR
+- if (lt->reentrancy) {
+- bt = &lt->backtrace[lt->reentrancy - 1];
+- }
+-#endif
+ ast_reentrancy_unlock(lt);
+
+ if (t->tracking) {
+@@ -1171,8 +1167,10 @@
+ if (t->tracking) {
+ #ifdef HAVE_BKTR
+ ast_reentrancy_lock(lt);
+- ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+- bt = &lt->backtrace[lt->reentrancy];
++ if (lt->reentrancy != AST_MAX_REENTRANCY) {
++ ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
++ bt = &lt->backtrace[lt->reentrancy];
++ }
+ ast_reentrancy_unlock(lt);
+ ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
+ #else
+@@ -1220,9 +1218,6 @@
+ lt->func[lt->reentrancy] = func;
+ lt->thread[lt->reentrancy] = pthread_self();
+ lt->reentrancy++;
+- } else {
+- __ast_mutex_logger("%s line %d (%s): read lock '%s' really deep reentrancy!\n",
+- filename, line, func, name);
+ }
+ ast_reentrancy_unlock(lt);
+ if (t->tracking) {
+@@ -1280,8 +1275,10 @@
+ if (t->tracking) {
+ #ifdef HAVE_BKTR
+ ast_reentrancy_lock(lt);
+- ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+- bt = &lt->backtrace[lt->reentrancy];
++ if (lt->reentrancy != AST_MAX_REENTRANCY) {
++ ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
++ bt = &lt->backtrace[lt->reentrancy];
++ }
+ ast_reentrancy_unlock(lt);
+ ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
+ #else
+@@ -1328,9 +1325,6 @@
+ lt->func[lt->reentrancy] = func;
+ lt->thread[lt->reentrancy] = pthread_self();
+ lt->reentrancy++;
+- } else {
+- __ast_mutex_logger("%s line %d (%s): write lock '%s' really deep reentrancy!\n",
+- filename, line, func, name);
+ }
+ ast_reentrancy_unlock(lt);
+ if (t->tracking) {
+@@ -1364,7 +1358,6 @@
+ {
+ int res;
+ struct ast_lock_track *lt = &t->track;
+- int canlog = strcmp(filename, "logger.c") & t->tracking;
+ #ifdef HAVE_BKTR
+ struct ast_bt *bt = NULL;
+ #endif
+@@ -1388,8 +1381,10 @@
+ if (t->tracking) {
+ #ifdef HAVE_BKTR
+ ast_reentrancy_lock(lt);
+- ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+- bt = &lt->backtrace[lt->reentrancy];
++ if (lt->reentrancy != AST_MAX_REENTRANCY) {
++ ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
++ bt = &lt->backtrace[lt->reentrancy];
++ }
+ ast_reentrancy_unlock(lt);
+ ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
+ #else
+@@ -1405,9 +1400,6 @@
+ lt->func[lt->reentrancy] = func;
+ lt->thread[lt->reentrancy] = pthread_self();
+ lt->reentrancy++;
+- } else {
+- __ast_mutex_logger("%s line %d (%s): read lock '%s' really deep reentrancy!\n",
+- filename, line, func, name);
+ }
+ ast_reentrancy_unlock(lt);
+ if (t->tracking) {
+@@ -1424,7 +1416,6 @@
+ {
+ int res;
+ struct ast_lock_track *lt= &t->track;
+- int canlog = strcmp(filename, "logger.c") & t->tracking;
+ #ifdef HAVE_BKTR
+ struct ast_bt *bt = NULL;
+ #endif
+@@ -1448,8 +1439,10 @@
+ if (t->tracking) {
+ #ifdef HAVE_BKTR
+ ast_reentrancy_lock(lt);
+- ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+- bt = &lt->backtrace[lt->reentrancy];
++ if (lt->reentrancy != AST_MAX_REENTRANCY) {
++ ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
++ bt = &lt->backtrace[lt->reentrancy];
++ }
+ ast_reentrancy_unlock(lt);
+ ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
+ #else
+@@ -1465,9 +1458,6 @@
+ lt->func[lt->reentrancy] = func;
+ lt->thread[lt->reentrancy] = pthread_self();
+ lt->reentrancy++;
+- } else {
+- __ast_mutex_logger("%s line %d (%s): write lock '%s' really deep reentrancy!\n",
+- filename, line, func, name);
+ }
+ ast_reentrancy_unlock(lt);
+ if (t->tracking) {
+Index: include/asterisk/pbx.h
+===================================================================
+--- a/include/asterisk/pbx.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/pbx.h (.../trunk) (revision 186562)
+@@ -37,12 +37,13 @@
+ #define AST_PBX_KEEP 0
+ #define AST_PBX_REPLACE 1
+
+-/*! \brief Special return values from applications to the PBX { */
++/*! \brief Special return values from applications to the PBX
++ * @{ */
+ #define AST_PBX_HANGUP -1 /*!< Jump to the 'h' exten */
+ #define AST_PBX_OK 0 /*!< No errors */
+ #define AST_PBX_ERROR 1 /*!< Jump to the 'e' exten */
+ #define AST_PBX_INCOMPLETE 12 /*!< Return to PBX matching, allowing more digits for the extension */
+-/*! } */
++/*! @} */
+
+ #define PRIORITY_HINT -1 /*!< Special Priority for a hint */
+
+@@ -134,7 +135,8 @@
+
+ /*!\brief Deallocates memory structures associated with a timing bitmap.
+ * \param i Pointer to an ast_timing structure.
+- * \retval Returns 0 on success or a number suitable for passing into strerror, otherwise.
++ * \retval 0 success
++ * \retval non-zero failure (number suitable to pass to \see strerror)
+ */
+ int ast_destroy_timing(struct ast_timing *i);
+
+@@ -152,7 +154,8 @@
+ * This function registers a populated ast_switch structure with the
+ * asterisk switching architecture.
+ *
+- * \return 0 on success, and other than 0 on failure
++ * \retval 0 success
++ * \retval non-zero failure
+ */
+ int ast_register_switch(struct ast_switch *sw);
+
+@@ -191,7 +194,8 @@
+ * saves the stack and executes the given application passing in
+ * the given data.
+ *
+- * \return 0 on success, and -1 on failure
++ * \retval 0 success
++ * \retval -1 failure
+ */
+ int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
+
+@@ -251,7 +255,7 @@
+ */
+ struct ast_context *ast_context_find(const char *name);
+
+-/*! \brief The result codes when starting the PBX on a channelwith \see ast_pbx_start.
++/*! \brief The result codes when starting the PBX on a channel with \see ast_pbx_start.
+ AST_PBX_CALL_LIMIT refers to the maxcalls call limit in asterisk.conf
+ */
+ enum ast_pbx_result {
+@@ -403,18 +407,18 @@
+ * \brief If an extension hint exists, return non-zero
+ *
+ * \param hint buffer for hint
+- * \param maxlen size of hint buffer
++ * \param hintsize size of hint buffer, in bytes
+ * \param name buffer for name portion of hint
+- * \param maxnamelen size of name buffer
+- * \param c this is not important
++ * \param namesize size of name buffer
++ * \param c Channel from which to return the hint. This is only important when the hint or name contains an expression to be expanded.
+ * \param context which context to look in
+ * \param exten which extension to search for
+ *
+ * \return If an extension within the given context with the priority PRIORITY_HINT
+- * is found a non zero value will be returned.
++ * is found, a non zero value will be returned.
+ * Otherwise, 0 is returned.
+ */
+-int ast_get_hint(char *hint, int maxlen, char *name, int maxnamelen,
++int ast_get_hint(char *hint, int hintsize, char *name, int namesize,
+ struct ast_channel *c, const char *context, const char *exten);
+
+ /*!
+@@ -679,6 +683,8 @@
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
++ *
++ * @{
+ */
+ int ast_context_remove_extension(const char *context, const char *extension, int priority,
+ const char *registrar);
+@@ -692,6 +698,7 @@
+ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension,
+ int priority, const char *callerid, int matchcid, const char *registrar,
+ int already_locked);
++/*! @} */
+
+ /*!
+ * \brief Add an ignorepat
+@@ -818,8 +825,13 @@
+ */
+ int ast_context_unlockmacro(const char *macrocontext);
+
++/*!\brief Set the channel to next execute the specified dialplan location.
++ * \see ast_async_parseable_goto, ast_async_goto_if_exists
++ */
+ int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority);
+
++/*!\brief Set the channel to next execute the specified dialplan location.
++ */
+ int ast_async_goto_by_name(const char *chan, const char *context, const char *exten, int priority);
+
+ /*! Synchronously or asynchronously make an outbound call and send it to a
+@@ -873,7 +885,8 @@
+ const char *ast_get_switch_registrar(struct ast_sw *sw);
+ /*! @} */
+
+-/* Walking functions ... */
++/*! @name Walking functions ... */
++/*! @{ */
+ struct ast_context *ast_walk_contexts(struct ast_context *con);
+ struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
+ struct ast_exten *priority);
+@@ -884,13 +897,16 @@
+ struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
+ struct ast_ignorepat *ip);
+ struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw);
++/*! @} */
+
+-/*!
++/*!\brief Create a human-readable string, specifying all variables and their corresponding values.
++ * \param chan Channel from which to read variables
++ * \param buf Dynamic string in which to place the result (should be allocated with \see ast_str_create).
+ * \note Will lock the channel.
+ */
+ int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf);
+
+-/*!
++/*!\brief Return a pointer to the value of the corresponding channel variable.
+ * \note Will lock the channel.
+ *
+ * \note This function will return a pointer to the buffer inside the channel
+@@ -909,43 +925,51 @@
+ */
+ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name);
+
+-/*!
++/*!\brief Add a variable to the channel variable stack, without removing any previously set value.
+ * \note Will lock the channel.
+ */
+ void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value);
+
+-/*!
+- * \note Will lock the channel.
++/*!\brief Add a variable to the channel variable stack, removing the most recently set value for the same name.
++ * \note Will lock the channel. May also be used to set a channel dialplan function to a particular value.
++ * \see ast_func_write
+ */
+ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value);
+
+-/*!
++/*!\brief Retrieve the value of a builtin variable or variable from the channel variable stack.
+ * \note Will lock the channel.
+ */
+ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp);
+ void pbx_builtin_clear_globals(void);
+
+-/*!
++/*!\brief Parse and set a single channel variable, where the name and value are separated with an '=' character.
+ * \note Will lock the channel.
+ */
+ int pbx_builtin_setvar(struct ast_channel *chan, void *data);
++
++/*!\brief Parse and set multiple channel variables, where the pairs are separated by the ',' character, and name and value are separated with an '=' character.
++ * \note Will lock the channel.
++ */
+ int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *data);
+
+ int pbx_builtin_raise_exception(struct ast_channel *chan, void *data);
+
+-void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
++/*! @name Substitution routines, using static string buffers
++ * @{ */
++void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count);
+ void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count);
+ void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);
+ void ast_str_substitute_variables(struct ast_str **buf, size_t maxlen, struct ast_channel *chan, const char *templ);
++/*! @} */
+
+ int ast_extension_patmatch(const char *pattern, const char *data);
+
+-/*! Set "autofallthrough" flag, if newval is <0, does not acutally set. If
++/*! Set "autofallthrough" flag, if newval is <0, does not actually set. If
+ set to 1, sets to auto fall through. If newval set to 0, sets to no auto
+ fall through (reads extension instead). Returns previous value. */
+ int pbx_set_autofallthrough(int newval);
+
+-/*! Set "extenpatternmatchnew" flag, if newval is <0, does not acutally set. If
++/*! Set "extenpatternmatchnew" flag, if newval is <0, does not actually set. If
+ set to 1, sets to use the new Trie-based pattern matcher. If newval set to 0, sets to use
+ the old linear-search algorithm. Returns previous value. */
+ int pbx_set_extenpatternmatchnew(int newval);
+@@ -963,10 +987,6 @@
+ int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority);
+
+ /*!
+- * \note I can find neither parsable nor parseable at dictionary.com,
+- * but google gives me 169000 hits for parseable and only 49,800
+- * for parsable
+- *
+ * \note This function will handle locking the channel as needed.
+ */
+ int ast_parseable_goto(struct ast_channel *chan, const char *goto_string);
+@@ -1023,7 +1043,8 @@
+ *
+ * This application executes a function in read mode on a given channel.
+ *
+- * \return zero on success, non-zero on failure
++ * \retval 0 success
++ * \retval non-zero failure
+ */
+ int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len);
+
+@@ -1036,7 +1057,8 @@
+ *
+ * This application executes a function in write mode on a given channel.
+ *
+- * \return zero on success, non-zero on failure
++ * \retval 0 success
++ * \retval non-zero failure
+ */
+ int ast_func_write(struct ast_channel *chan, const char *function, const char *value);
+
+@@ -1092,9 +1114,11 @@
+ int ast_wrlock_contexts_version(void);
+
+
+-/* hashtable functions for contexts */
++/*!\brief hashtable functions for contexts */
++/*! @{ */
+ int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+ unsigned int ast_hashtab_hash_contexts(const void *obj);
++/*! @} */
+
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+Index: include/asterisk/strings.h
+===================================================================
+--- a/include/asterisk/strings.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/strings.h (.../trunk) (revision 186562)
+@@ -451,7 +451,7 @@
+ )
+
+ /*!\brief Returns the current length of the string stored within buf.
+- * \param A pointer to the ast_str string.
++ * \param buf A pointer to the ast_str structure.
+ */
+ AST_INLINE_API(
+ size_t attribute_pure ast_str_strlen(struct ast_str *buf),
+@@ -461,7 +461,8 @@
+ )
+
+ /*!\brief Returns the current maximum length (without reallocation) of the current buffer.
+- * \param A pointer to the ast_str string.
++ * \param buf A pointer to the ast_str structure.
++ * \retval Current maximum length of the buffer.
+ */
+ AST_INLINE_API(
+ size_t attribute_pure ast_str_size(struct ast_str *buf),
+@@ -471,7 +472,8 @@
+ )
+
+ /*!\brief Returns the string buffer within the ast_str buf.
+- * \param A pointer to the ast_str string.
++ * \param buf A pointer to the ast_str structure.
++ * \retval A pointer to the enclosed string.
+ */
+ AST_INLINE_API(
+ char * attribute_pure ast_str_buffer(struct ast_str *buf),
+@@ -480,6 +482,11 @@
+ }
+ )
+
++/*!\brief Truncates the enclosed string to the given length.
++ * \param buf A pointer to the ast_str structure.
++ * \param len Maximum length of the string.
++ * \retval A pointer to the resulting string.
++ */
+ AST_INLINE_API(
+ char *ast_str_truncate(struct ast_str *buf, ssize_t len),
+ {
+@@ -852,6 +859,29 @@
+ }
+
+ /*!
++ * \brief Compute a hash value on a string
++ *
++ * \param[in] str The string to add to the hash
++ * \param[in] hash The hash value to add to
++ *
++ * \details
++ * This version of the function is for when you need to compute a
++ * string hash of more than one string.
++ *
++ * This famous hash algorithm was written by Dan Bernstein and is
++ * commonly used.
++ *
++ * \sa http://www.cse.yorku.ca/~oz/hash.html
++ */
++static force_inline int ast_str_hash_add(const char *str, int hash)
++{
++ while (*str)
++ hash = hash * 33 ^ *str++;
++
++ return abs(hash);
++}
++
++/*!
+ * \brief Compute a hash value on a case-insensitive string
+ *
+ * Uses the same hash algorithm as ast_str_hash, but converts
+Index: include/asterisk/stun.h
+===================================================================
+--- a/include/asterisk/stun.h (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/include/asterisk/stun.h (.../trunk) (revision 186562)
+@@ -0,0 +1,71 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2008, Digium, Inc.
++ *
++ * Mark Spencer <markster@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*!
++ * \file stun.h
++ * \brief STUN support.
++ *
++ * STUN is defined in RFC 3489.
++ */
++
++#ifndef _ASTERISK_STUN_H
++#define _ASTERISK_STUN_H
++
++#include "asterisk/network.h"
++
++#if defined(__cplusplus) || defined(c_plusplus)
++extern "C" {
++#endif
++
++enum ast_stun_result {
++ AST_STUN_IGNORE = 0,
++ AST_STUN_ACCEPT,
++};
++
++struct stun_attr;
++
++/*! \brief Generic STUN request
++ * send a generic stun request to the server specified.
++ * \param s the socket used to send the request
++ * \param dst the address of the STUN server
++ * \param username if non null, add the username in the request
++ * \param answer if non null, the function waits for a response and
++ * puts here the externally visible address.
++ * \return 0 on success, other values on error.
++ * The interface it may change in the future.
++ */
++int ast_stun_request(int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer);
++
++/*! \brief callback type to be invoked on stun responses. */
++typedef int (stun_cb_f)(struct stun_attr *attr, void *arg);
++
++/*! \brief handle an incoming STUN message.
++ *
++ * Do some basic sanity checks on packet size and content,
++ * try to extract a bit of information, and possibly reply.
++ * At the moment this only processes BIND requests, and returns
++ * the externally visible address of the request.
++ * If a callback is specified, invoke it with the attribute.
++ */
++int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg);
++
++#if defined(__cplusplus) || defined(c_plusplus)
++}
++#endif
++
++#endif /* _ASTERISK_STUN_H */
+
+Property changes on: include/asterisk/stun.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: include/asterisk/stringfields.h
+===================================================================
+--- a/include/asterisk/stringfields.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/stringfields.h (.../trunk) (revision 186562)
+@@ -57,25 +57,23 @@
+
+ Fields will default to pointing to an empty string, and will revert to
+ that when ast_string_field_set() is called with a NULL argument.
+- A string field will \b never contain NULL (this feature is not used
+- in this code, but comes from external requirements).
++ A string field will \b never contain NULL.
+
+ ast_string_field_init(x, 0) will reset fields to the
+ initial value while keeping the pool allocated.
+
+ Reading the fields is much like using 'const char * const' fields in the
+- structure: you cannot write to the field or to the memory it points to
+- (XXX perhaps the latter is too much of a restriction since values
+- are not shared).
++ structure: you cannot write to the field or to the memory it points to.
+
+ Writing to the fields must be done using the wrapper macros listed below;
+ and assignments are always by value (i.e. strings are copied):
+ * ast_string_field_set() stores a simple value;
+- * ast_string_field_build() builds the string using a printf-style;
++ * ast_string_field_build() builds the string using a printf-style format;
+ * ast_string_field_build_va() is the varargs version of the above (for
+- portability reasons it uses two vararg);
++ portability reasons it uses two vararg arguments);
+ * variants of these function allow passing a pointer to the field
+ as an argument.
++
+ \code
+ ast_string_field_set(x, foo, "infinite loop");
+ ast_string_field_set(x, foo, NULL); // set to an empty string
+@@ -110,6 +108,9 @@
+
+ Don't declare instances of this type directly; use the AST_STRING_FIELD()
+ macro instead.
++
++ In addition to the string itself, the amount of space allocated for the
++ field is stored in the two bytes immediately preceding it.
+ */
+ typedef const char * ast_string_field;
+
+@@ -117,7 +118,7 @@
+ \internal
+ \brief A constant empty string used for fields that have no other value
+ */
+-extern const char __ast_string_field_empty[];
++extern const char *__ast_string_field_empty;
+
+ /*!
+ \internal
+@@ -125,18 +126,17 @@
+ */
+ struct ast_string_field_pool {
+ struct ast_string_field_pool *prev; /*!< pointer to the previous pool, if any */
++ size_t size; /*!< the total size of the pool */
++ size_t used; /*!< the space used in the pool */
++ size_t active; /*!< the amount of space actively in use by fields */
+ char base[0]; /*!< storage space for the fields */
+ };
+
+ /*!
+ \internal
+ \brief Structure used to manage the storage for a set of string fields.
+- Because of the way pools are managed, we can only allocate from the topmost
+- pool, so the numbers here reflect just that.
+ */
+ struct ast_string_field_mgr {
+- size_t size; /*!< the total size of the current pool */
+- size_t used; /*!< the space used in the current pool */
+ ast_string_field last_alloc; /*!< the last field allocated */
+ };
+
+@@ -154,7 +154,8 @@
+ the pool has enough space available. If so, the additional space will be
+ allocated to this field and the field's address will not be changed.
+ */
+-int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
++int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
++ struct ast_string_field_pool **pool_head, size_t needed,
+ const ast_string_field *ptr);
+
+ /*!
+@@ -176,7 +177,7 @@
+ \internal
+ \brief Set a field to a complex (built) value
+ \param mgr Pointer to the pool manager structure
+- \param fields Pointer to the first entry of the field array
++ \param pool_head Pointer to the current pool
+ \param ptr Pointer to a field within the structure
+ \param format printf-style format string
+ \return nothing
+@@ -189,7 +190,7 @@
+ \internal
+ \brief Set a field to a complex (built) value
+ \param mgr Pointer to the pool manager structure
+- \param fields Pointer to the first entry of the field array
++ \param pool_head Pointer to the current pool
+ \param ptr Pointer to a field within the structure
+ \param format printf-style format string
+ \param args va_list of the args for the format_string
+@@ -242,29 +243,55 @@
+
+ /*! \internal \brief internal version of ast_string_field_init */
+ int __ast_string_field_init(struct ast_string_field_mgr *mgr,
+- struct ast_string_field_pool **pool_head, int needed);
++ struct ast_string_field_pool **pool_head, int needed);
+
+ /*!
++ \internal
++ \brief Release a field's allocation from a pool
++ \param pool_head Pointer to the current pool
++ \param ptr Field to be released
++ \return nothing
++
++ This function will search the pool list to find the pool that contains
++ the allocation for the specified field, then remove the field's allocation
++ from that pool's 'active' count. If the pool's active count reaches zero,
++ and it is not the current pool, then it will be freed.
++ */
++void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
++ const ast_string_field ptr);
++
++/* the type of storage used to track how many bytes were allocated for a field */
++
++typedef uint16_t ast_string_field_allocation;
++
++/*!
++ \brief Macro to provide access to the allocation field that lives immediately in front of a string field
++ \param x Pointer to the string field
++*/
++#define AST_STRING_FIELD_ALLOCATION(x) *((ast_string_field_allocation *) (x - sizeof(ast_string_field_allocation)))
++
++/*!
+ \brief Set a field to a simple string value
+ \param x Pointer to a structure containing fields
+ \param ptr Pointer to a field within the structure
+- \param data String value to be copied into the field
++ \param data String value to be copied into the field
+ \return nothing
+ */
+-#define ast_string_field_ptr_set(x, ptr, data) do { \
+- const char *__d__ = (data); \
+- size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
+- const char **__p__ = (const char **) (ptr); \
+- char *__q__; \
+- if (__dlen__ == 1) \
+- *__p__ = __ast_string_field_empty; \
+- else if (!__ast_string_field_ptr_grow(&(x)->__field_mgr, __dlen__, ptr)) { \
+- __q__ = (char *) *__p__; \
+- memcpy(__q__, __d__, __dlen__); \
+- } else if ((*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) { \
+- __q__ = (char *) *__p__; \
+- memcpy(__q__, __d__, __dlen__); \
+- } \
++#define ast_string_field_ptr_set(x, ptr, data) do { \
++ const char *__d__ = (data); \
++ size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
++ ast_string_field *__p__ = (ast_string_field *) (ptr); \
++ if (__dlen__ == 1) { \
++ __ast_string_field_release_active((x)->__field_mgr_pool, *__p__); \
++ *__p__ = __ast_string_field_empty; \
++ } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) || \
++ (!__ast_string_field_ptr_grow(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__, __p__)) || \
++ (*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) { \
++ if (*__p__ != (*ptr)) { \
++ __ast_string_field_release_active((x)->__field_mgr_pool, (*ptr)); \
++ } \
++ memcpy(* (void **) __p__, __d__, __dlen__); \
++ } \
+ } while (0)
+
+ /*!
+Index: include/asterisk/autoconfig.h.in
+===================================================================
+--- a/include/asterisk/autoconfig.h.in (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/autoconfig.h.in (.../trunk) (revision 186562)
+@@ -767,12 +767,6 @@
+ /* Define to indicate the ${ROUND_DESCRIP} library version */
+ #undef HAVE_ROUND_VERSION
+
+-/* Define if your system has the RTLD_NOLOAD headers. */
+-#undef HAVE_RTLD_NOLOAD
+-
+-/* Define RTLD_NOLOAD headers version */
+-#undef HAVE_RTLD_NOLOAD_VERSION
+-
+ /* Define to 1 if your system has /sbin/launchd. */
+ #undef HAVE_SBIN_LAUNCHD
+
+Index: include/asterisk/callerid.h
+===================================================================
+--- a/include/asterisk/callerid.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/callerid.h (.../trunk) (revision 186562)
+@@ -86,21 +86,24 @@
+ void callerid_init(void);
+
+ /*! \brief Generates a CallerID FSK stream in ulaw format suitable for transmission.
+- * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own. "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
++ * \param buf Buffer to use. If "buf" is supplied, it will use that buffer instead of allocating its own.
++ * "buf" must be at least 32000 bytes in size of you want to be sure you don't have an overrun.
+ * \param number Use NULL for no number or "P" for "private"
+ * \param name name to be used
+ * \param flags passed flags
+ * \param callwaiting callwaiting flag
+ * \param codec -- either AST_FORMAT_ULAW or AST_FORMAT_ALAW
++ * \details
+ * This function creates a stream of callerid (a callerid spill) data in ulaw format.
+ * \return It returns the size
+ * (in bytes) of the data (if it returns a size of 0, there is probably an error)
+-*/
++ */
+ int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, int codec);
+
+ /*! \brief Create a callerID state machine
+ * \param cid_signalling Type of signalling in use
+ *
++ * \details
+ * This function returns a malloc'd instance of the callerid_state data structure.
+ * \return Returns a pointer to a malloc'd callerid_state structure, or NULL on error.
+ */
+@@ -112,9 +115,11 @@
+ * \param samples number of samples contained within the buffer.
+ * \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
+ *
++ * \details
+ * Send received audio to the Caller*ID demodulator.
+- * \return Returns -1 on error, 0 for "needs more samples",
+- * and 1 if the CallerID spill reception is complete.
++ * \retval -1 on error
++ * \retval 0 for "needs more samples"
++ * \retval 1 if the CallerID spill reception is complete.
+ */
+ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
+
+@@ -124,9 +129,11 @@
+ * \param samples number of samples contained within the buffer.
+ * \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
+ *
++ * \details
+ * Send received audio to the Caller*ID demodulator (for japanese style lines).
+- * \return Returns -1 on error, 0 for "needs more samples",
+- * and 1 if the CallerID spill reception is complete.
++ * \retval -1 on error
++ * \retval 0 for "needs more samples"
++ * \retval 1 if the CallerID spill reception is complete.
+ */
+ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
+
+@@ -136,6 +143,7 @@
+ * \param name Pass the address of a pointer-to-char (will contain the name)
+ * \param flags Pass the address of an int variable(will contain the various callerid flags)
+ *
++ * \details
+ * This function extracts a callerid string out of a callerid_state state machine.
+ * If no number is found, *number will be set to NULL. Likewise for the name.
+ * Flags can contain any of the following:
+@@ -144,18 +152,16 @@
+ */
+ void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags);
+
+-/*! Get and parse DTMF-based callerid */
+ /*!
++ * \brief Get and parse DTMF-based callerid
+ * \param cidstring The actual transmitted string.
+ * \param number The cid number is returned here.
+ * \param flags The cid flags are returned here.
+- * This function parses DTMF callerid.
+ */
+ void callerid_get_dtmf(char *cidstring, char *number, int *flags);
+
+-/*! \brief Free a callerID state
++/*! \brief This function frees callerid_state cid.
+ * \param cid This is the callerid_state state machine to free
+- * This function frees callerid_state cid.
+ */
+ void callerid_free(struct callerid_state *cid);
+
+@@ -165,36 +171,44 @@
+ * \param number Caller-ID Number
+ * \param codec Asterisk codec (either AST_FORMAT_ALAW or AST_FORMAT_ULAW)
+ *
++ * \details
+ * Acts like callerid_generate except uses an asterisk format callerid string.
+ */
+ int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int codec);
+
+-/*! \brief Generate message waiting indicator
+- * \param active The message indicator state
++/*!
++ * \brief Generate message waiting indicator
++ * \param active The message indicator state
+ * -- either 0 no messages in mailbox or 1 messages in mailbox
+- * \param type Format of message (any of CID_MWI_TYPE_*)
+- * \see callerid_generate() for more info as it use the same encoding
+- * \version 1.6.1 changed mdmf parameter to type, added name, number and flags for caller id message generation
+-*/
+-int vmwi_generate(unsigned char *buf, int active, int type, int codec, const char *name,
++ * \param type Format of message (any of CID_MWI_TYPE_*)
++ * \see callerid_generate() for more info as it uses the same encoding
++ * \version 1.6.1 changed mdmf parameter to type, added name, number and flags for caller id message generation
++ */
++int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, int codec, const char *name,
+ const char *number, int flags);
+
+ /*! \brief Generate Caller-ID spill but in a format suitable for Call Waiting(tm)'s Caller*ID(tm)
+- * See ast_callerid_generate() for other details
++ * \see ast_callerid_generate() for other details
+ */
+ int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, int codec);
+
+ /*! \brief Destructively parse inbuf into name and location (or number)
++ * \details
+ * Parses callerid stream from inbuf and changes into useable form, outputed in name and location.
+ * \param instr buffer of callerid stream (in audio form) to be parsed. Warning, data in buffer is changed.
+ * \param name address of a pointer-to-char for the name value of the stream.
+ * \param location address of a pointer-to-char for the phone number value of the stream.
++ * \note XXX 'name' is not parsed consistently e.g. we have
++ * input location name
++ * " foo bar " <123> 123 ' foo bar ' (with spaces around)
++ * " foo bar " NULL 'foo bar' (without spaces around)
++ * The parsing of leading and trailing space/quotes should be more consistent.
+ * \return Returns 0 on success, -1 on failure.
+ */
+ int ast_callerid_parse(char *instr, char **name, char **location);
+
+-/*! Generate a CAS (CPE Alert Signal) tone for 'n' samples */
+ /*!
++ * \brief Generate a CAS (CPE Alert Signal) tone for 'n' samples
+ * \param outbuf Allocated buffer for data. Must be at least 2400 bytes unless no SAS is desired
+ * \param sas Non-zero if CAS should be preceeded by SAS
+ * \param len How many samples to generate.
+@@ -203,23 +217,26 @@
+ */
+ int ast_gen_cas(unsigned char *outbuf, int sas, int len, int codec);
+
+-/*! \brief Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s... */
+ /*!
++ * \brief Shrink a phone number in place to just digits (more accurately it just removes ()'s, .'s, and -'s...
+ * \param n The number to be stripped/shrunk
+ * \return Returns nothing important
+ */
+ void ast_shrink_phone_number(char *n);
+
+-/*! \brief Check if a string consists only of digits and + \#
+- \param n number to be checked.
+- \return Returns 0 if n is a number, 1 if it's not.
++/*!
++ * \brief Check if a string consists only of digits and + \#
++ * \param n number to be checked.
++ * \return Returns 0 if n is a number, 1 if it's not.
+ */
+ int ast_isphonenumber(const char *n);
+
+-/*! \brief Check if a string consists only of digits and and + \# ( ) - .
+- (meaning it can be cleaned with ast_shrink_phone_number)
+- \param exten The extension (or URI) to be checked.
+- \return Returns 0 if n is a number, 1 if it's not.
++/*!
++ * \brief Check if a string consists only of digits and and + \# ( ) - .
++ * (meaning it can be cleaned with ast_shrink_phone_number)
++ * \param exten The extension (or URI) to be checked.
++ * \retval 1 if string is valid AST shrinkable phone number
++ * \retval 0 if not
+ */
+ int ast_is_shrinkable_phonenumber(const char *exten);
+
+@@ -289,71 +306,171 @@
+
+ /* Various defines and bits for handling PRI- and SS7-type restriction */
+
+-#define AST_PRES_NUMBER_TYPE 0x03
++#define AST_PRES_NUMBER_TYPE 0x03
+ #define AST_PRES_USER_NUMBER_UNSCREENED 0x00
+ #define AST_PRES_USER_NUMBER_PASSED_SCREEN 0x01
+ #define AST_PRES_USER_NUMBER_FAILED_SCREEN 0x02
+-#define AST_PRES_NETWORK_NUMBER 0x03
++#define AST_PRES_NETWORK_NUMBER 0x03
+
+-#define AST_PRES_RESTRICTION 0x60
+-#define AST_PRES_ALLOWED 0x00
+-#define AST_PRES_RESTRICTED 0x20
+-#define AST_PRES_UNAVAILABLE 0x40
+-#define AST_PRES_RESERVED 0x60
++#define AST_PRES_RESTRICTION 0x60
++#define AST_PRES_ALLOWED 0x00
++#define AST_PRES_RESTRICTED 0x20
++#define AST_PRES_UNAVAILABLE 0x40
++#define AST_PRES_RESERVED 0x60
+
+ #define AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \
+- AST_PRES_USER_NUMBER_UNSCREENED + AST_PRES_ALLOWED
++ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED)
+
+ #define AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \
+- AST_PRES_USER_NUMBER_PASSED_SCREEN + AST_PRES_ALLOWED
++ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN)
+
+ #define AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \
+- AST_PRES_USER_NUMBER_FAILED_SCREEN + AST_PRES_ALLOWED
++ (AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN)
+
+ #define AST_PRES_ALLOWED_NETWORK_NUMBER \
+- AST_PRES_NETWORK_NUMBER + AST_PRES_ALLOWED
++ (AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER)
+
+ #define AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED \
+- AST_PRES_USER_NUMBER_UNSCREENED + AST_PRES_RESTRICTED
++ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED)
+
+ #define AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \
+- AST_PRES_USER_NUMBER_PASSED_SCREEN + AST_PRES_RESTRICTED
++ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN)
+
+ #define AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \
+- AST_PRES_USER_NUMBER_FAILED_SCREEN + AST_PRES_RESTRICTED
++ (AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN)
+
+ #define AST_PRES_PROHIB_NETWORK_NUMBER \
+- AST_PRES_NETWORK_NUMBER + AST_PRES_RESTRICTED
++ (AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER)
+
+ #define AST_PRES_NUMBER_NOT_AVAILABLE \
+- AST_PRES_NETWORK_NUMBER + AST_PRES_UNAVAILABLE
++ (AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER)
+
+ int ast_parse_caller_presentation(const char *data);
+ const char *ast_describe_caller_presentation(int data);
+ const char *ast_named_caller_presentation(int data);
+
+-/*! \page Def_CallerPres Caller ID Presentation
++/*!
++ * \page Def_CallerPres Caller ID Presentation
++ *
++ * Caller ID presentation values are used to set properties to a
++ * caller ID in PSTN networks, and as RPID value in SIP transactions.
++ *
++ * The following values are available to use:
++ * \arg \b Defined value, text string in config file, explanation
++ *
++ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", Presentation Allowed, Not Screened,
++ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", Presentation Allowed, Passed Screen,
++ * \arg \b AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", Presentation Allowed, Failed Screen,
++ * \arg \b AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", Presentation Allowed, Network Number,
++ * \arg \b AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", Presentation Prohibited, Not Screened,
++ * \arg \b AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", Presentation Prohibited, Passed Screen,
++ * \arg \b AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", Presentation Prohibited, Failed Screen,
++ * \arg \b AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", Presentation Prohibited, Network Number,
++ *
++ * \par References
++ * \arg \ref callerid.h Definitions
++ * \arg \ref callerid.c Functions
++ * \arg \ref CID Caller ID names and numbers
++ */
+
+- Caller ID presentation values are used to set properties to a
+- caller ID in PSTN networks, and as RPID value in SIP transactions.
++/*!
++ * \brief redirecting reason codes.
++ *
++ * This list attempts to encompass redirecting reasons
++ * as defined by several channel technologies.
++ */
++enum AST_REDIRECTING_REASON {
++ AST_REDIRECTING_REASON_UNKNOWN,
++ AST_REDIRECTING_REASON_USER_BUSY,
++ AST_REDIRECTING_REASON_NO_ANSWER,
++ AST_REDIRECTING_REASON_UNAVAILABLE,
++ AST_REDIRECTING_REASON_UNCONDITIONAL,
++ AST_REDIRECTING_REASON_TIME_OF_DAY,
++ AST_REDIRECTING_REASON_DO_NOT_DISTURB,
++ AST_REDIRECTING_REASON_DEFLECTION,
++ AST_REDIRECTING_REASON_FOLLOW_ME,
++ AST_REDIRECTING_REASON_OUT_OF_ORDER,
++ AST_REDIRECTING_REASON_AWAY,
++ AST_REDIRECTING_REASON_CALL_FWD_DTE, /* This is something defined in Q.931, and no I don't know what it means */
++};
+
+- The following values are available to use:
+- \arg \b Defined value, text string in config file, explanation
++/*!
++ * \since 1.6.3
++ * \brief Convert redirecting reason text code to value (used in config file parsing)
++ *
++ * \param data text string from config file
++ *
++ * \retval Q931_REDIRECTING_REASON from callerid.h
++ * \retval -1 if not in table
++ */
++int ast_redirecting_reason_parse(const char *data);
+
+- \arg \b AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", Presentation Allowed, Not Screened,
+- \arg \b AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", Presentation Allowed, Passed Screen,
+- \arg \b AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", Presentation Allowed, Failed Screen,
+- \arg \b AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", Presentation Allowed, Network Number,
+- \arg \b AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", Presentation Prohibited, Not Screened,
+- \arg \b AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", Presentation Prohibited, Passed Screen,
+- \arg \b AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", Presentation Prohibited, Failed Screen,
+- \arg \b AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", Presentation Prohibited, Network Number,
++/*!
++ * \since 1.6.3
++ * \brief Convert redirecting reason value to explanatory string
++ *
++ * \param data Q931_REDIRECTING_REASON from callerid.h
++ *
++ * \return string for human presentation
++ */
++const char *ast_redirecting_reason_describe(int data);
+
+- \par References
+- \arg \ref callerid.h Definitions
+- \arg \ref callerid.c Functions
+- \arg \ref CID Caller ID names and numbers
+-*/
++/*!
++ * \since 1.6.3
++ * \brief Convert redirecting reason value to text code
++ *
++ * \param data Q931_REDIRECTING_REASON from callerid.h
++ *
++ * \return string for config file
++ */
++const char *ast_redirecting_reason_name(int data);
+
++/*!
++ * \brief Connected line update source code
++ */
++enum AST_CONNECTED_LINE_UPDATE_SOURCE {
++ /*! Update for unknown reason (May be interpreted to mean from answer) */
++ AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN,
++ /*! Update from normal call answering */
++ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER,
++ /*! Update from call diversion (Deprecated, use REDIRECTING updates instead.) */
++ AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION,
++ /*! Update from call transfer(active) (Party has already answered) */
++ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
++ /*! Update from call transfer(alerting) (Party has not answered yet) */
++ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
++};
+
++/*!
++ * \since 1.6.3
++ * \brief Convert connected line update source text code to value (used in config file parsing)
++ *
++ * \param data text string from config file
++ *
++ * \retval AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
++ * \retval -1 if not in table
++ */
++int ast_connected_line_source_parse(const char *data);
++
++/*!
++ * \since 1.6.3
++ * \brief Convert connected line update source value to explanatory string
++ *
++ * \param data AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
++ *
++ * \return string for human presentation
++ */
++const char *ast_connected_line_source_describe(int data);
++
++/*!
++ * \since 1.6.3
++ * \brief Convert connected line update source value to text code
++ *
++ * \param data AST_CONNECTED_LINE_UPDATE_SOURCE from callerid.h
++ *
++ * \return string for config file
++ */
++const char *ast_connected_line_source_name(int data);
++
++
+ #endif /* _ASTERISK_CALLERID_H */
+Index: include/asterisk/doxyref.h
+===================================================================
+--- a/include/asterisk/doxyref.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/doxyref.h (.../trunk) (revision 186562)
+@@ -360,7 +360,8 @@
+ * Some commit history viewers treat the first line of commit messages as the
+ * summary for the commit. So, an effort should be made to format our commit
+ * messages in that fashion. The verbose description may contain multiple
+- * paragraphs, itemized lists, etc.
++ * paragraphs, itemized lists, etc. Always end the first sentence (and any
++ * subsequent sentences) with punctuation.
+ *
+ * Commit messages should be wrapped at 80 %columns.
+ *
+Index: include/asterisk/crypto.h
+===================================================================
+--- a/include/asterisk/crypto.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk/crypto.h (.../trunk) (revision 186562)
+@@ -40,7 +40,7 @@
+ * \retval the key on success.
+ * \retval NULL on failure.
+ */
+-struct ast_key *(*ast_key_get)(const char *key, int type);
++extern struct ast_key *(*ast_key_get)(const char *key, int type);
+
+ /*!
+ * \brief Check the authenticity of a message signature using a given public key
+@@ -52,7 +52,7 @@
+ * \retval -1 otherwise.
+ *
+ */
+-int (*ast_check_signature)(struct ast_key *key, const char *msg, const char *sig);
++extern int (*ast_check_signature)(struct ast_key *key, const char *msg, const char *sig);
+
+ /*!
+ * \brief Check the authenticity of a message signature using a given public key
+@@ -64,7 +64,7 @@
+ * \retval -1 otherwise.
+ *
+ */
+-int (*ast_check_signature_bin)(struct ast_key *key, const char *msg, int msglen, const unsigned char *sig);
++extern int (*ast_check_signature_bin)(struct ast_key *key, const char *msg, int msglen, const unsigned char *sig);
+
+ /*!
+ * \brief Sign a message signature using a given private key
+@@ -77,7 +77,7 @@
+ * \retval -1 on failure.
+ *
+ */
+-int (*ast_sign)(struct ast_key *key, char *msg, char *sig);
++extern int (*ast_sign)(struct ast_key *key, char *msg, char *sig);
+
+ /*!
+ * \brief Sign a message signature using a given private key
+@@ -90,7 +90,7 @@
+ * \retval -1 on failure.
+ *
+ */
+-int (*ast_sign_bin)(struct ast_key *key, const char *msg, int msglen, unsigned char *sig);
++extern int (*ast_sign_bin)(struct ast_key *key, const char *msg, int msglen, unsigned char *sig);
+
+ /*!
+ * \brief Encrypt a message using a given private key
+@@ -104,7 +104,7 @@
+ * \retval -1 on failure.
+ *
+ */
+-int (*ast_encrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
++extern int (*ast_encrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
+
+ /*!
+ * \brief Decrypt a message using a given private key
+@@ -118,7 +118,7 @@
+ * \retval -1 on failure.
+ *
+ */
+-int (*ast_decrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
++extern int (*ast_decrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+ #endif
+Index: include/asterisk.h
+===================================================================
+--- a/include/asterisk.h (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/include/asterisk.h (.../trunk) (revision 186562)
+@@ -146,10 +146,10 @@
+ *
+ * (note, this must be documented a lot more)
+ * ast_add_profile allocates a generic 'counter' with a given name,
+- * which can be shown with the command 'show profile <name>'
++ * which can be shown with the command 'core show profile &lt;name&gt;'
+ *
+ * The counter accumulates positive or negative values supplied by
+- * ast_add_profile(), dividing them by the 'scale' value passed in the
++ * \see ast_add_profile(), dividing them by the 'scale' value passed in the
+ * create call, and also counts the number of 'events'.
+ * Values can also be taked by the TSC counter on ia32 architectures,
+ * in which case you can mark the start of an event calling ast_mark(id, 1)
+Index: main/rtp.c
+===================================================================
+--- a/main/rtp.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/rtp.c (.../trunk) (revision 186562)
+-/*
+- * Asterisk -- An open source telephony toolkit.
+- *
+- * Copyright (C) 1999 - 2006, Digium, Inc.
+- *
+- * Mark Spencer <markster@digium.com>
+- *
+- * See http://www.asterisk.org for more information about
+- * the Asterisk project. Please do not directly contact
+- * any of the maintainers of this project for assistance;
+- * the project provides a web site, mailing lists and IRC
+- * channels for your use.
+- *
+- * This program is free software, distributed under the terms of
+- * the GNU General Public License Version 2. See the LICENSE file
+- * at the top of the source tree.
+- */
+-
+-/*!
+- * \file
+- *
+- * \brief Supports RTP and RTCP with Symmetric RTP support for NAT traversal.
+- *
+- * \author Mark Spencer <markster@digium.com>
+- *
+- * \note RTP is defined in RFC 3550.
+- */
+-
+-#include "asterisk.h"
+-
+-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 180373 $")
+-
+-#include <sys/time.h>
+-#include <signal.h>
+-#include <fcntl.h>
+-#include <math.h>
+-
+-#include "asterisk/rtp.h"
+-#include "asterisk/pbx.h"
+-#include "asterisk/frame.h"
+-#include "asterisk/channel.h"
+-#include "asterisk/acl.h"
+-#include "asterisk/config.h"
+-#include "asterisk/lock.h"
+-#include "asterisk/utils.h"
+-#include "asterisk/netsock.h"
+-#include "asterisk/cli.h"
+-#include "asterisk/manager.h"
+-#include "asterisk/unaligned.h"
+-
+-#define MAX_TIMESTAMP_SKEW 640
+-
+-#define RTP_SEQ_MOD (1<<16) /*!< A sequence number can't be more than 16 bits */
+-#define RTCP_DEFAULT_INTERVALMS 5000 /*!< Default milli-seconds between RTCP reports we send */
+-#define RTCP_MIN_INTERVALMS 500 /*!< Min milli-seconds between RTCP reports we send */
+-#define RTCP_MAX_INTERVALMS 60000 /*!< Max milli-seconds between RTCP reports we send */
+-
+-#define RTCP_PT_FUR 192
+-#define RTCP_PT_SR 200
+-#define RTCP_PT_RR 201
+-#define RTCP_PT_SDES 202
+-#define RTCP_PT_BYE 203
+-#define RTCP_PT_APP 204
+-
+-#define RTP_MTU 1200
+-
+-#define DEFAULT_DTMF_TIMEOUT 3000 /*!< samples */
+-
+-static int dtmftimeout = DEFAULT_DTMF_TIMEOUT;
+-
+-static int rtpstart = 5000; /*!< First port for RTP sessions (set in rtp.conf) */
+-static int rtpend = 31000; /*!< Last port for RTP sessions (set in rtp.conf) */
+-static int rtpdebug; /*!< Are we debugging? */
+-static int rtcpdebug; /*!< Are we debugging RTCP? */
+-static int rtcpstats; /*!< Are we debugging RTCP? */
+-static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */
+-static int stundebug; /*!< Are we debugging stun? */
+-static struct sockaddr_in rtpdebugaddr; /*!< Debug packets to/from this host */
+-static struct sockaddr_in rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */
+-#ifdef SO_NO_CHECK
+-static int nochecksums;
+-#endif
+-static int strictrtp;
+-
+-enum strict_rtp_state {
+- STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
+- STRICT_RTP_LEARN, /*! Accept next packet as source */
+- STRICT_RTP_CLOSED, /*! Drop all RTP packets not coming from source that was learned */
+-};
+-
+-/* Uncomment this to enable more intense native bridging, but note: this is currently buggy */
+-/* #define P2P_INTENSE */
+-
+-/*!
+- * \brief Structure representing a RTP session.
+- *
+- * RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP. A participant may be involved in multiple RTP sessions at the same time [...]"
+- *
+- */
+-
+-/*! \brief RTP session description */
+-struct ast_rtp {
+- int s;
+- struct ast_frame f;
+- unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
+- unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */
+- unsigned int themssrc; /*!< Their SSRC */
+- unsigned int rxssrc;
+- unsigned int lastts;
+- unsigned int lastrxts;
+- unsigned int lastividtimestamp;
+- unsigned int lastovidtimestamp;
+- unsigned int lastitexttimestamp;
+- unsigned int lastotexttimestamp;
+- unsigned int lasteventseqn;
+- int lastrxseqno; /*!< Last received sequence number */
+- unsigned short seedrxseqno; /*!< What sequence number did they start with?*/
+- unsigned int seedrxts; /*!< What RTP timestamp did they start with? */
+- unsigned int rxcount; /*!< How many packets have we received? */
+- unsigned int rxoctetcount; /*!< How many octets have we received? should be rxcount *160*/
+- unsigned int txcount; /*!< How many packets have we sent? */
+- unsigned int txoctetcount; /*!< How many octets have we sent? (txcount*160)*/
+- unsigned int cycles; /*!< Shifted count of sequence number cycles */
+- double rxjitter; /*!< Interarrival jitter at the moment */
+- double rxtransit; /*!< Relative transit time for previous packet */
+- int lasttxformat;
+- int lastrxformat;
+-
+- int rtptimeout; /*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
+- int rtpholdtimeout; /*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
+- int rtpkeepalive; /*!< Send RTP comfort noice packets for keepalive */
+-
+- /* DTMF Reception Variables */
+- char resp;
+- unsigned int lastevent;
+- int dtmfcount;
+- unsigned int dtmfsamples;
+- /* DTMF Transmission Variables */
+- unsigned int lastdigitts;
+- char sending_digit; /*!< boolean - are we sending digits */
+- char send_digit; /*!< digit we are sending */
+- int send_payload;
+- int send_duration;
+- int nat;
+- unsigned int flags;
+- struct sockaddr_in us; /*!< Socket representation of the local endpoint. */
+- struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */
+- struct timeval rxcore;
+- struct timeval txcore;
+- double drxcore; /*!< The double representation of the first received packet */
+- struct timeval lastrx; /*!< timeval when we last received a packet */
+- struct timeval dtmfmute;
+- struct ast_smoother *smoother;
+- int *ioid;
+- unsigned short seqno; /*!< Sequence number, RFC 3550, page 13. */
+- unsigned short rxseqno;
+- struct sched_context *sched;
+- struct io_context *io;
+- void *data;
+- ast_rtp_callback callback;
+-#ifdef P2P_INTENSE
+- ast_mutex_t bridge_lock;
+-#endif
+- struct rtpPayloadType current_RTP_PT[MAX_RTP_PT];
+- int rtp_lookup_code_cache_isAstFormat; /*!< a cache for the result of rtp_lookup_code(): */
+- int rtp_lookup_code_cache_code;
+- int rtp_lookup_code_cache_result;
+- struct ast_rtcp *rtcp;
+- struct ast_codec_pref pref;
+- struct ast_rtp *bridged; /*!< Who we are Packet bridged to */
+-
+- enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */
+- struct sockaddr_in strict_rtp_address; /*!< Remote address information for strict RTP purposes */
+-
+- int set_marker_bit:1; /*!< Whether to set the marker bit or not */
+- struct rtp_red *red;
+-};
+-
+-static struct ast_frame *red_t140_to_red(struct rtp_red *red);
+-static int red_write(const void *data);
+-
+-struct rtp_red {
+- struct ast_frame t140; /*!< Primary data */
+- struct ast_frame t140red; /*!< Redundant t140*/
+- unsigned char pt[RED_MAX_GENERATION]; /*!< Payload types for redundancy data */
+- unsigned char ts[RED_MAX_GENERATION]; /*!< Time stamps */
+- unsigned char len[RED_MAX_GENERATION]; /*!< length of each generation */
+- int num_gen; /*!< Number of generations */
+- int schedid; /*!< Timer id */
+- int ti; /*!< How long to buffer data before send */
+- unsigned char t140red_data[64000];
+- unsigned char buf_data[64000]; /*!< buffered primary data */
+- int hdrlen;
+- long int prev_ts;
+-};
+-
+-/* Forward declarations */
+-static int ast_rtcp_write(const void *data);
+-static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw);
+-static int ast_rtcp_write_sr(const void *data);
+-static int ast_rtcp_write_rr(const void *data);
+-static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp);
+-static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp);
+-int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
+-
+-#define FLAG_3389_WARNING (1 << 0)
+-#define FLAG_NAT_ACTIVE (3 << 1)
+-#define FLAG_NAT_INACTIVE (0 << 1)
+-#define FLAG_NAT_INACTIVE_NOWARN (1 << 1)
+-#define FLAG_HAS_DTMF (1 << 3)
+-#define FLAG_P2P_SENT_MARK (1 << 4)
+-#define FLAG_P2P_NEED_DTMF (1 << 5)
+-#define FLAG_CALLBACK_MODE (1 << 6)
+-#define FLAG_DTMF_COMPENSATE (1 << 7)
+-#define FLAG_HAS_STUN (1 << 8)
+-
+-/*!
+- * \brief Structure defining an RTCP session.
+- *
+- * The concept "RTCP session" is not defined in RFC 3550, but since
+- * this structure is analogous to ast_rtp, which tracks a RTP session,
+- * it is logical to think of this as a RTCP session.
+- *
+- * RTCP packet is defined on page 9 of RFC 3550.
+- *
+- */
+-struct ast_rtcp {
+- int rtcp_info;
+- int s; /*!< Socket */
+- struct sockaddr_in us; /*!< Socket representation of the local endpoint. */
+- struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */
+- unsigned int soc; /*!< What they told us */
+- unsigned int spc; /*!< What they told us */
+- unsigned int themrxlsr; /*!< The middle 32 bits of the NTP timestamp in the last received SR*/
+- struct timeval rxlsr; /*!< Time when we got their last SR */
+- struct timeval txlsr; /*!< Time when we sent or last SR*/
+- unsigned int expected_prior; /*!< no. packets in previous interval */
+- unsigned int received_prior; /*!< no. packets received in previous interval */
+- int schedid; /*!< Schedid returned from ast_sched_add() to schedule RTCP-transmissions*/
+- unsigned int rr_count; /*!< number of RRs we've sent, not including report blocks in SR's */
+- unsigned int sr_count; /*!< number of SRs we've sent */
+- unsigned int lastsrtxcount; /*!< Transmit packet count when last SR sent */
+- double accumulated_transit; /*!< accumulated a-dlsr-lsr */
+- double rtt; /*!< Last reported rtt */
+- unsigned int reported_jitter; /*!< The contents of their last jitter entry in the RR */
+- unsigned int reported_lost; /*!< Reported lost packets in their RR */
+- char quality[AST_MAX_USER_FIELD];
+- char quality_jitter[AST_MAX_USER_FIELD];
+- char quality_loss[AST_MAX_USER_FIELD];
+- char quality_rtt[AST_MAX_USER_FIELD];
+-
+- double reported_maxjitter;
+- double reported_minjitter;
+- double reported_normdev_jitter;
+- double reported_stdev_jitter;
+- unsigned int reported_jitter_count;
+-
+- double reported_maxlost;
+- double reported_minlost;
+- double reported_normdev_lost;
+- double reported_stdev_lost;
+-
+- double rxlost;
+- double maxrxlost;
+- double minrxlost;
+- double normdev_rxlost;
+- double stdev_rxlost;
+- unsigned int rxlost_count;
+-
+- double maxrxjitter;
+- double minrxjitter;
+- double normdev_rxjitter;
+- double stdev_rxjitter;
+- unsigned int rxjitter_count;
+- double maxrtt;
+- double minrtt;
+- double normdevrtt;
+- double stdevrtt;
+- unsigned int rtt_count;
+- int sendfur;
+-};
+-
+-/*!
+- * \brief STUN support code
+- *
+- * This code provides some support for doing STUN transactions.
+- * Eventually it should be moved elsewhere as other protocols
+- * than RTP can benefit from it - e.g. SIP.
+- * STUN is described in RFC3489 and it is based on the exchange
+- * of UDP packets between a client and one or more servers to
+- * determine the externally visible address (and port) of the client
+- * once it has gone through the NAT boxes that connect it to the
+- * outside.
+- * The simplest request packet is just the header defined in
+- * struct stun_header, and from the response we may just look at
+- * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
+- * By doing more transactions with different server addresses we
+- * may determine more about the behaviour of the NAT boxes, of
+- * course - the details are in the RFC.
+- *
+- * All STUN packets start with a simple header made of a type,
+- * length (excluding the header) and a 16-byte random transaction id.
+- * Following the header we may have zero or more attributes, each
+- * structured as a type, length and a value (whose format depends
+- * on the type, but often contains addresses).
+- * Of course all fields are in network format.
+- */
+-
+-typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
+-
+-struct stun_header {
+- unsigned short msgtype;
+- unsigned short msglen;
+- stun_trans_id id;
+- unsigned char ies[0];
+-} __attribute__((packed));
+-
+-struct stun_attr {
+- unsigned short attr;
+- unsigned short len;
+- unsigned char value[0];
+-} __attribute__((packed));
+-
+-/*
+- * The format normally used for addresses carried by STUN messages.
+- */
+-struct stun_addr {
+- unsigned char unused;
+- unsigned char family;
+- unsigned short port;
+- unsigned int addr;
+-} __attribute__((packed));
+-
+-#define STUN_IGNORE (0)
+-#define STUN_ACCEPT (1)
+-
+-/*! \brief STUN message types
+- * 'BIND' refers to transactions used to determine the externally
+- * visible addresses. 'SEC' refers to transactions used to establish
+- * a session key for subsequent requests.
+- * 'SEC' functionality is not supported here.
+- */
+-
+-#define STUN_BINDREQ 0x0001
+-#define STUN_BINDRESP 0x0101
+-#define STUN_BINDERR 0x0111
+-#define STUN_SECREQ 0x0002
+-#define STUN_SECRESP 0x0102
+-#define STUN_SECERR 0x0112
+-
+-/*! \brief Basic attribute types in stun messages.
+- * Messages can also contain custom attributes (codes above 0x7fff)
+- */
+-#define STUN_MAPPED_ADDRESS 0x0001
+-#define STUN_RESPONSE_ADDRESS 0x0002
+-#define STUN_CHANGE_REQUEST 0x0003
+-#define STUN_SOURCE_ADDRESS 0x0004
+-#define STUN_CHANGED_ADDRESS 0x0005
+-#define STUN_USERNAME 0x0006
+-#define STUN_PASSWORD 0x0007
+-#define STUN_MESSAGE_INTEGRITY 0x0008
+-#define STUN_ERROR_CODE 0x0009
+-#define STUN_UNKNOWN_ATTRIBUTES 0x000a
+-#define STUN_REFLECTED_FROM 0x000b
+-
+-/*! \brief helper function to print message names */
+-static const char *stun_msg2str(int msg)
+-{
+- switch (msg) {
+- case STUN_BINDREQ:
+- return "Binding Request";
+- case STUN_BINDRESP:
+- return "Binding Response";
+- case STUN_BINDERR:
+- return "Binding Error Response";
+- case STUN_SECREQ:
+- return "Shared Secret Request";
+- case STUN_SECRESP:
+- return "Shared Secret Response";
+- case STUN_SECERR:
+- return "Shared Secret Error Response";
+- }
+- return "Non-RFC3489 Message";
+-}
+-
+-/*! \brief helper function to print attribute names */
+-static const char *stun_attr2str(int msg)
+-{
+- switch (msg) {
+- case STUN_MAPPED_ADDRESS:
+- return "Mapped Address";
+- case STUN_RESPONSE_ADDRESS:
+- return "Response Address";
+- case STUN_CHANGE_REQUEST:
+- return "Change Request";
+- case STUN_SOURCE_ADDRESS:
+- return "Source Address";
+- case STUN_CHANGED_ADDRESS:
+- return "Changed Address";
+- case STUN_USERNAME:
+- return "Username";
+- case STUN_PASSWORD:
+- return "Password";
+- case STUN_MESSAGE_INTEGRITY:
+- return "Message Integrity";
+- case STUN_ERROR_CODE:
+- return "Error Code";
+- case STUN_UNKNOWN_ATTRIBUTES:
+- return "Unknown Attributes";
+- case STUN_REFLECTED_FROM:
+- return "Reflected From";
+- }
+- return "Non-RFC3489 Attribute";
+-}
+-
+-/*! \brief here we store credentials extracted from a message */
+-struct stun_state {
+- const char *username;
+- const char *password;
+-};
+-
+-static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
+-{
+- if (stundebug)
+- ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
+- stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
+- switch (ntohs(attr->attr)) {
+- case STUN_USERNAME:
+- state->username = (const char *) (attr->value);
+- break;
+- case STUN_PASSWORD:
+- state->password = (const char *) (attr->value);
+- break;
+- default:
+- if (stundebug)
+- ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
+- stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
+- }
+- return 0;
+-}
+-
+-/*! \brief append a string to an STUN message */
+-static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
+-{
+- int size = sizeof(**attr) + strlen(s);
+- if (*left > size) {
+- (*attr)->attr = htons(attrval);
+- (*attr)->len = htons(strlen(s));
+- memcpy((*attr)->value, s, strlen(s));
+- (*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
+- *len += size;
+- *left -= size;
+- }
+-}
+-
+-/*! \brief append an address to an STUN message */
+-static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sock_in, int *len, int *left)
+-{
+- int size = sizeof(**attr) + 8;
+- struct stun_addr *addr;
+- if (*left > size) {
+- (*attr)->attr = htons(attrval);
+- (*attr)->len = htons(8);
+- addr = (struct stun_addr *)((*attr)->value);
+- addr->unused = 0;
+- addr->family = 0x01;
+- addr->port = sock_in->sin_port;
+- addr->addr = sock_in->sin_addr.s_addr;
+- (*attr) = (struct stun_attr *)((*attr)->value + 8);
+- *len += size;
+- *left -= size;
+- }
+-}
+-
+-/*! \brief wrapper to send an STUN message */
+-static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
+-{
+- return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
+- (struct sockaddr *)dst, sizeof(*dst));
+-}
+-
+-/*! \brief helper function to generate a random request id */
+-static void stun_req_id(struct stun_header *req)
+-{
+- int x;
+- for (x = 0; x < 4; x++)
+- req->id.id[x] = ast_random();
+-}
+-
+-size_t ast_rtp_alloc_size(void)
+-{
+- return sizeof(struct ast_rtp);
+-}
+-
+-/*! \brief callback type to be invoked on stun responses. */
+-typedef int (stun_cb_f)(struct stun_attr *attr, void *arg);
+-
+-/*! \brief handle an incoming STUN message.
+- *
+- * Do some basic sanity checks on packet size and content,
+- * try to extract a bit of information, and possibly reply.
+- * At the moment this only processes BIND requests, and returns
+- * the externally visible address of the request.
+- * If a callback is specified, invoke it with the attribute.
+- */
+-static int stun_handle_packet(int s, struct sockaddr_in *src,
+- unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
+-{
+- struct stun_header *hdr = (struct stun_header *)data;
+- struct stun_attr *attr;
+- struct stun_state st;
+- int ret = STUN_IGNORE;
+- int x;
+-
+- /* On entry, 'len' is the length of the udp payload. After the
+- * initial checks it becomes the size of unprocessed options,
+- * while 'data' is advanced accordingly.
+- */
+- if (len < sizeof(struct stun_header)) {
+- ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
+- return -1;
+- }
+- len -= sizeof(struct stun_header);
+- data += sizeof(struct stun_header);
+- x = ntohs(hdr->msglen); /* len as advertised in the message */
+- if (stundebug)
+- ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
+- if (x > len) {
+- ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
+- } else
+- len = x;
+- memset(&st, 0, sizeof(st));
+- while (len) {
+- if (len < sizeof(struct stun_attr)) {
+- ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
+- break;
+- }
+- attr = (struct stun_attr *)data;
+- /* compute total attribute length */
+- x = ntohs(attr->len) + sizeof(struct stun_attr);
+- if (x > len) {
+- ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
+- break;
+- }
+- if (stun_cb)
+- stun_cb(attr, arg);
+- if (stun_process_attr(&st, attr)) {
+- ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
+- break;
+- }
+- /* Clear attribute id: in case previous entry was a string,
+- * this will act as the terminator for the string.
+- */
+- attr->attr = 0;
+- data += x;
+- len -= x;
+- }
+- /* Null terminate any string.
+- * XXX NOTE, we write past the size of the buffer passed by the
+- * caller, so this is potentially dangerous. The only thing that
+- * saves us is that usually we read the incoming message in a
+- * much larger buffer in the struct ast_rtp
+- */
+- *data = '\0';
+-
+- /* Now prepare to generate a reply, which at the moment is done
+- * only for properly formed (len == 0) STUN_BINDREQ messages.
+- */
+- if (len == 0) {
+- unsigned char respdata[1024];
+- struct stun_header *resp = (struct stun_header *)respdata;
+- int resplen = 0; /* len excluding header */
+- int respleft = sizeof(respdata) - sizeof(struct stun_header);
+-
+- resp->id = hdr->id;
+- resp->msgtype = 0;
+- resp->msglen = 0;
+- attr = (struct stun_attr *)resp->ies;
+- switch (ntohs(hdr->msgtype)) {
+- case STUN_BINDREQ:
+- if (stundebug)
+- ast_verbose("STUN Bind Request, username: %s\n",
+- st.username ? st.username : "<none>");
+- if (st.username)
+- append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
+- append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
+- resp->msglen = htons(resplen);
+- resp->msgtype = htons(STUN_BINDRESP);
+- stun_send(s, src, resp);
+- ret = STUN_ACCEPT;
+- break;
+- default:
+- if (stundebug)
+- ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
+- }
+- }
+- return ret;
+-}
+-
+-/*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
+- * This is used as a callback for stun_handle_response
+- * when called from ast_stun_request.
+- */
+-static int stun_get_mapped(struct stun_attr *attr, void *arg)
+-{
+- struct stun_addr *addr = (struct stun_addr *)(attr + 1);
+- struct sockaddr_in *sa = (struct sockaddr_in *)arg;
+-
+- if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
+- return 1; /* not us. */
+- sa->sin_port = addr->port;
+- sa->sin_addr.s_addr = addr->addr;
+- return 0;
+-}
+-
+-/*! \brief Generic STUN request
+- * Send a generic stun request to the server specified,
+- * possibly waiting for a reply and filling the 'reply' field with
+- * the externally visible address. Note that in this case the request
+- * will be blocking.
+- * (Note, the interface may change slightly in the future).
+- *
+- * \param s the socket used to send the request
+- * \param dst the address of the STUN server
+- * \param username if non null, add the username in the request
+- * \param answer if non null, the function waits for a response and
+- * puts here the externally visible address.
+- * \return 0 on success, other values on error.
+- */
+-int ast_stun_request(int s, struct sockaddr_in *dst,
+- const char *username, struct sockaddr_in *answer)
+-{
+- struct stun_header *req;
+- unsigned char reqdata[1024];
+- int reqlen, reqleft;
+- struct stun_attr *attr;
+- int res = 0;
+- int retry;
+-
+- req = (struct stun_header *)reqdata;
+- stun_req_id(req);
+- reqlen = 0;
+- reqleft = sizeof(reqdata) - sizeof(struct stun_header);
+- req->msgtype = 0;
+- req->msglen = 0;
+- attr = (struct stun_attr *)req->ies;
+- if (username)
+- append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
+- req->msglen = htons(reqlen);
+- req->msgtype = htons(STUN_BINDREQ);
+- for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
+- /* send request, possibly wait for reply */
+- unsigned char reply_buf[1024];
+- fd_set rfds;
+- struct timeval to = { 3, 0 }; /* timeout, make it configurable */
+- struct sockaddr_in src;
+- socklen_t srclen;
+-
+- res = stun_send(s, dst, req);
+- if (res < 0) {
+- ast_log(LOG_WARNING, "ast_stun_request send #%d failed error %d, retry\n",
+- retry, res);
+- continue;
+- }
+- if (answer == NULL)
+- break;
+- FD_ZERO(&rfds);
+- FD_SET(s, &rfds);
+- res = ast_select(s + 1, &rfds, NULL, NULL, &to);
+- if (res <= 0) /* timeout or error */
+- continue;
+- memset(&src, '\0', sizeof(src));
+- srclen = sizeof(src);
+- /* XXX pass -1 in the size, because stun_handle_packet might
+- * write past the end of the buffer.
+- */
+- res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1,
+- 0, (struct sockaddr *)&src, &srclen);
+- if (res < 0) {
+- ast_log(LOG_WARNING, "ast_stun_request recvfrom #%d failed error %d, retry\n",
+- retry, res);
+- continue;
+- }
+- memset(answer, '\0', sizeof(struct sockaddr_in));
+- stun_handle_packet(s, &src, reply_buf, res,
+- stun_get_mapped, answer);
+- res = 0; /* signal regular exit */
+- break;
+- }
+- return res;
+-}
+-
+-/*! \brief send a STUN BIND request to the given destination.
+- * Optionally, add a username if specified.
+- */
+-void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username)
+-{
+- ast_stun_request(rtp->s, suggestion, username, NULL);
+-}
+-
+-/*! \brief List of current sessions */
+-static AST_RWLIST_HEAD_STATIC(protos, ast_rtp_protocol);
+-
+-static void timeval2ntp(struct timeval when, unsigned int *msw, unsigned int *lsw)
+-{
+- unsigned int sec, usec, frac;
+- sec = when.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */
+- usec = when.tv_usec;
+- frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6);
+- *msw = sec;
+- *lsw = frac;
+-}
+-
+-int ast_rtp_fd(struct ast_rtp *rtp)
+-{
+- return rtp->s;
+-}
+-
+-int ast_rtcp_fd(struct ast_rtp *rtp)
+-{
+- if (rtp->rtcp)
+- return rtp->rtcp->s;
+- return -1;
+-}
+-
+-unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp)
+-{
+- unsigned int interval;
+- /*! \todo XXX Do a more reasonable calculation on this one
+- * Look in RFC 3550 Section A.7 for an example*/
+- interval = rtcpinterval;
+- return interval;
+-}
+-
+-/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
+-void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp)
+-{
+- rtp->rtptimeout = (-1) * rtp->rtptimeout;
+- rtp->rtpholdtimeout = (-1) * rtp->rtpholdtimeout;
+-}
+-
+-/*! \brief Set rtp timeout */
+-void ast_rtp_set_rtptimeout(struct ast_rtp *rtp, int timeout)
+-{
+- rtp->rtptimeout = timeout;
+-}
+-
+-/*! \brief Set rtp hold timeout */
+-void ast_rtp_set_rtpholdtimeout(struct ast_rtp *rtp, int timeout)
+-{
+- rtp->rtpholdtimeout = timeout;
+-}
+-
+-/*! \brief set RTP keepalive interval */
+-void ast_rtp_set_rtpkeepalive(struct ast_rtp *rtp, int period)
+-{
+- rtp->rtpkeepalive = period;
+-}
+-
+-/*! \brief Get rtp timeout */
+-int ast_rtp_get_rtptimeout(struct ast_rtp *rtp)
+-{
+- if (rtp->rtptimeout < 0) /* We're not checking, but remembering the setting (during T.38 transmission) */
+- return 0;
+- return rtp->rtptimeout;
+-}
+-
+-/*! \brief Get rtp hold timeout */
+-int ast_rtp_get_rtpholdtimeout(struct ast_rtp *rtp)
+-{
+- if (rtp->rtptimeout < 0) /* We're not checking, but remembering the setting (during T.38 transmission) */
+- return 0;
+- return rtp->rtpholdtimeout;
+-}
+-
+-/*! \brief Get RTP keepalive interval */
+-int ast_rtp_get_rtpkeepalive(struct ast_rtp *rtp)
+-{
+- return rtp->rtpkeepalive;
+-}
+-
+-void ast_rtp_set_data(struct ast_rtp *rtp, void *data)
+-{
+- rtp->data = data;
+-}
+-
+-void ast_rtp_set_callback(struct ast_rtp *rtp, ast_rtp_callback callback)
+-{
+- rtp->callback = callback;
+-}
+-
+-void ast_rtp_setnat(struct ast_rtp *rtp, int nat)
+-{
+- rtp->nat = nat;
+-}
+-
+-int ast_rtp_getnat(struct ast_rtp *rtp)
+-{
+- return ast_test_flag(rtp, FLAG_NAT_ACTIVE);
+-}
+-
+-void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf)
+-{
+- ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF);
+-}
+-
+-void ast_rtp_setdtmfcompensate(struct ast_rtp *rtp, int compensate)
+-{
+- ast_set2_flag(rtp, compensate ? 1 : 0, FLAG_DTMF_COMPENSATE);
+-}
+-
+-void ast_rtp_setstun(struct ast_rtp *rtp, int stun_enable)
+-{
+- ast_set2_flag(rtp, stun_enable ? 1 : 0, FLAG_HAS_STUN);
+-}
+-
+-static void rtp_bridge_lock(struct ast_rtp *rtp)
+-{
+-#ifdef P2P_INTENSE
+- ast_mutex_lock(&rtp->bridge_lock);
+-#endif
+- return;
+-}
+-
+-static void rtp_bridge_unlock(struct ast_rtp *rtp)
+-{
+-#ifdef P2P_INTENSE
+- ast_mutex_unlock(&rtp->bridge_lock);
+-#endif
+- return;
+-}
+-
+-/*! \brief Calculate normal deviation */
+-static double normdev_compute(double normdev, double sample, unsigned int sample_count)
+-{
+- normdev = normdev * sample_count + sample;
+- sample_count++;
+-
+- return normdev / sample_count;
+-}
+-
+-static double stddev_compute(double stddev, double sample, double normdev, double normdev_curent, unsigned int sample_count)
+-{
+-/*
+- for the formula check http://www.cs.umd.edu/~austinjp/constSD.pdf
+- return sqrt( (sample_count*pow(stddev,2) + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1));
+- we can compute the sigma^2 and that way we would have to do the sqrt only 1 time at the end and would save another pow 2 compute
+- optimized formula
+-*/
+-#define SQUARE(x) ((x) * (x))
+-
+- stddev = sample_count * stddev;
+- sample_count++;
+-
+- return stddev +
+- ( sample_count * SQUARE( (sample - normdev) / sample_count ) ) +
+- ( SQUARE(sample - normdev_curent) / sample_count );
+-
+-#undef SQUARE
+-}
+-
+-static struct ast_frame *send_dtmf(struct ast_rtp *rtp, enum ast_frame_type type)
+-{
+- if (((ast_test_flag(rtp, FLAG_DTMF_COMPENSATE) && type == AST_FRAME_DTMF_END) ||
+- (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
+- ast_debug(1, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(rtp->them.sin_addr));
+- rtp->resp = 0;
+- rtp->dtmfsamples = 0;
+- return &ast_null_frame;
+- }
+- ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(rtp->them.sin_addr));
+- if (rtp->resp == 'X') {
+- rtp->f.frametype = AST_FRAME_CONTROL;
+- rtp->f.subclass = AST_CONTROL_FLASH;
+- } else {
+- rtp->f.frametype = type;
+- rtp->f.subclass = rtp->resp;
+- }
+- rtp->f.datalen = 0;
+- rtp->f.samples = 0;
+- rtp->f.mallocd = 0;
+- rtp->f.src = "RTP";
+- return &rtp->f;
+-
+-}
+-
+-static inline int rtp_debug_test_addr(struct sockaddr_in *addr)
+-{
+- if (rtpdebug == 0)
+- return 0;
+- if (rtpdebugaddr.sin_addr.s_addr) {
+- if (((ntohs(rtpdebugaddr.sin_port) != 0)
+- && (rtpdebugaddr.sin_port != addr->sin_port))
+- || (rtpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
+- return 0;
+- }
+- return 1;
+-}
+-
+-static inline int rtcp_debug_test_addr(struct sockaddr_in *addr)
+-{
+- if (rtcpdebug == 0)
+- return 0;
+- if (rtcpdebugaddr.sin_addr.s_addr) {
+- if (((ntohs(rtcpdebugaddr.sin_port) != 0)
+- && (rtcpdebugaddr.sin_port != addr->sin_port))
+- || (rtcpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
+- return 0;
+- }
+- return 1;
+-}
+-
+-
+-static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *data, int len)
+-{
+- unsigned int event;
+- char resp = 0;
+- struct ast_frame *f = NULL;
+- unsigned char seq;
+- unsigned int flags;
+- unsigned int power;
+-
+- /* We should have at least 4 bytes in RTP data */
+- if (len < 4)
+- return f;
+-
+- /* The format of Cisco RTP DTMF packet looks like next:
+- +0 - sequence number of DTMF RTP packet (begins from 1,
+- wrapped to 0)
+- +1 - set of flags
+- +1 (bit 0) - flaps by different DTMF digits delimited by audio
+- or repeated digit without audio???
+- +2 (+4,+6,...) - power level? (rises from 0 to 32 at begin of tone
+- then falls to 0 at its end)
+- +3 (+5,+7,...) - detected DTMF digit (0..9,*,#,A-D,...)
+- Repeated DTMF information (bytes 4/5, 6/7) is history shifted right
+- by each new packet and thus provides some redudancy.
+-
+- Sample of Cisco RTP DTMF packet is (all data in hex):
+- 19 07 00 02 12 02 20 02
+- showing end of DTMF digit '2'.
+-
+- The packets
+- 27 07 00 02 0A 02 20 02
+- 28 06 20 02 00 02 0A 02
+- shows begin of new digit '2' with very short pause (20 ms) after
+- previous digit '2'. Bit +1.0 flips at begin of new digit.
+-
+- Cisco RTP DTMF packets comes as replacement of audio RTP packets
+- so its uses the same sequencing and timestamping rules as replaced
+- audio packets. Repeat interval of DTMF packets is 20 ms and not rely
+- on audio framing parameters. Marker bit isn't used within stream of
+- DTMFs nor audio stream coming immediately after DTMF stream. Timestamps
+- are not sequential at borders between DTMF and audio streams,
+- */
+-
+- seq = data[0];
+- flags = data[1];
+- power = data[2];
+- event = data[3] & 0x1f;
+-
+- if (option_debug > 2 || rtpdebug)
+- ast_debug(0, "Cisco DTMF Digit: %02x (len=%d, seq=%d, flags=%02x, power=%d, history count=%d)\n", event, len, seq, flags, power, (len - 4) / 2);
+- if (event < 10) {
+- resp = '0' + event;
+- } else if (event < 11) {
+- resp = '*';
+- } else if (event < 12) {
+- resp = '#';
+- } else if (event < 16) {
+- resp = 'A' + (event - 12);
+- } else if (event < 17) {
+- resp = 'X';
+- }
+- if ((!rtp->resp && power) || (rtp->resp && (rtp->resp != resp))) {
+- rtp->resp = resp;
+- /* Why we should care on DTMF compensation at reception? */
+- if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE)) {
+- f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
+- rtp->dtmfsamples = 0;
+- }
+- } else if ((rtp->resp == resp) && !power) {
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->samples = rtp->dtmfsamples * 8;
+- rtp->resp = 0;
+- } else if (rtp->resp == resp)
+- rtp->dtmfsamples += 20 * 8;
+- rtp->dtmfcount = dtmftimeout;
+- return f;
+-}
+-
+-/*!
+- * \brief Process RTP DTMF and events according to RFC 2833.
+- *
+- * RFC 2833 is "RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals".
+- *
+- * \param rtp
+- * \param data
+- * \param len
+- * \param seqno
+- * \param timestamp
+- * \returns
+- */
+-static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp)
+-{
+- unsigned int event;
+- unsigned int event_end;
+- unsigned int samples;
+- char resp = 0;
+- struct ast_frame *f = NULL;
+-
+- /* Figure out event, event end, and samples */
+- event = ntohl(*((unsigned int *)(data)));
+- event >>= 24;
+- event_end = ntohl(*((unsigned int *)(data)));
+- event_end <<= 8;
+- event_end >>= 24;
+- samples = ntohl(*((unsigned int *)(data)));
+- samples &= 0xFFFF;
+-
+- /* Print out debug if turned on */
+- if (rtpdebug || option_debug > 2)
+- ast_debug(0, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
+-
+- /* Figure out what digit was pressed */
+- if (event < 10) {
+- resp = '0' + event;
+- } else if (event < 11) {
+- resp = '*';
+- } else if (event < 12) {
+- resp = '#';
+- } else if (event < 16) {
+- resp = 'A' + (event - 12);
+- } else if (event < 17) { /* Event 16: Hook flash */
+- resp = 'X';
+- } else {
+- /* Not a supported event */
+- ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
+- return &ast_null_frame;
+- }
+-
+- if (ast_test_flag(rtp, FLAG_DTMF_COMPENSATE)) {
+- if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
+- rtp->resp = resp;
+- rtp->dtmfcount = 0;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->len = 0;
+- rtp->lastevent = timestamp;
+- }
+- } else {
+- if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
+- rtp->resp = resp;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
+- rtp->dtmfcount = dtmftimeout;
+- } else if ((event_end & 0x80) && (rtp->lastevent != seqno) && rtp->resp) {
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */
+- rtp->resp = 0;
+- rtp->dtmfcount = 0;
+- rtp->lastevent = seqno;
+- }
+- }
+-
+- rtp->dtmfsamples = samples;
+-
+- return f;
+-}
+-
+-/*!
+- * \brief Process Comfort Noise RTP.
+- *
+- * This is incomplete at the moment.
+- *
+-*/
+-static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *data, int len)
+-{
+- struct ast_frame *f = NULL;
+- /* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
+- totally help us out becuase we don't have an engine to keep it going and we are not
+- guaranteed to have it every 20ms or anything */
+- if (rtpdebug)
+- ast_debug(0, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", rtp->lastrxformat, len);
+-
+- if (!(ast_test_flag(rtp, FLAG_3389_WARNING))) {
+- ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s\n",
+- ast_inet_ntoa(rtp->them.sin_addr));
+- ast_set_flag(rtp, FLAG_3389_WARNING);
+- }
+-
+- /* Must have at least one byte */
+- if (!len)
+- return NULL;
+- if (len < 24) {
+- rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
+- rtp->f.datalen = len - 1;
+- rtp->f.offset = AST_FRIENDLY_OFFSET;
+- memcpy(rtp->f.data.ptr, data + 1, len - 1);
+- } else {
+- rtp->f.data.ptr = NULL;
+- rtp->f.offset = 0;
+- rtp->f.datalen = 0;
+- }
+- rtp->f.frametype = AST_FRAME_CNG;
+- rtp->f.subclass = data[0] & 0x7f;
+- rtp->f.datalen = len - 1;
+- rtp->f.samples = 0;
+- rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
+- f = &rtp->f;
+- return f;
+-}
+-
+-static int rtpread(int *id, int fd, short events, void *cbdata)
+-{
+- struct ast_rtp *rtp = cbdata;
+- struct ast_frame *f;
+- f = ast_rtp_read(rtp);
+- if (f) {
+- if (rtp->callback)
+- rtp->callback(rtp, f, rtp->data);
+- }
+- return 1;
+-}
+-
+-struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
+-{
+- socklen_t len;
+- int position, i, packetwords;
+- int res;
+- struct sockaddr_in sock_in;
+- unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
+- unsigned int *rtcpheader;
+- int pt;
+- struct timeval now;
+- unsigned int length;
+- int rc;
+- double rttsec;
+- uint64_t rtt = 0;
+- unsigned int dlsr;
+- unsigned int lsr;
+- unsigned int msw;
+- unsigned int lsw;
+- unsigned int comp;
+- struct ast_frame *f = &ast_null_frame;
+-
+- double reported_jitter;
+- double reported_normdev_jitter_current;
+- double normdevrtt_current;
+- double reported_lost;
+- double reported_normdev_lost_current;
+-
+- if (!rtp || !rtp->rtcp)
+- return &ast_null_frame;
+-
+- len = sizeof(sock_in);
+-
+- res = recvfrom(rtp->rtcp->s, rtcpdata + AST_FRIENDLY_OFFSET, sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET,
+- 0, (struct sockaddr *)&sock_in, &len);
+- rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
+-
+- if (res < 0) {
+- ast_assert(errno != EBADF);
+- if (errno != EAGAIN) {
+- ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", strerror(errno));
+- return NULL;
+- }
+- return &ast_null_frame;
+- }
+-
+- packetwords = res / 4;
+-
+- if (rtp->nat) {
+- /* Send to whoever sent to us */
+- if ((rtp->rtcp->them.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
+- (rtp->rtcp->them.sin_port != sock_in.sin_port)) {
+- memcpy(&rtp->rtcp->them, &sock_in, sizeof(rtp->rtcp->them));
+- if (option_debug || rtpdebug)
+- ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
+- }
+- }
+-
+- ast_debug(1, "Got RTCP report of %d bytes\n", res);
+-
+- /* Process a compound packet */
+- position = 0;
+- while (position < packetwords) {
+- i = position;
+- length = ntohl(rtcpheader[i]);
+- pt = (length & 0xff0000) >> 16;
+- rc = (length & 0x1f000000) >> 24;
+- length &= 0xffff;
+-
+- if ((i + length) > packetwords) {
+- if (option_debug || rtpdebug)
+- ast_log(LOG_DEBUG, "RTCP Read too short\n");
+- return &ast_null_frame;
+- }
+-
+- if (rtcp_debug_test_addr(&sock_in)) {
+- ast_verbose("\n\nGot RTCP from %s:%d\n", ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port));
+- ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown");
+- ast_verbose("Reception reports: %d\n", rc);
+- ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
+- }
+-
+- i += 2; /* Advance past header and ssrc */
+-
+- switch (pt) {
+- case RTCP_PT_SR:
+- gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
+- rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
+- rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
+- rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
+-
+- if (rtcp_debug_test_addr(&sock_in)) {
+- ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096);
+- ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2]));
+- ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
+- }
+- i += 5;
+- if (rc < 1)
+- break;
+- /* Intentional fall through */
+- case RTCP_PT_RR:
+- /* Don't handle multiple reception reports (rc > 1) yet */
+- /* Calculate RTT per RFC */
+- gettimeofday(&now, NULL);
+- timeval2ntp(now, &msw, &lsw);
+- if (ntohl(rtcpheader[i + 4]) && ntohl(rtcpheader[i + 5])) { /* We must have the LSR && DLSR */
+- comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
+- lsr = ntohl(rtcpheader[i + 4]);
+- dlsr = ntohl(rtcpheader[i + 5]);
+- rtt = comp - lsr - dlsr;
+-
+- /* Convert end to end delay to usec (keeping the calculation in 64bit space)
+- sess->ee_delay = (eedelay * 1000) / 65536; */
+- if (rtt < 4294) {
+- rtt = (rtt * 1000000) >> 16;
+- } else {
+- rtt = (rtt * 1000) >> 16;
+- rtt *= 1000;
+- }
+- rtt = rtt / 1000.;
+- rttsec = rtt / 1000.;
+- rtp->rtcp->rtt = rttsec;
+-
+- if (comp - dlsr >= lsr) {
+- rtp->rtcp->accumulated_transit += rttsec;
+-
+- if (rtp->rtcp->rtt_count == 0)
+- rtp->rtcp->minrtt = rttsec;
+-
+- if (rtp->rtcp->maxrtt<rttsec)
+- rtp->rtcp->maxrtt = rttsec;
+-
+- if (rtp->rtcp->minrtt>rttsec)
+- rtp->rtcp->minrtt = rttsec;
+-
+- normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);
+-
+- rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);
+-
+- rtp->rtcp->normdevrtt = normdevrtt_current;
+-
+- rtp->rtcp->rtt_count++;
+- } else if (rtcp_debug_test_addr(&sock_in)) {
+- ast_verbose("Internal RTCP NTP clock skew detected: "
+- "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
+- "diff=%d\n",
+- lsr, comp, dlsr, dlsr / 65536,
+- (dlsr % 65536) * 1000 / 65536,
+- dlsr - (comp - lsr));
+- }
+- }
+-
+- rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
+- reported_jitter = (double) rtp->rtcp->reported_jitter;
+-
+- if (rtp->rtcp->reported_jitter_count == 0)
+- rtp->rtcp->reported_minjitter = reported_jitter;
+-
+- if (reported_jitter < rtp->rtcp->reported_minjitter)
+- rtp->rtcp->reported_minjitter = reported_jitter;
+-
+- if (reported_jitter > rtp->rtcp->reported_maxjitter)
+- rtp->rtcp->reported_maxjitter = reported_jitter;
+-
+- reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
+-
+- rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
+-
+- rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
+-
+- rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
+-
+- reported_lost = (double) rtp->rtcp->reported_lost;
+-
+- /* using same counter as for jitter */
+- if (rtp->rtcp->reported_jitter_count == 0)
+- rtp->rtcp->reported_minlost = reported_lost;
+-
+- if (reported_lost < rtp->rtcp->reported_minlost)
+- rtp->rtcp->reported_minlost = reported_lost;
+-
+- if (reported_lost > rtp->rtcp->reported_maxlost)
+- rtp->rtcp->reported_maxlost = reported_lost;
+-
+- reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
+-
+- rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
+-
+- rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
+-
+- rtp->rtcp->reported_jitter_count++;
+-
+- if (rtcp_debug_test_addr(&sock_in)) {
+- ast_verbose(" Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
+- ast_verbose(" Packets lost so far: %d\n", rtp->rtcp->reported_lost);
+- ast_verbose(" Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
+- ast_verbose(" Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16);
+- ast_verbose(" Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
+- ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
+- ast_verbose(" DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
+- if (rtt)
+- ast_verbose(" RTT: %lu(sec)\n", (unsigned long) rtt);
+- }
+-
+- if (rtt) {
+- manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s:%d\r\n"
+- "PT: %d(%s)\r\n"
+- "ReceptionReports: %d\r\n"
+- "SenderSSRC: %u\r\n"
+- "FractionLost: %ld\r\n"
+- "PacketsLost: %d\r\n"
+- "HighestSequence: %ld\r\n"
+- "SequenceNumberCycles: %ld\r\n"
+- "IAJitter: %u\r\n"
+- "LastSR: %lu.%010lu\r\n"
+- "DLSR: %4.4f(sec)\r\n"
+- "RTT: %llu(sec)\r\n",
+- ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port),
+- pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
+- rc,
+- rtcpheader[i + 1],
+- (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
+- rtp->rtcp->reported_lost,
+- (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
+- (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16,
+- rtp->rtcp->reported_jitter,
+- (unsigned long) ntohl(rtcpheader[i + 4]) >> 16, ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
+- ntohl(rtcpheader[i + 5])/65536.0,
+- (unsigned long long)rtt);
+- } else {
+- manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s:%d\r\n"
+- "PT: %d(%s)\r\n"
+- "ReceptionReports: %d\r\n"
+- "SenderSSRC: %u\r\n"
+- "FractionLost: %ld\r\n"
+- "PacketsLost: %d\r\n"
+- "HighestSequence: %ld\r\n"
+- "SequenceNumberCycles: %ld\r\n"
+- "IAJitter: %u\r\n"
+- "LastSR: %lu.%010lu\r\n"
+- "DLSR: %4.4f(sec)\r\n",
+- ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port),
+- pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
+- rc,
+- rtcpheader[i + 1],
+- (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
+- rtp->rtcp->reported_lost,
+- (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
+- (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16,
+- rtp->rtcp->reported_jitter,
+- (unsigned long) ntohl(rtcpheader[i + 4]) >> 16,
+- ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
+- ntohl(rtcpheader[i + 5])/65536.0);
+- }
+- break;
+- case RTCP_PT_FUR:
+- if (rtcp_debug_test_addr(&sock_in))
+- ast_verbose("Received an RTCP Fast Update Request\n");
+- rtp->f.frametype = AST_FRAME_CONTROL;
+- rtp->f.subclass = AST_CONTROL_VIDUPDATE;
+- rtp->f.datalen = 0;
+- rtp->f.samples = 0;
+- rtp->f.mallocd = 0;
+- rtp->f.src = "RTP";
+- f = &rtp->f;
+- break;
+- case RTCP_PT_SDES:
+- if (rtcp_debug_test_addr(&sock_in))
+- ast_verbose("Received an SDES from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
+- break;
+- case RTCP_PT_BYE:
+- if (rtcp_debug_test_addr(&sock_in))
+- ast_verbose("Received a BYE from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
+- break;
+- default:
+- ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s:%d\n", pt, ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
+- break;
+- }
+- position += (length + 1);
+- }
+- rtp->rtcp->rtcp_info = 1;
+- return f;
+-}
+-
+-static void calc_rxstamp(struct timeval *when, struct ast_rtp *rtp, unsigned int timestamp, int mark)
+-{
+- struct timeval now;
+- double transit;
+- double current_time;
+- double d;
+- double dtv;
+- double prog;
+-
+- double normdev_rxjitter_current;
+- if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
+- gettimeofday(&rtp->rxcore, NULL);
+- rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
+- /* map timestamp to a real time */
+- rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */
+- rtp->rxcore.tv_sec -= timestamp / 8000;
+- rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
+- /* Round to 0.1ms for nice, pretty timestamps */
+- rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
+- if (rtp->rxcore.tv_usec < 0) {
+- /* Adjust appropriately if necessary */
+- rtp->rxcore.tv_usec += 1000000;
+- rtp->rxcore.tv_sec -= 1;
+- }
+- }
+-
+- gettimeofday(&now,NULL);
+- /* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
+- when->tv_sec = rtp->rxcore.tv_sec + timestamp / 8000;
+- when->tv_usec = rtp->rxcore.tv_usec + (timestamp % 8000) * 125;
+- if (when->tv_usec >= 1000000) {
+- when->tv_usec -= 1000000;
+- when->tv_sec += 1;
+- }
+- prog = (double)((timestamp-rtp->seedrxts)/8000.);
+- dtv = (double)rtp->drxcore + (double)(prog);
+- current_time = (double)now.tv_sec + (double)now.tv_usec/1000000;
+- transit = current_time - dtv;
+- d = transit - rtp->rxtransit;
+- rtp->rxtransit = transit;
+- if (d<0)
+- d=-d;
+- rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
+- if (rtp->rtcp && rtp->rxjitter > rtp->rtcp->maxrxjitter)
+- rtp->rtcp->maxrxjitter = rtp->rxjitter;
+- if (rtp->rtcp->rxjitter_count == 1)
+- rtp->rtcp->minrxjitter = rtp->rxjitter;
+- if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter)
+- rtp->rtcp->minrxjitter = rtp->rxjitter;
+-
+- normdev_rxjitter_current = normdev_compute(rtp->rtcp->normdev_rxjitter,rtp->rxjitter,rtp->rtcp->rxjitter_count);
+- rtp->rtcp->stdev_rxjitter = stddev_compute(rtp->rtcp->stdev_rxjitter,rtp->rxjitter,rtp->rtcp->normdev_rxjitter,normdev_rxjitter_current,rtp->rtcp->rxjitter_count);
+-
+- rtp->rtcp->normdev_rxjitter = normdev_rxjitter_current;
+- rtp->rtcp->rxjitter_count++;
+-}
+-
+-/*! \brief Perform a Packet2Packet RTP write */
+-static int bridge_p2p_rtp_write(struct ast_rtp *rtp, struct ast_rtp *bridged, unsigned int *rtpheader, int len, int hdrlen)
+-{
+- int res = 0, payload = 0, bridged_payload = 0, mark;
+- struct rtpPayloadType rtpPT;
+- int reconstruct = ntohl(rtpheader[0]);
+-
+- /* Get fields from packet */
+- payload = (reconstruct & 0x7f0000) >> 16;
+- mark = (((reconstruct & 0x800000) >> 23) != 0);
+-
+- /* Check what the payload value should be */
+- rtpPT = ast_rtp_lookup_pt(rtp, payload);
+-
+- /* If the payload is DTMF, and we are listening for DTMF - then feed it into the core */
+- if (ast_test_flag(rtp, FLAG_P2P_NEED_DTMF) && !rtpPT.isAstFormat && rtpPT.code == AST_RTP_DTMF)
+- return -1;
+-
+- /* Otherwise adjust bridged payload to match */
+- bridged_payload = ast_rtp_lookup_code(bridged, rtpPT.isAstFormat, rtpPT.code);
+-
+- /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */
+- if (!bridged->current_RTP_PT[bridged_payload].code)
+- return -1;
+-
+-
+- /* If the mark bit has not been sent yet... do it now */
+- if (!ast_test_flag(rtp, FLAG_P2P_SENT_MARK)) {
+- mark = 1;
+- ast_set_flag(rtp, FLAG_P2P_SENT_MARK);
+- }
+-
+- /* Reconstruct part of the packet */
+- reconstruct &= 0xFF80FFFF;
+- reconstruct |= (bridged_payload << 16);
+- reconstruct |= (mark << 23);
+- rtpheader[0] = htonl(reconstruct);
+-
+- /* Send the packet back out */
+- res = sendto(bridged->s, (void *)rtpheader, len, 0, (struct sockaddr *)&bridged->them, sizeof(bridged->them));
+- if (res < 0) {
+- if (!bridged->nat || (bridged->nat && (ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
+- ast_debug(1, "RTP Transmission error of packet to %s:%d: %s\n", ast_inet_ntoa(bridged->them.sin_addr), ntohs(bridged->them.sin_port), strerror(errno));
+- } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
+- if (option_debug || rtpdebug)
+- ast_debug(0, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(bridged->them.sin_addr), ntohs(bridged->them.sin_port));
+- ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN);
+- }
+- return 0;
+- } else if (rtp_debug_test_addr(&bridged->them))
+- ast_verbose("Sent RTP P2P packet to %s:%u (type %-2.2d, len %-6.6u)\n", ast_inet_ntoa(bridged->them.sin_addr), ntohs(bridged->them.sin_port), bridged_payload, len - hdrlen);
+-
+- return 0;
+-}
+-
+-struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
+-{
+- int res;
+- struct sockaddr_in sock_in;
+- socklen_t len;
+- unsigned int seqno;
+- int version;
+- int payloadtype;
+- int hdrlen = 12;
+- int padding;
+- int mark;
+- int ext;
+- int cc;
+- unsigned int ssrc;
+- unsigned int timestamp;
+- unsigned int *rtpheader;
+- struct rtpPayloadType rtpPT;
+- struct ast_rtp *bridged = NULL;
+- int prev_seqno;
+-
+- /* If time is up, kill it */
+- if (rtp->sending_digit)
+- ast_rtp_senddigit_continuation(rtp);
+-
+- len = sizeof(sock_in);
+-
+- /* Cache where the header will go */
+- res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
+- 0, (struct sockaddr *)&sock_in, &len);
+-
+- /* If strict RTP protection is enabled see if we need to learn this address or if the packet should be dropped */
+- if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
+- /* Copy over address that this packet was received on */
+- memcpy(&rtp->strict_rtp_address, &sock_in, sizeof(rtp->strict_rtp_address));
+- /* Now move over to actually protecting the RTP port */
+- rtp->strict_rtp_state = STRICT_RTP_CLOSED;
+- ast_debug(1, "Learned remote address is %s:%d for strict RTP purposes, now protecting the port.\n", ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
+- } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
+- /* If the address we previously learned doesn't match the address this packet came in on simply drop it */
+- if ((rtp->strict_rtp_address.sin_addr.s_addr != sock_in.sin_addr.s_addr) || (rtp->strict_rtp_address.sin_port != sock_in.sin_port)) {
+- ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
+- return &ast_null_frame;
+- }
+- }
+-
+- rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
+- if (res < 0) {
+- ast_assert(errno != EBADF);
+- if (errno != EAGAIN) {
+- ast_log(LOG_WARNING, "RTP Read error: %s. Hanging up.\n", strerror(errno));
+- return NULL;
+- }
+- return &ast_null_frame;
+- }
+-
+- if (res < hdrlen) {
+- ast_log(LOG_WARNING, "RTP Read too short\n");
+- return &ast_null_frame;
+- }
+-
+- /* Get fields */
+- seqno = ntohl(rtpheader[0]);
+-
+- /* Check RTP version */
+- version = (seqno & 0xC0000000) >> 30;
+- if (!version) {
+- /* If the two high bits are 0, this might be a
+- * STUN message, so process it. stun_handle_packet()
+- * answers to requests, and it returns STUN_ACCEPT
+- * if the request is valid.
+- */
+- if ((stun_handle_packet(rtp->s, &sock_in, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == STUN_ACCEPT) &&
+- (!rtp->them.sin_port && !rtp->them.sin_addr.s_addr)) {
+- memcpy(&rtp->them, &sock_in, sizeof(rtp->them));
+- }
+- return &ast_null_frame;
+- }
+-
+-#if 0 /* Allow to receive RTP stream with closed transmission path */
+- /* If we don't have the other side's address, then ignore this */
+- if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
+- return &ast_null_frame;
+-#endif
+-
+- /* Send to whoever send to us if NAT is turned on */
+- if (rtp->nat) {
+- if ((rtp->them.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
+- (rtp->them.sin_port != sock_in.sin_port)) {
+- rtp->them = sock_in;
+- if (rtp->rtcp) {
+- int h = 0;
+- memcpy(&rtp->rtcp->them, &sock_in, sizeof(rtp->rtcp->them));
+- h = ntohs(rtp->them.sin_port);
+- rtp->rtcp->them.sin_port = htons(h + 1);
+- }
+- rtp->rxseqno = 0;
+- ast_set_flag(rtp, FLAG_NAT_ACTIVE);
+- if (option_debug || rtpdebug)
+- ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s:%d\n", ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
+- }
+- }
+-
+- /* If we are bridged to another RTP stream, send direct */
+- if ((bridged = ast_rtp_get_bridged(rtp)) && !bridge_p2p_rtp_write(rtp, bridged, rtpheader, res, hdrlen))
+- return &ast_null_frame;
+-
+- if (version != 2)
+- return &ast_null_frame;
+-
+- payloadtype = (seqno & 0x7f0000) >> 16;
+- padding = seqno & (1 << 29);
+- mark = seqno & (1 << 23);
+- ext = seqno & (1 << 28);
+- cc = (seqno & 0xF000000) >> 24;
+- seqno &= 0xffff;
+- timestamp = ntohl(rtpheader[1]);
+- ssrc = ntohl(rtpheader[2]);
+-
+- if (!mark && rtp->rxssrc && rtp->rxssrc != ssrc) {
+- if (option_debug || rtpdebug)
+- ast_debug(0, "Forcing Marker bit, because SSRC has changed\n");
+- mark = 1;
+- }
+-
+- rtp->rxssrc = ssrc;
+-
+- if (padding) {
+- /* Remove padding bytes */
+- res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
+- }
+-
+- if (cc) {
+- /* CSRC fields present */
+- hdrlen += cc*4;
+- }
+-
+- if (ext) {
+- /* RTP Extension present */
+- hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;
+- hdrlen += 4;
+- if (option_debug) {
+- int profile;
+- profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;
+- if (profile == 0x505a)
+- ast_debug(1, "Found Zfone extension in RTP stream - zrtp - not supported.\n");
+- else
+- ast_debug(1, "Found unknown RTP Extensions %x\n", profile);
+- }
+- }
+-
+- if (res < hdrlen) {
+- ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d)\n", res, hdrlen);
+- return &ast_null_frame;
+- }
+-
+- rtp->rxcount++; /* Only count reasonably valid packets, this'll make the rtcp stats more accurate */
+-
+- if (rtp->rxcount==1) {
+- /* This is the first RTP packet successfully received from source */
+- rtp->seedrxseqno = seqno;
+- }
+-
+- /* Do not schedule RR if RTCP isn't run */
+- if (rtp->rtcp && rtp->rtcp->them.sin_addr.s_addr && rtp->rtcp->schedid < 1) {
+- /* Schedule transmission of Receiver Report */
+- rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
+- }
+- if ((int)rtp->lastrxseqno - (int)seqno > 100) /* if so it would indicate that the sender cycled; allow for misordering */
+- rtp->cycles += RTP_SEQ_MOD;
+-
+- prev_seqno = rtp->lastrxseqno;
+-
+- rtp->lastrxseqno = seqno;
+-
+- if (!rtp->themssrc)
+- rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
+-
+- if (rtp_debug_test_addr(&sock_in))
+- ast_verbose("Got RTP packet from %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+- ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
+-
+- rtpPT = ast_rtp_lookup_pt(rtp, payloadtype);
+- if (!rtpPT.isAstFormat) {
+- struct ast_frame *f = NULL;
+-
+- /* This is special in-band data that's not one of our codecs */
+- if (rtpPT.code == AST_RTP_DTMF) {
+- /* It's special -- rfc2833 process it */
+- if (rtp_debug_test_addr(&sock_in)) {
+- unsigned char *data;
+- unsigned int event;
+- unsigned int event_end;
+- unsigned int duration;
+- data = rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen;
+- event = ntohl(*((unsigned int *)(data)));
+- event >>= 24;
+- event_end = ntohl(*((unsigned int *)(data)));
+- event_end <<= 8;
+- event_end >>= 24;
+- duration = ntohl(*((unsigned int *)(data)));
+- duration &= 0xFFFF;
+- ast_verbose("Got RTP RFC2833 from %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port), payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
+- }
+- f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp);
+- } else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
+- /* It's really special -- process it the Cisco way */
+- if (rtp->lastevent <= seqno || (rtp->lastevent >= 65530 && seqno <= 6)) {
+- f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+- rtp->lastevent = seqno;
+- }
+- } else if (rtpPT.code == AST_RTP_CN) {
+- /* Comfort Noise */
+- f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+- } else {
+- ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(rtp->them.sin_addr));
+- }
+- return f ? f : &ast_null_frame;
+- }
+- rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
+- rtp->f.frametype = (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) ? AST_FRAME_VOICE : (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
+-
+- rtp->rxseqno = seqno;
+-
+- if (rtp->dtmfcount) {
+- rtp->dtmfcount -= (timestamp - rtp->lastrxts);
+-
+- if (rtp->dtmfcount < 0) {
+- rtp->dtmfcount = 0;
+- }
+-
+- if (rtp->resp && !rtp->dtmfcount) {
+- struct ast_frame *f;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- rtp->resp = 0;
+- return f;
+- }
+- }
+-
+- /* Record received timestamp as last received now */
+- rtp->lastrxts = timestamp;
+-
+- rtp->f.mallocd = 0;
+- rtp->f.datalen = res - hdrlen;
+- rtp->f.data.ptr = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
+- rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
+- rtp->f.seqno = seqno;
+-
+- if (rtp->f.subclass == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) {
+- unsigned char *data = rtp->f.data.ptr;
+-
+- memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
+- rtp->f.datalen +=3;
+- *data++ = 0xEF;
+- *data++ = 0xBF;
+- *data = 0xBD;
+- }
+-
+- if (rtp->f.subclass == AST_FORMAT_T140RED) {
+- unsigned char *data = rtp->f.data.ptr;
+- unsigned char *header_end;
+- int num_generations;
+- int header_length;
+- int length;
+- int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
+- int x;
+-
+- rtp->f.subclass = AST_FORMAT_T140;
+- header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
+- header_end++;
+-
+- header_length = header_end - data;
+- num_generations = header_length / 4;
+- length = header_length;
+-
+- if (!diff) {
+- for (x = 0; x < num_generations; x++)
+- length += data[x * 4 + 3];
+-
+- if (!(rtp->f.datalen - length))
+- return &ast_null_frame;
+-
+- rtp->f.data.ptr += length;
+- rtp->f.datalen -= length;
+- } else if (diff > num_generations && diff < 10) {
+- length -= 3;
+- rtp->f.data.ptr += length;
+- rtp->f.datalen -= length;
+-
+- data = rtp->f.data.ptr;
+- *data++ = 0xEF;
+- *data++ = 0xBF;
+- *data = 0xBD;
+- } else {
+- for ( x = 0; x < num_generations - diff; x++)
+- length += data[x * 4 + 3];
+-
+- rtp->f.data.ptr += length;
+- rtp->f.datalen -= length;
+- }
+- }
+-
+- if (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) {
+- rtp->f.samples = ast_codec_get_samples(&rtp->f);
+- if (rtp->f.subclass == AST_FORMAT_SLINEAR)
+- ast_frame_byteswap_be(&rtp->f);
+- calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
+- /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
+- ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
+- rtp->f.ts = timestamp / 8;
+- rtp->f.len = rtp->f.samples / ((ast_format_rate(rtp->f.subclass) / 1000));
+- } else if (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
+- /* Video -- samples is # of samples vs. 90000 */
+- if (!rtp->lastividtimestamp)
+- rtp->lastividtimestamp = timestamp;
+- rtp->f.samples = timestamp - rtp->lastividtimestamp;
+- rtp->lastividtimestamp = timestamp;
+- rtp->f.delivery.tv_sec = 0;
+- rtp->f.delivery.tv_usec = 0;
+- /* Pass the RTP marker bit as bit 0 in the subclass field.
+- * This is ok because subclass is actually a bitmask, and
+- * the low bits represent audio formats, that are not
+- * involved here since we deal with video.
+- */
+- if (mark)
+- rtp->f.subclass |= 0x1;
+- } else {
+- /* TEXT -- samples is # of samples vs. 1000 */
+- if (!rtp->lastitexttimestamp)
+- rtp->lastitexttimestamp = timestamp;
+- rtp->f.samples = timestamp - rtp->lastitexttimestamp;
+- rtp->lastitexttimestamp = timestamp;
+- rtp->f.delivery.tv_sec = 0;
+- rtp->f.delivery.tv_usec = 0;
+- }
+- rtp->f.src = "RTP";
+- return &rtp->f;
+-}
+-
+-/* The following array defines the MIME Media type (and subtype) for each
+- of our codecs, or RTP-specific data type. */
+-static const struct mimeType {
+- struct rtpPayloadType payloadType;
+- char *type;
+- char *subtype;
+- unsigned int sample_rate;
+-} mimeTypes[] = {
+- {{1, AST_FORMAT_G723_1}, "audio", "G723", 8000},
+- {{1, AST_FORMAT_GSM}, "audio", "GSM", 8000},
+- {{1, AST_FORMAT_ULAW}, "audio", "PCMU", 8000},
+- {{1, AST_FORMAT_ULAW}, "audio", "G711U", 8000},
+- {{1, AST_FORMAT_ALAW}, "audio", "PCMA", 8000},
+- {{1, AST_FORMAT_ALAW}, "audio", "G711A", 8000},
+- {{1, AST_FORMAT_G726}, "audio", "G726-32", 8000},
+- {{1, AST_FORMAT_ADPCM}, "audio", "DVI4", 8000},
+- {{1, AST_FORMAT_SLINEAR}, "audio", "L16", 8000},
+- {{1, AST_FORMAT_LPC10}, "audio", "LPC", 8000},
+- {{1, AST_FORMAT_G729A}, "audio", "G729", 8000},
+- {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
+- {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
+- {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
+- {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
+- /* this is the sample rate listed in the RTP profile for the G.722
+- codec, *NOT* the actual sample rate of the media stream
+- */
+- {{1, AST_FORMAT_G722}, "audio", "G722", 8000},
+- {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32", 8000},
+- {{0, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
+- {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
+- {{0, AST_RTP_CN}, "audio", "CN", 8000},
+- {{1, AST_FORMAT_JPEG}, "video", "JPEG", 90000},
+- {{1, AST_FORMAT_PNG}, "video", "PNG", 90000},
+- {{1, AST_FORMAT_H261}, "video", "H261", 90000},
+- {{1, AST_FORMAT_H263}, "video", "H263", 90000},
+- {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998", 90000},
+- {{1, AST_FORMAT_H264}, "video", "H264", 90000},
+- {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES", 90000},
+- {{1, AST_FORMAT_T140RED}, "text", "RED", 1000},
+- {{1, AST_FORMAT_T140}, "text", "T140", 1000},
+- {{1, AST_FORMAT_SIREN7}, "audio", "G7221", 16000},
+- {{1, AST_FORMAT_SIREN14}, "audio", "G7221", 32000},
+-};
+-
+-/*!
+- * \brief Mapping between Asterisk codecs and rtp payload types
+- *
+- * Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
+- * also, our own choices for dynamic payload types. This is our master
+- * table for transmission
+- *
+- * See http://www.iana.org/assignments/rtp-parameters for a list of
+- * assigned values
+- */
+-static const struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
+- [0] = {1, AST_FORMAT_ULAW},
+-#ifdef USE_DEPRECATED_G726
+- [2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
+-#endif
+- [3] = {1, AST_FORMAT_GSM},
+- [4] = {1, AST_FORMAT_G723_1},
+- [5] = {1, AST_FORMAT_ADPCM}, /* 8 kHz */
+- [6] = {1, AST_FORMAT_ADPCM}, /* 16 kHz */
+- [7] = {1, AST_FORMAT_LPC10},
+- [8] = {1, AST_FORMAT_ALAW},
+- [9] = {1, AST_FORMAT_G722},
+- [10] = {1, AST_FORMAT_SLINEAR}, /* 2 channels */
+- [11] = {1, AST_FORMAT_SLINEAR}, /* 1 channel */
+- [13] = {0, AST_RTP_CN},
+- [16] = {1, AST_FORMAT_ADPCM}, /* 11.025 kHz */
+- [17] = {1, AST_FORMAT_ADPCM}, /* 22.050 kHz */
+- [18] = {1, AST_FORMAT_G729A},
+- [19] = {0, AST_RTP_CN}, /* Also used for CN */
+- [26] = {1, AST_FORMAT_JPEG},
+- [31] = {1, AST_FORMAT_H261},
+- [34] = {1, AST_FORMAT_H263},
+- [97] = {1, AST_FORMAT_ILBC},
+- [98] = {1, AST_FORMAT_H263_PLUS},
+- [99] = {1, AST_FORMAT_H264},
+- [101] = {0, AST_RTP_DTMF},
+- [102] = {1, AST_FORMAT_SIREN7},
+- [103] = {1, AST_FORMAT_H263_PLUS},
+- [104] = {1, AST_FORMAT_MP4_VIDEO},
+- [105] = {1, AST_FORMAT_T140RED}, /* Real time text chat (with redundancy encoding) */
+- [106] = {1, AST_FORMAT_T140}, /* Real time text chat */
+- [110] = {1, AST_FORMAT_SPEEX},
+- [111] = {1, AST_FORMAT_G726},
+- [112] = {1, AST_FORMAT_G726_AAL2},
+- [115] = {1, AST_FORMAT_SIREN14},
+- [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
+-};
+-
+-void ast_rtp_pt_clear(struct ast_rtp* rtp)
+-{
+- int i;
+-
+- if (!rtp)
+- return;
+-
+- rtp_bridge_lock(rtp);
+-
+- for (i = 0; i < MAX_RTP_PT; ++i) {
+- rtp->current_RTP_PT[i].isAstFormat = 0;
+- rtp->current_RTP_PT[i].code = 0;
+- }
+-
+- rtp->rtp_lookup_code_cache_isAstFormat = 0;
+- rtp->rtp_lookup_code_cache_code = 0;
+- rtp->rtp_lookup_code_cache_result = 0;
+-
+- rtp_bridge_unlock(rtp);
+-}
+-
+-void ast_rtp_pt_default(struct ast_rtp* rtp)
+-{
+- int i;
+-
+- rtp_bridge_lock(rtp);
+-
+- /* Initialize to default payload types */
+- for (i = 0; i < MAX_RTP_PT; ++i) {
+- rtp->current_RTP_PT[i].isAstFormat = static_RTP_PT[i].isAstFormat;
+- rtp->current_RTP_PT[i].code = static_RTP_PT[i].code;
+- }
+-
+- rtp->rtp_lookup_code_cache_isAstFormat = 0;
+- rtp->rtp_lookup_code_cache_code = 0;
+- rtp->rtp_lookup_code_cache_result = 0;
+-
+- rtp_bridge_unlock(rtp);
+-}
+-
+-void ast_rtp_pt_copy(struct ast_rtp *dest, struct ast_rtp *src)
+-{
+- unsigned int i;
+-
+- rtp_bridge_lock(dest);
+- rtp_bridge_lock(src);
+-
+- for (i = 0; i < MAX_RTP_PT; ++i) {
+- dest->current_RTP_PT[i].isAstFormat =
+- src->current_RTP_PT[i].isAstFormat;
+- dest->current_RTP_PT[i].code =
+- src->current_RTP_PT[i].code;
+- }
+- dest->rtp_lookup_code_cache_isAstFormat = 0;
+- dest->rtp_lookup_code_cache_code = 0;
+- dest->rtp_lookup_code_cache_result = 0;
+-
+- rtp_bridge_unlock(src);
+- rtp_bridge_unlock(dest);
+-}
+-
+-/*! \brief Get channel driver interface structure */
+-static struct ast_rtp_protocol *get_proto(struct ast_channel *chan)
+-{
+- struct ast_rtp_protocol *cur = NULL;
+-
+- AST_RWLIST_RDLOCK(&protos);
+- AST_RWLIST_TRAVERSE(&protos, cur, list) {
+- if (cur->type == chan->tech->type)
+- break;
+- }
+- AST_RWLIST_UNLOCK(&protos);
+-
+- return cur;
+-}
+-
+-int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
+-{
+- struct ast_rtp *destp = NULL, *srcp = NULL; /* Audio RTP Channels */
+- struct ast_rtp *vdestp = NULL, *vsrcp = NULL; /* Video RTP channels */
+- struct ast_rtp *tdestp = NULL, *tsrcp = NULL; /* Text RTP channels */
+- struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
+- enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED, text_dest_res = AST_RTP_GET_FAILED;
+- enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED, text_src_res = AST_RTP_GET_FAILED;
+- int srccodec, destcodec, nat_active = 0;
+-
+- /* Lock channels */
+- ast_channel_lock(c0);
+- if (c1) {
+- while (ast_channel_trylock(c1)) {
+- ast_channel_unlock(c0);
+- usleep(1);
+- ast_channel_lock(c0);
+- }
+- }
+-
+- /* Find channel driver interfaces */
+- destpr = get_proto(c0);
+- if (c1)
+- srcpr = get_proto(c1);
+- if (!destpr) {
+- ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", c0->name);
+- ast_channel_unlock(c0);
+- if (c1)
+- ast_channel_unlock(c1);
+- return -1;
+- }
+- if (!srcpr) {
+- ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", c1 ? c1->name : "<unspecified>");
+- ast_channel_unlock(c0);
+- if (c1)
+- ast_channel_unlock(c1);
+- return -1;
+- }
+-
+- /* Get audio, video and text interface (if native bridge is possible) */
+- audio_dest_res = destpr->get_rtp_info(c0, &destp);
+- video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(c0, &vdestp) : AST_RTP_GET_FAILED;
+- text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(c0, &tdestp) : AST_RTP_GET_FAILED;
+- if (srcpr) {
+- audio_src_res = srcpr->get_rtp_info(c1, &srcp);
+- video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(c1, &vsrcp) : AST_RTP_GET_FAILED;
+- text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(c1, &tsrcp) : AST_RTP_GET_FAILED;
+- }
+-
+- /* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
+- if (audio_dest_res != AST_RTP_TRY_NATIVE || (video_dest_res != AST_RTP_GET_FAILED && video_dest_res != AST_RTP_TRY_NATIVE)) {
+- /* Somebody doesn't want to play... */
+- ast_channel_unlock(c0);
+- if (c1)
+- ast_channel_unlock(c1);
+- return -1;
+- }
+- if (audio_src_res == AST_RTP_TRY_NATIVE && (video_src_res == AST_RTP_GET_FAILED || video_src_res == AST_RTP_TRY_NATIVE) && srcpr->get_codec)
+- srccodec = srcpr->get_codec(c1);
+- else
+- srccodec = 0;
+- if (audio_dest_res == AST_RTP_TRY_NATIVE && (video_dest_res == AST_RTP_GET_FAILED || video_dest_res == AST_RTP_TRY_NATIVE) && destpr->get_codec)
+- destcodec = destpr->get_codec(c0);
+- else
+- destcodec = 0;
+- /* Ensure we have at least one matching codec */
+- if (srcp && !(srccodec & destcodec)) {
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return 0;
+- }
+- /* Consider empty media as non-existent */
+- if (audio_src_res == AST_RTP_TRY_NATIVE && !srcp->them.sin_addr.s_addr)
+- srcp = NULL;
+- if (srcp && (srcp->nat || ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
+- nat_active = 1;
+- /* Bridge media early */
+- if (destpr->set_rtp_peer(c0, srcp, vsrcp, tsrcp, srccodec, nat_active))
+- ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
+- ast_channel_unlock(c0);
+- if (c1)
+- ast_channel_unlock(c1);
+- ast_debug(1, "Setting early bridge SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
+- return 0;
+-}
+-
+-int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, int media)
+-{
+- struct ast_rtp *destp = NULL, *srcp = NULL; /* Audio RTP Channels */
+- struct ast_rtp *vdestp = NULL, *vsrcp = NULL; /* Video RTP channels */
+- struct ast_rtp *tdestp = NULL, *tsrcp = NULL; /* Text RTP channels */
+- struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
+- enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED, text_dest_res = AST_RTP_GET_FAILED;
+- enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED, text_src_res = AST_RTP_GET_FAILED;
+- int srccodec, destcodec;
+-
+- /* Lock channels */
+- ast_channel_lock(dest);
+- while (ast_channel_trylock(src)) {
+- ast_channel_unlock(dest);
+- usleep(1);
+- ast_channel_lock(dest);
+- }
+-
+- /* Find channel driver interfaces */
+- if (!(destpr = get_proto(dest))) {
+- ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", dest->name);
+- ast_channel_unlock(dest);
+- ast_channel_unlock(src);
+- return 0;
+- }
+- if (!(srcpr = get_proto(src))) {
+- ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", src->name);
+- ast_channel_unlock(dest);
+- ast_channel_unlock(src);
+- return 0;
+- }
+-
+- /* Get audio and video interface (if native bridge is possible) */
+- audio_dest_res = destpr->get_rtp_info(dest, &destp);
+- video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(dest, &vdestp) : AST_RTP_GET_FAILED;
+- text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(dest, &tdestp) : AST_RTP_GET_FAILED;
+- audio_src_res = srcpr->get_rtp_info(src, &srcp);
+- video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(src, &vsrcp) : AST_RTP_GET_FAILED;
+- text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(src, &tsrcp) : AST_RTP_GET_FAILED;
+-
+- /* Ensure we have at least one matching codec */
+- if (srcpr->get_codec)
+- srccodec = srcpr->get_codec(src);
+- else
+- srccodec = 0;
+- if (destpr->get_codec)
+- destcodec = destpr->get_codec(dest);
+- else
+- destcodec = 0;
+-
+- /* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
+- if (audio_dest_res != AST_RTP_TRY_NATIVE || (video_dest_res != AST_RTP_GET_FAILED && video_dest_res != AST_RTP_TRY_NATIVE) || audio_src_res != AST_RTP_TRY_NATIVE || (video_src_res != AST_RTP_GET_FAILED && video_src_res != AST_RTP_TRY_NATIVE) || !(srccodec & destcodec)) {
+- /* Somebody doesn't want to play... */
+- ast_channel_unlock(dest);
+- ast_channel_unlock(src);
+- return 0;
+- }
+- ast_rtp_pt_copy(destp, srcp);
+- if (vdestp && vsrcp)
+- ast_rtp_pt_copy(vdestp, vsrcp);
+- if (tdestp && tsrcp)
+- ast_rtp_pt_copy(tdestp, tsrcp);
+- if (media) {
+- /* Bridge early */
+- if (destpr->set_rtp_peer(dest, srcp, vsrcp, tsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
+- ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src->name);
+- }
+- ast_channel_unlock(dest);
+- ast_channel_unlock(src);
+- ast_debug(1, "Seeded SDP of '%s' with that of '%s'\n", dest->name, src->name);
+- return 1;
+-}
+-
+-/*! \brief Make a note of a RTP payload type that was seen in a SDP "m=" line.
+- * By default, use the well-known value for this type (although it may
+- * still be set to a different value by a subsequent "a=rtpmap:" line)
+- */
+-void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt)
+-{
+- if (pt < 0 || pt > MAX_RTP_PT || static_RTP_PT[pt].code == 0)
+- return; /* bogus payload type */
+-
+- rtp_bridge_lock(rtp);
+- rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
+- rtp_bridge_unlock(rtp);
+-}
+-
+-/*! \brief remove setting from payload type list if the rtpmap header indicates
+- an unknown media type */
+-void ast_rtp_unset_m_type(struct ast_rtp* rtp, int pt)
+-{
+- if (pt < 0 || pt > MAX_RTP_PT)
+- return; /* bogus payload type */
+-
+- rtp_bridge_lock(rtp);
+- rtp->current_RTP_PT[pt].isAstFormat = 0;
+- rtp->current_RTP_PT[pt].code = 0;
+- rtp_bridge_unlock(rtp);
+-}
+-
+-/*! \brief Make a note of a RTP payload type (with MIME type) that was seen in
+- * an SDP "a=rtpmap:" line.
+- * \return 0 if the MIME type was found and set, -1 if it wasn't found
+- */
+-int ast_rtp_set_rtpmap_type_rate(struct ast_rtp *rtp, int pt,
+- char *mimeType, char *mimeSubtype,
+- enum ast_rtp_options options,
+- unsigned int sample_rate)
+-{
+- unsigned int i;
+- int found = 0;
+-
+- if (pt < 0 || pt > MAX_RTP_PT)
+- return -1; /* bogus payload type */
+-
+- rtp_bridge_lock(rtp);
+-
+- for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
+- const struct mimeType *t = &mimeTypes[i];
+-
+- if (strcasecmp(mimeSubtype, t->subtype)) {
+- continue;
+- }
+-
+- if (strcasecmp(mimeType, t->type)) {
+- continue;
+- }
+-
+- /* if both sample rates have been supplied, and they don't match,
+- then this not a match; if one has not been supplied, then the
+- rates are not compared */
+- if (sample_rate && t->sample_rate &&
+- (sample_rate != t->sample_rate)) {
+- continue;
+- }
+-
+- found = 1;
+- rtp->current_RTP_PT[pt] = t->payloadType;
+-
+- if ((t->payloadType.code == AST_FORMAT_G726) &&
+- t->payloadType.isAstFormat &&
+- (options & AST_RTP_OPT_G726_NONSTANDARD)) {
+- rtp->current_RTP_PT[pt].code = AST_FORMAT_G726_AAL2;
+- }
+-
+- break;
+- }
+-
+- rtp_bridge_unlock(rtp);
+-
+- return (found ? 0 : -2);
+-}
+-
+-int ast_rtp_set_rtpmap_type(struct ast_rtp *rtp, int pt,
+- char *mimeType, char *mimeSubtype,
+- enum ast_rtp_options options)
+-{
+- return ast_rtp_set_rtpmap_type_rate(rtp, pt, mimeType, mimeSubtype, options, 0);
+-}
+-
+-/*! \brief Return the union of all of the codecs that were set by rtp_set...() calls
+- * They're returned as two distinct sets: AST_FORMATs, and AST_RTPs */
+-void ast_rtp_get_current_formats(struct ast_rtp* rtp,
+- int* astFormats, int* nonAstFormats)
+-{
+- int pt;
+-
+- rtp_bridge_lock(rtp);
+-
+- *astFormats = *nonAstFormats = 0;
+- for (pt = 0; pt < MAX_RTP_PT; ++pt) {
+- if (rtp->current_RTP_PT[pt].isAstFormat) {
+- *astFormats |= rtp->current_RTP_PT[pt].code;
+- } else {
+- *nonAstFormats |= rtp->current_RTP_PT[pt].code;
+- }
+- }
+-
+- rtp_bridge_unlock(rtp);
+-}
+-
+-struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt)
+-{
+- struct rtpPayloadType result;
+-
+- result.isAstFormat = result.code = 0;
+-
+- if (pt < 0 || pt > MAX_RTP_PT)
+- return result; /* bogus payload type */
+-
+- /* Start with negotiated codecs */
+- rtp_bridge_lock(rtp);
+- result = rtp->current_RTP_PT[pt];
+- rtp_bridge_unlock(rtp);
+-
+- /* If it doesn't exist, check our static RTP type list, just in case */
+- if (!result.code)
+- result = static_RTP_PT[pt];
+-
+- return result;
+-}
+-
+-/*! \brief Looks up an RTP code out of our *static* outbound list */
+-int ast_rtp_lookup_code(struct ast_rtp* rtp, const int isAstFormat, const int code)
+-{
+- int pt = 0;
+-
+- rtp_bridge_lock(rtp);
+-
+- if (isAstFormat == rtp->rtp_lookup_code_cache_isAstFormat &&
+- code == rtp->rtp_lookup_code_cache_code) {
+- /* Use our cached mapping, to avoid the overhead of the loop below */
+- pt = rtp->rtp_lookup_code_cache_result;
+- rtp_bridge_unlock(rtp);
+- return pt;
+- }
+-
+- /* Check the dynamic list first */
+- for (pt = 0; pt < MAX_RTP_PT; ++pt) {
+- if (rtp->current_RTP_PT[pt].code == code && rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
+- rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
+- rtp->rtp_lookup_code_cache_code = code;
+- rtp->rtp_lookup_code_cache_result = pt;
+- rtp_bridge_unlock(rtp);
+- return pt;
+- }
+- }
+-
+- /* Then the static list */
+- for (pt = 0; pt < MAX_RTP_PT; ++pt) {
+- if (static_RTP_PT[pt].code == code && static_RTP_PT[pt].isAstFormat == isAstFormat) {
+- rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
+- rtp->rtp_lookup_code_cache_code = code;
+- rtp->rtp_lookup_code_cache_result = pt;
+- rtp_bridge_unlock(rtp);
+- return pt;
+- }
+- }
+-
+- rtp_bridge_unlock(rtp);
+-
+- return -1;
+-}
+-
+-const char *ast_rtp_lookup_mime_subtype(const int isAstFormat, const int code,
+- enum ast_rtp_options options)
+-{
+- unsigned int i;
+-
+- for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
+- if ((mimeTypes[i].payloadType.code == code) && (mimeTypes[i].payloadType.isAstFormat == isAstFormat)) {
+- if (isAstFormat &&
+- (code == AST_FORMAT_G726_AAL2) &&
+- (options & AST_RTP_OPT_G726_NONSTANDARD))
+- return "G726-32";
+- else
+- return mimeTypes[i].subtype;
+- }
+- }
+-
+- return "";
+-}
+-
+-unsigned int ast_rtp_lookup_sample_rate(int isAstFormat, int code)
+-{
+- unsigned int i;
+-
+- for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
+- if ((mimeTypes[i].payloadType.code == code) && (mimeTypes[i].payloadType.isAstFormat == isAstFormat)) {
+- return mimeTypes[i].sample_rate;
+- }
+- }
+-
+- return 0;
+-}
+-
+-char *ast_rtp_lookup_mime_multiple(char *buf, size_t size, const int capability,
+- const int isAstFormat, enum ast_rtp_options options)
+-{
+- int format;
+- unsigned len;
+- char *end = buf;
+- char *start = buf;
+-
+- if (!buf || !size)
+- return NULL;
+-
+- snprintf(end, size, "0x%x (", capability);
+-
+- len = strlen(end);
+- end += len;
+- size -= len;
+- start = end;
+-
+- for (format = 1; format < AST_RTP_MAX; format <<= 1) {
+- if (capability & format) {
+- const char *name = ast_rtp_lookup_mime_subtype(isAstFormat, format, options);
+-
+- snprintf(end, size, "%s|", name);
+- len = strlen(end);
+- end += len;
+- size -= len;
+- }
+- }
+-
+- if (start == end)
+- ast_copy_string(start, "nothing)", size);
+- else if (size > 1)
+- *(end -1) = ')';
+-
+- return buf;
+-}
+-
+-/*! \brief Open RTP or RTCP socket for a session.
+- * Print a message on failure.
+- */
+-static int rtp_socket(const char *type)
+-{
+- int s = socket(AF_INET, SOCK_DGRAM, 0);
+- if (s < 0) {
+- if (type == NULL)
+- type = "RTP/RTCP";
+- ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno));
+- } else {
+- long flags = fcntl(s, F_GETFL);
+- fcntl(s, F_SETFL, flags | O_NONBLOCK);
+-#ifdef SO_NO_CHECK
+- if (nochecksums)
+- setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
+-#endif
+- }
+- return s;
+-}
+-
+-/*!
+- * \brief Initialize a new RTCP session.
+- *
+- * \returns The newly initialized RTCP session.
+- */
+-static struct ast_rtcp *ast_rtcp_new(void)
+-{
+- struct ast_rtcp *rtcp;
+-
+- if (!(rtcp = ast_calloc(1, sizeof(*rtcp))))
+- return NULL;
+- rtcp->s = rtp_socket("RTCP");
+- rtcp->us.sin_family = AF_INET;
+- rtcp->them.sin_family = AF_INET;
+- rtcp->schedid = -1;
+-
+- if (rtcp->s < 0) {
+- ast_free(rtcp);
+- return NULL;
+- }
+-
+- return rtcp;
+-}
+-
+-/*!
+- * \brief Initialize a new RTP structure.
+- *
+- */
+-void ast_rtp_new_init(struct ast_rtp *rtp)
+-{
+-#ifdef P2P_INTENSE
+- ast_mutex_init(&rtp->bridge_lock);
+-#endif
+-
+- rtp->them.sin_family = AF_INET;
+- rtp->us.sin_family = AF_INET;
+- rtp->ssrc = ast_random();
+- rtp->seqno = ast_random() & 0xffff;
+- ast_set_flag(rtp, FLAG_HAS_DTMF);
+- rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
+-}
+-
+-struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode, struct in_addr addr)
+-{
+- struct ast_rtp *rtp;
+- int x;
+- int startplace;
+-
+- if (!(rtp = ast_calloc(1, sizeof(*rtp))))
+- return NULL;
+-
+- ast_rtp_new_init(rtp);
+-
+- rtp->s = rtp_socket("RTP");
+- if (rtp->s < 0)
+- goto fail;
+- if (sched && rtcpenable) {
+- rtp->sched = sched;
+- rtp->rtcp = ast_rtcp_new();
+- }
+-
+- /*
+- * Try to bind the RTP port, x, and possibly the RTCP port, x+1 as well.
+- * Start from a random (even, by RTP spec) port number, and
+- * iterate until success or no ports are available.
+- * Note that the requirement of RTP port being even, or RTCP being the
+- * next one, cannot be enforced in presence of a NAT box because the
+- * mapping is not under our control.
+- */
+- x = (rtpend == rtpstart) ? rtpstart : (ast_random() % (rtpend - rtpstart)) + rtpstart;
+- x = x & ~1; /* make it an even number */
+- startplace = x; /* remember the starting point */
+- /* this is constant across the loop */
+- rtp->us.sin_addr = addr;
+- if (rtp->rtcp)
+- rtp->rtcp->us.sin_addr = addr;
+- for (;;) {
+- rtp->us.sin_port = htons(x);
+- if (!bind(rtp->s, (struct sockaddr *)&rtp->us, sizeof(rtp->us))) {
+- /* bind succeeded, if no rtcp then we are done */
+- if (!rtp->rtcp)
+- break;
+- /* have rtcp, try to bind it */
+- rtp->rtcp->us.sin_port = htons(x + 1);
+- if (!bind(rtp->rtcp->s, (struct sockaddr *)&rtp->rtcp->us, sizeof(rtp->rtcp->us)))
+- break; /* success again, we are really done */
+- /*
+- * RTCP bind failed, so close and recreate the
+- * already bound RTP socket for the next round.
+- */
+- close(rtp->s);
+- rtp->s = rtp_socket("RTP");
+- if (rtp->s < 0)
+- goto fail;
+- }
+- /*
+- * If we get here, there was an error in one of the bind()
+- * calls, so make sure it is nothing unexpected.
+- */
+- if (errno != EADDRINUSE) {
+- /* We got an error that wasn't expected, abort! */
+- ast_log(LOG_ERROR, "Unexpected bind error: %s\n", strerror(errno));
+- goto fail;
+- }
+- /*
+- * One of the ports is in use. For the next iteration,
+- * increment by two and handle wraparound.
+- * If we reach the starting point, then declare failure.
+- */
+- x += 2;
+- if (x > rtpend)
+- x = (rtpstart + 1) & ~1;
+- if (x == startplace) {
+- ast_log(LOG_ERROR, "No RTP ports remaining. Can't setup media stream for this call.\n");
+- goto fail;
+- }
+- }
+- rtp->sched = sched;
+- rtp->io = io;
+- if (callbackmode) {
+- rtp->ioid = ast_io_add(rtp->io, rtp->s, rtpread, AST_IO_IN, rtp);
+- ast_set_flag(rtp, FLAG_CALLBACK_MODE);
+- }
+- ast_rtp_pt_default(rtp);
+- return rtp;
+-
+-fail:
+- if (rtp->s >= 0)
+- close(rtp->s);
+- if (rtp->rtcp) {
+- close(rtp->rtcp->s);
+- ast_free(rtp->rtcp);
+- }
+- ast_free(rtp);
+- return NULL;
+-}
+-
+-struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode)
+-{
+- struct in_addr ia;
+-
+- memset(&ia, 0, sizeof(ia));
+- return ast_rtp_new_with_bindaddr(sched, io, rtcpenable, callbackmode, ia);
+-}
+-
+-int ast_rtp_setqos(struct ast_rtp *rtp, int type_of_service, int class_of_service, char *desc)
+-{
+- return ast_netsock_set_qos(rtp->s, type_of_service, class_of_service, desc);
+-}
+-
+-void ast_rtp_new_source(struct ast_rtp *rtp)
+-{
+- if (rtp) {
+- rtp->set_marker_bit = 1;
+- }
+- return;
+-}
+-
+-void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
+-{
+- rtp->them.sin_port = them->sin_port;
+- rtp->them.sin_addr = them->sin_addr;
+- if (rtp->rtcp) {
+- int h = ntohs(them->sin_port);
+- rtp->rtcp->them.sin_port = htons(h + 1);
+- rtp->rtcp->them.sin_addr = them->sin_addr;
+- }
+- rtp->rxseqno = 0;
+- /* If strict RTP protection is enabled switch back to the learn state so we don't drop packets from above */
+- if (strictrtp)
+- rtp->strict_rtp_state = STRICT_RTP_LEARN;
+-}
+-
+-int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
+-{
+- if ((them->sin_family != AF_INET) ||
+- (them->sin_port != rtp->them.sin_port) ||
+- (them->sin_addr.s_addr != rtp->them.sin_addr.s_addr)) {
+- them->sin_family = AF_INET;
+- them->sin_port = rtp->them.sin_port;
+- them->sin_addr = rtp->them.sin_addr;
+- return 1;
+- }
+- return 0;
+-}
+-
+-void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us)
+-{
+- *us = rtp->us;
+-}
+-
+-struct ast_rtp *ast_rtp_get_bridged(struct ast_rtp *rtp)
+-{
+- struct ast_rtp *bridged = NULL;
+-
+- rtp_bridge_lock(rtp);
+- bridged = rtp->bridged;
+- rtp_bridge_unlock(rtp);
+-
+- return bridged;
+-}
+-
+-void ast_rtp_stop(struct ast_rtp *rtp)
+-{
+- if (rtp->rtcp) {
+- AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
+- }
+- if (rtp->red) {
+- AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
+- free(rtp->red);
+- rtp->red = NULL;
+- }
+-
+- memset(&rtp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
+- memset(&rtp->them.sin_port, 0, sizeof(rtp->them.sin_port));
+- if (rtp->rtcp) {
+- memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->rtcp->them.sin_addr));
+- memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->rtcp->them.sin_port));
+- }
+-
+- ast_clear_flag(rtp, FLAG_P2P_SENT_MARK);
+-}
+-
+-void ast_rtp_reset(struct ast_rtp *rtp)
+-{
+- memset(&rtp->rxcore, 0, sizeof(rtp->rxcore));
+- memset(&rtp->txcore, 0, sizeof(rtp->txcore));
+- memset(&rtp->dtmfmute, 0, sizeof(rtp->dtmfmute));
+- rtp->lastts = 0;
+- rtp->lastdigitts = 0;
+- rtp->lastrxts = 0;
+- rtp->lastividtimestamp = 0;
+- rtp->lastovidtimestamp = 0;
+- rtp->lastitexttimestamp = 0;
+- rtp->lastotexttimestamp = 0;
+- rtp->lasteventseqn = 0;
+- rtp->lastevent = 0;
+- rtp->lasttxformat = 0;
+- rtp->lastrxformat = 0;
+- rtp->dtmfcount = 0;
+- rtp->dtmfsamples = 0;
+- rtp->seqno = 0;
+- rtp->rxseqno = 0;
+-}
+-
+-/*! Get QoS values from RTP and RTCP data (used in "sip show channelstats") */
+-unsigned int ast_rtp_get_qosvalue(struct ast_rtp *rtp, enum ast_rtp_qos_vars value)
+-{
+- if (rtp == NULL) {
+- if (option_debug > 1)
+- ast_log(LOG_DEBUG, "NO RTP Structure? Kidding me? \n");
+- return 0;
+- }
+- if (option_debug > 1 && rtp->rtcp == NULL) {
+- ast_log(LOG_DEBUG, "NO RTCP structure. Maybe in RTP p2p bridging mode? \n");
+- }
+-
+- switch (value) {
+- case AST_RTP_TXCOUNT:
+- return (unsigned int) rtp->txcount;
+- case AST_RTP_RXCOUNT:
+- return (unsigned int) rtp->rxcount;
+- case AST_RTP_TXJITTER:
+- return (unsigned int) (rtp->rxjitter * 100.0);
+- case AST_RTP_RXJITTER:
+- return (unsigned int) (rtp->rtcp ? (rtp->rtcp->reported_jitter / (unsigned int) 65536.0) : 0);
+- case AST_RTP_RXPLOSS:
+- return rtp->rtcp ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0;
+- case AST_RTP_TXPLOSS:
+- return rtp->rtcp ? rtp->rtcp->reported_lost : 0;
+- case AST_RTP_RTT:
+- return (unsigned int) (rtp->rtcp ? (rtp->rtcp->rtt * 100) : 0);
+- }
+- return 0; /* To make the compiler happy */
+-}
+-
+-static double __ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, int *found)
+-{
+- *found = 1;
+-
+- if (!strcasecmp(qos, "remote_maxjitter"))
+- return rtp->rtcp->reported_maxjitter * 1000.0;
+- if (!strcasecmp(qos, "remote_minjitter"))
+- return rtp->rtcp->reported_minjitter * 1000.0;
+- if (!strcasecmp(qos, "remote_normdevjitter"))
+- return rtp->rtcp->reported_normdev_jitter * 1000.0;
+- if (!strcasecmp(qos, "remote_stdevjitter"))
+- return sqrt(rtp->rtcp->reported_stdev_jitter) * 1000.0;
+-
+- if (!strcasecmp(qos, "local_maxjitter"))
+- return rtp->rtcp->maxrxjitter * 1000.0;
+- if (!strcasecmp(qos, "local_minjitter"))
+- return rtp->rtcp->minrxjitter * 1000.0;
+- if (!strcasecmp(qos, "local_normdevjitter"))
+- return rtp->rtcp->normdev_rxjitter * 1000.0;
+- if (!strcasecmp(qos, "local_stdevjitter"))
+- return sqrt(rtp->rtcp->stdev_rxjitter) * 1000.0;
+-
+- if (!strcasecmp(qos, "maxrtt"))
+- return rtp->rtcp->maxrtt * 1000.0;
+- if (!strcasecmp(qos, "minrtt"))
+- return rtp->rtcp->minrtt * 1000.0;
+- if (!strcasecmp(qos, "normdevrtt"))
+- return rtp->rtcp->normdevrtt * 1000.0;
+- if (!strcasecmp(qos, "stdevrtt"))
+- return sqrt(rtp->rtcp->stdevrtt) * 1000.0;
+-
+- *found = 0;
+-
+- return 0.0;
+-}
+-
+-int ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, char *buf, unsigned int buflen)
+-{
+- double value;
+- int found;
+-
+- value = __ast_rtp_get_qos(rtp, qos, &found);
+-
+- if (!found)
+- return -1;
+-
+- snprintf(buf, buflen, "%.0lf", value);
+-
+- return 0;
+-}
+-
+-void ast_rtp_set_vars(struct ast_channel *chan, struct ast_rtp *rtp) {
+- char *audioqos;
+- char *audioqos_jitter;
+- char *audioqos_loss;
+- char *audioqos_rtt;
+- struct ast_channel *bridge;
+-
+- if (!rtp || !chan)
+- return;
+-
+- bridge = ast_bridged_channel(chan);
+-
+- audioqos = ast_rtp_get_quality(rtp, NULL, RTPQOS_SUMMARY);
+- audioqos_jitter = ast_rtp_get_quality(rtp, NULL, RTPQOS_JITTER);
+- audioqos_loss = ast_rtp_get_quality(rtp, NULL, RTPQOS_LOSS);
+- audioqos_rtt = ast_rtp_get_quality(rtp, NULL, RTPQOS_RTT);
+-
+- pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", audioqos);
+- pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", audioqos_jitter);
+- pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", audioqos_loss);
+- pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", audioqos_rtt);
+-
+- if (!bridge)
+- return;
+-
+- pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", audioqos);
+- pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", audioqos_jitter);
+- pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", audioqos_loss);
+- pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", audioqos_rtt);
+-}
+-
+-static char *__ast_rtp_get_quality_jitter(struct ast_rtp *rtp)
+-{
+- /*
+- *ssrc our ssrc
+- *themssrc their ssrc
+- *lp lost packets
+- *rxjitter our calculated jitter(rx)
+- *rxcount no. received packets
+- *txjitter reported jitter of the other end
+- *txcount transmitted packets
+- *rlp remote lost packets
+- *rtt round trip time
+- */
+-#define RTCP_JITTER_FORMAT1 \
+- "minrxjitter=%f;" \
+- "maxrxjitter=%f;" \
+- "avgrxjitter=%f;" \
+- "stdevrxjitter=%f;" \
+- "reported_minjitter=%f;" \
+- "reported_maxjitter=%f;" \
+- "reported_avgjitter=%f;" \
+- "reported_stdevjitter=%f;"
+-
+-#define RTCP_JITTER_FORMAT2 \
+- "rxjitter=%f;"
+-
+- if (rtp->rtcp && rtp->rtcp->rtcp_info) {
+- snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), RTCP_JITTER_FORMAT1,
+- rtp->rtcp->minrxjitter,
+- rtp->rtcp->maxrxjitter,
+- rtp->rtcp->normdev_rxjitter,
+- sqrt(rtp->rtcp->stdev_rxjitter),
+- rtp->rtcp->reported_minjitter,
+- rtp->rtcp->reported_maxjitter,
+- rtp->rtcp->reported_normdev_jitter,
+- sqrt(rtp->rtcp->reported_stdev_jitter)
+- );
+- } else {
+- snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), RTCP_JITTER_FORMAT2,
+- rtp->rxjitter
+- );
+- }
+-
+- return rtp->rtcp->quality_jitter;
+-
+-#undef RTCP_JITTER_FORMAT1
+-#undef RTCP_JITTER_FORMAT2
+-}
+-
+-static char *__ast_rtp_get_quality_loss(struct ast_rtp *rtp)
+-{
+- unsigned int lost;
+- unsigned int extended;
+- unsigned int expected;
+- int fraction;
+-
+-#define RTCP_LOSS_FORMAT1 \
+- "minrxlost=%f;" \
+- "maxrxlost=%f;" \
+- "avgrxlostr=%f;" \
+- "stdevrxlost=%f;" \
+- "reported_minlost=%f;" \
+- "reported_maxlost=%f;" \
+- "reported_avglost=%f;" \
+- "reported_stdevlost=%f;"
+-
+-#define RTCP_LOSS_FORMAT2 \
+- "lost=%d;" \
+- "expected=%d;"
+-
+- if (rtp->rtcp && rtp->rtcp->rtcp_info && rtp->rtcp->maxrxlost > 0) {
+- snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), RTCP_LOSS_FORMAT1,
+- rtp->rtcp->minrxlost,
+- rtp->rtcp->maxrxlost,
+- rtp->rtcp->normdev_rxlost,
+- sqrt(rtp->rtcp->stdev_rxlost),
+- rtp->rtcp->reported_minlost,
+- rtp->rtcp->reported_maxlost,
+- rtp->rtcp->reported_normdev_lost,
+- sqrt(rtp->rtcp->reported_stdev_lost)
+- );
+- } else {
+- extended = rtp->cycles + rtp->lastrxseqno;
+- expected = extended - rtp->seedrxseqno + 1;
+- if (rtp->rxcount > expected)
+- expected += rtp->rxcount - expected;
+- lost = expected - rtp->rxcount;
+-
+- if (!expected || lost <= 0)
+- fraction = 0;
+- else
+- fraction = (lost << 8) / expected;
+-
+- snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), RTCP_LOSS_FORMAT2,
+- lost,
+- expected
+- );
+- }
+-
+- return rtp->rtcp->quality_loss;
+-
+-#undef RTCP_LOSS_FORMAT1
+-#undef RTCP_LOSS_FORMAT2
+-}
+-
+-static char *__ast_rtp_get_quality_rtt(struct ast_rtp *rtp)
+-{
+- if (rtp->rtcp && rtp->rtcp->rtcp_info) {
+- snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;",
+- rtp->rtcp->minrtt,
+- rtp->rtcp->maxrtt,
+- rtp->rtcp->normdevrtt,
+- sqrt(rtp->rtcp->stdevrtt)
+- );
+- } else {
+- snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "Not available");
+- }
+-
+- return rtp->rtcp->quality_rtt;
+-}
+-
+-static char *__ast_rtp_get_quality(struct ast_rtp *rtp)
+-{
+- /*
+- *ssrc our ssrc
+- *themssrc their ssrc
+- *lp lost packets
+- *rxjitter our calculated jitter(rx)
+- *rxcount no. received packets
+- *txjitter reported jitter of the other end
+- *txcount transmitted packets
+- *rlp remote lost packets
+- *rtt round trip time
+- */
+-
+- if (rtp->rtcp && rtp->rtcp->rtcp_info) {
+- snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality),
+- "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f",
+- rtp->ssrc,
+- rtp->themssrc,
+- rtp->rtcp->expected_prior - rtp->rtcp->received_prior,
+- rtp->rxjitter,
+- rtp->rxcount,
+- (double)rtp->rtcp->reported_jitter / 65536.0,
+- rtp->txcount,
+- rtp->rtcp->reported_lost,
+- rtp->rtcp->rtt
+- );
+- } else {
+- snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality), "ssrc=%u;themssrc=%u;rxjitter=%f;rxcount=%u;txcount=%u;",
+- rtp->ssrc,
+- rtp->themssrc,
+- rtp->rxjitter,
+- rtp->rxcount,
+- rtp->txcount
+- );
+- }
+-
+- return rtp->rtcp->quality;
+-}
+-
+-char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual, enum ast_rtp_quality_type qtype)
+-{
+- if (qual && rtp) {
+- qual->local_ssrc = rtp->ssrc;
+- qual->local_jitter = rtp->rxjitter;
+- qual->local_count = rtp->rxcount;
+- qual->remote_ssrc = rtp->themssrc;
+- qual->remote_count = rtp->txcount;
+-
+- if (rtp->rtcp) {
+- qual->local_lostpackets = rtp->rtcp->expected_prior - rtp->rtcp->received_prior;
+- qual->remote_lostpackets = rtp->rtcp->reported_lost;
+- qual->remote_jitter = rtp->rtcp->reported_jitter / 65536.0;
+- qual->rtt = rtp->rtcp->rtt;
+- }
+- }
+-
+- switch (qtype) {
+- case RTPQOS_SUMMARY:
+- return __ast_rtp_get_quality(rtp);
+- case RTPQOS_JITTER:
+- return __ast_rtp_get_quality_jitter(rtp);
+- case RTPQOS_LOSS:
+- return __ast_rtp_get_quality_loss(rtp);
+- case RTPQOS_RTT:
+- return __ast_rtp_get_quality_rtt(rtp);
+- }
+-
+- return NULL;
+-}
+-
+-void ast_rtp_destroy(struct ast_rtp *rtp)
+-{
+- if (rtcp_debug_test_addr(&rtp->them) || rtcpstats) {
+- /*Print some info on the call here */
+- ast_verbose(" RTP-stats\n");
+- ast_verbose("* Our Receiver:\n");
+- ast_verbose(" SSRC: %u\n", rtp->themssrc);
+- ast_verbose(" Received packets: %u\n", rtp->rxcount);
+- ast_verbose(" Lost packets: %u\n", rtp->rtcp ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0);
+- ast_verbose(" Jitter: %.4f\n", rtp->rxjitter);
+- ast_verbose(" Transit: %.4f\n", rtp->rxtransit);
+- ast_verbose(" RR-count: %u\n", rtp->rtcp ? rtp->rtcp->rr_count : 0);
+- ast_verbose("* Our Sender:\n");
+- ast_verbose(" SSRC: %u\n", rtp->ssrc);
+- ast_verbose(" Sent packets: %u\n", rtp->txcount);
+- ast_verbose(" Lost packets: %u\n", rtp->rtcp ? rtp->rtcp->reported_lost : 0);
+- ast_verbose(" Jitter: %u\n", rtp->rtcp ? (rtp->rtcp->reported_jitter / (unsigned int)65536.0) : 0);
+- ast_verbose(" SR-count: %u\n", rtp->rtcp ? rtp->rtcp->sr_count : 0);
+- ast_verbose(" RTT: %f\n", rtp->rtcp ? rtp->rtcp->rtt : 0);
+- }
+-
+- manager_event(EVENT_FLAG_REPORTING, "RTPReceiverStat", "SSRC: %u\r\n"
+- "ReceivedPackets: %u\r\n"
+- "LostPackets: %u\r\n"
+- "Jitter: %.4f\r\n"
+- "Transit: %.4f\r\n"
+- "RRCount: %u\r\n",
+- rtp->themssrc,
+- rtp->rxcount,
+- rtp->rtcp ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0,
+- rtp->rxjitter,
+- rtp->rxtransit,
+- rtp->rtcp ? rtp->rtcp->rr_count : 0);
+- manager_event(EVENT_FLAG_REPORTING, "RTPSenderStat", "SSRC: %u\r\n"
+- "SentPackets: %u\r\n"
+- "LostPackets: %u\r\n"
+- "Jitter: %u\r\n"
+- "SRCount: %u\r\n"
+- "RTT: %f\r\n",
+- rtp->ssrc,
+- rtp->txcount,
+- rtp->rtcp ? rtp->rtcp->reported_lost : 0,
+- rtp->rtcp ? rtp->rtcp->reported_jitter : 0,
+- rtp->rtcp ? rtp->rtcp->sr_count : 0,
+- rtp->rtcp ? rtp->rtcp->rtt : 0);
+- if (rtp->smoother)
+- ast_smoother_free(rtp->smoother);
+- if (rtp->ioid)
+- ast_io_remove(rtp->io, rtp->ioid);
+- if (rtp->s > -1)
+- close(rtp->s);
+- if (rtp->rtcp) {
+- AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
+- close(rtp->rtcp->s);
+- ast_free(rtp->rtcp);
+- rtp->rtcp=NULL;
+- }
+-#ifdef P2P_INTENSE
+- ast_mutex_destroy(&rtp->bridge_lock);
+-#endif
+- ast_free(rtp);
+-}
+-
+-static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
+-{
+- struct timeval t;
+- long ms;
+- if (ast_tvzero(rtp->txcore)) {
+- rtp->txcore = ast_tvnow();
+- /* Round to 20ms for nice, pretty timestamps */
+- rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
+- }
+- /* Use previous txcore if available */
+- t = (delivery && !ast_tvzero(*delivery)) ? *delivery : ast_tvnow();
+- ms = ast_tvdiff_ms(t, rtp->txcore);
+- if (ms < 0)
+- ms = 0;
+- /* Use what we just got for next time */
+- rtp->txcore = t;
+- return (unsigned int) ms;
+-}
+-
+-/*! \brief Send begin frames for DTMF */
+-int ast_rtp_senddigit_begin(struct ast_rtp *rtp, char digit)
+-{
+- unsigned int *rtpheader;
+- int hdrlen = 12, res = 0, i = 0, payload = 0;
+- char data[256];
+-
+- if ((digit <= '9') && (digit >= '0'))
+- digit -= '0';
+- else if (digit == '*')
+- digit = 10;
+- else if (digit == '#')
+- digit = 11;
+- else if ((digit >= 'A') && (digit <= 'D'))
+- digit = digit - 'A' + 12;
+- else if ((digit >= 'a') && (digit <= 'd'))
+- digit = digit - 'a' + 12;
+- else {
+- ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
+- return 0;
+- }
+-
+- /* If we have no peer, return immediately */
+- if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
+- return 0;
+-
+- payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
+-
+- rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
+- rtp->send_duration = 160;
+- rtp->lastdigitts = rtp->lastts + rtp->send_duration;
+-
+- /* Get a pointer to the header */
+- rtpheader = (unsigned int *)data;
+- rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno));
+- rtpheader[1] = htonl(rtp->lastdigitts);
+- rtpheader[2] = htonl(rtp->ssrc);
+-
+- for (i = 0; i < 2; i++) {
+- rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
+- res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+- if (res < 0)
+- ast_log(LOG_ERROR, "RTP Transmission error to %s:%u: %s\n",
+- ast_inet_ntoa(rtp->them.sin_addr),
+- ntohs(rtp->them.sin_port), strerror(errno));
+- if (rtp_debug_test_addr(&rtp->them))
+- ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+- ast_inet_ntoa(rtp->them.sin_addr),
+- ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
+- /* Increment sequence number */
+- rtp->seqno++;
+- /* Increment duration */
+- rtp->send_duration += 160;
+- /* Clear marker bit and set seqno */
+- rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
+- }
+-
+- /* Since we received a begin, we can safely store the digit and disable any compensation */
+- rtp->sending_digit = 1;
+- rtp->send_digit = digit;
+- rtp->send_payload = payload;
+-
+- return 0;
+-}
+-
+-/*! \brief Send continuation frame for DTMF */
+-static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp)
+-{
+- unsigned int *rtpheader;
+- int hdrlen = 12, res = 0;
+- char data[256];
+-
+- if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
+- return 0;
+-
+- /* Setup packet to send */
+- rtpheader = (unsigned int *)data;
+- rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
+- rtpheader[1] = htonl(rtp->lastdigitts);
+- rtpheader[2] = htonl(rtp->ssrc);
+- rtpheader[3] = htonl((rtp->send_digit << 24) | (0xa << 16) | (rtp->send_duration));
+- rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
+-
+- /* Transmit */
+- res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+- if (res < 0)
+- ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
+- ast_inet_ntoa(rtp->them.sin_addr),
+- ntohs(rtp->them.sin_port), strerror(errno));
+- if (rtp_debug_test_addr(&rtp->them))
+- ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+- ast_inet_ntoa(rtp->them.sin_addr),
+- ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
+-
+- /* Increment sequence number */
+- rtp->seqno++;
+- /* Increment duration */
+- rtp->send_duration += 160;
+-
+- return 0;
+-}
+-
+-/*! \brief Send end packets for DTMF */
+-int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit)
+-{
+- unsigned int *rtpheader;
+- int hdrlen = 12, res = 0, i = 0;
+- char data[256];
+-
+- /* If no address, then bail out */
+- if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
+- return 0;
+-
+- if ((digit <= '9') && (digit >= '0'))
+- digit -= '0';
+- else if (digit == '*')
+- digit = 10;
+- else if (digit == '#')
+- digit = 11;
+- else if ((digit >= 'A') && (digit <= 'D'))
+- digit = digit - 'A' + 12;
+- else if ((digit >= 'a') && (digit <= 'd'))
+- digit = digit - 'a' + 12;
+- else {
+- ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
+- return 0;
+- }
+-
+- rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
+-
+- rtpheader = (unsigned int *)data;
+- rtpheader[1] = htonl(rtp->lastdigitts);
+- rtpheader[2] = htonl(rtp->ssrc);
+- rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
+- /* Set end bit */
+- rtpheader[3] |= htonl((1 << 23));
+-
+- /* Send 3 termination packets */
+- for (i = 0; i < 3; i++) {
+- rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
+- res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
+- rtp->seqno++;
+- if (res < 0)
+- ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
+- ast_inet_ntoa(rtp->them.sin_addr),
+- ntohs(rtp->them.sin_port), strerror(errno));
+- if (rtp_debug_test_addr(&rtp->them))
+- ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+- ast_inet_ntoa(rtp->them.sin_addr),
+- ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
+- }
+- rtp->lastts += rtp->send_duration;
+- rtp->sending_digit = 0;
+- rtp->send_digit = 0;
+-
+- return res;
+-}
+-
+-/*! \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
+-int ast_rtcp_send_h261fur(void *data)
+-{
+- struct ast_rtp *rtp = data;
+- int res;
+-
+- rtp->rtcp->sendfur = 1;
+- res = ast_rtcp_write(data);
+-
+- return res;
+-}
+-
+-/*! \brief Send RTCP sender's report */
+-static int ast_rtcp_write_sr(const void *data)
+-{
+- struct ast_rtp *rtp = (struct ast_rtp *)data;
+- int res;
+- int len = 0;
+- struct timeval now;
+- unsigned int now_lsw;
+- unsigned int now_msw;
+- unsigned int *rtcpheader;
+- unsigned int lost;
+- unsigned int extended;
+- unsigned int expected;
+- unsigned int expected_interval;
+- unsigned int received_interval;
+- int lost_interval;
+- int fraction;
+- struct timeval dlsr;
+- char bdata[512];
+-
+- /* Commented condition is always not NULL if rtp->rtcp is not NULL */
+- if (!rtp || !rtp->rtcp/* || (&rtp->rtcp->them.sin_addr == 0)*/)
+- return 0;
+-
+- if (!rtp->rtcp->them.sin_addr.s_addr) { /* This'll stop rtcp for this rtp session */
+- ast_verbose("RTCP SR transmission error, rtcp halted\n");
+- AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
+- return 0;
+- }
+-
+- gettimeofday(&now, NULL);
+- timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
+- rtcpheader = (unsigned int *)bdata;
+- rtcpheader[1] = htonl(rtp->ssrc); /* Our SSRC */
+- rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
+- rtcpheader[3] = htonl(now_lsw); /* now, LSW */
+- rtcpheader[4] = htonl(rtp->lastts); /* FIXME shouldn't be that, it should be now */
+- rtcpheader[5] = htonl(rtp->txcount); /* No. packets sent */
+- rtcpheader[6] = htonl(rtp->txoctetcount); /* No. bytes sent */
+- len += 28;
+-
+- extended = rtp->cycles + rtp->lastrxseqno;
+- expected = extended - rtp->seedrxseqno + 1;
+- if (rtp->rxcount > expected)
+- expected += rtp->rxcount - expected;
+- lost = expected - rtp->rxcount;
+- expected_interval = expected - rtp->rtcp->expected_prior;
+- rtp->rtcp->expected_prior = expected;
+- received_interval = rtp->rxcount - rtp->rtcp->received_prior;
+- rtp->rtcp->received_prior = rtp->rxcount;
+- lost_interval = expected_interval - received_interval;
+- if (expected_interval == 0 || lost_interval <= 0)
+- fraction = 0;
+- else
+- fraction = (lost_interval << 8) / expected_interval;
+- timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
+- rtcpheader[7] = htonl(rtp->themssrc);
+- rtcpheader[8] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
+- rtcpheader[9] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
+- rtcpheader[10] = htonl((unsigned int)(rtp->rxjitter * 65536.));
+- rtcpheader[11] = htonl(rtp->rtcp->themrxlsr);
+- rtcpheader[12] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
+- len += 24;
+-
+- rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SR << 16) | ((len/4)-1));
+-
+- if (rtp->rtcp->sendfur) {
+- rtcpheader[13] = htonl((2 << 30) | (0 << 24) | (RTCP_PT_FUR << 16) | 1);
+- rtcpheader[14] = htonl(rtp->ssrc); /* Our SSRC */
+- len += 8;
+- rtp->rtcp->sendfur = 0;
+- }
+-
+- /* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */
+- /* it can change mid call, and SDES can't) */
+- rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
+- rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
+- rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
+- len += 12;
+-
+- res = sendto(rtp->rtcp->s, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them));
+- if (res < 0) {
+- ast_log(LOG_ERROR, "RTCP SR transmission error to %s:%d, rtcp halted %s\n",ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port), strerror(errno));
+- AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
+- return 0;
+- }
+-
+- /* FIXME Don't need to get a new one */
+- gettimeofday(&rtp->rtcp->txlsr, NULL);
+- rtp->rtcp->sr_count++;
+-
+- rtp->rtcp->lastsrtxcount = rtp->txcount;
+-
+- if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
+- ast_verbose("* Sent RTCP SR to %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
+- ast_verbose(" Our SSRC: %u\n", rtp->ssrc);
+- ast_verbose(" Sent(NTP): %u.%010u\n", (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096);
+- ast_verbose(" Sent(RTP): %u\n", rtp->lastts);
+- ast_verbose(" Sent packets: %u\n", rtp->txcount);
+- ast_verbose(" Sent octets: %u\n", rtp->txoctetcount);
+- ast_verbose(" Report block:\n");
+- ast_verbose(" Fraction lost: %u\n", fraction);
+- ast_verbose(" Cumulative loss: %u\n", lost);
+- ast_verbose(" IA jitter: %.4f\n", rtp->rxjitter);
+- ast_verbose(" Their last SR: %u\n", rtp->rtcp->themrxlsr);
+- ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(ntohl(rtcpheader[12])/65536.0));
+- }
+- manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To: %s:%d\r\n"
+- "OurSSRC: %u\r\n"
+- "SentNTP: %u.%010u\r\n"
+- "SentRTP: %u\r\n"
+- "SentPackets: %u\r\n"
+- "SentOctets: %u\r\n"
+- "ReportBlock:\r\n"
+- "FractionLost: %u\r\n"
+- "CumulativeLoss: %u\r\n"
+- "IAJitter: %.4f\r\n"
+- "TheirLastSR: %u\r\n"
+- "DLSR: %4.4f (sec)\r\n",
+- ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port),
+- rtp->ssrc,
+- (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096,
+- rtp->lastts,
+- rtp->txcount,
+- rtp->txoctetcount,
+- fraction,
+- lost,
+- rtp->rxjitter,
+- rtp->rtcp->themrxlsr,
+- (double)(ntohl(rtcpheader[12])/65536.0));
+- return res;
+-}
+-
+-/*! \brief Send RTCP recipient's report */
+-static int ast_rtcp_write_rr(const void *data)
+-{
+- struct ast_rtp *rtp = (struct ast_rtp *)data;
+- int res;
+- int len = 32;
+- unsigned int lost;
+- unsigned int extended;
+- unsigned int expected;
+- unsigned int expected_interval;
+- unsigned int received_interval;
+- int lost_interval;
+- struct timeval now;
+- unsigned int *rtcpheader;
+- char bdata[1024];
+- struct timeval dlsr;
+- int fraction;
+-
+- double rxlost_current;
+-
+- if (!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0))
+- return 0;
+-
+- if (!rtp->rtcp->them.sin_addr.s_addr) {
+- ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted\n");
+- AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
+- return 0;
+- }
+-
+- extended = rtp->cycles + rtp->lastrxseqno;
+- expected = extended - rtp->seedrxseqno + 1;
+- lost = expected - rtp->rxcount;
+- expected_interval = expected - rtp->rtcp->expected_prior;
+- rtp->rtcp->expected_prior = expected;
+- received_interval = rtp->rxcount - rtp->rtcp->received_prior;
+- rtp->rtcp->received_prior = rtp->rxcount;
+- lost_interval = expected_interval - received_interval;
+-
+- if (lost_interval <= 0)
+- rtp->rtcp->rxlost = 0;
+- else rtp->rtcp->rxlost = rtp->rtcp->rxlost;
+- if (rtp->rtcp->rxlost_count == 0)
+- rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
+- if (lost_interval < rtp->rtcp->minrxlost)
+- rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
+- if (lost_interval > rtp->rtcp->maxrxlost)
+- rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;
+-
+- rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
+- rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
+- rtp->rtcp->normdev_rxlost = rxlost_current;
+- rtp->rtcp->rxlost_count++;
+-
+- if (expected_interval == 0 || lost_interval <= 0)
+- fraction = 0;
+- else
+- fraction = (lost_interval << 8) / expected_interval;
+- gettimeofday(&now, NULL);
+- timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
+- rtcpheader = (unsigned int *)bdata;
+- rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_RR << 16) | ((len/4)-1));
+- rtcpheader[1] = htonl(rtp->ssrc);
+- rtcpheader[2] = htonl(rtp->themssrc);
+- rtcpheader[3] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
+- rtcpheader[4] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
+- rtcpheader[5] = htonl((unsigned int)(rtp->rxjitter * 65536.));
+- rtcpheader[6] = htonl(rtp->rtcp->themrxlsr);
+- rtcpheader[7] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
+-
+- if (rtp->rtcp->sendfur) {
+- rtcpheader[8] = htonl((2 << 30) | (0 << 24) | (RTCP_PT_FUR << 16) | 1); /* Header from page 36 in RFC 3550 */
+- rtcpheader[9] = htonl(rtp->ssrc); /* Our SSRC */
+- len += 8;
+- rtp->rtcp->sendfur = 0;
+- }
+-
+- /*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
+- it can change mid call, and SDES can't) */
+- rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
+- rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
+- rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
+- len += 12;
+-
+- res = sendto(rtp->rtcp->s, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them));
+-
+- if (res < 0) {
+- ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
+- /* Remove the scheduler */
+- AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
+- return 0;
+- }
+-
+- rtp->rtcp->rr_count++;
+-
+- if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
+- ast_verbose("\n* Sending RTCP RR to %s:%d\n"
+- " Our SSRC: %u\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n"
+- " IA jitter: %.4f\n"
+- " Their last SR: %u\n"
+- " DLSR: %4.4f (sec)\n\n",
+- ast_inet_ntoa(rtp->rtcp->them.sin_addr),
+- ntohs(rtp->rtcp->them.sin_port),
+- rtp->ssrc, rtp->themssrc, fraction, lost,
+- rtp->rxjitter,
+- rtp->rtcp->themrxlsr,
+- (double)(ntohl(rtcpheader[7])/65536.0));
+- }
+-
+- return res;
+-}
+-
+-/*! \brief Write and RTCP packet to the far end
+- * \note Decide if we are going to send an SR (with Reception Block) or RR
+- * RR is sent if we have not sent any rtp packets in the previous interval */
+-static int ast_rtcp_write(const void *data)
+-{
+- struct ast_rtp *rtp = (struct ast_rtp *)data;
+- int res;
+-
+- if (!rtp || !rtp->rtcp)
+- return 0;
+-
+- if (rtp->txcount > rtp->rtcp->lastsrtxcount)
+- res = ast_rtcp_write_sr(data);
+- else
+- res = ast_rtcp_write_rr(data);
+-
+- return res;
+-}
+-
+-/*! \brief generate comfort noice (CNG) */
+-int ast_rtp_sendcng(struct ast_rtp *rtp, int level)
+-{
+- unsigned int *rtpheader;
+- int hdrlen = 12;
+- int res;
+- int payload;
+- char data[256];
+- level = 127 - (level & 0x7f);
+- payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_CN);
+-
+- /* If we have no peer, return immediately */
+- if (!rtp->them.sin_addr.s_addr)
+- return 0;
+-
+- rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
+-
+- /* Get a pointer to the header */
+- rtpheader = (unsigned int *)data;
+- rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno++));
+- rtpheader[1] = htonl(rtp->lastts);
+- rtpheader[2] = htonl(rtp->ssrc);
+- data[12] = level;
+- if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
+- res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
+- if (res <0)
+- ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s:%d: %s\n", ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
+- if (rtp_debug_test_addr(&rtp->them))
+- ast_verbose("Sent Comfort Noise RTP packet to %s:%u (type %d, seq %u, ts %u, len %d)\n"
+- , ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastts,res - hdrlen);
+-
+- }
+- return 0;
+-}
+-
+-/*! \brief Write RTP packet with audio or video media frames into UDP packet */
+-static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec)
+-{
+- unsigned char *rtpheader;
+- int hdrlen = 12;
+- int res;
+- unsigned int ms;
+- int pred;
+- int mark = 0;
+-
+- if (rtp->sending_digit) {
+- return 0;
+- }
+-
+- ms = calc_txstamp(rtp, &f->delivery);
+- /* Default prediction */
+- if (f->frametype == AST_FRAME_VOICE) {
+- pred = rtp->lastts + f->samples;
+-
+- /* Re-calculate last TS */
+- rtp->lastts = rtp->lastts + ms * 8;
+- if (ast_tvzero(f->delivery)) {
+- /* If this isn't an absolute delivery time, Check if it is close to our prediction,
+- and if so, go with our prediction */
+- if (abs(rtp->lastts - pred) < MAX_TIMESTAMP_SKEW)
+- rtp->lastts = pred;
+- else {
+- ast_debug(3, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
+- mark = 1;
+- }
+- }
+- } else if (f->frametype == AST_FRAME_VIDEO) {
+- mark = f->subclass & 0x1;
+- pred = rtp->lastovidtimestamp + f->samples;
+- /* Re-calculate last TS */
+- rtp->lastts = rtp->lastts + ms * 90;
+- /* If it's close to our prediction, go for it */
+- if (ast_tvzero(f->delivery)) {
+- if (abs(rtp->lastts - pred) < 7200) {
+- rtp->lastts = pred;
+- rtp->lastovidtimestamp += f->samples;
+- } else {
+- ast_debug(3, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, f->samples);
+- rtp->lastovidtimestamp = rtp->lastts;
+- }
+- }
+- } else {
+- pred = rtp->lastotexttimestamp + f->samples;
+- /* Re-calculate last TS */
+- rtp->lastts = rtp->lastts + ms * 90;
+- /* If it's close to our prediction, go for it */
+- if (ast_tvzero(f->delivery)) {
+- if (abs(rtp->lastts - pred) < 7200) {
+- rtp->lastts = pred;
+- rtp->lastotexttimestamp += f->samples;
+- } else {
+- ast_debug(3, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, f->samples);
+- rtp->lastotexttimestamp = rtp->lastts;
+- }
+- }
+- }
+-
+- /* If we have been explicitly told to set the marker bit do so */
+- if (rtp->set_marker_bit) {
+- mark = 1;
+- rtp->set_marker_bit = 0;
+- }
+-
+- /* If the timestamp for non-digit packets has moved beyond the timestamp
+- for digits, update the digit timestamp.
+- */
+- if (rtp->lastts > rtp->lastdigitts)
+- rtp->lastdigitts = rtp->lastts;
+-
+- if (ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO))
+- rtp->lastts = f->ts * 8;
+-
+- /* Get a pointer to the header */
+- rtpheader = (unsigned char *)(f->data.ptr - hdrlen);
+-
+- put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (rtp->seqno) | (mark << 23)));
+- put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts));
+- put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc));
+-
+- if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
+- res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
+- if (res < 0) {
+- if (!rtp->nat || (rtp->nat && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
+- ast_debug(1, "RTP Transmission error of packet %d to %s:%d: %s\n", rtp->seqno, ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
+- } else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) {
+- /* Only give this error message once if we are not RTP debugging */
+- if (option_debug || rtpdebug)
+- ast_debug(0, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
+- ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN);
+- }
+- } else {
+- rtp->txcount++;
+- rtp->txoctetcount +=(res - hdrlen);
+-
+- /* Do not schedule RR if RTCP isn't run */
+- if (rtp->rtcp && rtp->rtcp->them.sin_addr.s_addr && rtp->rtcp->schedid < 1) {
+- rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
+- }
+- }
+-
+- if (rtp_debug_test_addr(&rtp->them))
+- ast_verbose("Sent RTP packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
+- ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), codec, rtp->seqno, rtp->lastts,res - hdrlen);
+- }
+-
+- rtp->seqno++;
+-
+- return 0;
+-}
+-
+-void ast_rtp_codec_setpref(struct ast_rtp *rtp, struct ast_codec_pref *prefs)
+-{
+- struct ast_format_list current_format_old, current_format_new;
+-
+- /* if no packets have been sent through this session yet, then
+- * changing preferences does not require any extra work
+- */
+- if (rtp->lasttxformat == 0) {
+- rtp->pref = *prefs;
+- return;
+- }
+-
+- current_format_old = ast_codec_pref_getsize(&rtp->pref, rtp->lasttxformat);
+-
+- rtp->pref = *prefs;
+-
+- current_format_new = ast_codec_pref_getsize(&rtp->pref, rtp->lasttxformat);
+-
+- /* if the framing desired for the current format has changed, we may have to create
+- * or adjust the smoother for this session
+- */
+- if ((current_format_new.inc_ms != 0) &&
+- (current_format_new.cur_ms != current_format_old.cur_ms)) {
+- int new_size = (current_format_new.cur_ms * current_format_new.fr_len) / current_format_new.inc_ms;
+-
+- if (rtp->smoother) {
+- ast_smoother_reconfigure(rtp->smoother, new_size);
+- if (option_debug) {
+- ast_log(LOG_DEBUG, "Adjusted smoother to %d ms and %d bytes\n", current_format_new.cur_ms, new_size);
+- }
+- } else {
+- if (!(rtp->smoother = ast_smoother_new(new_size))) {
+- ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", rtp->lasttxformat, current_format_new.cur_ms, new_size);
+- return;
+- }
+- if (current_format_new.flags) {
+- ast_smoother_set_flags(rtp->smoother, current_format_new.flags);
+- }
+- if (option_debug) {
+- ast_log(LOG_DEBUG, "Created smoother: format: %d ms: %d len: %d\n", rtp->lasttxformat, current_format_new.cur_ms, new_size);
+- }
+- }
+- }
+-
+-}
+-
+-struct ast_codec_pref *ast_rtp_codec_getpref(struct ast_rtp *rtp)
+-{
+- return &rtp->pref;
+-}
+-
+-int ast_rtp_codec_getformat(int pt)
+-{
+- if (pt < 0 || pt > MAX_RTP_PT)
+- return 0; /* bogus payload type */
+-
+- if (static_RTP_PT[pt].isAstFormat)
+- return static_RTP_PT[pt].code;
+- else
+- return 0;
+-}
+-
+-int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
+-{
+- struct ast_frame *f;
+- int codec;
+- int hdrlen = 12;
+- int subclass;
+-
+-
+- /* If we have no peer, return immediately */
+- if (!rtp->them.sin_addr.s_addr)
+- return 0;
+-
+- /* If there is no data length, return immediately */
+- if (!_f->datalen && !rtp->red)
+- return 0;
+-
+- /* Make sure we have enough space for RTP header */
+- if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO) && (_f->frametype != AST_FRAME_TEXT)) {
+- ast_log(LOG_WARNING, "RTP can only send voice, video and text\n");
+- return -1;
+- }
+-
+- if (rtp->red) {
+- /* return 0; */
+- /* no primary data or generations to send */
+- if ((_f = red_t140_to_red(rtp->red)) == NULL)
+- return 0;
+- }
+-
+- /* The bottom bit of a video subclass contains the marker bit */
+- subclass = _f->subclass;
+- if (_f->frametype == AST_FRAME_VIDEO)
+- subclass &= ~0x1;
+-
+- codec = ast_rtp_lookup_code(rtp, 1, subclass);
+- if (codec < 0) {
+- ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(_f->subclass));
+- return -1;
+- }
+-
+- if (rtp->lasttxformat != subclass) {
+- /* New format, reset the smoother */
+- ast_debug(1, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
+- rtp->lasttxformat = subclass;
+- if (rtp->smoother)
+- ast_smoother_free(rtp->smoother);
+- rtp->smoother = NULL;
+- }
+-
+- if (!rtp->smoother) {
+- struct ast_format_list fmt = ast_codec_pref_getsize(&rtp->pref, subclass);
+-
+- switch (subclass) {
+- case AST_FORMAT_SPEEX:
+- case AST_FORMAT_G723_1:
+- case AST_FORMAT_SIREN7:
+- case AST_FORMAT_SIREN14:
+- /* these are all frame-based codecs and cannot be safely run through
+- a smoother */
+- break;
+- default:
+- if (fmt.inc_ms) { /* if codec parameters is set / avoid division by zero */
+- if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
+- ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
+- return -1;
+- }
+- if (fmt.flags)
+- ast_smoother_set_flags(rtp->smoother, fmt.flags);
+- ast_debug(1, "Created smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
+- }
+- }
+- }
+- if (rtp->smoother) {
+- if (ast_smoother_test_flag(rtp->smoother, AST_SMOOTHER_FLAG_BE)) {
+- ast_smoother_feed_be(rtp->smoother, _f);
+- } else {
+- ast_smoother_feed(rtp->smoother, _f);
+- }
+-
+- while ((f = ast_smoother_read(rtp->smoother)) && (f->data.ptr)) {
+- if (f->subclass == AST_FORMAT_G722) {
+- /* G.722 is silllllllllllllly */
+- f->samples /= 2;
+- }
+-
+- ast_rtp_raw_write(rtp, f, codec);
+- }
+- } else {
+- /* Don't buffer outgoing frames; send them one-per-packet: */
+- if (_f->offset < hdrlen)
+- f = ast_frdup(_f); /*! \bug XXX this might never be free'd. Why do we do this? */
+- else
+- f = _f;
+- if (f->data.ptr)
+- ast_rtp_raw_write(rtp, f, codec);
+- if (f != _f)
+- ast_frfree(f);
+- }
+-
+- return 0;
+-}
+-
+-/*! \brief Unregister interface to channel driver */
+-void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto)
+-{
+- AST_RWLIST_WRLOCK(&protos);
+- AST_RWLIST_REMOVE(&protos, proto, list);
+- AST_RWLIST_UNLOCK(&protos);
+-}
+-
+-/*! \brief Register interface to channel driver */
+-int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
+-{
+- struct ast_rtp_protocol *cur;
+-
+- AST_RWLIST_WRLOCK(&protos);
+- AST_RWLIST_TRAVERSE(&protos, cur, list) {
+- if (!strcmp(cur->type, proto->type)) {
+- ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
+- AST_RWLIST_UNLOCK(&protos);
+- return -1;
+- }
+- }
+- AST_RWLIST_INSERT_HEAD(&protos, proto, list);
+- AST_RWLIST_UNLOCK(&protos);
+-
+- return 0;
+-}
+-
+-/*! \brief Bridge loop for true native bridge (reinvite) */
+-static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp *p0, struct ast_rtp *p1, struct ast_rtp *vp0, struct ast_rtp *vp1, struct ast_rtp *tp0, struct ast_rtp *tp1, struct ast_rtp_protocol *pr0, struct ast_rtp_protocol *pr1, int codec0, int codec1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
+-{
+- struct ast_frame *fr = NULL;
+- struct ast_channel *who = NULL, *other = NULL, *cs[3] = {NULL, };
+- int oldcodec0 = codec0, oldcodec1 = codec1;
+- struct sockaddr_in ac1 = {0,}, vac1 = {0,}, tac1 = {0,}, ac0 = {0,}, vac0 = {0,}, tac0 = {0,};
+- struct sockaddr_in t1 = {0,}, vt1 = {0,}, tt1 = {0,}, t0 = {0,}, vt0 = {0,}, tt0 = {0,};
+-
+- /* Set it up so audio goes directly between the two endpoints */
+-
+- /* Test the first channel */
+- if (!(pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) {
+- ast_rtp_get_peer(p1, &ac1);
+- if (vp1)
+- ast_rtp_get_peer(vp1, &vac1);
+- if (tp1)
+- ast_rtp_get_peer(tp1, &tac1);
+- } else
+- ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
+-
+- /* Test the second channel */
+- if (!(pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) {
+- ast_rtp_get_peer(p0, &ac0);
+- if (vp0)
+- ast_rtp_get_peer(vp0, &vac0);
+- if (tp0)
+- ast_rtp_get_peer(tp0, &tac0);
+- } else
+- ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c1->name, c0->name);
+-
+- /* Now we can unlock and move into our loop */
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+-
+- ast_poll_channel_add(c0, c1);
+-
+- /* Throw our channels into the structure and enter the loop */
+- cs[0] = c0;
+- cs[1] = c1;
+- cs[2] = NULL;
+- for (;;) {
+- /* Check if anything changed */
+- if ((c0->tech_pvt != pvt0) ||
+- (c1->tech_pvt != pvt1) ||
+- (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
+- (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks)) {
+- ast_debug(1, "Oooh, something is weird, backing out\n");
+- if (c0->tech_pvt == pvt0)
+- if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
+- if (c1->tech_pvt == pvt1)
+- if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
+- ast_poll_channel_del(c0, c1);
+- return AST_BRIDGE_RETRY;
+- }
+-
+- /* Check if they have changed their address */
+- ast_rtp_get_peer(p1, &t1);
+- if (vp1)
+- ast_rtp_get_peer(vp1, &vt1);
+- if (tp1)
+- ast_rtp_get_peer(tp1, &tt1);
+- if (pr1->get_codec)
+- codec1 = pr1->get_codec(c1);
+- ast_rtp_get_peer(p0, &t0);
+- if (vp0)
+- ast_rtp_get_peer(vp0, &vt0);
+- if (tp0)
+- ast_rtp_get_peer(tp0, &tt0);
+- if (pr0->get_codec)
+- codec0 = pr0->get_codec(c0);
+- if ((inaddrcmp(&t1, &ac1)) ||
+- (vp1 && inaddrcmp(&vt1, &vac1)) ||
+- (tp1 && inaddrcmp(&tt1, &tac1)) ||
+- (codec1 != oldcodec1)) {
+- ast_debug(2, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
+- c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), codec1);
+- ast_debug(2, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n",
+- c1->name, ast_inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), codec1);
+- ast_debug(2, "Oooh, '%s' changed end taddress to %s:%d (format %d)\n",
+- c1->name, ast_inet_ntoa(tt1.sin_addr), ntohs(tt1.sin_port), codec1);
+- ast_debug(2, "Oooh, '%s' was %s:%d/(format %d)\n",
+- c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
+- ast_debug(2, "Oooh, '%s' was %s:%d/(format %d)\n",
+- c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
+- ast_debug(2, "Oooh, '%s' was %s:%d/(format %d)\n",
+- c1->name, ast_inet_ntoa(tac1.sin_addr), ntohs(tac1.sin_port), oldcodec1);
+- if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, tt1.sin_addr.s_addr ? tp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
+- ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
+- memcpy(&ac1, &t1, sizeof(ac1));
+- memcpy(&vac1, &vt1, sizeof(vac1));
+- memcpy(&tac1, &tt1, sizeof(tac1));
+- oldcodec1 = codec1;
+- }
+- if ((inaddrcmp(&t0, &ac0)) ||
+- (vp0 && inaddrcmp(&vt0, &vac0)) ||
+- (tp0 && inaddrcmp(&tt0, &tac0))) {
+- ast_debug(2, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
+- c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), codec0);
+- ast_debug(2, "Oooh, '%s' was %s:%d/(format %d)\n",
+- c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
+- if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, tt0.sin_addr.s_addr ? tp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
+- ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
+- memcpy(&ac0, &t0, sizeof(ac0));
+- memcpy(&vac0, &vt0, sizeof(vac0));
+- memcpy(&tac0, &tt0, sizeof(tac0));
+- oldcodec0 = codec0;
+- }
+-
+- /* Wait for frame to come in on the channels */
+- if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
+- if (!timeoutms) {
+- if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
+- if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
+- return AST_BRIDGE_RETRY;
+- }
+- ast_debug(1, "Ooh, empty read...\n");
+- if (ast_check_hangup(c0) || ast_check_hangup(c1))
+- break;
+- continue;
+- }
+- fr = ast_read(who);
+- other = (who == c0) ? c1 : c0;
+- if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
+- (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
+- ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
+- /* Break out of bridge */
+- *fo = fr;
+- *rc = who;
+- ast_debug(1, "Oooh, got a %s\n", fr ? "digit" : "hangup");
+- if (c0->tech_pvt == pvt0)
+- if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
+- if (c1->tech_pvt == pvt1)
+- if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
+- ast_poll_channel_del(c0, c1);
+- return AST_BRIDGE_COMPLETE;
+- } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
+- if ((fr->subclass == AST_CONTROL_HOLD) ||
+- (fr->subclass == AST_CONTROL_UNHOLD) ||
+- (fr->subclass == AST_CONTROL_VIDUPDATE) ||
+- (fr->subclass == AST_CONTROL_T38) ||
+- (fr->subclass == AST_CONTROL_SRCUPDATE)) {
+- if (fr->subclass == AST_CONTROL_HOLD) {
+- /* If we someone went on hold we want the other side to reinvite back to us */
+- if (who == c0)
+- pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0);
+- else
+- pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0);
+- } else if (fr->subclass == AST_CONTROL_UNHOLD) {
+- /* If they went off hold they should go back to being direct */
+- if (who == c0)
+- pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE));
+- else
+- pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE));
+- }
+- /* Update local address information */
+- ast_rtp_get_peer(p0, &t0);
+- memcpy(&ac0, &t0, sizeof(ac0));
+- ast_rtp_get_peer(p1, &t1);
+- memcpy(&ac1, &t1, sizeof(ac1));
+- /* Update codec information */
+- if (pr0->get_codec && c0->tech_pvt)
+- oldcodec0 = codec0 = pr0->get_codec(c0);
+- if (pr1->get_codec && c1->tech_pvt)
+- oldcodec1 = codec1 = pr1->get_codec(c1);
+- ast_indicate_data(other, fr->subclass, fr->data.ptr, fr->datalen);
+- ast_frfree(fr);
+- } else {
+- *fo = fr;
+- *rc = who;
+- ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass, who->name);
+- return AST_BRIDGE_COMPLETE;
+- }
+- } else {
+- if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
+- (fr->frametype == AST_FRAME_DTMF_END) ||
+- (fr->frametype == AST_FRAME_VOICE) ||
+- (fr->frametype == AST_FRAME_VIDEO) ||
+- (fr->frametype == AST_FRAME_IMAGE) ||
+- (fr->frametype == AST_FRAME_HTML) ||
+- (fr->frametype == AST_FRAME_MODEM) ||
+- (fr->frametype == AST_FRAME_TEXT)) {
+- ast_write(other, fr);
+- }
+- ast_frfree(fr);
+- }
+- /* Swap priority */
+-#ifndef HAVE_EPOLL
+- cs[2] = cs[0];
+- cs[0] = cs[1];
+- cs[1] = cs[2];
+-#endif
+- }
+-
+- ast_poll_channel_del(c0, c1);
+-
+- if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
+- if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
+- ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
+-
+- return AST_BRIDGE_FAILED;
+-}
+-
+-/*! \brief P2P RTP Callback */
+-#ifdef P2P_INTENSE
+-static int p2p_rtp_callback(int *id, int fd, short events, void *cbdata)
+-{
+- int res = 0, hdrlen = 12;
+- struct sockaddr_in sin;
+- socklen_t len;
+- unsigned int *header;
+- struct ast_rtp *rtp = cbdata, *bridged = NULL;
+-
+- if (!rtp)
+- return 1;
+-
+- len = sizeof(sin);
+- if ((res = recvfrom(fd, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0, (struct sockaddr *)&sin, &len)) < 0)
+- return 1;
+-
+- header = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
+-
+- /* If NAT support is turned on, then see if we need to change their address */
+- if ((rtp->nat) &&
+- ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
+- (rtp->them.sin_port != sin.sin_port))) {
+- rtp->them = sin;
+- rtp->rxseqno = 0;
+- ast_set_flag(rtp, FLAG_NAT_ACTIVE);
+- if (option_debug || rtpdebug)
+- ast_debug(0, "P2P RTP NAT: Got audio from other end. Now sending to address %s:%d\n", ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
+- }
+-
+- /* Write directly out to other RTP stream if bridged */
+- if ((bridged = ast_rtp_get_bridged(rtp)))
+- bridge_p2p_rtp_write(rtp, bridged, header, res, hdrlen);
+-
+- return 1;
+-}
+-
+-/*! \brief Helper function to switch a channel and RTP stream into callback mode */
+-static int p2p_callback_enable(struct ast_channel *chan, struct ast_rtp *rtp, int **iod)
+-{
+- /* If we need DTMF, are looking for STUN, or we have no IO structure then we can't do direct callback */
+- if (ast_test_flag(rtp, FLAG_P2P_NEED_DTMF) || ast_test_flag(rtp, FLAG_HAS_STUN) || !rtp->io)
+- return 0;
+-
+- /* If the RTP structure is already in callback mode, remove it temporarily */
+- if (rtp->ioid) {
+- ast_io_remove(rtp->io, rtp->ioid);
+- rtp->ioid = NULL;
+- }
+-
+- /* Steal the file descriptors from the channel */
+- chan->fds[0] = -1;
+-
+- /* Now, fire up callback mode */
+- iod[0] = ast_io_add(rtp->io, ast_rtp_fd(rtp), p2p_rtp_callback, AST_IO_IN, rtp);
+-
+- return 1;
+-}
+-#else
+-static int p2p_callback_enable(struct ast_channel *chan, struct ast_rtp *rtp, int **iod)
+-{
+- return 0;
+-}
+-#endif
+-
+-/*! \brief Helper function to switch a channel and RTP stream out of callback mode */
+-static int p2p_callback_disable(struct ast_channel *chan, struct ast_rtp *rtp, int **iod)
+-{
+- ast_channel_lock(chan);
+-
+- /* Remove the callback from the IO context */
+- ast_io_remove(rtp->io, iod[0]);
+-
+- /* Restore file descriptors */
+- chan->fds[0] = ast_rtp_fd(rtp);
+- ast_channel_unlock(chan);
+-
+- /* Restore callback mode if previously used */
+- if (ast_test_flag(rtp, FLAG_CALLBACK_MODE))
+- rtp->ioid = ast_io_add(rtp->io, ast_rtp_fd(rtp), rtpread, AST_IO_IN, rtp);
+-
+- return 0;
+-}
+-
+-/*! \brief Helper function that sets what an RTP structure is bridged to */
+-static void p2p_set_bridge(struct ast_rtp *rtp0, struct ast_rtp *rtp1)
+-{
+- rtp_bridge_lock(rtp0);
+- rtp0->bridged = rtp1;
+- rtp_bridge_unlock(rtp0);
+-}
+-
+-/*! \brief Bridge loop for partial native bridge (packet2packet)
+-
+- In p2p mode, Asterisk is a very basic RTP proxy, just forwarding whatever
+- rtp/rtcp we get in to the channel.
+- \note this currently only works for Audio
+-*/
+-static enum ast_bridge_result bridge_p2p_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp *p0, struct ast_rtp *p1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
+-{
+- struct ast_frame *fr = NULL;
+- struct ast_channel *who = NULL, *other = NULL, *cs[3] = {NULL, };
+- int *p0_iod[2] = {NULL, NULL}, *p1_iod[2] = {NULL, NULL};
+- int p0_callback = 0, p1_callback = 0;
+- enum ast_bridge_result res = AST_BRIDGE_FAILED;
+-
+- /* Okay, setup each RTP structure to do P2P forwarding */
+- ast_clear_flag(p0, FLAG_P2P_SENT_MARK);
+- p2p_set_bridge(p0, p1);
+- ast_clear_flag(p1, FLAG_P2P_SENT_MARK);
+- p2p_set_bridge(p1, p0);
+-
+- /* Activate callback modes if possible */
+- p0_callback = p2p_callback_enable(c0, p0, &p0_iod[0]);
+- p1_callback = p2p_callback_enable(c1, p1, &p1_iod[0]);
+-
+- /* Now let go of the channel locks and be on our way */
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+-
+- ast_poll_channel_add(c0, c1);
+-
+- /* Go into a loop forwarding frames until we don't need to anymore */
+- cs[0] = c0;
+- cs[1] = c1;
+- cs[2] = NULL;
+- for (;;) {
+- /* If the underlying formats have changed force this bridge to break */
+- if ((c0->rawreadformat != c1->rawwriteformat) || (c1->rawreadformat != c0->rawwriteformat)) {
+- ast_debug(3, "p2p-rtp-bridge: Oooh, formats changed, backing out\n");
+- res = AST_BRIDGE_FAILED_NOWARN;
+- break;
+- }
+- /* Check if anything changed */
+- if ((c0->tech_pvt != pvt0) ||
+- (c1->tech_pvt != pvt1) ||
+- (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
+- (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks)) {
+- ast_debug(3, "p2p-rtp-bridge: Oooh, something is weird, backing out\n");
+- /* If a masquerade needs to happen we have to try to read in a frame so that it actually happens. Without this we risk being called again and going into a loop */
+- if ((c0->masq || c0->masqr) && (fr = ast_read(c0)))
+- ast_frfree(fr);
+- if ((c1->masq || c1->masqr) && (fr = ast_read(c1)))
+- ast_frfree(fr);
+- res = AST_BRIDGE_RETRY;
+- break;
+- }
+- /* Wait on a channel to feed us a frame */
+- if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
+- if (!timeoutms) {
+- res = AST_BRIDGE_RETRY;
+- break;
+- }
+- if (option_debug > 2)
+- ast_log(LOG_NOTICE, "p2p-rtp-bridge: Ooh, empty read...\n");
+- if (ast_check_hangup(c0) || ast_check_hangup(c1))
+- break;
+- continue;
+- }
+- /* Read in frame from channel */
+- fr = ast_read(who);
+- other = (who == c0) ? c1 : c0;
+- /* Depending on the frame we may need to break out of our bridge */
+- if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
+- ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) |
+- ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)))) {
+- /* Record received frame and who */
+- *fo = fr;
+- *rc = who;
+- ast_debug(3, "p2p-rtp-bridge: Ooh, got a %s\n", fr ? "digit" : "hangup");
+- res = AST_BRIDGE_COMPLETE;
+- break;
+- } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
+- if ((fr->subclass == AST_CONTROL_HOLD) ||
+- (fr->subclass == AST_CONTROL_UNHOLD) ||
+- (fr->subclass == AST_CONTROL_VIDUPDATE) ||
+- (fr->subclass == AST_CONTROL_T38) ||
+- (fr->subclass == AST_CONTROL_SRCUPDATE)) {
+- /* If we are going on hold, then break callback mode and P2P bridging */
+- if (fr->subclass == AST_CONTROL_HOLD) {
+- if (p0_callback)
+- p0_callback = p2p_callback_disable(c0, p0, &p0_iod[0]);
+- if (p1_callback)
+- p1_callback = p2p_callback_disable(c1, p1, &p1_iod[0]);
+- p2p_set_bridge(p0, NULL);
+- p2p_set_bridge(p1, NULL);
+- } else if (fr->subclass == AST_CONTROL_UNHOLD) {
+- /* If we are off hold, then go back to callback mode and P2P bridging */
+- ast_clear_flag(p0, FLAG_P2P_SENT_MARK);
+- p2p_set_bridge(p0, p1);
+- ast_clear_flag(p1, FLAG_P2P_SENT_MARK);
+- p2p_set_bridge(p1, p0);
+- p0_callback = p2p_callback_enable(c0, p0, &p0_iod[0]);
+- p1_callback = p2p_callback_enable(c1, p1, &p1_iod[0]);
+- }
+- ast_indicate_data(other, fr->subclass, fr->data.ptr, fr->datalen);
+- ast_frfree(fr);
+- } else {
+- *fo = fr;
+- *rc = who;
+- ast_debug(3, "p2p-rtp-bridge: Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass, who->name);
+- res = AST_BRIDGE_COMPLETE;
+- break;
+- }
+- } else {
+- if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
+- (fr->frametype == AST_FRAME_DTMF_END) ||
+- (fr->frametype == AST_FRAME_VOICE) ||
+- (fr->frametype == AST_FRAME_VIDEO) ||
+- (fr->frametype == AST_FRAME_IMAGE) ||
+- (fr->frametype == AST_FRAME_HTML) ||
+- (fr->frametype == AST_FRAME_MODEM) ||
+- (fr->frametype == AST_FRAME_TEXT)) {
+- ast_write(other, fr);
+- }
+-
+- ast_frfree(fr);
+- }
+- /* Swap priority */
+-#ifndef HAVE_EPOLL
+- cs[2] = cs[0];
+- cs[0] = cs[1];
+- cs[1] = cs[2];
+-#endif
+- }
+-
+- /* If we are totally avoiding the core, then restore our link to it */
+- if (p0_callback)
+- p0_callback = p2p_callback_disable(c0, p0, &p0_iod[0]);
+- if (p1_callback)
+- p1_callback = p2p_callback_disable(c1, p1, &p1_iod[0]);
+-
+- /* Break out of the direct bridge */
+- p2p_set_bridge(p0, NULL);
+- p2p_set_bridge(p1, NULL);
+-
+- ast_poll_channel_del(c0, c1);
+-
+- return res;
+-}
+-
+-/*! \page AstRTPbridge The Asterisk RTP bridge
+- The RTP bridge is called from the channel drivers that are using the RTP
+- subsystem in Asterisk - like SIP, H.323 and Jingle/Google Talk.
+-
+- This bridge aims to offload the Asterisk server by setting up
+- the media stream directly between the endpoints, keeping the
+- signalling in Asterisk.
+-
+- It checks with the channel driver, using a callback function, if
+- there are possibilities for a remote bridge.
+-
+- If this fails, the bridge hands off to the core bridge. Reasons
+- can be NAT support needed, DTMF features in audio needed by
+- the PBX for transfers or spying/monitoring on channels.
+-
+- If transcoding is needed - we can't do a remote bridge.
+- If only NAT support is needed, we're using Asterisk in
+- RTP proxy mode with the p2p RTP bridge, basically
+- forwarding incoming audio packets to the outbound
+- stream on a network level.
+-
+- References:
+- - ast_rtp_bridge()
+- - ast_channel_early_bridge()
+- - ast_channel_bridge()
+- - rtp.c
+- - rtp.h
+-*/
+-/*! \brief Bridge calls. If possible and allowed, initiate
+- re-invite so the peers exchange media directly outside
+- of Asterisk.
+-*/
+-enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
+-{
+- struct ast_rtp *p0 = NULL, *p1 = NULL; /* Audio RTP Channels */
+- struct ast_rtp *vp0 = NULL, *vp1 = NULL; /* Video RTP channels */
+- struct ast_rtp *tp0 = NULL, *tp1 = NULL; /* Text RTP channels */
+- struct ast_rtp_protocol *pr0 = NULL, *pr1 = NULL;
+- enum ast_rtp_get_result audio_p0_res = AST_RTP_GET_FAILED, video_p0_res = AST_RTP_GET_FAILED, text_p0_res = AST_RTP_GET_FAILED;
+- enum ast_rtp_get_result audio_p1_res = AST_RTP_GET_FAILED, video_p1_res = AST_RTP_GET_FAILED, text_p1_res = AST_RTP_GET_FAILED;
+- enum ast_bridge_result res = AST_BRIDGE_FAILED;
+- int codec0 = 0, codec1 = 0;
+- void *pvt0 = NULL, *pvt1 = NULL;
+-
+- /* Lock channels */
+- ast_channel_lock(c0);
+- while (ast_channel_trylock(c1)) {
+- ast_channel_unlock(c0);
+- usleep(1);
+- ast_channel_lock(c0);
+- }
+-
+- /* Ensure neither channel got hungup during lock avoidance */
+- if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
+- ast_log(LOG_WARNING, "Got hangup while attempting to bridge '%s' and '%s'\n", c0->name, c1->name);
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED;
+- }
+-
+- /* Find channel driver interfaces */
+- if (!(pr0 = get_proto(c0))) {
+- ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED;
+- }
+- if (!(pr1 = get_proto(c1))) {
+- ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED;
+- }
+-
+- /* Get channel specific interface structures */
+- pvt0 = c0->tech_pvt;
+- pvt1 = c1->tech_pvt;
+-
+- /* Get audio and video interface (if native bridge is possible) */
+- audio_p0_res = pr0->get_rtp_info(c0, &p0);
+- video_p0_res = pr0->get_vrtp_info ? pr0->get_vrtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
+- text_p0_res = pr0->get_trtp_info ? pr0->get_trtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
+- audio_p1_res = pr1->get_rtp_info(c1, &p1);
+- video_p1_res = pr1->get_vrtp_info ? pr1->get_vrtp_info(c1, &vp1) : AST_RTP_GET_FAILED;
+- text_p1_res = pr1->get_trtp_info ? pr1->get_trtp_info(c1, &vp1) : AST_RTP_GET_FAILED;
+-
+- /* If we are carrying video, and both sides are not reinviting... then fail the native bridge */
+- if (video_p0_res != AST_RTP_GET_FAILED && (audio_p0_res != AST_RTP_TRY_NATIVE || video_p0_res != AST_RTP_TRY_NATIVE))
+- audio_p0_res = AST_RTP_GET_FAILED;
+- if (video_p1_res != AST_RTP_GET_FAILED && (audio_p1_res != AST_RTP_TRY_NATIVE || video_p1_res != AST_RTP_TRY_NATIVE))
+- audio_p1_res = AST_RTP_GET_FAILED;
+-
+- /* Check if a bridge is possible (partial/native) */
+- if (audio_p0_res == AST_RTP_GET_FAILED || audio_p1_res == AST_RTP_GET_FAILED) {
+- /* Somebody doesn't want to play... */
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED_NOWARN;
+- }
+-
+- /* If we need to feed DTMF frames into the core then only do a partial native bridge */
+- if (ast_test_flag(p0, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
+- ast_set_flag(p0, FLAG_P2P_NEED_DTMF);
+- audio_p0_res = AST_RTP_TRY_PARTIAL;
+- }
+-
+- if (ast_test_flag(p1, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
+- ast_set_flag(p1, FLAG_P2P_NEED_DTMF);
+- audio_p1_res = AST_RTP_TRY_PARTIAL;
+- }
+-
+- /* If both sides are not using the same method of DTMF transmission
+- * (ie: one is RFC2833, other is INFO... then we can not do direct media.
+- * --------------------------------------------------
+- * | DTMF Mode | HAS_DTMF | Accepts Begin Frames |
+- * |-----------|------------|-----------------------|
+- * | Inband | False | True |
+- * | RFC2833 | True | True |
+- * | SIP INFO | False | False |
+- * --------------------------------------------------
+- * However, if DTMF from both channels is being monitored by the core, then
+- * we can still do packet-to-packet bridging, because passing through the
+- * core will handle DTMF mode translation.
+- */
+- if ((ast_test_flag(p0, FLAG_HAS_DTMF) != ast_test_flag(p1, FLAG_HAS_DTMF)) ||
+- (!c0->tech->send_digit_begin != !c1->tech->send_digit_begin)) {
+- if (!ast_test_flag(p0, FLAG_P2P_NEED_DTMF) || !ast_test_flag(p1, FLAG_P2P_NEED_DTMF)) {
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED_NOWARN;
+- }
+- audio_p0_res = AST_RTP_TRY_PARTIAL;
+- audio_p1_res = AST_RTP_TRY_PARTIAL;
+- }
+-
+- /* If we need to feed frames into the core don't do a P2P bridge */
+- if ((audio_p0_res == AST_RTP_TRY_PARTIAL && ast_test_flag(p0, FLAG_P2P_NEED_DTMF)) ||
+- (audio_p1_res == AST_RTP_TRY_PARTIAL && ast_test_flag(p1, FLAG_P2P_NEED_DTMF))) {
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED_NOWARN;
+- }
+-
+- /* Get codecs from both sides */
+- codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
+- codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;
+- if (codec0 && codec1 && !(codec0 & codec1)) {
+- /* Hey, we can't do native bridging if both parties speak different codecs */
+- ast_debug(3, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED_NOWARN;
+- }
+-
+- /* If either side can only do a partial bridge, then don't try for a true native bridge */
+- if (audio_p0_res == AST_RTP_TRY_PARTIAL || audio_p1_res == AST_RTP_TRY_PARTIAL) {
+- struct ast_format_list fmt0, fmt1;
+-
+- /* In order to do Packet2Packet bridging both sides must be in the same rawread/rawwrite */
+- if (c0->rawreadformat != c1->rawwriteformat || c1->rawreadformat != c0->rawwriteformat) {
+- ast_debug(1, "Cannot packet2packet bridge - raw formats are incompatible\n");
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED_NOWARN;
+- }
+- /* They must also be using the same packetization */
+- fmt0 = ast_codec_pref_getsize(&p0->pref, c0->rawreadformat);
+- fmt1 = ast_codec_pref_getsize(&p1->pref, c1->rawreadformat);
+- if (fmt0.cur_ms != fmt1.cur_ms) {
+- ast_debug(1, "Cannot packet2packet bridge - packetization settings prevent it\n");
+- ast_channel_unlock(c0);
+- ast_channel_unlock(c1);
+- return AST_BRIDGE_FAILED_NOWARN;
+- }
+-
+- ast_verb(3, "Packet2Packet bridging %s and %s\n", c0->name, c1->name);
+- res = bridge_p2p_loop(c0, c1, p0, p1, timeoutms, flags, fo, rc, pvt0, pvt1);
+- } else {
+- ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
+- res = bridge_native_loop(c0, c1, p0, p1, vp0, vp1, tp0, tp1, pr0, pr1, codec0, codec1, timeoutms, flags, fo, rc, pvt0, pvt1);
+- }
+-
+- return res;
+-}
+-
+-static char *rtp_do_debug_ip(struct ast_cli_args *a)
+-{
+- struct hostent *hp;
+- struct ast_hostent ahp;
+- int port = 0;
+- char *p, *arg;
+-
+- arg = a->argv[3];
+- p = strstr(arg, ":");
+- if (p) {
+- *p = '\0';
+- p++;
+- port = atoi(p);
+- }
+- hp = ast_gethostbyname(arg, &ahp);
+- if (hp == NULL) {
+- ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
+- return CLI_FAILURE;
+- }
+- rtpdebugaddr.sin_family = AF_INET;
+- memcpy(&rtpdebugaddr.sin_addr, hp->h_addr, sizeof(rtpdebugaddr.sin_addr));
+- rtpdebugaddr.sin_port = htons(port);
+- if (port == 0)
+- ast_cli(a->fd, "RTP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtpdebugaddr.sin_addr));
+- else
+- ast_cli(a->fd, "RTP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtpdebugaddr.sin_addr), port);
+- rtpdebug = 1;
+- return CLI_SUCCESS;
+-}
+-
+-static char *rtcp_do_debug_ip(struct ast_cli_args *a)
+-{
+- struct hostent *hp;
+- struct ast_hostent ahp;
+- int port = 0;
+- char *p, *arg;
+-
+- arg = a->argv[3];
+- p = strstr(arg, ":");
+- if (p) {
+- *p = '\0';
+- p++;
+- port = atoi(p);
+- }
+- hp = ast_gethostbyname(arg, &ahp);
+- if (hp == NULL) {
+- ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
+- return CLI_FAILURE;
+- }
+- rtcpdebugaddr.sin_family = AF_INET;
+- memcpy(&rtcpdebugaddr.sin_addr, hp->h_addr, sizeof(rtcpdebugaddr.sin_addr));
+- rtcpdebugaddr.sin_port = htons(port);
+- if (port == 0)
+- ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr));
+- else
+- ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr), port);
+- rtcpdebug = 1;
+- return CLI_SUCCESS;
+-}
+-
+-static char *handle_cli_rtp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+-{
+- switch (cmd) {
+- case CLI_INIT:
+- e->command = "rtp set debug {on|off|ip}";
+- e->usage =
+- "Usage: rtp set debug {on|off|ip host[:port]}\n"
+- " Enable/Disable dumping of all RTP packets. If 'ip' is\n"
+- " specified, limit the dumped packets to those to and from\n"
+- " the specified 'host' with optional port.\n";
+- return NULL;
+- case CLI_GENERATE:
+- return NULL;
+- }
+-
+- if (a->argc == e->args) { /* set on or off */
+- if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
+- rtpdebug = 1;
+- memset(&rtpdebugaddr, 0, sizeof(rtpdebugaddr));
+- ast_cli(a->fd, "RTP Debugging Enabled\n");
+- return CLI_SUCCESS;
+- } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
+- rtpdebug = 0;
+- ast_cli(a->fd, "RTP Debugging Disabled\n");
+- return CLI_SUCCESS;
+- }
+- } else if (a->argc == e->args +1) { /* ip */
+- return rtp_do_debug_ip(a);
+- }
+-
+- return CLI_SHOWUSAGE; /* default, failure */
+-}
+-
+-static char *handle_cli_rtcp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+-{
+- switch (cmd) {
+- case CLI_INIT:
+- e->command = "rtcp set debug {on|off|ip}";
+- e->usage =
+- "Usage: rtcp set debug {on|off|ip host[:port]}\n"
+- " Enable/Disable dumping of all RTCP packets. If 'ip' is\n"
+- " specified, limit the dumped packets to those to and from\n"
+- " the specified 'host' with optional port.\n";
+- return NULL;
+- case CLI_GENERATE:
+- return NULL;
+- }
+-
+- if (a->argc == e->args) { /* set on or off */
+- if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
+- rtcpdebug = 1;
+- memset(&rtcpdebugaddr, 0, sizeof(rtcpdebugaddr));
+- ast_cli(a->fd, "RTCP Debugging Enabled\n");
+- return CLI_SUCCESS;
+- } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
+- rtcpdebug = 0;
+- ast_cli(a->fd, "RTCP Debugging Disabled\n");
+- return CLI_SUCCESS;
+- }
+- } else if (a->argc == e->args +1) { /* ip */
+- return rtcp_do_debug_ip(a);
+- }
+-
+- return CLI_SHOWUSAGE; /* default, failure */
+-}
+-
+-static char *handle_cli_rtcp_set_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+-{
+- switch (cmd) {
+- case CLI_INIT:
+- e->command = "rtcp set stats {on|off}";
+- e->usage =
+- "Usage: rtcp set stats {on|off}\n"
+- " Enable/Disable dumping of RTCP stats.\n";
+- return NULL;
+- case CLI_GENERATE:
+- return NULL;
+- }
+-
+- if (a->argc != e->args)
+- return CLI_SHOWUSAGE;
+-
+- if (!strncasecmp(a->argv[e->args-1], "on", 2))
+- rtcpstats = 1;
+- else if (!strncasecmp(a->argv[e->args-1], "off", 3))
+- rtcpstats = 0;
+- else
+- return CLI_SHOWUSAGE;
+-
+- ast_cli(a->fd, "RTCP Stats %s\n", rtcpstats ? "Enabled" : "Disabled");
+- return CLI_SUCCESS;
+-}
+-
+-static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+-{
+- switch (cmd) {
+- case CLI_INIT:
+- e->command = "stun set debug {on|off}";
+- e->usage =
+- "Usage: stun set debug {on|off}\n"
+- " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
+- " debugging\n";
+- return NULL;
+- case CLI_GENERATE:
+- return NULL;
+- }
+-
+- if (a->argc != e->args)
+- return CLI_SHOWUSAGE;
+-
+- if (!strncasecmp(a->argv[e->args-1], "on", 2))
+- stundebug = 1;
+- else if (!strncasecmp(a->argv[e->args-1], "off", 3))
+- stundebug = 0;
+- else
+- return CLI_SHOWUSAGE;
+-
+- ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
+- return CLI_SUCCESS;
+-}
+-
+-static struct ast_cli_entry cli_rtp[] = {
+- AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging"),
+- AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging"),
+- AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"),
+- AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
+-};
+-
+-static int __ast_rtp_reload(int reload)
+-{
+- struct ast_config *cfg;
+- const char *s;
+- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+-
+- cfg = ast_config_load2("rtp.conf", "rtp", config_flags);
+- if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
+- return 0;
+- }
+-
+- rtpstart = 5000;
+- rtpend = 31000;
+- dtmftimeout = DEFAULT_DTMF_TIMEOUT;
+- strictrtp = STRICT_RTP_OPEN;
+- if (cfg) {
+- if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
+- rtpstart = atoi(s);
+- if (rtpstart < 1024)
+- rtpstart = 1024;
+- if (rtpstart > 65535)
+- rtpstart = 65535;
+- }
+- if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
+- rtpend = atoi(s);
+- if (rtpend < 1024)
+- rtpend = 1024;
+- if (rtpend > 65535)
+- rtpend = 65535;
+- }
+- if ((s = ast_variable_retrieve(cfg, "general", "rtcpinterval"))) {
+- rtcpinterval = atoi(s);
+- if (rtcpinterval == 0)
+- rtcpinterval = 0; /* Just so we're clear... it's zero */
+- if (rtcpinterval < RTCP_MIN_INTERVALMS)
+- rtcpinterval = RTCP_MIN_INTERVALMS; /* This catches negative numbers too */
+- if (rtcpinterval > RTCP_MAX_INTERVALMS)
+- rtcpinterval = RTCP_MAX_INTERVALMS;
+- }
+- if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
+-#ifdef SO_NO_CHECK
+- if (ast_false(s))
+- nochecksums = 1;
+- else
+- nochecksums = 0;
+-#else
+- if (ast_false(s))
+- ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
+-#endif
+- }
+- if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
+- dtmftimeout = atoi(s);
+- if ((dtmftimeout < 0) || (dtmftimeout > 20000)) {
+- ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
+- dtmftimeout, DEFAULT_DTMF_TIMEOUT);
+- dtmftimeout = DEFAULT_DTMF_TIMEOUT;
+- };
+- }
+- if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
+- strictrtp = ast_true(s);
+- }
+- ast_config_destroy(cfg);
+- }
+- if (rtpstart >= rtpend) {
+- ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
+- rtpstart = 5000;
+- rtpend = 31000;
+- }
+- ast_verb(2, "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
+- return 0;
+-}
+-
+-int ast_rtp_reload(void)
+-{
+- return __ast_rtp_reload(1);
+-}
+-
+-/*! \brief Initialize the RTP system in Asterisk */
+-void ast_rtp_init(void)
+-{
+- ast_cli_register_multiple(cli_rtp, sizeof(cli_rtp) / sizeof(struct ast_cli_entry));
+- __ast_rtp_reload(0);
+-}
+-
+-/*! \brief Write t140 redundacy frame
+- * \param data primary data to be buffered
+- */
+-static int red_write(const void *data)
+-{
+- struct ast_rtp *rtp = (struct ast_rtp*) data;
+-
+- ast_rtp_write(rtp, &rtp->red->t140);
+-
+- return 1;
+-}
+-
+-/*! \brief Construct a redundant frame
+- * \param red redundant data structure
+- */
+-static struct ast_frame *red_t140_to_red(struct rtp_red *red) {
+- unsigned char *data = red->t140red.data.ptr;
+- int len = 0;
+- int i;
+-
+- /* replace most aged generation */
+- if (red->len[0]) {
+- for (i = 1; i < red->num_gen+1; i++)
+- len += red->len[i];
+-
+- memmove(&data[red->hdrlen], &data[red->hdrlen+red->len[0]], len);
+- }
+-
+- /* Store length of each generation and primary data length*/
+- for (i = 0; i < red->num_gen; i++)
+- red->len[i] = red->len[i+1];
+- red->len[i] = red->t140.datalen;
+-
+- /* write each generation length in red header */
+- len = red->hdrlen;
+- for (i = 0; i < red->num_gen; i++)
+- len += data[i*4+3] = red->len[i];
+-
+- /* add primary data to buffer */
+- memcpy(&data[len], red->t140.data.ptr, red->t140.datalen);
+- red->t140red.datalen = len + red->t140.datalen;
+-
+- /* no primary data and no generations to send */
+- if (len == red->hdrlen && !red->t140.datalen)
+- return NULL;
+-
+- /* reset t.140 buffer */
+- red->t140.datalen = 0;
+-
+- return &red->t140red;
+-}
+-
+-/*! \brief Initialize t140 redundancy
+- * \param rtp
+- * \param ti buffer t140 for ti (msecs) before sending redundant frame
+- * \param red_data_pt Payloadtypes for primary- and generation-data
+- * \param num_gen numbers of generations (primary generation not encounted)
+- *
+-*/
+-int rtp_red_init(struct ast_rtp *rtp, int ti, int *red_data_pt, int num_gen)
+-{
+- struct rtp_red *r;
+- int x;
+-
+- if (!(r = ast_calloc(1, sizeof(struct rtp_red))))
+- return -1;
+-
+- r->t140.frametype = AST_FRAME_TEXT;
+- r->t140.subclass = AST_FORMAT_T140RED;
+- r->t140.data.ptr = &r->buf_data;
+-
+- r->t140.ts = 0;
+- r->t140red = r->t140;
+- r->t140red.data.ptr = &r->t140red_data;
+- r->t140red.datalen = 0;
+- r->ti = ti;
+- r->num_gen = num_gen;
+- r->hdrlen = num_gen * 4 + 1;
+- r->prev_ts = 0;
+-
+- for (x = 0; x < num_gen; x++) {
+- r->pt[x] = red_data_pt[x];
+- r->pt[x] |= 1 << 7; /* mark redundant generations pt */
+- r->t140red_data[x*4] = r->pt[x];
+- }
+- r->t140red_data[x*4] = r->pt[x] = red_data_pt[x]; /* primary pt */
+- r->schedid = ast_sched_add(rtp->sched, ti, red_write, rtp);
+- rtp->red = r;
+-
+- r->t140.datalen = 0;
+-
+- return 0;
+-}
+-
+-/*! \brief Buffer t140 from chan_sip
+- * \param rtp
+- * \param f frame
+- */
+-void red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f)
+-{
+- if (f->datalen > -1) {
+- struct rtp_red *red = rtp->red;
+- memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen);
+- red->t140.datalen += f->datalen;
+- red->t140.ts = f->ts;
+- }
+-}
+Index: main/utils.c
+===================================================================
+--- a/main/utils.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/utils.c (.../trunk) (revision 186562)
+@@ -1469,8 +1469,33 @@
+ * stringfields support routines.
+ */
+
+-const char __ast_string_field_empty[] = ""; /*!< the empty string */
++/* this is a little complex... string fields are stored with their
++ allocated size in the bytes preceding the string; even the
++ constant 'empty' string has to be this way, so the code that
++ checks to see if there is enough room for a new string doesn't
++ have to have any special case checks
++*/
+
++static const struct {
++ ast_string_field_allocation allocation;
++ char string[1];
++} __ast_string_field_empty_buffer;
++
++ast_string_field __ast_string_field_empty = __ast_string_field_empty_buffer.string;
++
++#define ALLOCATOR_OVERHEAD 48
++
++static size_t optimal_alloc_size(size_t size)
++{
++ unsigned int count;
++
++ size += ALLOCATOR_OVERHEAD;
++
++ for (count = 1; size; size >>= 1, count++);
++
++ return (1 << count) - ALLOCATOR_OVERHEAD;
++}
++
+ /*! \brief add a new block to the pool.
+ * We can only allocate from the topmost pool, so the
+ * fields in *mgr reflect the size of that only.
+@@ -1480,14 +1505,15 @@
+ size_t size)
+ {
+ struct ast_string_field_pool *pool;
++ size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
+
+- if (!(pool = ast_calloc(1, sizeof(*pool) + size)))
++ if (!(pool = ast_calloc(1, alloc_size))) {
+ return -1;
+-
++ }
++
+ pool->prev = *pool_head;
++ pool->size = alloc_size - sizeof(*pool);
+ *pool_head = pool;
+- mgr->size = size;
+- mgr->used = 0;
+ mgr->last_alloc = NULL;
+
+ return 0;
+@@ -1511,13 +1537,16 @@
+ struct ast_string_field_pool *cur = *pool_head;
+
+ /* clear fields - this is always necessary */
+- while ((struct ast_string_field_mgr *) p != mgr)
++ while ((struct ast_string_field_mgr *) p != mgr) {
+ *p++ = __ast_string_field_empty;
++ }
++
+ mgr->last_alloc = NULL;
+ if (size > 0) { /* allocate the initial pool */
+ *pool_head = NULL;
+ return add_string_pool(mgr, pool_head, size);
+ }
++
+ if (size < 0) { /* reset all pools */
+ *pool_head = NULL;
+ } else { /* preserve the first pool */
+@@ -1527,7 +1556,7 @@
+ }
+ cur = cur->prev;
+ (*pool_head)->prev = NULL;
+- mgr->used = 0;
++ (*pool_head)->used = (*pool_head)->active = 0;
+ }
+
+ while (cur) {
+@@ -1544,34 +1573,37 @@
+ struct ast_string_field_pool **pool_head, size_t needed)
+ {
+ char *result = NULL;
+- size_t space = mgr->size - mgr->used;
++ size_t space = (*pool_head)->size - (*pool_head)->used;
++ size_t to_alloc = needed + sizeof(ast_string_field_allocation);
+
+- if (__builtin_expect(needed > space, 0)) {
+- size_t new_size = mgr->size * 2;
++ if (__builtin_expect(to_alloc > space, 0)) {
++ size_t new_size = (*pool_head)->size;
+
+- while (new_size < needed)
++ while (new_size < to_alloc) {
+ new_size *= 2;
++ }
+
+ if (add_string_pool(mgr, pool_head, new_size))
+ return NULL;
+ }
+
+- result = (*pool_head)->base + mgr->used;
+- mgr->used += needed;
++ result = (*pool_head)->base + (*pool_head)->used;
++ (*pool_head)->used += to_alloc;
++ (*pool_head)->active += needed;
++ result += sizeof(ast_string_field_allocation);
++ AST_STRING_FIELD_ALLOCATION(result) = needed;
+ mgr->last_alloc = result;
++
+ return result;
+ }
+
+-int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
++int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr,
++ struct ast_string_field_pool **pool_head, size_t needed,
+ const ast_string_field *ptr)
+ {
+- int grow = needed - (strlen(*ptr) + 1);
+- size_t space = mgr->size - mgr->used;
++ ssize_t grow = needed - AST_STRING_FIELD_ALLOCATION(*ptr);
++ size_t space = (*pool_head)->size - (*pool_head)->used;
+
+- if (grow <= 0) {
+- return 0;
+- }
+-
+ if (*ptr != mgr->last_alloc) {
+ return 1;
+ }
+@@ -1580,30 +1612,57 @@
+ return 1;
+ }
+
+- mgr->used += grow;
++ (*pool_head)->used += grow;
++ (*pool_head)->active += grow;
++ AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
+
+ return 0;
+ }
+
++void __ast_string_field_release_active(struct ast_string_field_pool *pool_head,
++ const ast_string_field ptr)
++{
++ struct ast_string_field_pool *pool, *prev;
++
++ if (ptr == __ast_string_field_empty) {
++ return;
++ }
++
++ for (pool = pool_head, prev = NULL; pool; prev = pool, pool = pool->prev) {
++ if ((ptr >= pool->base) && (ptr <= (pool->base + pool->size))) {
++ pool->active -= AST_STRING_FIELD_ALLOCATION(ptr);
++ if ((pool->active == 0) && prev) {
++ prev->prev = pool->prev;
++ ast_free(pool);
++ }
++ break;
++ }
++ }
++}
++
+ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
+ struct ast_string_field_pool **pool_head,
+ ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
+ {
+ size_t needed;
+ size_t available;
+- size_t space = mgr->size - mgr->used;
++ size_t space = (*pool_head)->size - (*pool_head)->used;
++ ssize_t grow;
+ char *target;
+
+ /* if the field already has space allocated, try to reuse it;
+- otherwise, use the empty space at the end of the current
++ otherwise, try to use the empty space at the end of the current
+ pool
+ */
+- if ((*ptr)[0] != '\0') {
++ if (*ptr != __ast_string_field_empty) {
+ target = (char *) *ptr;
+- available = strlen(target) + 1;
++ available = AST_STRING_FIELD_ALLOCATION(*ptr);
++ if (*ptr == mgr->last_alloc) {
++ available += space;
++ }
+ } else {
+- target = (*pool_head)->base + mgr->used;
+- available = space;
++ target = (*pool_head)->base + (*pool_head)->used + sizeof(ast_string_field_allocation);
++ available = space - sizeof(ast_string_field_allocation);
+ }
+
+ needed = vsnprintf(target, available, format, ap1) + 1;
+@@ -1611,28 +1670,32 @@
+ va_end(ap1);
+
+ if (needed > available) {
+- /* if the space needed can be satisfied by using the current
+- pool (which could only occur if we tried to use the field's
+- allocated space and failed), then use that space; otherwise
+- allocate a new pool
++ /* the allocation could not be satisfied using the field's current allocation
++ (if it has one), or the space available in the pool (if it does not). allocate
++ space for it, adding a new string pool if necessary.
+ */
+- if (needed > space) {
+- size_t new_size = mgr->size * 2;
+-
+- while (new_size < needed)
+- new_size *= 2;
+-
+- if (add_string_pool(mgr, pool_head, new_size))
+- return;
++ if (!(target = (char *) __ast_string_field_alloc_space(mgr, pool_head, needed))) {
++ return;
+ }
+-
+- target = (*pool_head)->base + mgr->used;
+ vsprintf(target, format, ap2);
+- }
+-
+- if (*ptr != target) {
++ __ast_string_field_release_active(*pool_head, *ptr);
++ *ptr = target;
++ } else if (*ptr != target) {
++ /* the allocation was satisfied using available space in the pool, but not
++ using the space already allocated to the field
++ */
++ __ast_string_field_release_active(*pool_head, *ptr);
+ mgr->last_alloc = *ptr = target;
+- mgr->used += needed;
++ AST_STRING_FIELD_ALLOCATION(target) = needed;
++ (*pool_head)->used += needed + sizeof(ast_string_field_allocation);
++ (*pool_head)->active += needed;
++ } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {
++ /* the allocation was satisfied by using available space in the pool *and*
++ the field was the last allocated field from the pool, so it grew
++ */
++ (*pool_head)->used += grow;
++ (*pool_head)->active += grow;
++ AST_STRING_FIELD_ALLOCATION(*ptr) += grow;
+ }
+ }
+
+Index: main/loader.c
+===================================================================
+--- a/main/loader.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/loader.c (.../trunk) (revision 186562)
+@@ -43,7 +43,6 @@
+ #include "asterisk/manager.h"
+ #include "asterisk/cdr.h"
+ #include "asterisk/enum.h"
+-#include "asterisk/rtp.h"
+ #include "asterisk/http.h"
+ #include "asterisk/lock.h"
+ #include "asterisk/features.h"
+@@ -243,7 +242,6 @@
+ { "extconfig", read_config_maps },
+ { "enum", ast_enum_reload },
+ { "manager", reload_manager },
+- { "rtp", ast_rtp_reload },
+ { "http", ast_http_reload },
+ { "logger", logger_reload },
+ { "features", ast_features_reload },
+@@ -403,18 +401,6 @@
+ return NULL;
+ }
+
+- /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
+- on the already-opened library to what we want... if not, we have to
+- close it and start over
+- */
+-#if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
+- if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
+- ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
+- while (!dlclose(lib));
+- ast_free(resource_being_loaded);
+- return NULL;
+- }
+-#else
+ while (!dlclose(lib));
+ resource_being_loaded = NULL;
+
+@@ -435,7 +421,6 @@
+ /* since the module was successfully opened, and it registered itself
+ the previous time we did that, we're going to assume it worked this
+ time too :) */
+-#endif
+
+ AST_LIST_LAST(&module_list)->lib = lib;
+ resource_being_loaded = NULL;
+Index: main/channel.c
+===================================================================
+--- a/main/channel.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/channel.c (.../trunk) (revision 186562)
+@@ -718,6 +718,8 @@
+ AST_FORMAT_ULAW,
+ /*! Unless of course, you're a silly European, so then prefer ALAW */
+ AST_FORMAT_ALAW,
++ AST_FORMAT_SIREN14,
++ AST_FORMAT_SIREN7,
+ /*! G.722 is better then all below, but not as common as the above... so give ulaw and alaw priority */
+ AST_FORMAT_G722,
+ /*! Okay, well, signed linear is easy to translate into other stuff */
+@@ -794,6 +796,13 @@
+ return NULL;
+ }
+
++ if (!(tmp->cid.cid_name = ast_strdup(cid_name)) || !(tmp->cid.cid_num = ast_strdup(cid_num))) {
++ ast_string_field_free_memory(tmp);
++ sched_context_destroy(tmp->sched);
++ ast_free(tmp);
++ return NULL;
++ }
++
+ #ifdef HAVE_EPOLL
+ tmp->epfd = epoll_create(25);
+ #endif
+@@ -805,17 +814,19 @@
+ #endif
+ }
+
+- tmp->timingfd = ast_timer_open();
+- if (tmp->timingfd > -1) {
++ if ((tmp->timer = ast_timer_open())) {
+ needqueue = 0;
++ tmp->timingfd = ast_timer_fd(tmp->timer);
++ } else {
++ tmp->timingfd = -1;
+ }
+
+ if (needqueue) {
+ if (pipe(tmp->alertpipe)) {
+ ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
+ alertpipe_failed:
+- if (tmp->timingfd > -1) {
+- ast_timer_close(tmp->timingfd);
++ if (tmp->timer) {
++ ast_timer_close(tmp->timer);
+ }
+
+ sched_context_destroy(tmp->sched);
+@@ -862,9 +873,6 @@
+ ast_string_field_build(tmp, uniqueid, "%s-%li.%d", ast_config_AST_SYSTEM_NAME,
+ (long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
+ }
+-
+- tmp->cid.cid_name = ast_strdup(cid_name);
+- tmp->cid.cid_num = ast_strdup(cid_num);
+
+ if (!ast_strlen_zero(name_fmt)) {
+ /* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
+@@ -1008,7 +1016,7 @@
+ chan->name, f->frametype, f->subclass, qlen, strerror(errno));
+ }
+ } else if (chan->timingfd > -1) {
+- ast_timer_enable_continuous(chan->timingfd);
++ ast_timer_enable_continuous(chan->timer);
+ } else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) {
+ pthread_kill(chan->blocker, SIGURG);
+ }
+@@ -1307,6 +1315,279 @@
+ cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = cid->cid_rdnis = NULL;
+ }
+
++/*!
++ * \internal
++ * \brief Initialize the given party id structure.
++ *
++ * \param init Party id structure to initialize.
++ *
++ * \return Nothing
++ */
++static void ast_party_id_init(struct ast_party_id *init)
++{
++ init->number = NULL;
++ init->name = NULL;
++ init->number_type = 0; /* Unknown */
++ init->number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
++}
++
++/*!
++ * \internal
++ * \brief Copy the source party id information to the destination party id.
++ *
++ * \param dest Destination party id
++ * \param src Source party id
++ *
++ * \return Nothing
++ */
++static void ast_party_id_copy(struct ast_party_id *dest, const struct ast_party_id *src)
++{
++ if (dest == src) {
++ /* Don't copy to self */
++ return;
++ }
++
++ if (dest->number) {
++ ast_free(dest->number);
++ }
++ dest->number = ast_strdup(src->number);
++
++ if (dest->name) {
++ ast_free(dest->name);
++ }
++ dest->name = ast_strdup(src->name);
++
++ dest->number_type = src->number_type;
++ dest->number_presentation = src->number_presentation;
++}
++
++/*!
++ * \internal
++ * \brief Initialize the given party id structure using the given guide
++ * for a set update operation.
++ *
++ * \details
++ * The initialization is needed to allow a set operation to know if a
++ * value needs to be updated. Simple integers need the guide's original
++ * value in case the set operation is not trying to set a new value.
++ * String values are simply set to NULL pointers if they are not going
++ * to be updated.
++ *
++ * \param init Party id structure to initialize.
++ * \param guide Source party id to use as a guide in initializing.
++ *
++ * \return Nothing
++ */
++static void ast_party_id_set_init(struct ast_party_id *init, const struct ast_party_id *guide)
++{
++ init->number = NULL;
++ init->name = NULL;
++ init->number_type = guide->number_type;
++ init->number_presentation = guide->number_presentation;
++}
++
++/*!
++ * \internal
++ * \brief Set the source party id information into the destination party id.
++ *
++ * \param dest Destination party id
++ * \param src Source party id
++ *
++ * \return Nothing
++ */
++static void ast_party_id_set(struct ast_party_id *dest, const struct ast_party_id *src)
++{
++ if (dest == src) {
++ /* Don't set to self */
++ return;
++ }
++
++ if (src->name && src->name != dest->name) {
++ if (dest->name) {
++ ast_free(dest->name);
++ }
++ dest->name = ast_strdup(src->name);
++ }
++
++ if (src->number && src->number != dest->number) {
++ if (dest->number) {
++ ast_free(dest->number);
++ }
++ dest->number = ast_strdup(src->number);
++ }
++
++ dest->number_type = src->number_type;
++ dest->number_presentation = src->number_presentation;
++}
++
++/*!
++ * \internal
++ * \brief Destroy the party id contents
++ *
++ * \param doomed The party id to destroy.
++ *
++ * \return Nothing
++ */
++static void ast_party_id_free(struct ast_party_id *doomed)
++{
++ if (doomed->number) {
++ ast_free(doomed->number);
++ doomed->number = NULL;
++ }
++
++ if (doomed->name) {
++ ast_free(doomed->name);
++ doomed->name = NULL;
++ }
++}
++
++void ast_party_caller_copy(struct ast_callerid *dest, const struct ast_callerid *src)
++{
++ if (dest == src) {
++ /* Don't copy to self */
++ return;
++ }
++
++#if 1
++ /* Copy caller-id specific information ONLY from struct ast_callerid */
++ if (dest->cid_num)
++ {
++ ast_free(dest->cid_num);
++ }
++ dest->cid_num = ast_strdup(src->cid_num);
++
++ if (dest->cid_name)
++ {
++ ast_free(dest->cid_name);
++ }
++ dest->cid_name = ast_strdup(src->cid_name);
++
++ dest->cid_ton = src->cid_ton;
++ dest->cid_pres = src->cid_pres;
++
++
++ if (dest->cid_ani)
++ {
++ ast_free(dest->cid_ani);
++ }
++ dest->cid_ani = ast_strdup(src->cid_ani);
++
++ dest->cid_ani2 = src->cid_ani2;
++
++#else
++
++ /* The src and dest parameter types will become struct ast_party_caller ptrs. */
++ /* This is future code */
++
++ ast_party_id_copy(&dest->id, &src->id);
++
++ if (dest->ani) {
++ ast_free(dest->ani);
++ }
++ dest->ani = ast_strdup(src->ani);
++
++ dest->ani2 = src->ani2;
++#endif
++}
++
++void ast_party_connected_line_init(struct ast_party_connected_line *init)
++{
++ ast_party_id_init(&init->id);
++ init->ani = NULL;
++ init->ani2 = 0;
++ init->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
++}
++
++void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
++{
++ if (dest == src) {
++ /* Don't copy to self */
++ return;
++ }
++
++ ast_party_id_copy(&dest->id, &src->id);
++
++ if (dest->ani) {
++ ast_free(dest->ani);
++ }
++ dest->ani = ast_strdup(src->ani);
++
++ dest->ani2 = src->ani2;
++ dest->source = src->source;
++}
++
++void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
++{
++ ast_party_id_set_init(&init->id, &guide->id);
++ init->ani = NULL;
++ init->ani2 = guide->ani2;
++ init->source = guide->source;
++}
++
++void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
++{
++ ast_party_id_set(&dest->id, &src->id);
++
++ if (src->ani && src->ani != dest->ani) {
++ if (dest->ani) {
++ ast_free(dest->ani);
++ }
++ dest->ani = ast_strdup(src->ani);
++ }
++
++ dest->ani2 = src->ani2;
++ dest->source = src->source;
++}
++
++void ast_party_connected_line_collect_caller(struct ast_party_connected_line *connected, struct ast_callerid *cid)
++{
++ connected->id.number = cid->cid_num;
++ connected->id.name = cid->cid_name;
++ connected->id.number_type = cid->cid_ton;
++ connected->id.number_presentation = cid->cid_pres;
++
++ connected->ani = cid->cid_ani;
++ connected->ani2 = cid->cid_ani2;
++ connected->source = AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN;
++}
++
++void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
++{
++ ast_party_id_free(&doomed->id);
++
++ if (doomed->ani) {
++ ast_free(doomed->ani);
++ doomed->ani = NULL;
++ }
++}
++
++void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
++{
++ if (dest == src) {
++ /* Don't copy to self */
++ return;
++ }
++
++ ast_party_id_copy(&dest->from, &src->from);
++ ast_party_id_copy(&dest->to, &src->to);
++ dest->count = src->count;
++ dest->reason = src->reason;
++}
++
++void ast_party_redirecting_set_init(struct ast_party_redirecting *init, const struct ast_party_redirecting *guide)
++{
++ ast_party_id_set_init(&init->from, &guide->from);
++ ast_party_id_set_init(&init->to, &guide->to);
++ init->count = guide->count;
++ init->reason = guide->reason;
++}
++
++void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
++{
++ ast_party_id_free(&doomed->from);
++ ast_party_id_free(&doomed->to);
++}
++
+ /*! \brief Free a channel structure */
+ void ast_channel_free(struct ast_channel *chan)
+ {
+@@ -1370,14 +1651,19 @@
+ ast_translator_free_path(chan->writetrans);
+ if (chan->pbx)
+ ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
++
+ free_cid(&chan->cid);
++ ast_party_connected_line_free(&chan->connected);
++ ast_party_redirecting_free(&chan->redirecting);
++
+ /* Close pipes if appropriate */
+ if ((fd = chan->alertpipe[0]) > -1)
+ close(fd);
+ if ((fd = chan->alertpipe[1]) > -1)
+ close(fd);
+- if ((fd = chan->timingfd) > -1)
+- ast_timer_close(fd);
++ if (chan->timer) {
++ ast_timer_close(chan->timer);
++ }
+ #ifdef HAVE_EPOLL
+ for (i = 0; i < AST_MAX_FDS; i++) {
+ if (chan->epfd_data[i])
+@@ -2323,13 +2609,13 @@
+ data = NULL;
+ }
+
+- if (rate && rate > (max_rate = ast_timer_get_max_rate(c->timingfd))) {
++ if (rate && rate > (max_rate = ast_timer_get_max_rate(c->timer))) {
+ real_rate = max_rate;
+ }
+
+ ast_debug(1, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate);
+
+- res = ast_timer_set_rate(c->timingfd, real_rate);
++ res = ast_timer_set_rate(c->timer, real_rate);
+
+ c->timingfunc = func;
+ c->timingdata = data;
+@@ -2391,6 +2677,8 @@
+ case AST_CONTROL_RINGING:
+ case AST_CONTROL_ANSWER:
+ case AST_CONTROL_SRCUPDATE:
++ case AST_CONTROL_CONNECTED_LINE:
++ case AST_CONTROL_REDIRECTING:
+ /* Unimportant */
+ break;
+ default:
+@@ -2582,11 +2870,11 @@
+
+ ast_clear_flag(chan, AST_FLAG_EXCEPTION);
+
+- res = ast_timer_get_event(chan->timingfd);
++ res = ast_timer_get_event(chan->timer);
+
+ switch (res) {
+ case AST_TIMING_EVENT_EXPIRED:
+- ast_timer_ack(chan->timingfd, 1);
++ ast_timer_ack(chan->timer, 1);
+
+ if (chan->timingfunc) {
+ /* save a copy of func/data before unlocking the channel */
+@@ -2596,7 +2884,7 @@
+ ast_channel_unlock(chan);
+ func(data);
+ } else {
+- ast_timer_set_rate(chan->timingfd, 0);
++ ast_timer_set_rate(chan->timer, 0);
+ chan->fdno = -1;
+ ast_channel_unlock(chan);
+ }
+@@ -2607,7 +2895,7 @@
+ case AST_TIMING_EVENT_CONTINUOUS:
+ if (AST_LIST_EMPTY(&chan->readq) ||
+ !AST_LIST_NEXT(AST_LIST_FIRST(&chan->readq), frame_list)) {
+- ast_timer_disable_continuous(chan->timingfd);
++ ast_timer_disable_continuous(chan->timer);
+ }
+ break;
+ }
+@@ -2823,6 +3111,13 @@
+ ast_clear_flag(chan, AST_FLAG_EMULATE_DTMF);
+ chan->emulate_dtmf_digit = 0;
+ ast_log(LOG_DTMF, "DTMF end emulation of '%c' queued on %s\n", f->subclass, chan->name);
++ if (chan->audiohooks) {
++ struct ast_frame *old_frame = f;
++ f = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_READ, f);
++ if (old_frame != f) {
++ ast_frfree(old_frame);
++ }
++ }
+ }
+ }
+ break;
+@@ -2982,7 +3277,10 @@
+ case AST_CONTROL_ANSWER:
+ case AST_CONTROL_HANGUP:
+ case AST_CONTROL_T38:
+- return 0;
++ case AST_CONTROL_CONNECTED_LINE:
++ case AST_CONTROL_REDIRECTING:
++ case AST_CONTROL_TRANSFER:
++ break;
+
+ case AST_CONTROL_CONGESTION:
+ case AST_CONTROL_BUSY:
+@@ -3003,7 +3301,7 @@
+ * in switch statements. */
+ enum ast_control_frame_type condition = _condition;
+ struct ast_tone_zone_sound *ts = NULL;
+- int res = -1;
++ int res;
+
+ ast_channel_lock(chan);
+
+@@ -3012,10 +3310,41 @@
+ ast_channel_unlock(chan);
+ return -1;
+ }
++ switch (condition) {
++ case AST_CONTROL_CONNECTED_LINE:
++ {
++ struct ast_party_connected_line connected;
+
++ ast_party_connected_line_set_init(&connected, &chan->connected);
++ res = ast_connected_line_parse_data(data, datalen, &connected);
++ if (!res) {
++ ast_channel_set_connected_line(chan, &connected);
++ }
++ ast_party_connected_line_free(&connected);
++ }
++ break;
++
++ case AST_CONTROL_REDIRECTING:
++ {
++ struct ast_party_redirecting redirecting;
++
++ ast_party_redirecting_set_init(&redirecting, &chan->redirecting);
++ res = ast_redirecting_parse_data(data, datalen, &redirecting);
++ if (!res) {
++ ast_channel_set_redirecting(chan, &redirecting);
++ }
++ ast_party_redirecting_free(&redirecting);
++ }
++ break;
++
++ default:
++ break;
++ }
+ if (chan->tech->indicate) {
+ /* See if the channel driver can handle this condition. */
+ res = chan->tech->indicate(chan, condition, data, datalen);
++ } else {
++ res = -1;
+ }
+
+ ast_channel_unlock(chan);
+@@ -3068,6 +3397,9 @@
+ case AST_CONTROL_HOLD:
+ case AST_CONTROL_UNHOLD:
+ case AST_CONTROL_T38:
++ case AST_CONTROL_TRANSFER:
++ case AST_CONTROL_CONNECTED_LINE:
++ case AST_CONTROL_REDIRECTING:
+ /* Nothing left to do for these. */
+ res = 0;
+ break;
+@@ -3530,6 +3862,7 @@
+ struct ast_channel *chan;
+ int res = 0;
+ int last_subclass = 0;
++ struct ast_party_connected_line connected;
+
+ if (outstate)
+ *outstate = 0;
+@@ -3560,7 +3893,13 @@
+ if (oh->account)
+ ast_cdr_setaccount(chan, oh->account);
+ }
++
+ ast_set_callerid(chan, cid_num, cid_name, cid_num);
++ ast_party_connected_line_set_init(&connected, &chan->connected);
++ connected.id.number = (char *) cid_num;
++ connected.id.name = (char *) cid_name;
++ connected.id.number_presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
++ ast_channel_set_connected_line(chan, &connected);
+
+ if (ast_call(chan, data, 0)) { /* ast_call failed... */
+ ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
+@@ -3599,6 +3938,8 @@
+ case AST_CONTROL_UNHOLD:
+ case AST_CONTROL_VIDUPDATE:
+ case AST_CONTROL_SRCUPDATE:
++ case AST_CONTROL_CONNECTED_LINE:
++ case AST_CONTROL_REDIRECTING:
+ case -1: /* Ignore -- just stopping indications */
+ break;
+
+@@ -3747,6 +4088,37 @@
+ res = 0;
+ }
+ ast_channel_unlock(chan);
++
++ if (res < 0) {
++ return res;
++ }
++
++ for (;;) {
++ struct ast_frame *fr;
++
++ res = ast_waitfor(chan, -1);
++
++ if (res < 0 || !(fr = ast_read(chan))) {
++ res = -1;
++ break;
++ }
++
++ if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_TRANSFER) {
++ enum ast_control_transfer *message = fr->data.ptr;
++
++ if (*message == AST_TRANSFER_SUCCESS) {
++ res = 1;
++ } else {
++ res = -1;
++ }
++
++ ast_frfree(fr);
++ break;
++ }
++
++ ast_frfree(fr);
++ }
++
+ return res;
+ }
+
+@@ -4043,7 +4415,11 @@
+ struct ast_frame *current;
+ const struct ast_channel_tech *t;
+ void *t_pvt;
+- struct ast_callerid tmpcid;
++ union {
++ struct ast_callerid cid;
++ struct ast_party_connected_line connected;
++ struct ast_party_redirecting redirecting;
++ } exchange;
+ struct ast_channel *clonechan = original->masq;
+ struct ast_cdr *cdr;
+ int rformat = original->readformat;
+@@ -4224,11 +4600,19 @@
+ /* Stream stuff stays the same */
+ /* Keep the original state. The fixup code will need to work with it most likely */
+
+- /* Just swap the whole structures, nevermind the allocations, they'll work themselves
+- out. */
+- tmpcid = original->cid;
++ /*
++ * Just swap the whole structures, nevermind the allocations,
++ * they'll work themselves out.
++ */
++ exchange.cid = original->cid;
+ original->cid = clonechan->cid;
+- clonechan->cid = tmpcid;
++ clonechan->cid = exchange.cid;
++ exchange.connected = original->connected;
++ original->connected = clonechan->connected;
++ clonechan->connected = exchange.connected;
++ exchange.redirecting = original->redirecting;
++ original->redirecting = clonechan->redirecting;
++ clonechan->redirecting = exchange.redirecting;
+
+ /* Restore original timing file descriptor */
+ ast_channel_set_fd(original, AST_TIMING_FD, original->timingfd);
+@@ -4521,8 +4905,10 @@
+ case AST_CONTROL_HOLD:
+ case AST_CONTROL_UNHOLD:
+ case AST_CONTROL_VIDUPDATE:
++ case AST_CONTROL_T38:
+ case AST_CONTROL_SRCUPDATE:
+- case AST_CONTROL_T38:
++ case AST_CONTROL_CONNECTED_LINE:
++ case AST_CONTROL_REDIRECTING:
+ ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
+ if (jb_in_use) {
+ ast_jb_empty_and_reset(c0, c1);
+@@ -5485,3 +5871,576 @@
+
+ return ast_say_digit_str_full(chan, buf, ints, lang, audiofd, ctrlfd);
+ }
++
++void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_callerid *src)
++{
++#if 1
++ /* Must manually fill in struct ast_party_id until struct ast_callerid goes away */
++ if (dest->id.number) {
++ ast_free(dest->id.number);
++ }
++ dest->id.number = ast_strdup(src->cid_num);
++
++ if (dest->id.name) {
++ ast_free(dest->id.name);
++ }
++ dest->id.name = ast_strdup(src->cid_name);
++
++ dest->id.number_type = src->cid_ton;
++ dest->id.number_presentation = src->cid_pres;
++
++
++ if (dest->ani) {
++ ast_free(dest->ani);
++ }
++ dest->ani = ast_strdup(src->cid_ani);
++
++ dest->ani2 = src->cid_ani2;
++
++#else
++
++ /* The src parameter type will become a struct ast_party_caller ptr. */
++ /* This is future code */
++
++ ast_party_id_copy(&dest->id, &src->id);
++
++ if (dest->ani) {
++ ast_free(dest->ani);
++ }
++ dest->ani = ast_strdup(src->ani);
++
++ dest->ani2 = src->ani2;
++#endif
++}
++
++void ast_connected_line_copy_to_caller(struct ast_callerid *dest, const struct ast_party_connected_line *src)
++{
++#if 1
++ /* Must manually extract from struct ast_party_id until struct ast_callerid goes away */
++ if (dest->cid_num) {
++ ast_free(dest->cid_num);
++ }
++ dest->cid_num = ast_strdup(src->id.number);
++
++ if (dest->cid_name) {
++ ast_free(dest->cid_name);
++ }
++ dest->cid_name = ast_strdup(src->id.name);
++
++ dest->cid_ton = src->id.number_type;
++ dest->cid_pres = src->id.number_presentation;
++
++
++ if (dest->cid_ani) {
++ ast_free(dest->cid_ani);
++ }
++ dest->cid_ani = ast_strdup(src->ani);
++
++ dest->cid_ani2 = src->ani2;
++
++#else
++
++ /* The dest parameter type will become a struct ast_party_caller ptr. */
++ /* This is future code */
++
++ ast_party_id_copy(&dest->id, &src->id);
++
++ if (dest->ani) {
++ ast_free(dest->ani);
++ }
++ dest->ani = ast_strdup(src->ani);
++
++ dest->ani2 = src->ani2;
++#endif
++}
++
++void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
++{
++ if (&chan->connected == connected) {
++ /* Don't set to self */
++ return;
++ }
++
++ ast_channel_lock(chan);
++ ast_party_connected_line_set(&chan->connected, connected);
++ ast_channel_unlock(chan);
++}
++
++/*!
++ * \brief Element identifiers for connected line indication frame data
++ * \note Only add to the end of this enum.
++ */
++enum {
++ AST_CONNECTED_LINE_NUMBER,
++ AST_CONNECTED_LINE_NAME,
++ AST_CONNECTED_LINE_NUMBER_TYPE,
++ AST_CONNECTED_LINE_NUMBER_PRESENTATION,
++ AST_CONNECTED_LINE_SOURCE
++};
++
++int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected)
++{
++ int32_t value;
++ size_t length;
++ size_t pos = 0;
++
++ /*
++ * The size of integer values must be fixed in case the frame is
++ * shipped to another machine.
++ */
++
++ /* *************** Connected line party id *************** */
++ if (connected->id.number) {
++ length = strlen(connected->id.number);
++ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
++ ast_log(LOG_WARNING, "No space left for connected line number\n");
++ return -1;
++ }
++ data[pos++] = AST_CONNECTED_LINE_NUMBER;
++ data[pos++] = length;
++ memcpy(data + pos, connected->id.number, length);
++ pos += length;
++ }
++
++ if (connected->id.name) {
++ length = strlen(connected->id.name);
++ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
++ ast_log(LOG_WARNING, "No space left for connected line name\n");
++ return -1;
++ }
++ data[pos++] = AST_CONNECTED_LINE_NAME;
++ data[pos++] = length;
++ memcpy(data + pos, connected->id.name, length);
++ pos += length;
++ }
++
++ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
++ ast_log(LOG_WARNING, "No space left for connected line type of number\n");
++ return -1;
++ }
++ data[pos++] = AST_CONNECTED_LINE_NUMBER_TYPE;
++ data[pos++] = 1;
++ data[pos++] = connected->id.number_type;
++
++ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
++ ast_log(LOG_WARNING, "No space left for connected line presentation\n");
++ return -1;
++ }
++ data[pos++] = AST_CONNECTED_LINE_NUMBER_PRESENTATION;
++ data[pos++] = 1;
++ data[pos++] = connected->id.number_presentation;
++
++ /* Connected line source */
++ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
++ ast_log(LOG_WARNING, "No space left for connected line source\n");
++ return -1;
++ }
++ data[pos++] = AST_CONNECTED_LINE_SOURCE;
++ data[pos++] = sizeof(value);
++ value = htonl(connected->source);
++ memcpy(data + pos, &value, sizeof(value));
++ pos += sizeof(value);
++
++ return pos;
++}
++
++int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
++{
++ size_t pos;
++ unsigned char ie_len;
++ unsigned char ie_id;
++ int32_t value;
++
++ for (pos = 0; pos < datalen; pos += ie_len) {
++ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
++ ast_log(LOG_WARNING, "Invalid connected line update\n");
++ return -1;
++ }
++ ie_id = data[pos++];
++ ie_len = data[pos++];
++ if (datalen < pos + ie_len) {
++ ast_log(LOG_WARNING, "Invalid connected line update\n");
++ return -1;
++ }
++
++ switch (ie_id) {
++ case AST_CONNECTED_LINE_NUMBER:
++ if (connected->id.number) {
++ ast_free(connected->id.number);
++ }
++ connected->id.number = ast_malloc(ie_len + 1);
++ if (connected->id.number) {
++ memcpy(connected->id.number, data + pos, ie_len);
++ connected->id.number[ie_len] = 0;
++ }
++ break;
++ case AST_CONNECTED_LINE_NAME:
++ if (connected->id.name) {
++ ast_free(connected->id.name);
++ }
++ connected->id.name = ast_malloc(ie_len + 1);
++ if (connected->id.name) {
++ memcpy(connected->id.name, data + pos, ie_len);
++ connected->id.name[ie_len] = 0;
++ }
++ break;
++ case AST_CONNECTED_LINE_NUMBER_TYPE:
++ if (ie_len != 1) {
++ ast_log(LOG_WARNING, "Invalid connected line type of number (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ connected->id.number_type = data[pos];
++ break;
++ case AST_CONNECTED_LINE_NUMBER_PRESENTATION:
++ if (ie_len != 1) {
++ ast_log(LOG_WARNING, "Invalid connected line presentation (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ connected->id.number_presentation = data[pos];
++ break;
++ case AST_CONNECTED_LINE_SOURCE:
++ if (ie_len != sizeof(value)) {
++ ast_log(LOG_WARNING, "Invalid connected line source (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ memcpy(&value, data + pos, sizeof(value));
++ connected->source = ntohl(value);
++ break;
++ default:
++ ast_log(LOG_DEBUG, "Unknown connected line element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
++ break;
++ }
++ }
++
++ return 0;
++}
++
++void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected)
++{
++ unsigned char data[1024]; /* This should be large enough */
++ size_t datalen;
++
++ datalen = ast_connected_line_build_data(data, sizeof(data), connected);
++ if (datalen == (size_t) -1) {
++ return;
++ }
++
++ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
++}
++
++void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected)
++{
++ unsigned char data[1024]; /* This should be large enough */
++ size_t datalen;
++
++ datalen = ast_connected_line_build_data(data, sizeof(data), connected);
++ if (datalen == (size_t) -1) {
++ return;
++ }
++
++ ast_queue_control_data(chan, AST_CONTROL_CONNECTED_LINE, data, datalen);
++}
++
++void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
++{
++ if (&chan->redirecting == redirecting) {
++ /* Don't set to self */
++ return;
++ }
++
++ ast_channel_lock(chan);
++
++ ast_party_id_set(&chan->redirecting.from, &redirecting->from);
++ if (redirecting->from.number
++ && redirecting->from.number != chan->redirecting.from.number) {
++ /*
++ * Must move string to ast_channel.cid.cid_rdnis until it goes away.
++ */
++ if (chan->cid.cid_rdnis) {
++ ast_free(chan->cid.cid_rdnis);
++ }
++ chan->cid.cid_rdnis = chan->redirecting.from.number;
++ chan->redirecting.from.number = NULL;
++ }
++
++ ast_party_id_set(&chan->redirecting.to, &redirecting->to);
++ chan->redirecting.reason = redirecting->reason;
++ chan->redirecting.count = redirecting->count;
++
++ ast_channel_unlock(chan);
++}
++
++/*!
++ * \brief Element identifiers for redirecting indication frame data
++ * \note Only add to the end of this enum.
++ */
++enum {
++ AST_REDIRECTING_FROM_NUMBER,
++ AST_REDIRECTING_FROM_NAME,
++ AST_REDIRECTING_FROM_NUMBER_TYPE,
++ AST_REDIRECTING_FROM_NUMBER_PRESENTATION,
++ AST_REDIRECTING_TO_NUMBER,
++ AST_REDIRECTING_TO_NAME,
++ AST_REDIRECTING_TO_NUMBER_TYPE,
++ AST_REDIRECTING_TO_NUMBER_PRESENTATION,
++ AST_REDIRECTING_REASON,
++ AST_REDIRECTING_COUNT
++};
++
++int ast_redirecting_build_data(unsigned char *data, size_t datalen, const struct ast_party_redirecting *redirecting)
++{
++ int32_t value;
++ size_t length;
++ size_t pos = 0;
++
++ /*
++ * The size of integer values must be fixed in case the frame is
++ * shipped to another machine.
++ */
++
++ /* *************** Redirecting from party id *************** */
++ if (redirecting->from.number) {
++ length = strlen(redirecting->from.number);
++ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
++ ast_log(LOG_WARNING, "No space left for redirecting from number\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_FROM_NUMBER;
++ data[pos++] = length;
++ memcpy(data + pos, redirecting->from.number, length);
++ pos += length;
++ }
++
++ if (redirecting->from.name) {
++ length = strlen(redirecting->from.name);
++ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
++ ast_log(LOG_WARNING, "No space left for redirecting from name\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_FROM_NAME;
++ data[pos++] = length;
++ memcpy(data + pos, redirecting->from.name, length);
++ pos += length;
++ }
++
++ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
++ ast_log(LOG_WARNING, "No space left for redirecting from type of number\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_FROM_NUMBER_TYPE;
++ data[pos++] = 1;
++ data[pos++] = redirecting->from.number_type;
++
++ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
++ ast_log(LOG_WARNING, "No space left for redirecting from presentation\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_FROM_NUMBER_PRESENTATION;
++ data[pos++] = 1;
++ data[pos++] = redirecting->from.number_presentation;
++
++ /* *************** Redirecting to party id *************** */
++ if (redirecting->to.number) {
++ length = strlen(redirecting->to.number);
++ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
++ ast_log(LOG_WARNING, "No space left for redirecting to number\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_TO_NUMBER;
++ data[pos++] = length;
++ memcpy(data + pos, redirecting->to.number, length);
++ pos += length;
++ }
++
++ if (redirecting->to.name) {
++ length = strlen(redirecting->to.name);
++ if (datalen < pos + (sizeof(data[0]) * 2) + length) {
++ ast_log(LOG_WARNING, "No space left for redirecting to name\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_TO_NAME;
++ data[pos++] = length;
++ memcpy(data + pos, redirecting->to.name, length);
++ pos += length;
++ }
++
++ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
++ ast_log(LOG_WARNING, "No space left for redirecting to type of number\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_TO_NUMBER_TYPE;
++ data[pos++] = 1;
++ data[pos++] = redirecting->to.number_type;
++
++ if (datalen < pos + (sizeof(data[0]) * 2) + 1) {
++ ast_log(LOG_WARNING, "No space left for redirecting to presentation\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_TO_NUMBER_PRESENTATION;
++ data[pos++] = 1;
++ data[pos++] = redirecting->to.number_presentation;
++
++ /* Redirecting reason */
++ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
++ ast_log(LOG_WARNING, "No space left for redirecting reason\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_REASON;
++ data[pos++] = sizeof(value);
++ value = htonl(redirecting->reason);
++ memcpy(data + pos, &value, sizeof(value));
++ pos += sizeof(value);
++
++ /* Redirecting count */
++ if (datalen < pos + (sizeof(data[0]) * 2) + sizeof(value)) {
++ ast_log(LOG_WARNING, "No space left for redirecting count\n");
++ return -1;
++ }
++ data[pos++] = AST_REDIRECTING_COUNT;
++ data[pos++] = sizeof(value);
++ value = htonl(redirecting->count);
++ memcpy(data + pos, &value, sizeof(value));
++ pos += sizeof(value);
++
++ return pos;
++}
++
++int ast_redirecting_parse_data(const unsigned char *data, size_t datalen, struct ast_party_redirecting *redirecting)
++{
++ size_t pos;
++ unsigned char ie_len;
++ unsigned char ie_id;
++ int32_t value;
++
++ for (pos = 0; pos < datalen; pos += ie_len) {
++ if (datalen < pos + sizeof(ie_id) + sizeof(ie_len)) {
++ ast_log(LOG_WARNING, "Invalid redirecting update\n");
++ return -1;
++ }
++ ie_id = data[pos++];
++ ie_len = data[pos++];
++ if (datalen < pos + ie_len) {
++ ast_log(LOG_WARNING, "Invalid redirecting update\n");
++ return -1;
++ }
++
++ switch (ie_id) {
++ case AST_REDIRECTING_FROM_NUMBER:
++ if (redirecting->from.number) {
++ ast_free(redirecting->from.number);
++ }
++ redirecting->from.number = ast_malloc(ie_len + 1);
++ if (redirecting->from.number) {
++ memcpy(redirecting->from.number, data + pos, ie_len);
++ redirecting->from.number[ie_len] = 0;
++ }
++ break;
++ case AST_REDIRECTING_FROM_NAME:
++ if (redirecting->from.name) {
++ ast_free(redirecting->from.name);
++ }
++ redirecting->from.name = ast_malloc(ie_len + 1);
++ if (redirecting->from.name) {
++ memcpy(redirecting->from.name, data + pos, ie_len);
++ redirecting->from.name[ie_len] = 0;
++ }
++ break;
++ case AST_REDIRECTING_FROM_NUMBER_TYPE:
++ if (ie_len != 1) {
++ ast_log(LOG_WARNING, "Invalid redirecting from type of number (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ redirecting->from.number_type = data[pos];
++ break;
++ case AST_REDIRECTING_FROM_NUMBER_PRESENTATION:
++ if (ie_len != 1) {
++ ast_log(LOG_WARNING, "Invalid redirecting from presentation (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ redirecting->from.number_presentation = data[pos];
++ break;
++ case AST_REDIRECTING_TO_NUMBER:
++ if (redirecting->to.number) {
++ ast_free(redirecting->to.number);
++ }
++ redirecting->to.number = ast_malloc(ie_len + 1);
++ if (redirecting->to.number) {
++ memcpy(redirecting->to.number, data + pos, ie_len);
++ redirecting->to.number[ie_len] = 0;
++ }
++ break;
++ case AST_REDIRECTING_TO_NAME:
++ if (redirecting->to.name) {
++ ast_free(redirecting->to.name);
++ }
++ redirecting->to.name = ast_malloc(ie_len + 1);
++ if (redirecting->to.name) {
++ memcpy(redirecting->to.name, data + pos, ie_len);
++ redirecting->to.name[ie_len] = 0;
++ }
++ break;
++ case AST_REDIRECTING_TO_NUMBER_TYPE:
++ if (ie_len != 1) {
++ ast_log(LOG_WARNING, "Invalid redirecting to type of number (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ redirecting->to.number_type = data[pos];
++ break;
++ case AST_REDIRECTING_TO_NUMBER_PRESENTATION:
++ if (ie_len != 1) {
++ ast_log(LOG_WARNING, "Invalid redirecting to presentation (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ redirecting->to.number_presentation = data[pos];
++ break;
++ case AST_REDIRECTING_REASON:
++ if (ie_len != sizeof(value)) {
++ ast_log(LOG_WARNING, "Invalid redirecting reason (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ memcpy(&value, data + pos, sizeof(value));
++ redirecting->reason = ntohl(value);
++ break;
++ case AST_REDIRECTING_COUNT:
++ if (ie_len != sizeof(value)) {
++ ast_log(LOG_WARNING, "Invalid redirecting count (%u)\n", (unsigned) ie_len);
++ break;
++ }
++ memcpy(&value, data + pos, sizeof(value));
++ redirecting->count = ntohl(value);
++ break;
++ default:
++ ast_log(LOG_DEBUG, "Unknown redirecting element: %u (%u)\n", (unsigned) ie_id, (unsigned) ie_len);
++ break;
++ }
++ }
++
++ return 0;
++}
++
++void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
++{
++ unsigned char data[1024]; /* This should be large enough */
++ size_t datalen;
++
++ datalen = ast_redirecting_build_data(data, sizeof(data), redirecting);
++ if (datalen == (size_t) -1) {
++ return;
++ }
++
++ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
++}
++
++void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct ast_party_redirecting *redirecting)
++{
++ unsigned char data[1024]; /* This should be large enough */
++ size_t datalen;
++
++ datalen = ast_redirecting_build_data(data, sizeof(data), redirecting);
++ if (datalen == (size_t) -1) {
++ return;
++ }
++
++ ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
++}
++
+Index: main/manager.c
+===================================================================
+--- a/main/manager.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/manager.c (.../trunk) (revision 186562)
+@@ -499,7 +499,7 @@
+ }
+
+ /*! \brief Get displayconnects config option.
+- * \param s manager session to get parameter from.
++ * \param session manager session to get parameter from.
+ * \return displayconnects config option value.
+ */
+ static int manager_displayconnects (struct mansession_session *session)
+@@ -1759,22 +1759,39 @@
+ static char mandescr_hangup[] =
+ "Description: Hangup a channel\n"
+ "Variables: \n"
+-" Channel: The channel name to be hungup\n";
++" Channel: The channel name to be hungup\n"
++" Cause: numeric hangup cause\n";
+
+ static int action_hangup(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c = NULL;
++ int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
+ const char *name = astman_get_header(m, "Channel");
++ const char *cause = astman_get_header(m, "Cause");
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
++ if (!ast_strlen_zero(cause)) {
++ char *endptr;
++ causecode = strtol(cause, &endptr, 10);
++ if (causecode < 0 || causecode > 127 || *endptr != '\0') {
++ ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
++ /* keep going, better to hangup without cause than to not hang up at all */
++ causecode = 0; /* do not set channel's hangupcause */
++ }
++ }
+ c = ast_get_channel_by_name_locked(name);
+ if (!c) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+- ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
++ if (causecode > 0) {
++ ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
++ c->name, causecode, c->hangupcause);
++ c->hangupcause = causecode;
++ }
++ ast_softhangup_nolock(c, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(c);
+ astman_send_ack(s, m, "Channel Hungup");
+ return 0;
+@@ -3803,7 +3820,7 @@
+ * properties of the rand() function (and the constantcy of s), that
+ * won't happen twice in a row.
+ */
+- while ((session->managerid = rand() ^ (unsigned long) session) == 0);
++ while ((session->managerid = ast_random() ^ (unsigned long) session) == 0);
+ session->last_ev = grab_last();
+ AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
+ AST_LIST_LOCK(&sessions);
+Index: main/tdd.c
+===================================================================
+--- a/main/tdd.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/tdd.c (.../trunk) (revision 186562)
+@@ -274,7 +274,9 @@
+ PUT_TDD_STOP; /* Stop bit */ \
+ } while(0);
+
+-/*! Generate TDD hold tone */
++/*! Generate TDD hold tone
++ * \param buf Result buffer
++ * \todo How big should this be??? */
+ int tdd_gen_holdtone(unsigned char *buf)
+ {
+ int bytes = 0;
+Index: main/ast_expr2f.c
+===================================================================
+--- a/main/ast_expr2f.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/ast_expr2f.c (.../trunk) (revision 186562)
+@@ -1962,8 +1962,8 @@
+
+ /** Setup the input buffer state to scan the given bytes. The next call to ast_yylex() will
+ * scan from a @e copy of @a bytes.
+- * @param bytes the byte buffer to scan
+- * @param len the number of bytes in the buffer pointed to by @a bytes.
++ * @param yybytes the byte buffer to scan
++ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+@@ -2124,7 +2124,7 @@
+ }
+
+ /** Set the current column.
+- * @param line_number
++ * @param column_no
+ * @param yyscanner The scanner object.
+ */
+ void ast_yyset_column (int column_no , yyscan_t yyscanner)
+@@ -2387,19 +2387,12 @@
+
+ int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
+ {
+- struct parse_io io;
++ struct parse_io io = { .string = expr, .chan = chan };
+ int return_value = 0;
+-
+- memset(&io, 0, sizeof(io));
+- io.string = expr; /* to pass to the error routine */
+- io.chan = chan;
+-
++
+ ast_yylex_init(&io.scanner);
+-
+ ast_yy_scan_string(expr, io.scanner);
+-
+ ast_yyparse ((void *) &io);
+-
+ ast_yylex_destroy(io.scanner);
+
+ if (!io.val) {
+Index: main/features.c
+===================================================================
+--- a/main/features.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/features.c (.../trunk) (revision 186562)
+@@ -889,9 +889,6 @@
+ return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
+ }
+
+-#define FEATURE_SENSE_CHAN (1 << 0)
+-#define FEATURE_SENSE_PEER (1 << 1)
+-
+ /*!
+ * \brief set caller and callee according to the direction
+ * \param caller, callee, peer, chan, sense
+@@ -1390,6 +1387,7 @@
+ struct ast_bridge_config bconfig;
+ struct ast_frame *f;
+ int l;
++ struct ast_party_connected_line connected_line = {{0,},};
+ struct ast_datastore *features_datastore;
+ struct ast_dial_features *dialfeatures = NULL;
+
+@@ -1481,6 +1479,17 @@
+ memset(&bconfig,0,sizeof(struct ast_bridge_config));
+ ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
+ ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
++ /* We need to get the transferer's connected line information copied
++ * at this point because he is likely to hang up during the bridge with
++ * newchan. This info will be used down below before bridging the
++ * transferee and newchan
++ *
++ * As a result, we need to be sure to free this data before returning
++ * or overwriting it.
++ */
++ ast_channel_lock(transferer);
++ ast_party_connected_line_copy(&connected_line, &transferer->connected);
++ ast_channel_unlock(transferer);
+ res = ast_bridge_call(transferer, newchan, &bconfig);
+ if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
+ ast_hangup(newchan);
+@@ -1488,10 +1497,12 @@
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ finishup(transferee);
+ transferer->_softhangup = 0;
++ ast_party_connected_line_free(&connected_line);
+ return AST_FEATURE_RETURN_SUCCESS;
+ }
+ if (check_compat(transferee, newchan)) {
+ finishup(transferee);
++ ast_party_connected_line_free(&connected_line);
+ return -1;
+ }
+ ast_indicate(transferee, AST_CONTROL_UNHOLD);
+@@ -1502,11 +1513,13 @@
+ || ast_check_hangup(transferee)
+ || ast_check_hangup(newchan)) {
+ ast_hangup(newchan);
++ ast_party_connected_line_free(&connected_line);
+ return -1;
+ }
+ xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
+ if (!xferchan) {
+ ast_hangup(newchan);
++ ast_party_connected_line_free(&connected_line);
+ return -1;
+ }
+ /* Make formats okay */
+@@ -1526,6 +1539,7 @@
+ if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
+ ast_hangup(xferchan);
+ ast_hangup(newchan);
++ ast_party_connected_line_free(&connected_line);
+ return -1;
+ }
+
+@@ -1560,6 +1574,18 @@
+ tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
+ }
+
++ /* Due to a limitation regarding when callerID is set on a Local channel,
++ * we use the transferer's connected line information here.
++ */
++ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(xferchan, &connected_line);
++ ast_channel_lock(xferchan);
++ ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
++ ast_channel_unlock(xferchan);
++ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(newchan, &connected_line);
++ ast_party_connected_line_free(&connected_line);
++
+ if (ast_stream_and_wait(newchan, xfersound, ""))
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ bridge_call_thread_launch(tobj);
+@@ -1656,11 +1682,24 @@
+ tobj->chan = newchan;
+ tobj->peer = xferchan;
+ tobj->bconfig = *config;
+-
++
+ if (tobj->bconfig.end_bridge_callback_data_fixup) {
+ tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
+ }
+
++ ast_channel_lock(newchan);
++ ast_connected_line_copy_from_caller(&connected_line, &newchan->cid);
++ ast_channel_unlock(newchan);
++ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(xferchan, &connected_line);
++ ast_channel_lock(xferchan);
++ ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid);
++ ast_channel_unlock(xferchan);
++ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ ast_channel_update_connected_line(newchan, &connected_line);
++
++ ast_party_connected_line_free(&connected_line);
++
+ if (ast_stream_and_wait(newchan, xfersound, ""))
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ bridge_call_thread_launch(tobj);
+@@ -1969,53 +2008,42 @@
+ }
+
+ /*!
+- * \brief Check the dynamic features
+- * \param chan,peer,config,code,sense
++ * \brief Helper function for feature_interpret and ast_feature_detect
++ * \param chan,peer,config,code,sense,dynamic_features char buf,feature flags,operation,feature
+ *
+ * Lock features list, browse for code, unlock list
++ * If a feature is found and the operation variable is set, that feature's
++ * operation is executed. The first feature found is copied to the feature parameter.
+ * \retval res on success.
+ * \retval -1 on failure.
+ */
+-static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
++static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
++ struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf,
++ struct ast_flags *features, int operation, struct ast_call_feature *feature)
+ {
+ int x;
+- struct ast_flags features;
+- struct ast_call_feature *feature;
+ struct feature_group *fg = NULL;
+ struct feature_group_exten *fge;
+- const char *peer_dynamic_features, *chan_dynamic_features;
+- char dynamic_features_buf[128];
++ struct ast_call_feature *tmpfeature;
+ char *tmp, *tok;
+ int res = AST_FEATURE_RETURN_PASSDIGITS;
+ int feature_detected = 0;
+
+- if (sense == FEATURE_SENSE_CHAN) {
+- ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
++ if (!(peer && chan && config) && operation) {
++ return -1; /* can not run feature operation */
+ }
+- else {
+- ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
+- }
+
+- ast_channel_lock(peer);
+- peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
+- ast_channel_unlock(peer);
+-
+- ast_channel_lock(chan);
+- chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
+- ast_channel_unlock(chan);
+-
+- snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
+-
+- ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
+-
+ ast_rwlock_rdlock(&features_lock);
+ for (x = 0; x < FEATURES_COUNT; x++) {
+- if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
++ if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
+ !ast_strlen_zero(builtin_features[x].exten)) {
+ /* Feature is up for consideration */
+ if (!strcmp(builtin_features[x].exten, code)) {
+ ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
+- res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
++ if (operation) {
++ res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
++ }
++ memcpy(feature, &builtin_features[x], sizeof(feature));
+ feature_detected = 1;
+ break;
+ } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
+@@ -2026,8 +2054,9 @@
+ }
+ ast_rwlock_unlock(&features_lock);
+
+- if (ast_strlen_zero(dynamic_features_buf) || feature_detected)
++ if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
+ return res;
++ }
+
+ tmp = dynamic_features_buf;
+
+@@ -2040,8 +2069,10 @@
+ AST_LIST_TRAVERSE(&fg->features, fge, entry) {
+ if (strcasecmp(fge->exten, code))
+ continue;
+-
+- res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
++ if (operation) {
++ res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
++ }
++ memcpy(feature, fge->feature, sizeof(feature));
+ if (res != AST_FEATURE_RETURN_KEEPTRYING) {
+ AST_RWLIST_UNLOCK(&feature_groups);
+ break;
+@@ -2056,33 +2087,78 @@
+
+ AST_RWLIST_RDLOCK(&feature_list);
+
+- if (!(feature = find_dynamic_feature(tok))) {
++ if (!(tmpfeature = find_dynamic_feature(tok))) {
+ AST_RWLIST_UNLOCK(&feature_list);
+ continue;
+ }
+-
++
+ /* Feature is up for consideration */
+- if (!strcmp(feature->exten, code)) {
+- ast_verb(3, " Feature Found: %s exten: %s\n",feature->sname, tok);
+- res = feature->operation(chan, peer, config, code, sense, feature);
++ if (!strcmp(tmpfeature->exten, code)) {
++ ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
++ if (operation) {
++ res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
++ }
++ memcpy(feature, tmpfeature, sizeof(feature));
+ if (res != AST_FEATURE_RETURN_KEEPTRYING) {
+ AST_RWLIST_UNLOCK(&feature_list);
+ break;
+ }
+ res = AST_FEATURE_RETURN_PASSDIGITS;
+- } else if (!strncmp(feature->exten, code, strlen(code)))
++ } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
+ res = AST_FEATURE_RETURN_STOREDIGITS;
+
+ AST_RWLIST_UNLOCK(&feature_list);
+ }
+-
++
+ return res;
+ }
+
++/*!
++ * \brief Check the dynamic features
++ * \param chan,peer,config,code,sense
++ *
++ * \retval res on success.
++ * \retval -1 on failure.
++*/
++
++static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) {
++
++ char dynamic_features_buf[128];
++ const char *peer_dynamic_features, *chan_dynamic_features;
++ struct ast_flags features;
++ struct ast_call_feature feature;
++ if (sense == FEATURE_SENSE_CHAN) {
++ ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
++ }
++ else {
++ ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
++ }
++
++ ast_channel_lock(peer);
++ peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
++ ast_channel_unlock(peer);
++
++ ast_channel_lock(chan);
++ chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
++ ast_channel_unlock(chan);
++
++ snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,""));
++
++ ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf);
++
++ return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
++}
++
++
++int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) {
++
++ return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
++}
++
+ static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+ {
+ int x;
+-
++
+ ast_clear_flag(config, AST_FLAGS_ALL);
+
+ ast_rwlock_rdlock(&features_lock);
+@@ -2097,7 +2173,7 @@
+ ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
+ }
+ ast_rwlock_unlock(&features_lock);
+-
++
+ if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
+ const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
+
+@@ -2163,6 +2239,10 @@
+ ast_channel_inherit_variables(caller, chan);
+ pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
+
++ ast_channel_lock(chan);
++ ast_connected_line_copy_from_caller(&chan->connected, &caller->cid);
++ ast_channel_unlock(chan);
++
+ if (ast_call(chan, data, timeout)) {
+ ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
+ goto done;
+@@ -2232,6 +2312,8 @@
+ f = NULL;
+ ready=1;
+ break;
++ } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
++ ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+ } else if (f->subclass != -1) {
+ ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
+ }
+@@ -4410,8 +4492,19 @@
+ struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan);
+
+ if (cur) {
++ struct ast_party_connected_line connected_caller;
++
+ int res = -1;
+ ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
++
++ connected_caller = cur->connected;
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_update_connected_line(chan, &connected_caller);
++
++ ast_party_connected_line_collect_caller(&connected_caller, &chan->cid);
++ connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
++ ast_channel_queue_connected_line_update(chan, &connected_caller);
++
+ res = ast_answer(chan);
+ if (res)
+ ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
+Index: main/http.c
+===================================================================
+--- a/main/http.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/http.c (.../trunk) (revision 186562)
+@@ -213,7 +213,7 @@
+ "Server: Asterisk/%s\r\n"
+ "Date: %s\r\n"
+ "Connection: close\r\n"
+- "Cache-Control: no-cache, no-store\r\n"
++ "Cache-Control: private\r\n"
+ "Content-Length: %d\r\n"
+ "Content-type: %s\r\n\r\n",
+ ast_get_version(), buf, (int) st.st_size, mtype);
+Index: main/app.c
+===================================================================
+--- a/main/app.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/app.c (.../trunk) (revision 186562)
+@@ -52,7 +52,7 @@
+ #include "asterisk/linkedlists.h"
+ #include "asterisk/threadstorage.h"
+
+-AST_THREADSTORAGE_PUBLIC(global_app_buf);
++AST_THREADSTORAGE_PUBLIC(ast_str_thread_global_buf);
+
+
+ #define MAX_OTHER_FORMATS 10
+Index: main/bridging.c
+===================================================================
+--- a/main/bridging.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/bridging.c (.../trunk) (revision 186562)
+@@ -319,7 +319,7 @@
+ /* Move channels around for priority reasons if we have more than one channel in our array */
+ if (bridge->array_num > 1) {
+ struct ast_channel *first = bridge->array[0];
+- memmove(bridge->array, bridge->array + 1, sizeof(bridge->array) - 1);
++ memmove(bridge->array, bridge->array + 1, sizeof(struct ast_channel *) * (bridge->array_num - 1));
+ bridge->array[(bridge->array_num - 1)] = first;
+ }
+
+Index: main/stdtime/localtime.c
+===================================================================
+--- a/main/stdtime/localtime.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/stdtime/localtime.c (.../trunk) (revision 186562)
+@@ -310,7 +310,11 @@
+ sp->wd[1] = -1;
+ }
+ /* or if the symlink itself changes (or the real file is here, if path is not a symlink) */
+- sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE | IN_DONT_FOLLOW);
++ sp->wd[0] = inotify_add_watch(inotify_fd, path, IN_ATTRIB | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_CLOSE_WRITE
++#ifdef IN_DONT_FOLLOW /* Only defined in glibc 2.5 and above */
++ | IN_DONT_FOLLOW
++#endif
++ );
+ }
+ }
+ #else
+Index: main/Makefile
+===================================================================
+--- a/main/Makefile (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/Makefile (.../trunk) (revision 186562)
+@@ -20,7 +20,7 @@
+ OBJS= tcptls.o io.o sched.o logger.o frame.o loader.o config.o channel.o \
+ translate.o file.o pbx.o cli.o md5.o term.o heap.o \
+ ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
+- cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
++ cdr.o tdd.o acl.o udptl.o manager.o asterisk.o \
+ dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
+ astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
+ utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
+@@ -29,7 +29,7 @@
+ strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
+ astobj2.o hashtab.o global_datastores.o version.o \
+ features.o taskprocessor.o timing.o datastore.o xml.o xmldoc.o \
+- strings.o bridging.o poll.o
++ strings.o bridging.o poll.o rtp_engine.o stun.o
+
+ # we need to link in the objects statically, not as a library, because
+ # otherwise modules will not have them available if none of the static
+@@ -103,6 +103,10 @@
+ endif
+ endif
+
++ifeq ($(GNU_LD),1)
++ASTLINK+=-Wl,--version-script,asterisk.exports
++endif
++
+ CHECK_SUBDIR: # do nothing, just make sure that we recurse in the subdir/
+
+ editline/libedit.a: CHECK_SUBDIR
+@@ -163,15 +167,14 @@
+ GMIMELDFLAGS+=$(GMIME_LIB)
+ endif
+
+-$(MAIN_TGT): $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
++$(MAIN_TGT): $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) asterisk.exports
+ @$(CC) -c -o buildinfo.o $(ASTCFLAGS) buildinfo.c
+- $(ECHO_PREFIX) echo " [LD] $^ -> $@"
++ $(ECHO_PREFIX) echo " [LD] $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) -> $@"
+ ifneq ($(findstring chan_h323,$(MENUSELECT_CHANNELS)),)
+- $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS)
++ $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS)
+ else
+- $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS) $(GMIMELDFLAGS)
++ $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS) $(GMIMELDFLAGS)
+ endif
+- $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/strip_nonapi $@ || rm $@
+
+ clean::
+ rm -f asterisk
+Index: main/event.c
+===================================================================
+--- a/main/event.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/event.c (.../trunk) (revision 186562)
+@@ -28,6 +28,7 @@
+ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+ #include "asterisk/_private.h"
++
+ #include "asterisk/event.h"
+ #include "asterisk/linkedlists.h"
+ #include "asterisk/dlinkedlists.h"
+@@ -36,6 +37,7 @@
+ #include "asterisk/unaligned.h"
+ #include "asterisk/utils.h"
+ #include "asterisk/taskprocessor.h"
++#include "asterisk/astobj2.h"
+
+ struct ast_taskprocessor *event_dispatcher;
+
+@@ -55,6 +57,16 @@
+ } __attribute__((packed));
+
+ /*!
++ * \brief The payload for a string information element
++ */
++struct ast_event_ie_str_payload {
++ /*! \brief A hash calculated with ast_str_hash(), to speed up comparisons */
++ uint32_t hash;
++ /*! \brief The actual string, null terminated */
++ char str[1];
++} __attribute__((packed));
++
++/*!
+ * \brief An event
+ *
+ * An ast_event consists of an event header (this structure), and zero or
+@@ -74,9 +86,18 @@
+ unsigned char payload[0];
+ } __attribute__((packed));
+
++
++/*!
++ * \brief A holder for an event
++ *
++ * \details This struct used to have more of a purpose than it does now.
++ * It is used to hold events in the event cache. It can be completely removed
++ * if one of these two things is done:
++ * - ast_event gets changed such that it never has to be realloc()d
++ * - astobj2 is updated so that you can realloc() an astobj2 object
++ */
+ struct ast_event_ref {
+ struct ast_event *event;
+- AST_LIST_ENTRY(ast_event_ref) entry;
+ };
+
+ struct ast_event_ie_val {
+@@ -85,7 +106,10 @@
+ enum ast_event_ie_pltype ie_pltype;
+ union {
+ uint32_t uint;
+- const char *str;
++ struct {
++ uint32_t hash;
++ const char *str;
++ };
+ void *raw;
+ } payload;
+ size_t raw_datalen;
+@@ -107,13 +131,57 @@
+ * The event subscribers are indexed by which event they are subscribed to */
+ static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
+
+-/*! \brief Cached events
+- * The event cache is indexed on the event type. The purpose of this is
+- * for events that express some sort of state. So, when someone first
+- * needs to know this state, it can get the last known state from the cache. */
+-static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL];
++static int ast_event_cmp(void *obj, void *arg, int flags);
++static int ast_event_hash_mwi(const void *obj, const int flags);
++static int ast_event_hash_devstate(const void *obj, const int flags);
++static int ast_event_hash_devstate_change(const void *obj, const int flags);
+
++#ifdef LOW_MEMORY
++#define NUM_CACHE_BUCKETS 17
++#else
++#define NUM_CACHE_BUCKETS 563
++#endif
++
++#define MAX_CACHE_ARGS 8
++
+ /*!
++ * \brief Event types that are kept in the cache.
++ */
++static struct {
++ /*!
++ * \brief Container of cached events
++ *
++ * \details This gets allocated in ast_event_init() when Asterisk starts
++ * for the event types declared as using the cache.
++ */
++ struct ao2_container *container;
++ /*! \brief Event type specific hash function */
++ ao2_hash_fn *hash_fn;
++ /*!
++ * \brief Information Elements used for caching
++ *
++ * \details This array is the set of information elements that will be unique
++ * among all events in the cache for this event type. When a new event gets
++ * cached, a previous event with the same values for these information elements
++ * will be replaced.
++ */
++ enum ast_event_ie_type cache_args[MAX_CACHE_ARGS];
++} ast_event_cache[AST_EVENT_TOTAL] = {
++ [AST_EVENT_MWI] = {
++ .hash_fn = ast_event_hash_mwi,
++ .cache_args = { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_CONTEXT },
++ },
++ [AST_EVENT_DEVICE_STATE] = {
++ .hash_fn = ast_event_hash_devstate,
++ .cache_args = { AST_EVENT_IE_DEVICE, },
++ },
++ [AST_EVENT_DEVICE_STATE_CHANGE] = {
++ .hash_fn = ast_event_hash_devstate_change,
++ .cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
++ },
++};
++
++/*!
+ * The index of each entry _must_ match the event type number!
+ */
+ static struct event_name {
+@@ -237,6 +305,8 @@
+ {
+ switch (ie_val->ie_pltype) {
+ case AST_EVENT_IE_PLTYPE_STR:
++ ast_free((char *) ie_val->payload.str);
++ break;
+ case AST_EVENT_IE_PLTYPE_RAW:
+ ast_free(ie_val->payload.raw);
+ break;
+@@ -328,7 +398,8 @@
+ return res;
+ }
+
+-static int match_ie_val(struct ast_event *event, struct ast_event_ie_val *ie_val, struct ast_event *event2)
++static int match_ie_val(const struct ast_event *event,
++ const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
+ {
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
+ uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
+@@ -338,9 +409,19 @@
+ }
+
+ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
+- const char *str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
+- if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type)))
++ const char *str;
++ uint32_t hash;
++
++ hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
++ if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
++ return 0;
++ }
++
++ str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
++ if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
+ return 1;
++ }
++
+ return 0;
+ }
+
+@@ -360,28 +441,34 @@
+ return 0;
+ }
+
+-/*! \brief Dump the event cache for the subscribed event type */
+-void ast_event_dump_cache(const struct ast_event_sub *event_sub)
++static int dump_cache_cb(void *obj, void *arg, int flags)
+ {
+- struct ast_event_ref *event_ref;
+- enum ast_event_type type = event_sub->type;
++ const struct ast_event_ref *event_ref = obj;
++ const struct ast_event *event = event_ref->event;
++ const struct ast_event_sub *event_sub = arg;
++ struct ast_event_ie_val *ie_val = NULL;
+
+- AST_RWLIST_RDLOCK(&ast_event_cache[type]);
+- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
+- struct ast_event_ie_val *ie_val;
+- AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+- if (!match_ie_val(event_ref->event, ie_val, NULL))
+- break;
++ AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
++ if (!match_ie_val(event, ie_val, NULL)) {
++ break;
+ }
+- if (!ie_val) {
+- /* All parameters were matched on this cache entry, so dump it */
+- event_sub->cb(event_ref->event, event_sub->userdata);
+- }
+ }
+- AST_RWLIST_TRAVERSE_SAFE_END
+- AST_RWLIST_UNLOCK(&ast_event_cache[type]);
++
++ if (!ie_val) {
++ /* All parameters were matched on this cache entry, so dump it */
++ event_sub->cb(event, event_sub->userdata);
++ }
++
++ return 0;
+ }
+
++/*! \brief Dump the event cache for the subscribed event type */
++void ast_event_dump_cache(const struct ast_event_sub *event_sub)
++{
++ ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
++ dump_cache_cb, (void *) event_sub);
++}
++
+ static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
+ {
+ struct ast_event_ie_val *ie_val;
+@@ -536,6 +623,8 @@
+ return -1;
+ }
+
++ ie_val->payload.hash = ast_str_hash(str);
++
+ AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+ return 0;
+@@ -703,7 +792,11 @@
+
+ const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
+ {
+- return (const char*)iterator->ie->ie_payload;
++ const struct ast_event_ie_str_payload *str_payload;
++
++ str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
++
++ return str_payload->str;
+ }
+
+ void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
+@@ -725,9 +818,22 @@
+ return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+ }
+
++uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
++{
++ const struct ast_event_ie_str_payload *str_payload;
++
++ str_payload = ast_event_get_ie_raw(event, ie_type);
++
++ return str_payload->hash;
++}
++
+ const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
+ {
+- return ast_event_get_ie_raw(event, ie_type);
++ const struct ast_event_ie_str_payload *str_payload;
++
++ str_payload = ast_event_get_ie_raw(event, ie_type);
++
++ return str_payload->str;
+ }
+
+ const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
+@@ -746,7 +852,16 @@
+ int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
+ const char *str)
+ {
+- return ast_event_append_ie_raw(event, ie_type, str, strlen(str) + 1);
++ struct ast_event_ie_str_payload *str_payload;
++ size_t payload_len;
++
++ payload_len = sizeof(*str_payload) + strlen(str);
++ str_payload = alloca(payload_len);
++
++ strcpy(str_payload->str, str);
++ str_payload->hash = ast_str_hash(str);
++
++ return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
+ }
+
+ int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
+@@ -839,7 +954,7 @@
+ if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
+ /* If the event is originating on this server, add the server's
+ * entity ID to the event. */
+- ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &g_eid, sizeof(g_eid));
++ ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
+ }
+
+ return event;
+@@ -850,10 +965,11 @@
+ ast_free(event);
+ }
+
+-static void ast_event_ref_destroy(struct ast_event_ref *event_ref)
++static void ast_event_ref_destroy(void *obj)
+ {
++ struct ast_event_ref *event_ref = obj;
++
+ ast_event_destroy(event_ref->event);
+- ast_free(event_ref);
+ }
+
+ static struct ast_event *ast_event_dup(const struct ast_event *event)
+@@ -863,9 +979,10 @@
+
+ event_len = ast_event_get_size(event);
+
+- if (!(dup_event = ast_calloc(1, event_len)))
++ if (!(dup_event = ast_calloc(1, event_len))) {
+ return NULL;
+-
++ }
++
+ memcpy(dup_event, event, event_len);
+
+ return dup_event;
+@@ -876,139 +993,122 @@
+ va_list ap;
+ enum ast_event_ie_type ie_type;
+ struct ast_event *dup_event = NULL;
+- struct ast_event_ref *event_ref;
+- struct ast_event_ie_val *cache_arg;
+- AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val);
++ struct ast_event_ref *cached_event_ref;
++ struct ast_event *cache_arg_event;
++ struct ast_event_ref tmp_event_ref = {
++ .event = NULL,
++ };
++ struct ao2_container *container = NULL;
+
+ if (type >= AST_EVENT_TOTAL) {
+ ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
+ return NULL;
+ }
+
++ if (!(container = ast_event_cache[type].container)) {
++ ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
++ return NULL;
++ }
++
++ if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
++ return NULL;
++ }
++
+ va_start(ap, type);
+ for (ie_type = va_arg(ap, enum ast_event_type);
+ ie_type != AST_EVENT_IE_END;
+ ie_type = va_arg(ap, enum ast_event_type))
+ {
+- cache_arg = alloca(sizeof(*cache_arg));
+- memset(cache_arg, 0, sizeof(*cache_arg));
+- cache_arg->ie_type = ie_type;
+- cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+- if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
+- cache_arg->payload.uint = va_arg(ap, uint32_t);
+- else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
+- cache_arg->payload.str = ast_strdupa(va_arg(ap, const char *));
+- else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
++ enum ast_event_ie_pltype ie_pltype;
++
++ ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
++
++ switch (ie_pltype) {
++ case AST_EVENT_IE_PLTYPE_UINT:
++ ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
++ break;
++ case AST_EVENT_IE_PLTYPE_STR:
++ ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
++ break;
++ case AST_EVENT_IE_PLTYPE_RAW:
++ {
+ void *data = va_arg(ap, void *);
+ size_t datalen = va_arg(ap, size_t);
+- cache_arg->payload.raw = alloca(datalen);
+- memcpy(cache_arg->payload.raw, data, datalen);
+- cache_arg->raw_datalen = datalen;
++ ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
+ }
+- AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
++ case AST_EVENT_IE_PLTYPE_EXISTS:
++ ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
++ break;
++ case AST_EVENT_IE_PLTYPE_UNKNOWN:
++ break;
++ }
+ }
+ va_end(ap);
+
+- if (AST_LIST_EMPTY(&cache_args)) {
+- ast_log(LOG_ERROR, "Events can not be retrieved from the cache without "
+- "specifying at least one IE type!\n");
+- return NULL;
+- }
++ tmp_event_ref.event = cache_arg_event;
+
+- AST_RWLIST_RDLOCK(&ast_event_cache[type]);
+- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
+- AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
+- if (!match_ie_val(event_ref->event, cache_arg, NULL))
+- break;
+- }
+- if (!cache_arg) {
+- /* All parameters were matched on this cache entry, so return it */
+- dup_event = ast_event_dup(event_ref->event);
+- break;
+- }
++ cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
++
++ ast_event_destroy(cache_arg_event);
++ cache_arg_event = NULL;
++
++ if (cached_event_ref) {
++ dup_event = ast_event_dup(cached_event_ref->event);
++ ao2_ref(cached_event_ref, -1);
++ cached_event_ref = NULL;
+ }
+- AST_RWLIST_TRAVERSE_SAFE_END
+- AST_RWLIST_UNLOCK(&ast_event_cache[type]);
+
+ return dup_event;
+ }
+
++static struct ast_event_ref *alloc_event_ref(void)
++{
++ return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
++}
++
+ /*! \brief Duplicate an event and add it to the cache
+ * \note This assumes this index in to the cache is locked */
+-static int ast_event_dup_and_cache(const struct ast_event *event)
++static int attribute_unused ast_event_dup_and_cache(const struct ast_event *event)
+ {
+ struct ast_event *dup_event;
+ struct ast_event_ref *event_ref;
+
+- if (!(dup_event = ast_event_dup(event)))
++ if (!(dup_event = ast_event_dup(event))) {
+ return -1;
+- if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
++ }
++
++ if (!(event_ref = alloc_event_ref())) {
++ ast_event_destroy(dup_event);
+ return -1;
+-
++ }
++
+ event_ref->event = dup_event;
+
+- AST_LIST_INSERT_TAIL(&ast_event_cache[ntohs(event->type)], event_ref, entry);
++ ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
+
++ ao2_ref(event_ref, -1);
++
+ return 0;
+ }
+
+-int ast_event_queue_and_cache(struct ast_event *event, ...)
++int ast_event_queue_and_cache(struct ast_event *event)
+ {
+- va_list ap;
+- enum ast_event_type ie_type;
+- uint16_t host_event_type;
+- struct ast_event_ref *event_ref;
+- int res;
+- struct ast_event_ie_val *cache_arg;
+- AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val);
++ struct ao2_container *container;
++ struct ast_event_ref tmp_event_ref = {
++ .event = event,
++ };
+
+- host_event_type = ntohs(event->type);
+-
+- /* Invalid type */
+- if (host_event_type >= AST_EVENT_TOTAL) {
+- ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
+- "type '%d'!\n", host_event_type);
+- return -1;
++ if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
++ ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
++ goto queue_event;
+ }
+
+- va_start(ap, event);
+- for (ie_type = va_arg(ap, enum ast_event_type);
+- ie_type != AST_EVENT_IE_END;
+- ie_type = va_arg(ap, enum ast_event_type))
+- {
+- cache_arg = alloca(sizeof(*cache_arg));
+- memset(cache_arg, 0, sizeof(*cache_arg));
+- cache_arg->ie_type = ie_type;
+- cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+- if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
+- cache_arg->raw_datalen = va_arg(ap, size_t);
+- AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
+- }
+- va_end(ap);
++ /* Remove matches from the cache */
++ ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
++ ast_event_cmp, &tmp_event_ref);
+
+- if (AST_LIST_EMPTY(&cache_args)) {
+- ast_log(LOG_ERROR, "Events can not be cached without specifying at "
+- "least one IE type!\n");
+- return ast_event_queue(event);
+- }
+-
+- AST_RWLIST_WRLOCK(&ast_event_cache[host_event_type]);
+- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[host_event_type], event_ref, entry) {
+- AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
+- if (!match_ie_val(event_ref->event, cache_arg, event))
+- break;
+- }
+- if (!cache_arg) {
+- /* All parameters were matched on this cache entry, so remove it */
+- AST_LIST_REMOVE_CURRENT(entry);
+- ast_event_ref_destroy(event_ref);
+- }
+- }
+- AST_RWLIST_TRAVERSE_SAFE_END;
+- res = ast_event_dup_and_cache(event);
+- AST_RWLIST_UNLOCK(&ast_event_cache[host_event_type]);
+-
+- return (ast_event_queue(event) || res) ? -1 : 0;
++queue_event:
++ return ast_event_queue(event);
+ }
+
+ static int handle_event(void *data)
+@@ -1024,22 +1124,25 @@
+ AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
+ struct ast_event_ie_val *ie_val;
+ AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+- if (!match_ie_val(event_ref->event, ie_val, NULL))
++ if (!match_ie_val(event_ref->event, ie_val, NULL)) {
+ break;
++ }
+ }
+- if (ie_val)
++ if (ie_val) {
+ continue;
++ }
+ sub->cb(event_ref->event, sub->userdata);
+ }
+ AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]);
+
+ /* Now to subscribers to all event types */
+ AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
+- AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry)
++ AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry) {
+ sub->cb(event_ref->event, sub->userdata);
++ }
+ AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
+
+- ast_event_ref_destroy(event_ref);
++ ao2_ref(event_ref, -1);
+
+ return 0;
+ }
+@@ -1059,29 +1162,149 @@
+ }
+
+ /* If nobody has subscribed to this event type, throw it away now */
+- if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
+- == AST_EVENT_SUB_NONE) {
++ if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
++ == AST_EVENT_SUB_NONE) {
+ ast_event_destroy(event);
+ return 0;
+ }
+
+- if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
++ if (!(event_ref = alloc_event_ref())) {
+ return -1;
++ }
+
+ event_ref->event = event;
+
+ return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
+ }
+
+-void ast_event_init(void)
++static int ast_event_hash_mwi(const void *obj, const int flags)
+ {
++ const struct ast_event *event = obj;
++ const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
++ const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
++
++ return ast_str_hash_add(context, ast_str_hash(mailbox));
++}
++
++/*!
++ * \internal
++ * \brief Hash function for AST_EVENT_DEVICE_STATE
++ *
++ * \param[in] obj an ast_event
++ * \param[in] flags unused
++ *
++ * \return hash value
++ */
++static int ast_event_hash_devstate(const void *obj, const int flags)
++{
++ const struct ast_event *event = obj;
++
++ return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
++}
++
++/*!
++ * \internal
++ * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
++ *
++ * \param[in] obj an ast_event
++ * \param[in] flags unused
++ *
++ * \return hash value
++ */
++static int ast_event_hash_devstate_change(const void *obj, const int flags)
++{
++ const struct ast_event *event = obj;
++
++ return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
++}
++
++static int ast_event_hash(const void *obj, const int flags)
++{
++ const struct ast_event_ref *event_ref;
++ const struct ast_event *event;
++ ao2_hash_fn *hash_fn;
++
++ event_ref = obj;
++ event = event_ref->event;
++
++ if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
++ return 0;
++ }
++
++ return hash_fn(event, flags);
++}
++
++/*!
++ * \internal
++ * \brief Compare two events
++ *
++ * \param[in] obj the first event, as an ast_event_ref
++ * \param[in] arg the second event, as an ast_event_ref
++ * \param[in] flags unused
++ *
++ * \pre Both events must be the same type.
++ * \pre The event type must be declared as a cached event type in ast_event_cache
++ *
++ * \details This function takes two events, and determines if they are considered
++ * equivalent. The values of information elements specified in the cache arguments
++ * for the event type are used to determine if the events are equivalent.
++ *
++ * \retval 0 No match
++ * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
++ */
++static int ast_event_cmp(void *obj, void *arg, int flags)
++{
++ struct ast_event_ref *event_ref, *event_ref2;
++ struct ast_event *event, *event2;
++ int res = CMP_MATCH;
+ int i;
++ enum ast_event_ie_type *cache_args;
+
+- for (i = 0; i < AST_EVENT_TOTAL; i++)
++ event_ref = obj;
++ event = event_ref->event;
++
++ event_ref2 = arg;
++ event2 = event_ref2->event;
++
++ cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
++
++ for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
++ struct ast_event_ie_val ie_val = {
++ .ie_type = cache_args[i],
++ };
++
++ if (!match_ie_val(event, &ie_val, event2)) {
++ res = 0;
++ break;
++ }
++ }
++
++ return res;
++}
++
++int ast_event_init(void)
++{
++ int i;
++
++ for (i = 0; i < AST_EVENT_TOTAL; i++) {
+ AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
++ }
+
+- for (i = 0; i < AST_EVENT_TOTAL; i++)
+- AST_RWLIST_HEAD_INIT(&ast_event_cache[i]);
++ for (i = 0; i < AST_EVENT_TOTAL; i++) {
++ if (!ast_event_cache[i].hash_fn) {
++ /* This event type is not cached. */
++ continue;
++ }
+
+- event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0);
++ if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
++ ast_event_hash, ast_event_cmp))) {
++ return -1;
++ }
++ }
++
++ if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
++ return -1;
++ }
++
++ return 0;
+ }
+Index: main/asterisk.c
+===================================================================
+--- a/main/asterisk.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/asterisk.c (.../trunk) (revision 186562)
+@@ -120,7 +120,6 @@
+ #include "asterisk/cdr.h"
+ #include "asterisk/pbx.h"
+ #include "asterisk/enum.h"
+-#include "asterisk/rtp.h"
+ #include "asterisk/http.h"
+ #include "asterisk/udptl.h"
+ #include "asterisk/app.h"
+@@ -182,7 +181,7 @@
+
+ /*! @} */
+
+-struct ast_eid g_eid;
++struct ast_eid ast_eid_default;
+
+ /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
+ char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
+@@ -427,7 +426,7 @@
+ return NULL;
+ }
+
+- ast_eid_to_str(eid_str, sizeof(eid_str), &g_eid);
++ ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
+
+ ast_cli(a->fd, "\nPBX Core settings\n");
+ ast_cli(a->fd, "-----------------\n");
+@@ -2398,11 +2397,12 @@
+ int nummatches = 0;
+ char **matches;
+ int retval = CC_ERROR;
+- char buf[2048];
++ char buf[2048], savechr;
+ int res;
+
+ LineInfo *lf = (LineInfo *)el_line(editline);
+
++ savechr = *(char *)lf->cursor;
+ *(char *)lf->cursor = '\0';
+ ptr = (char *)lf->cursor;
+ if (ptr) {
+@@ -2428,8 +2428,10 @@
+ char *mbuf;
+ int mlen = 0, maxmbuf = 2048;
+ /* Start with a 2048 byte buffer */
+- if (!(mbuf = ast_malloc(maxmbuf)))
++ if (!(mbuf = ast_malloc(maxmbuf))) {
++ lf->cursor[0] = savechr;
+ return (char *)(CC_ERROR);
++ }
+ snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
+ fdsend(ast_consock, buf);
+ res = 0;
+@@ -2438,8 +2440,10 @@
+ if (mlen + 1024 > maxmbuf) {
+ /* Every step increment buffer 1024 bytes */
+ maxmbuf += 1024;
+- if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
++ if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
++ lf->cursor[0] = savechr;
+ return (char *)(CC_ERROR);
++ }
+ }
+ /* Only read 1024 bytes at a time */
+ res = read(ast_consock, mbuf + mlen, 1024);
+@@ -2499,6 +2503,8 @@
+ ast_free(matches);
+ }
+
++ lf->cursor[0] = savechr;
++
+ return (char *)(long)retval;
+ }
+
+@@ -2810,7 +2816,7 @@
+ ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
+ ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
+
+- ast_set_default_eid(&g_eid);
++ ast_set_default_eid(&ast_eid_default);
+
+ /* no asterisk.conf? no problem, use buildtime config! */
+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
+@@ -2981,7 +2987,7 @@
+ struct ast_eid tmp_eid;
+ if (!ast_str_to_eid(&tmp_eid, v->value)) {
+ ast_verbose("Successfully set global EID to '%s'\n", v->value);
+- g_eid = tmp_eid;
++ ast_eid_default = tmp_eid;
+ } else
+ ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
+ } else if (!strcasecmp(v->name, "lightbackground")) {
+@@ -3502,7 +3508,10 @@
+ }
+ #endif
+
+- ast_event_init();
++ if (ast_event_init()) {
++ printf("%s", term_quit());
++ exit(1);
++ }
+
+ ast_makesocket();
+ sigemptyset(&sigs);
+@@ -3569,7 +3578,6 @@
+ exit(1);
+ }
+
+- ast_rtp_init();
+ ast_dsp_init();
+ ast_udptl_init();
+
+Index: main/timing.c
+===================================================================
+--- a/main/timing.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/timing.c (.../trunk) (revision 186562)
+@@ -38,6 +38,7 @@
+ #include "asterisk/time.h"
+ #include "asterisk/heap.h"
+ #include "asterisk/module.h"
++#include "asterisk/poll-compat.h"
+
+ struct timing_holder {
+ /*! Do _not_ move this from the beginning of the struct. */
+@@ -48,6 +49,11 @@
+
+ static struct ast_heap *timing_interfaces;
+
++struct ast_timer {
++ int fd;
++ struct timing_holder *holder;
++};
++
+ static int timing_holder_cmp(void *_h1, void *_h2)
+ {
+ struct timing_holder *h1 = _h1;
+@@ -63,16 +69,16 @@
+ }
+
+ void *_ast_register_timing_interface(struct ast_timing_interface *funcs,
+- struct ast_module *mod)
++ struct ast_module *mod)
+ {
+ struct timing_holder *h;
+
+ if (!funcs->timer_open ||
+ !funcs->timer_close ||
+- !funcs->timer_set_rate ||
++ !funcs->timer_set_rate ||
+ !funcs->timer_ack ||
+ !funcs->timer_get_event ||
+- !funcs->timer_get_max_rate ||
++ !funcs->timer_get_max_rate ||
+ !funcs->timer_enable_continuous ||
+ !funcs->timer_disable_continuous) {
+ return NULL;
+@@ -110,10 +116,11 @@
+ return res;
+ }
+
+-int ast_timer_open(void)
++struct ast_timer *ast_timer_open(void)
+ {
+ int fd = -1;
+ struct timing_holder *h;
++ struct ast_timer *t = NULL;
+
+ ast_heap_rdlock(timing_interfaces);
+
+@@ -122,124 +129,88 @@
+ ast_module_ref(h->mod);
+ }
+
++ if (fd != -1) {
++ if (!(t = ast_calloc(1, sizeof(*t)))) {
++ h->iface->timer_close(fd);
++ } else {
++ t->fd = fd;
++ t->holder = h;
++ }
++ }
++
+ ast_heap_unlock(timing_interfaces);
+
+- return fd;
++ return t;
+ }
+
+-void ast_timer_close(int timer)
++void ast_timer_close(struct ast_timer *handle)
+ {
+- struct timing_holder *h;
++ handle->holder->iface->timer_close(handle->fd);
++ ast_module_unref(handle->holder->mod);
++ ast_free(handle);
++}
+
+- ast_heap_rdlock(timing_interfaces);
+-
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- h->iface->timer_close(timer);
+- ast_module_unref(h->mod);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
++int ast_timer_fd(const struct ast_timer *handle)
++{
++ return handle->fd;
+ }
+
+-int ast_timer_set_rate(int handle, unsigned int rate)
++int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
+ {
+- struct timing_holder *h;
+ int res = -1;
+
+- ast_heap_rdlock(timing_interfaces);
++ res = handle->holder->iface->timer_set_rate(handle->fd, rate);
+
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- res = h->iface->timer_set_rate(handle, rate);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
+-
+ return res;
+ }
+
+-void ast_timer_ack(int handle, unsigned int quantity)
++void ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
+ {
+- struct timing_holder *h;
+-
+- ast_heap_rdlock(timing_interfaces);
+-
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- h->iface->timer_ack(handle, quantity);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
++ handle->holder->iface->timer_ack(handle->fd, quantity);
+ }
+
+-int ast_timer_enable_continuous(int handle)
++int ast_timer_enable_continuous(const struct ast_timer *handle)
+ {
+- struct timing_holder *h;
+ int res = -1;
+
+- ast_heap_rdlock(timing_interfaces);
++ res = handle->holder->iface->timer_enable_continuous(handle->fd);
+
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- res = h->iface->timer_enable_continuous(handle);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
+-
+ return res;
+ }
+
+-int ast_timer_disable_continuous(int handle)
++int ast_timer_disable_continuous(const struct ast_timer *handle)
+ {
+- struct timing_holder *h;
+ int res = -1;
+
+- ast_heap_rdlock(timing_interfaces);
++ res = handle->holder->iface->timer_disable_continuous(handle->fd);
+
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- res = h->iface->timer_disable_continuous(handle);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
+-
+ return res;
+ }
+
+-enum ast_timer_event ast_timer_get_event(int handle)
++enum ast_timer_event ast_timer_get_event(const struct ast_timer *handle)
+ {
+- struct timing_holder *h;
+ enum ast_timer_event res = -1;
+
+- ast_heap_rdlock(timing_interfaces);
++ res = handle->holder->iface->timer_get_event(handle->fd);
+
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- res = h->iface->timer_get_event(handle);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
+-
+ return res;
+ }
+
+-unsigned int ast_timer_get_max_rate(int handle)
++unsigned int ast_timer_get_max_rate(const struct ast_timer *handle)
+ {
+- struct timing_holder *h;
+ unsigned int res = 0;
+
+- ast_heap_rdlock(timing_interfaces);
++ res = handle->holder->iface->timer_get_max_rate(handle->fd);
+
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- res = h->iface->timer_get_max_rate(handle);
+- }
+-
+- ast_heap_unlock(timing_interfaces);
+-
+ return res;
+ }
+
+ static char *timing_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- int fd, count = 0;
++ struct ast_timer *timer;
++ int count = 0;
+ struct timeval start, end;
+ unsigned int test_rate = 50;
+- struct timing_holder *h;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -267,34 +238,29 @@
+
+ ast_cli(a->fd, "Attempting to test a timer with %u ticks per second.\n", test_rate);
+
+- if ((fd = ast_timer_open()) == -1) {
++ if (!(timer = ast_timer_open())) {
+ ast_cli(a->fd, "Failed to open timing fd\n");
+ return CLI_FAILURE;
+ }
+
+- ast_heap_rdlock(timing_interfaces);
+- if ((h = ast_heap_peek(timing_interfaces, 1))) {
+- ast_cli(a->fd, "Using the '%s' timing module for this test.\n", h->iface->name);
+- h = NULL;
+- }
+- ast_heap_unlock(timing_interfaces);
++ ast_cli(a->fd, "Using the '%s' timing module for this test.\n", timer->holder->iface->name);
+
+ start = ast_tvnow();
+
+- ast_timer_set_rate(fd, test_rate);
++ ast_timer_set_rate(timer, test_rate);
+
+ while (ast_tvdiff_ms((end = ast_tvnow()), start) < 1000) {
+ int res;
+ struct pollfd pfd = {
+- .fd = fd,
++ .fd = ast_timer_fd(timer),
+ .events = POLLIN | POLLPRI,
+ };
+
+- res = poll(&pfd, 1, 100);
++ res = ast_poll(&pfd, 1, 100);
+
+ if (res == 1) {
+ count++;
+- ast_timer_ack(fd, 1);
++ ast_timer_ack(timer, 1);
+ } else if (!res) {
+ ast_cli(a->fd, "poll() timed out! This is bad.\n");
+ } else if (errno != EAGAIN && errno != EINTR) {
+@@ -302,7 +268,7 @@
+ }
+ }
+
+- ast_timer_close(fd);
++ ast_timer_close(timer);
+
+ ast_cli(a->fd, "It has been %d milliseconds, and we got %d timer ticks\n",
+ ast_tvdiff_ms(end, start), count);
+Index: main/devicestate.c
+===================================================================
+--- a/main/devicestate.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/devicestate.c (.../trunk) (revision 186562)
+@@ -196,8 +196,10 @@
+ ast_cond_t cond;
+ ast_mutex_t lock;
+ AST_LIST_HEAD_NOLOCK(, devstate_change) devstate_change_q;
++ unsigned int enabled:1;
+ } devstate_collector = {
+ .thread = AST_PTHREADT_NULL,
++ .enabled = 0,
+ };
+
+ /* Forward declarations */
+@@ -428,22 +430,26 @@
+ static void devstate_event(const char *device, enum ast_device_state state)
+ {
+ struct ast_event *event;
++ enum ast_event_type event_type;
+
++ if (devstate_collector.enabled) {
++ /* Distributed device state is enabled, so this state change is a change
++ * for a single server, not the real state. */
++ event_type = AST_EVENT_DEVICE_STATE_CHANGE;
++ } else {
++ event_type = AST_EVENT_DEVICE_STATE;
++ }
++
+ ast_debug(3, "device '%s' state '%d'\n", device, state);
+
+- if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
++ if (!(event = ast_event_new(event_type,
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+ AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+ AST_EVENT_IE_END))) {
+ return;
+ }
+
+- /* Cache this event, replacing an event in the cache with the same
+- * device name if it exists. */
+- ast_event_queue_and_cache(event,
+- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
+- AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, sizeof(struct ast_eid),
+- AST_EVENT_IE_END);
++ ast_event_queue_and_cache(event);
+ }
+
+ /*! Called by the state change thread to find out what the state is, and then
+@@ -632,13 +638,12 @@
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+ AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+ AST_EVENT_IE_END);
+-
+- if (!event)
++
++ if (!event) {
+ return;
++ }
+
+- ast_event_queue_and_cache(event,
+- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
+- AST_EVENT_IE_END);
++ ast_event_queue_and_cache(event);
+ }
+
+ static void handle_devstate_change(struct devstate_change *sc)
+@@ -719,21 +724,6 @@
+ /*! \brief Initialize the device state engine in separate thread */
+ int ast_device_state_engine_init(void)
+ {
+- devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
+- devstate_change_collector_cb, NULL, AST_EVENT_IE_END);
+-
+- if (!devstate_collector.event_sub) {
+- ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
+- return -1;
+- }
+-
+- ast_mutex_init(&devstate_collector.lock);
+- ast_cond_init(&devstate_collector.cond, NULL);
+- if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
+- ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
+- return -1;
+- }
+-
+ ast_cond_init(&change_pending, NULL);
+ if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
+ ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
+@@ -830,3 +820,28 @@
+ return AST_DEVICE_NOT_INUSE;
+ }
+
++int ast_enable_distributed_devstate(void)
++{
++ if (devstate_collector.enabled) {
++ return 0;
++ }
++
++ devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
++ devstate_change_collector_cb, NULL, AST_EVENT_IE_END);
++
++ if (!devstate_collector.event_sub) {
++ ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
++ return -1;
++ }
++
++ ast_mutex_init(&devstate_collector.lock);
++ ast_cond_init(&devstate_collector.cond, NULL);
++ if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
++ ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
++ return -1;
++ }
++
++ devstate_collector.enabled = 1;
++
++ return 0;
++}
+Index: main/taskprocessor.c
+===================================================================
+--- a/main/taskprocessor.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/taskprocessor.c (.../trunk) (revision 186562)
+@@ -84,10 +84,10 @@
+ /*! \brief tps_singletons is the astobj2 container for taskprocessor singletons */
+ static struct ao2_container *tps_singletons;
+
+-/*! \brief CLI 'taskprocessor ping <blah>' operation requires a ping condition */
++/*! \brief CLI <example>taskprocessor ping &lt;blah&gt;</example> operation requires a ping condition */
+ static ast_cond_t cli_ping_cond;
+
+-/*! \brief CLI 'taskprocessor ping <blah>' operation requires a ping condition lock */
++/*! \brief CLI <example>taskprocessor ping &lt;blah&gt;</example> operation requires a ping condition lock */
+ AST_MUTEX_DEFINE_STATIC(cli_ping_cond_lock);
+
+ /*! \brief The astobj2 hash callback for taskprocessors */
+@@ -101,7 +101,7 @@
+ /*! \brief Destroy the taskprocessor when its refcount reaches zero */
+ static void tps_taskprocessor_destroy(void *tps);
+
+-/*! \brief CLI 'taskprocessor ping <blah>' handler function */
++/*! \brief CLI <example>taskprocessor ping &lt;blah&gt;</example> handler function */
+ static int tps_ping_handler(void *datap);
+
+ /*! \brief Remove the front task off the taskprocessor queue */
+Index: main/astobj2.c
+===================================================================
+--- a/main/astobj2.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/astobj2.c (.../trunk) (revision 186562)
+@@ -134,20 +134,20 @@
+
+ /* the underlying functions common to debug and non-debug versions */
+
+-static int __ao2_ref(void *user_data, const int delta);
+-static void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn);
+-static struct ao2_container *__ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
+- ao2_callback_fn *cmp_fn);
+-static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func);
+-static void *__ao2_callback(struct ao2_container *c,
+- const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
+- char *tag, char *file, int line, const char *funcname);
+-static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q);
++static int internal_ao2_ref(void *user_data, const int delta);
++static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn);
++static struct ao2_container *internal_ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
++ ao2_callback_fn *cmp_fn);
++static struct bucket_list *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func);
++static void *internal_ao2_callback(struct ao2_container *c,
++ const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
++ char *tag, char *file, int line, const char *funcname);
++static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q);
+
+ #ifndef DEBUG_THREADS
+ int ao2_lock(void *user_data)
+ #else
+-int _ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
++int __ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
+ #endif
+ {
+ struct astobj2 *p = INTERNAL_OBJ(user_data);
+@@ -169,7 +169,7 @@
+ #ifndef DEBUG_THREADS
+ int ao2_unlock(void *user_data)
+ #else
+-int _ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
++int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
+ #endif
+ {
+ struct astobj2 *p = INTERNAL_OBJ(user_data);
+@@ -191,7 +191,7 @@
+ #ifndef DEBUG_THREADS
+ int ao2_trylock(void *user_data)
+ #else
+-int _ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
++int __ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
+ #endif
+ {
+ struct astobj2 *p = INTERNAL_OBJ(user_data);
+@@ -227,7 +227,7 @@
+ */
+
+
+-int _ao2_ref_debug(void *user_data, const int delta, char *tag, char *file, int line, const char *funcname)
++int __ao2_ref_debug(void *user_data, const int delta, char *tag, char *file, int line, const char *funcname)
+ {
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+
+@@ -244,20 +244,20 @@
+ fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag);
+ fclose(refo);
+ }
+- return __ao2_ref(user_data, delta);
++ return internal_ao2_ref(user_data, delta);
+ }
+
+-int _ao2_ref(void *user_data, const int delta)
++int __ao2_ref(void *user_data, const int delta)
+ {
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+
+ if (obj == NULL)
+ return -1;
+
+- return __ao2_ref(user_data, delta);
++ return internal_ao2_ref(user_data, delta);
+ }
+
+-static int __ao2_ref(void *user_data, const int delta)
++static int internal_ao2_ref(void *user_data, const int delta)
+ {
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+ int current_value;
+@@ -303,7 +303,7 @@
+ * We always alloc at least the size of a void *,
+ * for debugging purposes.
+ */
+-static void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
++static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
+ {
+ /* allocation */
+ struct astobj2 *obj;
+@@ -332,13 +332,13 @@
+ return EXTERNAL_OBJ(obj);
+ }
+
+-void *_ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname)
++void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag, char *file, int line, const char *funcname)
+ {
+ /* allocation */
+ void *obj;
+ FILE *refo = fopen(REF_FILE,"a");
+
+- obj = __ao2_alloc(data_size, destructor_fn);
++ obj = internal_ao2_alloc(data_size, destructor_fn);
+
+ if (obj == NULL)
+ return NULL;
+@@ -352,9 +352,9 @@
+ return obj;
+ }
+
+-void *_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
++void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
+ {
+- return __ao2_alloc(data_size, destructor_fn);
++ return internal_ao2_alloc(data_size, destructor_fn);
+ }
+
+
+@@ -418,8 +418,8 @@
+ /*
+ * A container is just an object, after all!
+ */
+-static struct ao2_container *__ao2_container_alloc(struct ao2_container *c, const unsigned int n_buckets, ao2_hash_fn *hash_fn,
+- ao2_callback_fn *cmp_fn)
++static struct ao2_container *internal_ao2_container_alloc(struct ao2_container *c, const unsigned int n_buckets, ao2_hash_fn *hash_fn,
++ ao2_callback_fn *cmp_fn)
+ {
+ /* XXX maybe consistency check on arguments ? */
+ /* compute the container size */
+@@ -439,28 +439,27 @@
+ return c;
+ }
+
+-struct ao2_container *_ao2_container_alloc_debug(const unsigned int n_buckets, ao2_hash_fn *hash_fn,
+- ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname)
++struct ao2_container *__ao2_container_alloc_debug(const unsigned int n_buckets, ao2_hash_fn *hash_fn,
++ ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname)
+ {
+ /* XXX maybe consistency check on arguments ? */
+ /* compute the container size */
+ size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
+- struct ao2_container *c = _ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname);
++ struct ao2_container *c = __ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname);
+
+- return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
++ return internal_ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
+ }
+
+-struct ao2_container *
+-_ao2_container_alloc(const unsigned int n_buckets, ao2_hash_fn *hash_fn,
+- ao2_callback_fn *cmp_fn)
++struct ao2_container *__ao2_container_alloc(const unsigned int n_buckets, ao2_hash_fn *hash_fn,
++ ao2_callback_fn *cmp_fn)
+ {
+ /* XXX maybe consistency check on arguments ? */
+ /* compute the container size */
+
+ size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
+- struct ao2_container *c = _ao2_alloc(container_size, container_destruct);
++ struct ao2_container *c = __ao2_alloc(container_size, container_destruct);
+
+- return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
++ return internal_ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
+ }
+
+ /*!
+@@ -486,7 +485,7 @@
+ * link an object to a container
+ */
+
+-static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
++static struct bucket_list *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
+ {
+ int i;
+ /* create a new list entry */
+@@ -516,23 +515,23 @@
+ return p;
+ }
+
+-void *_ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
++void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+ {
+- struct bucket_list *p = __ao2_link(c, user_data, file, line, funcname);
++ struct bucket_list *p = internal_ao2_link(c, user_data, file, line, funcname);
+
+ if (p) {
+- _ao2_ref_debug(user_data, +1, tag, file, line, funcname);
++ __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+ ao2_unlock(c);
+ }
+ return p;
+ }
+
+-void *_ao2_link(struct ao2_container *c, void *user_data)
++void *__ao2_link(struct ao2_container *c, void *user_data)
+ {
+- struct bucket_list *p = __ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
++ struct bucket_list *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+ if (p) {
+- _ao2_ref(user_data, +1);
++ __ao2_ref(user_data, +1);
+ ao2_unlock(c);
+ }
+ return p;
+@@ -550,23 +549,23 @@
+ * Unlink an object from the container
+ * and destroy the associated * ao2_bucket_list structure.
+ */
+-void *_ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
+- char *file, int line, const char *funcname)
++void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
++ char *file, int line, const char *funcname)
+ {
+ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
+ return NULL;
+
+- _ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
++ __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
+
+ return NULL;
+ }
+
+-void *_ao2_unlink(struct ao2_container *c, void *user_data)
++void *__ao2_unlink(struct ao2_container *c, void *user_data)
+ {
+ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
+ return NULL;
+
+- _ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
++ __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
+
+ return NULL;
+ }
+@@ -595,9 +594,9 @@
+ * aren't an excessive load to the system, as the callback should not be
+ * called as often as, say, the ao2_ref func is called.
+ */
+-static void *__ao2_callback(struct ao2_container *c,
+- const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
+- char *tag, char *file, int line, const char *funcname)
++static void *internal_ao2_callback(struct ao2_container *c,
++ const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
++ char *tag, char *file, int line, const char *funcname)
+ {
+ int i, last; /* search boundaries */
+ void *ret = NULL;
+@@ -675,9 +674,9 @@
+ /* it is important to handle this case before the unlink */
+ ret = EXTERNAL_OBJ(cur->astobj);
+ if (tag)
+- _ao2_ref_debug(ret, 1, tag, file, line, funcname);
++ __ao2_ref_debug(ret, 1, tag, file, line, funcname);
+ else
+- _ao2_ref(ret, 1);
++ __ao2_ref(ret, 1);
+ }
+
+ if (flags & OBJ_UNLINK) { /* must unlink */
+@@ -689,9 +688,9 @@
+ /* update number of elements and version */
+ ast_atomic_fetchadd_int(&c->elements, -1);
+ if (tag)
+- _ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
++ __ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
+ else
+- _ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
++ __ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
+ free(x); /* free the link record */
+ }
+
+@@ -715,45 +714,45 @@
+ return ret;
+ }
+
+-void *_ao2_callback_debug(struct ao2_container *c,
+- const enum search_flags flags,
+- ao2_callback_fn *cb_fn, void *arg,
+- char *tag, char *file, int line, const char *funcname)
++void *__ao2_callback_debug(struct ao2_container *c,
++ const enum search_flags flags,
++ ao2_callback_fn *cb_fn, void *arg,
++ char *tag, char *file, int line, const char *funcname)
+ {
+- return __ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
++ return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
+ }
+
+-void *_ao2_callback(struct ao2_container *c, const enum search_flags flags,
+- ao2_callback_fn *cb_fn, void *arg)
++void *__ao2_callback(struct ao2_container *c, const enum search_flags flags,
++ ao2_callback_fn *cb_fn, void *arg)
+ {
+- return __ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
++ return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
+ }
+
+-void *_ao2_callback_data_debug(struct ao2_container *c,
+- const enum search_flags flags,
+- ao2_callback_data_fn *cb_fn, void *arg, void *data,
+- char *tag, char *file, int line, const char *funcname)
++void *__ao2_callback_data_debug(struct ao2_container *c,
++ const enum search_flags flags,
++ ao2_callback_data_fn *cb_fn, void *arg, void *data,
++ char *tag, char *file, int line, const char *funcname)
+ {
+- return __ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
++ return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
+ }
+
+-void *_ao2_callback_data(struct ao2_container *c, const enum search_flags flags,
+- ao2_callback_data_fn *cb_fn, void *arg, void *data)
++void *__ao2_callback_data(struct ao2_container *c, const enum search_flags flags,
++ ao2_callback_data_fn *cb_fn, void *arg, void *data)
+ {
+- return __ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
++ return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
+ }
+
+ /*!
+ * the find function just invokes the default callback with some reasonable flags.
+ */
+-void *_ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
++void *__ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
+ {
+- return _ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
++ return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
+ }
+
+-void *_ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
++void *__ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
+ {
+- return _ao2_callback(c, flags, c->cmp_fn, arg);
++ return __ao2_callback(c, flags, c->cmp_fn, arg);
+ }
+
+ /*!
+@@ -772,7 +771,7 @@
+ /*
+ * move to the next element in the container.
+ */
+-static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q)
++static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q)
+ {
+ int lim;
+ struct bucket_list *p = NULL;
+@@ -827,16 +826,16 @@
+ return ret;
+ }
+
+-void * _ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
++void *__ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
+ {
+ struct bucket_list *p;
+ void *ret = NULL;
+
+- ret = __ao2_iterator_next(a, &p);
++ ret = internal_ao2_iterator_next(a, &p);
+
+ if (p) {
+ /* inc refcount of returned object */
+- _ao2_ref_debug(ret, 1, tag, file, line, funcname);
++ __ao2_ref_debug(ret, 1, tag, file, line, funcname);
+ }
+
+ if (!(a->flags & F_AO2I_DONTLOCK))
+@@ -845,16 +844,16 @@
+ return ret;
+ }
+
+-void * _ao2_iterator_next(struct ao2_iterator *a)
++void *__ao2_iterator_next(struct ao2_iterator *a)
+ {
+ struct bucket_list *p = NULL;
+ void *ret = NULL;
+
+- ret = __ao2_iterator_next(a, &p);
++ ret = internal_ao2_iterator_next(a, &p);
+
+ if (p) {
+ /* inc refcount of returned object */
+- _ao2_ref(ret, 1);
++ __ao2_ref(ret, 1);
+ }
+
+ if (!(a->flags & F_AO2I_DONTLOCK))
+@@ -868,13 +867,13 @@
+ */
+ static int cd_cb(void *obj, void *arg, int flag)
+ {
+- _ao2_ref(obj, -1);
++ __ao2_ref(obj, -1);
+ return 0;
+ }
+
+ static int cd_cb_debug(void *obj, void *arg, int flag)
+ {
+- _ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__);
++ __ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+ return 0;
+ }
+
+@@ -883,7 +882,7 @@
+ struct ao2_container *c = _c;
+ int i;
+
+- _ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
++ __ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
+
+ for (i = 0; i < c->n_buckets; i++) {
+ struct bucket_list *current;
+@@ -903,7 +902,7 @@
+ struct ao2_container *c = _c;
+ int i;
+
+- _ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
++ __ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+ for (i = 0; i < c->n_buckets; i++) {
+ struct bucket_list *current;
+Index: main/asterisk.exports
+===================================================================
+--- a/main/asterisk.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/main/asterisk.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,33 @@
++{
++ global:
++ ast_*;
++ _ast_*;
++ __ast_*;
++ pbx_*;
++ astman_*;
++ ao2_*;
++ __ao2_*;
++ option_debug;
++ option_verbose;
++ dahdi_chan_name;
++ dahdi_chan_name_len;
++ dahdi_chan_mode;
++ callerid_*;
++ cid_di;
++ cid_dr;
++ clidsb;
++ MD5*;
++ sched_*;
++ io_*;
++ jb_*;
++ aes_*;
++ config_*;
++ tdd_*;
++ term_*;
++ channelreloadreason2txt;
++ devstate2str;
++ __manager_event;
++ dialed_interface_info;
++ local:
++ *;
++};
+
+Property changes on: main/asterisk.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: main/cli.c
+===================================================================
+--- a/main/cli.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/cli.c (.../trunk) (revision 186562)
+@@ -1259,7 +1259,7 @@
+ {
+ struct ast_channel *c=NULL;
+ struct timeval now;
+- struct ast_str *out = ast_str_thread_get(&global_app_buf, 16);
++ struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16);
+ char cdrtime[256];
+ char nf[256], wf[256], rf[256];
+ long elapsed_seconds=0;
+Index: main/dial.c
+===================================================================
+--- a/main/dial.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/dial.c (.../trunk) (revision 186562)
+@@ -274,20 +274,19 @@
+ ast_channel_datastore_inherit(chan, channel->owner);
+
+ /* Copy over callerid information */
+- S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
+- S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
+- S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
+ S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
++ ast_party_redirecting_copy(&channel->owner->redirecting, &chan->redirecting);
+
++ channel->owner->cid.cid_tns = chan->cid.cid_tns;
++
++ ast_connected_line_copy_from_caller(&channel->owner->connected, &chan->cid);
++
+ ast_string_field_set(channel->owner, language, chan->language);
+ ast_string_field_set(channel->owner, accountcode, chan->accountcode);
+ channel->owner->cdrflags = chan->cdrflags;
+ if (ast_strlen_zero(channel->owner->musicclass))
+ ast_string_field_set(channel->owner, musicclass, chan->musicclass);
+
+- channel->owner->cid.cid_pres = chan->cid.cid_pres;
+- channel->owner->cid.cid_ton = chan->cid.cid_ton;
+- channel->owner->cid.cid_tns = chan->cid.cid_tns;
+ channel->owner->adsicpe = chan->adsicpe;
+ channel->owner->transfercapability = chan->transfercapability;
+ }
+@@ -429,6 +428,14 @@
+ ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", channel->owner->name, chan->name);
+ ast_indicate(chan, AST_CONTROL_SRCUPDATE);
+ break;
++ case AST_CONTROL_CONNECTED_LINE:
++ ast_verb(3, "%s connected line has changed, passing it to %s\n", channel->owner->name, chan->name);
++ ast_indicate_data(chan, AST_CONTROL_CONNECTED_LINE, fr->data.ptr, fr->datalen);
++ break;
++ case AST_CONTROL_REDIRECTING:
++ ast_verb(3, "%s redirecting info has changed, passing it to %s\n", channel->owner->name, chan->name);
++ ast_indicate_data(chan, AST_CONTROL_REDIRECTING, fr->data.ptr, fr->datalen);
++ break;
+ case AST_CONTROL_PROCEEDING:
+ ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
+ ast_indicate(chan, AST_CONTROL_PROCEEDING);
+Index: main/heap.c
+===================================================================
+--- a/main/heap.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/heap.c (.../trunk) (revision 186562)
+@@ -302,6 +302,8 @@
+ return h->cur_len;
+ }
+
++#ifndef DEBUG_THREADS
++
+ int ast_heap_wrlock(struct ast_heap *h)
+ {
+ return ast_rwlock_wrlock(&h->lock);
+@@ -317,3 +319,21 @@
+ return ast_rwlock_unlock(&h->lock);
+ }
+
++#else /* DEBUG_THREADS */
++
++int __ast_heap_wrlock(struct ast_heap *h, const char *file, const char *func, int line)
++{
++ return _ast_rwlock_wrlock(&h->lock, "&h->lock", file, line, func);
++}
++
++int __ast_heap_rdlock(struct ast_heap *h, const char *file, const char *func, int line)
++{
++ return _ast_rwlock_rdlock(&h->lock, "&h->lock", file, line, func);
++}
++
++int __ast_heap_unlock(struct ast_heap *h, const char *file, const char *func, int line)
++{
++ return _ast_rwlock_unlock(&h->lock, "&h->lock", file, line, func);
++}
++
++#endif /* DEBUG_THREADS */
+Index: main/pbx.c
+===================================================================
+--- a/main/pbx.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/pbx.c (.../trunk) (revision 186562)
+@@ -2924,7 +2924,7 @@
+ } else if (!strcmp(var, "SYSTEMNAME")) {
+ s = ast_config_AST_SYSTEM_NAME;
+ } else if (!strcmp(var, "ENTITYID")) {
+- ast_eid_to_str(workspace, workspacelen, &g_eid);
++ ast_eid_to_str(workspace, workspacelen, &ast_eid_default);
+ s = workspace;
+ }
+ }
+Index: main/strings.c
+===================================================================
+--- a/main/strings.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/strings.c (.../trunk) (revision 186562)
+@@ -66,7 +66,7 @@
+ }
+ /*
+ * Ask vsnprintf how much space we need. Remember that vsnprintf
+- * does not count the final '\0' so we must add 1.
++ * does not count the final <code>'\0'</code> so we must add 1.
+ */
+ va_copy(aq, ap);
+ res = vsnprintf((*buf)->__AST_STR_STR + offset, (*buf)->__AST_STR_LEN - offset, fmt, aq);
+@@ -143,7 +143,8 @@
+ maxlen--;
+ (*buf)->__AST_STR_USED++;
+
+- if (dynamic && (!maxlen || (escapecommas && !(maxlen - 1)))) {
++ if ((ptr >= (*buf)->__AST_STR_STR + (*buf)->__AST_STR_LEN - 3) ||
++ (dynamic && (!maxlen || (escapecommas && !(maxlen - 1))))) {
+ char *oldbase = (*buf)->__AST_STR_STR;
+ size_t old = (*buf)->__AST_STR_LEN;
+ if (ast_str_make_space(buf, (*buf)->__AST_STR_LEN * 2)) {
+@@ -156,11 +157,10 @@
+ ptr += (*buf)->__AST_STR_STR - oldbase;
+ }
+ }
+- if (__builtin_expect(!(maxsrc && maxlen), 0)) {
++ if (__builtin_expect(!maxlen, 0)) {
+ ptr--;
+ }
+ *ptr = '\0';
+- (*buf)->__AST_STR_USED--;
+ return (*buf)->__AST_STR_STR;
+ }
+
+Index: main/stun.c
+===================================================================
+--- a/main/stun.c (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/main/stun.c (.../trunk) (revision 186562)
+@@ -0,0 +1,475 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2008, Digium, Inc.
++ *
++ * Mark Spencer <markster@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*!
++ * \file
++ *
++ * \brief STUN Support
++ *
++ * \author Mark Spencer <markster@digium.com>
++ *
++ * \note STUN is defined in RFC 3489.
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include "asterisk/_private.h"
++#include "asterisk/stun.h"
++#include "asterisk/cli.h"
++#include "asterisk/utils.h"
++#include "asterisk/channel.h"
++
++static int stundebug; /*!< Are we debugging stun? */
++
++/*!
++ * \brief STUN support code
++ *
++ * This code provides some support for doing STUN transactions.
++ * Eventually it should be moved elsewhere as other protocols
++ * than RTP can benefit from it - e.g. SIP.
++ * STUN is described in RFC3489 and it is based on the exchange
++ * of UDP packets between a client and one or more servers to
++ * determine the externally visible address (and port) of the client
++ * once it has gone through the NAT boxes that connect it to the
++ * outside.
++ * The simplest request packet is just the header defined in
++ * struct stun_header, and from the response we may just look at
++ * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
++ * By doing more transactions with different server addresses we
++ * may determine more about the behaviour of the NAT boxes, of
++ * course - the details are in the RFC.
++ *
++ * All STUN packets start with a simple header made of a type,
++ * length (excluding the header) and a 16-byte random transaction id.
++ * Following the header we may have zero or more attributes, each
++ * structured as a type, length and a value (whose format depends
++ * on the type, but often contains addresses).
++ * Of course all fields are in network format.
++ */
++
++typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
++
++struct stun_header {
++ unsigned short msgtype;
++ unsigned short msglen;
++ stun_trans_id id;
++ unsigned char ies[0];
++} __attribute__((packed));
++
++struct stun_attr {
++ unsigned short attr;
++ unsigned short len;
++ unsigned char value[0];
++} __attribute__((packed));
++
++/*
++ * The format normally used for addresses carried by STUN messages.
++ */
++struct stun_addr {
++ unsigned char unused;
++ unsigned char family;
++ unsigned short port;
++ unsigned int addr;
++} __attribute__((packed));
++
++/*! \brief STUN message types
++ * 'BIND' refers to transactions used to determine the externally
++ * visible addresses. 'SEC' refers to transactions used to establish
++ * a session key for subsequent requests.
++ * 'SEC' functionality is not supported here.
++ */
++
++#define STUN_BINDREQ 0x0001
++#define STUN_BINDRESP 0x0101
++#define STUN_BINDERR 0x0111
++#define STUN_SECREQ 0x0002
++#define STUN_SECRESP 0x0102
++#define STUN_SECERR 0x0112
++
++/*! \brief Basic attribute types in stun messages.
++ * Messages can also contain custom attributes (codes above 0x7fff)
++ */
++#define STUN_MAPPED_ADDRESS 0x0001
++#define STUN_RESPONSE_ADDRESS 0x0002
++#define STUN_CHANGE_REQUEST 0x0003
++#define STUN_SOURCE_ADDRESS 0x0004
++#define STUN_CHANGED_ADDRESS 0x0005
++#define STUN_USERNAME 0x0006
++#define STUN_PASSWORD 0x0007
++#define STUN_MESSAGE_INTEGRITY 0x0008
++#define STUN_ERROR_CODE 0x0009
++#define STUN_UNKNOWN_ATTRIBUTES 0x000a
++#define STUN_REFLECTED_FROM 0x000b
++
++/*! \brief helper function to print message names */
++static const char *stun_msg2str(int msg)
++{
++ switch (msg) {
++ case STUN_BINDREQ:
++ return "Binding Request";
++ case STUN_BINDRESP:
++ return "Binding Response";
++ case STUN_BINDERR:
++ return "Binding Error Response";
++ case STUN_SECREQ:
++ return "Shared Secret Request";
++ case STUN_SECRESP:
++ return "Shared Secret Response";
++ case STUN_SECERR:
++ return "Shared Secret Error Response";
++ }
++ return "Non-RFC3489 Message";
++}
++
++/*! \brief helper function to print attribute names */
++static const char *stun_attr2str(int msg)
++{
++ switch (msg) {
++ case STUN_MAPPED_ADDRESS:
++ return "Mapped Address";
++ case STUN_RESPONSE_ADDRESS:
++ return "Response Address";
++ case STUN_CHANGE_REQUEST:
++ return "Change Request";
++ case STUN_SOURCE_ADDRESS:
++ return "Source Address";
++ case STUN_CHANGED_ADDRESS:
++ return "Changed Address";
++ case STUN_USERNAME:
++ return "Username";
++ case STUN_PASSWORD:
++ return "Password";
++ case STUN_MESSAGE_INTEGRITY:
++ return "Message Integrity";
++ case STUN_ERROR_CODE:
++ return "Error Code";
++ case STUN_UNKNOWN_ATTRIBUTES:
++ return "Unknown Attributes";
++ case STUN_REFLECTED_FROM:
++ return "Reflected From";
++ }
++ return "Non-RFC3489 Attribute";
++}
++
++/*! \brief here we store credentials extracted from a message */
++struct stun_state {
++ const char *username;
++ const char *password;
++};
++
++static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
++{
++ if (stundebug)
++ ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
++ stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
++ switch (ntohs(attr->attr)) {
++ case STUN_USERNAME:
++ state->username = (const char *) (attr->value);
++ break;
++ case STUN_PASSWORD:
++ state->password = (const char *) (attr->value);
++ break;
++ default:
++ if (stundebug)
++ ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
++ stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
++ }
++ return 0;
++}
++
++/*! \brief append a string to an STUN message */
++static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
++{
++ int size = sizeof(**attr) + strlen(s);
++ if (*left > size) {
++ (*attr)->attr = htons(attrval);
++ (*attr)->len = htons(strlen(s));
++ memcpy((*attr)->value, s, strlen(s));
++ (*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
++ *len += size;
++ *left -= size;
++ }
++}
++
++/*! \brief append an address to an STUN message */
++static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
++{
++ int size = sizeof(**attr) + 8;
++ struct stun_addr *addr;
++ if (*left > size) {
++ (*attr)->attr = htons(attrval);
++ (*attr)->len = htons(8);
++ addr = (struct stun_addr *)((*attr)->value);
++ addr->unused = 0;
++ addr->family = 0x01;
++ addr->port = sin->sin_port;
++ addr->addr = sin->sin_addr.s_addr;
++ (*attr) = (struct stun_attr *)((*attr)->value + 8);
++ *len += size;
++ *left -= size;
++ }
++}
++
++/*! \brief wrapper to send an STUN message */
++static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
++{
++ return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
++ (struct sockaddr *)dst, sizeof(*dst));
++}
++
++/*! \brief helper function to generate a random request id */
++static void stun_req_id(struct stun_header *req)
++{
++ int x;
++ for (x = 0; x < 4; x++)
++ req->id.id[x] = ast_random();
++}
++
++/*! \brief handle an incoming STUN message.
++ *
++ * Do some basic sanity checks on packet size and content,
++ * try to extract a bit of information, and possibly reply.
++ * At the moment this only processes BIND requests, and returns
++ * the externally visible address of the request.
++ * If a callback is specified, invoke it with the attribute.
++ */
++int ast_stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
++{
++ struct stun_header *hdr = (struct stun_header *)data;
++ struct stun_attr *attr;
++ struct stun_state st;
++ int ret = AST_STUN_IGNORE;
++ int x;
++
++ /* On entry, 'len' is the length of the udp payload. After the
++ * initial checks it becomes the size of unprocessed options,
++ * while 'data' is advanced accordingly.
++ */
++ if (len < sizeof(struct stun_header)) {
++ ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
++ return -1;
++ }
++ len -= sizeof(struct stun_header);
++ data += sizeof(struct stun_header);
++ x = ntohs(hdr->msglen); /* len as advertised in the message */
++ if (stundebug)
++ ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
++ if (x > len) {
++ ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
++ } else
++ len = x;
++ memset(&st, 0, sizeof(st));
++ while (len) {
++ if (len < sizeof(struct stun_attr)) {
++ ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
++ break;
++ }
++ attr = (struct stun_attr *)data;
++ /* compute total attribute length */
++ x = ntohs(attr->len) + sizeof(struct stun_attr);
++ if (x > len) {
++ ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
++ break;
++ }
++ if (stun_cb)
++ stun_cb(attr, arg);
++ if (stun_process_attr(&st, attr)) {
++ ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
++ break;
++ }
++ /* Clear attribute id: in case previous entry was a string,
++ * this will act as the terminator for the string.
++ */
++ attr->attr = 0;
++ data += x;
++ len -= x;
++ }
++ /* Null terminate any string.
++ * XXX NOTE, we write past the size of the buffer passed by the
++ * caller, so this is potentially dangerous. The only thing that
++ * saves us is that usually we read the incoming message in a
++ * much larger buffer in the struct ast_rtp
++ */
++ *data = '\0';
++
++ /* Now prepare to generate a reply, which at the moment is done
++ * only for properly formed (len == 0) STUN_BINDREQ messages.
++ */
++ if (len == 0) {
++ unsigned char respdata[1024];
++ struct stun_header *resp = (struct stun_header *)respdata;
++ int resplen = 0; /* len excluding header */
++ int respleft = sizeof(respdata) - sizeof(struct stun_header);
++
++ resp->id = hdr->id;
++ resp->msgtype = 0;
++ resp->msglen = 0;
++ attr = (struct stun_attr *)resp->ies;
++ switch (ntohs(hdr->msgtype)) {
++ case STUN_BINDREQ:
++ if (stundebug)
++ ast_verbose("STUN Bind Request, username: %s\n",
++ st.username ? st.username : "<none>");
++ if (st.username)
++ append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
++ append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
++ resp->msglen = htons(resplen);
++ resp->msgtype = htons(STUN_BINDRESP);
++ stun_send(s, src, resp);
++ ret = AST_STUN_ACCEPT;
++ break;
++ default:
++ if (stundebug)
++ ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
++ }
++ }
++ return ret;
++}
++
++/*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
++ * This is used as a callback for stun_handle_response
++ * when called from ast_stun_request.
++ */
++static int stun_get_mapped(struct stun_attr *attr, void *arg)
++{
++ struct stun_addr *addr = (struct stun_addr *)(attr + 1);
++ struct sockaddr_in *sa = (struct sockaddr_in *)arg;
++
++ if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
++ return 1; /* not us. */
++ sa->sin_port = addr->port;
++ sa->sin_addr.s_addr = addr->addr;
++ return 0;
++}
++
++/*! \brief Generic STUN request
++ * Send a generic stun request to the server specified,
++ * possibly waiting for a reply and filling the 'reply' field with
++ * the externally visible address. Note that in this case the request
++ * will be blocking.
++ * (Note, the interface may change slightly in the future).
++ *
++ * \param s the socket used to send the request
++ * \param dst the address of the STUN server
++ * \param username if non null, add the username in the request
++ * \param answer if non null, the function waits for a response and
++ * puts here the externally visible address.
++ * \return 0 on success, other values on error.
++ */
++int ast_stun_request(int s, struct sockaddr_in *dst,
++ const char *username, struct sockaddr_in *answer)
++{
++ struct stun_header *req;
++ unsigned char reqdata[1024];
++ int reqlen, reqleft;
++ struct stun_attr *attr;
++ int res = 0;
++ int retry;
++
++ req = (struct stun_header *)reqdata;
++ stun_req_id(req);
++ reqlen = 0;
++ reqleft = sizeof(reqdata) - sizeof(struct stun_header);
++ req->msgtype = 0;
++ req->msglen = 0;
++ attr = (struct stun_attr *)req->ies;
++ if (username)
++ append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
++ req->msglen = htons(reqlen);
++ req->msgtype = htons(STUN_BINDREQ);
++ for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
++ /* send request, possibly wait for reply */
++ unsigned char reply_buf[1024];
++ fd_set rfds;
++ struct timeval to = { 3, 0 }; /* timeout, make it configurable */
++ struct sockaddr_in src;
++ socklen_t srclen;
++
++ res = stun_send(s, dst, req);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "ast_stun_request send #%d failed error %d, retry\n",
++ retry, res);
++ continue;
++ }
++ if (answer == NULL)
++ break;
++ FD_ZERO(&rfds);
++ FD_SET(s, &rfds);
++ res = ast_select(s + 1, &rfds, NULL, NULL, &to);
++ if (res <= 0) /* timeout or error */
++ continue;
++ memset(&src, 0, sizeof(src));
++ srclen = sizeof(src);
++ /* XXX pass -1 in the size, because stun_handle_packet might
++ * write past the end of the buffer.
++ */
++ res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1,
++ 0, (struct sockaddr *)&src, &srclen);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "ast_stun_request recvfrom #%d failed error %d, retry\n",
++ retry, res);
++ continue;
++ }
++ memset(answer, 0, sizeof(struct sockaddr_in));
++ ast_stun_handle_packet(s, &src, reply_buf, res,
++ stun_get_mapped, answer);
++ res = 0; /* signal regular exit */
++ break;
++ }
++ return res;
++}
++
++static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "stun set debug {on|off}";
++ e->usage =
++ "Usage: stun set debug {on|off}\n"
++ " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
++ " debugging\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ if (a->argc != e->args)
++ return CLI_SHOWUSAGE;
++
++ if (!strncasecmp(a->argv[e->args-1], "on", 2))
++ stundebug = 1;
++ else if (!strncasecmp(a->argv[e->args-1], "off", 3))
++ stundebug = 0;
++ else
++ return CLI_SHOWUSAGE;
++
++ ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
++ return CLI_SUCCESS;
++}
++
++static struct ast_cli_entry cli_stun[] = {
++ AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
++};
++
++/*! \brief Initialize the STUN system in Asterisk */
++void ast_stun_init(void)
++{
++ ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
++}
+
+Property changes on: main/stun.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: main/file.c
+===================================================================
+--- a/main/file.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/file.c (.../trunk) (revision 186562)
+@@ -1234,6 +1234,7 @@
+ case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_HOLD:
+ case AST_CONTROL_UNHOLD:
++ case -1:
+ /* Unimportant */
+ break;
+ default:
+Index: main/callerid.c
+===================================================================
+--- a/main/callerid.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/callerid.c (.../trunk) (revision 186562)
+@@ -791,8 +791,8 @@
+
+ }
+
+-int vmwi_generate(unsigned char *buf, int active, int type, int codec,
+- const char* name, const char* number, int flags)
++int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, int codec,
++ const char* name, const char* number, int flags)
+ {
+ char msg[256];
+ int len = 0;
+@@ -922,8 +922,10 @@
+ return bytes;
+ }
+
+-/*! \brief Clean up phone string
+- * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
++/*!
++ * \brief Clean up phone string
++ * \details
++ * Remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
+ * Basically, remove anything that could be invalid in a pattern.
+ */
+ void ast_shrink_phone_number(char *n)
+@@ -958,11 +960,13 @@
+ n[y] = '\0';
+ }
+
+-/*! \brief Checks if phone number consists of valid characters
+- \param exten String that needs to be checked
+- \param valid Valid characters in string
+- \return 1 if valid string, 0 if string contains invalid characters
+-*/
++/*!
++ * \brief Checks if phone number consists of valid characters
++ * \param exten String that needs to be checked
++ * \param valid Valid characters in string
++ * \retval 1 if valid string
++ * \retval 0 if string contains invalid characters
++ */
+ static int ast_is_valid_string(const char *exten, const char *valid)
+ {
+ int x;
+@@ -975,34 +979,16 @@
+ return 1;
+ }
+
+-/*! \brief checks if string consists only of digits and * \# and +
+- \return 1 if string is valid AST phone number
+- \return 0 if not
+-*/
+ int ast_isphonenumber(const char *n)
+ {
+ return ast_is_valid_string(n, "0123456789*#+");
+ }
+
+-/*! \brief checks if string consists only of digits and ( ) - * \# and +
+- Pre-qualifies the string for ast_shrink_phone_number()
+- \return 1 if string is valid AST shrinkable phone number
+- \return 0 if not
+-*/
+ int ast_is_shrinkable_phonenumber(const char *exten)
+ {
+ return ast_is_valid_string(exten, "0123456789*#+()-.");
+ }
+
+-/*!
+- * \brief Destructively parse instr for caller id information
+- * \return always returns 0, as the code always returns something.
+- * \note XXX 'name' is not parsed consistently e.g. we have
+- * input location name
+- * " foo bar " <123> 123 ' foo bar ' (with spaces around)
+- * " foo bar " NULL 'foo bar' (without spaces around)
+- * The parsing of leading and trailing space/quotes should be more consistent.
+- */
+ int ast_callerid_parse(char *instr, char **name, char **location)
+ {
+ char *ns, *ne, *ls, *le;
+@@ -1103,68 +1089,191 @@
+ return 0;
+ }
+
+-/*! \brief Translation table for Caller ID Presentation settings */
+-static struct {
+- int val;
++struct ast_value_translation {
++ int value;
+ const char *name;
+ const char *description;
+-} pres_types[] = {
+- { AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened"},
+- { AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen"},
+- { AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen"},
+- { AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number"},
+- { AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened"},
+- { AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen"},
+- { AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen"},
+- { AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number"},
+- { AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable", "Number Unavailable"},
+ };
+
+-/*! \brief Convert caller ID text code to value
+- used in config file parsing
+- \param data text string
+- \return value AST_PRES_ from callerid.h
+-*/
++/*! \brief Translation table for Caller ID Presentation settings */
++static const struct ast_value_translation pres_types[] = {
++/* *INDENT-OFF* */
++ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened" },
++ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen" },
++ { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen" },
++ { AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number" },
++
++ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened" },
++ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen" },
++ { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen" },
++ { AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number" },
++
++ { AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER, "unavailable", "Number Unavailable" }, /* Default name to value conversion. */
++ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED, "unavailable", "Number Unavailable" },
++ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN, "unavailable", "Number Unavailable" },
++ { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN, "unavailable", "Number Unavailable" },
++/* *INDENT-ON* */
++};
++
++/*!
++ * \brief Convert caller ID text code to value (used in config file parsing)
++ * \param data text string from config file
++ * \retval value AST_PRES_ from callerid.h
++ * \retval -1 if not in table
++ */
+ int ast_parse_caller_presentation(const char *data)
+ {
+- int i;
++ int index;
+
+- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
+- if (!strcasecmp(pres_types[i].name, data))
+- return pres_types[i].val;
++ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
++ if (!strcasecmp(pres_types[index].name, data)) {
++ return pres_types[index].value;
++ }
+ }
+
+ return -1;
+ }
+
+-/*! \brief Convert caller ID pres value to explanatory string
+- \param data value (see callerid.h AST_PRES_ )
+- \return string for human presentation
+-*/
++/*!
++ * \brief Convert caller ID pres value to explanatory string
++ * \param data AST_PRES_ value from callerid.h
++ * \return string for human presentation
++ */
+ const char *ast_describe_caller_presentation(int data)
+ {
+- int i;
++ int index;
+
+- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
+- if (pres_types[i].val == data)
+- return pres_types[i].description;
++ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
++ if (pres_types[index].value == data) {
++ return pres_types[index].description;
++ }
+ }
+
+ return "unknown";
+ }
+
+-/*! \brief Convert caller ID pres value to text code
+- \param data text string
+- \return string for config file
+-*/
++/*!
++ * \brief Convert caller ID pres value to text code
++ * \param data AST_PRES_ value from callerid.h
++ * \return string for config file
++ */
+ const char *ast_named_caller_presentation(int data)
+ {
+- int i;
++ int index;
+
+- for (i = 0; i < ARRAY_LEN(pres_types); i++) {
+- if (pres_types[i].val == data)
+- return pres_types[i].name;
++ for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
++ if (pres_types[index].value == data) {
++ return pres_types[index].name;
++ }
+ }
+
+ return "unknown";
+ }
++
++/*! \brief Translation table for redirecting reason settings */
++static const struct ast_value_translation redirecting_reason_types[] = {
++/* *INDENT-OFF* */
++ { AST_REDIRECTING_REASON_UNKNOWN, "unknown", "Unknown" },
++ { AST_REDIRECTING_REASON_USER_BUSY, "cfb", "Call Forwarding Busy" },
++ { AST_REDIRECTING_REASON_NO_ANSWER, "cfnr", "Call Forwarding No Reply" },
++ { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable", "Callee is Unavailable" },
++ { AST_REDIRECTING_REASON_UNCONDITIONAL, "cfu", "Call Forwarding Unconditional" },
++ { AST_REDIRECTING_REASON_TIME_OF_DAY, "time_of_day", "Time of Day" },
++ { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "dnd", "Do Not Disturb" },
++ { AST_REDIRECTING_REASON_DEFLECTION, "deflection", "Call Deflection" },
++ { AST_REDIRECTING_REASON_FOLLOW_ME, "follow_me", "Follow Me" },
++ { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out_of_order", "Called DTE Out-Of-Order" },
++ { AST_REDIRECTING_REASON_AWAY, "away", "Callee is Away" },
++ { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", "Call Forwarding By The Called DTE" },
++/* *INDENT-ON* */
++};
++
++int ast_redirecting_reason_parse(const char *data)
++{
++ int index;
++
++ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
++ if (!strcasecmp(redirecting_reason_types[index].name, data)) {
++ return redirecting_reason_types[index].value;
++ }
++ }
++
++ return -1;
++}
++
++const char *ast_redirecting_reason_describe(int data)
++{
++ int index;
++
++ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
++ if (redirecting_reason_types[index].value == data) {
++ return redirecting_reason_types[index].description;
++ }
++ }
++
++ return "not-known";
++}
++
++const char *ast_redirecting_reason_name(int data)
++{
++ int index;
++
++ for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
++ if (redirecting_reason_types[index].value == data) {
++ return redirecting_reason_types[index].name;
++ }
++ }
++
++ return "not-known";
++}
++
++/*! \brief Translation table for connected line update source settings */
++static const struct ast_value_translation connected_line_source_types[] = {
++/* *INDENT-OFF* */
++ { AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, "unknown", "Unknown" },
++ { AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, "answer", "Normal Call Answering" },
++ { AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION, "diversion", "Call Diversion (Deprecated, use REDIRECTING)" },
++ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer_active", "Call Transfer(Active)" },
++ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, "transfer", "Call Transfer(Active)" },/* Old name must come after new name. */
++ { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, "transfer_alerting", "Call Transfer(Alerting)" }
++/* *INDENT-ON* */
++};
++
++int ast_connected_line_source_parse(const char *data)
++{
++ int index;
++
++ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
++ if (!strcasecmp(connected_line_source_types[index].name, data)) {
++ return connected_line_source_types[index].value;
++ }
++ }
++
++ return -1;
++}
++
++const char *ast_connected_line_source_describe(int data)
++{
++ int index;
++
++ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
++ if (connected_line_source_types[index].value == data) {
++ return connected_line_source_types[index].description;
++ }
++ }
++
++ return "not-known";
++}
++
++const char *ast_connected_line_source_name(int data)
++{
++ int index;
++
++ for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
++ if (connected_line_source_types[index].value == data) {
++ return connected_line_source_types[index].name;
++ }
++ }
++
++ return "not-known";
++}
+Index: main/audiohook.c
+===================================================================
+--- a/main/audiohook.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/main/audiohook.c (.../trunk) (revision 186562)
+@@ -441,12 +441,12 @@
+
+ void ast_audiohook_move_by_source(struct ast_channel *old_chan, struct ast_channel *new_chan, const char *source)
+ {
+- struct ast_audiohook *audiohook = find_audiohook_by_source(old_chan->audiohooks, source);
++ struct ast_audiohook *audiohook;
+
+- if (!audiohook) {
++ if (!old_chan->audiohooks || !(audiohook = find_audiohook_by_source(old_chan->audiohooks, source))) {
+ return;
+ }
+-
++
+ /* By locking both channels and the audiohook, we can assure that
+ * another thread will not have a chance to read the audiohook's status
+ * as done, even though ast_audiohook_remove signals the trigger
+@@ -576,6 +576,7 @@
+ }
+ if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0)))
+ return frame;
++ samples = middle_frame->samples;
+ }
+
+ /* Queue up signed linear frame to each spy */
+Index: main/rtp_engine.c
+===================================================================
+--- a/main/rtp_engine.c (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/main/rtp_engine.c (.../trunk) (revision 186562)
+@@ -0,0 +1,1572 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2008, Digium, Inc.
++ *
++ * Joshua Colp <jcolp@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*! \file
++ *
++ * \brief Pluggable RTP Architecture
++ *
++ * \author Joshua Colp <jcolp@digium.com>
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <math.h>
++
++#include "asterisk/channel.h"
++#include "asterisk/frame.h"
++#include "asterisk/module.h"
++#include "asterisk/rtp_engine.h"
++#include "asterisk/manager.h"
++#include "asterisk/options.h"
++#include "asterisk/astobj2.h"
++#include "asterisk/pbx.h"
++
++/*! Structure that represents an RTP session (instance) */
++struct ast_rtp_instance {
++ /*! Engine that is handling this RTP instance */
++ struct ast_rtp_engine *engine;
++ /*! Data unique to the RTP engine */
++ void *data;
++ /*! RTP properties that have been set and their value */
++ int properties[AST_RTP_PROPERTY_MAX];
++ /*! Address that we are expecting RTP to come in to */
++ struct sockaddr_in local_address;
++ /*! Address that we are sending RTP to */
++ struct sockaddr_in remote_address;
++ /*! Instance that we are bridged to if doing remote or local bridging */
++ struct ast_rtp_instance *bridged;
++ /*! Payload and packetization information */
++ struct ast_rtp_codecs codecs;
++ /*! RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
++ int timeout;
++ /*! RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
++ int holdtimeout;
++ /*! DTMF mode in use */
++ enum ast_rtp_dtmf_mode dtmf_mode;
++};
++
++/*! List of RTP engines that are currently registered */
++static AST_RWLIST_HEAD_STATIC(engines, ast_rtp_engine);
++
++/*! List of RTP glues */
++static AST_RWLIST_HEAD_STATIC(glues, ast_rtp_glue);
++
++/*! The following array defines the MIME Media type (and subtype) for each
++ of our codecs, or RTP-specific data type. */
++static const struct ast_rtp_mime_type {
++ struct ast_rtp_payload_type payload_type;
++ char *type;
++ char *subtype;
++ unsigned int sample_rate;
++} ast_rtp_mime_types[] = {
++ {{1, AST_FORMAT_G723_1}, "audio", "G723", 8000},
++ {{1, AST_FORMAT_GSM}, "audio", "GSM", 8000},
++ {{1, AST_FORMAT_ULAW}, "audio", "PCMU", 8000},
++ {{1, AST_FORMAT_ULAW}, "audio", "G711U", 8000},
++ {{1, AST_FORMAT_ALAW}, "audio", "PCMA", 8000},
++ {{1, AST_FORMAT_ALAW}, "audio", "G711A", 8000},
++ {{1, AST_FORMAT_G726}, "audio", "G726-32", 8000},
++ {{1, AST_FORMAT_ADPCM}, "audio", "DVI4", 8000},
++ {{1, AST_FORMAT_SLINEAR}, "audio", "L16", 8000},
++ {{1, AST_FORMAT_LPC10}, "audio", "LPC", 8000},
++ {{1, AST_FORMAT_G729A}, "audio", "G729", 8000},
++ {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
++ {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
++ {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
++ {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
++ /* this is the sample rate listed in the RTP profile for the G.722
++ codec, *NOT* the actual sample rate of the media stream
++ */
++ {{1, AST_FORMAT_G722}, "audio", "G722", 8000},
++ {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32", 8000},
++ {{0, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
++ {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
++ {{0, AST_RTP_CN}, "audio", "CN", 8000},
++ {{1, AST_FORMAT_JPEG}, "video", "JPEG", 90000},
++ {{1, AST_FORMAT_PNG}, "video", "PNG", 90000},
++ {{1, AST_FORMAT_H261}, "video", "H261", 90000},
++ {{1, AST_FORMAT_H263}, "video", "H263", 90000},
++ {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998", 90000},
++ {{1, AST_FORMAT_H264}, "video", "H264", 90000},
++ {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES", 90000},
++ {{1, AST_FORMAT_T140RED}, "text", "RED", 1000},
++ {{1, AST_FORMAT_T140}, "text", "T140", 1000},
++ {{1, AST_FORMAT_SIREN7}, "audio", "G7221", 16000},
++ {{1, AST_FORMAT_SIREN14}, "audio", "G7221", 32000},
++};
++
++/*!
++ * \brief Mapping between Asterisk codecs and rtp payload types
++ *
++ * Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
++ * also, our own choices for dynamic payload types. This is our master
++ * table for transmission
++ *
++ * See http://www.iana.org/assignments/rtp-parameters for a list of
++ * assigned values
++ */
++static const struct ast_rtp_payload_type static_RTP_PT[AST_RTP_MAX_PT] = {
++ [0] = {1, AST_FORMAT_ULAW},
++ #ifdef USE_DEPRECATED_G726
++ [2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
++ #endif
++ [3] = {1, AST_FORMAT_GSM},
++ [4] = {1, AST_FORMAT_G723_1},
++ [5] = {1, AST_FORMAT_ADPCM}, /* 8 kHz */
++ [6] = {1, AST_FORMAT_ADPCM}, /* 16 kHz */
++ [7] = {1, AST_FORMAT_LPC10},
++ [8] = {1, AST_FORMAT_ALAW},
++ [9] = {1, AST_FORMAT_G722},
++ [10] = {1, AST_FORMAT_SLINEAR}, /* 2 channels */
++ [11] = {1, AST_FORMAT_SLINEAR}, /* 1 channel */
++ [13] = {0, AST_RTP_CN},
++ [16] = {1, AST_FORMAT_ADPCM}, /* 11.025 kHz */
++ [17] = {1, AST_FORMAT_ADPCM}, /* 22.050 kHz */
++ [18] = {1, AST_FORMAT_G729A},
++ [19] = {0, AST_RTP_CN}, /* Also used for CN */
++ [26] = {1, AST_FORMAT_JPEG},
++ [31] = {1, AST_FORMAT_H261},
++ [34] = {1, AST_FORMAT_H263},
++ [97] = {1, AST_FORMAT_ILBC},
++ [98] = {1, AST_FORMAT_H263_PLUS},
++ [99] = {1, AST_FORMAT_H264},
++ [101] = {0, AST_RTP_DTMF},
++ [102] = {1, AST_FORMAT_SIREN7},
++ [103] = {1, AST_FORMAT_H263_PLUS},
++ [104] = {1, AST_FORMAT_MP4_VIDEO},
++ [105] = {1, AST_FORMAT_T140RED}, /* Real time text chat (with redundancy encoding) */
++ [106] = {1, AST_FORMAT_T140}, /* Real time text chat */
++ [110] = {1, AST_FORMAT_SPEEX},
++ [111] = {1, AST_FORMAT_G726},
++ [112] = {1, AST_FORMAT_G726_AAL2},
++ [115] = {1, AST_FORMAT_SIREN14},
++ [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
++};
++
++int ast_rtp_engine_register2(struct ast_rtp_engine *engine, struct ast_module *module)
++{
++ struct ast_rtp_engine *current_engine;
++
++ /* Perform a sanity check on the engine structure to make sure it has the basics */
++ if (ast_strlen_zero(engine->name) || !engine->new || !engine->destroy || !engine->write || !engine->read) {
++ ast_log(LOG_WARNING, "RTP Engine '%s' failed sanity check so it was not registered.\n", !ast_strlen_zero(engine->name) ? engine->name : "Unknown");
++ return -1;
++ }
++
++ /* Link owner module to the RTP engine for reference counting purposes */
++ engine->mod = module;
++
++ AST_RWLIST_WRLOCK(&engines);
++
++ /* Ensure that no two modules with the same name are registered at the same time */
++ AST_RWLIST_TRAVERSE(&engines, current_engine, entry) {
++ if (!strcmp(current_engine->name, engine->name)) {
++ ast_log(LOG_WARNING, "An RTP engine with the name '%s' has already been registered.\n", engine->name);
++ AST_RWLIST_UNLOCK(&engines);
++ return -1;
++ }
++ }
++
++ /* The engine survived our critique. Off to the list it goes to be used */
++ AST_RWLIST_INSERT_TAIL(&engines, engine, entry);
++
++ AST_RWLIST_UNLOCK(&engines);
++
++ ast_verb(2, "Registered RTP engine '%s'\n", engine->name);
++
++ return 0;
++}
++
++int ast_rtp_engine_unregister(struct ast_rtp_engine *engine)
++{
++ struct ast_rtp_engine *current_engine = NULL;
++
++ AST_RWLIST_WRLOCK(&engines);
++
++ if ((current_engine = AST_RWLIST_REMOVE(&engines, engine, entry))) {
++ ast_verb(2, "Unregistered RTP engine '%s'\n", engine->name);
++ }
++
++ AST_RWLIST_UNLOCK(&engines);
++
++ return current_engine ? 0 : -1;
++}
++
++int ast_rtp_glue_register2(struct ast_rtp_glue *glue, struct ast_module *module)
++{
++ struct ast_rtp_glue *current_glue = NULL;
++
++ if (ast_strlen_zero(glue->type)) {
++ return -1;
++ }
++
++ glue->mod = module;
++
++ AST_RWLIST_WRLOCK(&glues);
++
++ AST_RWLIST_TRAVERSE(&glues, current_glue, entry) {
++ if (!strcasecmp(current_glue->type, glue->type)) {
++ ast_log(LOG_WARNING, "RTP glue with the name '%s' has already been registered.\n", glue->type);
++ AST_RWLIST_UNLOCK(&glues);
++ return -1;
++ }
++ }
++
++ AST_RWLIST_INSERT_TAIL(&glues, glue, entry);
++
++ AST_RWLIST_UNLOCK(&glues);
++
++ ast_verb(2, "Registered RTP glue '%s'\n", glue->type);
++
++ return 0;
++}
++
++int ast_rtp_glue_unregister(struct ast_rtp_glue *glue)
++{
++ struct ast_rtp_glue *current_glue = NULL;
++
++ AST_RWLIST_WRLOCK(&glues);
++
++ if ((current_glue = AST_RWLIST_REMOVE(&glues, glue, entry))) {
++ ast_verb(2, "Unregistered RTP glue '%s'\n", glue->type);
++ }
++
++ AST_RWLIST_UNLOCK(&glues);
++
++ return current_glue ? 0 : -1;
++}
++
++static void instance_destructor(void *obj)
++{
++ struct ast_rtp_instance *instance = obj;
++
++ /* Pass us off to the engine to destroy */
++ if (instance->data && instance->engine->destroy(instance)) {
++ ast_debug(1, "Engine '%s' failed to destroy RTP instance '%p'\n", instance->engine->name, instance);
++ return;
++ }
++
++ /* Drop our engine reference */
++ ast_module_unref(instance->engine->mod);
++
++ ast_debug(1, "Destroyed RTP instance '%p'\n", instance);
++}
++
++int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
++{
++ ao2_ref(instance, -1);
++
++ return 0;
++}
++
++struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, struct sockaddr_in *sin, void *data)
++{
++ struct ast_rtp_instance *instance = NULL;
++ struct ast_rtp_engine *engine = NULL;
++
++ AST_RWLIST_RDLOCK(&engines);
++
++ /* If an engine name was specified try to use it or otherwise use the first one registered */
++ if (!ast_strlen_zero(engine_name)) {
++ AST_RWLIST_TRAVERSE(&engines, engine, entry) {
++ if (!strcmp(engine->name, engine_name)) {
++ break;
++ }
++ }
++ } else {
++ engine = AST_RWLIST_FIRST(&engines);
++ }
++
++ /* If no engine was actually found bail out now */
++ if (!engine) {
++ ast_log(LOG_ERROR, "No RTP engine was found. Do you have one loaded?\n");
++ AST_RWLIST_UNLOCK(&engines);
++ return NULL;
++ }
++
++ /* Bump up the reference count before we return so the module can not be unloaded */
++ ast_module_ref(engine->mod);
++
++ AST_RWLIST_UNLOCK(&engines);
++
++ /* Allocate a new RTP instance */
++ if (!(instance = ao2_alloc(sizeof(*instance), instance_destructor))) {
++ ast_module_unref(engine->mod);
++ return NULL;
++ }
++ instance->engine = engine;
++ memcpy(&instance->local_address, sin, sizeof(instance->local_address));
++
++ ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance);
++
++ /* And pass it off to the engine to setup */
++ if (instance->engine->new(instance, sched, sin, data)) {
++ ast_debug(1, "Engine '%s' failed to setup RTP instance '%p'\n", engine->name, instance);
++ ao2_ref(instance, -1);
++ return NULL;
++ }
++
++ ast_debug(1, "RTP instance '%p' is setup and ready to go\n", instance);
++
++ return instance;
++}
++
++void ast_rtp_instance_set_data(struct ast_rtp_instance *instance, void *data)
++{
++ instance->data = data;
++}
++
++void *ast_rtp_instance_get_data(struct ast_rtp_instance *instance)
++{
++ return instance->data;
++}
++
++int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
++{
++ return instance->engine->write(instance, frame);
++}
++
++struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
++{
++ return instance->engine->read(instance, rtcp);
++}
++
++int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
++{
++ memcpy(&instance->local_address, address, sizeof(instance->local_address));
++ return 0;
++}
++
++int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
++{
++ if (&instance->remote_address != address) {
++ memcpy(&instance->remote_address, address, sizeof(instance->remote_address));
++ }
++
++ /* moo */
++
++ if (instance->engine->remote_address_set) {
++ instance->engine->remote_address_set(instance, address);
++ }
++
++ return 0;
++}
++
++int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
++{
++ if ((address->sin_family != AF_INET) ||
++ (address->sin_port != instance->local_address.sin_port) ||
++ (address->sin_addr.s_addr != instance->local_address.sin_addr.s_addr)) {
++ memcpy(address, &instance->local_address, sizeof(address));
++ return 1;
++ }
++
++ return 0;
++}
++
++int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
++{
++ if ((address->sin_family != AF_INET) ||
++ (address->sin_port != instance->remote_address.sin_port) ||
++ (address->sin_addr.s_addr != instance->remote_address.sin_addr.s_addr)) {
++ memcpy(address, &instance->remote_address, sizeof(address));
++ return 1;
++ }
++
++ return 0;
++}
++
++void ast_rtp_instance_set_extended_prop(struct ast_rtp_instance *instance, int property, void *value)
++{
++ if (instance->engine->extended_prop_set) {
++ instance->engine->extended_prop_set(instance, property, value);
++ }
++}
++
++void *ast_rtp_instance_get_extended_prop(struct ast_rtp_instance *instance, int property)
++{
++ if (instance->engine->extended_prop_get) {
++ return instance->engine->extended_prop_get(instance, property);
++ }
++
++ return NULL;
++}
++
++void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
++{
++ instance->properties[property] = value;
++
++ if (instance->engine->prop_set) {
++ instance->engine->prop_set(instance, property, value);
++ }
++}
++
++int ast_rtp_instance_get_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property)
++{
++ return instance->properties[property];
++}
++
++struct ast_rtp_codecs *ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
++{
++ return &instance->codecs;
++}
++
++void ast_rtp_codecs_payloads_clear(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
++{
++ int i;
++
++ for (i = 0; i < AST_RTP_MAX_PT; i++) {
++ ast_debug(2, "Clearing payload %d on %p\n", i, codecs);
++ codecs->payloads[i].asterisk_format = 0;
++ codecs->payloads[i].code = 0;
++ if (instance && instance->engine && instance->engine->payload_set) {
++ instance->engine->payload_set(instance, i, 0, 0);
++ }
++ }
++}
++
++void ast_rtp_codecs_payloads_default(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance)
++{
++ int i;
++
++ for (i = 0; i < AST_RTP_MAX_PT; i++) {
++ if (static_RTP_PT[i].code) {
++ ast_debug(2, "Set default payload %d on %p\n", i, codecs);
++ codecs->payloads[i].asterisk_format = static_RTP_PT[i].asterisk_format;
++ codecs->payloads[i].code = static_RTP_PT[i].code;
++ if (instance && instance->engine && instance->engine->payload_set) {
++ instance->engine->payload_set(instance, i, codecs->payloads[i].asterisk_format, codecs->payloads[i].code);
++ }
++ }
++ }
++}
++
++void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
++{
++ int i;
++
++ for (i = 0; i < AST_RTP_MAX_PT; i++) {
++ if (src->payloads[i].code) {
++ ast_debug(2, "Copying payload %d from %p to %p\n", i, src, dest);
++ dest->payloads[i].asterisk_format = src->payloads[i].asterisk_format;
++ dest->payloads[i].code = src->payloads[i].code;
++ if (instance && instance->engine && instance->engine->payload_set) {
++ instance->engine->payload_set(instance, i, dest->payloads[i].asterisk_format, dest->payloads[i].code);
++ }
++ }
++ }
++}
++
++void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
++{
++ if (payload < 0 || payload > AST_RTP_MAX_PT || !static_RTP_PT[payload].code) {
++ return;
++ }
++
++ codecs->payloads[payload].asterisk_format = static_RTP_PT[payload].asterisk_format;
++ codecs->payloads[payload].code = static_RTP_PT[payload].code;
++
++ ast_debug(1, "Setting payload %d based on m type on %p\n", payload, codecs);
++
++ if (instance && instance->engine && instance->engine->payload_set) {
++ instance->engine->payload_set(instance, payload, codecs->payloads[payload].asterisk_format, codecs->payloads[payload].code);
++ }
++}
++
++int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int pt,
++ char *mimetype, char *mimesubtype,
++ enum ast_rtp_options options,
++ unsigned int sample_rate)
++{
++ unsigned int i;
++ int found = 0;
++
++ if (pt < 0 || pt > AST_RTP_MAX_PT)
++ return -1; /* bogus payload type */
++
++ for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
++ const struct ast_rtp_mime_type *t = &ast_rtp_mime_types[i];
++
++ if (strcasecmp(mimesubtype, t->subtype)) {
++ continue;
++ }
++
++ if (strcasecmp(mimetype, t->type)) {
++ continue;
++ }
++
++ /* if both sample rates have been supplied, and they don't match,
++ then this not a match; if one has not been supplied, then the
++ rates are not compared */
++ if (sample_rate && t->sample_rate &&
++ (sample_rate != t->sample_rate)) {
++ continue;
++ }
++
++ found = 1;
++ codecs->payloads[pt] = t->payload_type;
++
++ if ((t->payload_type.code == AST_FORMAT_G726) &&
++ t->payload_type.asterisk_format &&
++ (options & AST_RTP_OPT_G726_NONSTANDARD)) {
++ codecs->payloads[pt].code = AST_FORMAT_G726_AAL2;
++ }
++
++ if (instance && instance->engine && instance->engine->payload_set) {
++ instance->engine->payload_set(instance, pt, codecs->payloads[i].asterisk_format, codecs->payloads[i].code);
++ }
++
++ break;
++ }
++
++ return (found ? 0 : -2);
++}
++
++int ast_rtp_codecs_payloads_set_rtpmap_type(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload, char *mimetype, char *mimesubtype, enum ast_rtp_options options)
++{
++ return ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, instance, payload, mimetype, mimesubtype, options, 0);
++}
++
++void ast_rtp_codecs_payloads_unset(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, int payload)
++{
++ if (payload < 0 || payload > AST_RTP_MAX_PT) {
++ return;
++ }
++
++ ast_debug(2, "Unsetting payload %d on %p\n", payload, codecs);
++
++ codecs->payloads[payload].asterisk_format = 0;
++ codecs->payloads[payload].code = 0;
++
++ if (instance && instance->engine && instance->engine->payload_set) {
++ instance->engine->payload_set(instance, payload, 0, 0);
++ }
++}
++
++struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup(struct ast_rtp_codecs *codecs, int payload)
++{
++ struct ast_rtp_payload_type result = { .asterisk_format = 0, };
++
++ if (payload < 0 || payload > AST_RTP_MAX_PT) {
++ return result;
++ }
++
++ result.asterisk_format = codecs->payloads[payload].asterisk_format;
++ result.code = codecs->payloads[payload].code;
++
++ if (!result.code) {
++ result = static_RTP_PT[payload];
++ }
++
++ return result;
++}
++
++void ast_rtp_codecs_payload_formats(struct ast_rtp_codecs *codecs, int *astformats, int *nonastformats)
++{
++ int i;
++
++ *astformats = *nonastformats = 0;
++
++ for (i = 0; i < AST_RTP_MAX_PT; i++) {
++ if (codecs->payloads[i].code) {
++ ast_debug(1, "Incorporating payload %d on %p\n", i, codecs);
++ }
++ if (codecs->payloads[i].asterisk_format) {
++ *astformats |= codecs->payloads[i].code;
++ } else {
++ *nonastformats |= codecs->payloads[i].code;
++ }
++ }
++}
++
++int ast_rtp_codecs_payload_code(struct ast_rtp_codecs *codecs, const int asterisk_format, const int code)
++{
++ int i;
++
++ for (i = 0; i < AST_RTP_MAX_PT; i++) {
++ if (codecs->payloads[i].asterisk_format == asterisk_format && codecs->payloads[i].code == code) {
++ ast_debug(2, "Found code %d at payload %d on %p\n", code, i, codecs);
++ return i;
++ }
++ }
++
++ for (i = 0; i < AST_RTP_MAX_PT; i++) {
++ if (static_RTP_PT[i].asterisk_format == asterisk_format && static_RTP_PT[i].code == code) {
++ return i;
++ }
++ }
++
++ return -1;
++}
++
++const char *ast_rtp_lookup_mime_subtype2(const int asterisk_format, const int code, enum ast_rtp_options options)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); i++) {
++ if (ast_rtp_mime_types[i].payload_type.code == code && ast_rtp_mime_types[i].payload_type.asterisk_format == asterisk_format) {
++ if (asterisk_format && (code == AST_FORMAT_G726_AAL2) && (options & AST_RTP_OPT_G726_NONSTANDARD)) {
++ return "G726-32";
++ } else {
++ return ast_rtp_mime_types[i].subtype;
++ }
++ }
++ }
++
++ return "";
++}
++
++unsigned int ast_rtp_lookup_sample_rate2(int asterisk_format, int code)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_LEN(ast_rtp_mime_types); ++i) {
++ if ((ast_rtp_mime_types[i].payload_type.code == code) && (ast_rtp_mime_types[i].payload_type.asterisk_format == asterisk_format)) {
++ return ast_rtp_mime_types[i].sample_rate;
++ }
++ }
++
++ return 0;
++}
++
++char *ast_rtp_lookup_mime_multiple2(struct ast_str *buf, const int capability, const int asterisk_format, enum ast_rtp_options options)
++{
++ int format, found = 0;
++
++ if (!buf) {
++ return NULL;
++ }
++
++ ast_str_append(&buf, 0, "0x%x (", capability);
++
++ for (format = 1; format < AST_RTP_MAX; format <<= 1) {
++ if (capability & format) {
++ const char *name = ast_rtp_lookup_mime_subtype2(asterisk_format, format, options);
++ ast_str_append(&buf, 0, "%s|", name);
++ found = 1;
++ }
++ }
++
++ ast_str_append(&buf, 0, "%s", found ? ")" : "nothing)");
++
++ return ast_str_buffer(buf);
++}
++
++void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs)
++{
++ codecs->pref = *prefs;
++
++ if (instance && instance->engine->packetization_set) {
++ instance->engine->packetization_set(instance, &instance->codecs.pref);
++ }
++}
++
++int ast_rtp_instance_dtmf_begin(struct ast_rtp_instance *instance, char digit)
++{
++ return instance->engine->dtmf_begin ? instance->engine->dtmf_begin(instance, digit) : -1;
++}
++
++int ast_rtp_instance_dtmf_end(struct ast_rtp_instance *instance, char digit)
++{
++ return instance->engine->dtmf_end ? instance->engine->dtmf_end(instance, digit) : -1;
++}
++
++int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode)
++{
++ if (!instance->engine->dtmf_mode_set || instance->engine->dtmf_mode_set(instance, dtmf_mode)) {
++ return -1;
++ }
++
++ instance->dtmf_mode = dtmf_mode;
++
++ return 0;
++}
++
++enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance)
++{
++ return instance->dtmf_mode;
++}
++
++void ast_rtp_instance_new_source(struct ast_rtp_instance *instance)
++{
++ if (instance->engine->new_source) {
++ instance->engine->new_source(instance);
++ }
++}
++
++int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
++{
++ return instance->engine->qos ? instance->engine->qos(instance, tos, cos, desc) : -1;
++}
++
++void ast_rtp_instance_stop(struct ast_rtp_instance *instance)
++{
++ if (instance->engine->stop) {
++ instance->engine->stop(instance);
++ }
++}
++
++int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp)
++{
++ return instance->engine->fd ? instance->engine->fd(instance, rtcp) : -1;
++}
++
++struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type)
++{
++ struct ast_rtp_glue *glue = NULL;
++
++ AST_RWLIST_RDLOCK(&glues);
++
++ AST_RWLIST_TRAVERSE(&glues, glue, entry) {
++ if (!strcasecmp(glue->type, type)) {
++ break;
++ }
++ }
++
++ AST_RWLIST_UNLOCK(&glues);
++
++ return glue;
++}
++
++static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
++{
++ enum ast_bridge_result res = AST_BRIDGE_FAILED;
++ struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
++ struct ast_frame *fr = NULL;
++
++ /* Start locally bridging both instances */
++ if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) {
++ ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", c0->name, c1->name);
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++ return AST_BRIDGE_FAILED_NOWARN;
++ }
++ if (instance1->engine->local_bridge && instance1->engine->local_bridge(instance1, instance0)) {
++ ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", c1->name, c0->name);
++ if (instance0->engine->local_bridge) {
++ instance0->engine->local_bridge(instance0, NULL);
++ }
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++ return AST_BRIDGE_FAILED_NOWARN;
++ }
++
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++
++ instance0->bridged = instance1;
++ instance1->bridged = instance0;
++
++ ast_poll_channel_add(c0, c1);
++
++ /* Hop into a loop waiting for a frame from either channel */
++ cs[0] = c0;
++ cs[1] = c1;
++ cs[2] = NULL;
++ for (;;) {
++ /* If the underlying formats have changed force this bridge to break */
++ if ((c0->rawreadformat != c1->rawwriteformat) || (c1->rawreadformat != c0->rawwriteformat)) {
++ ast_debug(1, "rtp-engine-local-bridge: Oooh, formats changed, backing out\n");
++ res = AST_BRIDGE_FAILED_NOWARN;
++ break;
++ }
++ /* Check if anything changed */
++ if ((c0->tech_pvt != pvt0) ||
++ (c1->tech_pvt != pvt1) ||
++ (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
++ (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks)) {
++ ast_debug(1, "rtp-engine-local-bridge: Oooh, something is weird, backing out\n");
++ /* If a masquerade needs to happen we have to try to read in a frame so that it actually happens. Without this we risk being called again and going into a loop */
++ if ((c0->masq || c0->masqr) && (fr = ast_read(c0))) {
++ ast_frfree(fr);
++ }
++ if ((c1->masq || c1->masqr) && (fr = ast_read(c1))) {
++ ast_frfree(fr);
++ }
++ res = AST_BRIDGE_RETRY;
++ break;
++ }
++ /* Wait on a channel to feed us a frame */
++ if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
++ if (!timeoutms) {
++ res = AST_BRIDGE_RETRY;
++ break;
++ }
++ ast_debug(2, "rtp-engine-local-bridge: Ooh, empty read...\n");
++ if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
++ break;
++ }
++ continue;
++ }
++ /* Read in frame from channel */
++ fr = ast_read(who);
++ other = (who == c0) ? c1 : c0;
++ /* Depending on the frame we may need to break out of our bridge */
++ if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
++ ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) |
++ ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)))) {
++ /* Record received frame and who */
++ *fo = fr;
++ *rc = who;
++ ast_debug(1, "rtp-engine-local-bridge: Ooh, got a %s\n", fr ? "digit" : "hangup");
++ res = AST_BRIDGE_COMPLETE;
++ break;
++ } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
++ if ((fr->subclass == AST_CONTROL_HOLD) ||
++ (fr->subclass == AST_CONTROL_UNHOLD) ||
++ (fr->subclass == AST_CONTROL_VIDUPDATE) ||
++ (fr->subclass == AST_CONTROL_T38) ||
++ (fr->subclass == AST_CONTROL_SRCUPDATE)) {
++ /* If we are going on hold, then break callback mode and P2P bridging */
++ if (fr->subclass == AST_CONTROL_HOLD) {
++ if (instance0->engine->local_bridge) {
++ instance0->engine->local_bridge(instance0, NULL);
++ }
++ if (instance1->engine->local_bridge) {
++ instance1->engine->local_bridge(instance1, NULL);
++ }
++ instance0->bridged = NULL;
++ instance1->bridged = NULL;
++ } else if (fr->subclass == AST_CONTROL_UNHOLD) {
++ if (instance0->engine->local_bridge) {
++ instance0->engine->local_bridge(instance0, instance1);
++ }
++ if (instance1->engine->local_bridge) {
++ instance1->engine->local_bridge(instance1, instance0);
++ }
++ instance0->bridged = instance1;
++ instance1->bridged = instance0;
++ }
++ ast_indicate_data(other, fr->subclass, fr->data.ptr, fr->datalen);
++ ast_frfree(fr);
++ } else {
++ *fo = fr;
++ *rc = who;
++ ast_debug(1, "rtp-engine-local-bridge: Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass, who->name);
++ res = AST_BRIDGE_COMPLETE;
++ break;
++ }
++ } else {
++ if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
++ (fr->frametype == AST_FRAME_DTMF_END) ||
++ (fr->frametype == AST_FRAME_VOICE) ||
++ (fr->frametype == AST_FRAME_VIDEO) ||
++ (fr->frametype == AST_FRAME_IMAGE) ||
++ (fr->frametype == AST_FRAME_HTML) ||
++ (fr->frametype == AST_FRAME_MODEM) ||
++ (fr->frametype == AST_FRAME_TEXT)) {
++ ast_write(other, fr);
++ }
++
++ ast_frfree(fr);
++ }
++ /* Swap priority */
++ cs[2] = cs[0];
++ cs[0] = cs[1];
++ cs[1] = cs[2];
++ }
++
++ /* Stop locally bridging both instances */
++ if (instance0->engine->local_bridge) {
++ instance0->engine->local_bridge(instance0, NULL);
++ }
++ if (instance1->engine->local_bridge) {
++ instance1->engine->local_bridge(instance1, NULL);
++ }
++
++ instance0->bridged = NULL;
++ instance1->bridged = NULL;
++
++ ast_poll_channel_del(c0, c1);
++
++ return res;
++}
++
++static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1,
++ struct ast_rtp_instance *vinstance0, struct ast_rtp_instance *vinstance1, struct ast_rtp_instance *tinstance0,
++ struct ast_rtp_instance *tinstance1, struct ast_rtp_glue *glue0, struct ast_rtp_glue *glue1, int codec0, int codec1, int timeoutms,
++ int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
++{
++ enum ast_bridge_result res = AST_BRIDGE_FAILED;
++ struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
++ int oldcodec0 = codec0, oldcodec1 = codec1;
++ struct sockaddr_in ac1 = {0,}, vac1 = {0,}, tac1 = {0,}, ac0 = {0,}, vac0 = {0,}, tac0 = {0,};
++ struct sockaddr_in t1 = {0,}, vt1 = {0,}, tt1 = {0,}, t0 = {0,}, vt0 = {0,}, tt0 = {0,};
++ struct ast_frame *fr = NULL;
++
++ /* Test the first channel */
++ if (!(glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0))) {
++ ast_rtp_instance_get_remote_address(instance1, &ac1);
++ if (vinstance1) {
++ ast_rtp_instance_get_remote_address(vinstance1, &vac1);
++ }
++ if (tinstance1) {
++ ast_rtp_instance_get_remote_address(tinstance1, &tac1);
++ }
++ } else {
++ ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
++ }
++
++ /* Test the second channel */
++ if (!(glue1->update_peer(c1, instance0, vinstance0, tinstance0, codec0, 0))) {
++ ast_rtp_instance_get_remote_address(instance0, &ac0);
++ if (vinstance0) {
++ ast_rtp_instance_get_remote_address(instance0, &vac0);
++ }
++ if (tinstance0) {
++ ast_rtp_instance_get_remote_address(instance0, &tac0);
++ }
++ } else {
++ ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c1->name, c0->name);
++ }
++
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++
++ instance0->bridged = instance1;
++ instance1->bridged = instance0;
++
++ ast_poll_channel_add(c0, c1);
++
++ /* Go into a loop handling any stray frames that may come in */
++ cs[0] = c0;
++ cs[1] = c1;
++ cs[2] = NULL;
++ for (;;) {
++ /* Check if anything changed */
++ if ((c0->tech_pvt != pvt0) ||
++ (c1->tech_pvt != pvt1) ||
++ (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
++ (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks)) {
++ ast_debug(1, "Oooh, something is weird, backing out\n");
++ res = AST_BRIDGE_RETRY;
++ break;
++ }
++
++ /* Check if they have changed their address */
++ ast_rtp_instance_get_remote_address(instance1, &t1);
++ if (vinstance1) {
++ ast_rtp_instance_get_remote_address(vinstance1, &vt1);
++ }
++ if (tinstance1) {
++ ast_rtp_instance_get_remote_address(tinstance1, &tt1);
++ }
++ if (glue1->get_codec) {
++ codec1 = glue1->get_codec(c1);
++ }
++
++ ast_rtp_instance_get_remote_address(instance0, &t0);
++ if (vinstance0) {
++ ast_rtp_instance_get_remote_address(vinstance0, &vt0);
++ }
++ if (tinstance0) {
++ ast_rtp_instance_get_remote_address(tinstance0, &tt0);
++ }
++ if (glue0->get_codec) {
++ codec0 = glue0->get_codec(c0);
++ }
++
++ if ((inaddrcmp(&t1, &ac1)) ||
++ (vinstance1 && inaddrcmp(&vt1, &vac1)) ||
++ (tinstance1 && inaddrcmp(&tt1, &tac1)) ||
++ (codec1 != oldcodec1)) {
++ ast_debug(1, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
++ c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), codec1);
++ ast_debug(1, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n",
++ c1->name, ast_inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), codec1);
++ ast_debug(1, "Oooh, '%s' changed end taddress to %s:%d (format %d)\n",
++ c1->name, ast_inet_ntoa(tt1.sin_addr), ntohs(tt1.sin_port), codec1);
++ ast_debug(1, "Oooh, '%s' was %s:%d/(format %d)\n",
++ c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
++ ast_debug(1, "Oooh, '%s' was %s:%d/(format %d)\n",
++ c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
++ ast_debug(1, "Oooh, '%s' was %s:%d/(format %d)\n",
++ c1->name, ast_inet_ntoa(tac1.sin_addr), ntohs(tac1.sin_port), oldcodec1);
++ if (glue0->update_peer(c0, t1.sin_addr.s_addr ? instance1 : NULL, vt1.sin_addr.s_addr ? vinstance1 : NULL, tt1.sin_addr.s_addr ? tinstance1 : NULL, codec1, 0)) {
++ ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
++ }
++ memcpy(&ac1, &t1, sizeof(ac1));
++ memcpy(&vac1, &vt1, sizeof(vac1));
++ memcpy(&tac1, &tt1, sizeof(tac1));
++ oldcodec1 = codec1;
++ }
++ if ((inaddrcmp(&t0, &ac0)) ||
++ (vinstance0 && inaddrcmp(&vt0, &vac0)) ||
++ (tinstance0 && inaddrcmp(&tt0, &tac0))) {
++ ast_debug(1, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
++ c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), codec0);
++ ast_debug(1, "Oooh, '%s' was %s:%d/(format %d)\n",
++ c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
++ if (glue1->update_peer(c1, t0.sin_addr.s_addr ? instance0 : NULL, vt0.sin_addr.s_addr ? vinstance0 : NULL, tt0.sin_addr.s_addr ? tinstance0 : NULL, codec0, 0)) {
++ ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
++ }
++ memcpy(&ac0, &t0, sizeof(ac0));
++ memcpy(&vac0, &vt0, sizeof(vac0));
++ memcpy(&tac0, &tt0, sizeof(tac0));
++ oldcodec0 = codec0;
++ }
++
++ /* Wait for frame to come in on the channels */
++ if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
++ if (!timeoutms) {
++ res = AST_BRIDGE_RETRY;
++ break;
++ }
++ ast_debug(1, "Ooh, empty read...\n");
++ if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
++ break;
++ }
++ continue;
++ }
++ fr = ast_read(who);
++ other = (who == c0) ? c1 : c0;
++ if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
++ (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
++ ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
++ /* Break out of bridge */
++ *fo = fr;
++ *rc = who;
++ ast_debug(1, "Oooh, got a %s\n", fr ? "digit" : "hangup");
++ res = AST_BRIDGE_COMPLETE;
++ break;
++ } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
++ if ((fr->subclass == AST_CONTROL_HOLD) ||
++ (fr->subclass == AST_CONTROL_UNHOLD) ||
++ (fr->subclass == AST_CONTROL_VIDUPDATE) ||
++ (fr->subclass == AST_CONTROL_T38) ||
++ (fr->subclass == AST_CONTROL_SRCUPDATE)) {
++ if (fr->subclass == AST_CONTROL_HOLD) {
++ /* If we someone went on hold we want the other side to reinvite back to us */
++ if (who == c0) {
++ glue1->update_peer(c1, NULL, NULL, NULL, 0, 0);
++ } else {
++ glue0->update_peer(c0, NULL, NULL, NULL, 0, 0);
++ }
++ } else if (fr->subclass == AST_CONTROL_UNHOLD) {
++ /* If they went off hold they should go back to being direct */
++ if (who == c0) {
++ glue1->update_peer(c1, instance0, vinstance0, tinstance0, codec0, 0);
++ } else {
++ glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0);
++ }
++ }
++ /* Update local address information */
++ ast_rtp_instance_get_remote_address(instance0, &t0);
++ memcpy(&ac0, &t0, sizeof(ac0));
++ ast_rtp_instance_get_remote_address(instance1, &t1);
++ memcpy(&ac1, &t1, sizeof(ac1));
++ /* Update codec information */
++ if (glue0->get_codec && c0->tech_pvt) {
++ oldcodec0 = codec0 = glue0->get_codec(c0);
++ }
++ if (glue1->get_codec && c1->tech_pvt) {
++ oldcodec1 = codec1 = glue1->get_codec(c1);
++ }
++ ast_indicate_data(other, fr->subclass, fr->data.ptr, fr->datalen);
++ ast_frfree(fr);
++ } else {
++ *fo = fr;
++ *rc = who;
++ ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass, who->name);
++ return AST_BRIDGE_COMPLETE;
++ }
++ } else {
++ if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
++ (fr->frametype == AST_FRAME_DTMF_END) ||
++ (fr->frametype == AST_FRAME_VOICE) ||
++ (fr->frametype == AST_FRAME_VIDEO) ||
++ (fr->frametype == AST_FRAME_IMAGE) ||
++ (fr->frametype == AST_FRAME_HTML) ||
++ (fr->frametype == AST_FRAME_MODEM) ||
++ (fr->frametype == AST_FRAME_TEXT)) {
++ ast_write(other, fr);
++ }
++ ast_frfree(fr);
++ }
++ /* Swap priority */
++ cs[2] = cs[0];
++ cs[0] = cs[1];
++ cs[1] = cs[2];
++ }
++
++ if (glue0->update_peer(c0, NULL, NULL, NULL, 0, 0)) {
++ ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
++ }
++ if (glue1->update_peer(c1, NULL, NULL, NULL, 0, 0)) {
++ ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
++ }
++
++ instance0->bridged = NULL;
++ instance1->bridged = NULL;
++
++ ast_poll_channel_del(c0, c1);
++
++ return res;
++}
++
++/*!
++ * \brief Conditionally unref an rtp instance
++ */
++static void unref_instance_cond(struct ast_rtp_instance **instance)
++{
++ if (*instance) {
++ ao2_ref(*instance, -1);
++ *instance = NULL;
++ }
++}
++
++enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
++{
++ struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
++ *vinstance0 = NULL, *vinstance1 = NULL,
++ *tinstance0 = NULL, *tinstance1 = NULL;
++ struct ast_rtp_glue *glue0, *glue1;
++ enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
++ enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
++ enum ast_bridge_result res = AST_BRIDGE_FAILED;
++ int codec0 = 0, codec1 = 0;
++ int unlock_chans = 1;
++
++ /* Lock both channels so we can look for the glue that binds them together */
++ ast_channel_lock(c0);
++ while (ast_channel_trylock(c1)) {
++ ast_channel_unlock(c0);
++ usleep(1);
++ ast_channel_lock(c0);
++ }
++
++ /* Ensure neither channel got hungup during lock avoidance */
++ if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
++ ast_log(LOG_WARNING, "Got hangup while attempting to bridge '%s' and '%s'\n", c0->name, c1->name);
++ goto done;
++ }
++
++ /* Grab glue that binds each channel to something using the RTP engine */
++ if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
++ ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
++ goto done;
++ }
++
++ audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
++ video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
++ text_glue0_res = glue0->get_trtp_info ? glue0->get_trtp_info(c0, &tinstance0) : AST_RTP_GLUE_RESULT_FORBID;
++
++ audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
++ video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
++ text_glue1_res = glue1->get_trtp_info ? glue1->get_trtp_info(c1, &tinstance1) : AST_RTP_GLUE_RESULT_FORBID;
++
++ /* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
++ if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
++ audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
++ }
++ if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
++ audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
++ }
++
++ /* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
++ if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) {
++ res = AST_BRIDGE_FAILED_NOWARN;
++ goto done;
++ }
++
++ /* If we have gotten to a local bridge make sure that both sides have the same local bridge callback and that they are DTMF compatible */
++ if ((audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) && ((instance0->engine->local_bridge != instance1->engine->local_bridge) || (instance0->engine->dtmf_compatible && !instance0->engine->dtmf_compatible(c0, instance0, c1, instance1)))) {
++ res = AST_BRIDGE_FAILED_NOWARN;
++ goto done;
++ }
++
++ /* Make sure that codecs match */
++ codec0 = glue0->get_codec ? glue0->get_codec(c0) : 0;
++ codec1 = glue1->get_codec ? glue1->get_codec(c1) : 0;
++ if (codec0 && codec1 && !(codec0 & codec1)) {
++ ast_debug(1, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
++ res = AST_BRIDGE_FAILED_NOWARN;
++ goto done;
++ }
++
++ /* Depending on the end result for bridging either do a local bridge or remote bridge */
++ if (audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) {
++ ast_verbose(VERBOSE_PREFIX_3 "Locally bridging %s and %s\n", c0->name, c1->name);
++ res = local_bridge_loop(c0, c1, instance0, instance1, timeoutms, flags, fo, rc, c0->tech_pvt, c1->tech_pvt);
++ } else {
++ ast_verbose(VERBOSE_PREFIX_3 "Remotely bridging %s and %s\n", c0->name, c1->name);
++ res = remote_bridge_loop(c0, c1, instance0, instance1, vinstance0, vinstance1,
++ tinstance0, tinstance1, glue0, glue1, codec0, codec1, timeoutms, flags,
++ fo, rc, c0->tech_pvt, c1->tech_pvt);
++ }
++
++ unlock_chans = 0;
++
++done:
++ if (unlock_chans) {
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++ }
++
++ unref_instance_cond(&instance0);
++ unref_instance_cond(&instance1);
++ unref_instance_cond(&vinstance0);
++ unref_instance_cond(&vinstance1);
++ unref_instance_cond(&tinstance0);
++ unref_instance_cond(&tinstance1);
++
++ return res;
++}
++
++struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance)
++{
++ return instance->bridged;
++}
++
++void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struct ast_channel *c1)
++{
++ struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
++ *vinstance0 = NULL, *vinstance1 = NULL,
++ *tinstance0 = NULL, *tinstance1 = NULL;
++ struct ast_rtp_glue *glue0, *glue1;
++ enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
++ enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
++ int codec0 = 0, codec1 = 0;
++ int res = 0;
++
++ /* Lock both channels so we can look for the glue that binds them together */
++ ast_channel_lock(c0);
++ while (ast_channel_trylock(c1)) {
++ ast_channel_unlock(c0);
++ usleep(1);
++ ast_channel_lock(c0);
++ }
++
++ /* Grab glue that binds each channel to something using the RTP engine */
++ if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
++ ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
++ goto done;
++ }
++
++ audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
++ video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
++ text_glue0_res = glue0->get_trtp_info ? glue0->get_trtp_info(c0, &tinstance0) : AST_RTP_GLUE_RESULT_FORBID;
++
++ audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
++ video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
++ text_glue1_res = glue1->get_trtp_info ? glue1->get_trtp_info(c1, &tinstance1) : AST_RTP_GLUE_RESULT_FORBID;
++
++ /* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
++ if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
++ audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
++ }
++ if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
++ audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
++ }
++ if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec(c0)) {
++ codec0 = glue0->get_codec(c0);
++ }
++ if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec(c1)) {
++ codec1 = glue1->get_codec(c1);
++ }
++
++ /* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
++ if (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE) {
++ goto done;
++ }
++
++ /* Make sure we have matching codecs */
++ if (!(codec0 & codec1)) {
++ goto done;
++ }
++
++ ast_rtp_codecs_payloads_copy(&instance0->codecs, &instance1->codecs, instance1);
++
++ if (vinstance0 && vinstance1) {
++ ast_rtp_codecs_payloads_copy(&vinstance0->codecs, &vinstance1->codecs, vinstance1);
++ }
++ if (tinstance0 && tinstance1) {
++ ast_rtp_codecs_payloads_copy(&tinstance0->codecs, &tinstance1->codecs, tinstance1);
++ }
++
++ res = 0;
++
++done:
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++
++ unref_instance_cond(&instance0);
++ unref_instance_cond(&instance1);
++ unref_instance_cond(&vinstance0);
++ unref_instance_cond(&vinstance1);
++ unref_instance_cond(&tinstance0);
++ unref_instance_cond(&tinstance1);
++
++ if (!res) {
++ ast_debug(1, "Seeded SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
++ }
++}
++
++int ast_rtp_instance_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
++{
++ struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL,
++ *vinstance0 = NULL, *vinstance1 = NULL,
++ *tinstance0 = NULL, *tinstance1 = NULL;
++ struct ast_rtp_glue *glue0, *glue1;
++ enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
++ enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
++ int codec0 = 0, codec1 = 0;
++ int res = 0;
++
++ /* If there is no second channel just immediately bail out, we are of no use in that scenario */
++ if (!c1) {
++ return -1;
++ }
++
++ /* Lock both channels so we can look for the glue that binds them together */
++ ast_channel_lock(c0);
++ while (ast_channel_trylock(c1)) {
++ ast_channel_unlock(c0);
++ usleep(1);
++ ast_channel_lock(c0);
++ }
++
++ /* Grab glue that binds each channel to something using the RTP engine */
++ if (!(glue0 = ast_rtp_instance_get_glue(c0->tech->type)) || !(glue1 = ast_rtp_instance_get_glue(c1->tech->type))) {
++ ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", glue0 ? c1->name : c0->name);
++ goto done;
++ }
++
++ audio_glue0_res = glue0->get_rtp_info(c0, &instance0);
++ video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
++ text_glue0_res = glue0->get_trtp_info ? glue0->get_trtp_info(c0, &tinstance0) : AST_RTP_GLUE_RESULT_FORBID;
++
++ audio_glue1_res = glue1->get_rtp_info(c1, &instance1);
++ video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
++ text_glue1_res = glue1->get_trtp_info ? glue1->get_trtp_info(c1, &tinstance1) : AST_RTP_GLUE_RESULT_FORBID;
++
++ /* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
++ if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
++ audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
++ }
++ if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
++ audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
++ }
++ if (audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE) && glue0->get_codec(c0)) {
++ codec0 = glue0->get_codec(c0);
++ }
++ if (audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && (video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) && glue1->get_codec(c1)) {
++ codec1 = glue1->get_codec(c1);
++ }
++
++ /* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
++ if (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE) {
++ goto done;
++ }
++
++ /* Make sure we have matching codecs */
++ if (!(codec0 & codec1)) {
++ goto done;
++ }
++
++ /* Bridge media early */
++ if (glue0->update_peer(c0, instance1, vinstance1, tinstance1, codec1, 0)) {
++ ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
++ }
++
++ res = 0;
++
++done:
++ ast_channel_unlock(c0);
++ ast_channel_unlock(c1);
++
++ unref_instance_cond(&instance0);
++ unref_instance_cond(&instance1);
++ unref_instance_cond(&vinstance0);
++ unref_instance_cond(&vinstance1);
++ unref_instance_cond(&tinstance0);
++ unref_instance_cond(&tinstance1);
++
++ if (!res) {
++ ast_debug(1, "Setting early bridge SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
++ }
++
++ return res;
++}
++
++int ast_rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
++{
++ return instance->engine->red_init ? instance->engine->red_init(instance, buffer_time, payloads, generations) : -1;
++}
++
++int ast_rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
++{
++ return instance->engine->red_buffer ? instance->engine->red_buffer(instance, frame) : -1;
++}
++
++int ast_rtp_instance_get_stats(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
++{
++ return instance->engine->get_stat ? instance->engine->get_stat(instance, stats, stat) : -1;
++}
++
++char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_rtp_instance_stat_field field, char *buf, size_t size)
++{
++ struct ast_rtp_instance_stats stats;
++ enum ast_rtp_instance_stat stat;
++
++ /* Determine what statistics we will need to retrieve based on field passed in */
++ if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY) {
++ stat = AST_RTP_INSTANCE_STAT_ALL;
++ } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER) {
++ stat = AST_RTP_INSTANCE_STAT_COMBINED_JITTER;
++ } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS) {
++ stat = AST_RTP_INSTANCE_STAT_COMBINED_LOSS;
++ } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {
++ stat = AST_RTP_INSTANCE_STAT_COMBINED_RTT;
++ } else {
++ return NULL;
++ }
++
++ /* Attempt to actually retrieve the statistics we need to generate the quality string */
++ if (ast_rtp_instance_get_stats(instance, &stats, stat)) {
++ return NULL;
++ }
++
++ /* Now actually fill the buffer with the good information */
++ if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY) {
++ snprintf(buf, size, "ssrc=%i;themssrc=%u;lp=%u;rxjitter=%u;rxcount=%u;txjitter=%u;txcount=%u;rlp=%u;rtt=%u",
++ stats.local_ssrc, stats.remote_ssrc, stats.rxploss, stats.txjitter, stats.rxcount, stats.rxjitter, stats.txcount, stats.txploss, stats.rtt);
++ } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER) {
++ snprintf(buf, size, "minrxjitter=%f;maxrxjitter=%f;avgrxjitter=%f;stdevrxjitter=%f;reported_minjitter=%f;reported_maxjitter=%f;reported_avgjitter=%f;reported_stdevjitter=%f;",
++ stats.local_minjitter, stats.local_maxjitter, stats.local_normdevjitter, sqrt(stats.local_stdevjitter), stats.remote_minjitter, stats.remote_maxjitter, stats.remote_normdevjitter, sqrt(stats.remote_stdevjitter));
++ } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS) {
++ snprintf(buf, size, "minrxlost=%f;maxrxlost=%f;avgrxlost=%f;stdevrxlost=%f;reported_minlost=%f;reported_maxlost=%f;reported_avglost=%f;reported_stdevlost=%f;",
++ stats.local_minrxploss, stats.local_maxrxploss, stats.local_normdevrxploss, sqrt(stats.local_stdevrxploss), stats.remote_minrxploss, stats.remote_maxrxploss, stats.remote_normdevrxploss, sqrt(stats.remote_stdevrxploss));
++ } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {
++ snprintf(buf, size, "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;", stats.minrtt, stats.maxrtt, stats.normdevrtt, stats.stdevrtt);
++ }
++
++ return buf;
++}
++
++void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_instance *instance)
++{
++ char quality_buf[AST_MAX_USER_FIELD], *quality;
++ struct ast_channel *bridge = ast_bridged_channel(chan);
++
++ if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) {
++ pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", quality);
++ if (bridge) {
++ pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", quality);
++ }
++ }
++
++ if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)))) {
++ pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", quality);
++ if (bridge) {
++ pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", quality);
++ }
++ }
++
++ if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)))) {
++ pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", quality);
++ if (bridge) {
++ pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", quality);
++ }
++ }
++
++ if ((quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)))) {
++ pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", quality);
++ if (bridge) {
++ pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", quality);
++ }
++ }
++}
++
++int ast_rtp_instance_set_read_format(struct ast_rtp_instance *instance, int format)
++{
++ return instance->engine->set_read_format ? instance->engine->set_read_format(instance, format) : -1;
++}
++
++int ast_rtp_instance_set_write_format(struct ast_rtp_instance *instance, int format)
++{
++ return instance->engine->set_write_format ? instance->engine->set_write_format(instance, format) : -1;
++}
++
++int ast_rtp_instance_make_compatible(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_channel *peer)
++{
++ struct ast_rtp_glue *glue;
++ struct ast_rtp_instance *peer_instance = NULL;
++ int res = -1;
++
++ if (!instance->engine->make_compatible) {
++ return -1;
++ }
++
++ ast_channel_lock(peer);
++
++ if (!(glue = ast_rtp_instance_get_glue(peer->tech->type))) {
++ ast_channel_unlock(peer);
++ return -1;
++ }
++
++ glue->get_rtp_info(peer, &peer_instance);
++
++ if (!peer_instance || peer_instance->engine != instance->engine) {
++ ast_channel_unlock(peer);
++ peer_instance = (ao2_ref(peer_instance, -1), NULL);
++ return -1;
++ }
++
++ res = instance->engine->make_compatible(chan, instance, peer, peer_instance);
++
++ ast_channel_unlock(peer);
++
++ peer_instance = (ao2_ref(peer_instance, -1), NULL);
++
++ return res;
++}
++
++int ast_rtp_instance_activate(struct ast_rtp_instance *instance)
++{
++ return instance->engine->activate ? instance->engine->activate(instance) : 0;
++}
++
++void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username)
++{
++ if (instance->engine->stun_request) {
++ instance->engine->stun_request(instance, suggestion, username);
++ }
++}
++
++void ast_rtp_instance_set_timeout(struct ast_rtp_instance *instance, int timeout)
++{
++ instance->timeout = timeout;
++}
++
++void ast_rtp_instance_set_hold_timeout(struct ast_rtp_instance *instance, int timeout)
++{
++ instance->holdtimeout = timeout;
++}
++
++int ast_rtp_instance_get_timeout(struct ast_rtp_instance *instance)
++{
++ return instance->timeout;
++}
++
++int ast_rtp_instance_get_hold_timeout(struct ast_rtp_instance *instance)
++{
++ return instance->holdtimeout;
++}
+
+Property changes on: main/rtp_engine.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: configs/sip.conf.sample
+===================================================================
+--- a/configs/sip.conf.sample (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/configs/sip.conf.sample (.../trunk) (revision 186562)
+@@ -182,6 +182,11 @@
+ ;vmexten=voicemail ; dialplan extension to reach mailbox sets the
+ ; Message-Account in the MWI notify message
+ ; defaults to "asterisk"
++
++;preferred_codec_only=yes ; Respond to a SIP invite with the single most preferred codec
++ ; rather than advertising all joint codec capabilities. This
++ ; limits the other side's codec choice to exactly what we prefer.
++
+ ;disallow=all ; First disallow all codecs
+ ;allow=ulaw ; Allow codecs in order of preference
+ ;allow=ilbc ; see doc/rtp-packetization for framing options
+@@ -209,6 +214,14 @@
+ ;relaxdtmf=yes ; Relax dtmf handling
+ ;trustrpid = no ; If Remote-Party-ID should be trusted
+ ;sendrpid = yes ; If Remote-Party-ID should be sent
++;sendrpid = rpid ; Use the "Remote-Party-ID" header
++ ; to send the identity of the remote party
++ ; This is identical to sendrpid=yes
++;sendrpid = pai ; Use the "P-Asserted-Identity" header
++ ; to send the identity of the remote party
++;rpid_header = rpid ; Which header should be used when sending Remote Party ID
++ ; 'rpid' means to send "Remote-Party-ID"
++ ; 'pai' means to send "P-Asserted-Identity"
+ ;progressinband=never ; If we should generate in-band ringing always
+ ; use 'never' to never use in-band signalling, even in cases
+ ; where some buggy devices might not render it
+@@ -256,9 +269,11 @@
+ ;authfailureevents=no ; generate manager "peerstatus" events when peer can't
+ ; authenticate with Asterisk. Peerstatus will be "rejected".
+ ;alwaysauthreject = yes ; When an incoming INVITE or REGISTER is to be rejected,
+- ; for any reason, always reject with '401 Unauthorized'
++ ; for any reason, always reject with an identical response
++ ; equivalent to valid username and invalid password/hash
+ ; instead of letting the requester know whether there was
+- ; a matching user or peer for their request
++ ; a matching user or peer for their request. This reduces
++ ; the ability of an attacker to scan for valid SIP usernames.
+
+ ;g726nonstandard = yes ; If the peer negotiates G726-32 audio, use AAL2 packing
+ ; order instead of RFC3551 packing order (this is required
+@@ -285,6 +300,8 @@
+ ;contactpermit=172.16.0.0/255.255.0.0 ; restrict at what IPs your users may
+ ; register their phones.
+
++;engine=asterisk ; RTP engine to use when communicating with the device
++
+ ;
+ ; If regcontext is specified, Asterisk will dynamically create and destroy a
+ ; NoOp priority 1 extension for a given peer who registers or unregisters with
+Index: configs/voicemail.conf.sample
+===================================================================
+--- a/configs/voicemail.conf.sample (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/configs/voicemail.conf.sample (.../trunk) (revision 186562)
+@@ -115,6 +115,10 @@
+ ; Change the from, body and/or subject, variables:
+ ; VM_NAME, VM_DUR, VM_MSGNUM, VM_MAILBOX, VM_CALLERID, VM_CIDNUM,
+ ; VM_CIDNAME, VM_DATE
++; Additionally, on forwarded messages, you have the variables:
++; ORIG_VM_CALLERID, ORIG_VM_CIDNUM, ORIG_VM_CIDNAME, ORIG_VM_DATE
++; You can select between two variables by using dialplan functions, e.g.
++; ${IF(${ISNULL(${ORIG_VM_DATE})}?${VM_DATE}:${ORIG_VM_DATE})}
+ ;
+ ; Note: The emailbody config row can only be up to 512 characters due to a
+ ; limitation in the Asterisk configuration subsystem.
+@@ -124,6 +128,11 @@
+ ; caller", if they are both null.
+ ;emailbody=Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just left a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE}, so you might\nwant to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n
+ ;
++; Note: ${IF()} strips spacing at the beginning and end of its true and false
++; values, so a newline cannot be placed at either location. The word 'so' is
++; therefore duplicated, in order for the newline to be interpreted correctly.
++;emailbody=Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just ${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?left:forwarded)} a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID}, on ${VM_DATE},\n${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?so:(originally sent by ${ORIG_VM_CALLERID} on ${ORIG_VM_DATE})\nso)} you might want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n
++;
+ ; You can also change the Pager From: string, the pager body and/or subject.
+ ; The above defined variables also can be used here
+ ;pagerfromstring=The Asterisk PBX
+@@ -240,8 +249,10 @@
+ ; exitcontext=fromvm ; Context to go to on user exit such as * or 0
+ ; The default is the current context.
+ ; review=yes ; Allow sender to review/rerecord their message before saving it [OFF by default
+-; operator=yes ; Allow sender to hit 0 before/after/during leaving a voicemail to
+- ; reach an operator [OFF by default]
++; operator=yes ; Allow sender to hit 0 before/after/during leaving a voicemail to
++ ; reach an operator. This option REQUIRES an 'o' extension in the
++ ; same context (or in exitcontext, if set), as that is where the
++ ; 0 key will send you. [OFF by default]
+ ; envelope=no ; Turn on/off envelope playback before message playback. [ON by default]
+ ; This does NOT affect option 3,3 from the advanced options menu
+ ; delete=yes ; After notification, the voicemail is deleted from the server. [per-mailbox only]
+Index: configs/misdn.conf.sample
+===================================================================
+--- a/configs/misdn.conf.sample (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/configs/misdn.conf.sample (.../trunk) (revision 186562)
+@@ -7,13 +7,13 @@
+ ; for debugging and general setup, things that are not bound to port groups
+ ;
+
+-[general]
++[general]
+ ;
+ ; Sets the Path to the misdn-init.conf (for nt_ptp mode checking)
+ ;
+ misdn_init=/etc/misdn-init.conf
+
+-; set debugging flag:
++; set debugging flag:
+ ; 0 - No Debug
+ ; 1 - mISDN Messages and * - Messages, and * - State changes
+ ; 2 - Messages + Message specific Informations (e.g. bearer capability)
+@@ -26,8 +26,8 @@
+
+
+
+-; set debugging file and flags for mISDNuser (NT-Stack)
+-;
++; set debugging file and flags for mISDNuser (NT-Stack)
++;
+ ; flags can be or'ed with the following values:
+ ;
+ ; DBGM_NET 0x00000001
+@@ -57,7 +57,7 @@
+ ntdebugfile=/var/log/misdn-nt.log
+
+
+-; some pbx systems do cut the L1 for some milliseconds, to avoid
++; some pbx systems do cut the L1 for some milliseconds, to avoid
+ ; dropping running calls, we can set this flag to yes and tell
+ ; mISDNuser not to drop the calls on L2_RELEASE
+ ntkeepcalls=no
+@@ -76,26 +76,13 @@
+ bridging=no
+
+
+-;
+-; watches the L1s of every port. If one l1 is down it tries to
+-; get it up. The timeout is given in seconds. with 0 as value it
+-; does not watch the l1 at all
+-;
+-; default value: 0
+-;
+-; this option is only read at loading time of chan_misdn,
+-; which means you need to unload and load chan_misdn to change the
+-; value, an asterisk restart should do the trick
+-;
+-l1watcher_timeout=0
+-
+ ; stops dialtone after getting first digit on nt Port
+ ;
+ ; default value: yes
+ ;
+ stop_tone_after_first_digit=yes
+
+-; whether to append overlapdialed Digits to Extension or not
++; whether to append overlapdialed Digits to Extension or not
+ ;
+ ; default value: yes
+ ;
+@@ -122,19 +109,6 @@
+ ;
+ crypt_keys=test,muh
+
+-; users sections:
+-;
+-; name your sections as you which but not "general" !
+-; the sections are Groups, you can dial out in extensions.conf
+-; with Dial(mISDN/g:extern/101) where extern is a section name,
+-; chan_misdn tries every port in this section to find a
+-; new free channel
+-;
+-
+-; The default section is not a group section, it just contains config elements
+-; which are inherited by group sections.
+-;
+-
+ ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
+ ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
+ ; SIP channel. Defaults to "no". An enabled jitterbuffer will
+@@ -161,6 +135,17 @@
+ ; jblog = no ; Enables jitterbuffer frame logging. Defaults to "no".
+ ;-----------------------------------------------------------------------------------
+
++; users sections:
++;
++; name your sections as you wish but not "general" or "default" !
++; the sections are Groups, you can dial out in extensions.conf
++; with Dial(mISDN/g:extern/101) where extern is a section name,
++; chan_misdn tries every port in this section to find a
++; new free channel
++;
++; The default section is not a group section, it just contains config elements
++; which are inherited by group sections.
++;
+ [default]
+
+ ; define your default context here
+@@ -182,7 +167,7 @@
+
+ ;
+ ; Either if we should produce DTMF Tones ourselves
+-;
++;
+ senddtmf=yes
+
+ ;
+@@ -205,14 +190,26 @@
+ ;
+ allowed_bearers=all
+
+-; Prefixes for national and international, those are put before the
+-; oad if an according dialplan is set by the other end.
++; Prefixes for national and international Type-Of-Number. These are
++; inserted before any number (caller, dialed, connected, redirecting,
++; redirection) received from the ISDN link if that number has the
++; correspondng Type-Of-Number.
++; See the dialplan options.
+ ;
+-; default values: nationalprefix : 0
+-; internationalprefix : 00
++; default values:
++; unknownprefix=
++; internationalprefix=00
++; nationalprefix=0
++; netspecificprefix=
++; subscriberprefix=
++; abbreviatedprefix=
+ ;
++;unknownprefix=
++internationalprefix=00
+ nationalprefix=0
+-internationalprefix=00
++;netspecificprefix=
++;subscriberprefix=
++;abbreviatedprefix=
+
+ ; set rx/tx gains between -8 and 8 to change the RX/TX Gain
+ ;
+@@ -222,7 +219,7 @@
+ rxgain=0
+ txgain=0
+
+-; some telcos especially in NL seem to need this set to yes, also in
++; some telcos especially in NL seem to need this set to yes, also in
+ ; switzerland this seems to be important
+ ;
+ ; default value: no
+@@ -232,7 +229,20 @@
+
+
+ ;
+-; This option defines, if chan_misdn should check the L1 on a PMP
++; Monitors L1 of the port. If L1 is down it tries
++; to bring it up. The polling timeout is given in seconds.
++; Setting the value to 0 disables monitoring L1 of the port.
++;
++; default value: 0
++;
++; This option is only read at chan_misdn loading time.
++; You need to unload and load chan_misdn to change the
++; value. An asterisk restart will also do the trick.
++;
++l1watcher_timeout=0
++
++;
++; This option defines, if chan_misdn should check the L1 on a PMP
+ ; before making a group call on it. The L1 may go down for PMP Ports
+ ; so we might need this.
+ ; But be aware! a broken or plugged off cable might be used for a group call
+@@ -245,19 +255,19 @@
+
+
+ ;
+-; in PMP this option defines which cause should be sent out to
++; in PMP this option defines which cause should be sent out to
+ ; the 3. caller. chan_misdn does not support callwaiting on TE
+-; PMP side. This allows to modify the RELEASE_COMPLETE cause
++; PMP side. This allows to modify the RELEASE_COMPLETE cause
+ ; at least.
+ ;
+ reject_cause=16
+
+
+ ;
+-; Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),
+-; this requests additional Infos, so we can waitfordigits
++; Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),
++; this requests additional Infos, so we can waitfordigits
+ ; without much issues. This works only for PTP Ports
+-;
++;
+ ; default value: no
+ ;
+ need_more_infos=no
+@@ -269,40 +279,42 @@
+ ;
+ nttimeout=no
+
+-; set the method to use for channel selection:
+-; standard - always choose the first free channel with the lowest number
+-; round_robin - use the round robin algorithm to select a channel. use this
+-; if you want to balance your load.
++; Set the method to use for channel selection:
++; standard - Use the first free channel starting from the lowest number.
++; standard_dec - Use the first free channel starting from the highest number.
++; round_robin - Use the round robin algorithm to select a channel. Use this
++; if you want to balance your load.
+ ;
+ ; default value: standard
+ ;
+ method=standard
+
+
+-; specify if chan_misdn should collect digits before going into the
++; specify if chan_misdn should collect digits before going into the
+ ; dialplan, you can choose yes=4 Seconds, no, or specify the amount
+ ; of seconds you need;
+-;
++;
+ overlapdial=yes
+
+ ;
+-; dialplan means Type Of Number in ISDN Terms (for outgoing calls)
++; dialplan means Type Of Number in ISDN Terms
++; There are different types of the dialplan:
+ ;
+-; there are different types of the dialplan:
++; dialplan -> for outgoing call's dialed number
++; localdialplan -> for outgoing call's callerid
++; (if -1 is set use the value from the asterisk channel)
++; cpndialplan -> for incoming call's connected party number sent to caller
++; (if -1 is set use the value from the asterisk channel)
+ ;
+-; dialplan -> outgoing Number
+-; localdialplan -> callerid
+-; cpndialplan -> connected party number
++; dialplan options:
+ ;
+-; dialplan options:
+-;
+ ; 0 - unknown
+ ; 1 - International
+ ; 2 - National
++; 3 - Network-Specific
+ ; 4 - Subscriber
++; 5 - Abbreviated
+ ;
+-; This setting is used for outgoing calls
+-;
+ ; default value: 0
+ ;
+ dialplan=0
+@@ -312,7 +324,7 @@
+
+
+ ;
+-; turn this to no if you don't mind correct handling of Progress Indicators
++; turn this to no if you don't mind correct handling of Progress Indicators
+ ;
+ early_bconnect=yes
+
+@@ -320,16 +332,16 @@
+ ;
+ ; turn this on if you like to send Tone Indications to a Incoming
+ ; isdn channel on a TE Port. Rarely used, only if the Telco allows
+-; you to send indications by yourself, normally the Telco sends the
++; you to send indications by yourself, normally the Telco sends the
+ ; indications to the remote party.
+-;
++;
+ ; default: no
+ ;
+ incoming_early_audio=no
+
+ ; uncomment the following to get into s extension at extension conf
+ ; there you can use DigitTimeout if you can't or don't want to use
+-; isdn overlap dial.
++; isdn overlap dial.
+ ; note: This will jump into the s exten for every exten!
+ ;
+ ; default value: no
+@@ -337,7 +349,7 @@
+ ;always_immediate=no
+
+ ;
+-; set this to yes if you want to generate your own dialtone
++; set this to yes if you want to generate your own dialtone
+ ; with always_immediate=yes, else chan_misdn generates the dialtone
+ ;
+ ; default value: no
+@@ -345,9 +357,9 @@
+ nodialtone=no
+
+
+-; uncomment the following if you want callers which called exactly the
++; uncomment the following if you want callers which called exactly the
+ ; base number (so no extension is set) jump to the s extension.
+-; if the user dials something more it jumps to the correct extension
++; if the user dials something more it jumps to the correct extension
+ ; instead
+ ;
+ ; default value: no
+@@ -368,6 +380,8 @@
+ ;callgroup=1
+ ;pickupgroup=1
+
++; Set the outgoing caller id to the value.
++;callerid="name" <number>
+
+ ;
+ ; these are the exact isdn screening and presentation indicators
+@@ -375,11 +389,31 @@
+ ; from asterisks CALLERPRES function.
+ ; s=0, p=0 -> callerid presented
+ ; s=1, p=1 -> callerid restricted (the remote end does not see it!)
+-;
++;
+ ; default values s=-1, p=-1
+ presentation=-1
+ screen=-1
+
++; 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.
++;
++display_connected=0
++
++; 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.
++;
++display_setup=0
++
+ ; This enables echo cancellation with the given number of taps.
+ ; Be aware: Move this setting only to outgoing portgroups!
+ ; A value of zero turns echo cancellation off.
+@@ -390,18 +424,9 @@
+ ;
+ ;echocancel=no
+
+-; Set this to no to disable echotraining. You can enter a number > 10
+-; the value is a multiple of 0.125 ms.
+ ;
+-; default value: no
+-; yes = 2000
+-; no = 0
++; chan_misdns jitterbuffer, default 4000
+ ;
+-echotraining=no
+-
+-;
+-; chan_misdns jitterbuffer, default 4000
+-;
+ jitterbuffer=4000
+
+ ;
+@@ -411,7 +436,7 @@
+
+
+ ;
+-; change this to yes, if you want to bridge a mISDN data channel to
++; change this to yes, if you want to bridge a mISDN data channel to
+ ; another channel type or to an application.
+ ;
+ hdlc=no
+@@ -419,8 +444,8 @@
+
+ ;
+ ; defines the maximum amount of incoming calls per port for
+-; this group. Calls which exceed the maximum will be marked with
+-; the channel variable MAX_OVERFLOW. It will contain the amount of
++; this group. Calls which exceed the maximum will be marked with
++; the channel variable MAX_OVERFLOW. It will contain the amount of
+ ; overflowed calls
+ ;
+ max_incoming=-1
+@@ -432,7 +457,7 @@
+ max_outgoing=-1
+
+ [intern]
+-; define your ports, e.g. 1,2 (depends on mISDN-driver loading order)
++; define your ports, e.g. 1,2 (depends on mISDN-driver loading order)
+ ports=1,2
+ ; context where to go to when incoming Call on one of the above ports
+ context=Intern
+@@ -444,21 +469,21 @@
+ ; configs. For backwards compatibility you can still set ptp here.
+ ;
+ ports=3
+-
++
+ [first_extern]
+ ; again port defs
+ ports=4
+ ; again a context for incoming calls
+ context=Extern1
+-; msns for te ports, listen on those numbers on the above ports, and
++; msns for te ports, listen on those numbers on the above ports, and
+ ; indicate the incoming calls to asterisk
+-; here you can give a comma separated list or simply an '*' for
+-; any msn.
++; here you can give a comma separated list or simply an '*' for
++; any msn.
+ msns=*
+
+ ; here an example with given msns
+ [second_extern]
+ ports=5
+ context=Extern2
+-callerid=15
++callerid="Asterisk" <1234>
+ msns=102,144,101,104
+Index: configs/features.conf.sample
+===================================================================
+--- a/configs/features.conf.sample (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/configs/features.conf.sample (.../trunk) (revision 186562)
+@@ -62,7 +62,7 @@
+ ;disconnect => *0 ; Disconnect (default is *) -- Make sure to set the H and/or h option in the Dial() or Queue() app call!
+ ;automon => *1 ; One Touch Record a.k.a. Touch Monitor -- Make sure to set the W and/or w option in the Dial() or Queue() app call!
+ ;atxfer => *2 ; Attended transfer -- Make sure to set the T and/or t option in the Dial() or Queue() app call!
+-;parkcall => #72 ; Park call (one step parking) -- Make sure to set the K and/or K option in the Dial() app call!
++;parkcall => #72 ; Park call (one step parking) -- Make sure to set the K and/or k option in the Dial() app call!
+ ;automixmon => *3 ; One Touch Record a.k.a. Touch MixMonitor -- Make sure to set the X and/or x option in the Dial() or Queue() app call!
+
+ [applicationmap]
+Index: makeopts.in
+===================================================================
+--- a/makeopts.in (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/makeopts.in (.../trunk) (revision 186562)
+@@ -47,6 +47,8 @@
+ PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
+ PTHREAD_LIBS=@PTHREAD_LIBS@
+
++GNU_LD=@GNU_LD@
++
+ prefix = @prefix@
+ exec_prefix = @exec_prefix@
+
+Index: res/res_config_sqlite.c
+===================================================================
+--- a/res/res_config_sqlite.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_config_sqlite.c (.../trunk) (revision 186562)
+@@ -1862,7 +1862,7 @@
+ return 0;
+ }
+
+-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Realtime SQLite configuration",
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Realtime SQLite configuration",
+ .load = load_module,
+ .unload = unload_module,
+ );
+Index: res/res_speech.exports
+===================================================================
+--- a/res/res_speech.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_speech.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,21 @@
++{
++ global:
++ ast_speech_change;
++ ast_speech_change_results_type;
++ ast_speech_change_state;
++ ast_speech_destroy;
++ ast_speech_dtmf;
++ ast_speech_grammar_activate;
++ ast_speech_grammar_deactivate;
++ ast_speech_grammar_load;
++ ast_speech_grammar_unload;
++ ast_speech_new;
++ ast_speech_register;
++ ast_speech_results_free;
++ ast_speech_results_get;
++ ast_speech_start;
++ ast_speech_unregister;
++ ast_speech_write;
++ local:
++ *;
++};
+
+Property changes on: res/res_speech.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_config_odbc.c
+===================================================================
+--- a/res/res_config_odbc.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_config_odbc.c (.../trunk) (revision 186562)
+@@ -1067,7 +1067,7 @@
+ return 0;
+ }
+
+-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Realtime ODBC configuration",
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Realtime ODBC configuration",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload_module,
+Index: res/res_agi.c
+===================================================================
+--- a/res/res_agi.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_agi.c (.../trunk) (revision 186562)
+@@ -737,6 +737,10 @@
+ ast_frfree(f);
+ }
+ }
++
++ if (async_agi.speech) {
++ ast_speech_destroy(async_agi.speech);
++ }
+ quit:
+ /* notify manager users this channel cannot be
+ controlled anymore by Async AGI */
+@@ -2929,6 +2933,9 @@
+ }
+ }
+ }
++ if (agi->speech) {
++ ast_speech_destroy(agi->speech);
++ }
+ /* Notify process */
+ if (send_sighup) {
+ if (pid > -1) {
+Index: res/res_adsi.exports
+===================================================================
+--- a/res/res_adsi.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_adsi.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,33 @@
++{
++ global:
++ ast_adsi_available;
++ ast_adsi_begin_download;
++ ast_adsi_channel_restore;
++ ast_adsi_clear_screen;
++ ast_adsi_clear_soft_keys;
++ ast_adsi_connect_session;
++ ast_adsi_data_mode;
++ ast_adsi_disconnect_session;
++ ast_adsi_display;
++ ast_adsi_download_connect;
++ ast_adsi_download_disconnect;
++ ast_adsi_end_download;
++ ast_adsi_get_cpeid;
++ ast_adsi_get_cpeinfo;
++ ast_adsi_input_control;
++ ast_adsi_input_format;
++ ast_adsi_load_session;
++ ast_adsi_load_soft_key;
++ ast_adsi_print;
++ ast_adsi_query_cpeid;
++ ast_adsi_query_cpeinfo;
++ ast_adsi_read_encoded_dtmf;
++ ast_adsi_set_keys;
++ ast_adsi_set_line;
++ ast_adsi_transmit_message;
++ ast_adsi_transmit_message_full;
++ ast_adsi_unload_session;
++ ast_adsi_voice_mode;
++ local:
++ *;
++};
+
+Property changes on: res/res_adsi.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_config_ldap.c
+===================================================================
+--- a/res/res_config_ldap.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_config_ldap.c (.../trunk) (revision 186562)
+@@ -1758,7 +1758,7 @@
+ return CLI_SUCCESS;
+ }
+
+-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP realtime interface",
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "LDAP realtime interface",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+Index: res/res_odbc.c
+===================================================================
+--- a/res/res_odbc.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_odbc.c (.../trunk) (revision 186562)
+@@ -133,7 +133,7 @@
+ struct ao2_container *obj_container;
+ };
+
+-struct ao2_container *class_container;
++static struct ao2_container *class_container;
+
+ static AST_RWLIST_HEAD_STATIC(odbc_tables, odbc_cache_tables);
+
+@@ -415,11 +415,12 @@
+
+ /*!
+ * \brief Find or create an entry describing the table specified.
+- * \param obj An active ODBC handle on which to query the table
+- * \param table Tablename to describe
++ * \param database Name of an ODBC class on which to query the table
++ * \param tablename Tablename to describe
+ * \retval A structure describing the table layout, or NULL, if the table is not found or another error occurs.
+ * When a structure is returned, the contained columns list will be
+ * rdlock'ed, to ensure that it will be retained in memory.
++ * \since 1.6.1
+ */
+ struct odbc_cache_tables *ast_odbc_find_table(const char *database, const char *tablename)
+ {
+Index: res/res_snmp.c
+===================================================================
+--- a/res/res_snmp.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_snmp.c (.../trunk) (revision 186562)
+@@ -115,7 +115,7 @@
+ return ((thread != AST_PTHREADT_NULL) ? pthread_join(thread, NULL) : 0);
+ }
+
+-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "SNMP [Sub]Agent for Asterisk",
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SNMP [Sub]Agent for Asterisk",
+ .load = load_module,
+ .unload = unload_module,
+ );
+Index: res/ais/evt.c
+===================================================================
+--- a/res/ais/evt.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/ais/evt.c (.../trunk) (revision 186562)
+@@ -47,6 +47,7 @@
+ #include "asterisk/event.h"
+ #include "asterisk/config.h"
+ #include "asterisk/linkedlists.h"
++#include "asterisk/devicestate.h"
+
+ #ifndef AST_MODULE
+ /* XXX HACK */
+@@ -111,34 +112,7 @@
+
+ static void queue_event(struct ast_event *ast_event)
+ {
+- enum ast_event_type type;
+-
+- /*!
+- * \todo This hack macks me sad. I need to come up with a better way to
+- * figure out whether an event should be cached or not, and what
+- * parameters to cache on.
+- *
+- * As long as the types of events that are supported is limited,
+- * this isn't *terrible*, I guess. Perhaps we should just define
+- * caching rules in the core, and make them configurable, and not
+- * have it be the job of the event publishers.
+- */
+-
+- type = ast_event_get_type(ast_event);
+-
+- if (type == AST_EVENT_MWI) {
+- ast_event_queue_and_cache(ast_event,
+- AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR,
+- AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR,
+- AST_EVENT_IE_END);
+- } else if (type == AST_EVENT_DEVICE_STATE_CHANGE) {
+- ast_event_queue_and_cache(ast_event,
+- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
+- AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, sizeof(struct ast_eid),
+- AST_EVENT_IE_END);
+- } else {
+- ast_event_queue(ast_event);
+- }
++ ast_event_queue_and_cache(ast_event);
+ }
+
+ void evt_event_deliver_cb(SaEvtSubscriptionIdT sub_id,
+@@ -167,7 +141,7 @@
+ return;
+ }
+
+- if (!ast_eid_cmp(&g_eid, ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
++ if (!ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
+ /* Don't feed events back in that originated locally. */
+ return;
+ }
+@@ -209,7 +183,7 @@
+
+ ast_log(LOG_DEBUG, "Got an event to forward\n");
+
+- if (ast_eid_cmp(&g_eid, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
++ if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
+ /* If the event didn't originate from this server, don't send it back out. */
+ ast_log(LOG_DEBUG, "Returning here\n");
+ return;
+@@ -341,9 +315,14 @@
+ return;
+ }
+
+- if (!(publish_event = ast_calloc(1, sizeof(*publish_event))))
++ if (type == AST_EVENT_DEVICE_STATE_CHANGE && ast_enable_distributed_devstate()) {
+ return;
+-
++ }
++
++ if (!(publish_event = ast_calloc(1, sizeof(*publish_event)))) {
++ return;
++ }
++
+ publish_event->type = type;
+ ast_log(LOG_DEBUG, "Subscribing to event type %d\n", type);
+ publish_event->sub = ast_event_subscribe(type, ast_event_cb, event_channel,
+@@ -399,9 +378,14 @@
+ return;
+ }
+
+- if (!(subscribe_event = ast_calloc(1, sizeof(*subscribe_event))))
++ if (type == AST_EVENT_DEVICE_STATE_CHANGE && ast_enable_distributed_devstate()) {
+ return;
+-
++ }
++
++ if (!(subscribe_event = ast_calloc(1, sizeof(*subscribe_event)))) {
++ return;
++ }
++
+ subscribe_event->type = type;
+ subscribe_event->id = ast_atomic_fetchadd_int(&unique_id, +1);
+
+Index: res/res_agi.exports
+===================================================================
+--- a/res/res_agi.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_agi.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,7 @@
++{
++ global:
++ ast_agi_register;
++ ast_agi_unregister;
++ local:
++ *;
++};
+
+Property changes on: res/res_agi.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_monitor.c
+===================================================================
+--- a/res/res_monitor.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_monitor.c (.../trunk) (revision 186562)
+@@ -587,11 +587,7 @@
+
+ if (ast_strlen_zero(fname)) {
+ /* No filename base specified, default to channel name as per CLI */
+- if (!(fname = ast_strdup(c->name))) {
+- astman_send_error(s, m, "Could not start monitoring channel");
+- ast_channel_unlock(c);
+- return 0;
+- }
++ fname = ast_strdupa(c->name);
+ /* Channels have the format technology/channel_name - have to replace that / */
+ if ((d = strchr(fname, '/')))
+ *d = '-';
+Index: res/res_odbc.exports
+===================================================================
+--- a/res/res_odbc.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_odbc.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,20 @@
++{
++ global:
++ ast_odbc_ast_str_SQLGetData;
++ ast_odbc_backslash_is_escape;
++ ast_odbc_clear_cache;
++ ast_odbc_direct_execute;
++ ast_odbc_find_column;
++ ast_odbc_find_table;
++ ast_odbc_prepare_and_execute;
++ ast_odbc_release_obj;
++ ast_odbc_request_obj;
++ _ast_odbc_request_obj;
++ ast_odbc_request_obj2;
++ _ast_odbc_request_obj2;
++ ast_odbc_retrieve_transaction_obj;
++ ast_odbc_sanity_check;
++ ast_odbc_smart_execute;
++ local:
++ *;
++};
+
+Property changes on: res/res_odbc.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_features.exports
+===================================================================
+--- a/res/res_features.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_features.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,13 @@
++{
++ global:
++ ast_bridge_call;
++ ast_masq_park_call;
++ ast_park_call;
++ ast_parking_ext;
++ ast_pickup_call;
++ ast_pickup_ext;
++ ast_register_feature;
++ ast_unregister_feature;
++ local:
++ *;
++};
+
+Property changes on: res/res_features.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_curl.c
+===================================================================
+--- a/res/res_curl.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_curl.c (.../trunk) (revision 186562)
+@@ -71,5 +71,3 @@
+ }
+
+ AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "cURL Resource Module");
+-
+-
+Index: res/res_ael_share.exports
+===================================================================
+--- a/res/res_ael_share.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_ael_share.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,4 @@
++{
++ global:
++ *;
++};
+
+Property changes on: res/res_ael_share.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_jabber.exports
+===================================================================
+--- a/res/res_jabber.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_jabber.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,14 @@
++{
++ global:
++ ast_aji_create_chat;
++ ast_aji_disconnect;
++ ast_aji_get_client;
++ ast_aji_get_clients;
++ ast_aji_increment_mid;
++ ast_aji_invite_chat;
++ ast_aji_join_chat;
++ ast_aji_send;
++ ast_aji_send_chat;
++ local:
++ *;
++};
+
+Property changes on: res/res_jabber.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_monitor.exports
+===================================================================
+--- a/res/res_monitor.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_monitor.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,11 @@
++{
++ global:
++ ast_monitor_change_fname;
++ ast_monitor_pause;
++ ast_monitor_setjoinfiles;
++ ast_monitor_start;
++ ast_monitor_stop;
++ ast_monitor_unpause;
++ local:
++ *;
++};
+
+Property changes on: res/res_monitor.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_rtp_asterisk.c
+===================================================================
+--- a/res/res_rtp_asterisk.c (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_rtp_asterisk.c (.../trunk) (revision 186562)
+@@ -0,0 +1,2579 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2008, Digium, Inc.
++ *
++ * Mark Spencer <markster@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*!
++ * \file
++ *
++ * \brief Supports RTP and RTCP with Symmetric RTP support for NAT traversal.
++ *
++ * \author Mark Spencer <markster@digium.com>
++ *
++ * \note RTP is defined in RFC 3550.
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <sys/time.h>
++#include <signal.h>
++#include <fcntl.h>
++#include <math.h>
++
++#include "asterisk/stun.h"
++#include "asterisk/pbx.h"
++#include "asterisk/frame.h"
++#include "asterisk/channel.h"
++#include "asterisk/acl.h"
++#include "asterisk/config.h"
++#include "asterisk/lock.h"
++#include "asterisk/utils.h"
++#include "asterisk/netsock.h"
++#include "asterisk/cli.h"
++#include "asterisk/manager.h"
++#include "asterisk/unaligned.h"
++#include "asterisk/module.h"
++#include "asterisk/rtp_engine.h"
++
++#define MAX_TIMESTAMP_SKEW 640
++
++#define RTP_SEQ_MOD (1<<16) /*!< A sequence number can't be more than 16 bits */
++#define RTCP_DEFAULT_INTERVALMS 5000 /*!< Default milli-seconds between RTCP reports we send */
++#define RTCP_MIN_INTERVALMS 500 /*!< Min milli-seconds between RTCP reports we send */
++#define RTCP_MAX_INTERVALMS 60000 /*!< Max milli-seconds between RTCP reports we send */
++
++#define DEFAULT_RTP_START 5000 /*!< Default port number to start allocating RTP ports from */
++#define DEFAULT_RTP_END 31000 /*!< Default maximum port number to end allocating RTP ports at */
++
++#define MINIMUM_RTP_PORT 1024 /*!< Minimum port number to accept */
++#define MAXIMUM_RTP_PORT 65535 /*!< Maximum port number to accept */
++
++#define RTCP_PT_FUR 192
++#define RTCP_PT_SR 200
++#define RTCP_PT_RR 201
++#define RTCP_PT_SDES 202
++#define RTCP_PT_BYE 203
++#define RTCP_PT_APP 204
++
++#define RTP_MTU 1200
++
++#define DEFAULT_DTMF_TIMEOUT 3000 /*!< samples */
++
++#define ZFONE_PROFILE_ID 0x505a
++
++static int dtmftimeout = DEFAULT_DTMF_TIMEOUT;
++
++static int rtpstart = DEFAULT_RTP_START; /*!< First port for RTP sessions (set in rtp.conf) */
++static int rtpend = DEFAULT_RTP_END; /*!< Last port for RTP sessions (set in rtp.conf) */
++static int rtpdebug; /*!< Are we debugging? */
++static int rtcpdebug; /*!< Are we debugging RTCP? */
++static int rtcpstats; /*!< Are we debugging RTCP? */
++static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */
++static struct sockaddr_in rtpdebugaddr; /*!< Debug packets to/from this host */
++static struct sockaddr_in rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */
++#ifdef SO_NO_CHECK
++static int nochecksums;
++#endif
++static int strictrtp;
++
++enum strict_rtp_state {
++ STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
++ STRICT_RTP_LEARN, /*! Accept next packet as source */
++ STRICT_RTP_CLOSED, /*! Drop all RTP packets not coming from source that was learned */
++};
++
++#define FLAG_3389_WARNING (1 << 0)
++#define FLAG_NAT_ACTIVE (3 << 1)
++#define FLAG_NAT_INACTIVE (0 << 1)
++#define FLAG_NAT_INACTIVE_NOWARN (1 << 1)
++#define FLAG_NEED_MARKER_BIT (1 << 3)
++#define FLAG_DTMF_COMPENSATE (1 << 4)
++
++/*! \brief RTP session description */
++struct ast_rtp {
++ int s;
++ struct ast_frame f;
++ unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
++ unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */
++ unsigned int themssrc; /*!< Their SSRC */
++ unsigned int rxssrc;
++ unsigned int lastts;
++ unsigned int lastrxts;
++ unsigned int lastividtimestamp;
++ unsigned int lastovidtimestamp;
++ unsigned int lastitexttimestamp;
++ unsigned int lastotexttimestamp;
++ unsigned int lasteventseqn;
++ int lastrxseqno; /*!< Last received sequence number */
++ unsigned short seedrxseqno; /*!< What sequence number did they start with?*/
++ unsigned int seedrxts; /*!< What RTP timestamp did they start with? */
++ unsigned int rxcount; /*!< How many packets have we received? */
++ unsigned int rxoctetcount; /*!< How many octets have we received? should be rxcount *160*/
++ unsigned int txcount; /*!< How many packets have we sent? */
++ unsigned int txoctetcount; /*!< How many octets have we sent? (txcount*160)*/
++ unsigned int cycles; /*!< Shifted count of sequence number cycles */
++ double rxjitter; /*!< Interarrival jitter at the moment */
++ double rxtransit; /*!< Relative transit time for previous packet */
++ int lasttxformat;
++ int lastrxformat;
++
++ int rtptimeout; /*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
++ int rtpholdtimeout; /*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
++ int rtpkeepalive; /*!< Send RTP comfort noice packets for keepalive */
++
++ /* DTMF Reception Variables */
++ char resp;
++ unsigned int lastevent;
++ int dtmfcount;
++ unsigned int dtmfsamples;
++ /* DTMF Transmission Variables */
++ unsigned int lastdigitts;
++ char sending_digit; /*!< boolean - are we sending digits */
++ char send_digit; /*!< digit we are sending */
++ int send_payload;
++ int send_duration;
++ unsigned int flags;
++ struct timeval rxcore;
++ struct timeval txcore;
++ double drxcore; /*!< The double representation of the first received packet */
++ struct timeval lastrx; /*!< timeval when we last received a packet */
++ struct timeval dtmfmute;
++ struct ast_smoother *smoother;
++ int *ioid;
++ unsigned short seqno; /*!< Sequence number, RFC 3550, page 13. */
++ unsigned short rxseqno;
++ struct sched_context *sched;
++ struct io_context *io;
++ void *data;
++ struct ast_rtcp *rtcp;
++ struct ast_rtp *bridged; /*!< Who we are Packet bridged to */
++
++ enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */
++ struct sockaddr_in strict_rtp_address; /*!< Remote address information for strict RTP purposes */
++
++ struct rtp_red *red;
++};
++
++/*!
++ * \brief Structure defining an RTCP session.
++ *
++ * The concept "RTCP session" is not defined in RFC 3550, but since
++ * this structure is analogous to ast_rtp, which tracks a RTP session,
++ * it is logical to think of this as a RTCP session.
++ *
++ * RTCP packet is defined on page 9 of RFC 3550.
++ *
++ */
++struct ast_rtcp {
++ int rtcp_info;
++ int s; /*!< Socket */
++ struct sockaddr_in us; /*!< Socket representation of the local endpoint. */
++ struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */
++ unsigned int soc; /*!< What they told us */
++ unsigned int spc; /*!< What they told us */
++ unsigned int themrxlsr; /*!< The middle 32 bits of the NTP timestamp in the last received SR*/
++ struct timeval rxlsr; /*!< Time when we got their last SR */
++ struct timeval txlsr; /*!< Time when we sent or last SR*/
++ unsigned int expected_prior; /*!< no. packets in previous interval */
++ unsigned int received_prior; /*!< no. packets received in previous interval */
++ int schedid; /*!< Schedid returned from ast_sched_add() to schedule RTCP-transmissions*/
++ unsigned int rr_count; /*!< number of RRs we've sent, not including report blocks in SR's */
++ unsigned int sr_count; /*!< number of SRs we've sent */
++ unsigned int lastsrtxcount; /*!< Transmit packet count when last SR sent */
++ double accumulated_transit; /*!< accumulated a-dlsr-lsr */
++ double rtt; /*!< Last reported rtt */
++ unsigned int reported_jitter; /*!< The contents of their last jitter entry in the RR */
++ unsigned int reported_lost; /*!< Reported lost packets in their RR */
++
++ double reported_maxjitter;
++ double reported_minjitter;
++ double reported_normdev_jitter;
++ double reported_stdev_jitter;
++ unsigned int reported_jitter_count;
++
++ double reported_maxlost;
++ double reported_minlost;
++ double reported_normdev_lost;
++ double reported_stdev_lost;
++
++ double rxlost;
++ double maxrxlost;
++ double minrxlost;
++ double normdev_rxlost;
++ double stdev_rxlost;
++ unsigned int rxlost_count;
++
++ double maxrxjitter;
++ double minrxjitter;
++ double normdev_rxjitter;
++ double stdev_rxjitter;
++ unsigned int rxjitter_count;
++ double maxrtt;
++ double minrtt;
++ double normdevrtt;
++ double stdevrtt;
++ unsigned int rtt_count;
++};
++
++struct rtp_red {
++ struct ast_frame t140; /*!< Primary data */
++ struct ast_frame t140red; /*!< Redundant t140*/
++ unsigned char pt[AST_RED_MAX_GENERATION]; /*!< Payload types for redundancy data */
++ unsigned char ts[AST_RED_MAX_GENERATION]; /*!< Time stamps */
++ unsigned char len[AST_RED_MAX_GENERATION]; /*!< length of each generation */
++ int num_gen; /*!< Number of generations */
++ int schedid; /*!< Timer id */
++ int ti; /*!< How long to buffer data before send */
++ unsigned char t140red_data[64000];
++ unsigned char buf_data[64000]; /*!< buffered primary data */
++ int hdrlen;
++ long int prev_ts;
++};
++
++/* Forward Declarations */
++static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data);
++static int ast_rtp_destroy(struct ast_rtp_instance *instance);
++static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit);
++static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit);
++static void ast_rtp_new_source(struct ast_rtp_instance *instance);
++static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame);
++static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp);
++static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
++static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp);
++static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin);
++static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations);
++static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame);
++static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1);
++static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat);
++static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1);
++static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username);
++static void ast_rtp_stop(struct ast_rtp_instance *instance);
++
++/* RTP Engine Declaration */
++static struct ast_rtp_engine asterisk_rtp_engine = {
++ .name = "asterisk",
++ .new = ast_rtp_new,
++ .destroy = ast_rtp_destroy,
++ .dtmf_begin = ast_rtp_dtmf_begin,
++ .dtmf_end = ast_rtp_dtmf_end,
++ .new_source = ast_rtp_new_source,
++ .write = ast_rtp_write,
++ .read = ast_rtp_read,
++ .prop_set = ast_rtp_prop_set,
++ .fd = ast_rtp_fd,
++ .remote_address_set = ast_rtp_remote_address_set,
++ .red_init = rtp_red_init,
++ .red_buffer = rtp_red_buffer,
++ .local_bridge = ast_rtp_local_bridge,
++ .get_stat = ast_rtp_get_stat,
++ .dtmf_compatible = ast_rtp_dtmf_compatible,
++ .stun_request = ast_rtp_stun_request,
++ .stop = ast_rtp_stop,
++};
++
++static inline int rtp_debug_test_addr(struct sockaddr_in *addr)
++{
++ if (!rtpdebug) {
++ return 0;
++ }
++
++ if (rtpdebugaddr.sin_addr.s_addr) {
++ if (((ntohs(rtpdebugaddr.sin_port) != 0)
++ && (rtpdebugaddr.sin_port != addr->sin_port))
++ || (rtpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
++ return 0;
++ }
++
++ return 1;
++}
++
++static inline int rtcp_debug_test_addr(struct sockaddr_in *addr)
++{
++ if (!rtcpdebug) {
++ return 0;
++ }
++
++ if (rtcpdebugaddr.sin_addr.s_addr) {
++ if (((ntohs(rtcpdebugaddr.sin_port) != 0)
++ && (rtcpdebugaddr.sin_port != addr->sin_port))
++ || (rtcpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
++ return 0;
++ }
++
++ return 1;
++}
++
++static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp)
++{
++ unsigned int interval;
++ /*! \todo XXX Do a more reasonable calculation on this one
++ * Look in RFC 3550 Section A.7 for an example*/
++ interval = rtcpinterval;
++ return interval;
++}
++
++/*! \brief Calculate normal deviation */
++static double normdev_compute(double normdev, double sample, unsigned int sample_count)
++{
++ normdev = normdev * sample_count + sample;
++ sample_count++;
++
++ return normdev / sample_count;
++}
++
++static double stddev_compute(double stddev, double sample, double normdev, double normdev_curent, unsigned int sample_count)
++{
++/*
++ for the formula check http://www.cs.umd.edu/~austinjp/constSD.pdf
++ return sqrt( (sample_count*pow(stddev,2) + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1));
++ we can compute the sigma^2 and that way we would have to do the sqrt only 1 time at the end and would save another pow 2 compute
++ optimized formula
++*/
++#define SQUARE(x) ((x) * (x))
++
++ stddev = sample_count * stddev;
++ sample_count++;
++
++ return stddev +
++ ( sample_count * SQUARE( (sample - normdev) / sample_count ) ) +
++ ( SQUARE(sample - normdev_curent) / sample_count );
++
++#undef SQUARE
++}
++
++static int create_new_socket(const char *type)
++{
++ int sock = socket(AF_INET, SOCK_DGRAM, 0);
++
++ if (sock < 0) {
++ if (!type) {
++ type = "RTP/RTCP";
++ }
++ ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno));
++ } else {
++ long flags = fcntl(sock, F_GETFL);
++ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
++#ifdef SO_NO_CHECK
++ if (nochecksums) {
++ setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
++ }
++#endif
++ }
++
++ return sock;
++}
++
++static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context *sched, struct sockaddr_in *sin, void *data)
++{
++ struct ast_rtp *rtp = NULL;
++ int x, startplace;
++
++ /* Create a new RTP structure to hold all of our data */
++ if (!(rtp = ast_calloc(1, sizeof(*rtp)))) {
++ return -1;
++ }
++
++ /* Set default parameters on the newly created RTP structure */
++ rtp->ssrc = ast_random();
++ rtp->seqno = ast_random() & 0xffff;
++ rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
++
++ /* Create a new socket for us to listen on and use */
++ if ((rtp->s = create_new_socket("RTP")) < 0) {
++ ast_debug(1, "Failed to create a new socket for RTP instance '%p'\n", instance);
++ ast_free(rtp);
++ return -1;
++ }
++
++ /* Now actually find a free RTP port to use */
++ x = (rtpend == rtpstart) ? rtpstart : (ast_random() % (rtpend - rtpstart)) + rtpstart;
++ x = x & ~1;
++ startplace = x;
++
++ for (;;) {
++ struct sockaddr_in local_address = { 0, };
++
++ local_address.sin_port = htons(x);
++ /* Try to bind, this will tell us whether the port is available or not */
++ if (!bind(rtp->s, (struct sockaddr*)&local_address, sizeof(local_address))) {
++ ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance);
++ ast_rtp_instance_set_local_address(instance, &local_address);
++ break;
++ }
++
++ x += 2;
++ if (x > rtpend) {
++ x = (rtpstart + 1) & ~1;
++ }
++
++ /* See if we ran out of ports or if the bind actually failed because of something other than the address being in use */
++ if (x == startplace || errno != EADDRINUSE) {
++ ast_log(LOG_ERROR, "Oh dear... we couldn't allocate a port for RTP instance '%p'\n", instance);
++ return -1;
++ }
++ }
++
++ /* Record any information we may need */
++ rtp->sched = sched;
++
++ /* Associate the RTP structure with the RTP instance and be done */
++ ast_rtp_instance_set_data(instance, rtp);
++
++ return 0;
++}
++
++static int ast_rtp_destroy(struct ast_rtp_instance *instance)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ /* Destroy the smoother that was smoothing out audio if present */
++ if (rtp->smoother) {
++ ast_smoother_free(rtp->smoother);
++ }
++
++ /* Close our own socket so we no longer get packets */
++ if (rtp->s > -1) {
++ close(rtp->s);
++ }
++
++ /* Destroy RTCP if it was being used */
++ if (rtp->rtcp) {
++ AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
++ close(rtp->rtcp->s);
++ ast_free(rtp->rtcp);
++ }
++
++ /* Destroy RED if it was being used */
++ if (rtp->red) {
++ AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
++ ast_free(rtp->red);
++ }
++
++ /* Finally destroy ourselves */
++ ast_free(rtp);
++
++ return 0;
++}
++
++static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in remote_address;
++ int hdrlen = 12, res = 0, i = 0, payload = 101;
++ char data[256];
++ unsigned int *rtpheader = (unsigned int*)data;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ /* If we have no remote address information bail out now */
++ if (!remote_address.sin_addr.s_addr || !remote_address.sin_port) {
++ return -1;
++ }
++
++ /* Convert given digit into what we want to transmit */
++ if ((digit <= '9') && (digit >= '0')) {
++ digit -= '0';
++ } else if (digit == '*') {
++ digit = 10;
++ } else if (digit == '#') {
++ digit = 11;
++ } else if ((digit >= 'A') && (digit <= 'D')) {
++ digit = digit - 'A' + 12;
++ } else if ((digit >= 'a') && (digit <= 'd')) {
++ digit = digit - 'a' + 12;
++ } else {
++ ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
++ return -1;
++ }
++
++ /* Grab the payload that they expect the RFC2833 packet to be received in */
++ payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, AST_RTP_DTMF);
++
++ rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
++ rtp->send_duration = 160;
++ rtp->lastdigitts = rtp->lastts + rtp->send_duration;
++
++ /* Create the actual packet that we will be sending */
++ rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno));
++ rtpheader[1] = htonl(rtp->lastdigitts);
++ rtpheader[2] = htonl(rtp->ssrc);
++
++ /* Actually send the packet */
++ for (i = 0; i < 2; i++) {
++ rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
++ res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &remote_address, sizeof(remote_address));
++ if (res < 0) {
++ ast_log(LOG_ERROR, "RTP Transmission error to %s:%u: %s\n",
++ ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno));
++ }
++ if (rtp_debug_test_addr(&remote_address)) {
++ ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
++ ast_inet_ntoa(remote_address.sin_addr),
++ ntohs(remote_address.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
++ }
++ rtp->seqno++;
++ rtp->send_duration += 160;
++ rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
++ }
++
++ /* Record that we are in the process of sending a digit and information needed to continue doing so */
++ rtp->sending_digit = 1;
++ rtp->send_digit = digit;
++ rtp->send_payload = payload;
++
++ return 0;
++}
++
++static int ast_rtp_dtmf_continuation(struct ast_rtp_instance *instance)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in remote_address;
++ int hdrlen = 12, res = 0;
++ char data[256];
++ unsigned int *rtpheader = (unsigned int*)data;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ /* Make sure we know where the other side is so we can send them the packet */
++ if (!remote_address.sin_addr.s_addr || !remote_address.sin_port) {
++ return -1;
++ }
++
++ /* Actually create the packet we will be sending */
++ rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
++ rtpheader[1] = htonl(rtp->lastdigitts);
++ rtpheader[2] = htonl(rtp->ssrc);
++ rtpheader[3] = htonl((rtp->send_digit << 24) | (0xa << 16) | (rtp->send_duration));
++ rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
++
++ /* Boom, send it on out */
++ res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &remote_address, sizeof(remote_address));
++ if (res < 0) {
++ ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
++ ast_inet_ntoa(remote_address.sin_addr),
++ ntohs(remote_address.sin_port), strerror(errno));
++ }
++
++ if (rtp_debug_test_addr(&remote_address)) {
++ ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
++ ast_inet_ntoa(remote_address.sin_addr),
++ ntohs(remote_address.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
++ }
++
++ /* And now we increment some values for the next time we swing by */
++ rtp->seqno++;
++ rtp->send_duration += 160;
++
++ return 0;
++}
++
++static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in remote_address;
++ int hdrlen = 12, res = 0, i = 0;
++ char data[256];
++ unsigned int *rtpheader = (unsigned int*)data;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ /* Make sure we know where the remote side is so we can send them the packet we construct */
++ if (!remote_address.sin_addr.s_addr || !remote_address.sin_port) {
++ return -1;
++ }
++
++ /* Convert the given digit to the one we are going to send */
++ if ((digit <= '9') && (digit >= '0')) {
++ digit -= '0';
++ } else if (digit == '*') {
++ digit = 10;
++ } else if (digit == '#') {
++ digit = 11;
++ } else if ((digit >= 'A') && (digit <= 'D')) {
++ digit = digit - 'A' + 12;
++ } else if ((digit >= 'a') && (digit <= 'd')) {
++ digit = digit - 'a' + 12;
++ } else {
++ ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
++ return -1;
++ }
++
++ rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
++
++ /* Construct the packet we are going to send */
++ rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
++ rtpheader[1] = htonl(rtp->lastdigitts);
++ rtpheader[2] = htonl(rtp->ssrc);
++ rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
++ rtpheader[3] |= htonl((1 << 23));
++ rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
++
++ /* Send it 3 times, that's the magical number */
++ for (i = 0; i < 3; i++) {
++ res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &remote_address, sizeof(remote_address));
++ if (res < 0) {
++ ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
++ ast_inet_ntoa(remote_address.sin_addr),
++ ntohs(remote_address.sin_port), strerror(errno));
++ }
++ if (rtp_debug_test_addr(&remote_address)) {
++ ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
++ ast_inet_ntoa(remote_address.sin_addr),
++ ntohs(remote_address.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
++ }
++ }
++
++ /* Oh and we can't forget to turn off the stuff that says we are sending DTMF */
++ rtp->lastts += rtp->send_duration;
++ rtp->sending_digit = 0;
++ rtp->send_digit = 0;
++
++ return 0;
++}
++
++static void ast_rtp_new_source(struct ast_rtp_instance *instance)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ /* We simply set this bit so that the next packet sent will have the marker bit turned on */
++ ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
++
++ return;
++}
++
++static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
++{
++ struct timeval t;
++ long ms;
++
++ if (ast_tvzero(rtp->txcore)) {
++ rtp->txcore = ast_tvnow();
++ rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
++ }
++
++ t = (delivery && !ast_tvzero(*delivery)) ? *delivery : ast_tvnow();
++ if ((ms = ast_tvdiff_ms(t, rtp->txcore)) < 0) {
++ ms = 0;
++ }
++ rtp->txcore = t;
++
++ return (unsigned int) ms;
++}
++
++static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
++{
++ unsigned int sec, usec, frac;
++ sec = tv.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */
++ usec = tv.tv_usec;
++ frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6);
++ *msw = sec;
++ *lsw = frac;
++}
++
++/*! \brief Send RTCP recipient's report */
++static int ast_rtcp_write_rr(const void *data)
++{
++ struct ast_rtp *rtp = (struct ast_rtp *)data;
++ int res;
++ int len = 32;
++ unsigned int lost;
++ unsigned int extended;
++ unsigned int expected;
++ unsigned int expected_interval;
++ unsigned int received_interval;
++ int lost_interval;
++ struct timeval now;
++ unsigned int *rtcpheader;
++ char bdata[1024];
++ struct timeval dlsr;
++ int fraction;
++
++ double rxlost_current;
++
++ if (!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0))
++ return 0;
++
++ if (!rtp->rtcp->them.sin_addr.s_addr) {
++ ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted\n");
++ AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
++ return 0;
++ }
++
++ extended = rtp->cycles + rtp->lastrxseqno;
++ expected = extended - rtp->seedrxseqno + 1;
++ lost = expected - rtp->rxcount;
++ expected_interval = expected - rtp->rtcp->expected_prior;
++ rtp->rtcp->expected_prior = expected;
++ received_interval = rtp->rxcount - rtp->rtcp->received_prior;
++ rtp->rtcp->received_prior = rtp->rxcount;
++ lost_interval = expected_interval - received_interval;
++
++ if (lost_interval <= 0)
++ rtp->rtcp->rxlost = 0;
++ else rtp->rtcp->rxlost = rtp->rtcp->rxlost;
++ if (rtp->rtcp->rxlost_count == 0)
++ rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
++ if (lost_interval < rtp->rtcp->minrxlost)
++ rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
++ if (lost_interval > rtp->rtcp->maxrxlost)
++ rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;
++
++ rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
++ rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
++ rtp->rtcp->normdev_rxlost = rxlost_current;
++ rtp->rtcp->rxlost_count++;
++
++ if (expected_interval == 0 || lost_interval <= 0)
++ fraction = 0;
++ else
++ fraction = (lost_interval << 8) / expected_interval;
++ gettimeofday(&now, NULL);
++ timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
++ rtcpheader = (unsigned int *)bdata;
++ rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_RR << 16) | ((len/4)-1));
++ rtcpheader[1] = htonl(rtp->ssrc);
++ rtcpheader[2] = htonl(rtp->themssrc);
++ rtcpheader[3] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
++ rtcpheader[4] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
++ rtcpheader[5] = htonl((unsigned int)(rtp->rxjitter * 65536.));
++ rtcpheader[6] = htonl(rtp->rtcp->themrxlsr);
++ rtcpheader[7] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
++
++ /*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
++ it can change mid call, and SDES can't) */
++ rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
++ rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
++ rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
++ len += 12;
++
++ res = sendto(rtp->rtcp->s, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them));
++
++ if (res < 0) {
++ ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
++ /* Remove the scheduler */
++ AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
++ return 0;
++ }
++
++ rtp->rtcp->rr_count++;
++ if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
++ ast_verbose("\n* Sending RTCP RR to %s:%d\n"
++ " Our SSRC: %u\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n"
++ " IA jitter: %.4f\n"
++ " Their last SR: %u\n"
++ " DLSR: %4.4f (sec)\n\n",
++ ast_inet_ntoa(rtp->rtcp->them.sin_addr),
++ ntohs(rtp->rtcp->them.sin_port),
++ rtp->ssrc, rtp->themssrc, fraction, lost,
++ rtp->rxjitter,
++ rtp->rtcp->themrxlsr,
++ (double)(ntohl(rtcpheader[7])/65536.0));
++ }
++
++ return res;
++}
++
++/*! \brief Send RTCP sender's report */
++static int ast_rtcp_write_sr(const void *data)
++{
++ struct ast_rtp *rtp = (struct ast_rtp *)data;
++ int res;
++ int len = 0;
++ struct timeval now;
++ unsigned int now_lsw;
++ unsigned int now_msw;
++ unsigned int *rtcpheader;
++ unsigned int lost;
++ unsigned int extended;
++ unsigned int expected;
++ unsigned int expected_interval;
++ unsigned int received_interval;
++ int lost_interval;
++ int fraction;
++ struct timeval dlsr;
++ char bdata[512];
++
++ /* Commented condition is always not NULL if rtp->rtcp is not NULL */
++ if (!rtp || !rtp->rtcp/* || (&rtp->rtcp->them.sin_addr == 0)*/)
++ return 0;
++
++ if (!rtp->rtcp->them.sin_addr.s_addr) { /* This'll stop rtcp for this rtp session */
++ ast_verbose("RTCP SR transmission error, rtcp halted\n");
++ AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
++ return 0;
++ }
++
++ gettimeofday(&now, NULL);
++ timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
++ rtcpheader = (unsigned int *)bdata;
++ rtcpheader[1] = htonl(rtp->ssrc); /* Our SSRC */
++ rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
++ rtcpheader[3] = htonl(now_lsw); /* now, LSW */
++ rtcpheader[4] = htonl(rtp->lastts); /* FIXME shouldn't be that, it should be now */
++ rtcpheader[5] = htonl(rtp->txcount); /* No. packets sent */
++ rtcpheader[6] = htonl(rtp->txoctetcount); /* No. bytes sent */
++ len += 28;
++
++ extended = rtp->cycles + rtp->lastrxseqno;
++ expected = extended - rtp->seedrxseqno + 1;
++ if (rtp->rxcount > expected)
++ expected += rtp->rxcount - expected;
++ lost = expected - rtp->rxcount;
++ expected_interval = expected - rtp->rtcp->expected_prior;
++ rtp->rtcp->expected_prior = expected;
++ received_interval = rtp->rxcount - rtp->rtcp->received_prior;
++ rtp->rtcp->received_prior = rtp->rxcount;
++ lost_interval = expected_interval - received_interval;
++ if (expected_interval == 0 || lost_interval <= 0)
++ fraction = 0;
++ else
++ fraction = (lost_interval << 8) / expected_interval;
++ timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
++ rtcpheader[7] = htonl(rtp->themssrc);
++ rtcpheader[8] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
++ rtcpheader[9] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
++ rtcpheader[10] = htonl((unsigned int)(rtp->rxjitter * 65536.));
++ rtcpheader[11] = htonl(rtp->rtcp->themrxlsr);
++ rtcpheader[12] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
++ len += 24;
++
++ rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SR << 16) | ((len/4)-1));
++
++ /* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */
++ /* it can change mid call, and SDES can't) */
++ rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
++ rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
++ rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
++ len += 12;
++
++ res = sendto(rtp->rtcp->s, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them));
++ if (res < 0) {
++ ast_log(LOG_ERROR, "RTCP SR transmission error to %s:%d, rtcp halted %s\n",ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port), strerror(errno));
++ AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
++ return 0;
++ }
++
++ /* FIXME Don't need to get a new one */
++ gettimeofday(&rtp->rtcp->txlsr, NULL);
++ rtp->rtcp->sr_count++;
++
++ rtp->rtcp->lastsrtxcount = rtp->txcount;
++
++ if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
++ ast_verbose("* Sent RTCP SR to %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
++ ast_verbose(" Our SSRC: %u\n", rtp->ssrc);
++ ast_verbose(" Sent(NTP): %u.%010u\n", (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096);
++ ast_verbose(" Sent(RTP): %u\n", rtp->lastts);
++ ast_verbose(" Sent packets: %u\n", rtp->txcount);
++ ast_verbose(" Sent octets: %u\n", rtp->txoctetcount);
++ ast_verbose(" Report block:\n");
++ ast_verbose(" Fraction lost: %u\n", fraction);
++ ast_verbose(" Cumulative loss: %u\n", lost);
++ ast_verbose(" IA jitter: %.4f\n", rtp->rxjitter);
++ ast_verbose(" Their last SR: %u\n", rtp->rtcp->themrxlsr);
++ ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(ntohl(rtcpheader[12])/65536.0));
++ }
++ manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To %s:%d\r\n"
++ "OurSSRC: %u\r\n"
++ "SentNTP: %u.%010u\r\n"
++ "SentRTP: %u\r\n"
++ "SentPackets: %u\r\n"
++ "SentOctets: %u\r\n"
++ "ReportBlock:\r\n"
++ "FractionLost: %u\r\n"
++ "CumulativeLoss: %u\r\n"
++ "IAJitter: %.4f\r\n"
++ "TheirLastSR: %u\r\n"
++ "DLSR: %4.4f (sec)\r\n",
++ ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port),
++ rtp->ssrc,
++ (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096,
++ rtp->lastts,
++ rtp->txcount,
++ rtp->txoctetcount,
++ fraction,
++ lost,
++ rtp->rxjitter,
++ rtp->rtcp->themrxlsr,
++ (double)(ntohl(rtcpheader[12])/65536.0));
++ return res;
++}
++
++/*! \brief Write and RTCP packet to the far end
++ * \note Decide if we are going to send an SR (with Reception Block) or RR
++ * RR is sent if we have not sent any rtp packets in the previous interval */
++static int ast_rtcp_write(const void *data)
++{
++ struct ast_rtp *rtp = (struct ast_rtp *)data;
++ int res;
++
++ if (!rtp || !rtp->rtcp)
++ return 0;
++
++ if (rtp->txcount > rtp->rtcp->lastsrtxcount)
++ res = ast_rtcp_write_sr(data);
++ else
++ res = ast_rtcp_write_rr(data);
++
++ return res;
++}
++
++static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ int pred, mark = 0;
++ unsigned int ms = calc_txstamp(rtp, &frame->delivery);
++ struct sockaddr_in remote_address;
++
++ if (rtp->sending_digit) {
++ return 0;
++ }
++
++ if (frame->frametype == AST_FRAME_VOICE) {
++ pred = rtp->lastts + frame->samples;
++
++ /* Re-calculate last TS */
++ rtp->lastts = rtp->lastts + ms * 8;
++ if (ast_tvzero(frame->delivery)) {
++ /* If this isn't an absolute delivery time, Check if it is close to our prediction,
++ and if so, go with our prediction */
++ if (abs(rtp->lastts - pred) < MAX_TIMESTAMP_SKEW) {
++ rtp->lastts = pred;
++ } else {
++ ast_debug(3, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
++ mark = 1;
++ }
++ }
++ } else if (frame->frametype == AST_FRAME_VIDEO) {
++ mark = frame->subclass & 0x1;
++ pred = rtp->lastovidtimestamp + frame->samples;
++ /* Re-calculate last TS */
++ rtp->lastts = rtp->lastts + ms * 90;
++ /* If it's close to our prediction, go for it */
++ if (ast_tvzero(frame->delivery)) {
++ if (abs(rtp->lastts - pred) < 7200) {
++ rtp->lastts = pred;
++ rtp->lastovidtimestamp += frame->samples;
++ } else {
++ ast_debug(3, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
++ rtp->lastovidtimestamp = rtp->lastts;
++ }
++ }
++ } else {
++ pred = rtp->lastotexttimestamp + frame->samples;
++ /* Re-calculate last TS */
++ rtp->lastts = rtp->lastts + ms * 90;
++ /* If it's close to our prediction, go for it */
++ if (ast_tvzero(frame->delivery)) {
++ if (abs(rtp->lastts - pred) < 7200) {
++ rtp->lastts = pred;
++ rtp->lastotexttimestamp += frame->samples;
++ } else {
++ ast_debug(3, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
++ rtp->lastotexttimestamp = rtp->lastts;
++ }
++ }
++ }
++
++ /* If we have been explicitly told to set the marker bit then do so */
++ if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) {
++ mark = 1;
++ ast_clear_flag(rtp, FLAG_NEED_MARKER_BIT);
++ }
++
++ /* If the timestamp for non-digt packets has moved beyond the timestamp for digits, update the digit timestamp */
++ if (rtp->lastts > rtp->lastdigitts) {
++ rtp->lastdigitts = rtp->lastts;
++ }
++
++ if (ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO)) {
++ rtp->lastts = frame->ts * 8;
++ }
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ /* If we know the remote address construct a packet and send it out */
++ if (remote_address.sin_port && remote_address.sin_addr.s_addr) {
++ int hdrlen = 12, res;
++ unsigned char *rtpheader = (unsigned char *)(frame->data.ptr - hdrlen);
++
++ put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (rtp->seqno) | (mark << 23)));
++ put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts));
++ put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc));
++
++ if ((res = sendto(rtp->s, (void *)rtpheader, frame->datalen + hdrlen, 0, (struct sockaddr *)&remote_address, sizeof(remote_address))) < 0) {
++ if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
++ ast_debug(1, "RTP Transmission error of packet %d to %s:%d: %s\n", rtp->seqno, ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno));
++ } else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) {
++ /* Only give this error message once if we are not RTP debugging */
++ if (option_debug || rtpdebug)
++ ast_debug(0, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port));
++ ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN);
++ }
++ } else {
++ rtp->txcount++;
++ rtp->txoctetcount += (res - hdrlen);
++
++ if (rtp->rtcp && rtp->rtcp->schedid < 1) {
++ ast_debug(1, "Starting RTCP transmission on RTP instance '%p'\n", instance);
++ rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
++ }
++ }
++
++ if (rtp_debug_test_addr(&remote_address)) {
++ ast_verbose("Sent RTP packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
++ ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), codec, rtp->seqno, rtp->lastts, res - hdrlen);
++ }
++ }
++
++ rtp->seqno++;
++
++ return 0;
++}
++
++static struct ast_frame *red_t140_to_red(struct rtp_red *red) {
++ unsigned char *data = red->t140red.data.ptr;
++ int len = 0;
++ int i;
++
++ /* replace most aged generation */
++ if (red->len[0]) {
++ for (i = 1; i < red->num_gen+1; i++)
++ len += red->len[i];
++
++ memmove(&data[red->hdrlen], &data[red->hdrlen+red->len[0]], len);
++ }
++
++ /* Store length of each generation and primary data length*/
++ for (i = 0; i < red->num_gen; i++)
++ red->len[i] = red->len[i+1];
++ red->len[i] = red->t140.datalen;
++
++ /* write each generation length in red header */
++ len = red->hdrlen;
++ for (i = 0; i < red->num_gen; i++)
++ len += data[i*4+3] = red->len[i];
++
++ /* add primary data to buffer */
++ memcpy(&data[len], red->t140.data.ptr, red->t140.datalen);
++ red->t140red.datalen = len + red->t140.datalen;
++
++ /* no primary data and no generations to send */
++ if (len == red->hdrlen && !red->t140.datalen)
++ return NULL;
++
++ /* reset t.140 buffer */
++ red->t140.datalen = 0;
++
++ return &red->t140red;
++}
++
++static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in remote_address;
++ int codec, subclass;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ /* If we don't actually know the remote address don't even bother doing anything */
++ if (!remote_address.sin_addr.s_addr) {
++ ast_debug(1, "No remote address on RTP instance '%p' so dropping frame\n", instance);
++ return -1;
++ }
++
++ /* If there is no data length we can't very well send the packet */
++ if (!frame->datalen) {
++ ast_debug(1, "Received frame with no data for RTP instance '%p' so dropping frame\n", instance);
++ return -1;
++ }
++
++ /* If the packet is not one our RTP stack supports bail out */
++ if (frame->frametype != AST_FRAME_VOICE && frame->frametype != AST_FRAME_VIDEO && frame->frametype != AST_FRAME_TEXT) {
++ ast_log(LOG_WARNING, "RTP can only send voice, video, and text\n");
++ return -1;
++ }
++
++ if (rtp->red) {
++ /* return 0; */
++ /* no primary data or generations to send */
++ if ((frame = red_t140_to_red(rtp->red)) == NULL)
++ return 0;
++ }
++
++ /* Grab the subclass and look up the payload we are going to use */
++ subclass = frame->subclass;
++ if (frame->frametype == AST_FRAME_VIDEO) {
++ subclass &= ~0x1;
++ }
++ if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, subclass)) < 0) {
++ ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(frame->subclass));
++ return -1;
++ }
++
++ /* Oh dear, if the format changed we will have to set up a new smoother */
++ if (rtp->lasttxformat != subclass) {
++ ast_debug(1, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
++ rtp->lasttxformat = subclass;
++ if (rtp->smoother) {
++ ast_smoother_free(rtp->smoother);
++ rtp->smoother = NULL;
++ }
++ }
++
++ /* If no smoother is present see if we have to set one up */
++ if (!rtp->smoother) {
++ struct ast_format_list fmt = ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance)->pref, subclass);
++
++ switch (subclass) {
++ case AST_FORMAT_SPEEX:
++ case AST_FORMAT_G723_1:
++ case AST_FORMAT_SIREN7:
++ case AST_FORMAT_SIREN14:
++ /* these are all frame-based codecs and cannot be safely run through
++ a smoother */
++ break;
++ default:
++ if (fmt.inc_ms) {
++ if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
++ ast_log(LOG_WARNING, "Unable to create smoother: format %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
++ return -1;
++ }
++ if (fmt.flags) {
++ ast_smoother_set_flags(rtp->smoother, fmt.flags);
++ }
++ ast_debug(1, "Created smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
++ }
++ }
++ }
++
++ /* Feed audio frames into the actual function that will create a frame and send it */
++ if (rtp->smoother) {
++ struct ast_frame *f;
++
++ if (ast_smoother_test_flag(rtp->smoother, AST_SMOOTHER_FLAG_BE)) {
++ ast_smoother_feed_be(rtp->smoother, frame);
++ } else {
++ ast_smoother_feed(rtp->smoother, frame);
++ }
++
++ while ((f = ast_smoother_read(rtp->smoother)) && (f->data.ptr)) {
++ if (f->subclass == AST_FORMAT_G722) {
++ f->samples /= 2;
++ }
++
++ ast_rtp_raw_write(instance, f, codec);
++ }
++ } else {
++ int hdrlen = 12;
++ struct ast_frame *f = NULL;
++
++ if (frame->offset < hdrlen) {
++ f = ast_frdup(frame);
++ } else {
++ f = frame;
++ }
++ if (f->data.ptr) {
++ ast_rtp_raw_write(instance, f, codec);
++ }
++ if (f != frame) {
++ ast_frfree(f);
++ }
++
++ }
++
++ return 0;
++}
++
++static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark)
++{
++ struct timeval now;
++ double transit;
++ double current_time;
++ double d;
++ double dtv;
++ double prog;
++
++ double normdev_rxjitter_current;
++ if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
++ gettimeofday(&rtp->rxcore, NULL);
++ rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
++ /* map timestamp to a real time */
++ rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */
++ rtp->rxcore.tv_sec -= timestamp / 8000;
++ rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
++ /* Round to 0.1ms for nice, pretty timestamps */
++ rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
++ if (rtp->rxcore.tv_usec < 0) {
++ /* Adjust appropriately if necessary */
++ rtp->rxcore.tv_usec += 1000000;
++ rtp->rxcore.tv_sec -= 1;
++ }
++ }
++
++ gettimeofday(&now,NULL);
++ /* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
++ tv->tv_sec = rtp->rxcore.tv_sec + timestamp / 8000;
++ tv->tv_usec = rtp->rxcore.tv_usec + (timestamp % 8000) * 125;
++ if (tv->tv_usec >= 1000000) {
++ tv->tv_usec -= 1000000;
++ tv->tv_sec += 1;
++ }
++ prog = (double)((timestamp-rtp->seedrxts)/8000.);
++ dtv = (double)rtp->drxcore + (double)(prog);
++ current_time = (double)now.tv_sec + (double)now.tv_usec/1000000;
++ transit = current_time - dtv;
++ d = transit - rtp->rxtransit;
++ rtp->rxtransit = transit;
++ if (d<0)
++ d=-d;
++ rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
++
++ if (rtp->rtcp) {
++ if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
++ rtp->rtcp->maxrxjitter = rtp->rxjitter;
++ if (rtp->rtcp->rxjitter_count == 1)
++ rtp->rtcp->minrxjitter = rtp->rxjitter;
++ if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter)
++ rtp->rtcp->minrxjitter = rtp->rxjitter;
++
++ normdev_rxjitter_current = normdev_compute(rtp->rtcp->normdev_rxjitter,rtp->rxjitter,rtp->rtcp->rxjitter_count);
++ rtp->rtcp->stdev_rxjitter = stddev_compute(rtp->rtcp->stdev_rxjitter,rtp->rxjitter,rtp->rtcp->normdev_rxjitter,normdev_rxjitter_current,rtp->rtcp->rxjitter_count);
++
++ rtp->rtcp->normdev_rxjitter = normdev_rxjitter_current;
++ rtp->rtcp->rxjitter_count++;
++ }
++}
++
++static struct ast_frame *send_dtmf(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in remote_address;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ if (((compensate && type == AST_FRAME_DTMF_END) || (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
++ ast_debug(1, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(remote_address.sin_addr));
++ rtp->resp = 0;
++ rtp->dtmfsamples = 0;
++ return &ast_null_frame;
++ }
++ ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(remote_address.sin_addr));
++ if (rtp->resp == 'X') {
++ rtp->f.frametype = AST_FRAME_CONTROL;
++ rtp->f.subclass = AST_CONTROL_FLASH;
++ } else {
++ rtp->f.frametype = type;
++ rtp->f.subclass = rtp->resp;
++ }
++ rtp->f.datalen = 0;
++ rtp->f.samples = 0;
++ rtp->f.mallocd = 0;
++ rtp->f.src = "RTP";
++
++ return &rtp->f;
++}
++
++static struct ast_frame *process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in remote_address;
++ unsigned int event, event_end, samples;
++ char resp = 0;
++ struct ast_frame *f = NULL;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ /* Figure out event, event end, and samples */
++ event = ntohl(*((unsigned int *)(data)));
++ event >>= 24;
++ event_end = ntohl(*((unsigned int *)(data)));
++ event_end <<= 8;
++ event_end >>= 24;
++ samples = ntohl(*((unsigned int *)(data)));
++ samples &= 0xFFFF;
++
++ ast_verbose("Got RTP RFC2833 from %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n", ast_inet_ntoa(remote_address.sin_addr),
++ ntohs(remote_address.sin_port), payloadtype, seqno, timestamp, len, (mark?1:0), event, ((event_end & 0x80)?1:0), samples);
++
++ /* Print out debug if turned on */
++ if (rtpdebug || option_debug > 2)
++ ast_debug(0, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
++
++ /* Figure out what digit was pressed */
++ if (event < 10) {
++ resp = '0' + event;
++ } else if (event < 11) {
++ resp = '*';
++ } else if (event < 12) {
++ resp = '#';
++ } else if (event < 16) {
++ resp = 'A' + (event - 12);
++ } else if (event < 17) { /* Event 16: Hook flash */
++ resp = 'X';
++ } else {
++ /* Not a supported event */
++ ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
++ return &ast_null_frame;
++ }
++
++ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
++ if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
++ rtp->resp = resp;
++ rtp->dtmfcount = 0;
++ f = send_dtmf(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
++ f->len = 0;
++ rtp->lastevent = timestamp;
++ }
++ } else {
++ if ((!(rtp->resp) && (!(event_end & 0x80))) || (rtp->resp && rtp->resp != resp)) {
++ rtp->resp = resp;
++ f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
++ rtp->dtmfcount = dtmftimeout;
++ } else if ((event_end & 0x80) && (rtp->lastevent != seqno) && rtp->resp) {
++ f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
++ f->len = ast_tvdiff_ms(ast_samp2tv(samples, 8000), ast_tv(0, 0)); /* XXX hard coded 8kHz */
++ rtp->resp = 0;
++ rtp->dtmfcount = 0;
++ rtp->lastevent = seqno;
++ }
++ }
++
++ rtp->dtmfsamples = samples;
++
++ return f;
++}
++
++static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ unsigned int event, flags, power;
++ char resp = 0;
++ unsigned char seq;
++ struct ast_frame *f = NULL;
++
++ if (len < 4) {
++ return NULL;
++ }
++
++ /* The format of Cisco RTP DTMF packet looks like next:
++ +0 - sequence number of DTMF RTP packet (begins from 1,
++ wrapped to 0)
++ +1 - set of flags
++ +1 (bit 0) - flaps by different DTMF digits delimited by audio
++ or repeated digit without audio???
++ +2 (+4,+6,...) - power level? (rises from 0 to 32 at begin of tone
++ then falls to 0 at its end)
++ +3 (+5,+7,...) - detected DTMF digit (0..9,*,#,A-D,...)
++ Repeated DTMF information (bytes 4/5, 6/7) is history shifted right
++ by each new packet and thus provides some redudancy.
++
++ Sample of Cisco RTP DTMF packet is (all data in hex):
++ 19 07 00 02 12 02 20 02
++ showing end of DTMF digit '2'.
++
++ The packets
++ 27 07 00 02 0A 02 20 02
++ 28 06 20 02 00 02 0A 02
++ shows begin of new digit '2' with very short pause (20 ms) after
++ previous digit '2'. Bit +1.0 flips at begin of new digit.
++
++ Cisco RTP DTMF packets comes as replacement of audio RTP packets
++ so its uses the same sequencing and timestamping rules as replaced
++ audio packets. Repeat interval of DTMF packets is 20 ms and not rely
++ on audio framing parameters. Marker bit isn't used within stream of
++ DTMFs nor audio stream coming immediately after DTMF stream. Timestamps
++ are not sequential at borders between DTMF and audio streams,
++ */
++
++ seq = data[0];
++ flags = data[1];
++ power = data[2];
++ event = data[3] & 0x1f;
++
++ if (option_debug > 2 || rtpdebug)
++ ast_debug(0, "Cisco DTMF Digit: %02x (len=%d, seq=%d, flags=%02x, power=%d, history count=%d)\n", event, len, seq, flags, power, (len - 4) / 2);
++ if (event < 10) {
++ resp = '0' + event;
++ } else if (event < 11) {
++ resp = '*';
++ } else if (event < 12) {
++ resp = '#';
++ } else if (event < 16) {
++ resp = 'A' + (event - 12);
++ } else if (event < 17) {
++ resp = 'X';
++ }
++ if ((!rtp->resp && power) || (rtp->resp && (rtp->resp != resp))) {
++ rtp->resp = resp;
++ /* Why we should care on DTMF compensation at reception? */
++ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
++ f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
++ rtp->dtmfsamples = 0;
++ }
++ } else if ((rtp->resp == resp) && !power) {
++ f = send_dtmf(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
++ f->samples = rtp->dtmfsamples * 8;
++ rtp->resp = 0;
++ } else if (rtp->resp == resp)
++ rtp->dtmfsamples += 20 * 8;
++ rtp->dtmfcount = dtmftimeout;
++
++ return f;
++}
++
++static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct sockaddr_in *sin, int payloadtype, int mark)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ /* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
++ totally help us out becuase we don't have an engine to keep it going and we are not
++ guaranteed to have it every 20ms or anything */
++ if (rtpdebug)
++ ast_debug(0, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", rtp->lastrxformat, len);
++
++ if (ast_test_flag(rtp, FLAG_3389_WARNING)) {
++ struct sockaddr_in remote_address;
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s\n",
++ ast_inet_ntoa(remote_address.sin_addr));
++ ast_set_flag(rtp, FLAG_3389_WARNING);
++ }
++
++ /* Must have at least one byte */
++ if (!len)
++ return NULL;
++ if (len < 24) {
++ rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
++ rtp->f.datalen = len - 1;
++ rtp->f.offset = AST_FRIENDLY_OFFSET;
++ memcpy(rtp->f.data.ptr, data + 1, len - 1);
++ } else {
++ rtp->f.data.ptr = NULL;
++ rtp->f.offset = 0;
++ rtp->f.datalen = 0;
++ }
++ rtp->f.frametype = AST_FRAME_CNG;
++ rtp->f.subclass = data[0] & 0x7f;
++ rtp->f.datalen = len - 1;
++ rtp->f.samples = 0;
++ rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
++
++ return &rtp->f;
++}
++
++static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in sin;
++ socklen_t len = sizeof(sin);
++ unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
++ unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
++ int res, packetwords, position = 0;
++ struct ast_frame *f = &ast_null_frame;
++
++ /* Read in RTCP data from the socket */
++ if ((res = recvfrom(rtp->rtcp->s, rtcpdata + AST_FRIENDLY_OFFSET, sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET, 0, (struct sockaddr *)&sin, &len)) < 0) {
++ ast_assert(errno != EBADF);
++ if (errno != EAGAIN) {
++ ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", strerror(errno));
++ return NULL;
++ }
++ return &ast_null_frame;
++ }
++
++ packetwords = res / 4;
++
++ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
++ /* Send to whoever sent to us */
++ if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
++ (rtp->rtcp->them.sin_port != sin.sin_port)) {
++ memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
++ if (option_debug || rtpdebug)
++ ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
++ }
++ }
++
++ ast_debug(1, "Got RTCP report of %d bytes\n", res);
++
++ while (position < packetwords) {
++ int i, pt, rc;
++ unsigned int length, dlsr, lsr, msw, lsw, comp;
++ struct timeval now;
++ double rttsec, reported_jitter, reported_normdev_jitter_current, normdevrtt_current, reported_lost, reported_normdev_lost_current;
++ uint64_t rtt = 0;
++
++ i = position;
++ length = ntohl(rtcpheader[i]);
++ pt = (length & 0xff0000) >> 16;
++ rc = (length & 0x1f000000) >> 24;
++ length &= 0xffff;
++
++ if ((i + length) > packetwords) {
++ if (option_debug || rtpdebug)
++ ast_log(LOG_DEBUG, "RTCP Read too short\n");
++ return &ast_null_frame;
++ }
++
++ if (rtcp_debug_test_addr(&sin)) {
++ ast_verbose("\n\nGot RTCP from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
++ ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown");
++ ast_verbose("Reception reports: %d\n", rc);
++ ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
++ }
++
++ i += 2; /* Advance past header and ssrc */
++
++ switch (pt) {
++ case RTCP_PT_SR:
++ gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
++ rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
++ rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
++ rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
++
++ if (rtcp_debug_test_addr(&sin)) {
++ ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096);
++ ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2]));
++ ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
++ }
++ i += 5;
++ if (rc < 1)
++ break;
++ /* Intentional fall through */
++ case RTCP_PT_RR:
++ /* Don't handle multiple reception reports (rc > 1) yet */
++ /* Calculate RTT per RFC */
++ gettimeofday(&now, NULL);
++ timeval2ntp(now, &msw, &lsw);
++ if (ntohl(rtcpheader[i + 4]) && ntohl(rtcpheader[i + 5])) { /* We must have the LSR && DLSR */
++ comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
++ lsr = ntohl(rtcpheader[i + 4]);
++ dlsr = ntohl(rtcpheader[i + 5]);
++ rtt = comp - lsr - dlsr;
++
++ /* Convert end to end delay to usec (keeping the calculation in 64bit space)
++ sess->ee_delay = (eedelay * 1000) / 65536; */
++ if (rtt < 4294) {
++ rtt = (rtt * 1000000) >> 16;
++ } else {
++ rtt = (rtt * 1000) >> 16;
++ rtt *= 1000;
++ }
++ rtt = rtt / 1000.;
++ rttsec = rtt / 1000.;
++ rtp->rtcp->rtt = rttsec;
++
++ if (comp - dlsr >= lsr) {
++ rtp->rtcp->accumulated_transit += rttsec;
++
++ if (rtp->rtcp->rtt_count == 0)
++ rtp->rtcp->minrtt = rttsec;
++
++ if (rtp->rtcp->maxrtt<rttsec)
++ rtp->rtcp->maxrtt = rttsec;
++ if (rtp->rtcp->minrtt>rttsec)
++ rtp->rtcp->minrtt = rttsec;
++
++ normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);
++
++ rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);
++
++ rtp->rtcp->normdevrtt = normdevrtt_current;
++
++ rtp->rtcp->rtt_count++;
++ } else if (rtcp_debug_test_addr(&sin)) {
++ ast_verbose("Internal RTCP NTP clock skew detected: "
++ "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
++ "diff=%d\n",
++ lsr, comp, dlsr, dlsr / 65536,
++ (dlsr % 65536) * 1000 / 65536,
++ dlsr - (comp - lsr));
++ }
++ }
++
++ rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
++ reported_jitter = (double) rtp->rtcp->reported_jitter;
++
++ if (rtp->rtcp->reported_jitter_count == 0)
++ rtp->rtcp->reported_minjitter = reported_jitter;
++
++ if (reported_jitter < rtp->rtcp->reported_minjitter)
++ rtp->rtcp->reported_minjitter = reported_jitter;
++
++ if (reported_jitter > rtp->rtcp->reported_maxjitter)
++ rtp->rtcp->reported_maxjitter = reported_jitter;
++
++ reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
++
++ rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
++
++ rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
++
++ rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
++
++ reported_lost = (double) rtp->rtcp->reported_lost;
++
++ /* using same counter as for jitter */
++ if (rtp->rtcp->reported_jitter_count == 0)
++ rtp->rtcp->reported_minlost = reported_lost;
++
++ if (reported_lost < rtp->rtcp->reported_minlost)
++ rtp->rtcp->reported_minlost = reported_lost;
++
++ if (reported_lost > rtp->rtcp->reported_maxlost)
++ rtp->rtcp->reported_maxlost = reported_lost;
++ reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
++
++ rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
++
++ rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
++
++ rtp->rtcp->reported_jitter_count++;
++
++ if (rtcp_debug_test_addr(&sin)) {
++ ast_verbose(" Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
++ ast_verbose(" Packets lost so far: %d\n", rtp->rtcp->reported_lost);
++ ast_verbose(" Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
++ ast_verbose(" Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16);
++ ast_verbose(" Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
++ ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
++ ast_verbose(" DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
++ if (rtt)
++ ast_verbose(" RTT: %lu(sec)\n", (unsigned long) rtt);
++ }
++ if (rtt) {
++ manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s:%d\r\n"
++ "PT: %d(%s)\r\n"
++ "ReceptionReports: %d\r\n"
++ "SenderSSRC: %u\r\n"
++ "FractionLost: %ld\r\n"
++ "PacketsLost: %d\r\n"
++ "HighestSequence: %ld\r\n"
++ "SequenceNumberCycles: %ld\r\n"
++ "IAJitter: %u\r\n"
++ "LastSR: %lu.%010lu\r\n"
++ "DLSR: %4.4f(sec)\r\n"
++ "RTT: %llu(sec)\r\n",
++ ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port),
++ pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
++ rc,
++ rtcpheader[i + 1],
++ (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
++ rtp->rtcp->reported_lost,
++ (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
++ (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16,
++ rtp->rtcp->reported_jitter,
++ (unsigned long) ntohl(rtcpheader[i + 4]) >> 16, ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
++ ntohl(rtcpheader[i + 5])/65536.0,
++ (unsigned long long)rtt);
++ } else {
++ manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From %s:%d\r\n"
++ "PT: %d(%s)\r\n"
++ "ReceptionReports: %d\r\n"
++ "SenderSSRC: %u\r\n"
++ "FractionLost: %ld\r\n"
++ "PacketsLost: %d\r\n"
++ "HighestSequence: %ld\r\n"
++ "SequenceNumberCycles: %ld\r\n"
++ "IAJitter: %u\r\n"
++ "LastSR: %lu.%010lu\r\n"
++ "DLSR: %4.4f(sec)\r\n",
++ ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port),
++ pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
++ rc,
++ rtcpheader[i + 1],
++ (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
++ rtp->rtcp->reported_lost,
++ (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
++ (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16,
++ rtp->rtcp->reported_jitter,
++ (unsigned long) ntohl(rtcpheader[i + 4]) >> 16,
++ ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
++ ntohl(rtcpheader[i + 5])/65536.0);
++ }
++ break;
++ case RTCP_PT_FUR:
++ if (rtcp_debug_test_addr(&sin))
++ ast_verbose("Received an RTCP Fast Update Request\n");
++ rtp->f.frametype = AST_FRAME_CONTROL;
++ rtp->f.subclass = AST_CONTROL_VIDUPDATE;
++ rtp->f.datalen = 0;
++ rtp->f.samples = 0;
++ rtp->f.mallocd = 0;
++ rtp->f.src = "RTP";
++ f = &rtp->f;
++ break;
++ case RTCP_PT_SDES:
++ if (rtcp_debug_test_addr(&sin))
++ ast_verbose("Received an SDES from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
++ break;
++ case RTCP_PT_BYE:
++ if (rtcp_debug_test_addr(&sin))
++ ast_verbose("Received a BYE from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
++ break;
++ default:
++ ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s:%d\n", pt, ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
++ break;
++ }
++ position += (length + 1);
++ }
++
++ rtp->rtcp->rtcp_info = 1;
++
++ return f;
++}
++
++static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen)
++{
++ struct ast_rtp_instance *instance1 = ast_rtp_instance_get_bridged(instance);
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance), *bridged = ast_rtp_instance_get_data(instance1);
++ int res = 0, payload = 0, bridged_payload = 0, mark;
++ struct ast_rtp_payload_type payload_type;
++ int reconstruct = ntohl(rtpheader[0]);
++ struct sockaddr_in remote_address;
++
++ /* Get fields from packet */
++ payload = (reconstruct & 0x7f0000) >> 16;
++ mark = (((reconstruct & 0x800000) >> 23) != 0);
++
++ /* Check what the payload value should be */
++ payload_type = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payload);
++
++ /* Otherwise adjust bridged payload to match */
++ bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type.asterisk_format, payload_type.code);
++
++ /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */
++ if (!(ast_rtp_instance_get_codecs(instance1)->payloads[bridged_payload].code)) {
++ return -1;
++ }
++
++ /* If the marker bit has been explicitly set turn it on */
++ if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) {
++ mark = 1;
++ ast_clear_flag(rtp, FLAG_NEED_MARKER_BIT);
++ }
++
++ /* Reconstruct part of the packet */
++ reconstruct &= 0xFF80FFFF;
++ reconstruct |= (bridged_payload << 16);
++ reconstruct |= (mark << 23);
++ rtpheader[0] = htonl(reconstruct);
++
++ ast_rtp_instance_get_remote_address(instance1, &remote_address);
++
++ /* Send the packet back out */
++ res = sendto(bridged->s, (void *)rtpheader, len, 0, (struct sockaddr *)&remote_address, sizeof(remote_address));
++ if (res < 0) {
++ if (!ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_NAT) && (ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
++ ast_debug(1, "RTP Transmission error of packet to %s:%d: %s\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), strerror(errno));
++ } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
++ if (option_debug || rtpdebug)
++ ast_debug(0, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port));
++ ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN);
++ }
++ return 0;
++ } else if (rtp_debug_test_addr(&remote_address)) {
++ ast_verbose("Sent RTP P2P packet to %s:%u (type %-2.2d, len %-6.6u)\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), bridged_payload, len - hdrlen);
++ }
++
++ return 0;
++}
++
++static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in sin;
++ socklen_t len = sizeof(sin);
++ int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;
++ unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp;
++ struct ast_rtp_payload_type payload;
++ struct sockaddr_in remote_address;
++
++ /* If this is actually RTCP let's hop on over and handle it */
++ if (rtcp) {
++ if (rtp->rtcp) {
++ return ast_rtcp_read(instance);
++ }
++ return &ast_null_frame;
++ }
++
++ /* If we are currently sending DTMF to the remote party send a continuation packet */
++ if (rtp->sending_digit) {
++ ast_rtp_dtmf_continuation(instance);
++ }
++
++ /* Actually read in the data from the socket */
++ if ((res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0, (struct sockaddr*)&sin, &len)) < 0) {
++ ast_assert(errno != EBADF);
++ if (errno != EAGAIN) {
++ ast_log(LOG_WARNING, "RTP Read error: %s. Hanging up.\n", strerror(errno));
++ return NULL;
++ }
++ return &ast_null_frame;
++ }
++
++ /* Make sure the data that was read in is actually enough to make up an RTP packet */
++ if (res < hdrlen) {
++ ast_log(LOG_WARNING, "RTP Read too short\n");
++ return &ast_null_frame;
++ }
++
++ /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */
++ if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
++ memcpy(&rtp->strict_rtp_address, &sin, sizeof(rtp->strict_rtp_address));
++ rtp->strict_rtp_state = STRICT_RTP_CLOSED;
++ } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
++ if ((rtp->strict_rtp_address.sin_addr.s_addr != sin.sin_addr.s_addr) || (rtp->strict_rtp_address.sin_port != sin.sin_port)) {
++ ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
++ return &ast_null_frame;
++ }
++ }
++
++ /* Get fields and verify this is an RTP packet */
++ seqno = ntohl(rtpheader[0]);
++
++ ast_rtp_instance_get_remote_address(instance, &remote_address);
++
++ if (!(version = (seqno & 0xC0000000) >> 30)) {
++ if ((ast_stun_handle_packet(rtp->s, &sin, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) &&
++ (!remote_address.sin_port && !remote_address.sin_addr.s_addr)) {
++ ast_rtp_instance_set_remote_address(instance, &sin);
++ }
++ return &ast_null_frame;
++ }
++
++ /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */
++ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
++ if ((remote_address.sin_addr.s_addr != sin.sin_addr.s_addr) ||
++ (remote_address.sin_port != sin.sin_port)) {
++ ast_rtp_instance_set_remote_address(instance, &sin);
++ memcpy(&remote_address, &sin, sizeof(remote_address));
++ if (rtp->rtcp) {
++ memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
++ rtp->rtcp->them.sin_port = htons(ntohs(sin.sin_port)+1);
++ }
++ rtp->rxseqno = 0;
++ ast_set_flag(rtp, FLAG_NAT_ACTIVE);
++ if (option_debug || rtpdebug)
++ ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s:%d\n", ast_inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port));
++ }
++ }
++
++ /* If we are directly bridged to another instance send the audio directly out */
++ if (ast_rtp_instance_get_bridged(instance) && !bridge_p2p_rtp_write(instance, rtpheader, res, hdrlen)) {
++ return &ast_null_frame;
++ }
++
++ /* If the version is not what we expected by this point then just drop the packet */
++ if (version != 2) {
++ return &ast_null_frame;
++ }
++
++ /* Pull out the various other fields we will need */
++ payloadtype = (seqno & 0x7f0000) >> 16;
++ padding = seqno & (1 << 29);
++ mark = seqno & (1 << 23);
++ ext = seqno & (1 << 28);
++ cc = (seqno & 0xF000000) >> 24;
++ seqno &= 0xffff;
++ timestamp = ntohl(rtpheader[1]);
++ ssrc = ntohl(rtpheader[2]);
++
++ /* Force a marker bit if the SSRC changes */
++ if (!mark && rtp->rxssrc && rtp->rxssrc != ssrc) {
++ if (option_debug || rtpdebug) {
++ ast_debug(1, "Forcing Marker bit, because SSRC has changed\n");
++ }
++ mark = 1;
++ }
++
++ /* Remove any padding bytes that may be present */
++ if (padding) {
++ res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
++ }
++
++ /* Skip over any CSRC fields */
++ if (cc) {
++ hdrlen += cc * 4;
++ }
++
++ /* Look for any RTP extensions, currently we do not support any */
++ if (ext) {
++ hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;
++ hdrlen += 4;
++ if (option_debug) {
++ int profile;
++ profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;
++ if (profile == 0x505a)
++ ast_debug(1, "Found Zfone extension in RTP stream - zrtp - not supported.\n");
++ else
++ ast_debug(1, "Found unknown RTP Extensions %x\n", profile);
++ }
++ }
++
++ /* Make sure after we potentially mucked with the header length that it is once again valid */
++ if (res < hdrlen) {
++ ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen);
++ return &ast_null_frame;
++ }
++
++ rtp->rxcount++;
++ if (rtp->rxcount == 1) {
++ rtp->seedrxseqno = seqno;
++ }
++
++ /* Do not schedule RR if RTCP isn't run */
++ if (rtp->rtcp && rtp->rtcp->them.sin_addr.s_addr && rtp->rtcp->schedid < 1) {
++ /* Schedule transmission of Receiver Report */
++ rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
++ }
++ if ((int)rtp->lastrxseqno - (int)seqno > 100) /* if so it would indicate that the sender cycled; allow for misordering */
++ rtp->cycles += RTP_SEQ_MOD;
++
++ prev_seqno = rtp->lastrxseqno;
++ rtp->lastrxseqno = seqno;
++
++ if (!rtp->themssrc) {
++ rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
++ }
++
++ if (rtp_debug_test_addr(&sin)) {
++ ast_verbose("Got RTP packet from %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
++ ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
++ }
++
++ payload = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payloadtype);
++
++ /* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */
++ if (!payload.asterisk_format) {
++ struct ast_frame *f = NULL;
++
++ if (payload.code == AST_RTP_DTMF) {
++ f = process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
++ } else if (payload.code == AST_RTP_CISCO_DTMF) {
++ f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
++ } else if (payload.code == AST_RTP_CN) {
++ f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &sin, payloadtype, mark);
++ } else {
++ ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(remote_address.sin_addr));
++ }
++
++ return f ? f : &ast_null_frame;
++ }
++
++ rtp->lastrxformat = rtp->f.subclass = payload.code;
++ rtp->f.frametype = (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) ? AST_FRAME_VOICE : (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
++
++ rtp->rxseqno = seqno;
++ rtp->lastrxts = timestamp;
++
++ rtp->f.src = "RTP";
++ rtp->f.mallocd = 0;
++ rtp->f.datalen = res - hdrlen;
++ rtp->f.data.ptr = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
++ rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
++ rtp->f.seqno = seqno;
++
++ if (rtp->f.subclass == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) {
++ unsigned char *data = rtp->f.data.ptr;
++
++ memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
++ rtp->f.datalen +=3;
++ *data++ = 0xEF;
++ *data++ = 0xBF;
++ *data = 0xBD;
++ }
++
++ if (rtp->f.subclass == AST_FORMAT_T140RED) {
++ unsigned char *data = rtp->f.data.ptr;
++ unsigned char *header_end;
++ int num_generations;
++ int header_length;
++ int len;
++ int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
++ int x;
++
++ rtp->f.subclass = AST_FORMAT_T140;
++ header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
++ header_end++;
++
++ header_length = header_end - data;
++ num_generations = header_length / 4;
++ len = header_length;
++
++ if (!diff) {
++ for (x = 0; x < num_generations; x++)
++ len += data[x * 4 + 3];
++
++ if (!(rtp->f.datalen - len))
++ return &ast_null_frame;
++
++ rtp->f.data.ptr += len;
++ rtp->f.datalen -= len;
++ } else if (diff > num_generations && diff < 10) {
++ len -= 3;
++ rtp->f.data.ptr += len;
++ rtp->f.datalen -= len;
++
++ data = rtp->f.data.ptr;
++ *data++ = 0xEF;
++ *data++ = 0xBF;
++ *data = 0xBD;
++ } else {
++ for ( x = 0; x < num_generations - diff; x++)
++ len += data[x * 4 + 3];
++
++ rtp->f.data.ptr += len;
++ rtp->f.datalen -= len;
++ }
++ }
++
++ if (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) {
++ rtp->f.samples = ast_codec_get_samples(&rtp->f);
++ if (rtp->f.subclass == AST_FORMAT_SLINEAR)
++ ast_frame_byteswap_be(&rtp->f);
++ calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
++ /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
++ ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
++ rtp->f.ts = timestamp / 8;
++ rtp->f.len = rtp->f.samples / ((ast_format_rate(rtp->f.subclass) / 1000));
++ } else if (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
++ /* Video -- samples is # of samples vs. 90000 */
++ if (!rtp->lastividtimestamp)
++ rtp->lastividtimestamp = timestamp;
++ rtp->f.samples = timestamp - rtp->lastividtimestamp;
++ rtp->lastividtimestamp = timestamp;
++ rtp->f.delivery.tv_sec = 0;
++ rtp->f.delivery.tv_usec = 0;
++ /* Pass the RTP marker bit as bit 0 in the subclass field.
++ * This is ok because subclass is actually a bitmask, and
++ * the low bits represent audio formats, that are not
++ * involved here since we deal with video.
++ */
++ if (mark)
++ rtp->f.subclass |= 0x1;
++ } else {
++ /* TEXT -- samples is # of samples vs. 1000 */
++ if (!rtp->lastitexttimestamp)
++ rtp->lastitexttimestamp = timestamp;
++ rtp->f.samples = timestamp - rtp->lastitexttimestamp;
++ rtp->lastitexttimestamp = timestamp;
++ rtp->f.delivery.tv_sec = 0;
++ rtp->f.delivery.tv_usec = 0;
++ }
++
++ return &rtp->f;
++}
++
++static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ if (property == AST_RTP_PROPERTY_RTCP) {
++ if (rtp->rtcp) {
++ ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance);
++ return;
++ }
++ if (!(rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp)))) {
++ return;
++ }
++ if ((rtp->rtcp->s = create_new_socket("RTCP")) < 0) {
++ ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance);
++ ast_free(rtp->rtcp);
++ rtp->rtcp = NULL;
++ return;
++ }
++
++ /* Grab the IP address and port we are going to use */
++ ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us);
++ rtp->rtcp->us.sin_port = htons(ntohs(rtp->rtcp->us.sin_port) + 1);
++
++ /* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */
++ if (bind(rtp->rtcp->s, (struct sockaddr*)&rtp->rtcp->us, sizeof(rtp->rtcp->us))) {
++ ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance);
++ close(rtp->rtcp->s);
++ ast_free(rtp->rtcp);
++ rtp->rtcp = NULL;
++ return;
++ }
++
++ ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance);
++ rtp->rtcp->schedid = -1;
++
++ return;
++ }
++
++ return;
++}
++
++static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ return rtcp ? (rtp->rtcp ? rtp->rtcp->s : -1) : rtp->s;
++}
++
++static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ if (rtp->rtcp) {
++ ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
++ memcpy(&rtp->rtcp->them, sin, sizeof(rtp->rtcp->them));
++ rtp->rtcp->them.sin_port = htons(ntohs(sin->sin_port) + 1);
++ }
++
++ rtp->rxseqno = 0;
++
++ if (strictrtp) {
++ rtp->strict_rtp_state = STRICT_RTP_LEARN;
++ }
++
++ return;
++}
++
++/*! \brief Write t140 redundacy frame
++ * \param data primary data to be buffered
++ */
++static int red_write(const void *data)
++{
++ struct ast_rtp_instance *instance = (struct ast_rtp_instance*) data;
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ ast_rtp_write(instance, &rtp->red->t140);
++
++ return 1;
++}
++
++static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ int x;
++
++ if (!(rtp->red = ast_calloc(1, sizeof(*rtp->red)))) {
++ return -1;
++ }
++
++ rtp->red->t140.frametype = AST_FRAME_TEXT;
++ rtp->red->t140.subclass = AST_FORMAT_T140RED;
++ rtp->red->t140.data.ptr = &rtp->red->buf_data;
++
++ rtp->red->t140.ts = 0;
++ rtp->red->t140red = rtp->red->t140;
++ rtp->red->t140red.data.ptr = &rtp->red->t140red_data;
++ rtp->red->t140red.datalen = 0;
++ rtp->red->ti = buffer_time;
++ rtp->red->num_gen = generations;
++ rtp->red->hdrlen = generations * 4 + 1;
++ rtp->red->prev_ts = 0;
++
++ for (x = 0; x < generations; x++) {
++ rtp->red->pt[x] = payloads[x];
++ rtp->red->pt[x] |= 1 << 7; /* mark redundant generations pt */
++ rtp->red->t140red_data[x*4] = rtp->red->pt[x];
++ }
++ rtp->red->t140red_data[x*4] = rtp->red->pt[x] = payloads[x]; /* primary pt */
++ rtp->red->schedid = ast_sched_add(rtp->sched, generations, red_write, instance);
++
++ rtp->red->t140.datalen = 0;
++
++ return 0;
++}
++
++static int rtp_red_buffer(struct ast_rtp_instance *instance, struct ast_frame *frame)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ if (frame->datalen > -1) {
++ struct rtp_red *red = rtp->red;
++ memcpy(&red->buf_data[red->t140.datalen], frame->data.ptr, frame->datalen);
++ red->t140.datalen += frame->datalen;
++ red->t140.ts = frame->ts;
++ }
++
++ return 0;
++}
++
++static int ast_rtp_local_bridge(struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance0);
++
++ ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
++
++ return 0;
++}
++
++static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ if (!rtp->rtcp) {
++ return -1;
++ }
++
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXCOUNT, -1, stats->txcount, rtp->txcount);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXCOUNT, -1, stats->rxcount, rtp->rxcount);
++
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->txploss, rtp->rtcp->reported_lost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->rxploss, rtp->rtcp->expected_prior - rtp->rtcp->received_prior);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_maxrxploss, rtp->rtcp->reported_maxlost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_minrxploss, rtp->rtcp->reported_minlost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_normdevrxploss, rtp->rtcp->reported_normdev_lost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_STDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_stdevrxploss, rtp->rtcp->reported_stdev_lost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MAXRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_maxrxploss, rtp->rtcp->maxrxlost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MINRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_minrxploss, rtp->rtcp->minrxlost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_normdevrxploss, rtp->rtcp->normdev_rxlost);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_stdevrxploss, rtp->rtcp->stdev_rxlost);
++ AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_LOSS);
++
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->txjitter, rtp->rxjitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->rxjitter, rtp->rtcp->reported_jitter / (unsigned int) 65536.0);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_maxjitter, rtp->rtcp->reported_maxjitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_minjitter, rtp->rtcp->reported_minjitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_normdevjitter, rtp->rtcp->reported_normdev_jitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_STDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_stdevjitter, rtp->rtcp->reported_stdev_jitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MAXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_maxjitter, rtp->rtcp->maxrxjitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MINJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_minjitter, rtp->rtcp->minrxjitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_normdevjitter, rtp->rtcp->normdev_rxjitter);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_stdevjitter, rtp->rtcp->stdev_rxjitter);
++ AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_JITTER);
++
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->rtt, rtp->rtcp->rtt);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_MAX_RTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->maxrtt, rtp->rtcp->maxrtt);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_MIN_RTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->minrtt, rtp->rtcp->minrtt);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_NORMDEVRTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->normdevrtt, rtp->rtcp->normdevrtt);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_STDEVRTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->stdevrtt, rtp->rtcp->stdevrtt);
++ AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_RTT);
++
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_SSRC, -1, stats->local_ssrc, rtp->ssrc);
++ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_SSRC, -1, stats->remote_ssrc, rtp->themssrc);
++
++ return 0;
++}
++
++static int ast_rtp_dtmf_compatible(struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1)
++{
++ /* If both sides are not using the same method of DTMF transmission
++ * (ie: one is RFC2833, other is INFO... then we can not do direct media.
++ * --------------------------------------------------
++ * | DTMF Mode | HAS_DTMF | Accepts Begin Frames |
++ * |-----------|------------|-----------------------|
++ * | Inband | False | True |
++ * | RFC2833 | True | True |
++ * | SIP INFO | False | False |
++ * --------------------------------------------------
++ */
++ return (((ast_rtp_instance_get_prop(instance0, AST_RTP_PROPERTY_DTMF) != ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_DTMF)) ||
++ (!chan0->tech->send_digit_begin != !chan1->tech->send_digit_begin)) ? 0 : 1);
++}
++
++static void ast_rtp_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ ast_stun_request(rtp->s, suggestion, username, NULL);
++}
++
++static void ast_rtp_stop(struct ast_rtp_instance *instance)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++ struct sockaddr_in sin = { 0, };
++
++ if (rtp->rtcp) {
++ AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
++ }
++ if (rtp->red) {
++ AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
++ free(rtp->red);
++ rtp->red = NULL;
++ }
++
++ ast_rtp_instance_set_remote_address(instance, &sin);
++ if (rtp->rtcp) {
++ memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->rtcp->them.sin_addr));
++ memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->rtcp->them.sin_port));
++ }
++
++ ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
++}
++
++static char *rtp_do_debug_ip(struct ast_cli_args *a)
++{
++ struct hostent *hp;
++ struct ast_hostent ahp;
++ int port = 0;
++ char *p, *arg;
++
++ arg = a->argv[3];
++ p = strstr(arg, ":");
++ if (p) {
++ *p = '\0';
++ p++;
++ port = atoi(p);
++ }
++ hp = ast_gethostbyname(arg, &ahp);
++ if (hp == NULL) {
++ ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
++ return CLI_FAILURE;
++ }
++ rtpdebugaddr.sin_family = AF_INET;
++ memcpy(&rtpdebugaddr.sin_addr, hp->h_addr, sizeof(rtpdebugaddr.sin_addr));
++ rtpdebugaddr.sin_port = htons(port);
++ if (port == 0)
++ ast_cli(a->fd, "RTP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtpdebugaddr.sin_addr));
++ else
++ ast_cli(a->fd, "RTP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtpdebugaddr.sin_addr), port);
++ rtpdebug = 1;
++ return CLI_SUCCESS;
++}
++
++static char *rtcp_do_debug_ip(struct ast_cli_args *a)
++{
++ struct hostent *hp;
++ struct ast_hostent ahp;
++ int port = 0;
++ char *p, *arg;
++
++ arg = a->argv[3];
++ p = strstr(arg, ":");
++ if (p) {
++ *p = '\0';
++ p++;
++ port = atoi(p);
++ }
++ hp = ast_gethostbyname(arg, &ahp);
++ if (hp == NULL) {
++ ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
++ return CLI_FAILURE;
++ }
++ rtcpdebugaddr.sin_family = AF_INET;
++ memcpy(&rtcpdebugaddr.sin_addr, hp->h_addr, sizeof(rtcpdebugaddr.sin_addr));
++ rtcpdebugaddr.sin_port = htons(port);
++ if (port == 0)
++ ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr));
++ else
++ ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr), port);
++ rtcpdebug = 1;
++ return CLI_SUCCESS;
++}
++
++static char *handle_cli_rtp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "rtp set debug {on|off|ip}";
++ e->usage =
++ "Usage: rtp set debug {on|off|ip host[:port]}\n"
++ " Enable/Disable dumping of all RTP packets. If 'ip' is\n"
++ " specified, limit the dumped packets to those to and from\n"
++ " the specified 'host' with optional port.\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ if (a->argc == e->args) { /* set on or off */
++ if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
++ rtpdebug = 1;
++ memset(&rtpdebugaddr, 0, sizeof(rtpdebugaddr));
++ ast_cli(a->fd, "RTP Debugging Enabled\n");
++ return CLI_SUCCESS;
++ } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
++ rtpdebug = 0;
++ ast_cli(a->fd, "RTP Debugging Disabled\n");
++ return CLI_SUCCESS;
++ }
++ } else if (a->argc == e->args +1) { /* ip */
++ return rtp_do_debug_ip(a);
++ }
++
++ return CLI_SHOWUSAGE; /* default, failure */
++}
++
++static char *handle_cli_rtcp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "rtcp set debug {on|off|ip}";
++ e->usage =
++ "Usage: rtcp set debug {on|off|ip host[:port]}\n"
++ " Enable/Disable dumping of all RTCP packets. If 'ip' is\n"
++ " specified, limit the dumped packets to those to and from\n"
++ " the specified 'host' with optional port.\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ if (a->argc == e->args) { /* set on or off */
++ if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
++ rtcpdebug = 1;
++ memset(&rtcpdebugaddr, 0, sizeof(rtcpdebugaddr));
++ ast_cli(a->fd, "RTCP Debugging Enabled\n");
++ return CLI_SUCCESS;
++ } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
++ rtcpdebug = 0;
++ ast_cli(a->fd, "RTCP Debugging Disabled\n");
++ return CLI_SUCCESS;
++ }
++ } else if (a->argc == e->args +1) { /* ip */
++ return rtcp_do_debug_ip(a);
++ }
++
++ return CLI_SHOWUSAGE; /* default, failure */
++}
++
++static char *handle_cli_rtcp_set_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "rtcp set stats {on|off}";
++ e->usage =
++ "Usage: rtcp set stats {on|off}\n"
++ " Enable/Disable dumping of RTCP stats.\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ if (a->argc != e->args)
++ return CLI_SHOWUSAGE;
++
++ if (!strncasecmp(a->argv[e->args-1], "on", 2))
++ rtcpstats = 1;
++ else if (!strncasecmp(a->argv[e->args-1], "off", 3))
++ rtcpstats = 0;
++ else
++ return CLI_SHOWUSAGE;
++
++ ast_cli(a->fd, "RTCP Stats %s\n", rtcpstats ? "Enabled" : "Disabled");
++ return CLI_SUCCESS;
++}
++
++static struct ast_cli_entry cli_rtp[] = {
++ AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging"),
++ AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging"),
++ AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"),
++};
++
++static int rtp_reload(int reload)
++{
++ struct ast_config *cfg;
++ const char *s;
++ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
++
++ cfg = ast_config_load2("rtp.conf", "rtp", config_flags);
++ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
++ return 0;
++ }
++
++ rtpstart = DEFAULT_RTP_START;
++ rtpend = DEFAULT_RTP_END;
++ dtmftimeout = DEFAULT_DTMF_TIMEOUT;
++ strictrtp = STRICT_RTP_OPEN;
++ if (cfg) {
++ if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
++ rtpstart = atoi(s);
++ if (rtpstart < MINIMUM_RTP_PORT)
++ rtpstart = MINIMUM_RTP_PORT;
++ if (rtpstart > MAXIMUM_RTP_PORT)
++ rtpstart = MAXIMUM_RTP_PORT;
++ }
++ if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
++ rtpend = atoi(s);
++ if (rtpend < MINIMUM_RTP_PORT)
++ rtpend = MINIMUM_RTP_PORT;
++ if (rtpend > MAXIMUM_RTP_PORT)
++ rtpend = MAXIMUM_RTP_PORT;
++ }
++ if ((s = ast_variable_retrieve(cfg, "general", "rtcpinterval"))) {
++ rtcpinterval = atoi(s);
++ if (rtcpinterval == 0)
++ rtcpinterval = 0; /* Just so we're clear... it's zero */
++ if (rtcpinterval < RTCP_MIN_INTERVALMS)
++ rtcpinterval = RTCP_MIN_INTERVALMS; /* This catches negative numbers too */
++ if (rtcpinterval > RTCP_MAX_INTERVALMS)
++ rtcpinterval = RTCP_MAX_INTERVALMS;
++ }
++ if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
++#ifdef SO_NO_CHECK
++ nochecksums = ast_false(s) ? 1 : 0;
++#else
++ if (ast_false(s))
++ ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
++#endif
++ }
++ if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
++ dtmftimeout = atoi(s);
++ if ((dtmftimeout < 0) || (dtmftimeout > 20000)) {
++ ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
++ dtmftimeout, DEFAULT_DTMF_TIMEOUT);
++ dtmftimeout = DEFAULT_DTMF_TIMEOUT;
++ };
++ }
++ if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
++ strictrtp = ast_true(s);
++ }
++ ast_config_destroy(cfg);
++ }
++ if (rtpstart >= rtpend) {
++ ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
++ rtpstart = DEFAULT_RTP_START;
++ rtpend = DEFAULT_RTP_END;
++ }
++ ast_verb(2, "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
++ return 0;
++}
++
++static int reload_module(void)
++{
++ rtp_reload(1);
++ return 0;
++}
++
++static int load_module(void)
++{
++ if (ast_rtp_engine_register(&asterisk_rtp_engine)) {
++ return AST_MODULE_LOAD_DECLINE;
++ }
++
++ if (ast_cli_register_multiple(cli_rtp, ARRAY_LEN(cli_rtp))) {
++ ast_rtp_engine_unregister(&asterisk_rtp_engine);
++ return AST_MODULE_LOAD_DECLINE;
++ }
++
++ rtp_reload(0);
++
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ ast_rtp_engine_unregister(&asterisk_rtp_engine);
++ ast_cli_unregister_multiple(cli_rtp, ARRAY_LEN(cli_rtp));
++
++ return 0;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk RTP Stack",
++ .load = load_module,
++ .unload = unload_module,
++ .reload = reload_module,
++ );
+
+Property changes on: res/res_rtp_asterisk.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_config_pgsql.c
+===================================================================
+--- a/res/res_config_pgsql.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_config_pgsql.c (.../trunk) (revision 186562)
+@@ -1530,7 +1530,7 @@
+ }
+
+ /* needs usecount semantics defined */
+-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PostgreSQL RealTime Configuration Driver",
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PostgreSQL RealTime Configuration Driver",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload
+Index: res/res_smdi.exports
+===================================================================
+--- a/res/res_smdi.exports (.../tags/1.6.2.0-beta1) (revision 0)
++++ b/res/res_smdi.exports (.../trunk) (revision 186562)
+@@ -0,0 +1,18 @@
++{
++ global:
++ ast_smdi_interface_find;
++ ast_smdi_interface_unref;
++ ast_smdi_md_message_destroy;
++ ast_smdi_md_message_pop;
++ ast_smdi_md_message_putback;
++ ast_smdi_md_message_wait;
++ ast_smdi_mwi_message_destroy;
++ ast_smdi_mwi_message_pop;
++ ast_smdi_mwi_message_putback;
++ ast_smdi_mwi_message_wait;
++ ast_smdi_mwi_message_wait_station;
++ ast_smdi_mwi_set;
++ ast_smdi_mwi_unset;
++ local:
++ *;
++};
+
+Property changes on: res/res_smdi.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_phoneprov.c
+===================================================================
+--- a/res/res_phoneprov.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/res/res_phoneprov.c (.../trunk) (revision 186562)
+@@ -1305,7 +1305,7 @@
+ return 0;
+ }
+
+-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "HTTP Phone Provisioning",
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP Phone Provisioning",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+Index: utils/Makefile
+===================================================================
+--- a/utils/Makefile (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/utils/Makefile (.../trunk) (revision 186562)
+@@ -163,6 +163,11 @@
+ $(CMD_PREFIX) cp "$<" "$@"
+ utils.o: ASTCFLAGS+=-DSTANDALONE
+
++poll.c: $(ASTTOPDIR)/main/poll.c
++ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
++ $(CMD_PREFIX) cp "$<" "$@"
++poll.o: ASTCFLAGS+=-DSTANDALONE
++
+ strings.c: $(ASTTOPDIR)/main/strings.c
+ $(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
+ $(CMD_PREFIX) cp "$<" "$@"
+@@ -179,12 +184,12 @@
+ threadstorage.o: ASTCFLAGS+=-DSTANDALONE
+
+ hashtest2.o: ASTCFLAGS+=-O0 -DSTANDALONE
+-hashtest2: hashtest2.o md5.o utils.o strings.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o
++hashtest2: hashtest2.o md5.o utils.o strings.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o poll.o
+
+-hashtest: hashtest.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o
++hashtest: hashtest.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o poll.o
+ hashtest.o: ASTCFLAGS+=-O0 -DSTANDALONE
+
+-refcounter: refcounter.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o
++refcounter: refcounter.o md5.o hashtab.o utils.o strings.o sha1.o strcompat.o threadstorage.o clicompat.o poll.o
+ refcounter.o: ASTCFLAGS+=-O0 -DSTANDALONE
+
+ extconf.o: extconf.c
+
+Property changes on: utils
+___________________________________________________________________
+Modified: svn:ignore
+ - *.d
+*.i
+*.s
+aelbison.c
+aelparse
+aelparse.c
+ast_expr2.c
+ast_expr2f.c
+astman
+astobj2.c
+check_expr
+conf2ael
+hashtab.c
+hashtest
+hashtest2
+md5.c
+muted
+pbx_ael.c
+pval.c
+sha1.c
+smsq
+stereorize
+strcompat.c
+streamplayer
+strings.c
+threadstorage.c
+utils.c
+astcanary
+refcounter
+
+ + *.d
+*.i
+*.s
+aelbison.c
+aelparse
+aelparse.c
+ast_expr2.c
+ast_expr2f.c
+astman
+astobj2.c
+check_expr
+conf2ael
+hashtab.c
+hashtest
+hashtest2
+md5.c
+muted
+pbx_ael.c
+pval.c
+poll.c
+sha1.c
+smsq
+stereorize
+strcompat.c
+streamplayer
+strings.c
+threadstorage.c
+utils.c
+astcanary
+refcounter
+
+
+Index: Makefile.rules
+===================================================================
+--- a/Makefile.rules (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/Makefile.rules (.../trunk) (revision 186562)
+@@ -51,8 +51,13 @@
+ # per-target settings will be applied
+ CC_CFLAGS=$(PTHREAD_CFLAGS) $(ASTCFLAGS)
+ CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(ASTCFLAGS))
+-CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
+-CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
++
++ifeq ($(GNU_LD),1)
++SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(if $(wildcard $(subst .so,.exports,$@)),$(subst .so,.exports,$@),$(ASTTOPDIR)/default.exports)
++endif
++
++CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS)
++CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS)
+ CC_LIBS=$(PTHREAD_LIBS) $(LIBS)
+ CXX_LIBS=$(PTHREAD_LIBS) $(LIBS)
+
+Index: cdr/cdr_radius.c
+===================================================================
+--- a/cdr/cdr_radius.c (.../tags/1.6.2.0-beta1) (revision 186562)
++++ b/cdr/cdr_radius.c (.../trunk) (revision 186562)
+@@ -205,13 +205,19 @@
+
+ if (build_radius_record(&tosend, cdr)) {
+ ast_debug(1, "Unable to create RADIUS record. CDR not recorded!\n");
+- return result;
++ goto return_cleanup;
+ }
+
+ result = rc_acct(rh, 0, tosend);
+- if (result != OK_RC)
++ if (result != OK_RC) {
+ ast_log(LOG_ERROR, "Failed to record Radius CDR record!\n");
++ }
+
++return_cleanup:
++ if (tosend) {
++ rc_avpair_free(tosend);
++ }
++
+ return result;
+ }
+
+
+Property changes on: .
+___________________________________________________________________
+Deleted: trunk-blocked
+ - /trunk:182362,182521,182762,182960,183124,183148
+Deleted: trunk-merged
+ - /trunk:1-182359,182408,182450,182525,182530,182553,182722,182847,183028,183057,183108,183117
+Added: branch-1.4-blocked
+ + /branches/1.4:43484,43510,43582,43626,43703,43756,44023,44080,44109,44407,44409,44567,44650,44660-44662,44665,44746,44760,44776-44777,44805,44992,45246,45313-45314,45381,45464,46114-46117,46165,46214,46253,46255,46401,46431,46583,46716,46883,47107-47108,47323,47329,47344,47348,47369,47444,47542,47553,47558,47564,47573,47576,47613,47736,47762,47856,47892,48046,48147,48162,48195,48234,48270,48281,48561,48583,48931,49022,49024,49032,49035,49070,49096,49189,49212,49282,49388,49710,50186,50921,51245,51755,51895,52000,52158,52373,52535,52809,52856,53077,53086,53099,53818,53878,54026,56006,56922,57591,58939,58955,59042,59069-59070,59230,60709,61220,62095,62299,62739,62913,63283,63656,64280,64565,64605,65394,65452,66068,66160,66244,66312,66602,66637,67018,67372,72453,72462,72493,72554,72597,72599,72665,73143,74262,74628,74839,75437,75439,75447,75712,75980,76054,76176,76178,76227,76891,77871,78146,78416,78620,78826,78860,80086,80088,80167,80497,80689,80747,81375,81492,82198,82276,82398,83400,83653,84163,84437,84544,85397,85536,85548,85687,85717,85852,86028,86371-86372,86406,87067,87340,87534,88471,89111,89191,89254,89339,89616,89727,89999,90147,90546,90798,91032,91501,92200,92510,93000,93183,93420,93764,94466,94543,94765,94769,94831,96020,96022,96024,97206,98025,98082,98265,98734,98849,98972-98973,98982,99127,99878,100418,100673,100934,101820,102653,103503,103556,103607,103698,103701,103703,103709,103713,103768,103807,104026-104027,104111,104332,104591,105591,107472,107582,109057,109171,109393,110880,112689,112709,113507,114032,114072,114167,114173,114180,114211,114248,114297,114299,114522,114542,114545,114550,114649,115257,115517,117523,117809,118055,119076,120061,120371,120671,120731,121992,122208,122314,122613,122663,124743,124908,125530,125893,126395,126680,127069,127501,127754,128029,128637,129158,129208,129505,130042,130298,130317,130373,131480,132042,132784,132787,132974,133237,133709,134652,134704,134976,136238,136304,136348,136404,136458,136560,137348,137527,137529,137580,137677,137850,138309,138516,138569,138938,138949,139145,139521,139769,140050,140115,141217,141267,141678,143204,143270,143475,143674,143964,144420,144758,145839,146129,146244,147941,148990,149840,150557,150816,151100,151167,151763,154724,158306,158629,159158,159571,160570,160764,162071,162670-162671,163785,164082,164204,164343,165537,165991,166157,166262,166592,168598,169581,169797,171120,171122,171452,172639,173248,173770,173900,174644,174885,175407,175698,177160,177450,177696,178640,178838,180010,181133,182652,182963,182965,184980,185298,185531,186057
+Added: branch-1.4-merged
+ + /branches/1.4:1-43376,43383,43386,43388,43392,43396,43405,43410,43422,43441,43445,43450,43454,43456,43464,43466,43469,43477,43482,43486,43489,43492,43518,43524,43553,43564,43616,43635-43702,43704-43755,43757-43800,43802-43846,43852,43861-43862,43864,43873,43877,43893,43898-43899,43913,43915,43918-43919,43933,43944,43952,43978,43993,43996-44012,44022,44034-44043,44053,44055,44057,44068,44078,44090,44111,44125,44135,44166-44167,44169,44186,44199,44215,44283-44286,44298,44312,44322,44378,44390,44393,44433,44436,44450,44476,44486,44502,44559,44561-44563,44581,44605,44628,44631,44684,44759,44764,44786,44788,44806,44808-44809,44819,44888,44911,44921,44942,44945,44956,44971,44982,44994,45026-45027,45031,45040,45049,45051,45066,45079,45088,45104,45106,45125,45196,45213,45262,45280,45327,45378,45408,45410,45439,45441,45452,45517,45595,45622,45646,45678,45692,45694,45741,45775,45817-45818,45916,45928,45999,46065,46067,46078,46080,46082-46113,46118-46141,46143-46154,46200,46216,46237,46249,46252,46276,46298,46329,46347,46351-46353,46358,46363,46367,46370,46377,46382,46389,46398,46403,46407,46433,46474,46506,46511,46526,46554,46558,46561,46563,46606,46628,46631,46714,46744,46775,46778,46780,46822,46845,46847,46857,46901,46930,46937,46965,46992,47015,47051,47053,47192,47195-47196,47199,47239,47250,47268,47279,47284,47287,47309,47327,47331,47333,47352,47366,47372,47375,47377,47380,47391,47398,47405,47414,47418,47432-47433,47436,47454,47457,47463,47466,47474,47476,47492,47494,47497,47507,47509,47511,47513,47523,47526-47527,47540,47551,47572,47581,47584,47597,47617,47621,47625,47628,47632,47635,47639,47641,47645,47656,47684,47690,47693,47698,47701,47707,47709,47712,47733,47744,47748,47751,47755,47758,47764,47777,47782,47823,47843,47845,47850,47852,47860,47864-47865,47897,47944,47959,47989,47992,48002,48015,48017,48031,48038,48049,48054,48088,48095,48101,48105,48107,48113,48115,48129,48135,48143,48152,48155,48158,48166,48168,48177,48179,48186,48190,48193,48199,48219,48223,48228,48230,48248,48252,48254,48264,48279,48317,48323,48326,48349,48357,48363,48372,48375,48377,48379,48381-48382,48391,48396,48399,48401,48427,48461,48472,48478,48481,48487,48502,48504,48506,48513,48521,48525,48528,48548,48554,48564,48571,48577,48586,48592,48596,48637,48783,48870,48888,48906,48944,48948,48956,48960,48964,48966,48975,48977,48980,48982,48985,48987-48988,48993,48995,48997,49006,49009,49024,49028,49046,49061,49063,49066,49073,49098-49099,49102,49145,49165,49237,49259,49313,49355,49413,49457-49461,49465,49523,49536,49551,49553,49581,49600,49636,49680,49705,49712,49714-49715,49742,49831,49834,49866,49890,49925,49945,49983,50006,50032,50073,50098,50124,50151,50228,50266,50298,50346,50377,50405,50433,50466,50468,50562,50602,50647,50674,50727,50754,50782,50820,50867,50895,50957,50994,51030,51057,51087,51146,51148,51150,51159,51162,51165,51167,51170,51172,51176,51182,51186,51195,51198,51204-51205,51211,51213,51233,51236,51241,51243,51251,51256,51262,51265,51272,51274,51311,51326,51328,51331,51339,51341,51343,51348,51350,51407,51409,51513,51558,51615,51683,51716,51750,51781,51788,51829,51848,51931,51989,52016,52049,52052,52107,52160,52163,52208,52210,52265,52335,52370,52416,52462,52494-52506,52523,52572,52611,52645,52647,52679,52688,52695,52717,52763,52807-52808,52904,52952,52997,52999,53001,53035,53037,53040,53042,53046,53050,53052,53057,53062,53064,53070,53072,53075,53079,53081,53085,53088,53093,53097,53104,53109,53114,53118,53120,53131,53136,53138,53143,53150,53152,53246,53294,53324,53355,53358,53399,53429,53434,53464,53497,53530,53532,53601,53715,53749,53779-53781,53783,53810,53850,53879-53881,54002,54066,54103,54204,54218,54235,54290,54375,54481,54623,54714,54772,54787,54884,54886,54888,54898,54924,54969,55002,55006,55050,55052,55086,55129,55154,55217,55219,55278,55397,55435,55483,55553,55555,55590,55634,55670,55688,55717,55741,55758,55799,55834,55869,55914,55947,55949,55951,55954,55957,56008,56011,56055,56094,56125,56231,56277,56341,56372,56407,56457,56505,56569,56685,56740,56783,56785,56805,56839,56847,56856,56888,56975,57049,57053,57055,57089,57093,57139,57144,57146,57203,57207,57318,57364,57396,57426,57473,57477,57556,57649,57768,57770,57798,57826,57870,57872,57914,58023,58053,58119,58121,58165,58240,58243,58320,58351-58352,58354,58389,58436,58474,58479,58510,58512,58584,58604,58638,58669,58705,58779,58783,58825-58826,58843,58845,58848,58902,58906,58923,58931,58933,58935,58937,58941,58946-58947,58953,58957,58992,59035,59037,59040,59049,59064,59076,59078,59081,59087,59089,59145,59180,59182,59188,59195,59200,59202,59206,59213,59215,59217,59223,59225,59228,59254,59256,59259,59261-59262,59273,59275,59278,59281,59284,59289,59302,59304,59341,59358,59361,59363,59452,59486,59522,59573,59654,59688,59724,59774,59804,59853,59887,59936,59939,59963,60069,60088,60112,60137,60214,60265,60268,60323,60325,60361,60399,60459,60485,60521,60565,60603,60661,60712-60713,60762,60798,60847,60850,60936,60984,60989,61183,61342-61443,61477,61641,61644-61645,61648,61651,61656,61658,61674,61676,61678,61681,61683,61686,61690,61694,61697,61705,61707,61763,61765,61772,61774,61779,61787,61799,61805,61863,61870,61914,61959,61961,62005,62038,62137,62171,62174,62218,62331,62369,62371,62414,62419,62497,62545,62548,62624,62689,62692,62738,62789,62797-62807,62842,62883,62912,62942,62986,62989,63047,63099,63152,63254,63286,63329,63360,63403,63445,63448,63478,63532,63534-63535,63566,63608,63611-63612,63698,63749,63804,63830,63872,63886,63905,63982,64044,64086,64114,64157,64193,64240,64276,64278,64306,64324,64353,64426,64515-64516,64543,64578,64602,64686,64720,64754,64756,64759,64761,64820,64868,64904,64974,65039,65076,65123,65200-65201,65250,65342,65408,65501,65541,65589,65677,65679-65680,65683,65685,65768,65836,65839,65841-65842,65853,65863,65866,65965-65967,65978,66026,66029-66030,66070,66074,66076,66157,66159,66363,66398,66404,66414,66437,66474,66503,66538,66671,66768,66770,66775,66821,66879,66881,66897,66916,66919,67020-67021,67026,67061,67064,67066,67068,67071,67073,67119,67121,67156,67158,67162,67210,67270,67304,67308,67329,67334,67360,67420,67457,67492,67526,67558,67594,67597,67626,67631,67650,67716,67804,67862,67872,67924,67941,67993,68027-68028,68030,68071,68157,68192,68198,68211,68249,68280,68313,68326,68354,68370,68401,68450,68527,68595,68644,68683,68733,68781,68814,68922,69010,69012,69014,69016,69069,69071,69128,69144,69181,69183-69184,69221,69259,69358,69392,69434,69470,69518,69558,69579,69625,69660-69661,69668,69689,69702,69708,69744,69775,69794,69796,69805,69847,69895,69944,69987,70003,70062,70084,70164,70198,70360,70397,70445,70494,70552,70554,70560,70612,70656,70677,70726-70727,70808,70841,70866,70883,70899,70949,71003,71063,71096,71106,71118,71120-71123,71214,71230,71289,71291,71362,71371,71412,71422,71430,71519,71522,71576,71657,71751,71796,71877,71915,71953,72006,72042,72112,72125,72148,72257,72260,72272,72328,72331,72335,72381,72383,72556,72705,72766,72806,72850-72852,72888,72926,72933,73005,73053,73208,73253,73316,73319,73355,73398,73400,73467,73512,73548,73551,73555,73598,73629,73675,73679,73696,73727,73769,73849,73930,73980,73985,74043,74045,74047,74082,74120,74122,74159,74162,74211,74265,74314,74317,74323,74374,74379,74388,74428,74476,74515,74572,74642,74722,74767,74815,74864,74866,74888,74922,74955,74997,75053,75067,75078,75108,75253,75306,75401,75403,75405,75441,75445,75450,75529,75583,75619,75621,75623,75658,75707,75711,75732,75749,75759,75807,75928,75969,75978,76067,76087,76132,76139,76174,76211,76485,76519,76561,76618,76620,76654,76656,76708,76801,76803,76937,76983,77071,77154,77176,77191,77318,77348,77350,77380,77410,77424-77429,77460,77490,77536,77540,77571,77768,77771,77778,77780,77783,77785,77788,77794-77795,77824,77827,77831,77844,77852,77854,77863,77865,77867,77869,77883,77886-77887,77890,77894,77939,77943,77945,77947,77949,77993,77996,78028,78063,78095,78101,78103,78242,78275,78371,78375,78415,78437,78450,78488,78569,78575,78646,78717,78749,78778,78859,78891,78907,78936,78951,78955,78995,79044,79049,79142,79174,79207,79214,79255,79397,79436,79470,79523,79527,79553,79642,79665,79690,79748,79756,79778,79792,79833,79857,79902,79904,79906,79912,79947,79998,80044,80047,80049,80130,80132,80166,80183,80255,80257,80302,80304,80330,80360,80362,80390,80424,80426,80469,80499,80501,80539,80547,80573,80661,80717,80722,80750,80789,80820,80849,80895,80932,80974,81010,81012,81042,81065,81074,81120,81158,81189,81226,81291,81331,81340,81342,81346,81349,81367,81369,81373,81379,81381,81383,81392,81395,81397,81401,81403,81405-81406,81410,81412,81415-81416,81418,81426,81433,81435,81437,81439,81442,81448,81453,81455,81520,81523,81525,81569,81599,81650,81682,81713,81743,81776,81778,81826,81832,81886,81923,81952,81997,82028,82091,82155,82236,82238,82240,82243,82245,82250,82252,82261,82263,82265,82267,82274,82278,82280,82285-82286,82291,82296,82309,82326,82335,82337,82339,82344,82346,82358,82376,82385,82394,82396,82435,82444,82514,82590-82592,82594,82644,82676,82751,82802,82834,82865,82867,82929,82961,82992,83023-83024,83070,83074,83121,83175,83177,83179,83230,83232,83246,83316,83348,83432,83558,83589,83637,83695,83773,83879,83910,83941,83943,83974,83976,84018,84049,84078,84133,84146,84158,84160,84166,84170,84206,84236,84239,84271,84274,84291,84370,84410,84474,84511,84581,84637,84690,84692,84742,84783,84818,84851,84890,84902,84957,84990,85023,85057,85093,85158,85195,85242,85276,85280,85316,85356,85515,85517,85523,85532-85533,85540,85543,85545,85552,85556,85559,85561,85571,85604,85647,85649,85684,85686,85720,85818,85850,85896,85921,85958,85994,85997,86032,86063,86066,86117,86149,86202,86237,86296,86328,86330,86405,86469,86471,86502,86598,86630,86661,86663,86694,86726,86750,86754,86756,86787,86836,86880-86881,86902,86936,86982,87069,87120,87168,87262,87294,87342,87373,87396,87460,87567,87571,87650,87686,87739,87775,87849,87852,87906,87908,87970,88026,88078,88116,88210,88283,88328,88366,88539,88585,88624,88671,88709,88719,88765,88768,88805,88826,88862,88931,88994,89032,89036-89037,89042,89045-89046,89053,89079,89088,89090,89093,89095,89097,89099,89101,89103,89105,89115,89119,89125,89169-89173,89184,89194,89205,89239,89241,89246,89248,89260,89275,89280-89281,89286,89288,89296,89298,89301-89302,89323,89325,89416,89419,89450,89457,89491,89493,89495,89527,89534,89536,89540,89545,89559,89571,89577,89580,89586-89587,89592,89594,89599,89610,89618,89622,89624,89630-89631,89634,89701,89709,89790,89837,89839,89844,89886,89893,90059,90098,90101,90142,90145,90154-90155,90160,90163,90166-90545,90547-90753,90876,90967,91070,91074,91192,91237,91273,91292,91366,91439,91450,91637,91675,91677,91693,91737,91777,91780,91783,91826,91828,91830,91890,92158,92202,92204,92323,92363,92443,92463,92617,92696,92803,92807,92809,92815,92875,92933-92934,92937,93180,93182,93250,93291,93336,93377,93381,93625,93668,93949,93955,94077,94122,94251,94256,94418,94420,94464,94468,94538,94540,94660,94763,94767,94789-94790,94793,94797,94801,94808,94824,94828-94829,94905,94924,94977,95024,95095,95191,95470,95577,95890,95946,96102,96198-96199,96318,96394,96449,96525,96573,96575,96644,96884,96932,97077,97093,97152,97192,97194-97195,97304,97308,97350,97410,97448,97450,97489,97491,97529,97575,97618,97622,97640,97645,97697,97734,97753,97847,97849,97889,97925,97973,97976,98164,98219,98315,98317,98325,98372,98390,98467,98733,98774,98894,98934,98943,98946,98951,98955,98958,98960,98964,98966,98991,99004,99079,99081,99187,99301,99341,99426,99540,99592,99594,99643,99652,99718,99775,99777,99923,99975,99977-99978,100138,100164,100264,100378,100465,100581,100624,100626,100629,100672,100675,100740,100793,100835,100882,100922,100930,100932,100973,101035,101080,101152,101216,101219,101222,101413-101414,101433,101480,101482,101531,101601,101649,101693,101772,101818,101822,101894,101942,101989,102090,102142,102214,102323,102378,102450,102453,102576,102651,102725,102807,102858,102968,103070,103120,103197,103315,103324,103385,103683,103688,103690,103722,103726,103728,103741,103763,103770,103780,103786,103790,103795,103801,103812,103821,103823,103845,103904,103953,103956,104015,104037,104082,104084,104086,104092,104094-104095,104102,104106,104119,104132,104135,104139,104141,104334,104536,104593,104596,104598,104625,104665,104704,104783,104787,104841,105059,105113,105116,105261,105326,105409,105557,105560,105563,105565,105568,105570,105572,105674,105676,105932,106015,106038,106235,106237,106328,106437,106552,106606,106635,106704,106788,106842,106895,106945,107016,107099,107102,107158,107161,107173,107230,107290,107352,107405,107408,107461,107464,107637,107646,107713-107714,107826,107877,108031,108083,108086,108135,108227,108288,108469,108530,108583,108682,108737,108792,108796,108961,109012,109107,109226,109309,109386,109575,109648,109713,109763,109838,109908,109973,110019,110035,110083,110163,110336,110395,110474,110614,110628,110635,110779,110962,111014,111020,111024,111049,111121,111126,111129,111245,111280,111341,111391,111442,111605,111658,111720,111856,112068,112125,112138,112204,112209,112393,112468,112599,112711,112766,112820,113012,113065,113117-113118,113296,113348,113399,113402,113454,113504,113596,113681,113784,113874,113927,114021,114029,114035,114045,114051,114063,114083,114100,114103,114106,114112,114117,114120,114133,114138,114148,114184,114191,114195,114198,114204,114207,114226,114230,114242,114257,114275,114278,114284,114322,114537,114558,114571,114579,114584,114587,114591,114594,114597,114600,114603,114608,114621,114624,114628,114632,114662,114673,114689,114695,114708,114823,114829,114848,114875,114880,114890-114891,115017,115102,115196,115276,115279,115282,115285,115304,115308,115312,115320,115327,115333,115341,115415,115418,115422,115512,115545,115551,115554,115557,115561,115565,115568,115579,115884,115944,115990,116038,116088,116230,116296,116352,116409,116463,116466,116799,116978,117081,117086,117135,117462,117479,117507,117514,117519,117574,117582,117899,118048,118052,118163,118251,118358,118365,118465,118509,118551,118558,118646,118858,118953-118954,118956,118961,119009,119012,119071,119156,119238,119301,119354,119404,119478,119530,119533,119585,119636,119687,119742,119838,119926,119929,120001,120168,120173,120226,120282,120285,120425,120513,120675,120863-120885,120908,120959,121078,121229,121280,121442,121495,121596,121751,121804,121861,122046,122127,122130,122137,122259,122311,122713,122869,122919,123110,123113,123271,123274,123333,123391,123485,123710,123769,123869,123883,123909,123930,124112,124182,124315,124372,124395,124450,124540,124910,124965,125132,125218,125276,125327,125384,125585,125587,125740,125793,126056,126516,126573,126735,126789,126844,126899,126902,126999,127068,127133,127244,127560,127663,127892-127895,127973,128639,128737,128795,128812,128856,128912,128950,129047,129149,129343,129436,129567,129741,129803,129907,129966-129967,129970,130039,130102,130169,130173,130236,130514,130573,130634,130735,130792,130889,130959,131012,131242,131299,131357,131369,131421,131491,131790,131915,131921,131970,131985,131988,132107,132112,132311,132571,132641-132642,132645,132704,132712-132713,132826,132872,133038,133101,133104,133169,133295,133488,133572,133578,133649,134161,134254,134352,134475,134480,134536,134540,134595,134649,134758,134883,134915,134983,135055,135058,135473,135479,135482,135536,135597,135747,135799,135841-135850,135899,135915,135949,136062,136190,136241,136484,136488,136726,136946,137138,137405,137530,137679,137731,137847,138023,138027,138119-138238,138258,138360,138886,138942,139015,139074,139213,139347,139387,139456,139466,139553,139621,139635,139764,139869,139909,139927,140051,140056,140060,140421,140488,140605,140670,140690,140747,140751,140816,140850,141028,141094,141156,141366,141503,141565,141741,141806,141809,142063,142079,142218,142354,142358,142416,142474,142575,142675,142740,142744,142807,142865,142927,143140,143337,143404,143534,143736,143903,144066,144238,144356,144677,144924-144925,145479,145751,146026,146448,146643,146711,146799,147193,147517,147681,147997,148257,148611,148736,148912,148916,148987,149061,149130,149200,149204,149207,149266,149452,149683,150124,150304,151240-151241,151905,152059,152215,152286,152368,152463,152535,152538-152539,152811,152922,152958,152992,153114,153337,153651,154060,154066,154263,154266,154365,154685,155011,155398,155553,155803,155861,156164,156167,156178,156229,156289,156294,156297,156386,156688,156755,156816,157104,157162-157163,157305,157365,157859,158053,158071,158126,158483,158539,158600,158603,159025,159246,159269,159316,159476,159808,159897,159900,159976,160003,160207,160297,160480,160551,160558,160703,160770,160943,161013,161287,161426,161725,161948,162013-162014,162136,162188,162204,162264-162265,162273,162286,162341,162348,162413,162463,162653,162659,162663,162738,162804,162874,162926,163080,163084,163088,163092,163253,163316,163383,163448,163511,163761,164201,164350,164416,164422,164605,164634,164672,164736,164806,164876,164881,164977,165317,165591,165661,165767,165796,165889,166093,166297,166380,166509,166568,166772,166953,167095,167179,167260,167299,167432,167541,167545,167554,167566,167714,167840,168128,168191,168198,168267,168480,168507,168516,168546,168551,168561,168593,168603,168608,168614,168622,168628,168716,168721,168745,168828,168975,169210,169364,169485,169722,169867,169943,170050,170147,170158,170239,170392,170504,170568,170588,170648,170671,170719,170836,170979,171187,171264,171527,171621,171837,171963,172030,172169,172438,172962,173066,173070,173211,173392,173396,173559,173592,173692,173696,173917,173967-173968,174082,174148,174218,174282,174369,174583,175029,175124,175187,175294,175311,175590,175777,175792,175825,175921,176029,176216,176249-176252,176254,176354,176426,176661,176701,177096,177225,177383,177536,177540,177701,177786,178141,178205,178373,178445,178508,178804,178956,179395,179461,179468,179532,179536,179608,179671,179741,179807,179840,180006,180194,180372,180380,180464,180532,180567,180941,181029-181031,181295,181328,181340,181423,181436,181655,181659-181660,181664,181768,181898,181990,182208,182281,182449,182808,182810,182882,183115,183123,183126,183145,183238,183241,183291,183319,183342,183386,183559,183700,183913,184078,184188,184388,184447,184565,184842,184947,185031,185120-185121,185196,185362,185468,185599,185771,185845,185952,186059,186081,186174,186229,186320,186415,186445,186458
+Modified: svn:externals
+ - menuselect http://svn.digium.com/svn/menuselect/tags/autotag_for_asterisk/1.6.2.0-beta1
+
+ + menuselect http://svn.digium.com/svn/menuselect/trunk
+
+
diff --git a/testing/asterisk/asterisk-07-issue14068.patch b/testing/asterisk/asterisk-07-issue14068.patch
new file mode 100644
index 00000000..49cad168
--- /dev/null
+++ b/testing/asterisk/asterisk-07-issue14068.patch
@@ -0,0 +1,1423 @@
+Index: channels/chan_dahdi.c
+===================================================================
+--- a/channels/chan_dahdi.c (.../trunk) (revision 186562)
++++ b/channels/chan_dahdi.c (.../team/group/issue14068) (revision 186562)
+@@ -3096,6 +3096,196 @@
+ }
+ #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;
+@@ -3391,7 +3581,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;
+@@ -3528,7 +3719,8 @@
+ ast_setstate(ast, AST_STATE_DIALING);
+ ss7_rel(p->ss7);
+ }
+-#endif /* HAVE_SS7 */
++#endif /* defined(HAVE_SS7) */
++
+ #ifdef HAVE_OPENR2
+ if (p->mfcr2) {
+ openr2_calling_party_category_t chancat;
+@@ -3563,7 +3755,8 @@
+ ast_setstate(ast, AST_STATE_DIALING);
+ }
+ #endif /* HAVE_OPENR2 */
+-#ifdef HAVE_PRI
++
++#if defined(HAVE_PRI)
+ if (p->pri) {
+ struct pri_sr *sr;
+ #ifdef SUPPORT_USERUSER
+@@ -3574,8 +3767,6 @@
+ int prilocaldialplan;
+ int ldp_strip;
+ int exclusive;
+- const char *rr_str;
+- int redirect_reason;
+
+ c = strchr(dest, '/');
+ if (c) {
+@@ -3804,20 +3995,10 @@
+ }
+ pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
+ p->use_callingpres ? ast->connected.id.number_presentation : (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);
++ 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 */
+@@ -3838,7 +4019,8 @@
+ ast_setstate(ast, AST_STATE_DIALING);
+ pri_rel(p->pri);
+ }
+-#endif
++#endif /* defined(HAVE_PRI) */
++
+ ast_mutex_unlock(&p->lock);
+ return 0;
+ }
+@@ -7111,6 +7293,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);
+@@ -7345,6 +7528,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;
+@@ -12607,17 +12849,17 @@
+ 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);
+- }
++ 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);
+@@ -12635,17 +12877,40 @@
+ 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);
++ 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);
+@@ -12683,6 +12948,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 */
+@@ -12704,6 +12970,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) {
+@@ -12789,7 +13066,9 @@
+ 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) {
+@@ -12804,6 +13083,9 @@
+
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+
++ if (c && (redirecting.from.number || redirecting.from.name)) {
++ ast_channel_update_redirecting(c, &redirecting);
++ }
+ if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+ pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+ }
+@@ -12821,8 +13103,10 @@
+
+ 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);
+@@ -12849,6 +13133,9 @@
+
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+
++ if (redirecting.from.number || redirecting.from.name) {
++ ast_channel_update_redirecting(c, &redirecting);
++ }
+ if (e->ring.ani2 >= 0) {
+ snprintf(ani2str, 5, "%d", e->ring.ani2);
+ pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+@@ -12861,8 +13148,10 @@
+ }
+ #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);
+@@ -12946,6 +13235,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_channel_queue_connected_line_update(pri->pvts[chanpos]->owner, &connected);
++ }
++
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ }
+ }
+@@ -13050,12 +13352,85 @@
+ 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_FACILITY:
++ chanpos = pri_find_principle(pri, e->facility.channel);
++ if (chanpos < 0) {
++ 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 {
++ 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 {
++ int i;
++
++ 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;
++
++ 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_channel_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_channel_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);
++ }
++ }
++ break;
+ case PRI_EVENT_ANSWER:
+ chanpos = pri_find_principle(pri, e->answer.channel);
+ if (chanpos < 0) {
+@@ -13067,6 +13442,9 @@
+ 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 */
+
+@@ -13105,15 +13483,26 @@
+ 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;
+ 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_channel_queue_connected_line_update(owner, &connected);
++ }
++
+ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
+ }
+ }
+@@ -13152,6 +13541,7 @@
+ break;
+ default:
+ pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ break;
+ }
+ }
+ }
+Index: CHANGES
+===================================================================
+--- a/CHANGES (.../trunk) (revision 186562)
++++ b/CHANGES (.../team/group/issue14068) (revision 186562)
+@@ -55,6 +55,10 @@
+ received number from the ISDN link if that number has the corresponding
+ Type-Of-Number.
+
++libpri channel driver (chan_dahdi) changes
++-------------------------------------------
++ * The channel variable PRIREDIRECTREASON is now just a status variable.
++ Use the REDIRECTING(reason) dialplan function to alter the reason.
+
+ SIP channel driver (chan_sip) changes
+ -------------------------------------------
+Index: funcs/func_redirecting.c
+===================================================================
+--- a/funcs/func_redirecting.c (.../trunk) (revision 0)
++++ b/funcs/func_redirecting.c (.../team/group/issue14068) (revision 186562)
+@@ -0,0 +1,474 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*!
++ * \file
++ * \brief Redirecting data dialplan function
++ * \ingroup functions
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ *
++ * See Also:
++ * \arg \ref AstCREDITS
++ */
++
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++/* ------------------------------------------------------------------- */
++
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++
++#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"
++
++/*** DOCUMENTATION
++ <function name="REDIRECTING" language="en_US">
++ <synopsis>
++ Gets or sets Redirecting data on the channel.
++ </synopsis>
++ <syntax>
++ <parameter name="datatype" required="true">
++ <para>The allowable datatypes are:</para>
++ <enumlist>
++ <enum name = "from-all" />
++ <enum name = "from-num" />
++ <enum name = "from-name" />
++ <enum name = "from-ton" />
++ <enum name = "to-all" />
++ <enum name = "to-num" />
++ <enum name = "to-name" />
++ <enum name = "to-ton" />
++ <enum name = "pres" />
++ <enum name = "reason" />
++ <enum name = "count" />
++ </enumlist>
++ </parameter>
++ <parameter name="i">
++ <para>If set, this will prevent the channel from sending out protocol
++ messages because of the value being set</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Gets or sets Redirecting data on the channel. The allowable values
++ for the <replaceable>reason</replaceable> field are the following:</para>
++ <enumlist>
++ <enum name = "unknown"><para>Unknown</para></enum>
++ <enum name = "cfb"><para>Call Forwarding Busy</para></enum>
++ <enum name = "cfnr"><para>Call Forwarding No Reply</para></enum>
++ <enum name = "unavailable"><para>Callee is Unavailable</para></enum>
++ <enum name = "time_of_day"><para>Time of Day</para></enum>
++ <enum name = "dnd"><para>Do Not Disturb</para></enum>
++ <enum name = "deflection"><para>Call Deflection</para></enum>
++ <enum name = "follow_me"><para>Follow Me</para></enum>
++ <enum name = "out_of_order"><para>Called DTE Out-Of-Order</para></enum>
++ <enum name = "away"><para>Callee is Away</para></enum>
++ <enum name = "cf_dte"><para>Call Forwarding By The Called DTE</para></enum>
++ <enum name = "cfu"><para>Call Forwarding Unconditional</para></enum>
++ </enumlist>
++ </description>
++ </function>
++ ***/
++
++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;
++}
++
++
++
++
++/* ******************************************************************* */
++/*!
++ * \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;
++ }
++ } 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;
++ }
++ } 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;
++}
++
++
++
++
++/* ******************************************************************* */
++/*!
++ * \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));
++ if (!(id->name = ast_strdup(name))) {
++ return ID_FIELD_INVALID;
++ }
++ if (!(id->number = ast_strdup(num))) {
++ return ID_FIELD_INVALID;
++ }
++ } 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;
++}
++
++
++
++
++/* ******************************************************************* */
++/*!
++ * \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_channel_set_redirecting;
++ break;
++
++ default:
++ ast_log(LOG_ERROR, "Unknown redirecting option '%s'.\n", option);
++ return 0;
++ }
++ }
++ else {
++ set_it = ast_channel_update_redirecting;
++ }
++
++ 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;
++ }
++ } 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;
++ }
++ } 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;
++}
++
++
++
++
++static struct ast_custom_function redirecting_function = {
++ .name = "REDIRECTING",
++ .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);
++}
++
++
++
++
++/* ******************************************************************* */
++/*!
++ * \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)
++ ? AST_MODULE_LOAD_DECLINE
++ : AST_MODULE_LOAD_SUCCESS;
++}
++
++
++
++
++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_connectedline.c
+===================================================================
+--- a/funcs/func_connectedline.c (.../trunk) (revision 0)
++++ b/funcs/func_connectedline.c (.../team/group/issue14068) (revision 186562)
+@@ -0,0 +1,239 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2007, Gareth Palmer
++ *
++ * Gareth Palmer <gareth@acsdata.co.nz>
++ *
++ * 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 Connected Line dialplan function
++ *
++ * \ingroup functions
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++
++#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"
++
++/*** DOCUMENTATION
++ <function name="CONNECTEDLINE" language="en_US">
++ <synopsis>
++ Gets or sets Connected Line data on the channel.
++ </synopsis>
++ <syntax>
++ <parameter name="datatype" required="true">
++ <para>The allowable datatypes are:</para>
++ <enumlist>
++ <enum name = "all" />
++ <enum name = "num" />
++ <enum name = "name" />
++ <enum name = "ton" />
++ <enum name = "pres" />
++ <enum name = "source" />
++ </enumlist>
++ </parameter>
++ <parameter name="i">
++ <para>If set, this will prevent the channel from sending out protocol
++ messages because of the value being set</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Gets or sets Connected Line data on the channel. Possible values
++ for the <replaceable>source</replaceable> datatype are:</para>
++ <enumlist>
++ <enum name="answer"><para>Normal Call Answering</para></enum>
++ <enum name="transfer_alerting"><para>Call Transfer(Alerting)</para></enum>
++ <enum name="transfer_active"><para>Call Transfer(Active)</para></enum>
++ </enumlist>
++ </description>
++ </function>
++ ***/
++
++static int connectedline_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("all", data, 3)) {
++ snprintf(buf, len, "\"%s\" <%s>",
++ S_OR(chan->connected.id.name, ""),
++ S_OR(chan->connected.id.number, ""));
++ } else if (!strncasecmp("name", data, 4)) {
++ if (chan->connected.id.name) {
++ ast_copy_string(buf, chan->connected.id.name, len);
++ }
++ } else if (!strncasecmp("num", data, 3)) {
++ if (chan->connected.id.number) {
++ ast_copy_string(buf, chan->connected.id.number, len);
++ }
++ } else if (!strncasecmp("ton", data, 3)) {
++ snprintf(buf, len, "%d", chan->connected.id.number_type);
++ } else if (!strncasecmp("pres", data, 4)) {
++ ast_copy_string(buf, ast_named_caller_presentation(chan->connected.id.number_presentation), len);
++ } else if (!strncasecmp("source", data, 6)) {
++ ast_copy_string(buf, ast_connected_line_source_name(chan->connected.source), len);
++ } else {
++ ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
++ }
++
++ ast_channel_unlock(chan);
++
++ return 0;
++}
++
++static int connectedline_write(struct ast_channel *chan, const char *cmd, char *data,
++ const char *value)
++{
++ struct ast_party_connected_line connected;
++ char *val;
++ char *option;
++ void (*set_it)(struct ast_channel *chan, const struct ast_party_connected_line *connected);
++
++ 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_channel_set_connected_line;
++ break;
++
++ default:
++ ast_log(LOG_ERROR, "Unknown connectedline option '%s'.\n", option);
++ return 0;
++ }
++ }
++ else {
++ set_it = ast_channel_update_connected_line;
++ }
++
++ ast_channel_lock(chan);
++ ast_party_connected_line_set_init(&connected, &chan->connected);
++ ast_channel_unlock(chan);
++
++ value = ast_skip_blanks(value);
++
++ if (!strncasecmp("all", data, 3)) {
++ char name[256];
++ char num[256];
++
++ ast_callerid_split(value, name, sizeof(name), num, sizeof(num));
++ connected.id.name = name;
++ connected.id.number = num;
++ set_it(chan, &connected);
++ } else if (!strncasecmp("name", data, 4)) {
++ connected.id.name = ast_strdupa(value);
++ ast_trim_blanks(connected.id.name);
++ set_it(chan, &connected);
++ } else if (!strncasecmp("num", data, 3)) {
++ connected.id.number = ast_strdupa(value);
++ ast_trim_blanks(connected.id.number);
++ set_it(chan, &connected);
++ } else if (!strncasecmp("ton", data, 3)) {
++ val = ast_strdupa(value);
++ ast_trim_blanks(val);
++
++ if (('0' <= val[0]) && (val[0] <= '9')) {
++ connected.id.number_type = atoi(val);
++ set_it(chan, &connected);
++ } else {
++ ast_log(LOG_ERROR, "Unknown connectedline type of number '%s', value unchanged\n", val);
++ }
++ } 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 connectedline number presentation '%s', value unchanged\n", val);
++ } else {
++ connected.id.number_presentation = pres;
++ set_it(chan, &connected);
++ }
++ } else if (!strncasecmp("source", data, 6)) {
++ int source;
++
++ val = ast_strdupa(value);
++ ast_trim_blanks(val);
++
++ if (('0' <= val[0]) && (val[0] <= '9')) {
++ source = atoi(val);
++ } else {
++ source = ast_connected_line_source_parse(val);
++ }
++
++ if (source < 0) {
++ ast_log(LOG_ERROR, "Unknown connectedline source '%s', value unchanged\n", val);
++ } else {
++ connected.source = source;
++ set_it(chan, &connected);
++ }
++ } else {
++ ast_log(LOG_ERROR, "Unknown connectedline data type '%s'.\n", data);
++ }
++
++ return 0;
++}
++
++static struct ast_custom_function connectedline_function = {
++ .name = "CONNECTEDLINE",
++ .read = connectedline_read,
++ .write = connectedline_write,
++};
++
++static int unload_module(void)
++{
++ return ast_custom_function_unregister(&connectedline_function);
++}
++
++static int load_module(void)
++{
++ return ast_custom_function_register(&connectedline_function)
++ ? AST_MODULE_LOAD_DECLINE
++ : AST_MODULE_LOAD_SUCCESS;
++}
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Connected Line dialplan function");
+
+Property changes on: funcs/func_connectedline.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+
+Property changes on: .
+___________________________________________________________________
+Added: automerge
+ + *
+Added: svnmerge-integrated
+ + /trunk:1-186557
+Added: automerge-email
+ + rmudgett@digium.com
+